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