1159
|
1 import std/macros
|
1161
|
2 import std/strformat
|
1159
|
3 import std/typetraits
|
|
4
|
1161
|
5 import semicongine/core/utils
|
|
6 import semicongine/core/imagetypes
|
1159
|
7 import semicongine/core/vector
|
|
8 import semicongine/core/matrix
|
|
9 import semicongine/core/vulkanapi
|
1161
|
10 import semicongine/vulkan/buffer
|
1159
|
11
|
|
12 template VertexAttribute* {.pragma.}
|
|
13 template InstanceAttribute* {.pragma.}
|
1161
|
14 template DescriptorAttribute* {.pragma.}
|
|
15
|
1159
|
16
|
|
17 type
|
|
18 SupportedGPUType* = float32 | float64 | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64 | TVec2[int32] | TVec2[int64] | TVec3[int32] | TVec3[int64] | TVec4[int32] | TVec4[int64] | TVec2[uint32] | TVec2[uint64] | TVec3[uint32] | TVec3[uint64] | TVec4[uint32] | TVec4[uint64] | TVec2[float32] | TVec2[float64] | TVec3[float32] | TVec3[float64] | TVec4[float32] | TVec4[float64] | TMat2[float32] | TMat2[float64] | TMat23[float32] | TMat23[float64] | TMat32[float32] | TMat32[float64] | TMat3[float32] | TMat3[float64] | TMat34[float32] | TMat34[float64] | TMat43[float32] | TMat43[float64] | TMat4[float32] | TMat4[float64]
|
|
19
|
|
20 func VkType[T: SupportedGPUType](value: T): VkFormat =
|
|
21 when T is float32: VK_FORMAT_R32_SFLOAT
|
|
22 elif T is float64: VK_FORMAT_R64_SFLOAT
|
|
23 elif T is int8: VK_FORMAT_R8_SINT
|
|
24 elif T is int16: VK_FORMAT_R16_SINT
|
|
25 elif T is int32: VK_FORMAT_R32_SINT
|
|
26 elif T is int64: VK_FORMAT_R64_SINT
|
|
27 elif T is uint8: VK_FORMAT_R8_UINT
|
|
28 elif T is uint16: VK_FORMAT_R16_UINT
|
|
29 elif T is uint32: VK_FORMAT_R32_UINT
|
|
30 elif T is uint64: VK_FORMAT_R64_UINT
|
|
31 elif T is TVec2[int32]: VK_FORMAT_R32G32_SINT
|
|
32 elif T is TVec2[int64]: VK_FORMAT_R64G64_SINT
|
|
33 elif T is TVec3[int32]: VK_FORMAT_R32G32B32_SINT
|
|
34 elif T is TVec3[int64]: VK_FORMAT_R64G64B64_SINT
|
|
35 elif T is TVec4[int32]: VK_FORMAT_R32G32B32A32_SINT
|
|
36 elif T is TVec4[int64]: VK_FORMAT_R64G64B64A64_SINT
|
|
37 elif T is TVec2[uint32]: VK_FORMAT_R32G32_UINT
|
|
38 elif T is TVec2[uint64]: VK_FORMAT_R64G64_UINT
|
|
39 elif T is TVec3[uint32]: VK_FORMAT_R32G32B32_UINT
|
|
40 elif T is TVec3[uint64]: VK_FORMAT_R64G64B64_UINT
|
|
41 elif T is TVec4[uint32]: VK_FORMAT_R32G32B32A32_UINT
|
|
42 elif T is TVec4[uint64]: VK_FORMAT_R64G64B64A64_UINT
|
|
43 elif T is TVec2[float32]: VK_FORMAT_R32G32_SFLOAT
|
|
44 elif T is TVec2[float64]: VK_FORMAT_R64G64_SFLOAT
|
|
45 elif T is TVec3[float32]: VK_FORMAT_R32G32B32_SFLOAT
|
|
46 elif T is TVec3[float64]: VK_FORMAT_R64G64B64_SFLOAT
|
|
47 elif T is TVec4[float32]: VK_FORMAT_R32G32B32A32_SFLOAT
|
|
48 elif T is TVec4[float64]: VK_FORMAT_R64G64B64A64_SFLOAT
|
|
49 elif T is Mat2[float32]: VK_FORMAT_R32G32_SFLOAT
|
|
50 elif T is Mat2[float64]: VK_FORMAT_R64G64_SFLOAT
|
|
51 elif T is Mat23[float32]: VK_FORMAT_R32G32B32_SFLOAT
|
|
52 elif T is Mat23[float64]: VK_FORMAT_R64G64B64_SFLOAT
|
|
53 elif T is Mat32[float32]: VK_FORMAT_R32G32_SFLOAT
|
|
54 elif T is Mat32[float64]: VK_FORMAT_R64G64_SFLOAT
|
|
55 elif T is Mat3[float32]: VK_FORMAT_R32G32B32_SFLOAT
|
|
56 elif T is Mat3[float64]: VK_FORMAT_R64G64B64_SFLOAT
|
|
57 elif T is Mat34[float32]: VK_FORMAT_R32G32B32A32_SFLOAT
|
|
58 elif T is Mat34[float64]: VK_FORMAT_R64G64B64A64_SFLOAT
|
|
59 elif T is Mat43[float32]: VK_FORMAT_R32G32B32_SFLOAT
|
|
60 elif T is Mat43[float64]: VK_FORMAT_R64G64B64_SFLOAT
|
|
61 elif T is Mat4[float32]: VK_FORMAT_R32G32B32A32_SFLOAT
|
|
62 elif T is Mat4[float64]: VK_FORMAT_R64G64B64A64_SFLOAT
|
|
63 else: {.error: "Unsupported data type on GPU".}
|
|
64
|
|
65 template getElementType(field: typed): untyped =
|
|
66 when not (typeof(field) is seq or typeof(field) is array):
|
|
67 {.error: "getElementType can only be used with seq or array".}
|
|
68 genericParams(typeof(field)).get(0)
|
|
69
|
1161
|
70 template ForVertexDataFields*(inputData: typed, fieldname, valuename, isinstancename, body: untyped): untyped =
|
1159
|
71 for theFieldname, value in fieldPairs(inputData):
|
1161
|
72 when hasCustomPragma(value, VertexAttribute) or hasCustomPragma(value, InstanceAttribute):
|
1159
|
73 when not typeof(value) is seq:
|
|
74 {.error: "field '" & theFieldname & "' needs to be a seq".}
|
|
75 when not typeof(value) is SupportedGPUType:
|
|
76 {.error: "field '" & theFieldname & "' is not a supported GPU type".}
|
|
77 block:
|
|
78 let `fieldname` {.inject.} = theFieldname
|
|
79 let `valuename` {.inject.} = default(getElementType(value))
|
|
80 let `isinstancename` {.inject.} = value.isInstanceAttribute()
|
|
81 body
|
|
82
|
1161
|
83 template ForDescriptorFields*(inputData: typed, fieldname, valuename, typename, countname, body: untyped): untyped =
|
|
84 for theFieldname, value in fieldPairs(inputData):
|
|
85 when hasCustomPragma(value, DescriptorAttribute):
|
|
86 when not (
|
|
87 typeof(value) is SupportedGPUType
|
|
88 or (typeof(value) is array and elementType(value) is SupportedGPUType)
|
|
89 or typeof(value) is Texture
|
|
90 ):
|
|
91 {.error: "field '" & theFieldname & "' needs to be a SupportedGPUType or an array of SupportedGPUType".}
|
|
92 block:
|
|
93 let `fieldname` {.inject.} = theFieldname
|
|
94 let `valuename` {.inject.} = default(getElementType(value))
|
|
95
|
|
96 # TODO
|
|
97 let `typename` {.inject.} = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
|
|
98 let `typename` {.inject.} = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
|
|
99
|
|
100 when typeof(value) is array:
|
|
101 let `countname` {.inject.} = genericParams(typeof(value)).get(0)
|
|
102 else:
|
|
103 let `countname` {.inject.} = 1
|
|
104 body
|
|
105
|
1159
|
106 func NumberOfVertexInputAttributeDescriptors[T: SupportedGPUType](value: T): uint32 =
|
|
107 when T is TMat2[float32] or T is TMat2[float64] or T is TMat23[float32] or T is TMat23[float64]:
|
|
108 2
|
|
109 elif T is TMat32[float32] or T is TMat32[float64] or T is TMat3[float32] or T is TMat3[float64] or T is TMat34[float32] or T is TMat34[float64]:
|
|
110 3
|
|
111 elif T is TMat43[float32] or T is TMat43[float64] or T is TMat4[float32] or T is TMat4[float64]:
|
|
112 4
|
|
113 else:
|
|
114 1
|
|
115
|
|
116 func NLocationSlots[T: SupportedGPUType](value: T): uint32 =
|
|
117 #[
|
|
118 single location:
|
|
119 16-bit scalar and vector types, and
|
|
120 32-bit scalar and vector types, and
|
|
121 64-bit scalar and 2-component vector types.
|
|
122 two locations
|
|
123 64-bit three- and four-component vectors
|
|
124 ]#
|
|
125 when typeof(value) is TVec3 and sizeof(getElementType(value)) == 8:
|
|
126 return 2
|
|
127 elif typeof(value) is TVec4 and sizeof(getElementType(value)) == 8:
|
|
128 return 2
|
|
129 else:
|
|
130 return 1
|
|
131
|
|
132 type
|
1161
|
133 IndexType = enum
|
|
134 None, UInt8, UInt16, UInt32
|
|
135 RenderBuffers = object
|
|
136 deviceBuffers: seq[Buffer] # for fast reads
|
|
137 hostVisibleBuffers: seq[Buffer] # for fast writes
|
|
138 Renderable[TMesh, TInstance] = object
|
|
139 vertexBuffers: seq[VkBuffer]
|
|
140 bufferOffsets: seq[VkDeviceSize]
|
1159
|
141 instanceCount: uint32
|
1161
|
142 case indexType: IndexType
|
|
143 of None:
|
1160
|
144 vertexCount: uint32
|
1161
|
145 else:
|
1160
|
146 indexBuffer: VkBuffer
|
|
147 indexCount: uint32
|
|
148 indexBufferOffset: VkDeviceSize
|
1161
|
149 Pipeline[TShaderInputs] = object
|
1159
|
150 pipeline: VkPipeline
|
|
151 layout: VkPipelineLayout
|
|
152 descriptorSets: array[2, seq[VkDescriptorSet]]
|
1161
|
153 ShaderSet[TShaderInputs] = object
|
1159
|
154 vertexShader: VkShaderModule
|
|
155 fragmentShader: VkShaderModule
|
1161
|
156 converter toVkIndexType(indexType: IndexType): VkIndexType =
|
|
157 case indexType:
|
|
158 of None: VK_INDEX_TYPE_NONE_KHR
|
|
159 of UInt8: VK_INDEX_TYPE_UINT8_EXT
|
|
160 of UInt16: VK_INDEX_TYPE_UINT16
|
|
161 of UInt32: VK_INDEX_TYPE_UINT32
|
1159
|
162
|
1161
|
163
|
|
164 proc CreatePipeline*[TShaderInputs](
|
1159
|
165 device: VkDevice,
|
|
166 renderPass: VkRenderPass,
|
1161
|
167 shaderSet: ShaderSet[TShaderInputs],
|
1159
|
168 topology: VkPrimitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
|
169 polygonMode: VkPolygonMode = VK_POLYGON_MODE_FILL,
|
|
170 cullMode: VkCullModeFlagBits = VK_CULL_MODE_BACK_BIT,
|
|
171 frontFace: VkFrontFace = VK_FRONT_FACE_CLOCKWISE,
|
1161
|
172 ): Pipeline[TShaderInputs] =
|
1159
|
173 # assumptions/limitations:
|
|
174 # - we are only using vertex and fragment shaders (2 stages)
|
|
175 # - we only support one subpass
|
|
176
|
|
177 # CONTINUE HERE, WITH PIPELINE LAYOUT!!!!
|
1161
|
178 # Rely on TShaderInputs
|
|
179
|
|
180 var layoutbindings: seq[VkDescriptorSetLayoutBinding]
|
|
181 let descriptors = [
|
|
182 (VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1), # more than 1 for arrays
|
|
183 (VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1),
|
|
184 ]
|
|
185 var descriptorBindingNumber = 0'u32
|
|
186 ForDescriptorFields(default(TShaderInputs), fieldname, value, descriptorCount):
|
|
187 layoutbindings.add VkDescriptorSetLayoutBinding(
|
|
188 binding: descriptorBindingNumber,
|
|
189 descriptorType: descriptorType,
|
|
190 descriptorCount: descriptorCount,
|
|
191 stageFlags: VK_SHADER_STAGE_ALL_GRAPHICS,
|
|
192 pImmutableSamplers: nil,
|
|
193 )
|
|
194 inc descriptorBindingNumber
|
|
195 var layoutCreateInfo = VkDescriptorSetLayoutCreateInfo(
|
|
196 sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
|
197 bindingCount: uint32(layoutbindings.len),
|
|
198 pBindings: layoutbindings.ToCPointer
|
|
199 )
|
|
200 var descriptorSetLayout: VkDescriptorSetLayout
|
|
201 checkVkResult vkCreateDescriptorSetLayout(device.vk, addr(layoutCreateInfo), nil, addr(descriptorSetLayout))
|
|
202 let pipelineLayoutInfo = VkPipelineLayoutCreateInfo(
|
|
203 sType: VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
|
204 setLayoutCount: 1,
|
|
205 pSetLayouts: addr(descriptorSetLayout),
|
|
206 # pushConstantRangeCount: uint32(pushConstants.len),
|
|
207 # pPushConstantRanges: pushConstants.ToCPointer,
|
|
208 )
|
|
209 checkVkResult vkCreatePipelineLayout(device, addr(pipelineLayoutInfo), nil, addr(result.layout))
|
1159
|
210
|
|
211 let stages = [
|
|
212 VkPipelineShaderStageCreateInfo(
|
|
213 sType: VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
214 stage: VK_SHADER_STAGE_VERTEX_BIT,
|
|
215 module: shaderSet.vertexShader,
|
|
216 pName: "main",
|
|
217 ),
|
|
218 VkPipelineShaderStageCreateInfo(
|
|
219 sType: VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
220 stage: VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
221 module: shaderSet.fragmentShader,
|
|
222 pName: "main",
|
|
223 ),
|
|
224 ]
|
|
225 let
|
|
226 bindings: var seq[VkVertexInputBindingDescription]
|
|
227 attributes: var seq[VkVertexInputAttributeDescription]
|
|
228 var inputBindingNumber = 0'u32
|
|
229 var inputLocationNumber = 0'u32
|
1161
|
230 ForVertexDataFields(default(TShaderInputs), fieldname, value, isInstanceAttr):
|
1159
|
231 bindings.add VkVertexInputBindingDescription(
|
|
232 binding: inputBindingNumber,
|
|
233 stride: sizeof(value).uint32,
|
|
234 inputRate: if isInstanceAttr: VK_VERTEX_INPUT_RATE_INSTANCE else: VK_VERTEX_INPUT_RATE_VERTEX,
|
|
235 )
|
|
236 # allows to submit larger data structures like Mat44, for most other types will be 1
|
|
237 let perDescriptorSize = sizeof(value).uint32 div NumberOfVertexInputAttributeDescriptors(value)
|
|
238 for i in 0'u32 ..< NumberOfVertexInputAttributeDescriptors(value):
|
|
239 attributes.add VkVertexInputAttributeDescription(
|
|
240 binding: inputBindingNumber,
|
|
241 inputLocationNumber: inputLocationNumber,
|
|
242 format: VkType(value),
|
|
243 offset: i * perDescriptorSize,
|
|
244 )
|
|
245 inputLocationNumber += NLocationSlots(value)
|
|
246 inc inputBindingNumber
|
|
247
|
|
248 let
|
|
249 vertexInputInfo = VkPipelineVertexInputStateCreateInfo(
|
|
250 sType: VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
|
251 vertexBindingDescriptionCount: uint32(bindings.len),
|
|
252 pVertexBindingDescriptions: bindings.ToCPointer,
|
|
253 vertexAttributeDescriptionCount: uint32(attributes.len),
|
|
254 pVertexAttributeDescriptions: attributes.ToCPointer,
|
|
255 )
|
|
256 inputAssembly = VkPipelineInputAssemblyStateCreateInfo(
|
|
257 sType: VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
|
258 topology: topology,
|
|
259 primitiveRestartEnable: false,
|
|
260 )
|
|
261 viewportState = VkPipelineViewportStateCreateInfo(
|
|
262 sType: VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
|
263 viewportCount: 1,
|
|
264 scissorCount: 1,
|
|
265 )
|
|
266 rasterizer = VkPipelineRasterizationStateCreateInfo(
|
|
267 sType: VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
|
268 depthClampEnable: VK_FALSE,
|
|
269 rasterizerDiscardEnable: VK_FALSE,
|
|
270 polygonMode: polygonMode,
|
|
271 lineWidth: 1.0,
|
|
272 cullMode: toBits [cullMode],
|
|
273 frontFace: frontFace,
|
|
274 depthBiasEnable: VK_FALSE,
|
|
275 depthBiasConstantFactor: 0.0,
|
|
276 depthBiasClamp: 0.0,
|
|
277 depthBiasSlopeFactor: 0.0,
|
|
278 )
|
|
279 multisampling = VkPipelineMultisampleStateCreateInfo(
|
|
280 sType: VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
|
281 sampleShadingEnable: VK_FALSE,
|
|
282 rasterizationSamples: VK_SAMPLE_COUNT_1_BIT,
|
|
283 minSampleShading: 1.0,
|
|
284 pSampleMask: nil,
|
|
285 alphaToCoverageEnable: VK_FALSE,
|
|
286 alphaToOneEnable: VK_FALSE,
|
|
287 )
|
|
288 colorBlendAttachment = VkPipelineColorBlendAttachmentState(
|
|
289 colorWriteMask: toBits [VK_COLOR_COMPONENT_R_BIT, VK_COLOR_COMPONENT_G_BIT, VK_COLOR_COMPONENT_B_BIT, VK_COLOR_COMPONENT_A_BIT],
|
|
290 blendEnable: VK_TRUE,
|
|
291 srcColorBlendFactor: VK_BLEND_FACTOR_SRC_ALPHA,
|
|
292 dstColorBlendFactor: VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
|
|
293 colorBlendOp: VK_BLEND_OP_ADD,
|
|
294 srcAlphaBlendFactor: VK_BLEND_FACTOR_ONE,
|
|
295 dstAlphaBlendFactor: VK_BLEND_FACTOR_ZERO,
|
|
296 alphaBlendOp: VK_BLEND_OP_ADD,
|
|
297 )
|
|
298 colorBlending = VkPipelineColorBlendStateCreateInfo(
|
|
299 sType: VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
|
300 logicOpEnable: false,
|
|
301 attachmentCount: 1,
|
|
302 pAttachments: addr(colorBlendAttachment),
|
|
303 )
|
|
304 dynamicStates = [VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR]
|
|
305 dynamicState = VkPipelineDynamicStateCreateInfo(
|
|
306 sType: VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
|
307 dynamicStateCount: dynamicStates.len.uint32,
|
|
308 pDynamicStates: dynamicStates.ToCPointer,
|
|
309 )
|
|
310 let createInfo = VkGraphicsPipelineCreateInfo(
|
|
311 sType: VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
|
312 stageCount: 2,
|
|
313 pStages: addr(stages),
|
|
314 pVertexInputState: addr(vertexInputInfo),
|
|
315 pInputAssemblyState: addr(inputAssembly),
|
|
316 pViewportState: addr(viewportState),
|
|
317 pRasterizationState: addr(rasterizer),
|
|
318 pMultisampleState: addr(multisampling),
|
|
319 pDepthStencilState: nil,
|
|
320 pColorBlendState: addr(colorBlending),
|
|
321 pDynamicState: addr(dynamicState),
|
|
322 layout: result.layout,
|
|
323 renderPass: renderPass,
|
|
324 subpass: 0,
|
|
325 basePipelineHandle: VkPipeline(0),
|
|
326 basePipelineIndex: -1,
|
|
327 )
|
|
328 checkVkResult vkCreateGraphicsPipelines(
|
|
329 device,
|
|
330 VkPipelineCache(0),
|
|
331 1,
|
|
332 addr(createInfo),
|
|
333 nil,
|
|
334 addr(result.pipeline)
|
|
335 )
|
|
336
|
1161
|
337 proc CreateRenderable[TMesh, TInstance](
|
|
338 mesh: TMesh,
|
|
339 instance: TInstance,
|
|
340 buffers: RenderBuffers,
|
|
341 ): Renderable[TMesh, TInstance] =
|
|
342 result.indexType = None
|
1159
|
343
|
1161
|
344 proc Bind(pipeline: Pipeline, commandBuffer: VkCommandBuffer, currentFrameInFlight: int) =
|
1159
|
345 commandBuffer.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipeline)
|
|
346 commandBuffer.vkCmdBindDescriptorSets(
|
|
347 VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
348 pipeline.layout,
|
|
349 0,
|
1161
|
350 pipeline.descriptorSets[currentFrameInFlight].len,
|
|
351 pipeline.descriptorSets[currentFrameInFlight],
|
1159
|
352 0,
|
|
353 nil,
|
|
354 )
|
1161
|
355
|
|
356 proc AssertCompatible(TShaderInputs, TMesh, TInstance, TGlobals: typedesc) =
|
|
357 # assert seq-fields of TMesh|TInstance == seq-fields of TShaderInputs
|
|
358 # assert normal fields of TMesh|Globals == normal fields of TShaderDescriptors
|
|
359 for inputName, inputValue in default(TShaderInputs).fieldPairs:
|
|
360 echo "checking shader input '" & inputName & "'"
|
|
361 var foundField = false
|
|
362 when hasCustomPragma(inputValue, VertexAttribute):
|
|
363 echo " is vertex attribute"
|
|
364 for meshName, meshValue in default(TMesh).fieldPairs:
|
|
365 when meshName == inputName:
|
|
366 assert foundField == false, "Shader input '" & TShaderInputs.name & "." & inputName & "' has been found more than once"
|
|
367 assert getElementType(meshValue) is typeof(inputValue), "Shader input " & TShaderInputs.name & "." & inputName & " is of type '" & typeof(inputValue).name & "' but mesh attribute is of type '" & getElementType(meshValue).name & "'"
|
|
368 foundField = true
|
|
369 assert foundField, "Shader input '" & TShaderInputs.name & "." & inputName & ": " & typeof(inputValue).name & "' not found in '" & TMesh.name & "'"
|
|
370 elif hasCustomPragma(inputValue, InstanceAttribute):
|
|
371 echo " is instance attribute"
|
|
372 for instanceName, instanceValue in default(TInstance).fieldPairs:
|
|
373 when instanceName == inputName:
|
|
374 assert foundField == false, "Shader input '" & TShaderInputs.name & "." & inputName & "' has been found more than once"
|
|
375 assert getElementType(instanceValue) is typeof(inputValue), "Shader input " & TShaderInputs.name & "." & inputName & " is of type '" & typeof(inputValue).name & "' but instance attribute is of type '" & getElementType(instanceValue).name & "'"
|
|
376 foundField = true
|
|
377 assert foundField, "Shader input '" & TShaderInputs.name & "." & inputName & ": " & typeof(inputValue).name & "' not found in '" & TInstance.name & "'"
|
|
378 elif hasCustomPragma(inputValue, DescriptorAttribute):
|
|
379 echo " is descriptor attribute"
|
|
380 for meshName, meshValue in default(TMesh).fieldPairs:
|
|
381 when meshName == inputName:
|
|
382 assert foundField == false, "Shader input '" & TShaderInputs.name & "." & inputName & "' has been found more than once"
|
|
383 assert typeof(meshValue) is typeof(inputValue), "Shader input " & TShaderInputs.name & "." & inputName & " is of type '" & typeof(inputValue).name & "' but mesh attribute is of type '" & getElementType(meshValue).name & "'"
|
|
384 foundField = true
|
|
385 for globalName, globalValue in default(TGlobals).fieldPairs:
|
|
386 when globalName == inputName:
|
|
387 assert foundField == false, "Shader input '" & TShaderInputs.name & "." & inputName & "' has been found more than once"
|
|
388 assert typeof(globalValue) is typeof(inputValue), "Shader input " & TShaderInputs.name & "." & inputName & " is of type '" & typeof(inputValue).name & "' but global attribute is of type '" & typeof(globalValue).name & "'"
|
|
389 foundField = true
|
|
390 assert foundField, "Shader input '" & TShaderInputs.name & "." & inputName & ": " & typeof(inputValue).name & "' not found in '" & TMesh.name & "|" & TGlobals.name & "'"
|
|
391 echo " found"
|
|
392
|
|
393
|
|
394 proc Render[TShaderInputs, TMesh, TInstance, TGlobals](
|
|
395 pipeline: Pipeline[TShaderInputs],
|
|
396 renderable: Renderable[TMesh, TInstance],
|
|
397 globals: TGlobals,
|
|
398 commandBuffer: VkCommandBuffer,
|
|
399 ) =
|
|
400 static:
|
|
401 AssertCompatible(TShaderInputs, TMesh, TInstance, TGlobals)
|
1159
|
402 commandBuffer.vkCmdBindVertexBuffers(
|
|
403 firstBinding = 0'u32,
|
1161
|
404 bindingCount = uint32(renderable.vertexBuffers.len),
|
|
405 pBuffers = renderable.vertexBuffers.ToCPointer(),
|
|
406 pOffsets = renderable.bufferOffsets.ToCPointer()
|
1159
|
407 )
|
1161
|
408 if renderable.indexType != None:
|
1159
|
409 commandBuffer.vkCmdBindIndexBuffer(
|
|
410 renderable.indexBuffer,
|
|
411 renderable.indexBufferOffset,
|
1161
|
412 renderable.indexType,
|
1159
|
413 )
|
|
414 commandBuffer.vkCmdDrawIndexed(
|
1161
|
415 indexCount = renderable.indexCount,
|
|
416 instanceCount = renderable.instanceCount,
|
1159
|
417 firstIndex = 0,
|
|
418 vertexOffset = 0,
|
|
419 firstInstance = 0
|
|
420 )
|
|
421 else:
|
|
422 commandBuffer.vkCmdDraw(
|
1161
|
423 vertexCount = renderable.vertexCount,
|
|
424 instanceCount = renderable.instanceCount,
|
1159
|
425 firstVertex = 0,
|
|
426 firstInstance = 0
|
|
427 )
|
1161
|
428
|
|
429 when isMainModule:
|
|
430 type
|
|
431 MeshA = object
|
|
432 position: seq[Vec3f]
|
|
433 transparency: float
|
|
434 InstanceA = object
|
|
435 transform: seq[Mat4]
|
|
436 position: seq[Vec3f]
|
|
437 Globals = object
|
|
438 color: Vec4f
|
|
439
|
|
440 ShaderInputsA = object
|
|
441 position {.VertexAttribute.}: Vec3f
|
|
442 transform {.InstanceAttribute.}: Mat4
|
|
443 color {.DescriptorAttribute.}: Vec4f
|
|
444
|
|
445 var p: Pipeline[ShaderInputsA]
|
|
446 var r: Renderable[MeshA, InstanceA]
|
|
447 var g: Globals
|
|
448 var s: ShaderSet[ShaderInputsA]
|
|
449
|
|
450 var p1 = CreatePipeline(device = VkDevice(0), renderPass = VkRenderPass(0), shaderSet = s)
|
|
451 Render(p, r, g, VkCommandBuffer(0))
|