Mercurial > games > semicongine
annotate src/vulkan_helpers.nim @ 2:213fdf8d31dd
did: hello world triangle, a bit of code organization
| author | Sam <sam@basx.dev> |
|---|---|
| date | Mon, 19 Dec 2022 10:41:20 +0700 |
| parents | bb2a7d3a7003 |
| children | af9183acb173 |
| rev | line source |
|---|---|
| 1 | 1 import std/tables |
| 0 | 2 import std/strutils |
|
2
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
3 import std/strformat |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
4 import std/logging |
| 1 | 5 |
| 6 import ./glslang/glslang | |
| 7 import ./vulkan | |
| 8 | |
| 0 | 9 when defined(release): |
|
2
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
10 const ENABLEVULKANVALIDATIONLAYERS* = false |
| 0 | 11 else: |
|
2
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
12 const ENABLEVULKANVALIDATIONLAYERS* = true |
| 0 | 13 |
| 14 | |
| 15 template checkVkResult*(call: untyped) = | |
|
2
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
16 when defined(release): |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
17 discard call |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
18 else: |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
19 let value = call |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
20 debug(&"CALLING vulkan: {astToStr(call)}") |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
21 if value != VK_SUCCESS: |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
22 raise newException(Exception, "Vulkan error: " & astToStr(call) & " returned " & $value) |
| 0 | 23 |
| 24 | |
| 25 proc VK_MAKE_API_VERSION*(variant: uint32, major: uint32, minor: uint32, patch: uint32): uint32 {.compileTime.} = | |
| 26 (variant shl 29) or (major shl 22) or (minor shl 12) or patch | |
| 27 | |
| 1 | 28 |
|
2
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
29 proc filterForSurfaceFormat*(formats: seq[VkSurfaceFormatKHR]): seq[VkSurfaceFormatKHR] = |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
30 for format in formats: |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
31 if format.format == VK_FORMAT_B8G8R8A8_SRGB and format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR: |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
32 result.add(format) |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
33 |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
34 |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
35 proc cleanString*(str: openArray[char]): string = |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
36 for i in 0 ..< len(str): |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
37 if str[i] == char(0): |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
38 result = join(str[0 ..< i]) |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
39 break |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
40 |
| 0 | 41 proc getInstanceExtensions*(): seq[string] = |
| 42 var extensionCount: uint32 | |
| 43 checkVkResult vkEnumerateInstanceExtensionProperties(nil, addr(extensionCount), nil) | |
| 44 var extensions = newSeq[VkExtensionProperties](extensionCount) | |
| 45 checkVkResult vkEnumerateInstanceExtensionProperties(nil, addr(extensionCount), addr(extensions[0])) | |
| 46 | |
| 47 for extension in extensions: | |
|
2
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
48 result.add(cleanString(extension.extensionName)) |
| 0 | 49 |
| 50 | |
| 51 proc getDeviceExtensions*(device: VkPhysicalDevice): seq[string] = | |
| 52 var extensionCount: uint32 | |
| 53 checkVkResult vkEnumerateDeviceExtensionProperties(device, nil, addr(extensionCount), nil) | |
| 54 var extensions = newSeq[VkExtensionProperties](extensionCount) | |
| 55 checkVkResult vkEnumerateDeviceExtensionProperties(device, nil, addr(extensionCount), addr(extensions[0])) | |
| 56 | |
| 57 for extension in extensions: | |
|
2
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
58 result.add(cleanString(extension.extensionName)) |
| 0 | 59 |
| 60 | |
| 61 proc getValidationLayers*(): seq[string] = | |
| 62 var n_layers: uint32 | |
| 63 checkVkResult vkEnumerateInstanceLayerProperties(addr(n_layers), nil) | |
| 64 var layers = newSeq[VkLayerProperties](n_layers) | |
| 65 checkVkResult vkEnumerateInstanceLayerProperties(addr(n_layers), addr(layers[0])) | |
| 66 | |
| 67 for layer in layers: | |
|
2
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
68 result.add(cleanString(layer.layerName)) |
| 0 | 69 |
| 70 | |
| 71 proc getVulkanPhysicalDevices*(instance: VkInstance): seq[VkPhysicalDevice] = | |
| 72 var n_devices: uint32 | |
| 73 checkVkResult vkEnumeratePhysicalDevices(instance, addr(n_devices), nil) | |
| 74 result = newSeq[VkPhysicalDevice](n_devices) | |
| 75 checkVkResult vkEnumeratePhysicalDevices(instance, addr(n_devices), addr(result[0])) | |
| 76 | |
| 77 | |
| 78 proc getQueueFamilies*(device: VkPhysicalDevice): seq[VkQueueFamilyProperties] = | |
| 79 var n_queuefamilies: uint32 | |
| 80 vkGetPhysicalDeviceQueueFamilyProperties(device, addr(n_queuefamilies), nil) | |
| 81 result = newSeq[VkQueueFamilyProperties](n_queuefamilies) | |
| 82 vkGetPhysicalDeviceQueueFamilyProperties(device, addr(n_queuefamilies), addr(result[0])) | |
| 83 | |
| 84 | |
| 85 proc getDeviceSurfaceFormats*(device: VkPhysicalDevice, surface: VkSurfaceKHR): seq[VkSurfaceFormatKHR] = | |
| 86 var n_formats: uint32 | |
| 87 checkVkResult vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, addr(n_formats), nil); | |
| 88 result = newSeq[VkSurfaceFormatKHR](n_formats) | |
| 89 checkVkResult vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, addr(n_formats), addr(result[0])) | |
| 90 | |
| 91 | |
| 92 proc getDeviceSurfacePresentModes*(device: VkPhysicalDevice, surface: VkSurfaceKHR): seq[VkPresentModeKHR] = | |
| 93 var n_modes: uint32 | |
| 94 checkVkResult vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, addr(n_modes), nil); | |
| 95 result = newSeq[VkPresentModeKHR](n_modes) | |
| 96 checkVkResult vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, addr(n_modes), addr(result[0])) | |
| 97 | |
| 98 | |
| 99 proc getSwapChainImages*(device: VkDevice, swapChain: VkSwapchainKHR): seq[VkImage] = | |
| 100 var n_images: uint32 | |
| 101 checkVkResult vkGetSwapchainImagesKHR(device, swapChain, addr(n_images), nil); | |
| 102 result = newSeq[VkImage](n_images) | |
| 103 checkVkResult vkGetSwapchainImagesKHR(device, swapChain, addr(n_images), addr(result[0])); | |
| 104 | |
| 105 | |
| 106 proc getPresentMode*(modes: seq[VkPresentModeKHR]): VkPresentModeKHR = | |
| 107 let preferredModes = [ | |
|
2
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
108 VK_PRESENT_MODE_MAILBOX_KHR, # triple buffering |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
109 VK_PRESENT_MODE_FIFO_RELAXED_KHR, # double duffering |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
110 VK_PRESENT_MODE_FIFO_KHR, # double duffering |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
111 VK_PRESENT_MODE_IMMEDIATE_KHR, # single buffering |
| 0 | 112 ] |
| 113 for preferredMode in preferredModes: | |
| 114 for mode in modes: | |
| 115 if preferredMode == mode: | |
| 116 return mode | |
| 117 # should never be reached, but seems to be garuanteed by vulkan specs to always be available | |
| 118 return VK_PRESENT_MODE_FIFO_KHR | |
| 119 | |
| 120 | |
| 121 proc createVulkanInstance*(vulkanVersion: uint32): VkInstance = | |
| 122 var requiredExtensions = [ | |
| 123 "VK_EXT_acquire_xlib_display".cstring, | |
| 124 "VK_EXT_direct_mode_display".cstring, | |
| 125 "VK_KHR_display".cstring, | |
| 126 "VK_KHR_surface".cstring, | |
| 127 "VK_KHR_xlib_surface".cstring, | |
|
2
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
128 "VK_EXT_debug_utils".cstring, |
| 0 | 129 ] |
| 130 let availableExtensions = getInstanceExtensions() | |
| 131 for extension in requiredExtensions: | |
| 132 assert $extension in availableExtensions | |
| 133 | |
| 134 let desiredLayers = ["VK_LAYER_KHRONOS_validation".cstring, "VK_LAYER_MESA_overlay".cstring] | |
| 135 let availableLayers = getValidationLayers() | |
| 136 var usableLayers = newSeq[cstring]() | |
| 137 | |
| 138 when ENABLEVULKANVALIDATIONLAYERS: | |
| 139 for layer in desiredLayers: | |
| 140 if $layer in availableLayers: | |
| 141 usableLayers.add(layer) | |
| 142 | |
|
2
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
143 echo "Available validation layers: ", availableLayers |
| 0 | 144 echo "Using validation layers: ", usableLayers |
|
2
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
145 echo "Available extensions: ", availableExtensions |
| 0 | 146 echo "Using extensions: ", requiredExtensions |
| 147 | |
| 148 var appinfo = VkApplicationInfo( | |
| 149 sType: VK_STRUCTURE_TYPE_APPLICATION_INFO, | |
| 150 pApplicationName: "Hello Triangle", | |
| 151 pEngineName: "Custom engine", | |
| 152 apiVersion: vulkanVersion, | |
| 153 ) | |
| 154 var createinfo = VkInstanceCreateInfo( | |
| 155 sType: VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, | |
| 156 pApplicationInfo: addr(appinfo), | |
| 157 enabledLayerCount: usableLayers.len.uint32, | |
| 158 ppEnabledLayerNames: cast[ptr UncheckedArray[cstring]](addr(usableLayers[0])), | |
| 159 enabledExtensionCount: requiredExtensions.len.uint32, | |
| 160 ppEnabledExtensionNames: cast[ptr UncheckedArray[cstring]](addr(requiredExtensions)) | |
| 161 ) | |
| 162 checkVkResult vkCreateInstance(addr(createinfo), nil, addr(result)) | |
| 163 | |
| 164 loadVK_KHR_surface() | |
| 165 loadVK_KHR_xlib_surface() | |
| 166 loadVK_KHR_swapchain() | |
|
2
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
167 when ENABLEVULKANVALIDATIONLAYERS: |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
168 loadVK_EXT_debug_utils(result) |
| 0 | 169 |
| 170 | |
| 171 proc getVulcanDevice*( | |
| 172 physicalDevice: var VkPhysicalDevice, | |
| 173 features: var VkPhysicalDeviceFeatures, | |
|
2
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
174 graphicsQueueFamily: uint32, |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
175 presentationQueueFamily: uint32, |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
176 ): (VkDevice, VkQueue, VkQueue) = |
| 0 | 177 # setup queue and device |
|
2
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
178 # TODO: need check this, possibly wrong logic, see Vulkan tutorial |
| 0 | 179 var priority = 1.0'f32 |
|
2
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
180 var queueCreateInfo = [ |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
181 VkDeviceQueueCreateInfo( |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
182 sType: VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
183 queueFamilyIndex: graphicsQueueFamily, |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
184 queueCount: 1, |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
185 pQueuePriorities: addr(priority), |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
186 ), |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
187 ] |
| 0 | 188 |
| 189 var requiredExtensions = ["VK_KHR_swapchain".cstring] | |
| 190 var deviceCreateInfo = VkDeviceCreateInfo( | |
| 191 sType: VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, | |
|
2
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
192 queueCreateInfoCount: uint32(queueCreateInfo.len), |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
193 pQueueCreateInfos: addr(queueCreateInfo[0]), |
| 0 | 194 pEnabledFeatures: addr(features), |
| 195 enabledExtensionCount: requiredExtensions.len.uint32, | |
| 196 ppEnabledExtensionNames: cast[ptr UncheckedArray[cstring]](addr(requiredExtensions)) | |
| 197 ) | |
| 198 checkVkResult vkCreateDevice(physicalDevice, addr(deviceCreateInfo), nil, addr(result[0])) | |
|
2
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
199 vkGetDeviceQueue(result[0], graphicsQueueFamily, 0'u32, addr(result[1])); |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
200 vkGetDeviceQueue(result[0], presentationQueueFamily, 0'u32, addr(result[2])); |
| 1 | 201 |
| 202 proc createShaderStage*(device: VkDevice, stage: VkShaderStageFlagBits, shader: string): VkPipelineShaderStageCreateInfo = | |
| 203 const VK_GLSL_MAP = { | |
| 204 VK_SHADER_STAGE_VERTEX_BIT: GLSLANG_STAGE_VERTEX, | |
| 205 VK_SHADER_STAGE_FRAGMENT_BIT: GLSLANG_STAGE_FRAGMENT, | |
| 206 }.toTable() | |
| 207 var code = compileGLSLToSPIRV(VK_GLSL_MAP[stage], shader, "<memory-shader>") | |
| 208 var createInfo = VkShaderModuleCreateInfo( | |
| 209 sType: VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, | |
|
2
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
210 codeSize: uint(code.len * sizeof(uint32)), |
| 1 | 211 pCode: addr(code[0]), |
| 212 ) | |
| 213 var shaderModule: VkShaderModule | |
| 214 checkVkResult vkCreateShaderModule(device, addr(createInfo), nil, addr(shaderModule)) | |
| 215 | |
|
2
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
216 return VkPipelineShaderStageCreateInfo( |
| 1 | 217 sType: VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, |
| 218 stage: stage, | |
| 219 module: shaderModule, | |
| 220 pName: "main", # entry point for shader | |
| 221 ) | |
|
2
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
222 |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
223 proc debugCallback*( |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
224 messageSeverity: VkDebugUtilsMessageSeverityFlagBitsEXT, |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
225 messageTypes: VkDebugUtilsMessageTypeFlagsEXT, |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
226 pCallbackData: VkDebugUtilsMessengerCallbackDataEXT, |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
227 userData: pointer |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
228 ): VkBool32 {.cdecl.} = |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
229 echo &"{messageSeverity}: {VkDebugUtilsMessageTypeFlagBitsEXT(messageTypes)}: {pCallbackData.pMessage}" |
|
213fdf8d31dd
did: hello world triangle, a bit of code organization
Sam <sam@basx.dev>
parents:
1
diff
changeset
|
230 return VK_FALSE |
