Mercurial > games > semicongine
comparison semiconginev2/rendering/shaders.nim @ 1218:56781cc0fc7c compiletime-tests
did: renamge main package
author | sam <sam@basx.dev> |
---|---|
date | Wed, 17 Jul 2024 21:01:37 +0700 |
parents | semicongine/rendering/shaders.nim@570ac1620fb6 |
children | 4e465583ea32 |
comparison
equal
deleted
inserted
replaced
1217:f819a874058f | 1218:56781cc0fc7c |
---|---|
1 func GlslType[T: SupportedGPUType|Texture](value: T): string = | |
2 when T is float32: "float" | |
3 elif T is float64: "double" | |
4 elif T is int8 or T is int16 or T is int32 or T is int64: "int" | |
5 elif T is uint8 or T is uint16 or T is uint32 or T is uint64: "uint" | |
6 elif T is TVec2[int32]: "ivec2" | |
7 elif T is TVec2[int64]: "ivec2" | |
8 elif T is TVec3[int32]: "ivec3" | |
9 elif T is TVec3[int64]: "ivec3" | |
10 elif T is TVec4[int32]: "ivec4" | |
11 elif T is TVec4[int64]: "ivec4" | |
12 elif T is TVec2[uint32]: "uvec2" | |
13 elif T is TVec2[uint64]: "uvec2" | |
14 elif T is TVec3[uint32]: "uvec3" | |
15 elif T is TVec3[uint64]: "uvec3" | |
16 elif T is TVec4[uint32]: "uvec4" | |
17 elif T is TVec4[uint64]: "uvec4" | |
18 elif T is TVec2[float32]: "vec2" | |
19 elif T is TVec2[float64]: "dvec2" | |
20 elif T is TVec3[float32]: "vec3" | |
21 elif T is TVec3[float64]: "dvec3" | |
22 elif T is TVec4[float32]: "vec4" | |
23 elif T is TVec4[float64]: "dvec4" | |
24 elif T is TMat2[float32]: "mat2" | |
25 elif T is TMat2[float64]: "dmat2" | |
26 elif T is TMat23[float32]: "mat23" | |
27 elif T is TMat23[float64]: "dmat23" | |
28 elif T is TMat32[float32]: "mat32" | |
29 elif T is TMat32[float64]: "dmat32" | |
30 elif T is TMat3[float32]: "mat3" | |
31 elif T is TMat3[float64]: "dmat3" | |
32 elif T is TMat34[float32]: "mat34" | |
33 elif T is TMat34[float64]: "dmat34" | |
34 elif T is TMat43[float32]: "mat43" | |
35 elif T is TMat43[float64]: "dmat43" | |
36 elif T is TMat4[float32]: "mat4" | |
37 elif T is TMat4[float64]: "dmat4" | |
38 elif T is Texture: "sampler2D" | |
39 else: {.error: "Unsupported data type on GPU".} | |
40 | |
41 func VkType[T: SupportedGPUType](value: T): VkFormat = | |
42 when T is float32: VK_FORMAT_R32_SFLOAT | |
43 elif T is float64: VK_FORMAT_R64_SFLOAT | |
44 elif T is int8: VK_FORMAT_R8_SINT | |
45 elif T is int16: VK_FORMAT_R16_SINT | |
46 elif T is int32: VK_FORMAT_R32_SINT | |
47 elif T is int64: VK_FORMAT_R64_SINT | |
48 elif T is uint8: VK_FORMAT_R8_UINT | |
49 elif T is uint16: VK_FORMAT_R16_UINT | |
50 elif T is uint32: VK_FORMAT_R32_UINT | |
51 elif T is uint64: VK_FORMAT_R64_UINT | |
52 elif T is TVec2[int32]: VK_FORMAT_R32G32_SINT | |
53 elif T is TVec2[int64]: VK_FORMAT_R64G64_SINT | |
54 elif T is TVec3[int32]: VK_FORMAT_R32G32B32_SINT | |
55 elif T is TVec3[int64]: VK_FORMAT_R64G64B64_SINT | |
56 elif T is TVec4[int32]: VK_FORMAT_R32G32B32A32_SINT | |
57 elif T is TVec4[int64]: VK_FORMAT_R64G64B64A64_SINT | |
58 elif T is TVec2[uint32]: VK_FORMAT_R32G32_UINT | |
59 elif T is TVec2[uint64]: VK_FORMAT_R64G64_UINT | |
60 elif T is TVec3[uint32]: VK_FORMAT_R32G32B32_UINT | |
61 elif T is TVec3[uint64]: VK_FORMAT_R64G64B64_UINT | |
62 elif T is TVec4[uint32]: VK_FORMAT_R32G32B32A32_UINT | |
63 elif T is TVec4[uint64]: VK_FORMAT_R64G64B64A64_UINT | |
64 elif T is TVec2[float32]: VK_FORMAT_R32G32_SFLOAT | |
65 elif T is TVec2[float64]: VK_FORMAT_R64G64_SFLOAT | |
66 elif T is TVec3[float32]: VK_FORMAT_R32G32B32_SFLOAT | |
67 elif T is TVec3[float64]: VK_FORMAT_R64G64B64_SFLOAT | |
68 elif T is TVec4[float32]: VK_FORMAT_R32G32B32A32_SFLOAT | |
69 elif T is TVec4[float64]: VK_FORMAT_R64G64B64A64_SFLOAT | |
70 elif T is TMat2[float32]: VK_FORMAT_R32G32_SFLOAT | |
71 elif T is TMat2[float64]: VK_FORMAT_R64G64_SFLOAT | |
72 elif T is TMat23[float32]: VK_FORMAT_R32G32B32_SFLOAT | |
73 elif T is TMat23[float64]: VK_FORMAT_R64G64B64_SFLOAT | |
74 elif T is TMat32[float32]: VK_FORMAT_R32G32_SFLOAT | |
75 elif T is TMat32[float64]: VK_FORMAT_R64G64_SFLOAT | |
76 elif T is TMat3[float32]: VK_FORMAT_R32G32B32_SFLOAT | |
77 elif T is TMat3[float64]: VK_FORMAT_R64G64B64_SFLOAT | |
78 elif T is TMat34[float32]: VK_FORMAT_R32G32B32A32_SFLOAT | |
79 elif T is TMat34[float64]: VK_FORMAT_R64G64B64A64_SFLOAT | |
80 elif T is TMat43[float32]: VK_FORMAT_R32G32B32_SFLOAT | |
81 elif T is TMat43[float64]: VK_FORMAT_R64G64B64_SFLOAT | |
82 elif T is TMat4[float32]: VK_FORMAT_R32G32B32A32_SFLOAT | |
83 elif T is TMat4[float64]: VK_FORMAT_R64G64B64A64_SFLOAT | |
84 else: {.error: "Unsupported data type on GPU".} | |
85 | |
86 | |
87 func NumberOfVertexInputAttributeDescriptors[T: SupportedGPUType|Texture](value: T): uint32 = | |
88 when T is TMat2[float32] or T is TMat2[float64] or T is TMat23[float32] or T is TMat23[float64]: | |
89 2 | |
90 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]: | |
91 3 | |
92 elif T is TMat43[float32] or T is TMat43[float64] or T is TMat4[float32] or T is TMat4[float64]: | |
93 4 | |
94 else: | |
95 1 | |
96 | |
97 func NLocationSlots[T: SupportedGPUType|Texture](value: T): uint32 = | |
98 #[ | |
99 single location: | |
100 - any scalar | |
101 - any 16-bit vector | |
102 - any 32-bit vector | |
103 - any 64-bit vector that has max. 2 components | |
104 16-bit scalar and vector types, and | |
105 32-bit scalar and vector types, and | |
106 64-bit scalar and 2-component vector types. | |
107 two locations | |
108 64-bit three- and four-component vectors | |
109 ]# | |
110 when T is TVec3[int64] or | |
111 T is TVec4[int64] or | |
112 T is TVec3[uint64] or | |
113 T is TVec4[uint64] or | |
114 T is TVec3[float64] or | |
115 T is TVec4[float64] or | |
116 T is TMat23[float64] or | |
117 T is TMat3[float64] or | |
118 T is TMat34[float64] or | |
119 T is TMat43[float64] or | |
120 T is TMat4[float64]: | |
121 return 2 | |
122 else: | |
123 return 1 | |
124 | |
125 proc generateShaderSource[TShader](shader: TShader): (string, string) {.compileTime.} = | |
126 const GLSL_VERSION = "450" | |
127 var vsInput: seq[string] | |
128 var vsOutput: seq[string] | |
129 var fsInput: seq[string] | |
130 var fsOutput: seq[string] | |
131 var uniforms: seq[string] | |
132 var samplers: seq[string] | |
133 var vsInputLocation = 0'u32 | |
134 var passLocation = 0 | |
135 var fsOutputLocation = 0 | |
136 | |
137 var sawDescriptorSets = false | |
138 for fieldname, value in fieldPairs(shader): | |
139 # vertex shader inputs | |
140 when hasCustomPragma(value, VertexAttribute) or hasCustomPragma(value, InstanceAttribute): | |
141 assert typeof(value) is SupportedGPUType | |
142 vsInput.add "layout(location = " & $vsInputLocation & ") in " & GlslType(value) & " " & fieldname & ";" | |
143 for j in 0 ..< NumberOfVertexInputAttributeDescriptors(value): | |
144 vsInputLocation += NLocationSlots(value) | |
145 | |
146 # intermediate values, passed between shaders | |
147 elif hasCustomPragma(value, Pass) or hasCustomPragma(value, PassFlat): | |
148 let flat = if hasCustomPragma(value, PassFlat): "flat " else: "" | |
149 vsOutput.add "layout(location = " & $passLocation & ") " & flat & "out " & GlslType(value) & " " & fieldname & ";" | |
150 fsInput.add "layout(location = " & $passLocation & ") " & flat & "in " & GlslType(value) & " " & fieldname & ";" | |
151 passLocation.inc | |
152 | |
153 # fragment shader output | |
154 elif hasCustomPragma(value, ShaderOutput): | |
155 fsOutput.add &"layout(location = " & $fsOutputLocation & ") out " & GlslType(value) & " " & fieldname & ";" | |
156 fsOutputLocation.inc | |
157 | |
158 # descriptor sets | |
159 # need to consider 4 cases: uniform block, texture, uniform block array, texture array | |
160 elif hasCustomPragma(value, DescriptorSets): | |
161 assert not sawDescriptorSets, "Only one field with pragma DescriptorSets allowed per shader" | |
162 assert typeof(value) is tuple, "Descriptor field '" & fieldname & "' must be of type tuple" | |
163 assert tupleLen(typeof(value)) <= MAX_DESCRIPTORSETS, typetraits.name(TShader) & ": maximum " & $MAX_DESCRIPTORSETS & " allowed" | |
164 sawDescriptorSets = true | |
165 var descriptorSetIndex = 0 | |
166 for descriptor in value.fields: | |
167 | |
168 var descriptorBinding = 0 | |
169 | |
170 for descriptorName, descriptorValue in fieldPairs(descriptor): | |
171 | |
172 when typeof(descriptorValue) is Texture: | |
173 samplers.add "layout(set=" & $descriptorSetIndex & ", binding = " & $descriptorBinding & ") uniform " & GlslType(descriptorValue) & " " & descriptorName & ";" | |
174 descriptorBinding.inc | |
175 | |
176 elif typeof(descriptorValue) is GPUValue: | |
177 | |
178 uniforms.add "layout(set=" & $descriptorSetIndex & ", binding = " & $descriptorBinding & ") uniform T" & descriptorName & " {" | |
179 when typeof(descriptorValue.data) is object: | |
180 | |
181 for blockFieldName, blockFieldValue in descriptorValue.data.fieldPairs(): | |
182 assert typeof(blockFieldValue) is SupportedGPUType, "uniform block field '" & blockFieldName & "' is not a SupportedGPUType" | |
183 uniforms.add " " & GlslType(blockFieldValue) & " " & blockFieldName & ";" | |
184 uniforms.add "} " & descriptorName & ";" | |
185 | |
186 else: | |
187 {.error: "Unsupported shader descriptor field " & descriptorName & " (must be object)".} | |
188 descriptorBinding.inc | |
189 | |
190 elif typeof(descriptorValue) is array: | |
191 | |
192 when elementType(descriptorValue) is Texture: | |
193 | |
194 let arrayDecl = "[" & $typeof(descriptorValue).len & "]" | |
195 samplers.add "layout(set=" & $descriptorSetIndex & ", binding = " & $descriptorBinding & ") uniform " & GlslType(default(elementType(descriptorValue))) & " " & descriptorName & "" & arrayDecl & ";" | |
196 descriptorBinding.inc | |
197 | |
198 elif elementType(descriptorValue) is GPUValue: | |
199 | |
200 uniforms.add "layout(set=" & $descriptorSetIndex & ", binding = " & $descriptorBinding & ") uniform T" & descriptorName & " {" | |
201 | |
202 for blockFieldName, blockFieldValue in default(elementType(descriptorValue)).data.fieldPairs(): | |
203 assert typeof(blockFieldValue) is SupportedGPUType, "uniform block field '" & blockFieldName & "' is not a SupportedGPUType" | |
204 uniforms.add " " & GlslType(blockFieldValue) & " " & blockFieldName & ";" | |
205 uniforms.add "} " & descriptorName & "[" & $descriptorValue.len & "];" | |
206 descriptorBinding.inc | |
207 | |
208 else: | |
209 {.error: "Unsupported shader descriptor field " & descriptorName.} | |
210 | |
211 descriptorSetIndex.inc | |
212 elif fieldname in ["vertexCode", "fragmentCode"]: | |
213 discard | |
214 else: | |
215 {.error: "Unsupported shader field '" & typetraits.name(TShader) & "." & fieldname & "' of type " & typetraits.name(typeof(value)).} | |
216 | |
217 result[0] = (@[&"#version {GLSL_VERSION}", "#extension GL_EXT_scalar_block_layout : require", ""] & | |
218 vsInput & | |
219 uniforms & | |
220 samplers & | |
221 vsOutput & | |
222 @[shader.vertexCode]).join("\n") | |
223 | |
224 result[1] = (@[&"#version {GLSL_VERSION}", "#extension GL_EXT_scalar_block_layout : require", ""] & | |
225 fsInput & | |
226 uniforms & | |
227 samplers & | |
228 fsOutput & | |
229 @[shader.fragmentCode]).join("\n") | |
230 | |
231 proc compileGlslToSPIRV(stage: VkShaderStageFlagBits, shaderSource: string): seq[uint32] {.compileTime.} = | |
232 func stage2string(stage: VkShaderStageFlagBits): string {.compileTime.} = | |
233 case stage | |
234 of VK_SHADER_STAGE_VERTEX_BIT: "vert" | |
235 of VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: "tesc" | |
236 of VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: "tese" | |
237 of VK_SHADER_STAGE_GEOMETRY_BIT: "geom" | |
238 of VK_SHADER_STAGE_FRAGMENT_BIT: "frag" | |
239 of VK_SHADER_STAGE_COMPUTE_BIT: "comp" | |
240 else: "" | |
241 | |
242 when defined(nimcheck): # will not run if nimcheck is running | |
243 return result | |
244 | |
245 let | |
246 stagename = stage2string(stage) | |
247 shaderHash = hash(shaderSource) | |
248 shaderfile = getTempDir() / &"shader_{shaderHash}.{stagename}" | |
249 | |
250 if not shaderfile.fileExists: | |
251 echo "shader of type ", stage | |
252 for i, line in enumerate(shaderSource.splitlines()): | |
253 echo " ", i + 1, " ", line | |
254 var glslExe = currentSourcePath.parentDir.parentDir.parentDir / "tools" / "glslangValidator" | |
255 when defined(windows): | |
256 glslExe = glslExe & "." & ExeExt | |
257 let command = &"{glslExe} --entry-point main -V --stdin -S {stagename} -o {shaderfile}" | |
258 echo "run: ", command | |
259 discard StaticExecChecked( | |
260 command = command, | |
261 input = shaderSource | |
262 ) | |
263 else: | |
264 echo &"shaderfile {shaderfile} is up-to-date" | |
265 | |
266 when defined(mingw) and defined(linux): # required for crosscompilation, path separators get messed up | |
267 let shaderbinary = staticRead shaderfile.replace("\\", "/") | |
268 else: | |
269 let shaderbinary = staticRead shaderfile | |
270 | |
271 var i = 0 | |
272 while i < shaderbinary.len: | |
273 result.add( | |
274 (uint32(shaderbinary[i + 0]) shl 0) or | |
275 (uint32(shaderbinary[i + 1]) shl 8) or | |
276 (uint32(shaderbinary[i + 2]) shl 16) or | |
277 (uint32(shaderbinary[i + 3]) shl 24) | |
278 ) | |
279 i += 4 | |
280 | |
281 | |
282 proc CompileShader[TShader](shader: static TShader): (VkShaderModule, VkShaderModule) = | |
283 const (vertexShaderSource, fragmentShaderSource) = generateShaderSource(shader) | |
284 | |
285 let vertexBinary = compileGlslToSPIRV(VK_SHADER_STAGE_VERTEX_BIT, vertexShaderSource) | |
286 let fragmentBinary = compileGlslToSPIRV(VK_SHADER_STAGE_FRAGMENT_BIT, fragmentShaderSource) | |
287 | |
288 var createInfoVertex = VkShaderModuleCreateInfo( | |
289 sType: VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, | |
290 codeSize: csize_t(vertexBinary.len * sizeof(uint32)), | |
291 pCode: vertexBinary.ToCPointer, | |
292 ) | |
293 checkVkResult vulkan.device.vkCreateShaderModule(addr(createInfoVertex), nil, addr(result[0])) | |
294 var createInfoFragment = VkShaderModuleCreateInfo( | |
295 sType: VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, | |
296 codeSize: csize_t(fragmentBinary.len * sizeof(uint32)), | |
297 pCode: fragmentBinary.ToCPointer, | |
298 ) | |
299 checkVkResult vulkan.device.vkCreateShaderModule(addr(createInfoFragment), nil, addr(result[1])) | |
300 | |
301 template ForVertexDataFields(shader: typed, fieldname, valuename, isinstancename, body: untyped): untyped = | |
302 for theFieldname, value in fieldPairs(shader): | |
303 when hasCustomPragma(value, VertexAttribute) or hasCustomPragma(value, InstanceAttribute): | |
304 when not typeof(value) is seq: | |
305 {.error: "field '" & theFieldname & "' needs to be a seq".} | |
306 when not typeof(value) is SupportedGPUType: | |
307 {.error: "field '" & theFieldname & "' is not a supported GPU type".} | |
308 block: | |
309 const `fieldname` {.inject.} = theFieldname | |
310 let `valuename` {.inject.} = value | |
311 const `isinstancename` {.inject.} = hasCustomPragma(value, InstanceAttribute) | |
312 body | |
313 | |
314 proc GetDescriptorSetCount[TShader](): uint32 = | |
315 for _, value in fieldPairs(default(TShader)): | |
316 when hasCustomPragma(value, DescriptorSets): | |
317 return tupleLen(typeof(value)).uint32 | |
318 | |
319 proc CreateDescriptorSetLayouts[TShader](): array[MAX_DESCRIPTORSETS, VkDescriptorSetLayout] = | |
320 var setNumber: int | |
321 for _, value in fieldPairs(default(TShader)): | |
322 when hasCustomPragma(value, DescriptorSets): | |
323 for descriptorSet in value.fields: | |
324 var layoutbindings: seq[VkDescriptorSetLayoutBinding] | |
325 ForDescriptorFields(descriptorSet, fieldName, fieldValue, descriptorType, descriptorCount, descriptorBindingNumber): | |
326 layoutbindings.add VkDescriptorSetLayoutBinding( | |
327 binding: descriptorBindingNumber, | |
328 descriptorType: descriptorType, | |
329 descriptorCount: descriptorCount, | |
330 stageFlags: VkShaderStageFlags(VK_SHADER_STAGE_ALL_GRAPHICS), | |
331 pImmutableSamplers: nil, | |
332 ) | |
333 var layoutCreateInfo = VkDescriptorSetLayoutCreateInfo( | |
334 sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, | |
335 bindingCount: layoutbindings.len.uint32, | |
336 pBindings: layoutbindings.ToCPointer | |
337 ) | |
338 checkVkResult vkCreateDescriptorSetLayout( | |
339 vulkan.device, | |
340 addr(layoutCreateInfo), | |
341 nil, | |
342 addr(result[setNumber]) | |
343 ) | |
344 inc setNumber | |
345 | |
346 proc CreatePipeline*[TShader]( | |
347 renderPass: VkRenderPass, | |
348 topology: VkPrimitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, | |
349 polygonMode: VkPolygonMode = VK_POLYGON_MODE_FILL, | |
350 cullMode: VkCullModeFlagBits = VK_CULL_MODE_BACK_BIT, | |
351 frontFace: VkFrontFace = VK_FRONT_FACE_CLOCKWISE, | |
352 descriptorPoolLimit = 1024, | |
353 samples = VK_SAMPLE_COUNT_1_BIT, | |
354 ): Pipeline[TShader] = | |
355 # create pipeline | |
356 | |
357 const shader = default(TShader) | |
358 (result.vertexShaderModule, result.fragmentShaderModule) = CompileShader(shader) | |
359 | |
360 var nSets = GetDescriptorSetCount[TShader]() | |
361 result.descriptorSetLayouts = CreateDescriptorSetLayouts[TShader]() | |
362 let pipelineLayoutInfo = VkPipelineLayoutCreateInfo( | |
363 sType: VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, | |
364 setLayoutCount: nSets, | |
365 pSetLayouts: if nSets == 0: nil else: result.descriptorSetLayouts.ToCPointer, | |
366 # pushConstantRangeCount: uint32(pushConstants.len), | |
367 # pPushConstantRanges: pushConstants.ToCPointer, | |
368 ) | |
369 checkVkResult vkCreatePipelineLayout(vulkan.device, addr(pipelineLayoutInfo), nil, addr(result.layout)) | |
370 | |
371 let stages = [ | |
372 VkPipelineShaderStageCreateInfo( | |
373 sType: VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | |
374 stage: VK_SHADER_STAGE_VERTEX_BIT, | |
375 module: result.vertexShaderModule, | |
376 pName: "main", | |
377 ), | |
378 VkPipelineShaderStageCreateInfo( | |
379 sType: VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | |
380 stage: VK_SHADER_STAGE_FRAGMENT_BIT, | |
381 module: result.fragmentShaderModule, | |
382 pName: "main", | |
383 ), | |
384 ] | |
385 var | |
386 bindings: seq[VkVertexInputBindingDescription] | |
387 attributes: seq[VkVertexInputAttributeDescription] | |
388 var inputBindingNumber = 0'u32 | |
389 var location = 0'u32 | |
390 ForVertexDataFields(default(TShader), fieldname, value, isInstanceAttr): | |
391 bindings.add VkVertexInputBindingDescription( | |
392 binding: inputBindingNumber, | |
393 stride: sizeof(value).uint32, | |
394 inputRate: if isInstanceAttr: VK_VERTEX_INPUT_RATE_INSTANCE else: VK_VERTEX_INPUT_RATE_VERTEX, | |
395 ) | |
396 # allows to submit larger data structures like Mat44, for most other types will be 1 | |
397 let perDescriptorSize = sizeof(value).uint32 div NumberOfVertexInputAttributeDescriptors(value) | |
398 for i in 0'u32 ..< NumberOfVertexInputAttributeDescriptors(value): | |
399 attributes.add VkVertexInputAttributeDescription( | |
400 binding: inputBindingNumber, | |
401 location: location, | |
402 format: VkType(value), | |
403 offset: i * perDescriptorSize, | |
404 ) | |
405 location += NLocationSlots(value) | |
406 inc inputBindingNumber | |
407 | |
408 let | |
409 vertexInputInfo = VkPipelineVertexInputStateCreateInfo( | |
410 sType: VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, | |
411 vertexBindingDescriptionCount: uint32(bindings.len), | |
412 pVertexBindingDescriptions: bindings.ToCPointer, | |
413 vertexAttributeDescriptionCount: uint32(attributes.len), | |
414 pVertexAttributeDescriptions: attributes.ToCPointer, | |
415 ) | |
416 inputAssembly = VkPipelineInputAssemblyStateCreateInfo( | |
417 sType: VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, | |
418 topology: topology, | |
419 primitiveRestartEnable: false, | |
420 ) | |
421 viewportState = VkPipelineViewportStateCreateInfo( | |
422 sType: VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, | |
423 viewportCount: 1, | |
424 scissorCount: 1, | |
425 ) | |
426 rasterizer = VkPipelineRasterizationStateCreateInfo( | |
427 sType: VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, | |
428 depthClampEnable: VK_FALSE, | |
429 rasterizerDiscardEnable: VK_FALSE, | |
430 polygonMode: polygonMode, | |
431 lineWidth: 1.0, | |
432 cullMode: toBits [cullMode], | |
433 frontFace: frontFace, | |
434 depthBiasEnable: VK_FALSE, | |
435 depthBiasConstantFactor: 0.0, | |
436 depthBiasClamp: 0.0, | |
437 depthBiasSlopeFactor: 0.0, | |
438 ) | |
439 multisampling = VkPipelineMultisampleStateCreateInfo( | |
440 sType: VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, | |
441 sampleShadingEnable: VK_FALSE, | |
442 rasterizationSamples: samples, | |
443 minSampleShading: 1.0, | |
444 pSampleMask: nil, | |
445 alphaToCoverageEnable: VK_FALSE, | |
446 alphaToOneEnable: VK_FALSE, | |
447 ) | |
448 colorBlendAttachment = VkPipelineColorBlendAttachmentState( | |
449 colorWriteMask: toBits [VK_COLOR_COMPONENT_R_BIT, VK_COLOR_COMPONENT_G_BIT, VK_COLOR_COMPONENT_B_BIT, VK_COLOR_COMPONENT_A_BIT], | |
450 blendEnable: VK_TRUE, | |
451 srcColorBlendFactor: VK_BLEND_FACTOR_SRC_ALPHA, | |
452 dstColorBlendFactor: VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, | |
453 colorBlendOp: VK_BLEND_OP_ADD, | |
454 srcAlphaBlendFactor: VK_BLEND_FACTOR_ONE, | |
455 dstAlphaBlendFactor: VK_BLEND_FACTOR_ZERO, | |
456 alphaBlendOp: VK_BLEND_OP_ADD, | |
457 ) | |
458 colorBlending = VkPipelineColorBlendStateCreateInfo( | |
459 sType: VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, | |
460 logicOpEnable: false, | |
461 attachmentCount: 1, | |
462 pAttachments: addr(colorBlendAttachment), | |
463 ) | |
464 dynamicStates = [VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR] | |
465 dynamicState = VkPipelineDynamicStateCreateInfo( | |
466 sType: VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, | |
467 dynamicStateCount: dynamicStates.len.uint32, | |
468 pDynamicStates: dynamicStates.ToCPointer, | |
469 ) | |
470 let createInfo = VkGraphicsPipelineCreateInfo( | |
471 sType: VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | |
472 stageCount: 2, | |
473 pStages: stages.ToCPointer, | |
474 pVertexInputState: addr(vertexInputInfo), | |
475 pInputAssemblyState: addr(inputAssembly), | |
476 pViewportState: addr(viewportState), | |
477 pRasterizationState: addr(rasterizer), | |
478 pMultisampleState: addr(multisampling), | |
479 pDepthStencilState: nil, | |
480 pColorBlendState: addr(colorBlending), | |
481 pDynamicState: addr(dynamicState), | |
482 layout: result.layout, | |
483 renderPass: renderPass, | |
484 subpass: 0, | |
485 basePipelineHandle: VkPipeline(0), | |
486 basePipelineIndex: -1, | |
487 ) | |
488 checkVkResult vkCreateGraphicsPipelines( | |
489 vulkan.device, | |
490 VkPipelineCache(0), | |
491 1, | |
492 addr(createInfo), | |
493 nil, | |
494 addr(result.vk) | |
495 ) | |
496 | |
497 template WithPipeline*(commandbuffer: VkCommandBuffer, pipeline: Pipeline, body: untyped): untyped = | |
498 block: | |
499 vkCmdBindPipeline(commandbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.vk) | |
500 body | |
501 | |
502 proc DestroyPipeline*(pipeline: Pipeline) = | |
503 | |
504 for descriptorSetLayout in pipeline.descriptorSetLayouts: | |
505 vkDestroyDescriptorSetLayout(vulkan.device, descriptorSetLayout, nil) | |
506 | |
507 vkDestroyShaderModule(vulkan.device, pipeline.vertexShaderModule, nil) | |
508 vkDestroyShaderModule(vulkan.device, pipeline.fragmentShaderModule, nil) | |
509 vkDestroyPipelineLayout(vulkan.device, pipeline.layout, nil) | |
510 vkDestroyPipeline(vulkan.device, pipeline.vk, nil) |