comparison static_utils.nim @ 1181:6b66e6c837bc compiletime-tests

sync to notebook in bedroom
author sam <sam@basx.dev>
date Tue, 02 Jul 2024 17:50:14 +0700
parents d554f8185815
children e9a212e9cdf7
comparison
equal deleted inserted replaced
1180:d554f8185815 1181:6b66e6c837bc
19 template PassFlat {.pragma.} 19 template PassFlat {.pragma.}
20 template ShaderOutput {.pragma.} 20 template ShaderOutput {.pragma.}
21 template VertexIndices {.pragma.} 21 template VertexIndices {.pragma.}
22 template DescriptorSet {.pragma.} 22 template DescriptorSet {.pragma.}
23 23
24 const INFLIGHTFRAMES = 2'u32
25 const MAX_DESCRIPTORSETS = 2
26 const MEMORY_ALIGNMENT = 65536'u64 # Align buffers inside memory along this alignment
27 const BUFFER_ALIGNMENT = 64'u64 # align offsets inside buffers along this alignment
28
29 # some globals that will (likely?) never change during the life time of the engine 24 # some globals that will (likely?) never change during the life time of the engine
30 type 25 type
26 DescriptorSetType = enum
27 GlobalSet
28 MaterialSet
31 VulkanGlobals = object 29 VulkanGlobals = object
32 instance: VkInstance 30 instance: VkInstance
33 device: VkDevice 31 device: VkDevice
34 physicalDevice: VkPhysicalDevice 32 physicalDevice: VkPhysicalDevice
35 queueFamilyIndex: uint32 33 queueFamilyIndex: uint32
36 queue: VkQueue 34 queue: VkQueue
35
36 const INFLIGHTFRAMES = 2'u32
37 const MAX_DESCRIPTORSETS = tt.enumLen(DescriptorSetType)
38 const MEMORY_ALIGNMENT = 65536'u64 # Align buffers inside memory along this alignment
39 const BUFFER_ALIGNMENT = 64'u64 # align offsets inside buffers along this alignment
40
37 var vulkan: VulkanGlobals 41 var vulkan: VulkanGlobals
38 42
39 type 43 type
40 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] 44 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]
41 ShaderObject[TShader] = object 45 ShaderObject[TShader] = object
146 let `valuename` {.inject.} = value 150 let `valuename` {.inject.} = value
147 const `isinstancename` {.inject.} = hasCustomPragma(value, InstanceAttribute) 151 const `isinstancename` {.inject.} = hasCustomPragma(value, InstanceAttribute)
148 body 152 body
149 153
150 template ForDescriptorSets(shader: typed, setNumber, descriptorSet, body: untyped): untyped = 154 template ForDescriptorSets(shader: typed, setNumber, descriptorSet, body: untyped): untyped =
151 var n = 0 155 var n = DescriptorSetType.low
152 for theFieldname, value in fieldPairs(shader): 156 for theFieldname, value in fieldPairs(shader):
153 when value.hasCustomPragma(DescriptorSet): 157 when value.hasCustomPragma(DescriptorSet):
154 block: 158 block:
155 let `setNumber` {.inject.} = n 159 let `setNumber` {.inject.} = n
156 let `descriptorSet` {.inject.} = value 160 let `descriptorSet` {.inject.} = value
157 body 161 body
158 n.inc 162 if n < DescriptorSetType.high:
163 n.inc
159 164
160 template ForDescriptorFields(shader: typed, fieldname, typename, countname, bindingNumber, body: untyped): untyped = 165 template ForDescriptorFields(shader: typed, fieldname, typename, countname, bindingNumber, body: untyped): untyped =
161 var `bindingNumber` {.inject.} = 1'u32 166 var `bindingNumber` {.inject.} = 1'u32
162 for theFieldname, value in fieldPairs(shader): 167 for theFieldname, value in fieldPairs(shader):
163 when typeof(value) is Texture: 168 when typeof(value) is Texture:
464 proc UpdateAllGPUBuffers[T](value: T) = 469 proc UpdateAllGPUBuffers[T](value: T) =
465 for name, fieldvalue in value.fieldPairs(): 470 for name, fieldvalue in value.fieldPairs():
466 when typeof(fieldvalue) is GPUData: 471 when typeof(fieldvalue) is GPUData:
467 UpdateGPUBuffer(fieldvalue) 472 UpdateGPUBuffer(fieldvalue)
468 473
469 proc AssertCompatible(TShader, TDescriptorSet: typedesc, DescriptorSetIndex: static int) = 474 proc AssertCompatible(TShader, TDescriptorSet: typedesc, descriptorSetType: static DescriptorSetType) =
470 ForDescriptorSets(default(TShader), setNumber, descriptorSet): 475 ForDescriptorSets(default(TShader), setNumber, descriptorSet):
471 if setNumber == DescriptorSetIndex: 476 if setNumber == descriptorSetType:
472 assert typeof(descriptorSet) is TDescriptorSet 477 assert typeof(descriptorSet) is TDescriptorSet
473 478
474 proc CreateDescriptorSet[T, TShader]( 479 proc CreateDescriptorSet[T, TShader](
475 renderData: RenderData, 480 renderData: RenderData,
476 pipeline: Pipeline[TShader], 481 pipeline: Pipeline[TShader],
477 value: T, 482 value: T,
478 setNumber: static int 483 descriptorSetType: static DescriptorSetType
479 ): array[INFLIGHTFRAMES.int, VkDescriptorSet] = 484 ): array[INFLIGHTFRAMES.int, VkDescriptorSet] =
480 485
481 static: AssertCompatible(TShader, T, setNumber) 486 static: AssertCompatible(TShader, T, descriptorSetType)
482 487
483 var layouts = newSeqWith(result.len, pipeline.descriptorSetLayouts[setNumber]) 488 var layouts = newSeqWith(result.len, pipeline.descriptorSetLayouts[descriptorSetType.int])
484 var allocInfo = VkDescriptorSetAllocateInfo( 489 var allocInfo = VkDescriptorSetAllocateInfo(
485 sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, 490 sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
486 descriptorPool: renderData.descriptorPool, 491 descriptorPool: renderData.descriptorPool,
487 descriptorSetCount: uint32(layouts.len), 492 descriptorSetCount: uint32(layouts.len),
488 pSetLayouts: layouts.ToCPointer, 493 pSetLayouts: layouts.ToCPointer,
733 ) 738 )
734 checkVkResult vkCreateDescriptorSetLayout( 739 checkVkResult vkCreateDescriptorSetLayout(
735 vulkan.device, 740 vulkan.device,
736 addr(layoutCreateInfo), 741 addr(layoutCreateInfo),
737 nil, 742 nil,
738 addr(result.descriptorSetLayouts[setNumber]) 743 addr(result.descriptorSetLayouts[setNumber.int])
739 ) 744 )
740 let pipelineLayoutInfo = VkPipelineLayoutCreateInfo( 745 let pipelineLayoutInfo = VkPipelineLayoutCreateInfo(
741 sType: VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 746 sType: VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
742 setLayoutCount: result.descriptorSetLayouts.len.uint32, 747 setLayoutCount: result.descriptorSetLayouts.len.uint32,
743 pSetLayouts: result.descriptorSetLayouts.ToCPointer, 748 pSetLayouts: result.descriptorSetLayouts.ToCPointer,
1042 maxSets: descriptorPoolLimit, 1047 maxSets: descriptorPoolLimit,
1043 ) 1048 )
1044 checkVkResult vkCreateDescriptorPool(vulkan.device, addr(poolInfo), nil, addr(result.descriptorPool)) 1049 checkVkResult vkCreateDescriptorPool(vulkan.device, addr(poolInfo), nil, addr(result.descriptorPool))
1045 1050
1046 # allocate some memory 1051 # allocate some memory
1047 var initialAllocationSize = 1_000_000_000'u64 # TODO: make this more dynamic or something 1052 var initialAllocationSize = 1_000_000_000'u64 # TODO: make this more dynamic or something?
1048 result.indirectMemory = @[(memory: AllocateIndirectMemory(size = initialAllocationSize), usedOffset: 0'u64)] 1053 result.indirectMemory = @[(memory: AllocateIndirectMemory(size = initialAllocationSize), usedOffset: 0'u64)]
1049 result.directMemory = @[(memory: AllocateDirectMemory(size = initialAllocationSize), usedOffset: 0'u64)] 1054 result.directMemory = @[(memory: AllocateDirectMemory(size = initialAllocationSize), usedOffset: 0'u64)]
1050 1055
1051 proc FlushDirectMemory(renderData: RenderData) = 1056 proc FlushDirectMemory(renderData: RenderData) =
1052 var flushRegions = newSeqOfCap[VkMappedMemoryRange](renderData.directMemory.len) 1057 var flushRegions = newSeqOfCap[VkMappedMemoryRange](renderData.directMemory.len)
1213 nil, 1218 nil,
1214 ) 1219 )
1215 ]# 1220 ]#
1216 1221
1217 proc AssertCompatible(TShader, TMesh, TInstance, TUniforms, TGlobals: typedesc) = 1222 proc AssertCompatible(TShader, TMesh, TInstance, TUniforms, TGlobals: typedesc) =
1218 # TODO: overhaul this 1223 var descriptorSetCount = 0
1224
1219 for inputName, inputValue in default(TShader).fieldPairs: 1225 for inputName, inputValue in default(TShader).fieldPairs:
1220 var foundField = false 1226 var foundField = false
1221 1227
1222 # Vertex input data 1228 # Vertex input data
1223 when hasCustomPragma(inputValue, VertexAttribute): 1229 when hasCustomPragma(inputValue, VertexAttribute):
1239 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once" 1245 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once"
1240 assert elementType(instanceValue.data) is typeof(inputValue), "Shader input " & tt.name(TShader) & "." & inputName & " is of type '" & tt.name(typeof(inputValue)) & "' but instance attribute is of type '" & tt.name(elementType(instanceValue.data)) & "'" 1246 assert elementType(instanceValue.data) is typeof(inputValue), "Shader input " & tt.name(TShader) & "." & inputName & " is of type '" & tt.name(typeof(inputValue)) & "' but instance attribute is of type '" & tt.name(elementType(instanceValue.data)) & "'"
1241 foundField = true 1247 foundField = true
1242 assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TInstance) & "'" 1248 assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TInstance) & "'"
1243 1249
1250
1251 elif hasCustomPragma(inputValue, DescriptorSet):
1252 assert descriptorSetCount < MAX_DESCRIPTORSETS, &"{tt.name(TShader)}: maximum {MAX_DESCRIPTORSETS} allowed"
1253 descriptorSetCount.inc
1254 echo "DescriptorSet: ", inputName
1255
1256 for descriptorName, descriptorValue in inputValue.fieldPairs():
1257 when typeof(descriptorValue) is Texture:
1258 echo " Texture: ", descriptorName
1259 elif typeof(descriptorValue) is GPUValue:
1260 echo " Uniform block: ", descriptorName
1261
1262 #[
1244 # Texture 1263 # Texture
1245 elif typeof(inputValue) is Texture: 1264 elif typeof(inputValue) is Texture:
1246 for uniformName, uniformValue in default(TUniforms).fieldPairs: 1265 for uniformName, uniformValue in default(TUniforms).fieldPairs:
1247 when uniformName == inputName: 1266 when uniformName == inputName:
1248 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once" 1267 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once"
1301 assert globalValue is GPUValue, "global attribute '" & globalName & "' must be of type 'GPUValue' but is of type " & tt.name(typeof(globalValue)) 1320 assert globalValue is GPUValue, "global attribute '" & globalName & "' must be of type 'GPUValue' but is of type " & tt.name(typeof(globalValue))
1302 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once" 1321 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once"
1303 assert typeof(globalValue.data) is typeof(inputValue), "Shader input " & tt.name(TShader) & "." & inputName & " is of type '" & tt.name(typeof(inputValue)) & "' but global attribute is of type '" & tt.name(typeof(globalValue.data)) & "'" 1322 assert typeof(globalValue.data) is typeof(inputValue), "Shader input " & tt.name(TShader) & "." & inputName & " is of type '" & tt.name(typeof(inputValue)) & "' but global attribute is of type '" & tt.name(typeof(globalValue.data)) & "'"
1304 foundField = true 1323 foundField = true
1305 assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TMesh) & "|" & tt.name(TGlobals) & "'" 1324 assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TMesh) & "|" & tt.name(TGlobals) & "'"
1325 ]#
1326
1327
1328
1329
1306 1330
1307 1331
1308 proc Render[TShader, TUniforms, TGlobals, TMesh, TInstance]( 1332 proc Render[TShader, TUniforms, TGlobals, TMesh, TInstance](
1309 commandBuffer: VkCommandBuffer, 1333 commandBuffer: VkCommandBuffer,
1310 pipeline: Pipeline[TShader], 1334 pipeline: Pipeline[TShader],
1311 uniforms: TUniforms, 1335 uniforms: TUniforms,
1312 globals: TGlobals, 1336 globals: TGlobals,
1313 mesh: TMesh, 1337 mesh: TMesh,
1314 instances: TInstance, 1338 instances: TInstance,
1315 ) = 1339 ) =
1316 discard 1340 static: AssertCompatible(TShader, TMesh, TInstance, TUniforms, TGlobals)
1317 # static: AssertCompatible(TShader, TMesh, TInstance, TUniforms, TGlobals)
1318 #[ 1341 #[
1319 if renderable.vertexBuffers.len > 0: 1342 if renderable.vertexBuffers.len > 0:
1320 commandBuffer.vkCmdBindVertexBuffers( 1343 commandBuffer.vkCmdBindVertexBuffers(
1321 firstBinding = 0'u32, 1344 firstBinding = 0'u32,
1322 bindingCount = uint32(renderable.vertexBuffers.len), 1345 bindingCount = uint32(renderable.vertexBuffers.len),
1517 UpdateAllGPUBuffers(instances1) 1540 UpdateAllGPUBuffers(instances1)
1518 UpdateAllGPUBuffers(uniforms1) 1541 UpdateAllGPUBuffers(uniforms1)
1519 UpdateAllGPUBuffers(myGlobals) 1542 UpdateAllGPUBuffers(myGlobals)
1520 renderdata.FlushDirectMemory() 1543 renderdata.FlushDirectMemory()
1521 1544
1522 var s1 = CreateDescriptorSet(renderdata, pipeline1, myGlobals, 0)
1523 var s2 = CreateDescriptorSet(renderdata, pipeline1, uniforms1, 1)
1524 1545
1525 # descriptors 1546 # descriptors
1547 # TODO: I think we can write and assign descriptors directly after creation
1548 var s1 = CreateDescriptorSet(renderdata, pipeline1, myGlobals, GlobalSet)
1549 var s2 = CreateDescriptorSet(renderdata, pipeline1, uniforms1, MaterialSet)
1526 # WriteDescriptors[ShaderA, UniformsA, GlobalsA](renderdata, uniforms1, myGlobals) 1550 # WriteDescriptors[ShaderA, UniformsA, GlobalsA](renderdata, uniforms1, myGlobals)
1527
1528 # create descriptor sets
1529 #[
1530 var descriptorSets: array[INFLIGHTFRAMES.int, VkDescriptorSet]
1531 var layouts = newSeqWith(descriptorSets.len, pipeline.descriptorSetLayouts)
1532 var allocInfo = VkDescriptorSetAllocateInfo(
1533 sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
1534 descriptorPool: pool,
1535 descriptorSetCount: uint32(layouts.len),
1536 pSetLayouts: layouts.ToCPointer,
1537 )
1538 checkVkResult vkAllocateDescriptorSets(device, addr(allocInfo), descriptorSets.ToCPointer)
1539 ]#
1540 1551
1541 1552
1542 1553
1543 # command buffer 1554 # command buffer
1544 var 1555 var