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