Mercurial > games > semicongine
comparison semiconginev2/rendering/vulkan_wrappers.nim @ 1218:56781cc0fc7c compiletime-tests
did: renamge main package
author | sam <sam@basx.dev> |
---|---|
date | Wed, 17 Jul 2024 21:01:37 +0700 |
parents | semicongine/rendering/vulkan_wrappers.nim@04e446a7eb2b |
children | 5dcb503ef0c0 |
comparison
equal
deleted
inserted
replaced
1217:f819a874058f | 1218:56781cc0fc7c |
---|---|
1 proc GetBestPhysicalDevice(instance: VkInstance): VkPhysicalDevice = | |
2 var nDevices: uint32 | |
3 checkVkResult vkEnumeratePhysicalDevices(instance, addr(nDevices), nil) | |
4 var devices = newSeq[VkPhysicalDevice](nDevices) | |
5 checkVkResult vkEnumeratePhysicalDevices(instance, addr(nDevices), devices.ToCPointer) | |
6 | |
7 var score = 0'u32 | |
8 for pDevice in devices: | |
9 var props: VkPhysicalDeviceProperties | |
10 # CANNOT use svkGetPhysicalDeviceProperties (not initialized yet) | |
11 vkGetPhysicalDeviceProperties(pDevice, addr(props)) | |
12 if props.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU and props.limits.maxImageDimension2D > score: | |
13 score = props.limits.maxImageDimension2D | |
14 result = pDevice | |
15 | |
16 if score == 0: | |
17 for pDevice in devices: | |
18 var props: VkPhysicalDeviceProperties | |
19 # CANNOT use svkGetPhysicalDeviceProperties (not initialized yet) | |
20 vkGetPhysicalDeviceProperties(pDevice, addr(props)) | |
21 if props.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU and props.limits.maxImageDimension2D > score: | |
22 score = props.limits.maxImageDimension2D | |
23 result = pDevice | |
24 | |
25 assert score > 0, "Unable to find integrated or discrete GPU" | |
26 | |
27 proc svkGetPhysicalDeviceSurfaceSupportKHR*(queueFamily: uint32): bool = | |
28 var presentation = VkBool32(false) | |
29 checkVkResult vkGetPhysicalDeviceSurfaceSupportKHR(vulkan.physicalDevice, queueFamily, vulkan.surface, addr(presentation)) | |
30 return bool(presentation) | |
31 | |
32 proc GetQueueFamily(pDevice: VkPhysicalDevice, qType: VkQueueFlagBits): uint32 = | |
33 var nQueuefamilies: uint32 | |
34 vkGetPhysicalDeviceQueueFamilyProperties(pDevice, addr nQueuefamilies, nil) | |
35 var queuFamilies = newSeq[VkQueueFamilyProperties](nQueuefamilies) | |
36 vkGetPhysicalDeviceQueueFamilyProperties(pDevice, addr nQueuefamilies, queuFamilies.ToCPointer) | |
37 for i in 0'u32 ..< nQueuefamilies: | |
38 if qType in toEnums(queuFamilies[i].queueFlags): | |
39 # for graphics queues we always also want prsentation, they seem never to be separated in practice | |
40 if svkGetPhysicalDeviceSurfaceSupportKHR(i) or qType != VK_QUEUE_GRAPHICS_BIT: | |
41 return i | |
42 assert false, &"Queue of type {qType} not found" | |
43 | |
44 proc svkGetDeviceQueue*(device: VkDevice, queueFamilyIndex: uint32, qType: VkQueueFlagBits): VkQueue = | |
45 vkGetDeviceQueue( | |
46 device, | |
47 queueFamilyIndex, | |
48 0, | |
49 addr(result), | |
50 ) | |
51 | |
52 proc DefaultSurfaceFormat(): VkFormat = | |
53 # EVERY windows driver and almost every linux driver should support this | |
54 VK_FORMAT_B8G8R8A8_SRGB | |
55 | |
56 func size(format: VkFormat): uint64 = | |
57 const formatSize = [ | |
58 VK_FORMAT_B8G8R8A8_SRGB.int: 4'u64, | |
59 ] | |
60 return formatSize[format.int] | |
61 | |
62 proc svkGetPhysicalDeviceSurfacePresentModesKHR*(): seq[VkPresentModeKHR] = | |
63 var n_modes: uint32 | |
64 checkVkResult vkGetPhysicalDeviceSurfacePresentModesKHR(vulkan.physicalDevice, vulkan.surface, addr(n_modes), nil) | |
65 result = newSeq[VkPresentModeKHR](n_modes) | |
66 checkVkResult vkGetPhysicalDeviceSurfacePresentModesKHR(vulkan.physicalDevice, vulkan.surface, addr(n_modes), result.ToCPointer) | |
67 | |
68 proc svkGetPhysicalDeviceSurfaceFormatsKHR(): seq[VkSurfaceFormatKHR] = | |
69 var n_formats: uint32 | |
70 checkVkResult vkGetPhysicalDeviceSurfaceFormatsKHR(vulkan.physicalDevice, vulkan.surface, addr(n_formats), nil) | |
71 result = newSeq[VkSurfaceFormatKHR](n_formats) | |
72 checkVkResult vkGetPhysicalDeviceSurfaceFormatsKHR(vulkan.physicalDevice, vulkan.surface, addr(n_formats), result.ToCPointer) | |
73 | |
74 proc hasValidationLayer*(): bool = | |
75 var n_layers: uint32 | |
76 checkVkResult vkEnumerateInstanceLayerProperties(addr(n_layers), nil) | |
77 if n_layers > 0: | |
78 var layers = newSeq[VkLayerProperties](n_layers) | |
79 checkVkResult vkEnumerateInstanceLayerProperties(addr(n_layers), layers.ToCPointer) | |
80 for layer in layers: | |
81 if layer.layerName.CleanString == "VK_LAYER_KHRONOS_validation": | |
82 return true | |
83 return false | |
84 | |
85 proc svkGetPhysicalDeviceProperties*(): VkPhysicalDeviceProperties = | |
86 vkGetPhysicalDeviceProperties(vulkan.physicalDevice, addr(result)) | |
87 | |
88 proc svkCreateBuffer*(size: uint64, usage: openArray[VkBufferUsageFlagBits]): VkBuffer = | |
89 var createInfo = VkBufferCreateInfo( | |
90 sType: VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | |
91 flags: VkBufferCreateFlags(0), | |
92 size: size, | |
93 usage: usage.toBits, | |
94 sharingMode: VK_SHARING_MODE_EXCLUSIVE, | |
95 ) | |
96 checkVkResult vkCreateBuffer( | |
97 device = vulkan.device, | |
98 pCreateInfo = addr(createInfo), | |
99 pAllocator = nil, | |
100 pBuffer = addr(result), | |
101 ) | |
102 | |
103 proc svkAllocateMemory*(size: uint64, typeIndex: uint32): VkDeviceMemory = | |
104 var memoryAllocationInfo = VkMemoryAllocateInfo( | |
105 sType: VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, | |
106 allocationSize: size, | |
107 memoryTypeIndex: typeIndex, | |
108 ) | |
109 checkVkResult vkAllocateMemory( | |
110 vulkan.device, | |
111 addr(memoryAllocationInfo), | |
112 nil, | |
113 addr(result), | |
114 ) | |
115 | |
116 proc svkCreate2DImage*(width, height: uint32, format: VkFormat, usage: openArray[VkImageUsageFlagBits], samples = VK_SAMPLE_COUNT_1_BIT): VkImage = | |
117 var imageProps: VkImageFormatProperties | |
118 checkVkResult vkGetPhysicalDeviceImageFormatProperties( | |
119 vulkan.physicalDevice, | |
120 format, | |
121 VK_IMAGE_TYPE_2D, | |
122 VK_IMAGE_TILING_OPTIMAL, | |
123 usage.toBits, | |
124 VkImageCreateFlags(0), | |
125 addr(imageProps) | |
126 ) | |
127 | |
128 var imageInfo = VkImageCreateInfo( | |
129 sType: VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, | |
130 imageType: VK_IMAGE_TYPE_2D, | |
131 extent: VkExtent3D(width: width, height: height, depth: 1), | |
132 mipLevels: min(1'u32, imageProps.maxMipLevels), | |
133 arrayLayers: min(1'u32, imageProps.maxArrayLayers), | |
134 format: format, | |
135 tiling: VK_IMAGE_TILING_OPTIMAL, | |
136 initialLayout: VK_IMAGE_LAYOUT_UNDEFINED, | |
137 usage: usage.toBits, | |
138 sharingMode: VK_SHARING_MODE_EXCLUSIVE, | |
139 samples: samples, | |
140 ) | |
141 checkVkResult vkCreateImage(vulkan.device, addr imageInfo, nil, addr(result)) | |
142 | |
143 proc svkCreate2DImageView(image: VkImage, format: VkFormat): VkImageView = | |
144 var createInfo = VkImageViewCreateInfo( | |
145 sType: VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | |
146 image: image, | |
147 viewType: VK_IMAGE_VIEW_TYPE_2D, | |
148 format: format, | |
149 components: VkComponentMapping( | |
150 r: VK_COMPONENT_SWIZZLE_IDENTITY, | |
151 g: VK_COMPONENT_SWIZZLE_IDENTITY, | |
152 b: VK_COMPONENT_SWIZZLE_IDENTITY, | |
153 a: VK_COMPONENT_SWIZZLE_IDENTITY, | |
154 ), | |
155 subresourceRange: VkImageSubresourceRange( | |
156 aspectMask: VkImageAspectFlags(VK_IMAGE_ASPECT_COLOR_BIT), | |
157 baseMipLevel: 0, | |
158 levelCount: 1, | |
159 baseArrayLayer: 0, | |
160 layerCount: 1, | |
161 ), | |
162 ) | |
163 checkVkResult vkCreateImageView(vulkan.device, addr(createInfo), nil, addr(result)) | |
164 | |
165 proc svkCreateFramebuffer*(renderpass: VkRenderPass, width, height: uint32, attachments: openArray[VkImageView]): VkFramebuffer = | |
166 var framebufferInfo = VkFramebufferCreateInfo( | |
167 sType: VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, | |
168 renderPass: renderpass, | |
169 attachmentCount: attachments.len.uint32, | |
170 pAttachments: attachments.ToCPointer, | |
171 width: width, | |
172 height: height, | |
173 layers: 1, | |
174 ) | |
175 checkVkResult vkCreateFramebuffer(vulkan.device, addr(framebufferInfo), nil, addr(result)) | |
176 | |
177 proc svkGetBufferMemoryRequirements*(buffer: VkBuffer): tuple[size: uint64, alignment: uint64, memoryTypes: seq[uint32]] = | |
178 var reqs: VkMemoryRequirements | |
179 vkGetBufferMemoryRequirements(vulkan.device, buffer, addr(reqs)) | |
180 result.size = reqs.size | |
181 result.alignment = reqs.alignment | |
182 for i in 0'u32 ..< VK_MAX_MEMORY_TYPES: | |
183 if ((1'u32 shl i) and reqs.memoryTypeBits) > 0: | |
184 result.memoryTypes.add i | |
185 | |
186 proc svkGetImageMemoryRequirements*(image: VkImage): tuple[size: uint64, alignment: uint64, memoryTypes: seq[uint32]] = | |
187 var reqs: VkMemoryRequirements | |
188 vkGetImageMemoryRequirements(vulkan.device, image, addr(reqs)) | |
189 result.size = reqs.size | |
190 result.alignment = reqs.alignment | |
191 for i in 0'u32 ..< VK_MAX_MEMORY_TYPES: | |
192 if ((1'u32 shl i) and reqs.memoryTypeBits) > 0: | |
193 result.memoryTypes.add i | |
194 | |
195 proc svkCreateFence*(signaled = false): VkFence = | |
196 var fenceInfo = VkFenceCreateInfo( | |
197 sType: VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, | |
198 flags: if signaled: toBits [VK_FENCE_CREATE_SIGNALED_BIT] else: VkFenceCreateFlags(0) | |
199 ) | |
200 checkVkResult vkCreateFence(vulkan.device, addr(fenceInfo), nil, addr(result)) | |
201 | |
202 proc svkCreateSemaphore*(): VkSemaphore = | |
203 var semaphoreInfo = VkSemaphoreCreateInfo(sType: VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO) | |
204 checkVkResult vkCreateSemaphore(vulkan.device, addr(semaphoreInfo), nil, addr(result)) | |
205 | |
206 proc Await*(fence: VkFence, timeout = high(uint64)): bool = | |
207 let waitResult = vkWaitForFences(vulkan.device, 1, addr(fence), false, timeout) | |
208 if waitResult == VK_TIMEOUT: | |
209 return false | |
210 checkVkResult waitResult | |
211 return true | |
212 | |
213 proc svkResetFences*(fence: VkFence) = | |
214 checkVkResult vkResetFences(vulkan.device, 1, addr(fence)) | |
215 | |
216 proc svkCmdBindDescriptorSets(commandBuffer: VkCommandBuffer, descriptorSets: openArray[VkDescriptorSet], layout: VkPipelineLayout) = | |
217 vkCmdBindDescriptorSets( | |
218 commandBuffer = commandBuffer, | |
219 pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, | |
220 layout = layout, | |
221 firstSet = 0, | |
222 descriptorSetCount = descriptorSets.len.uint32, | |
223 pDescriptorSets = descriptorSets.ToCPointer, | |
224 dynamicOffsetCount = 0, | |
225 pDynamicOffsets = nil | |
226 ) | |
227 | |
228 | |
229 proc svkCreateRenderPass( | |
230 attachments: openArray[VkAttachmentDescription], | |
231 colorAttachments: openArray[VkAttachmentReference], | |
232 resolveAttachments: openArray[VkAttachmentReference], | |
233 dependencies: openArray[VkSubpassDependency], | |
234 ): VkRenderPass = | |
235 assert colorAttachments.len == resolveAttachments.len or resolveAttachments.len == 0 | |
236 var subpass = VkSubpassDescription( | |
237 flags: VkSubpassDescriptionFlags(0), | |
238 pipelineBindPoint: VK_PIPELINE_BIND_POINT_GRAPHICS, | |
239 inputAttachmentCount: 0, | |
240 pInputAttachments: nil, | |
241 colorAttachmentCount: colorAttachments.len.uint32, | |
242 pColorAttachments: colorAttachments.ToCPointer, | |
243 pResolveAttachments: resolveAttachments.ToCPointer, | |
244 pDepthStencilAttachment: nil, | |
245 preserveAttachmentCount: 0, | |
246 pPreserveAttachments: nil, | |
247 ) | |
248 var createInfo = VkRenderPassCreateInfo( | |
249 sType: VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, | |
250 attachmentCount: uint32(attachments.len), | |
251 pAttachments: attachments.ToCPointer, | |
252 subpassCount: 1, | |
253 pSubpasses: addr(subpass), | |
254 dependencyCount: uint32(dependencies.len), | |
255 pDependencies: dependencies.ToCPointer, | |
256 ) | |
257 checkVkResult vkCreateRenderPass(vulkan.device, addr(createInfo), nil, addr(result)) | |
258 | |
259 proc BestMemory*(mappable: bool, filter: seq[uint32] = @[]): uint32 = | |
260 var physicalProperties: VkPhysicalDeviceMemoryProperties | |
261 vkGetPhysicalDeviceMemoryProperties(vulkan.physicalDevice, addr(physicalProperties)) | |
262 | |
263 var maxScore: float = -1 | |
264 var maxIndex: uint32 = 0 | |
265 for index in 0'u32 ..< physicalProperties.memoryTypeCount: | |
266 if filter.len == 0 or index in filter: | |
267 let flags = toEnums(physicalProperties.memoryTypes[index].propertyFlags) | |
268 if not mappable or VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT in flags: | |
269 var score: float = 0 | |
270 if VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT in flags: score += 1_000_000 | |
271 if VK_MEMORY_PROPERTY_HOST_CACHED_BIT in flags: score += 1_000 | |
272 score += float(physicalProperties.memoryHeaps[physicalProperties.memoryTypes[index].heapIndex].size) / 1_000_000_000 | |
273 if score > maxScore: | |
274 maxScore = score | |
275 maxIndex = index | |
276 assert maxScore > 0, &"Unable to find memory type (mappable: {mappable}, filter: {filter})" | |
277 return maxIndex | |
278 | |
279 template WithSingleUseCommandBuffer*(cmd, body: untyped): untyped = | |
280 block: | |
281 var | |
282 commandBufferPool: VkCommandPool | |
283 createInfo = VkCommandPoolCreateInfo( | |
284 sType: VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, | |
285 flags: VkCommandPoolCreateFlags(0), | |
286 queueFamilyIndex: vulkan.graphicsQueueFamily, | |
287 ) | |
288 checkVkResult vkCreateCommandPool(vulkan.device, addr createInfo, nil, addr(commandBufferPool)) | |
289 var | |
290 `cmd` {.inject.}: VkCommandBuffer | |
291 allocInfo = VkCommandBufferAllocateInfo( | |
292 sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, | |
293 commandPool: commandBufferPool, | |
294 level: VK_COMMAND_BUFFER_LEVEL_PRIMARY, | |
295 commandBufferCount: 1, | |
296 ) | |
297 checkVkResult vulkan.device.vkAllocateCommandBuffers(addr allocInfo, addr(`cmd`)) | |
298 var beginInfo = VkCommandBufferBeginInfo( | |
299 sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, | |
300 flags: VkCommandBufferUsageFlags(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT), | |
301 ) | |
302 checkVkResult `cmd`.vkBeginCommandBuffer(addr beginInfo) | |
303 | |
304 body | |
305 | |
306 checkVkResult `cmd`.vkEndCommandBuffer() | |
307 var submitInfo = VkSubmitInfo( | |
308 sType: VK_STRUCTURE_TYPE_SUBMIT_INFO, | |
309 commandBufferCount: 1, | |
310 pCommandBuffers: addr(`cmd`), | |
311 ) | |
312 | |
313 var fence = svkCreateFence() | |
314 checkVkResult vkQueueSubmit(vulkan.graphicsQueue, 1, addr(submitInfo), fence) | |
315 discard fence.Await() | |
316 vkDestroyFence(vulkan.device, fence, nil) | |
317 vkDestroyCommandPool(vulkan.device, commandBufferPool, nil) | |
318 | |
319 template WithStagingBuffer*[T: (VkBuffer, uint64)|(VkImage, uint32, uint32)]( | |
320 target: T, | |
321 bufferSize: uint64, | |
322 dataPointer, | |
323 body: untyped | |
324 ): untyped = | |
325 var `dataPointer` {.inject.}: pointer | |
326 let stagingBuffer = svkCreateBuffer(bufferSize, [VK_BUFFER_USAGE_TRANSFER_SRC_BIT]) | |
327 let memoryRequirements = svkGetBufferMemoryRequirements(stagingBuffer) | |
328 let memoryType = BestMemory(mappable = true, filter = memoryRequirements.memoryTypes) | |
329 let stagingMemory = svkAllocateMemory(memoryRequirements.size, memoryType) | |
330 checkVkResult vkMapMemory( | |
331 device = vulkan.device, | |
332 memory = stagingMemory, | |
333 offset = 0'u64, | |
334 size = VK_WHOLE_SIZE, | |
335 flags = VkMemoryMapFlags(0), | |
336 ppData = addr(`dataPointer`) | |
337 ) | |
338 checkVkResult vkBindBufferMemory(vulkan.device, stagingBuffer, stagingMemory, 0) | |
339 | |
340 block: | |
341 # usually: write data to dataPointer in body | |
342 body | |
343 | |
344 var stagingRange = VkMappedMemoryRange( | |
345 sType: VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, | |
346 memory: stagingMemory, | |
347 size: VK_WHOLE_SIZE, | |
348 ) | |
349 checkVkResult vkFlushMappedMemoryRanges(vulkan.device, 1, addr(stagingRange)) | |
350 | |
351 WithSingleUseCommandBuffer(commandBuffer): | |
352 when T is (VkBuffer, uint64): | |
353 let copyRegion = VkBufferCopy( | |
354 size: bufferSize, | |
355 dstOffset: target[1], | |
356 srcOffset: 0 | |
357 ) | |
358 vkCmdCopyBuffer( | |
359 commandBuffer = commandBuffer, | |
360 srcBuffer = stagingBuffer, | |
361 dstBuffer = target[0], | |
362 regionCount = 1, | |
363 pRegions = addr(copyRegion) | |
364 ) | |
365 elif T is (VkImage, uint32, uint32): | |
366 let region = VkBufferImageCopy( | |
367 bufferOffset: 0, | |
368 bufferRowLength: 0, | |
369 bufferImageHeight: 0, | |
370 imageSubresource: VkImageSubresourceLayers( | |
371 aspectMask: toBits [VK_IMAGE_ASPECT_COLOR_BIT], | |
372 mipLevel: 0, | |
373 baseArrayLayer: 0, | |
374 layerCount: 1, | |
375 ), | |
376 imageOffset: VkOffset3D(x: 0, y: 0, z: 0), | |
377 imageExtent: VkExtent3D(width: target[1], height: target[2], depth: 1) | |
378 ) | |
379 vkCmdCopyBufferToImage( | |
380 commandBuffer = commandBuffer, | |
381 srcBuffer = stagingBuffer, | |
382 dstImage = target[0], | |
383 dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | |
384 regionCount = 1, | |
385 pRegions = addr(region) | |
386 ) | |
387 | |
388 vkDestroyBuffer(vulkan.device, stagingBuffer, nil) | |
389 vkFreeMemory(vulkan.device, stagingMemory, nil) | |
390 |