1
|
1 import std/tables
|
0
|
2 import std/strutils
|
1
|
3
|
|
4 import ./glslang/glslang
|
|
5 import ./vulkan
|
|
6
|
0
|
7
|
|
8 when defined(release):
|
|
9 const ENABLEVULKANVALIDATIONLAYERS = false
|
|
10 else:
|
|
11 const ENABLEVULKANVALIDATIONLAYERS = true
|
|
12
|
|
13
|
|
14 template checkVkResult*(call: untyped) =
|
|
15 let value = call
|
|
16 if value != VK_SUCCESS:
|
|
17 raise newException(Exception, "Vulkan error: " & astToStr(call) & " returned " & $value)
|
|
18
|
|
19
|
|
20 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
|
|
22
|
1
|
23
|
0
|
24 proc getInstanceExtensions*(): seq[string] =
|
|
25 var extensionCount: uint32
|
|
26 checkVkResult vkEnumerateInstanceExtensionProperties(nil, addr(extensionCount), nil)
|
|
27 var extensions = newSeq[VkExtensionProperties](extensionCount)
|
|
28 checkVkResult vkEnumerateInstanceExtensionProperties(nil, addr(extensionCount), addr(extensions[0]))
|
|
29
|
|
30 for extension in extensions:
|
|
31 result.add(join(extension.extensionName).strip(chars={char(0)}))
|
|
32
|
|
33
|
|
34 proc getDeviceExtensions*(device: VkPhysicalDevice): seq[string] =
|
|
35 var extensionCount: uint32
|
|
36 checkVkResult vkEnumerateDeviceExtensionProperties(device, nil, addr(extensionCount), nil)
|
|
37 var extensions = newSeq[VkExtensionProperties](extensionCount)
|
|
38 checkVkResult vkEnumerateDeviceExtensionProperties(device, nil, addr(extensionCount), addr(extensions[0]))
|
|
39
|
|
40 for extension in extensions:
|
|
41 result.add(join(extension.extensionName).strip(chars={char(0)}))
|
|
42
|
|
43
|
|
44 proc getValidationLayers*(): seq[string] =
|
|
45 var n_layers: uint32
|
|
46 checkVkResult vkEnumerateInstanceLayerProperties(addr(n_layers), nil)
|
|
47 var layers = newSeq[VkLayerProperties](n_layers)
|
|
48 checkVkResult vkEnumerateInstanceLayerProperties(addr(n_layers), addr(layers[0]))
|
|
49
|
|
50 for layer in layers:
|
|
51 result.add(join(layer.layerName).strip(chars={char(0)}))
|
|
52
|
|
53
|
|
54 proc getVulkanPhysicalDevices*(instance: VkInstance): seq[VkPhysicalDevice] =
|
|
55 var n_devices: uint32
|
|
56 checkVkResult vkEnumeratePhysicalDevices(instance, addr(n_devices), nil)
|
|
57 result = newSeq[VkPhysicalDevice](n_devices)
|
|
58 checkVkResult vkEnumeratePhysicalDevices(instance, addr(n_devices), addr(result[0]))
|
|
59
|
|
60
|
|
61 proc getQueueFamilies*(device: VkPhysicalDevice): seq[VkQueueFamilyProperties] =
|
|
62 var n_queuefamilies: uint32
|
|
63 vkGetPhysicalDeviceQueueFamilyProperties(device, addr(n_queuefamilies), nil)
|
|
64 result = newSeq[VkQueueFamilyProperties](n_queuefamilies)
|
|
65 vkGetPhysicalDeviceQueueFamilyProperties(device, addr(n_queuefamilies), addr(result[0]))
|
|
66
|
|
67
|
|
68 proc getDeviceSurfaceFormats*(device: VkPhysicalDevice, surface: VkSurfaceKHR): seq[VkSurfaceFormatKHR] =
|
|
69 var n_formats: uint32
|
|
70 checkVkResult vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, addr(n_formats), nil);
|
|
71 result = newSeq[VkSurfaceFormatKHR](n_formats)
|
|
72 checkVkResult vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, addr(n_formats), addr(result[0]))
|
|
73
|
|
74
|
|
75 proc getDeviceSurfacePresentModes*(device: VkPhysicalDevice, surface: VkSurfaceKHR): seq[VkPresentModeKHR] =
|
|
76 var n_modes: uint32
|
|
77 checkVkResult vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, addr(n_modes), nil);
|
|
78 result = newSeq[VkPresentModeKHR](n_modes)
|
|
79 checkVkResult vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, addr(n_modes), addr(result[0]))
|
|
80
|
|
81
|
|
82 proc getSwapChainImages*(device: VkDevice, swapChain: VkSwapchainKHR): seq[VkImage] =
|
|
83 var n_images: uint32
|
|
84 checkVkResult vkGetSwapchainImagesKHR(device, swapChain, addr(n_images), nil);
|
|
85 result = newSeq[VkImage](n_images)
|
|
86 checkVkResult vkGetSwapchainImagesKHR(device, swapChain, addr(n_images), addr(result[0]));
|
|
87
|
|
88
|
|
89 proc getPresentMode*(modes: seq[VkPresentModeKHR]): VkPresentModeKHR =
|
|
90 let preferredModes = [
|
|
91 VK_PRESENT_MODE_MAILBOX_KHR,
|
|
92 VK_PRESENT_MODE_FIFO_RELAXED_KHR,
|
|
93 VK_PRESENT_MODE_FIFO_KHR,
|
|
94 VK_PRESENT_MODE_IMMEDIATE_KHR,
|
|
95 ]
|
|
96 for preferredMode in preferredModes:
|
|
97 for mode in modes:
|
|
98 if preferredMode == mode:
|
|
99 return mode
|
|
100 # should never be reached, but seems to be garuanteed by vulkan specs to always be available
|
|
101 return VK_PRESENT_MODE_FIFO_KHR
|
|
102
|
|
103
|
|
104 proc createVulkanInstance*(vulkanVersion: uint32): VkInstance =
|
|
105 var requiredExtensions = [
|
|
106 "VK_EXT_acquire_xlib_display".cstring,
|
|
107 "VK_EXT_direct_mode_display".cstring,
|
|
108 "VK_KHR_display".cstring,
|
|
109 "VK_KHR_surface".cstring,
|
|
110 "VK_KHR_xlib_surface".cstring,
|
|
111 ]
|
|
112 let availableExtensions = getInstanceExtensions()
|
|
113 for extension in requiredExtensions:
|
|
114 assert $extension in availableExtensions
|
|
115
|
|
116 let desiredLayers = ["VK_LAYER_KHRONOS_validation".cstring, "VK_LAYER_MESA_overlay".cstring]
|
|
117 let availableLayers = getValidationLayers()
|
|
118 var usableLayers = newSeq[cstring]()
|
|
119
|
|
120 when ENABLEVULKANVALIDATIONLAYERS:
|
|
121 for layer in desiredLayers:
|
|
122 if $layer in availableLayers:
|
|
123 usableLayers.add(layer)
|
|
124
|
|
125 echo "Using validation layers: ", usableLayers
|
|
126 echo "Using extensions: ", requiredExtensions
|
|
127
|
|
128 var appinfo = VkApplicationInfo(
|
|
129 sType: VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
|
130 pApplicationName: "Hello Triangle",
|
|
131 pEngineName: "Custom engine",
|
|
132 apiVersion: vulkanVersion,
|
|
133 )
|
|
134 var createinfo = VkInstanceCreateInfo(
|
|
135 sType: VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
|
136 pApplicationInfo: addr(appinfo),
|
|
137 enabledLayerCount: usableLayers.len.uint32,
|
|
138 ppEnabledLayerNames: cast[ptr UncheckedArray[cstring]](addr(usableLayers[0])),
|
|
139 enabledExtensionCount: requiredExtensions.len.uint32,
|
|
140 ppEnabledExtensionNames: cast[ptr UncheckedArray[cstring]](addr(requiredExtensions))
|
|
141 )
|
|
142 checkVkResult vkCreateInstance(addr(createinfo), nil, addr(result))
|
|
143
|
|
144 loadVK_KHR_surface()
|
|
145 loadVK_KHR_xlib_surface()
|
|
146 loadVK_KHR_swapchain()
|
|
147
|
|
148
|
|
149 proc getVulcanDevice*(
|
|
150 physicalDevice: var VkPhysicalDevice,
|
|
151 features: var VkPhysicalDeviceFeatures,
|
|
152 selectedQueueFamily: uint32,
|
|
153 ): (VkDevice, VkQueue) =
|
|
154 # setup queue and device
|
|
155 var priority = 1.0'f32
|
|
156 var queueCreateInfo = VkDeviceQueueCreateInfo(
|
|
157 sType: VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
|
158 queueFamilyIndex: uint32(selectedQueueFamily),
|
|
159 queueCount: 1,
|
|
160 pQueuePriorities: addr(priority),
|
|
161 )
|
|
162
|
|
163 var requiredExtensions = ["VK_KHR_swapchain".cstring]
|
|
164 var deviceCreateInfo = VkDeviceCreateInfo(
|
|
165 sType: VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
|
166 pQueueCreateInfos: addr(queueCreateInfo),
|
|
167 queueCreateInfoCount: 1,
|
|
168 pEnabledFeatures: addr(features),
|
|
169 enabledExtensionCount: requiredExtensions.len.uint32,
|
|
170 ppEnabledExtensionNames: cast[ptr UncheckedArray[cstring]](addr(requiredExtensions))
|
|
171 )
|
|
172 checkVkResult vkCreateDevice(physicalDevice, addr(deviceCreateInfo), nil, addr(result[0]))
|
|
173 vkGetDeviceQueue(result[0], selectedQueueFamily, 0'u32, addr(result[1]));
|
1
|
174
|
|
175 proc createShaderStage*(device: VkDevice, stage: VkShaderStageFlagBits, shader: string): VkPipelineShaderStageCreateInfo =
|
|
176 const VK_GLSL_MAP = {
|
|
177 VK_SHADER_STAGE_VERTEX_BIT: GLSLANG_STAGE_VERTEX,
|
|
178 VK_SHADER_STAGE_FRAGMENT_BIT: GLSLANG_STAGE_FRAGMENT,
|
|
179 }.toTable()
|
|
180 var code = compileGLSLToSPIRV(VK_GLSL_MAP[stage], shader, "<memory-shader>")
|
|
181 var createInfo = VkShaderModuleCreateInfo(
|
|
182 sType: VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
|
183 codeSize: code.len.uint,
|
|
184 pCode: addr(code[0]),
|
|
185 )
|
|
186 var shaderModule: VkShaderModule
|
|
187 checkVkResult vkCreateShaderModule(device, addr(createInfo), nil, addr(shaderModule))
|
|
188
|
|
189 var vertShaderStageInfo = VkPipelineShaderStageCreateInfo(
|
|
190 sType: VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
191 stage: stage,
|
|
192 module: shaderModule,
|
|
193 pName: "main", # entry point for shader
|
|
194 )
|