comparison static_utils.nim @ 1177:4ef959278451 compiletime-tests

sync from bedroom to office
author sam <sam@basx.dev>
date Sun, 30 Jun 2024 06:40:33 +0700
parents 511c9f7cd1da
children ec4ff70299f2
comparison
equal deleted inserted replaced
1176:511c9f7cd1da 1177:4ef959278451
17 template VertexAttribute* {.pragma.} 17 template VertexAttribute* {.pragma.}
18 template InstanceAttribute* {.pragma.} 18 template InstanceAttribute* {.pragma.}
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 template VertexIndices*{.pragma.}
22 23
23 const INFLIGHTFRAMES = 2'u32 24 const INFLIGHTFRAMES = 2'u32
25 const MEMORY_ALIGNMENT = 65536'u64 # Align buffers inside memory along this alignment
26 const BUFFERALIGNMENT = 64'u64 # align offsets inside buffers along this alignment
24 27
25 type 28 type
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] 29 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]
27 ShaderObject*[TShader] = object 30 ShaderObject*[TShader] = object
28 vertexShader: VkShaderModule 31 vertexShader: VkShaderModule
199 None, UInt8, UInt16, UInt32 202 None, UInt8, UInt16, UInt32
200 203
201 IndirectGPUMemory = object 204 IndirectGPUMemory = object
202 vk: VkDeviceMemory 205 vk: VkDeviceMemory
203 size: uint64 206 size: uint64
207 needsTransfer: bool # usually true
204 DirectGPUMemory = object 208 DirectGPUMemory = object
205 vk: VkDeviceMemory 209 vk: VkDeviceMemory
206 size: uint64 210 size: uint64
207 data: pointer 211 data: pointer
212 needsFlush: bool # usually true
208 GPUMemory = IndirectGPUMemory | DirectGPUMemory 213 GPUMemory = IndirectGPUMemory | DirectGPUMemory
209 214
210 Buffer[TMemory: GPUMemory] = object 215 Buffer[TMemory: GPUMemory] = object
211 vk: VkBuffer 216 vk: VkBuffer
212 memory*: TMemory
213 offset: uint64 217 offset: uint64
214 size: uint64 218 size: uint64
215 219
216 GPUArray[T: SupportedGPUType, TMemory: GPUMemory] = object 220 GPUArray[T: SupportedGPUType, TMemory: GPUMemory] = object
217 data: seq[T] 221 data: seq[T]
238 pipeline: VkPipeline 242 pipeline: VkPipeline
239 layout: VkPipelineLayout 243 layout: VkPipelineLayout
240 descriptorSetLayout: VkDescriptorSetLayout 244 descriptorSetLayout: VkDescriptorSetLayout
241 RenderData = object 245 RenderData = object
242 descriptorPool: VkDescriptorPool 246 descriptorPool: VkDescriptorPool
243 indirectMemory: seq[IndirectGPUMemory] 247 # tuple is memory and offset to next free allocation in that memory
244 nextFreeIndirectMemoryOffset: seq[uint64] 248 indirectMemory: seq[tuple[memory: IndirectGPUMemory, nextFree: uint64]]
249 directMemory: seq[tuple[memory: DirectGPUMemory, nextFree: uint64]]
245 indirectBuffers: seq[Buffer[IndirectGPUMemory]] 250 indirectBuffers: seq[Buffer[IndirectGPUMemory]]
246 directMemory: seq[DirectGPUMemory]
247 nextFreeDirectMemoryOffset: seq[uint64]
248 directBuffers: seq[Buffer[DirectGPUMemory]] 251 directBuffers: seq[Buffer[DirectGPUMemory]]
252
253 template IsDirectMemory(gpuArray: GPUArray): untyped =
254 get(genericParams(typeof(gpuArray)), 1) is DirectGPUMemory
255 template IsDirectMemory(gpuValue: GPUValue): untyped =
256 get(genericParams(typeof(gpuValue)), 1) is DirectGPUMemory
249 257
250 converter toVkIndexType(indexType: IndexType): VkIndexType = 258 converter toVkIndexType(indexType: IndexType): VkIndexType =
251 case indexType: 259 case indexType:
252 of None: VK_INDEX_TYPE_NONE_KHR 260 of None: VK_INDEX_TYPE_NONE_KHR
253 of UInt8: VK_INDEX_TYPE_UINT8_EXT 261 of UInt8: VK_INDEX_TYPE_UINT8_EXT
472 var layoutCreateInfo = VkDescriptorSetLayoutCreateInfo( 480 var layoutCreateInfo = VkDescriptorSetLayoutCreateInfo(
473 sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, 481 sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
474 bindingCount: uint32(layoutbindings.len), 482 bindingCount: uint32(layoutbindings.len),
475 pBindings: layoutbindings.ToCPointer 483 pBindings: layoutbindings.ToCPointer
476 ) 484 )
477 result.descriptorSetLayout: VkDescriptorSetLayout
478 checkVkResult vkCreateDescriptorSetLayout(device, addr(layoutCreateInfo), nil, addr(result.descriptorSetLayout)) 485 checkVkResult vkCreateDescriptorSetLayout(device, addr(layoutCreateInfo), nil, addr(result.descriptorSetLayout))
479 let pipelineLayoutInfo = VkPipelineLayoutCreateInfo( 486 let pipelineLayoutInfo = VkPipelineLayoutCreateInfo(
480 sType: VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 487 sType: VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
481 setLayoutCount: 1, 488 setLayoutCount: 1,
482 pSetLayouts: addr(result.descriptorSetLayout), 489 pSetLayouts: addr(result.descriptorSetLayout),
609 addr(createInfo), 616 addr(createInfo),
610 nil, 617 nil,
611 addr(result.pipeline) 618 addr(result.pipeline)
612 ) 619 )
613 620
614 proc AllocateIndirectMemory(device: VkDevice, pDevice: VkPhysicalDevice, allocationSize: uint64): IndirectGPUMemory = 621 proc AllocateIndirectMemory(device: VkDevice, pDevice: VkPhysicalDevice, size: uint64): IndirectGPUMemory =
615 # chooses biggest memory type that has NOT VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT 622 # chooses biggest memory type that has NOT VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
616 result.size = allocationSize 623 result.size = size
624 result.needsTransfer = true
617 625
618 # find a good memory type 626 # find a good memory type
619 var physicalProperties: VkPhysicalDeviceMemoryProperties 627 var physicalProperties: VkPhysicalDeviceMemoryProperties
620 vkGetPhysicalDeviceMemoryProperties(pDevice, addr physicalProperties) 628 vkGetPhysicalDeviceMemoryProperties(pDevice, addr physicalProperties)
621 629
622 var biggestHeap: uint64 = -1 630 var biggestHeap: uint64 = 0
623 var memoryTypeIndex = -1 631 var memoryTypeIndex = high(uint32)
624 # try to find non-host-visible type 632 # try to find non-host-visible type
625 for i in 0 ..< physicalProperties.memoryTypeCount: 633 for i in 0'u32 ..< physicalProperties.memoryTypeCount:
626 if VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT not in toEnums(physicalProperties.memoryTypes[i].propertyFlags) 634 if not (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT in toEnums(physicalProperties.memoryTypes[i].propertyFlags)):
627 let size = physicalProperties.memoryHeaps[physicalProperties.memoryTypes[i].heapIndex].size 635 let size = physicalProperties.memoryHeaps[physicalProperties.memoryTypes[i].heapIndex].size
628 if size > biggestHeap: 636 if size > biggestHeap:
629 biggest = size 637 biggestHeap = size
630 memoryTypeIndex = i 638 memoryTypeIndex = i
631 639
632 # If we did not found a device-only memory type, let's just take the biggest overall 640 # If we did not found a device-only memory type, let's just take the biggest overall
633 if memoryTypeIndex < 0: 641 if memoryTypeIndex == high(uint32):
634 for i in 0 ..< physicalProperties.memoryTypeCount: 642 result.needsTransfer = false
635 let size = physicalProperties.memoryHeaps[physicalProperties.memoryTypes[i].heapIndex].size 643 for i in 0'u32 ..< physicalProperties.memoryTypeCount:
636 if size > biggestHeap: 644 let size = physicalProperties.memoryHeaps[physicalProperties.memoryTypes[i].heapIndex].size
637 biggest = size 645 if size > biggestHeap:
638 memoryTypeIndex = i 646 biggestHeap = size
639 647 memoryTypeIndex = i
640 assert memoryTypeIndex >= 0, "Unable to find indirect memory type" 648
649 assert memoryTypeIndex != high(uint32), "Unable to find indirect memory type"
641 var allocationInfo = VkMemoryAllocateInfo( 650 var allocationInfo = VkMemoryAllocateInfo(
642 sType: VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, 651 sType: VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
643 allocationSize: initialAllocationSize, 652 allocationSize: result.size,
644 memoryTypeIndex: memoryTypeIndex, 653 memoryTypeIndex: memoryTypeIndex,
645 ) 654 )
646 checkVkResult vkAllocateMemory( 655 checkVkResult vkAllocateMemory(
647 device, 656 device,
648 addr allocationInfo, 657 addr allocationInfo,
649 nil, 658 nil,
650 addr result.vk 659 addr result.vk
651 ) 660 )
652 661
653 proc AllocateDirectMemory(device: VkDevice, allocationSize: uint64): DirectGPUMemory = 662 proc AllocateDirectMemory(device: VkDevice, pDevice: VkPhysicalDevice, size: uint64): DirectGPUMemory =
654 result.size = allocationSize 663 result.size = size
664 result.needsFlush = true
655 665
656 # find a good memory type 666 # find a good memory type
657 var physicalProperties: VkPhysicalDeviceMemoryProperties 667 var physicalProperties: VkPhysicalDeviceMemoryProperties
658 vkGetPhysicalDeviceMemoryProperties(pDevice, addr physicalProperties) 668 vkGetPhysicalDeviceMemoryProperties(pDevice, addr physicalProperties)
659 669
660 var biggestHeap: uint64 = -1 670 var biggestHeap: uint64 = 0
661 var memoryTypeIndex = -1 671 var memoryTypeIndex = high(uint32)
662 # try to find host-visible type 672 # try to find host-visible type
663 for i in 0 ..< physicalProperties.memoryTypeCount: 673 for i in 0 ..< physicalProperties.memoryTypeCount:
664 if VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT in toEnums(physicalProperties.memoryTypes[i].propertyFlags) 674 let flags = toEnums(physicalProperties.memoryTypes[i].propertyFlags)
675 if VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT in flags:
665 let size = physicalProperties.memoryHeaps[physicalProperties.memoryTypes[i].heapIndex].size 676 let size = physicalProperties.memoryHeaps[physicalProperties.memoryTypes[i].heapIndex].size
666 if size > biggestHeap: 677 if size > biggestHeap:
667 biggest = size 678 biggestHeap = size
668 memoryTypeIndex = i 679 memoryTypeIndex = i
669 680 result.needsFlush = not (VK_MEMORY_PROPERTY_HOST_COHERENT_BIT in flags)
670 assert memoryTypeIndex >= 0, "Unable to find direct (aka host-visible) memory type" 681
682 assert memoryTypeIndex != high(uint32), "Unable to find indirect memory type"
671 var allocationInfo = VkMemoryAllocateInfo( 683 var allocationInfo = VkMemoryAllocateInfo(
672 sType: VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, 684 sType: VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
673 allocationSize: initialAllocationSize, 685 allocationSize: result.size,
674 memoryTypeIndex: memoryTypeIndex, 686 memoryTypeIndex: memoryTypeIndex,
675 ) 687 )
676 checkVkResult vkAllocateMemory( 688 checkVkResult vkAllocateMemory(
677 device, 689 device,
678 addr allocationInfo, 690 addr allocationInfo,
679 nil, 691 nil,
680 addr result.vk 692 addr result.vk
681 ) 693 )
682 checkVkResult result.device.vk.vkMapMemory( 694 checkVkResult vkMapMemory(
695 device = device,
683 memory = result.vk, 696 memory = result.vk,
684 offset = 0'u64, 697 offset = 0'u64,
685 size = result.size, 698 size = result.size,
686 flags = VkMemoryMapFlags(0), 699 flags = VkMemoryMapFlags(0),
687 ppData = addr(result.data) 700 ppData = addr(result.data)
688 ) 701 )
689 702
690 proc InitRenderData(device: VkDevice, descriptorPoolLimit = 1024): RenderData = 703 proc AllocateIndirectBuffer(device: VkDevice, renderData: var RenderData, size: uint64, usage: openArray[VkBufferUsageFlagBits]) =
704 assert size > 0, "Buffer sizes must be larger than 0"
705 var buffer = Buffer[IndirectGPUMemory](size: size)
706
707 # iterate through memory areas to find big enough free space
708 for (memory, offset) in renderData.indirectMemory.mitems:
709 if memory.size - offset >= size:
710 buffer.offset = offset
711 # create buffer
712 var createInfo = VkBufferCreateInfo(
713 sType: VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
714 flags: VkBufferCreateFlags(0),
715 size: buffer.size,
716 usage: toBits(@usage & @[VK_BUFFER_USAGE_TRANSFER_DST_BIT]), # ensure we can transfer to this buffer
717 sharingMode: VK_SHARING_MODE_EXCLUSIVE,
718 )
719 checkVkResult vkCreateBuffer(
720 device = device,
721 pCreateInfo = addr createInfo,
722 pAllocator = nil,
723 pBuffer = addr(buffer.vk)
724 )
725 checkVkResult vkBindBufferMemory(device, buffer.vk, memory.vk, buffer.offset)
726 renderData.indirectBuffers.add buffer
727 # update memory area offset
728 offset = offset + size
729 if offset mod MEMORY_ALIGNMENT != 0:
730 offset = offset + MEMORY_ALIGNMENT - (offset mod MEMORY_ALIGNMENT)
731 return
732
733 assert false, "Did not find allocated memory region with enough space"
734
735 proc AllocateDirectBuffer(device: VkDevice, renderData: var RenderData, size: uint64, usage: openArray[VkBufferUsageFlagBits]) =
736 assert size > 0, "Buffer sizes must be larger than 0"
737 var buffer = Buffer[DirectGPUMemory](size: size)
738
739 # iterate through memory areas to find big enough free space
740 for (memory, offset) in renderData.directMemory.mitems:
741 if memory.size - offset >= size:
742 buffer.offset = offset
743 # create buffer
744 var createInfo = VkBufferCreateInfo(
745 sType: VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
746 flags: VkBufferCreateFlags(0),
747 size: buffer.size,
748 usage: toBits(usage),
749 sharingMode: VK_SHARING_MODE_EXCLUSIVE,
750 )
751 checkVkResult vkCreateBuffer(
752 device = device,
753 pCreateInfo = addr createInfo,
754 pAllocator = nil,
755 pBuffer = addr(buffer.vk)
756 )
757 checkVkResult vkBindBufferMemory(device, buffer.vk, memory.vk, buffer.offset)
758 renderData.directBuffers.add buffer
759 # update memory area offset
760 offset = offset + size
761 if offset mod MEMORY_ALIGNMENT != 0:
762 offset = offset + MEMORY_ALIGNMENT - (offset mod MEMORY_ALIGNMENT)
763 return
764
765 assert false, "Did not find allocated memory region with enough space"
766
767 proc InitRenderData(device: VkDevice, pDevice: VkPhysicalDevice, descriptorPoolLimit = 1024'u32): RenderData =
691 # allocate descriptor pools 768 # allocate descriptor pools
692 var poolSizes = [ 769 var poolSizes = [
693 VkDescriptorPoolSize(thetype: VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, descriptorCount: descriptorPoolLimit) 770 VkDescriptorPoolSize(thetype: VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, descriptorCount: descriptorPoolLimit),
694 VkDescriptorPoolSize(thetype: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount: descriptorPoolLimit) 771 VkDescriptorPoolSize(thetype: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount: descriptorPoolLimit),
695 ] 772 ]
696 var poolInfo = VkDescriptorPoolCreateInfo( 773 var poolInfo = VkDescriptorPoolCreateInfo(
697 sType: VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, 774 sType: VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
698 poolSizeCount: poolSizes.len.uint32, 775 poolSizeCount: poolSizes.len.uint32,
699 pPoolSizes: poolSizes.ToCPointer, 776 pPoolSizes: poolSizes.ToCPointer,
700 maxSets: descriptorPoolLimit, 777 maxSets: descriptorPoolLimit,
701 ) 778 )
702 checkVkResult vkCreateDescriptorPool(device, addr(poolInfo), nil, addr(result.descriptorPool)) 779 checkVkResult vkCreateDescriptorPool(device, addr(poolInfo), nil, addr(result.descriptorPool))
703 780
704 # allocate some memory 781 # allocate some memory
705 var initialAllocationSize: 1_000_000_000 # TODO: make this more dynamic or something 782 var initialAllocationSize = 1_000_000_000'u64 # TODO: make this more dynamic or something
706 result.indirectMemory = @[AllocateIndirectMemory(device, size=initialAllocationSize)] 783 result.indirectMemory = @[(AllocateIndirectMemory(device, pDevice, size = initialAllocationSize), 0'u64)]
707 result.nextFreeIndirectMemoryOffset = @[0'u64] 784 result.directMemory = @[(AllocateDirectMemory(device, pDevice, size = initialAllocationSize), 0'u64)]
708 result.directMemory = @[AllocateDirectMemory(device, size=initialAllocationSize)] 785
709 result.nextFreeDirectMemoryOffset = @[0'u64] 786 proc GetIndirectBufferSizes[T](data: T): uint64 =
710 787 # return buffer sizes for direct and indirect buffers
711 proc WriteDescriptors[TShader](device: VkDevice, pipeline: Pipeline[TShader]) = 788 # BUFFER_ALIGNMENT is just added for a rough estimate, to ensure we have enough space to align when binding
789 for name, value in fieldPairs(data):
790 when not hasCustomPragma(value, VertexIndices)
791 when typeof(value) is GPUArray:
792 if not IsDirectMemory(value):
793 result += (value.data.len * sizeof(elementType(value.data))).uint64 + BUFFER_ALIGNMENT
794 when typeof(value) is GPUValue:
795 if not IsDirectMemory(value):
796 result += sizeof(value.data).uint64 + BUFFER_ALIGNMENT
797 proc GetDirectBufferSizes[T](data: T): uint64 =
798 # return buffer sizes for direct and indirect buffers
799 # BUFFER_ALIGNMENT is just added for a rough estimate, to ensure we have enough space to align when binding
800 for name, value in fieldPairs(data):
801 when not hasCustomPragma(value, VertexIndices)
802 when typeof(value) is GPUArray:
803 if IsDirectMemory(value):
804 result += (value.data.len * sizeof(elementType(value.data))).uint64 + BUFFER_ALIGNMENT
805 when typeof(value) is GPUValue:
806 if IsDirectMemory(value):
807 result += sizeof(value.data).uint64 + BUFFER_ALIGNMENT
808
809 proc GetIndirectIndexBufferSizes[T](data: T): uint64 =
810 for name, value in fieldPairs(data):
811 when hasCustomPragma(value, VertexIndices):
812 static: assert typeof(value) is GPUArray, "Index buffers must be of type GPUArray"
813 static: assert elementType(value.data) is uint8 or elementType(value.data) is uint16 or elementType(value.data) is uint32
814 if not IsDirectMemory(value):
815 result += (value.data.len * sizeof(elementType(value.data))).uint64 + BUFFER_ALIGNMENT
816
817 proc GetDirectIndexBufferSizes[T](data: T): uint64 =
818 for name, value in fieldPairs(data):
819 when hasCustomPragma(value, VertexIndices):
820 static: assert typeof(value) is GPUArray, "Index buffers must be of type GPUArray"
821 static: assert elementType(value.data) is uint8 or elementType(value.data) is uint16 or elementType(value.data) is uint32
822 if IsDirectMemory(value):
823 result += (value.data.len * sizeof(elementType(value.data))).uint64 + BUFFER_ALIGNMENT
824
825
826 proc WriteDescriptors[TShader](device: VkDevice, descriptorSets: array[INFLIGHTFRAMES.int, VkDescriptorSet]) =
712 var descriptorSetWrites: seq[VkWriteDescriptorSet] 827 var descriptorSetWrites: seq[VkWriteDescriptorSet]
713 # map (buffer + offset + range) to descriptor 828 # map (buffer + offset + range) to descriptor
714 # map (texture) to descriptor 829 # map (texture) to descriptor
715 ForDescriptorFields(default(TShader), fieldName, descriptorType, descriptorCount, descriptorBindingNumber): 830 ForDescriptorFields(default(TShader), fieldName, descriptorType, descriptorCount, descriptorBindingNumber):
716 for frameInFlight in 0 ..< pipeline.descriptorSets.len: 831 for frameInFlight in 0 ..< descriptorSets.len:
717 if descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: 832 when descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
718 # TODO 833 # TODO
719 let bufferInfo = VkDescriptorBufferInfo( 834 let bufferInfo = VkDescriptorBufferInfo(
720 buffer: VkBuffer(0), 835 buffer: VkBuffer(0),
721 offset: 0, 836 offset: 0,
722 range: 1, 837 range: 1,
723 ) 838 )
724 descriptorSetWrites.add VkWriteDescriptorSet( 839 descriptorSetWrites.add VkWriteDescriptorSet(
725 sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 840 sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
726 dstSet: pipeline.descriptorSets[frameInFlight], 841 dstSet: descriptorSets[frameInFlight],
727 dstBinding: descriptorBindingNumber, 842 dstBinding: descriptorBindingNumber,
728 dstArrayElement: uint32(0), 843 dstArrayElement: uint32(0),
729 descriptorType: descriptorType, 844 descriptorType: descriptorType,
730 descriptorCount: descriptorCount, 845 descriptorCount: descriptorCount,
731 pImageInfo: nil, 846 pImageInfo: nil,
738 imageView: VkImageView(0), 853 imageView: VkImageView(0),
739 imageLayout: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 854 imageLayout: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
740 ) 855 )
741 descriptorSetWrites.add VkWriteDescriptorSet( 856 descriptorSetWrites.add VkWriteDescriptorSet(
742 sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 857 sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
743 dstSet: pipeline.descriptorSets[frameInFlight], 858 dstSet: descriptorSets[frameInFlight],
744 dstBinding: descriptorBindingNumber, 859 dstBinding: descriptorBindingNumber,
745 dstArrayElement: uint32(0), 860 dstArrayElement: uint32(0),
746 descriptorType: descriptorType, 861 descriptorType: descriptorType,
747 descriptorCount: descriptorCount, 862 descriptorCount: descriptorCount,
748 pImageInfo: addr(imageInfo), 863 pImageInfo: addr(imageInfo),
749 pBufferInfo: nil, 864 pBufferInfo: nil,
750 ) 865 )
751 vkUpdateDescriptorSets(device, uint32(descriptorSetWrites.len), descriptorSetWrites.ToCPointer, 0, nil) 866 vkUpdateDescriptorSets(device, uint32(descriptorSetWrites.len), descriptorSetWrites.ToCPointer, 0, nil)
752 867
753 proc CreateRenderable[TMesh, TInstance](
754 mesh: TMesh,
755 instance: TInstance,
756 ): Renderable[TMesh, TInstance] =
757 result.indexType = None
758
759 proc Bind[T](pipeline: Pipeline[T], commandBuffer: VkCommandBuffer, currentFrameInFlight: int) = 868 proc Bind[T](pipeline: Pipeline[T], commandBuffer: VkCommandBuffer, currentFrameInFlight: int) =
760 let a = pipeline.descriptorSets
761 commandBuffer.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipeline) 869 commandBuffer.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipeline)
762 if a[currentFrameInFlight] != VkDescriptorSet(0): 870 #[
763 commandBuffer.vkCmdBindDescriptorSets( 871 commandBuffer.vkCmdBindDescriptorSets(
764 VK_PIPELINE_BIND_POINT_GRAPHICS, 872 VK_PIPELINE_BIND_POINT_GRAPHICS,
765 pipeline.layout, 873 pipeline.layout,
766 0, 874 0,
767 1, 875 1,
768 addr pipeline.descriptorSets[currentFrameInFlight], 876 addr pipeline.descriptorSets[currentFrameInFlight],
769 0, 877 0,
770 nil, 878 nil,
771 ) 879 )
772 880 ]#
773 proc AssertCompatible(TShader, TMesh, TInstance, TGlobals: typedesc) = 881
882 proc AssertCompatible(TShader, TMesh, TInstance, TUniforms, TGlobals: typedesc) =
774 # assert seq-fields of TMesh|TInstance == seq-fields of TShader 883 # assert seq-fields of TMesh|TInstance == seq-fields of TShader
775 # assert normal fields of TMesh|Globals == normal fields of TShaderDescriptors 884 # assert normal fields of TMesh|Globals == normal fields of TShaderDescriptors
776 for inputName, inputValue in default(TShader).fieldPairs: 885 for inputName, inputValue in default(TShader).fieldPairs:
777 var foundField = false 886 var foundField = false
778 887
798 foundField = true 907 foundField = true
799 assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TInstance) & "'" 908 assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TInstance) & "'"
800 909
801 # Texture 910 # Texture
802 elif typeof(inputValue) is Texture: 911 elif typeof(inputValue) is Texture:
803 for meshName, meshValue in default(TMesh).fieldPairs: 912 for uniformName, uniformValue in default(TUniforms).fieldPairs:
804 when meshName == inputName: 913 when uniformName == inputName:
805 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once" 914 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once"
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)) & "'" 915 assert typeof(uniformValue) is typeof(inputValue), "Shader input " & tt.name(TShader) & "." & inputName & " is of type '" & tt.name(typeof(inputValue)) & "' but uniform attribute is of type '" & tt.name(typeof(uniformValue)) & "'"
807 foundField = true 916 foundField = true
808 for globalName, globalValue in default(TGlobals).fieldPairs: 917 for globalName, globalValue in default(TGlobals).fieldPairs:
809 when globalName == inputName: 918 when globalName == inputName:
810 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once" 919 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once"
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)) & "'" 920 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)) & "'"
812 foundField = true 921 foundField = true
813 assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TMesh) & "|" & tt.name(TGlobals) & "'" 922 assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TMesh) & "|" & tt.name(TGlobals) & "'"
814 923
815 # Uniform block 924 # Uniform block
816 elif typeof(inputValue) is object: 925 elif typeof(inputValue) is object:
817 for meshName, meshValue in default(TMesh).fieldPairs: 926 for uniformName, uniformValue in default(TUniforms).fieldPairs:
818 when meshName == inputName: 927 when uniformName == inputName:
819 assert meshValue is GPUValue, "Mesh attribute '" & meshName & "' must be of type 'GPUValue' but is of type " & tt.name(typeof(meshValue)) 928 assert uniformValue is GPUValue, "global attribute '" & uniformName & "' must be of type 'GPUValue' but is of type " & tt.name(typeof(uniformValue))
820 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once" 929 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)) & "'" 930 assert typeof(uniformValue.data) is typeof(inputValue), "Shader input " & tt.name(TShader) & "." & inputName & " is of type '" & tt.name(typeof(inputValue)) & "' but uniform attribute is of type '" & tt.name(typeof(uniformValue.data)) & "'"
822 foundField = true 931 foundField = true
823 for globalName, globalValue in default(TGlobals).fieldPairs: 932 for globalName, globalValue in default(TGlobals).fieldPairs:
824 when globalName == inputName: 933 when globalName == inputName:
825 assert globalValue is GPUValue, "global attribute '" & globalName & "' must be of type 'GPUValue' but is of type " & tt.name(typeof(globalValue)) 934 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" 935 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once"
831 # array 940 # array
832 elif typeof(inputValue) is array: 941 elif typeof(inputValue) is array:
833 942
834 # texture-array 943 # texture-array
835 when elementType(inputValue) is Texture: 944 when elementType(inputValue) is Texture:
836 for meshName, meshValue in default(TMesh).fieldPairs: 945 for uniformName, uniformValue in default(TUniforms).fieldPairs:
837 when meshName == inputName: 946 when uniformName == inputName:
838 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once" 947 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once"
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)) & "'" 948 assert typeof(uniformValue) is typeof(inputValue), "Shader input " & tt.name(TShader) & "." & inputName & " is of type '" & tt.name(typeof(inputValue)) & "' but uniform attribute is of type '" & tt.name(typeof(uniformValue)) & "'"
840 foundField = true 949 foundField = true
841 for globalName, globalValue in default(TGlobals).fieldPairs: 950 for globalName, globalValue in default(TGlobals).fieldPairs:
842 when globalName == inputName: 951 when globalName == inputName:
843 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once" 952 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once"
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)) & "'" 953 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 954 foundField = true
846 assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TMesh) & "|" & tt.name(TGlobals) & "'" 955 assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TMesh) & "|" & tt.name(TGlobals) & "'"
847 956
848 # uniform-block array 957 # uniform-block array
849 elif elementType(inputValue) is object: 958 elif elementType(inputValue) is object:
850 for meshName, meshValue in default(TMesh).fieldPairs: 959 for uniformName, uniformValue in default(TUniforms).fieldPairs:
851 when meshName == inputName: 960 when uniformName == inputName:
852 assert meshValue is GPUValue, "Mesh attribute '" & meshName & "' must be of type 'GPUValue' but is of type " & tt.name(typeof(meshValue)) 961 assert uniformValue is GPUValue, "global attribute '" & uniformName & "' must be of type 'GPUValue' but is of type " & tt.name(typeof(uniformValue))
853 assert foundField == false, "Shader input '" & tt.name(TShader) & "." & inputName & "' has been found more than once" 962 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)) & "'" 963 assert typeof(uniformValue.data) is typeof(inputValue), "Shader input " & tt.name(TShader) & "." & inputName & " is of type '" & tt.name(typeof(inputValue)) & "' but uniform attribute is of type '" & tt.name(typeof(uniformValue.data)) & "'"
855 foundField = true 964 foundField = true
856 for globalName, globalValue in default(TGlobals).fieldPairs: 965 for globalName, globalValue in default(TGlobals).fieldPairs:
857 when globalName == inputName: 966 when globalName == inputName:
858 assert globalValue is GPUValue, "global attribute '" & globalName & "' must be of type 'GPUValue' but is of type " & tt.name(typeof(globalValue)) 967 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" 968 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)) & "'" 969 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)) & "'"
861 foundField = true 970 foundField = true
862 assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TMesh) & "|" & tt.name(TGlobals) & "'" 971 assert foundField, "Shader input '" & tt.name(TShader) & "." & inputName & ": " & tt.name(typeof(inputValue)) & "' not found in '" & tt.name(TMesh) & "|" & tt.name(TGlobals) & "'"
863 972
864 973
865 proc Render[TShader, TMesh, TInstance, TGlobals]( 974 proc Render[TShader, TMesh, TInstance, TUniforms, TGlobals](
866 pipeline: Pipeline[TShader], 975 pipeline: Pipeline[TShader],
867 renderable: Renderable[TMesh, TInstance], 976 renderable: Renderable[TMesh, TInstance],
977 uniforms: TUniforms,
868 globals: TGlobals, 978 globals: TGlobals,
869 commandBuffer: VkCommandBuffer, 979 commandBuffer: VkCommandBuffer,
870 ) = 980 ) =
871 static: AssertCompatible(TShader, TMesh, TInstance, TGlobals) 981 static: AssertCompatible(TShader, TMesh, TInstance, TUniforms, TGlobals)
872 if renderable.vertexBuffers.len > 0: 982 if renderable.vertexBuffers.len > 0:
873 commandBuffer.vkCmdBindVertexBuffers( 983 commandBuffer.vkCmdBindVertexBuffers(
874 firstBinding = 0'u32, 984 firstBinding = 0'u32,
875 bindingCount = uint32(renderable.vertexBuffers.len), 985 bindingCount = uint32(renderable.vertexBuffers.len),
876 pBuffers = renderable.vertexBuffers.ToCPointer(), 986 pBuffers = renderable.vertexBuffers.ToCPointer(),
903 import semicongine/vulkan/device 1013 import semicongine/vulkan/device
904 import semicongine/vulkan/physicaldevice 1014 import semicongine/vulkan/physicaldevice
905 import std/options 1015 import std/options
906 1016
907 type 1017 type
1018 MeshA = object
1019 position: GPUArray[Vec3f, IndirectGPUMemory]
1020 indices {.VertexIndices.}: GPUArray[uint16, IndirectGPUMemory]
1021 InstanceA = object
1022 rotation: GPUArray[Vec4f, IndirectGPUMemory]
1023 objPosition: GPUArray[Vec3f, IndirectGPUMemory]
908 MaterialA = object 1024 MaterialA = object
909 reflection: float32 1025 reflection: float32
910 baseColor: Vec3f 1026 baseColor: Vec3f
911 ShaderSettings = object
912 brightness: float32
913 MeshA = object
914 position: GPUArray[Vec3f, IndirectGPUMemory]
915 InstanceA = object
916 rotation: GPUArray[Vec4f, IndirectGPUMemory]
917 objPosition: GPUArray[Vec3f, IndirectGPUMemory]
918 UniformsA = object 1027 UniformsA = object
919 materials: GPUValue[array[3, MaterialA], IndirectGPUMemory] 1028 materials: GPUValue[array[3, MaterialA], IndirectGPUMemory]
920 materialTextures: array[3, Texture] 1029 materialTextures: array[3, Texture]
1030 ShaderSettings = object
1031 brightness: float32
921 GlobalsA = object 1032 GlobalsA = object
922 fontAtlas: Texture 1033 fontAtlas: Texture
923 settings: GPUValue[ShaderSettings, IndirectGPUMemory] 1034 settings: GPUValue[ShaderSettings, IndirectGPUMemory]
924 1035
925 ShaderA = object 1036 ShaderA = object
988 # shaders 1099 # shaders
989 const shader = ShaderA() 1100 const shader = ShaderA()
990 let shaderObject = dev.vk.CompileShader(shader) 1101 let shaderObject = dev.vk.CompileShader(shader)
991 var pipeline1 = CreatePipeline(dev.vk, renderPass = renderpass, shaderObject) 1102 var pipeline1 = CreatePipeline(dev.vk, renderPass = renderpass, shaderObject)
992 1103
993 var renderdata = InitRenderData(dev.vk) 1104 var renderdata = InitRenderData(dev.vk, dev.physicalDevice.vk)
994 1105
995 # create descriptor sets 1106 # create descriptor sets
1107 #[
996 var descriptorSets: array[INFLIGHTFRAMES.int, VkDescriptorSet] 1108 var descriptorSets: array[INFLIGHTFRAMES.int, VkDescriptorSet]
997 var layouts = newSeqWith(descriptorSets.len, pipeline.descriptorSetLayout) 1109 var layouts = newSeqWith(descriptorSets.len, pipeline.descriptorSetLayout)
998 var allocInfo = VkDescriptorSetAllocateInfo( 1110 var allocInfo = VkDescriptorSetAllocateInfo(
999 sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, 1111 sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
1000 descriptorPool: pool, 1112 descriptorPool: pool,
1001 descriptorSetCount: uint32(layouts.len), 1113 descriptorSetCount: uint32(layouts.len),
1002 pSetLayouts: layouts.ToCPointer, 1114 pSetLayouts: layouts.ToCPointer,
1003 ) 1115 )
1004 checkVkResult vkAllocateDescriptorSets(device, addr(allocInfo), descriptorSets.ToCPointer) 1116 checkVkResult vkAllocateDescriptorSets(device, addr(allocInfo), descriptorSets.ToCPointer)
1005 1117 ]#
1006 1118
1007 #[ 1119 #[
1008 # TODO: probably here: allocate renderables, uniform buffers & textures 1120 # TODO:
1009 let meshBuffers: seq[(bool, uint64)] = GetBufferSizes[MeshA](item = myMesh1) 1121 #
1010 let instanceBuffers: seq[(bool, uint64)] = GetBufferSizes[InstanceA](item = instances1) 1122 # assign indirect buffers to vertex data, can happen through the GPUArray/GPUValue-wrappers, they know buffers
1011 let globalBuffers: seq[(bool, uint64)] = GetBufferSizes[Globals](item = myGlobals) 1123 # assign direct buffers to vertex data
1012 var myRenderable = CreateRenderable() 1124 # assign indirect buffers to uniform data
1013 UploadTextures[MeshA]() 1125 # assign direct buffers to uniform data
1014 UploadTextures[Globals]() 1126 #
1127 # upload all textures
1128 # write descriptors for textures and uniform buffers
1129 #
1015 ]# 1130 ]#
1016 var myRenderable: Renderable[MeshA, InstanceA] 1131 var myRenderable: Renderable[MeshA, InstanceA]
1017 1132
1133 var
1134 indirectVertexSizes = 0'u64
1135 directVertexSizes = 0'u64
1136 indirectIndexSizes = 0'u64
1137 directIndexSizes = 0'u64
1138 indirectUniformSizes = 0'u64
1139 directUniformSizes = 0'u64
1140
1141 indirectVertexSizes += GetIndirectBufferSizes(myMesh1)
1142 indirectVertexSizes += GetIndirectBufferSizes(instances1)
1143 if indirectVertexSizes > 0:
1144 AllocateIndirectBuffer(dev.vk, renderdata, indirectVertexSizes, [VK_BUFFER_USAGE_VERTEX_BUFFER_BIT])
1145
1146 directVertexSizes += GetDirectBufferSizes(myMesh1)
1147 directVertexSizes += GetDirectBufferSizes(instances1)
1148 if directVertexSizes > 0:
1149 AllocateDirectBuffer(dev.vk, renderdata, directVertexSizes, [VK_BUFFER_USAGE_VERTEX_BUFFER_BIT])
1150
1151 indirectIndexSizes += GetIndirectIndexBufferSizes(myMesh1)
1152 if indirectIndexSizes > 0:
1153 AllocateIndirectBuffer(dev.vk, renderdata, indirectIndexSizes, [VK_BUFFER_USAGE_INDEX_BUFFER_BIT])
1154
1155 directIndexSizes += GetDirectIndexBufferSizes(myMesh1)
1156 if directIndexSizes > 0:
1157 AllocateIndirectBuffer(dev.vk, renderdata, directIndexSizes, [VK_BUFFER_USAGE_INDEX_BUFFER_BIT])
1158
1159 indirectUniformSizes += GetIndirectBufferSizes(uniforms1)
1160 indirectUniformSizes += GetIndirectBufferSizes(myGlobals)
1161 if indirectUniformSizes > 0:
1162 AllocateIndirectBuffer(dev.vk, renderdata, indirectUniformSizes, [VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT])
1163
1164 directUniformSizes += GetDirectBufferSizes(uniforms1)
1165 directUniformSizes += GetDirectBufferSizes(myGlobals)
1166 if directUniformSizes > 0:
1167 AllocateDirectBuffer(dev.vk, renderdata, directUniformSizes, [VK_BUFFER_USAGE_VERTEX_BUFFER_BIT])
1168
1018 # descriptors 1169 # descriptors
1019 WriteDescriptors(dev.vk, pipeline1) 1170 # WriteDescriptors(dev.vk, pipeline1)
1020 1171
1021 # command buffer 1172 # command buffer
1022 var 1173 var
1023 commandBufferPool: VkCommandPool 1174 commandBufferPool: VkCommandPool
1024 cmdBuffers: array[INFLIGHTFRAMES.int, VkCommandBuffer] 1175 cmdBuffers: array[INFLIGHTFRAMES.int, VkCommandBuffer]
1086 block: 1237 block:
1087 Bind(pipeline1, cmd, currentFrameInFlight = currentFrameInFlight) 1238 Bind(pipeline1, cmd, currentFrameInFlight = currentFrameInFlight)
1088 1239
1089 # render object, will be loop 1240 # render object, will be loop
1090 block: 1241 block:
1091 Render(pipeline1, myRenderable, myGlobals, cmd) 1242 Render(pipeline1, myRenderable, uniforms1, myGlobals, cmd)
1092 1243
1093 vkCmdEndRenderPass(cmd) 1244 vkCmdEndRenderPass(cmd)
1094 checkVkResult cmd.vkEndCommandBuffer() 1245 checkVkResult cmd.vkEndCommandBuffer()