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