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 |