Mercurial > games > semicongine
comparison vulkan_utils.nim @ 1188:427c11c0aeb1 compiletime-tests
add: missing file
| author | sam <sam@basx.dev> |
|---|---|
| date | Sun, 07 Jul 2024 15:09:14 +0700 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1187:b14861786b61 | 1188:427c11c0aeb1 |
|---|---|
| 1 import std/strformat | |
| 2 | |
| 3 import semicongine/core/vulkanapi | |
| 4 | |
| 5 type | |
| 6 VulkanGlobals* = object | |
| 7 instance*: VkInstance | |
| 8 device*: VkDevice | |
| 9 physicalDevice*: VkPhysicalDevice | |
| 10 queueFamilyIndex*: uint32 | |
| 11 queue*: VkQueue | |
| 12 anisotropy*: float32 = 0 # needs to be enable during device creation | |
| 13 | |
| 14 var vulkan*: VulkanGlobals | |
| 15 | |
| 16 proc svkGetPhysicalDeviceProperties*(): VkPhysicalDeviceProperties = | |
| 17 vkGetPhysicalDeviceProperties(vulkan.physicalDevice, addr(result)) | |
| 18 | |
| 19 proc svkCreateBuffer*(size: uint64, usage: openArray[VkBufferUsageFlagBits]): VkBuffer = | |
| 20 var createInfo = VkBufferCreateInfo( | |
| 21 sType: VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | |
| 22 flags: VkBufferCreateFlags(0), | |
| 23 size: size, | |
| 24 usage: usage.toBits, | |
| 25 sharingMode: VK_SHARING_MODE_EXCLUSIVE, | |
| 26 ) | |
| 27 checkVkResult vkCreateBuffer( | |
| 28 device = vulkan.device, | |
| 29 pCreateInfo = addr(createInfo), | |
| 30 pAllocator = nil, | |
| 31 pBuffer = addr(result), | |
| 32 ) | |
| 33 | |
| 34 proc svkAllocateMemory*(size: uint64, typeIndex: uint32): VkDeviceMemory = | |
| 35 var memoryAllocationInfo = VkMemoryAllocateInfo( | |
| 36 sType: VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, | |
| 37 allocationSize: size, | |
| 38 memoryTypeIndex: typeIndex, | |
| 39 ) | |
| 40 checkVkResult vkAllocateMemory( | |
| 41 vulkan.device, | |
| 42 addr(memoryAllocationInfo), | |
| 43 nil, | |
| 44 addr(result), | |
| 45 ) | |
| 46 | |
| 47 proc svkCreate2DImage*(width, height: uint32, format: VkFormat, usage: openArray[VkImageUsageFlagBits]): VkImage = | |
| 48 var imageProps: VkImageFormatProperties | |
| 49 checkVkResult vkGetPhysicalDeviceImageFormatProperties( | |
| 50 vulkan.physicalDevice, | |
| 51 format, | |
| 52 VK_IMAGE_TYPE_2D, | |
| 53 VK_IMAGE_TILING_OPTIMAL, | |
| 54 usage.toBits, | |
| 55 VkImageCreateFlags(0), | |
| 56 addr(imageProps) | |
| 57 ) | |
| 58 | |
| 59 var imageInfo = VkImageCreateInfo( | |
| 60 sType: VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, | |
| 61 imageType: VK_IMAGE_TYPE_2D, | |
| 62 extent: VkExtent3D(width: width, height: height, depth: 1), | |
| 63 mipLevels: min(1'u32, imageProps.maxMipLevels), | |
| 64 arrayLayers: min(1'u32, imageProps.maxArrayLayers), | |
| 65 format: format, | |
| 66 tiling: VK_IMAGE_TILING_OPTIMAL, | |
| 67 initialLayout: VK_IMAGE_LAYOUT_UNDEFINED, | |
| 68 usage: usage.toBits, | |
| 69 sharingMode: VK_SHARING_MODE_EXCLUSIVE, | |
| 70 samples: VK_SAMPLE_COUNT_1_BIT, | |
| 71 ) | |
| 72 checkVkResult vkCreateImage(vulkan.device, addr imageInfo, nil, addr(result)) | |
| 73 | |
| 74 proc svkGetDeviceQueue*(device: VkDevice, queueFamilyIndex: uint32, qType: VkQueueFlagBits): VkQueue = | |
| 75 vkGetDeviceQueue( | |
| 76 device, | |
| 77 queueFamilyIndex, | |
| 78 0, | |
| 79 addr(result), | |
| 80 ) | |
| 81 | |
| 82 proc svkGetBufferMemoryRequirements*(buffer: VkBuffer): tuple[size: uint64, alignment: uint64, memoryTypes: seq[uint32]] = | |
| 83 var reqs: VkMemoryRequirements | |
| 84 vkGetBufferMemoryRequirements(vulkan.device, buffer, addr(reqs)) | |
| 85 result.size = reqs.size | |
| 86 result.alignment = reqs.alignment | |
| 87 for i in 0'u32 ..< VK_MAX_MEMORY_TYPES: | |
| 88 if ((1'u32 shl i) and reqs.memoryTypeBits) > 0: | |
| 89 result.memoryTypes.add i | |
| 90 | |
| 91 proc svkGetImageMemoryRequirements*(image: VkImage): tuple[size: uint64, alignment: uint64, memoryTypes: seq[uint32]] = | |
| 92 var reqs: VkMemoryRequirements | |
| 93 vkGetImageMemoryRequirements(vulkan.device, image, addr(reqs)) | |
| 94 result.size = reqs.size | |
| 95 result.alignment = reqs.alignment | |
| 96 for i in 0'u32 ..< VK_MAX_MEMORY_TYPES: | |
| 97 if ((1'u32 shl i) and reqs.memoryTypeBits) > 0: | |
| 98 result.memoryTypes.add i | |
| 99 | |
| 100 proc BestMemory*(mappable: bool, filter: seq[uint32] = @[]): uint32 = | |
| 101 var physicalProperties: VkPhysicalDeviceMemoryProperties | |
| 102 vkGetPhysicalDeviceMemoryProperties(vulkan.physicalDevice, addr(physicalProperties)) | |
| 103 | |
| 104 var maxScore: float = -1 | |
| 105 var maxIndex: uint32 = 0 | |
| 106 for index in 0'u32 ..< physicalProperties.memoryTypeCount: | |
| 107 if filter.len == 0 or index in filter: | |
| 108 let flags = toEnums(physicalProperties.memoryTypes[index].propertyFlags) | |
| 109 if not mappable or VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT in flags: | |
| 110 var score: float = 0 | |
| 111 if VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT in flags: score += 1_000_000 | |
| 112 if VK_MEMORY_PROPERTY_HOST_CACHED_BIT in flags: score += 1_000 | |
| 113 score += float(physicalProperties.memoryHeaps[physicalProperties.memoryTypes[index].heapIndex].size) / 1_000_000_000 | |
| 114 if score > maxScore: | |
| 115 maxScore = score | |
| 116 maxIndex = index | |
| 117 assert maxScore > 0, &"Unable to find memory type (mappable: {mappable}, filter: {filter})" | |
| 118 return maxIndex | |
| 119 | |
| 120 template WithSingleUseCommandBuffer*(cmd, body: untyped): untyped = | |
| 121 block: | |
| 122 var | |
| 123 commandBufferPool: VkCommandPool | |
| 124 createInfo = VkCommandPoolCreateInfo( | |
| 125 sType: VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, | |
| 126 flags: toBits [VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT], | |
| 127 queueFamilyIndex: vulkan.queueFamilyIndex, | |
| 128 ) | |
| 129 checkVkResult vkCreateCommandPool(vulkan.device, addr createInfo, nil, addr(commandBufferPool)) | |
| 130 var | |
| 131 `cmd` {.inject.}: VkCommandBuffer | |
| 132 allocInfo = VkCommandBufferAllocateInfo( | |
| 133 sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, | |
| 134 commandPool: commandBufferPool, | |
| 135 level: VK_COMMAND_BUFFER_LEVEL_PRIMARY, | |
| 136 commandBufferCount: 1, | |
| 137 ) | |
| 138 checkVkResult vulkan.device.vkAllocateCommandBuffers(addr allocInfo, addr(`cmd`)) | |
| 139 var beginInfo = VkCommandBufferBeginInfo( | |
| 140 sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, | |
| 141 flags: VkCommandBufferUsageFlags(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT), | |
| 142 ) | |
| 143 checkVkResult `cmd`.vkBeginCommandBuffer(addr beginInfo) | |
| 144 | |
| 145 body | |
| 146 | |
| 147 checkVkResult `cmd`.vkEndCommandBuffer() | |
| 148 var submitInfo = VkSubmitInfo( | |
| 149 sType: VK_STRUCTURE_TYPE_SUBMIT_INFO, | |
| 150 commandBufferCount: 1, | |
| 151 pCommandBuffers: addr(`cmd`), | |
| 152 ) | |
| 153 | |
| 154 var | |
| 155 fence: VkFence | |
| 156 fenceInfo = VkFenceCreateInfo( | |
| 157 sType: VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, | |
| 158 # flags: toBits [VK_FENCE_CREATE_SIGNALED_BIT] | |
| 159 ) | |
| 160 checkVkResult vulkan.device.vkCreateFence(addr(fenceInfo), nil, addr(fence)) | |
| 161 checkVkResult vkQueueSubmit(vulkan.queue, 1, addr(submitInfo), fence) | |
| 162 checkVkResult vkWaitForFences(vulkan.device, 1, addr fence, false, high(uint64)) | |
| 163 vkDestroyCommandPool(vulkan.device, commandBufferPool, nil) | |
| 164 | |
| 165 template WithStagingBuffer*[T: (VkBuffer, uint64)|(VkImage, uint32, uint32)]( | |
| 166 target: T, | |
| 167 bufferSize: uint64, | |
| 168 dataPointer, | |
| 169 body: untyped | |
| 170 ): untyped = | |
| 171 var `dataPointer` {.inject.}: pointer | |
| 172 let stagingBuffer = svkCreateBuffer(bufferSize, [VK_BUFFER_USAGE_TRANSFER_SRC_BIT]) | |
| 173 let memoryRequirements = svkGetBufferMemoryRequirements(stagingBuffer) | |
| 174 let memoryType = BestMemory(mappable = true, filter = memoryRequirements.memoryTypes) | |
| 175 let stagingMemory = svkAllocateMemory(memoryRequirements.size, memoryType) | |
| 176 checkVkResult vkMapMemory( | |
| 177 device = vulkan.device, | |
| 178 memory = stagingMemory, | |
| 179 offset = 0'u64, | |
| 180 size = VK_WHOLE_SIZE, | |
| 181 flags = VkMemoryMapFlags(0), | |
| 182 ppData = addr(`dataPointer`) | |
| 183 ) | |
| 184 checkVkResult vkBindBufferMemory(vulkan.device, stagingBuffer, stagingMemory, 0) | |
| 185 | |
| 186 block: | |
| 187 # usually: write data to dataPointer in body | |
| 188 body | |
| 189 | |
| 190 var stagingRange = VkMappedMemoryRange( | |
| 191 sType: VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, | |
| 192 memory: stagingMemory, | |
| 193 size: VK_WHOLE_SIZE, | |
| 194 ) | |
| 195 checkVkResult vkFlushMappedMemoryRanges(vulkan.device, 1, addr(stagingRange)) | |
| 196 | |
| 197 WithSingleUseCommandBuffer(commandBuffer): | |
| 198 when T is (VkBuffer, uint64): | |
| 199 let copyRegion = VkBufferCopy( | |
| 200 size: bufferSize, | |
| 201 dstOffset: target[1], | |
| 202 srcOffset: 0 | |
| 203 ) | |
| 204 vkCmdCopyBuffer( | |
| 205 commandBuffer = commandBuffer, | |
| 206 srcBuffer = stagingBuffer, | |
| 207 dstBuffer = target[0], | |
| 208 regionCount = 1, | |
| 209 pRegions = addr(copyRegion) | |
| 210 ) | |
| 211 elif T is (VkImage, uint32, uint32): | |
| 212 let region = VkBufferImageCopy( | |
| 213 bufferOffset: 0, | |
| 214 bufferRowLength: 0, | |
| 215 bufferImageHeight: 0, | |
| 216 imageSubresource: VkImageSubresourceLayers( | |
| 217 aspectMask: toBits [VK_IMAGE_ASPECT_COLOR_BIT], | |
| 218 mipLevel: 0, | |
| 219 baseArrayLayer: 0, | |
| 220 layerCount: 1, | |
| 221 ), | |
| 222 imageOffset: VkOffset3D(x: 0, y: 0, z: 0), | |
| 223 imageExtent: VkExtent3D(width: target[1], height: target[2], depth: 1) | |
| 224 ) | |
| 225 vkCmdCopyBufferToImage( | |
| 226 commandBuffer = commandBuffer, | |
| 227 srcBuffer = stagingBuffer, | |
| 228 dstImage = target[0], | |
| 229 dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | |
| 230 regionCount = 1, | |
| 231 pRegions = addr(region) | |
| 232 ) | |
| 233 | |
| 234 vkDestroyBuffer(vulkan.device, stagingBuffer, nil) | |
| 235 vkFreeMemory(vulkan.device, stagingMemory, nil) | |
| 236 |
