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) |
