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 |
