Mercurial > games > semicongine
comparison static_utils.nim @ 1176:511c9f7cd1da compiletime-tests
sync to notebook in bedroom
author | sam <sam@basx.dev> |
---|---|
date | Sat, 29 Jun 2024 21:04:04 +0700 |
parents | fafc2f14da0b |
children | 4ef959278451 |
comparison
equal
deleted
inserted
replaced
1175:a94732d98cc6 | 1176:511c9f7cd1da |
---|---|
19 template Pass* {.pragma.} | 19 template Pass* {.pragma.} |
20 template PassFlat* {.pragma.} | 20 template PassFlat* {.pragma.} |
21 template ShaderOutput* {.pragma.} | 21 template ShaderOutput* {.pragma.} |
22 | 22 |
23 const INFLIGHTFRAMES = 2'u32 | 23 const INFLIGHTFRAMES = 2'u32 |
24 | |
24 type | 25 type |
25 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] | 26 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] |
26 ShaderObject*[TShader] = object | 27 ShaderObject*[TShader] = object |
27 vertexShader: VkShaderModule | 28 vertexShader: VkShaderModule |
28 fragmentShader: VkShaderModule | 29 fragmentShader: VkShaderModule |
123 let `fieldname` {.inject.} = theFieldname | 124 let `fieldname` {.inject.} = theFieldname |
124 let `valuename` {.inject.} = value | 125 let `valuename` {.inject.} = value |
125 let `isinstancename` {.inject.} = hasCustomPragma(value, InstanceAttribute) | 126 let `isinstancename` {.inject.} = hasCustomPragma(value, InstanceAttribute) |
126 body | 127 body |
127 | 128 |
128 template ForDescriptorFields*(inputData: typed, typename, countname, bindingNumber, body: untyped): untyped = | 129 template ForDescriptorFields*(inputData: typed, fieldname, typename, countname, bindingNumber, body: untyped): untyped = |
129 var `bindingNumber` {.inject.} = 1'u32 | 130 var `bindingNumber` {.inject.} = 1'u32 |
130 for theFieldname, value in fieldPairs(inputData): | 131 for theFieldname, value in fieldPairs(inputData): |
132 let `fieldname` {.inject.} = theFieldname | |
131 when typeof(value) is Texture: | 133 when typeof(value) is Texture: |
132 block: | 134 block: |
133 let `typename` {.inject.} = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER | 135 let `typename` {.inject.} = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER |
134 let `countname` {.inject.} = 1'u32 | 136 let `countname` {.inject.} = 1'u32 |
135 body | 137 body |
193 return 1 | 195 return 1 |
194 | 196 |
195 type | 197 type |
196 IndexType = enum | 198 IndexType = enum |
197 None, UInt8, UInt16, UInt32 | 199 None, UInt8, UInt16, UInt32 |
198 RenderBuffers = object | 200 |
199 deviceBuffers: seq[Buffer] # for fast reads | 201 IndirectGPUMemory = object |
200 hostVisibleBuffers: seq[Buffer] # for fast writes | 202 vk: VkDeviceMemory |
203 size: uint64 | |
204 DirectGPUMemory = object | |
205 vk: VkDeviceMemory | |
206 size: uint64 | |
207 data: pointer | |
208 GPUMemory = IndirectGPUMemory | DirectGPUMemory | |
209 | |
210 Buffer[TMemory: GPUMemory] = object | |
211 vk: VkBuffer | |
212 memory*: TMemory | |
213 offset: uint64 | |
214 size: uint64 | |
215 | |
216 GPUArray[T: SupportedGPUType, TMemory: GPUMemory] = object | |
217 data: seq[T] | |
218 buffer: Buffer[TMemory] | |
219 offset: uint64 | |
220 GPUValue[T: object|array, TMemory: GPUMemory] = object | |
221 data: T | |
222 buffer: Buffer[TMemory] | |
223 offset: uint64 | |
224 | |
201 Renderable[TMesh, TInstance] = object | 225 Renderable[TMesh, TInstance] = object |
202 vertexBuffers: seq[VkBuffer] | 226 vertexBuffers: seq[VkBuffer] |
203 bufferOffsets: seq[VkDeviceSize] | 227 bufferOffsets: seq[VkDeviceSize] |
204 instanceCount: uint32 | 228 instanceCount: uint32 |
205 case indexType: IndexType | 229 case indexType: IndexType |
207 vertexCount: uint32 | 231 vertexCount: uint32 |
208 else: | 232 else: |
209 indexBuffer: VkBuffer | 233 indexBuffer: VkBuffer |
210 indexCount: uint32 | 234 indexCount: uint32 |
211 indexBufferOffset: VkDeviceSize | 235 indexBufferOffset: VkDeviceSize |
236 | |
212 Pipeline[TShader] = object | 237 Pipeline[TShader] = object |
213 pipeline: VkPipeline | 238 pipeline: VkPipeline |
214 layout: VkPipelineLayout | 239 layout: VkPipelineLayout |
215 descriptorSets: array[INFLIGHTFRAMES.int, VkDescriptorSet] | 240 descriptorSetLayout: VkDescriptorSetLayout |
241 RenderData = object | |
242 descriptorPool: VkDescriptorPool | |
243 indirectMemory: seq[IndirectGPUMemory] | |
244 nextFreeIndirectMemoryOffset: seq[uint64] | |
245 indirectBuffers: seq[Buffer[IndirectGPUMemory]] | |
246 directMemory: seq[DirectGPUMemory] | |
247 nextFreeDirectMemoryOffset: seq[uint64] | |
248 directBuffers: seq[Buffer[DirectGPUMemory]] | |
216 | 249 |
217 converter toVkIndexType(indexType: IndexType): VkIndexType = | 250 converter toVkIndexType(indexType: IndexType): VkIndexType = |
218 case indexType: | 251 case indexType: |
219 of None: VK_INDEX_TYPE_NONE_KHR | 252 of None: VK_INDEX_TYPE_NONE_KHR |
220 of UInt8: VK_INDEX_TYPE_UINT8_EXT | 253 of UInt8: VK_INDEX_TYPE_UINT8_EXT |
422 shader: ShaderObject[TShader], | 455 shader: ShaderObject[TShader], |
423 topology: VkPrimitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, | 456 topology: VkPrimitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, |
424 polygonMode: VkPolygonMode = VK_POLYGON_MODE_FILL, | 457 polygonMode: VkPolygonMode = VK_POLYGON_MODE_FILL, |
425 cullMode: VkCullModeFlagBits = VK_CULL_MODE_BACK_BIT, | 458 cullMode: VkCullModeFlagBits = VK_CULL_MODE_BACK_BIT, |
426 frontFace: VkFrontFace = VK_FRONT_FACE_CLOCKWISE, | 459 frontFace: VkFrontFace = VK_FRONT_FACE_CLOCKWISE, |
460 descriptorPoolLimit = 1024 | |
427 ): Pipeline[TShader] = | 461 ): Pipeline[TShader] = |
428 # assumptions/limitations: | |
429 # - we are only using vertex and fragment shaders (2 stages) | |
430 # - we only support one subpass | |
431 # = we only support one Uniform-Block | |
432 | |
433 # create pipeline | 462 # create pipeline |
434 var layoutbindings: seq[VkDescriptorSetLayoutBinding] | 463 var layoutbindings: seq[VkDescriptorSetLayoutBinding] |
435 ForDescriptorFields(default(TShader), descriptorType, descriptorCount, descriptorBindingNumber): | 464 ForDescriptorFields(default(TShader), fieldName, descriptorType, descriptorCount, descriptorBindingNumber): |
436 layoutbindings.add VkDescriptorSetLayoutBinding( | 465 layoutbindings.add VkDescriptorSetLayoutBinding( |
437 binding: descriptorBindingNumber, | 466 binding: descriptorBindingNumber, |
438 descriptorType: descriptorType, | 467 descriptorType: descriptorType, |
439 descriptorCount: descriptorCount, | 468 descriptorCount: descriptorCount, |
440 stageFlags: VkShaderStageFlags(VK_SHADER_STAGE_ALL_GRAPHICS), | 469 stageFlags: VkShaderStageFlags(VK_SHADER_STAGE_ALL_GRAPHICS), |
443 var layoutCreateInfo = VkDescriptorSetLayoutCreateInfo( | 472 var layoutCreateInfo = VkDescriptorSetLayoutCreateInfo( |
444 sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, | 473 sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, |
445 bindingCount: uint32(layoutbindings.len), | 474 bindingCount: uint32(layoutbindings.len), |
446 pBindings: layoutbindings.ToCPointer | 475 pBindings: layoutbindings.ToCPointer |
447 ) | 476 ) |
448 var descriptorSetLayout: VkDescriptorSetLayout | 477 result.descriptorSetLayout: VkDescriptorSetLayout |
449 checkVkResult vkCreateDescriptorSetLayout(device, addr(layoutCreateInfo), nil, addr(descriptorSetLayout)) | 478 checkVkResult vkCreateDescriptorSetLayout(device, addr(layoutCreateInfo), nil, addr(result.descriptorSetLayout)) |
450 let pipelineLayoutInfo = VkPipelineLayoutCreateInfo( | 479 let pipelineLayoutInfo = VkPipelineLayoutCreateInfo( |
451 sType: VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, | 480 sType: VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, |
452 setLayoutCount: 1, | 481 setLayoutCount: 1, |
453 pSetLayouts: addr(descriptorSetLayout), | 482 pSetLayouts: addr(result.descriptorSetLayout), |
454 # pushConstantRangeCount: uint32(pushConstants.len), | 483 # pushConstantRangeCount: uint32(pushConstants.len), |
455 # pPushConstantRanges: pushConstants.ToCPointer, | 484 # pPushConstantRanges: pushConstants.ToCPointer, |
456 ) | 485 ) |
457 checkVkResult vkCreatePipelineLayout(device, addr(pipelineLayoutInfo), nil, addr(result.layout)) | 486 checkVkResult vkCreatePipelineLayout(device, addr(pipelineLayoutInfo), nil, addr(result.layout)) |
458 | 487 |
580 addr(createInfo), | 609 addr(createInfo), |
581 nil, | 610 nil, |
582 addr(result.pipeline) | 611 addr(result.pipeline) |
583 ) | 612 ) |
584 | 613 |
585 # create descriptors, one per frame-in-flight | 614 proc AllocateIndirectMemory(device: VkDevice, pDevice: VkPhysicalDevice, allocationSize: uint64): IndirectGPUMemory = |
586 let nSamplers = 0'u32 | 615 # chooses biggest memory type that has NOT VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
587 let nUniformBuffers = 0'u32 | 616 result.size = allocationSize |
588 | 617 |
589 if nSamplers + nUniformBuffers > 0: | 618 # find a good memory type |
590 var poolSizes: seq[VkDescriptorPoolSize] | 619 var physicalProperties: VkPhysicalDeviceMemoryProperties |
591 if nUniformBuffers > 0: | 620 vkGetPhysicalDeviceMemoryProperties(pDevice, addr physicalProperties) |
592 poolSizes.add VkDescriptorPoolSize(thetype: VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, descriptorCount: nSamplers * INFLIGHTFRAMES) | 621 |
593 if nSamplers > 0: | 622 var biggestHeap: uint64 = -1 |
594 poolSizes.add VkDescriptorPoolSize(thetype: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount: nUniformBuffers * INFLIGHTFRAMES) | 623 var memoryTypeIndex = -1 |
595 var poolInfo = VkDescriptorPoolCreateInfo( | 624 # try to find non-host-visible type |
596 sType: VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, | 625 for i in 0 ..< physicalProperties.memoryTypeCount: |
597 poolSizeCount: uint32(poolSizes.len), | 626 if VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT not in toEnums(physicalProperties.memoryTypes[i].propertyFlags) |
598 pPoolSizes: poolSizes.ToCPointer, | 627 let size = physicalProperties.memoryHeaps[physicalProperties.memoryTypes[i].heapIndex].size |
599 maxSets: (nUniformBuffers + nSamplers) * INFLIGHTFRAMES * 2, # good formula? no idea... | 628 if size > biggestHeap: |
600 ) | 629 biggest = size |
601 var pool: VkDescriptorPool | 630 memoryTypeIndex = i |
602 checkVkResult vkCreateDescriptorPool(device, addr(poolInfo), nil, addr(pool)) | 631 |
603 | 632 # If we did not found a device-only memory type, let's just take the biggest overall |
604 var layouts = newSeqWith(result.descriptorSets.len, descriptorSetLayout) | 633 if memoryTypeIndex < 0: |
605 var allocInfo = VkDescriptorSetAllocateInfo( | 634 for i in 0 ..< physicalProperties.memoryTypeCount: |
606 sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, | 635 let size = physicalProperties.memoryHeaps[physicalProperties.memoryTypes[i].heapIndex].size |
607 descriptorPool: pool, | 636 if size > biggestHeap: |
608 descriptorSetCount: uint32(layouts.len), | 637 biggest = size |
609 pSetLayouts: layouts.ToCPointer, | 638 memoryTypeIndex = i |
610 ) | 639 |
611 checkVkResult vkAllocateDescriptorSets(device, addr(allocInfo), result.descriptorSets.ToCPointer) | 640 assert memoryTypeIndex >= 0, "Unable to find indirect memory type" |
641 var allocationInfo = VkMemoryAllocateInfo( | |
642 sType: VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, | |
643 allocationSize: initialAllocationSize, | |
644 memoryTypeIndex: memoryTypeIndex, | |
645 ) | |
646 checkVkResult vkAllocateMemory( | |
647 device, | |
648 addr allocationInfo, | |
649 nil, | |
650 addr result.vk | |
651 ) | |
652 | |
653 proc AllocateDirectMemory(device: VkDevice, allocationSize: uint64): DirectGPUMemory = | |
654 result.size = allocationSize | |
655 | |
656 # find a good memory type | |
657 var physicalProperties: VkPhysicalDeviceMemoryProperties | |
658 vkGetPhysicalDeviceMemoryProperties(pDevice, addr physicalProperties) | |
659 | |
660 var biggestHeap: uint64 = -1 | |
661 var memoryTypeIndex = -1 | |
662 # try to find host-visible type | |
663 for i in 0 ..< physicalProperties.memoryTypeCount: | |
664 if VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT in toEnums(physicalProperties.memoryTypes[i].propertyFlags) | |
665 let size = physicalProperties.memoryHeaps[physicalProperties.memoryTypes[i].heapIndex].size | |
666 if size > biggestHeap: | |
667 biggest = size | |
668 memoryTypeIndex = i | |
669 | |
670 assert memoryTypeIndex >= 0, "Unable to find direct (aka host-visible) memory type" | |
671 var allocationInfo = VkMemoryAllocateInfo( | |
672 sType: VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, | |
673 allocationSize: initialAllocationSize, | |
674 memoryTypeIndex: memoryTypeIndex, | |
675 ) | |
676 checkVkResult vkAllocateMemory( | |
677 device, | |
678 addr allocationInfo, | |
679 nil, | |
680 addr result.vk | |
681 ) | |
682 checkVkResult result.device.vk.vkMapMemory( | |
683 memory = result.vk, | |
684 offset = 0'u64, | |
685 size = result.size, | |
686 flags = VkMemoryMapFlags(0), | |
687 ppData = addr(result.data) | |
688 ) | |
689 | |
690 proc InitRenderData(device: VkDevice, descriptorPoolLimit = 1024): RenderData = | |
691 # allocate descriptor pools | |
692 var poolSizes = [ | |
693 VkDescriptorPoolSize(thetype: VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, descriptorCount: descriptorPoolLimit) | |
694 VkDescriptorPoolSize(thetype: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount: descriptorPoolLimit) | |
695 ] | |
696 var poolInfo = VkDescriptorPoolCreateInfo( | |
697 sType: VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, | |
698 poolSizeCount: poolSizes.len.uint32, | |
699 pPoolSizes: poolSizes.ToCPointer, | |
700 maxSets: descriptorPoolLimit, | |
701 ) | |
702 checkVkResult vkCreateDescriptorPool(device, addr(poolInfo), nil, addr(result.descriptorPool)) | |
703 | |
704 # allocate some memory | |
705 var initialAllocationSize: 1_000_000_000 # TODO: make this more dynamic or something | |
706 result.indirectMemory = @[AllocateIndirectMemory(device, size=initialAllocationSize)] | |
707 result.nextFreeIndirectMemoryOffset = @[0'u64] | |
708 result.directMemory = @[AllocateDirectMemory(device, size=initialAllocationSize)] | |
709 result.nextFreeDirectMemoryOffset = @[0'u64] | |
612 | 710 |
613 proc WriteDescriptors[TShader](device: VkDevice, pipeline: Pipeline[TShader]) = | 711 proc WriteDescriptors[TShader](device: VkDevice, pipeline: Pipeline[TShader]) = |
614 var descriptorSetWrites: seq[VkWriteDescriptorSet] | 712 var descriptorSetWrites: seq[VkWriteDescriptorSet] |
615 ForDescriptorFields(default(TShader), descriptorType, descriptorCount, descriptorBindingNumber): | 713 # map (buffer + offset + range) to descriptor |
714 # map (texture) to descriptor | |
715 ForDescriptorFields(default(TShader), fieldName, descriptorType, descriptorCount, descriptorBindingNumber): | |
616 for frameInFlight in 0 ..< pipeline.descriptorSets.len: | 716 for frameInFlight in 0 ..< pipeline.descriptorSets.len: |
617 if descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: | 717 if descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: |
618 # TODO | 718 # TODO |
619 let bufferInfo = VkDescriptorBufferInfo( | 719 let bufferInfo = VkDescriptorBufferInfo( |
620 buffer: VkBuffer(0), | 720 buffer: VkBuffer(0), |
651 vkUpdateDescriptorSets(device, uint32(descriptorSetWrites.len), descriptorSetWrites.ToCPointer, 0, nil) | 751 vkUpdateDescriptorSets(device, uint32(descriptorSetWrites.len), descriptorSetWrites.ToCPointer, 0, nil) |
652 | 752 |
653 proc CreateRenderable[TMesh, TInstance]( | 753 proc CreateRenderable[TMesh, TInstance]( |
654 mesh: TMesh, | 754 mesh: TMesh, |
655 instance: TInstance, | 755 instance: TInstance, |
656 buffers: RenderBuffers, | |
657 ): Renderable[TMesh, TInstance] = | 756 ): Renderable[TMesh, TInstance] = |
658 result.indexType = None | 757 result.indexType = None |
659 | 758 |
660 proc Bind[T](pipeline: Pipeline[T], commandBuffer: VkCommandBuffer, currentFrameInFlight: int) = | 759 proc Bind[T](pipeline: Pipeline[T], commandBuffer: VkCommandBuffer, currentFrameInFlight: int) = |
661 let a = pipeline.descriptorSets | 760 let a = pipeline.descriptorSets |
674 proc AssertCompatible(TShader, TMesh, TInstance, TGlobals: typedesc) = | 773 proc AssertCompatible(TShader, TMesh, TInstance, TGlobals: typedesc) = |
675 # assert seq-fields of TMesh|TInstance == seq-fields of TShader | 774 # assert seq-fields of TMesh|TInstance == seq-fields of TShader |
676 # assert normal fields of TMesh|Globals == normal fields of TShaderDescriptors | 775 # assert normal fields of TMesh|Globals == normal fields of TShaderDescriptors |
677 for inputName, inputValue in default(TShader).fieldPairs: | 776 for inputName, inputValue in default(TShader).fieldPairs: |
678 var foundField = false | 777 var foundField = false |
778 | |
779 # Vertex input data | |
679 when hasCustomPragma(inputValue, VertexAttribute): | 780 when hasCustomPragma(inputValue, VertexAttribute): |
680 assert typeof(inputValue) is SupportedGPUType | 781 assert typeof(inputValue) is SupportedGPUType |
681 for meshName, meshValue in default(TMesh).fieldPairs: | 782 for meshName, meshValue in default(TMesh).fieldPairs: |
682 when meshName == inputName: | 783 when meshName == inputName: |
784 assert meshValue is GPUArray, "Mesh attribute '" & meshName & "' must be of type 'GPUArray' but is of type " & tt.name(typeof(meshValue)) | |
683 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once" | 785 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once" |
684 assert elementType(meshValue) is typeof(inputValue), "Shader input " & tt.name(TShader) & "." & inputName & " is of type '" & tt.name(typeof(inputValue)) & "' but mesh attribute is of type '" & tt.name(elementType(meshValue)) & "'" | 786 assert elementType(meshValue.data) is typeof(inputValue), "Shader input " & tt.name(TShader) & "." & inputName & " is of type '" & tt.name(typeof(inputValue)) & "' but mesh attribute is of type '" & tt.name(elementType(meshValue.data)) & "'" |
685 foundField = true | 787 foundField = true |
686 assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TMesh) & "'" | 788 assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TMesh) & "'" |
789 | |
790 # Instance input data | |
687 elif hasCustomPragma(inputValue, InstanceAttribute): | 791 elif hasCustomPragma(inputValue, InstanceAttribute): |
688 assert typeof(inputValue) is SupportedGPUType | 792 assert typeof(inputValue) is SupportedGPUType |
689 for instanceName, instanceValue in default(TInstance).fieldPairs: | 793 for instanceName, instanceValue in default(TInstance).fieldPairs: |
690 when instanceName == inputName: | 794 when instanceName == inputName: |
795 assert instanceValue is GPUArray, "Instance attribute '" & instanceName & "' must be of type 'GPUArray' but is of type " & tt.name(typeof(instanceName)) | |
691 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once" | 796 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once" |
692 assert elementType(instanceValue) 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)) & "'" | 797 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)) & "'" |
693 foundField = true | 798 foundField = true |
694 assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TInstance) & "'" | 799 assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TInstance) & "'" |
695 elif typeof(inputValue) is Texture or typeof(inputValue) is object: | 800 |
801 # Texture | |
802 elif typeof(inputValue) is Texture: | |
696 for meshName, meshValue in default(TMesh).fieldPairs: | 803 for meshName, meshValue in default(TMesh).fieldPairs: |
697 when meshName == inputName: | 804 when meshName == inputName: |
698 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once" | 805 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once" |
699 assert typeof(meshValue) is typeof(inputValue), "Shader input " & tt.name(TShader) & "." & inputName & " is of type '" & tt.name(typeof(inputValue)) & "' but mesh attribute is of type '" & tt.name(elementType(meshValue)) & "'" | 806 assert typeof(meshValue) is typeof(inputValue), "Shader input " & tt.name(TShader) & "." & inputName & " is of type '" & tt.name(typeof(inputValue)) & "' but mesh attribute is of type '" & tt.name(elementType(meshValue)) & "'" |
700 foundField = true | 807 foundField = true |
702 when globalName == inputName: | 809 when globalName == inputName: |
703 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once" | 810 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once" |
704 assert typeof(globalValue) 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)) & "'" | 811 assert typeof(globalValue) 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)) & "'" |
705 foundField = true | 812 foundField = true |
706 assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TMesh) & "|" & tt.name(TGlobals) & "'" | 813 assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TMesh) & "|" & tt.name(TGlobals) & "'" |
814 | |
815 # Uniform block | |
816 elif typeof(inputValue) is object: | |
817 for meshName, meshValue in default(TMesh).fieldPairs: | |
818 when meshName == inputName: | |
819 assert meshValue is GPUValue, "Mesh attribute '" & meshName & "' must be of type 'GPUValue' but is of type " & tt.name(typeof(meshValue)) | |
820 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once" | |
821 assert typeof(meshValue.data) is typeof(inputValue), "Shader input " & tt.name(TShader) & "." & inputName & " is of type '" & tt.name(typeof(inputValue)) & "' but mesh attribute is of type '" & tt.name(elementType(meshValue.data)) & "'" | |
822 foundField = true | |
823 for globalName, globalValue in default(TGlobals).fieldPairs: | |
824 when globalName == inputName: | |
825 assert globalValue is GPUValue, "global attribute '" & globalName & "' must be of type 'GPUValue' but is of type " & tt.name(typeof(globalValue)) | |
826 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once" | |
827 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)) & "'" | |
828 foundField = true | |
829 assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TMesh) & "|" & tt.name(TGlobals) & "'" | |
830 | |
831 # array | |
707 elif typeof(inputValue) is array: | 832 elif typeof(inputValue) is array: |
708 when (elementType(inputValue) is Texture or elementType(inputValue) is object): | 833 |
834 # texture-array | |
835 when elementType(inputValue) is Texture: | |
709 for meshName, meshValue in default(TMesh).fieldPairs: | 836 for meshName, meshValue in default(TMesh).fieldPairs: |
710 when meshName == inputName: | 837 when meshName == inputName: |
711 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once" | 838 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once" |
712 assert typeof(meshValue) is typeof(inputValue), "Shader input " & tt.name(TShader) & "." & inputName & " is of type '" & tt.name(typeof(inputValue)) & "' but mesh attribute is of type '" & tt.name(elementType(meshValue)) & "'" | 839 assert typeof(meshValue) is typeof(inputValue), "Shader input " & tt.name(TShader) & "." & inputName & " is of type '" & tt.name(typeof(inputValue)) & "' but mesh attribute is of type '" & tt.name(elementType(meshValue)) & "'" |
713 foundField = true | 840 foundField = true |
714 for globalName, globalValue in default(TGlobals).fieldPairs: | 841 for globalName, globalValue in default(TGlobals).fieldPairs: |
715 when globalName == inputName: | 842 when globalName == inputName: |
716 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once" | 843 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once" |
717 assert typeof(globalValue) 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)) & "'" | 844 assert typeof(globalValue) 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)) & "'" |
845 foundField = true | |
846 assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TMesh) & "|" & tt.name(TGlobals) & "'" | |
847 | |
848 # uniform-block array | |
849 elif elementType(inputValue) is object: | |
850 for meshName, meshValue in default(TMesh).fieldPairs: | |
851 when meshName == inputName: | |
852 assert meshValue is GPUValue, "Mesh attribute '" & meshName & "' must be of type 'GPUValue' but is of type " & tt.name(typeof(meshValue)) | |
853 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once" | |
854 assert typeof(meshValue.data) is typeof(inputValue), "Shader input " & tt.name(TShader) & "." & inputName & " is of type '" & tt.name(typeof(inputValue)) & "' but mesh attribute is of type '" & tt.name(elementType(meshValue.data)) & "'" | |
855 foundField = true | |
856 for globalName, globalValue in default(TGlobals).fieldPairs: | |
857 when globalName == inputName: | |
858 assert globalValue is GPUValue, "global attribute '" & globalName & "' must be of type 'GPUValue' but is of type " & tt.name(typeof(globalValue)) | |
859 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once" | |
860 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)) & "'" | |
718 foundField = true | 861 foundField = true |
719 assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TMesh) & "|" & tt.name(TGlobals) & "'" | 862 assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TMesh) & "|" & tt.name(TGlobals) & "'" |
720 | 863 |
721 | 864 |
722 proc Render[TShader, TMesh, TInstance, TGlobals]( | 865 proc Render[TShader, TMesh, TInstance, TGlobals]( |
766 reflection: float32 | 909 reflection: float32 |
767 baseColor: Vec3f | 910 baseColor: Vec3f |
768 ShaderSettings = object | 911 ShaderSettings = object |
769 brightness: float32 | 912 brightness: float32 |
770 MeshA = object | 913 MeshA = object |
771 position: seq[Vec3f] | 914 position: GPUArray[Vec3f, IndirectGPUMemory] |
772 transparency: float | 915 InstanceA = object |
773 material: array[3, MaterialA] | 916 rotation: GPUArray[Vec4f, IndirectGPUMemory] |
917 objPosition: GPUArray[Vec3f, IndirectGPUMemory] | |
918 UniformsA = object | |
919 materials: GPUValue[array[3, MaterialA], IndirectGPUMemory] | |
774 materialTextures: array[3, Texture] | 920 materialTextures: array[3, Texture] |
775 InstanceA = object | 921 GlobalsA = object |
776 transform: seq[Mat4] | |
777 position: seq[Vec3f] | |
778 Globals = object | |
779 fontAtlas: Texture | 922 fontAtlas: Texture |
780 settings: ShaderSettings | 923 settings: GPUValue[ShaderSettings, IndirectGPUMemory] |
781 | 924 |
782 ShaderA = object | 925 ShaderA = object |
783 # vertex input | 926 # vertex input |
784 position {.VertexAttribute.}: Vec3f | 927 position {.VertexAttribute.}: Vec3f |
785 transform {.InstanceAttribute.}: Mat4 | 928 objPosition {.InstanceAttribute.}: Vec3f |
929 rotation {.InstanceAttribute.}: Vec4f | |
786 # intermediate | 930 # intermediate |
787 test {.Pass.}: float32 | 931 test {.Pass.}: float32 |
788 test1 {.PassFlat.}: Vec3f | 932 test1 {.PassFlat.}: Vec3f |
789 # output | 933 # output |
790 color {.ShaderOutput.}: Vec4f | 934 color {.ShaderOutput.}: Vec4f |
791 # uniforms | 935 # uniforms |
792 material: array[3, MaterialA] | 936 materials: array[3, MaterialA] |
793 settings: ShaderSettings | 937 settings: ShaderSettings |
794 # textures | 938 # textures |
795 fontAtlas: Texture | 939 fontAtlas: Texture |
796 materialTextures: array[3, Texture] | 940 materialTextures: array[3, Texture] |
797 # code | 941 # code |
804 vulkanVersion = VK_MAKE_API_VERSION(0, 1, 3, 0), | 948 vulkanVersion = VK_MAKE_API_VERSION(0, 1, 3, 0), |
805 instanceExtensions = @[], | 949 instanceExtensions = @[], |
806 layers = @["VK_LAYER_KHRONOS_validation"], | 950 layers = @["VK_LAYER_KHRONOS_validation"], |
807 ) | 951 ) |
808 | 952 |
809 | |
810 let selectedPhysicalDevice = i.GetPhysicalDevices().FilterBestGraphics() | 953 let selectedPhysicalDevice = i.GetPhysicalDevices().FilterBestGraphics() |
811 let dev = i.CreateDevice( | 954 let dev = i.CreateDevice( |
812 selectedPhysicalDevice, | 955 selectedPhysicalDevice, |
813 enabledExtensions = @[], | 956 enabledExtensions = @[], |
814 selectedPhysicalDevice.FilterForGraphicsPresentationQueues() | 957 selectedPhysicalDevice.FilterForGraphicsPresentationQueues() |
815 ) | 958 ) |
816 let frameWidth = 100'u32 | 959 let frameWidth = 100'u32 |
817 let frameHeight = 100'u32 | 960 let frameHeight = 100'u32 |
818 | 961 |
819 var myRenderable: Renderable[MeshA, InstanceA] | 962 var myMesh1 = MeshA( |
820 var myGlobals: Globals | 963 position: GPUArray[Vec3f, IndirectGPUMemory](data: @[NewVec3f(0, 0, ), NewVec3f(0, 0, ), NewVec3f(0, 0, )]), |
964 ) | |
965 var uniforms1 = UniformsA( | |
966 materials: GPUValue[array[3, MaterialA], IndirectGPUMemory](data: [ | |
967 MaterialA(reflection: 0, baseColor: NewVec3f(1, 0, 0)), | |
968 MaterialA(reflection: 0.1, baseColor: NewVec3f(0, 1, 0)), | |
969 MaterialA(reflection: 0.5, baseColor: NewVec3f(0, 0, 1)), | |
970 ]), | |
971 materialTextures: [ | |
972 Texture(isGrayscale: false, colorImage: Image[RGBAPixel](width: 1, height: 1, imagedata: @[[255'u8, 0'u8, 0'u8, 255'u8]])), | |
973 Texture(isGrayscale: false, colorImage: Image[RGBAPixel](width: 1, height: 1, imagedata: @[[0'u8, 255'u8, 0'u8, 255'u8]])), | |
974 Texture(isGrayscale: false, colorImage: Image[RGBAPixel](width: 1, height: 1, imagedata: @[[0'u8, 0'u8, 255'u8, 255'u8]])), | |
975 ] | |
976 ) | |
977 var instances1 = InstanceA( | |
978 rotation: GPUArray[Vec4f, IndirectGPUMemory](data: @[NewVec4f(1, 0, 0, 0.1), NewVec4f(0, 1, 0, 0.1)]), | |
979 objPosition: GPUArray[Vec3f, IndirectGPUMemory](data: @[NewVec3f(0, 0, 0), NewVec3f(1, 1, 1)]), | |
980 ) | |
981 var myGlobals: GlobalsA | |
821 | 982 |
822 # setup for rendering (TODO: swapchain & framebuffers) | 983 # setup for rendering (TODO: swapchain & framebuffers) |
823 | 984 |
824 # renderpass | 985 # renderpass |
825 let renderpass = dev.vk.CreateRenderPass(dev.physicalDevice.GetSurfaceFormats().FilterSurfaceFormat().format) | 986 let renderpass = dev.vk.CreateRenderPass(dev.physicalDevice.GetSurfaceFormats().FilterSurfaceFormat().format) |
827 # shaders | 988 # shaders |
828 const shader = ShaderA() | 989 const shader = ShaderA() |
829 let shaderObject = dev.vk.CompileShader(shader) | 990 let shaderObject = dev.vk.CompileShader(shader) |
830 var pipeline1 = CreatePipeline(dev.vk, renderPass = renderpass, shaderObject) | 991 var pipeline1 = CreatePipeline(dev.vk, renderPass = renderpass, shaderObject) |
831 | 992 |
993 var renderdata = InitRenderData(dev.vk) | |
994 | |
995 # create descriptor sets | |
996 var descriptorSets: array[INFLIGHTFRAMES.int, VkDescriptorSet] | |
997 var layouts = newSeqWith(descriptorSets.len, pipeline.descriptorSetLayout) | |
998 var allocInfo = VkDescriptorSetAllocateInfo( | |
999 sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, | |
1000 descriptorPool: pool, | |
1001 descriptorSetCount: uint32(layouts.len), | |
1002 pSetLayouts: layouts.ToCPointer, | |
1003 ) | |
1004 checkVkResult vkAllocateDescriptorSets(device, addr(allocInfo), descriptorSets.ToCPointer) | |
1005 | |
1006 | |
1007 #[ | |
832 # TODO: probably here: allocate renderables, uniform buffers & textures | 1008 # TODO: probably here: allocate renderables, uniform buffers & textures |
1009 let meshBuffers: seq[(bool, uint64)] = GetBufferSizes[MeshA](item = myMesh1) | |
1010 let instanceBuffers: seq[(bool, uint64)] = GetBufferSizes[InstanceA](item = instances1) | |
1011 let globalBuffers: seq[(bool, uint64)] = GetBufferSizes[Globals](item = myGlobals) | |
1012 var myRenderable = CreateRenderable() | |
1013 UploadTextures[MeshA]() | |
1014 UploadTextures[Globals]() | |
1015 ]# | |
1016 var myRenderable: Renderable[MeshA, InstanceA] | |
833 | 1017 |
834 # descriptors | 1018 # descriptors |
835 WriteDescriptors(dev.vk, pipeline1) | 1019 WriteDescriptors(dev.vk, pipeline1) |
836 | 1020 |
837 # command buffer | 1021 # command buffer |