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