comparison src/engine.nim @ 4:af9183acb173

did: refactor, add resizing, proper cleanup
author Sam <sam@basx.dev>
date Tue, 20 Dec 2022 00:28:05 +0700
parents 213fdf8d31dd
children 4ed9cb098315
comparison
equal deleted inserted replaced
3:5d54ef652619 4:af9183acb173
1 import std/typetraits
1 import std/strformat 2 import std/strformat
2 import std/enumerate 3 import std/enumerate
3 import std/logging 4 import std/logging
4 5
5 6
44 x11/x 45 x11/x
45 46
46 const VULKAN_VERSION = VK_MAKE_API_VERSION(0'u32, 1'u32, 2'u32, 0'u32) 47 const VULKAN_VERSION = VK_MAKE_API_VERSION(0'u32, 1'u32, 2'u32, 0'u32)
47 48
48 type 49 type
49 GraphicsPipeline = object 50 Device = object
51 physicalDevice: PhysicalDevice
52 graphicsQueueFamily: uint32
53 presentationQueueFamily: uint32
54 device: VkDevice
55 graphicsQueue: VkQueue
56 presentationQueue: VkQueue
57 Swapchain = object
58 swapchain: VkSwapchainKHR
59 images: seq[VkImage]
60 imageviews: seq[VkImageView]
61 RenderPipeline = object
50 shaderStages*: seq[VkPipelineShaderStageCreateInfo] 62 shaderStages*: seq[VkPipelineShaderStageCreateInfo]
51 layout*: VkPipelineLayout 63 layout*: VkPipelineLayout
52 renderPass*: VkRenderPass
53 pipeline*: VkPipeline 64 pipeline*: VkPipeline
65 viewport*: VkViewport
66 scissor*: VkRect2D
54 QueueFamily = object 67 QueueFamily = object
55 properties*: VkQueueFamilyProperties 68 properties*: VkQueueFamilyProperties
56 hasSurfaceSupport*: bool 69 hasSurfaceSupport*: bool
57 PhysicalDevice = object 70 PhysicalDevice = object
58 device*: VkPhysicalDevice 71 device*: VkPhysicalDevice
65 presentModes: seq[VkPresentModeKHR] 78 presentModes: seq[VkPresentModeKHR]
66 Vulkan* = object 79 Vulkan* = object
67 debugMessenger: VkDebugUtilsMessengerEXT 80 debugMessenger: VkDebugUtilsMessengerEXT
68 instance*: VkInstance 81 instance*: VkInstance
69 deviceList*: seq[PhysicalDevice] 82 deviceList*: seq[PhysicalDevice]
70 activePhysicalDevice*: PhysicalDevice 83 device*: Device
71 graphicsQueueFamily*: uint32
72 graphicsQueue*: VkQueue
73 presentationQueueFamily*: uint32
74 presentationQueue*: VkQueue
75 device*: VkDevice
76 surface*: VkSurfaceKHR 84 surface*: VkSurfaceKHR
77 selectedSurfaceFormat: VkSurfaceFormatKHR 85 surfaceFormat: VkSurfaceFormatKHR
78 selectedPresentationMode: VkPresentModeKHR
79 frameDimension: VkExtent2D 86 frameDimension: VkExtent2D
80 swapChain: VkSwapchainKHR 87 swapchain: Swapchain
81 swapImages: seq[VkImage] 88 framebuffers: seq[VkFramebuffer]
82 swapFramebuffers: seq[VkFramebuffer] 89 renderPass*: VkRenderPass
83 swapImageViews: seq[VkImageView] 90 pipeline*: RenderPipeline
84 pipeline*: GraphicsPipeline
85 commandPool*: VkCommandPool 91 commandPool*: VkCommandPool
86 commandBuffers*: array[MAX_FRAMES_IN_FLIGHT, VkCommandBuffer] 92 commandBuffers*: array[MAX_FRAMES_IN_FLIGHT, VkCommandBuffer]
87 viewport*: VkViewport
88 scissor*: VkRect2D
89 imageAvailableSemaphores*: array[MAX_FRAMES_IN_FLIGHT, VkSemaphore] 93 imageAvailableSemaphores*: array[MAX_FRAMES_IN_FLIGHT, VkSemaphore]
90 renderFinishedSemaphores*: array[MAX_FRAMES_IN_FLIGHT, VkSemaphore] 94 renderFinishedSemaphores*: array[MAX_FRAMES_IN_FLIGHT, VkSemaphore]
91 inFlightFences*: array[MAX_FRAMES_IN_FLIGHT, VkFence] 95 inFlightFences*: array[MAX_FRAMES_IN_FLIGHT, VkFence]
92 Engine* = object 96 Window* = object
93 display*: PDisplay 97 display*: PDisplay
94 window*: x.Window 98 window*: x.Window
99 Engine* = object
95 vulkan*: Vulkan 100 vulkan*: Vulkan
101 window: Window
96 102
97 103
98 proc getAllPhysicalDevices(instance: VkInstance, surface: VkSurfaceKHR): seq[PhysicalDevice] = 104 proc getAllPhysicalDevices(instance: VkInstance, surface: VkSurfaceKHR): seq[PhysicalDevice] =
99 for vulkanPhysicalDevice in getVulkanPhysicalDevices(instance): 105 for vulkanPhysicalDevice in getVulkanPhysicalDevices(instance):
100 var device = PhysicalDevice(device: vulkanPhysicalDevice, extensions: getDeviceExtensions(vulkanPhysicalDevice)) 106 var device = PhysicalDevice(device: vulkanPhysicalDevice, extensions: getDeviceExtensions(vulkanPhysicalDevice))
129 135
130 for (device, graphicsQueueFamily, presentationQueueFamily) in result: 136 for (device, graphicsQueueFamily, presentationQueueFamily) in result:
131 debug(&"Viable device: {cleanString(device.properties.deviceName)} (graphics queue family {graphicsQueueFamily}, presentation queue family {presentationQueueFamily})") 137 debug(&"Viable device: {cleanString(device.properties.deviceName)} (graphics queue family {graphicsQueueFamily}, presentation queue family {presentationQueueFamily})")
132 138
133 139
134 proc getFrameDimension(display: PDisplay, window: Window, capabilities: VkSurfaceCapabilitiesKHR): VkExtent2D = 140 proc getFrameDimension(window: Window, capabilities: VkSurfaceCapabilitiesKHR): VkExtent2D =
135 if capabilities.currentExtent.width != high(uint32): 141 if capabilities.currentExtent.width != high(uint32):
136 return capabilities.currentExtent 142 return capabilities.currentExtent
137 else: 143 else:
138 let (width, height) = xlibFramebufferSize(display, window) 144 let (width, height) = window.display.xlibFramebufferSize(window.window)
139 return VkExtent2D( 145 return VkExtent2D(
140 width: min(max(uint32(width), capabilities.minImageExtent.width), capabilities.maxImageExtent.width), 146 width: min(max(uint32(width), capabilities.minImageExtent.width), capabilities.maxImageExtent.width),
141 height: min(max(uint32(height), capabilities.minImageExtent.height), capabilities.maxImageExtent.height), 147 height: min(max(uint32(height), capabilities.minImageExtent.height), capabilities.maxImageExtent.height),
142 ) 148 )
143 149
144 proc createVulkanSurface(instance: VkInstance, display: PDisplay, window: Window): VkSurfaceKHR = 150 proc setupDebugLog(instance: VkInstance): VkDebugUtilsMessengerEXT =
151 var createInfo = VkDebugUtilsMessengerCreateInfoEXT(
152 sType: VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
153 messageSeverity: VkDebugUtilsMessageSeverityFlagsEXT(
154 ord(VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) or
155 ord(VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) or
156 ord(VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
157 ),
158 messageType: VkDebugUtilsMessageTypeFlagsEXT(
159 ord(VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) or
160 ord(VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) or
161 ord(VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT)
162 ),
163 pfnUserCallback: debugCallback,
164 pUserData: nil,
165 )
166 checkVkResult instance.vkCreateDebugUtilsMessengerEXT(addr(createInfo), nil, addr(result))
167
168 proc createVulkanSurface(instance: VkInstance, window: Window): VkSurfaceKHR =
145 var surfaceCreateInfo = VkXlibSurfaceCreateInfoKHR( 169 var surfaceCreateInfo = VkXlibSurfaceCreateInfoKHR(
146 sType: VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, 170 sType: VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
147 dpy: display, 171 dpy: window.display,
148 window: window, 172 window: window.window,
149 ) 173 )
150 checkVkResult vkCreateXlibSurfaceKHR(instance, addr(surfaceCreateInfo), nil, addr(result)) 174 checkVkResult vkCreateXlibSurfaceKHR(instance, addr(surfaceCreateInfo), nil, addr(result))
151 175
152 proc setupVulkanDeviceAndQueues(instance: VkInstance, surface: VkSurfaceKHR): (PhysicalDevice, uint32, uint32, VkDevice, VkQueue, VkQueue) = 176 proc setupVulkanDeviceAndQueues(instance: VkInstance, surface: VkSurfaceKHR): Device =
153 let usableDevices = instance.getAllPhysicalDevices(surface).filterForDevice() 177 let usableDevices = instance.getAllPhysicalDevices(surface).filterForDevice()
154 if len(usableDevices) == 0: 178 if len(usableDevices) == 0:
155 raise newException(Exception, "No suitable graphics device found") 179 raise newException(Exception, "No suitable graphics device found")
156 result[0] = usableDevices[0][0] 180 result.physicalDevice = usableDevices[0][0]
157 result[1] = usableDevices[0][1] 181 result.graphicsQueueFamily = usableDevices[0][1]
158 result[2] = usableDevices[0][2] 182 result.presentationQueueFamily = usableDevices[0][2]
159 183
160 debug(&"Chose device {cleanString(result[0].properties.deviceName)}") 184 debug(&"Chose device {cleanString(result.physicalDevice.properties.deviceName)}")
161 185
162 (result[3], result[4], result[5]) = getVulcanDevice( 186 (result.device, result.graphicsQueue, result.presentationQueue) = getVulcanDevice(
163 result[0].device, 187 result.physicalDevice.device,
164 result[0].features, 188 result.physicalDevice.features,
165 result[1], 189 result.graphicsQueueFamily,
166 result[2], 190 result.presentationQueueFamily,
167 ) 191 )
168 192
169 proc igniteEngine*(): Engine = 193 proc setupSwapChain(device: VkDevice, physicalDevice: PhysicalDevice, surface: VkSurfaceKHR, dimension: VkExtent2D, surfaceFormat: VkSurfaceFormatKHR): Swapchain =
170 194 var selectedPresentationMode = getPresentMode(physicalDevice.presentModes)
171 # init X11 window
172 (result.display, result.window) = xlibInit()
173
174 # create vulkan instance
175 vkLoad1_0()
176 vkLoad1_1()
177 vkLoad1_2()
178 result.vulkan.instance = createVulkanInstance(VULKAN_VERSION)
179 when ENABLEVULKANVALIDATIONLAYERS:
180 var createInfo = VkDebugUtilsMessengerCreateInfoEXT(
181 sType: VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
182 messageSeverity: VkDebugUtilsMessageSeverityFlagsEXT(
183 ord(VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) or
184 ord(VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) or
185 ord(VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
186 ),
187 messageType: VkDebugUtilsMessageTypeFlagsEXT(
188 ord(VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) or
189 ord(VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) or
190 ord(VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT)
191 ),
192 pfnUserCallback: debugCallback,
193 pUserData: nil,
194 )
195 checkVkResult vkCreateDebugUtilsMessengerEXT(result.vulkan.instance, addr(createInfo), nil, addr(result.vulkan.debugMessenger))
196
197 result.vulkan.surface = result.vulkan.instance.createVulkanSurface(result.display, result.window)
198
199 (
200 result.vulkan.activePhysicalDevice,
201 result.vulkan.graphicsQueueFamily,
202 result.vulkan.presentationQueueFamily,
203 result.vulkan.device,
204 result.vulkan.graphicsQueue,
205 result.vulkan.presentationQueue
206 ) = result.vulkan.instance.setupVulkanDeviceAndQueues(result.vulkan.surface)
207
208 # determine surface format for swapchain
209 let usableSurfaceFormats = filterForSurfaceFormat(result.vulkan.activePhysicalDevice.surfaceFormats)
210 if len(usableSurfaceFormats) == 0:
211 raise newException(Exception, "No suitable surface formats found")
212 result.vulkan.selectedSurfaceFormat = usableSurfaceFormats[0]
213 result.vulkan.selectedPresentationMode = getPresentMode(result.vulkan.activePhysicalDevice.presentModes)
214 result.vulkan.frameDimension = result.display.getFrameDimension(result.window, result.vulkan.activePhysicalDevice.surfaceCapabilities)
215
216 # setup swapchain 195 # setup swapchain
217 var swapchainCreateInfo = VkSwapchainCreateInfoKHR( 196 var swapchainCreateInfo = VkSwapchainCreateInfoKHR(
218 sType: VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, 197 sType: VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
219 surface: result.vulkan.surface, 198 surface: surface,
220 minImageCount: max(result.vulkan.activePhysicalDevice.surfaceCapabilities.minImageCount + 1, result.vulkan.activePhysicalDevice.surfaceCapabilities.maxImageCount), 199 minImageCount: max(physicalDevice.surfaceCapabilities.minImageCount + 1, physicalDevice.surfaceCapabilities.maxImageCount),
221 imageFormat: result.vulkan.selectedSurfaceFormat.format, 200 imageFormat: surfaceFormat.format,
222 imageColorSpace: result.vulkan.selectedSurfaceFormat.colorSpace, 201 imageColorSpace: surfaceFormat.colorSpace,
223 imageExtent: result.vulkan.frameDimension, 202 imageExtent: dimension,
224 imageArrayLayers: 1, 203 imageArrayLayers: 1,
225 imageUsage: VkImageUsageFlags(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT), 204 imageUsage: VkImageUsageFlags(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT),
226 # VK_SHARING_MODE_CONCURRENT no supported (i.e cannot use different queue families for drawing to swap surface?) 205 # VK_SHARING_MODE_CONCURRENT no supported (i.e cannot use different queue families for drawing to swap surface?)
227 imageSharingMode: VK_SHARING_MODE_EXCLUSIVE, 206 imageSharingMode: VK_SHARING_MODE_EXCLUSIVE,
228 preTransform: result.vulkan.activePhysicalDevice.surfaceCapabilities.currentTransform, 207 preTransform: physicalDevice.surfaceCapabilities.currentTransform,
229 compositeAlpha: VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, 208 compositeAlpha: VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
230 presentMode: result.vulkan.selectedPresentationMode, 209 presentMode: selectedPresentationMode,
231 clipped: VK_TRUE, 210 clipped: VK_TRUE,
232 oldSwapchain: VkSwapchainKHR(0), 211 oldSwapchain: VkSwapchainKHR(0),
233 ) 212 )
234 checkVkResult result.vulkan.device.vkCreateSwapchainKHR(addr(swapchainCreateInfo), nil, addr(result.vulkan.swapChain)) 213 checkVkResult device.vkCreateSwapchainKHR(addr(swapchainCreateInfo), nil, addr(result.swapchain))
235 result.vulkan.swapImages = result.vulkan.device.getSwapChainImages(result.vulkan.swapChain) 214 result.images = device.getSwapChainImages(result.swapchain)
236 215
237 # setup swapchian image views 216 # setup swapchian image views
238 result.vulkan.swapImageViews = newSeq[VkImageView](result.vulkan.swapImages.len) 217
239 for i, image in enumerate(result.vulkan.swapImages): 218 result.imageviews = newSeq[VkImageView](result.images.len)
219 for i, image in enumerate(result.images):
240 var imageViewCreateInfo = VkImageViewCreateInfo( 220 var imageViewCreateInfo = VkImageViewCreateInfo(
241 sType: VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 221 sType: VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
242 image: image, 222 image: image,
243 viewType: VK_IMAGE_VIEW_TYPE_2D, 223 viewType: VK_IMAGE_VIEW_TYPE_2D,
244 format: result.vulkan.selectedSurfaceFormat.format, 224 format: surfaceFormat.format,
245 components: VkComponentMapping( 225 components: VkComponentMapping(
246 r: VK_COMPONENT_SWIZZLE_IDENTITY, 226 r: VK_COMPONENT_SWIZZLE_IDENTITY,
247 g: VK_COMPONENT_SWIZZLE_IDENTITY, 227 g: VK_COMPONENT_SWIZZLE_IDENTITY,
248 b: VK_COMPONENT_SWIZZLE_IDENTITY, 228 b: VK_COMPONENT_SWIZZLE_IDENTITY,
249 a: VK_COMPONENT_SWIZZLE_IDENTITY, 229 a: VK_COMPONENT_SWIZZLE_IDENTITY,
254 levelCount: 1, 234 levelCount: 1,
255 baseArrayLayer: 0, 235 baseArrayLayer: 0,
256 layerCount: 1, 236 layerCount: 1,
257 ), 237 ),
258 ) 238 )
259 checkVkResult result.vulkan.device.vkCreateImageView(addr(imageViewCreateInfo), nil, addr(result.vulkan.swapImageViews[i])) 239 checkVkResult device.vkCreateImageView(addr(imageViewCreateInfo), nil, addr(result.imageviews[i]))
260 240
261 # init shader system 241 proc setupRenderPass(device: VkDevice, format: VkFormat): VkRenderPass =
262 checkGlslangResult glslang_initialize_process()
263
264 # load shaders
265 result.vulkan.pipeline.shaderStages.add(result.vulkan.device.createShaderStage(VK_SHADER_STAGE_VERTEX_BIT, vertexShaderCode))
266 result.vulkan.pipeline.shaderStages.add(result.vulkan.device.createShaderStage(VK_SHADER_STAGE_FRAGMENT_BIT, fragmentShaderCode))
267
268 # setup render passes
269 var 242 var
270 colorAttachment = VkAttachmentDescription( 243 colorAttachment = VkAttachmentDescription(
271 format: result.vulkan.selectedSurfaceFormat.format, 244 format: format,
272 samples: VK_SAMPLE_COUNT_1_BIT, 245 samples: VK_SAMPLE_COUNT_1_BIT,
273 loadOp: VK_ATTACHMENT_LOAD_OP_CLEAR, 246 loadOp: VK_ATTACHMENT_LOAD_OP_CLEAR,
274 storeOp: VK_ATTACHMENT_STORE_OP_STORE, 247 storeOp: VK_ATTACHMENT_STORE_OP_STORE,
275 stencilLoadOp: VK_ATTACHMENT_LOAD_OP_DONT_CARE, 248 stencilLoadOp: VK_ATTACHMENT_LOAD_OP_DONT_CARE,
276 stencilStoreOp: VK_ATTACHMENT_STORE_OP_DONT_CARE, 249 stencilStoreOp: VK_ATTACHMENT_STORE_OP_DONT_CARE,
301 subpassCount: 1, 274 subpassCount: 1,
302 pSubpasses: addr(subpass), 275 pSubpasses: addr(subpass),
303 dependencyCount: 1, 276 dependencyCount: 1,
304 pDependencies: addr(dependency), 277 pDependencies: addr(dependency),
305 ) 278 )
306 checkVkResult result.vulkan.device.vkCreateRenderPass(addr(renderPassCreateInfo), nil, addr(result.vulkan.pipeline.renderPass)) 279 checkVkResult device.vkCreateRenderPass(addr(renderPassCreateInfo), nil, addr(result))
307 280
308 # create graphis pipeline 281 proc setupRenderPipeline(device: VkDevice, frameDimension: VkExtent2D, renderPass: VkRenderPass): RenderPipeline =
309 282 # (seq[VkPipelineShaderStageCreateInfo], VkViewport, VkRect2D, VkPipelineLayout, VkPipeline) =
283
284 # load shaders
285 result.shaderStages.add(device.createShaderStage(VK_SHADER_STAGE_VERTEX_BIT, vertexShaderCode))
286 result.shaderStages.add(device.createShaderStage(VK_SHADER_STAGE_FRAGMENT_BIT, fragmentShaderCode))
287
310 var 288 var
311 # define which parts can be dynamic (pipeline is fixed after setup) 289 # define which parts can be dynamic (pipeline is fixed after setup)
312 dynamicStates = [VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR] 290 dynamicStates = [VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR]
313 dynamicState = VkPipelineDynamicStateCreateInfo( 291 dynamicState = VkPipelineDynamicStateCreateInfo(
314 sType: VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, 292 sType: VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
315 dynamicStateCount: uint32(dynamicStates.len), 293 dynamicStateCount: uint32(dynamicStates.len),
316 pDynamicStates: addr(dynamicStates[0]), 294 pDynamicStates: addr(dynamicStates[0]),
317 ) 295 )
318
319 # define input data format 296 # define input data format
320 vertexInputInfo = VkPipelineVertexInputStateCreateInfo( 297 vertexInputInfo = VkPipelineVertexInputStateCreateInfo(
321 sType: VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, 298 sType: VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
322 vertexBindingDescriptionCount: 0, 299 vertexBindingDescriptionCount: 0,
323 pVertexBindingDescriptions: nil, 300 pVertexBindingDescriptions: nil,
329 topology: VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 306 topology: VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
330 primitiveRestartEnable: VK_FALSE, 307 primitiveRestartEnable: VK_FALSE,
331 ) 308 )
332 309
333 # setup viewport 310 # setup viewport
334 result.vulkan.viewport = VkViewport( 311 result.viewport = VkViewport(
335 x: 0.0, 312 x: 0.0,
336 y: 0.0, 313 y: 0.0,
337 width: (float) result.vulkan.frameDimension.width, 314 width: (float) frameDimension.width,
338 height: (float) result.vulkan.frameDimension.height, 315 height: (float) frameDimension.height,
339 minDepth: 0.0, 316 minDepth: 0.0,
340 maxDepth: 1.0, 317 maxDepth: 1.0,
341 ) 318 )
342 result.vulkan.scissor = VkRect2D( 319 result.scissor = VkRect2D(
343 offset: VkOffset2D(x: 0, y: 0), 320 offset: VkOffset2D(x: 0, y: 0),
344 extent: result.vulkan.frameDimension 321 extent: frameDimension
345 ) 322 )
346 var viewportState = VkPipelineViewportStateCreateInfo( 323 var viewportState = VkPipelineViewportStateCreateInfo(
347 sType: VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, 324 sType: VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
348 viewportCount: 1, 325 viewportCount: 1,
349 pViewports: addr(result.vulkan.viewport), 326 pViewports: addr(result.viewport),
350 scissorCount: 1, 327 scissorCount: 1,
351 pScissors: addr(result.vulkan.scissor), 328 pScissors: addr(result.scissor),
352 ) 329 )
353 330
354 # rasterizerization config 331 # rasterizerization config
355 var 332 var
356 rasterizer = VkPipelineRasterizationStateCreateInfo( 333 rasterizer = VkPipelineRasterizationStateCreateInfo(
405 setLayoutCount: 0, 382 setLayoutCount: 0,
406 pSetLayouts: nil, 383 pSetLayouts: nil,
407 pushConstantRangeCount: 0, 384 pushConstantRangeCount: 0,
408 pPushConstantRanges: nil, 385 pPushConstantRanges: nil,
409 ) 386 )
410 checkVkResult result.vulkan.device.vkCreatePipelineLayout(addr(pipelineLayoutInfo), nil, addr(result.vulkan.pipeline.layout)) 387 checkVkResult device.vkCreatePipelineLayout(addr(pipelineLayoutInfo), nil, addr(result.layout))
411 388
412 var pipelineInfo = VkGraphicsPipelineCreateInfo( 389 var pipelineInfo = VkGraphicsPipelineCreateInfo(
413 sType: VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, 390 sType: VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
414 stageCount: 2, 391 stageCount: 2,
415 pStages: addr(result.vulkan.pipeline.shaderStages[0]), 392 pStages: addr(result.shaderStages[0]),
416 pVertexInputState: addr(vertexInputInfo), 393 pVertexInputState: addr(vertexInputInfo),
417 pInputAssemblyState: addr(inputAssembly), 394 pInputAssemblyState: addr(inputAssembly),
418 pViewportState: addr(viewportState), 395 pViewportState: addr(viewportState),
419 pRasterizationState: addr(rasterizer), 396 pRasterizationState: addr(rasterizer),
420 pMultisampleState: addr(multisampling), 397 pMultisampleState: addr(multisampling),
421 pDepthStencilState: nil, 398 pDepthStencilState: nil,
422 pColorBlendState: addr(colorBlending), 399 pColorBlendState: addr(colorBlending),
423 pDynamicState: addr(dynamicState), 400 pDynamicState: addr(dynamicState),
424 layout: result.vulkan.pipeline.layout, 401 layout: result.layout,
425 renderPass: result.vulkan.pipeline.renderPass, 402 renderPass: renderPass,
426 subpass: 0, 403 subpass: 0,
427 basePipelineHandle: VkPipeline(0), 404 basePipelineHandle: VkPipeline(0),
428 basePipelineIndex: -1, 405 basePipelineIndex: -1,
429 ) 406 )
430 checkVkResult result.vulkan.device.vkCreateGraphicsPipelines( 407 checkVkResult device.vkCreateGraphicsPipelines(
431 VkPipelineCache(0), 408 VkPipelineCache(0),
432 1, 409 1,
433 addr(pipelineInfo), 410 addr(pipelineInfo),
434 nil, 411 nil,
435 addr(result.vulkan.pipeline.pipeline) 412 addr(result.pipeline)
436 ) 413 )
437 414
438 # set up framebuffers 415 proc setupFramebuffers(device: VkDevice, swapchain: var Swapchain, renderPass: VkRenderPass, dimension: VkExtent2D): seq[VkFramebuffer] =
439 result.vulkan.swapFramebuffers = newSeq[VkFramebuffer](result.vulkan.swapImages.len) 416 result = newSeq[VkFramebuffer](swapchain.images.len)
440 417 for i, imageview in enumerate(swapchain.imageviews):
441 for i, imageview in enumerate(result.vulkan.swapImageViews):
442 var framebufferInfo = VkFramebufferCreateInfo( 418 var framebufferInfo = VkFramebufferCreateInfo(
443 sType: VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, 419 sType: VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
444 renderPass: result.vulkan.pipeline.renderPass, 420 renderPass: renderPass,
445 attachmentCount: 1, 421 attachmentCount: 1,
446 pAttachments: addr(result.vulkan.swapImageViews[i]), 422 pAttachments: addr(swapchain.imageviews[i]),
447 width: result.vulkan.frameDimension.width, 423 width: dimension.width,
448 height: result.vulkan.frameDimension.height, 424 height: dimension.height,
449 layers: 1, 425 layers: 1,
450 ) 426 )
451 checkVkResult result.vulkan.device.vkCreateFramebuffer(addr(framebufferInfo), nil, addr(result.vulkan.swapFramebuffers[i])) 427 checkVkResult device.vkCreateFramebuffer(addr(framebufferInfo), nil, addr(result[i]))
452 428
429 proc recreateSwapchain(vulkan: Vulkan): (Swapchain, seq[VkFramebuffer]) =
430 checkVkResult vulkan.device.device.vkDeviceWaitIdle()
431 for framebuffer in vulkan.framebuffers:
432 vulkan.device.device.vkDestroyFramebuffer(framebuffer, nil)
433 for imageview in vulkan.swapchain.imageviews:
434 vulkan.device.device.vkDestroyImageView(imageview, nil)
435 vulkan.device.device.vkDestroySwapchainKHR(vulkan.swapchain.swapchain, nil)
436
437 result[0] = vulkan.device.device.setupSwapChain(
438 vulkan.device.physicalDevice,
439 vulkan.surface,
440 vulkan.frameDimension,
441 vulkan.surfaceFormat
442 )
443 result[1] = vulkan.device.device.setupFramebuffers(
444 result[0],
445 vulkan.renderPass,
446 vulkan.frameDimension
447 )
448
449 # createFramebuffers();
450
451
452 proc setupCommandBuffers(device: VkDevice, graphicsQueueFamily: uint32): (VkCommandPool, array[MAX_FRAMES_IN_FLIGHT, VkCommandBuffer]) =
453 # set up command buffer 453 # set up command buffer
454 var poolInfo = VkCommandPoolCreateInfo( 454 var poolInfo = VkCommandPoolCreateInfo(
455 sType: VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, 455 sType: VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
456 flags: VkCommandPoolCreateFlags(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT), 456 flags: VkCommandPoolCreateFlags(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT),
457 queueFamilyIndex: result.vulkan.graphicsQueueFamily, 457 queueFamilyIndex: graphicsQueueFamily,
458 ) 458 )
459 checkVkResult result.vulkan.device.vkCreateCommandPool(addr(poolInfo), nil, addr(result.vulkan.commandPool)) 459 checkVkResult device.vkCreateCommandPool(addr(poolInfo), nil, addr(result[0]))
460 460
461 var allocInfo = VkCommandBufferAllocateInfo( 461 var allocInfo = VkCommandBufferAllocateInfo(
462 sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 462 sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
463 commandPool: result.vulkan.commandPool, 463 commandPool: result[0],
464 level: VK_COMMAND_BUFFER_LEVEL_PRIMARY, 464 level: VK_COMMAND_BUFFER_LEVEL_PRIMARY,
465 commandBufferCount: result.vulkan.commandBuffers.len.uint32, 465 commandBufferCount: result[1].len.uint32,
466 ) 466 )
467 checkVkResult result.vulkan.device.vkAllocateCommandBuffers(addr(allocInfo), addr(result.vulkan.commandBuffers[0])) 467 checkVkResult device.vkAllocateCommandBuffers(addr(allocInfo), addr(result[1][0]))
468 468
469 # create semaphores for syncing rendering 469 proc setupSyncPrimitives(device: VkDevice): (
470 array[MAX_FRAMES_IN_FLIGHT, VkSemaphore],
471 array[MAX_FRAMES_IN_FLIGHT, VkSemaphore],
472 array[MAX_FRAMES_IN_FLIGHT, VkFence],
473 ) =
470 var semaphoreInfo = VkSemaphoreCreateInfo(sType: VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO) 474 var semaphoreInfo = VkSemaphoreCreateInfo(sType: VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO)
471 var fenceInfo = VkFenceCreateInfo( 475 var fenceInfo = VkFenceCreateInfo(
472 sType: VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, 476 sType: VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
473 flags: VkFenceCreateFlags(VK_FENCE_CREATE_SIGNALED_BIT) 477 flags: VkFenceCreateFlags(VK_FENCE_CREATE_SIGNALED_BIT)
474 ) 478 )
475 for i in 0 ..< MAX_FRAMES_IN_FLIGHT: 479 for i in 0 ..< MAX_FRAMES_IN_FLIGHT:
476 checkVkResult result.vulkan.device.vkCreateSemaphore(addr(semaphoreInfo), nil, addr(result.vulkan.imageAvailableSemaphores[i])) 480 checkVkResult device.vkCreateSemaphore(addr(semaphoreInfo), nil, addr(result[0][i]))
477 checkVkResult result.vulkan.device.vkCreateSemaphore(addr(semaphoreInfo), nil, addr(result.vulkan.renderFinishedSemaphores[i])) 481 checkVkResult device.vkCreateSemaphore(addr(semaphoreInfo), nil, addr(result[1][i]))
478 checkVkResult result.vulkan.device.vkCreateFence(addr(fenceInfo), nil, addr(result.vulkan.inFlightFences[i])) 482 checkVkResult device.vkCreateFence(addr(fenceInfo), nil, addr(result[2][i]))
479 483
480 484 proc igniteEngine*(): Engine =
481 proc recordCommandBuffer(vulkan: var Vulkan, commandBuffer: VkCommandBuffer, imageIndex: uint32) = 485
486 # init X11 window
487 (result.window.display, result.window.window) = xlibInit()
488
489 # setup vulkan functions
490 vkLoad1_0()
491 vkLoad1_1()
492 vkLoad1_2()
493 checkGlslangResult glslang_initialize_process()
494
495 # create vulkan instance
496 result.vulkan.instance = createVulkanInstance(VULKAN_VERSION)
497 when ENABLEVULKANVALIDATIONLAYERS:
498 result.vulkan.debugMessenger = result.vulkan.instance.setupDebugLog()
499 result.vulkan.surface = result.vulkan.instance.createVulkanSurface(result.window)
500 result.vulkan.device = result.vulkan.instance.setupVulkanDeviceAndQueues(result.vulkan.surface)
501
502 # get basic frame information
503 result.vulkan.surfaceFormat = result.vulkan.device.physicalDevice.surfaceFormats.getSuitableSurfaceFormat()
504 result.vulkan.frameDimension = result.window.getFrameDimension(result.vulkan.device.physicalDevice.surfaceCapabilities)
505
506 # setup swapchain and render pipeline
507 result.vulkan.swapchain = result.vulkan.device.device.setupSwapChain(
508 result.vulkan.device.physicalDevice,
509 result.vulkan.surface,
510 result.vulkan.frameDimension,
511 result.vulkan.surfaceFormat
512 )
513 result.vulkan.renderPass = result.vulkan.device.device.setupRenderPass(result.vulkan.surfaceFormat.format)
514 result.vulkan.pipeline = result.vulkan.device.device.setupRenderPipeline(result.vulkan.frameDimension, result.vulkan.renderPass)
515 result.vulkan.framebuffers = result.vulkan.device.device.setupFramebuffers(
516 result.vulkan.swapchain,
517 result.vulkan.renderPass,
518 result.vulkan.frameDimension
519 )
520
521 (
522 result.vulkan.commandPool,
523 result.vulkan.commandBuffers,
524 ) = result.vulkan.device.device.setupCommandBuffers(result.vulkan.device.graphicsQueueFamily)
525
526 (
527 result.vulkan.imageAvailableSemaphores,
528 result.vulkan.renderFinishedSemaphores,
529 result.vulkan.inFlightFences,
530 ) = result.vulkan.device.device.setupSyncPrimitives()
531
532
533 proc recordCommandBuffer(renderPass: VkRenderPass, pipeline: var RenderPipeline, commandBuffer: VkCommandBuffer, framebuffer: VkFramebuffer) =
482 var beginInfo = VkCommandBufferBeginInfo( 534 var beginInfo = VkCommandBufferBeginInfo(
483 sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 535 sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
484 pInheritanceInfo: nil, 536 pInheritanceInfo: nil,
485 ) 537 )
486 checkVkResult commandBuffer.vkBeginCommandBuffer(addr(beginInfo)) 538 checkVkResult commandBuffer.vkBeginCommandBuffer(addr(beginInfo))
487 539
488 var 540 var
489 clearColor = VkClearValue(color: VkClearColorValue(float32: [0.2'f, 0.2'f, 0.2'f, 1.0'f])) 541 clearColor = VkClearValue(color: VkClearColorValue(float32: [0.2'f, 0.2'f, 0.2'f, 1.0'f]))
490 renderPassInfo = VkRenderPassBeginInfo( 542 renderPassInfo = VkRenderPassBeginInfo(
491 sType: VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, 543 sType: VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
492 renderPass: vulkan.pipeline.renderPass, 544 renderPass: renderPass,
493 framebuffer: vulkan.swapFramebuffers[imageIndex], 545 framebuffer: framebuffer,
494 renderArea: VkRect2D( 546 renderArea: VkRect2D(
495 offset: VkOffset2D(x: 0, y: 0), 547 offset: VkOffset2D(x: 0, y: 0),
496 extent: vulkan.frameDimension, 548 extent: VkExtent2D(
549 width: uint32(pipeline.viewport.width),
550 height: uint32(pipeline.viewport.height)
551 ),
497 ), 552 ),
498 clearValueCount: 1, 553 clearValueCount: 1,
499 pClearValues: addr(clearColor), 554 pClearValues: addr(clearColor),
500 ) 555 )
501 commandBuffer.vkCmdBeginRenderPass(addr(renderPassInfo), VK_SUBPASS_CONTENTS_INLINE) 556 commandBuffer.vkCmdBeginRenderPass(addr(renderPassInfo), VK_SUBPASS_CONTENTS_INLINE)
502 commandBuffer.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, vulkan.pipeline.pipeline) 557 commandBuffer.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipeline)
503 558
504 commandBuffer.vkCmdSetViewport(firstViewport=0, viewportCount=1, addr(vulkan.viewport)) 559 commandBuffer.vkCmdSetViewport(firstViewport=0, viewportCount=1, addr(pipeline.viewport))
505 commandBuffer.vkCmdSetScissor(firstScissor=0, scissorCount=1, addr(vulkan.scissor)) 560 commandBuffer.vkCmdSetScissor(firstScissor=0, scissorCount=1, addr(pipeline.scissor))
506 commandBuffer.vkCmdDraw(vertexCount=3, instanceCount=1, firstVertex=0, firstInstance=0) 561 commandBuffer.vkCmdDraw(vertexCount=3, instanceCount=1, firstVertex=0, firstInstance=0)
507 commandBuffer.vkCmdEndRenderPass() 562 commandBuffer.vkCmdEndRenderPass()
508 checkVkResult commandBuffer.vkEndCommandBuffer() 563 checkVkResult commandBuffer.vkEndCommandBuffer()
509 564
510 proc drawFrame(vulkan: var Vulkan, currentFrame: int) = 565 proc drawFrame(window: Window, vulkan: var Vulkan, currentFrame: int) =
511 checkVkResult vulkan.device.vkWaitForFences(1, addr(vulkan.inFlightFences[currentFrame]), VK_TRUE, high(uint64)) 566 checkVkResult vulkan.device.device.vkWaitForFences(1, addr(vulkan.inFlightFences[currentFrame]), VK_TRUE, high(uint64))
512 checkVkResult vulkan.device.vkResetFences(1, addr(vulkan.inFlightFences[currentFrame])) 567 checkVkResult vulkan.device.device.vkResetFences(1, addr(vulkan.inFlightFences[currentFrame]))
513 var bufferImageIndex: uint32 568 var bufferImageIndex: uint32
514 checkVkResult vulkan.device.vkAcquireNextImageKHR( 569 let nextImageResult = vulkan.device.device.vkAcquireNextImageKHR(
515 vulkan.swapChain, 570 vulkan.swapchain.swapchain,
516 high(uint64), 571 high(uint64),
517 vulkan.imageAvailableSemaphores[currentFrame], 572 vulkan.imageAvailableSemaphores[currentFrame],
518 VkFence(0), 573 VkFence(0),
519 addr(bufferImageIndex) 574 addr(bufferImageIndex)
520 ) 575 )
521 576 if nextImageResult == VK_ERROR_OUT_OF_DATE_KHR:
522 checkVkResult vkResetCommandBuffer(vulkan.commandBuffers[currentFrame], VkCommandBufferResetFlags(0)) 577 vulkan.frameDimension = window.getFrameDimension(vulkan.device.physicalDevice.surfaceCapabilities)
523 recordCommandBuffer(vulkan, vulkan.commandBuffers[currentFrame], bufferImageIndex) 578 (vulkan.swapchain, vulkan.framebuffers) = vulkan.recreateSwapchain()
579 return
580
581 checkVkResult vulkan.commandBuffers[currentFrame].vkResetCommandBuffer(VkCommandBufferResetFlags(0))
582 vulkan.renderPass.recordCommandBuffer(vulkan.pipeline, vulkan.commandBuffers[currentFrame], vulkan.framebuffers[bufferImageIndex])
524 var 583 var
525 waitSemaphores = [vulkan.imageAvailableSemaphores[currentFrame]] 584 waitSemaphores = [vulkan.imageAvailableSemaphores[currentFrame]]
526 waitStages = [VkPipelineStageFlags(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)] 585 waitStages = [VkPipelineStageFlags(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)]
527 signalSemaphores = [vulkan.renderFinishedSemaphores[currentFrame]] 586 signalSemaphores = [vulkan.renderFinishedSemaphores[currentFrame]]
528 submitInfo = VkSubmitInfo( 587 submitInfo = VkSubmitInfo(
533 commandBufferCount: 1, 592 commandBufferCount: 1,
534 pCommandBuffers: addr(vulkan.commandBuffers[currentFrame]), 593 pCommandBuffers: addr(vulkan.commandBuffers[currentFrame]),
535 signalSemaphoreCount: 1, 594 signalSemaphoreCount: 1,
536 pSignalSemaphores: addr(signalSemaphores[0]), 595 pSignalSemaphores: addr(signalSemaphores[0]),
537 ) 596 )
538 checkVkResult vkQueueSubmit(vulkan.graphicsQueue, 1, addr(submitInfo), vulkan.inFlightFences[currentFrame]) 597 checkVkResult vkQueueSubmit(vulkan.device.graphicsQueue, 1, addr(submitInfo), vulkan.inFlightFences[currentFrame])
539 598
540 var presentInfo = VkPresentInfoKHR( 599 var presentInfo = VkPresentInfoKHR(
541 sType: VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, 600 sType: VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
542 waitSemaphoreCount: 1, 601 waitSemaphoreCount: 1,
543 pWaitSemaphores: addr(signalSemaphores[0]), 602 pWaitSemaphores: addr(signalSemaphores[0]),
544 swapchainCount: 1, 603 swapchainCount: 1,
545 pSwapchains: addr(vulkan.swapChain), 604 pSwapchains: addr(vulkan.swapchain.swapchain),
546 pImageIndices: addr(bufferImageIndex), 605 pImageIndices: addr(bufferImageIndex),
547 pResults: nil, 606 pResults: nil,
548 ) 607 )
549 checkVkResult vkQueuePresentKHR(vulkan.presentationQueue, addr(presentInfo)) 608 let presentResult = vkQueuePresentKHR(vulkan.device.presentationQueue, addr(presentInfo))
609
610 if presentResult == VK_ERROR_OUT_OF_DATE_KHR or presentResult == VK_SUBOPTIMAL_KHR:
611 vulkan.frameDimension = window.getFrameDimension(vulkan.device.physicalDevice.surfaceCapabilities)
612 (vulkan.swapchain, vulkan.framebuffers) = vulkan.recreateSwapchain()
613 return
550 614
551 615
552 proc fullThrottle*(engine: var Engine) = 616 proc fullThrottle*(engine: var Engine) =
553 var 617 var
554 event: XEvent 618 event: XEvent
555 killed = false 619 killed = false
556 currentFrame = 0 620 currentFrame = 0
557 621
558 while not killed: 622 while not killed:
559 while engine.display.XPending() > 0 and not killed: 623 while engine.window.display.XPending() > 0 and not killed:
560 discard engine.display.XNextEvent(addr(event)) 624 discard engine.window.display.XNextEvent(addr(event))
561 case event.theType 625 case event.theType
562 of ClientMessage: 626 of ClientMessage:
563 if cast[Atom](event.xclient.data.l[0]) == deleteMessage: 627 if cast[Atom](event.xclient.data.l[0]) == deleteMessage:
564 killed = true 628 killed = true
565 of KeyPress: 629 of KeyPress:
566 let key = XLookupKeysym(cast[PXKeyEvent](addr(event)), 0) 630 let key = XLookupKeysym(cast[PXKeyEvent](addr(event)), 0)
567 if key == XK_Escape: 631 if key == XK_Escape:
568 killed = true 632 killed = true
633 of ConfigureNotify:
634 engine.vulkan.frameDimension = engine.window.getFrameDimension(engine.vulkan.device.physicalDevice.surfaceCapabilities)
635 (engine.vulkan.swapchain, engine.vulkan.framebuffers) = engine.vulkan.recreateSwapchain()
569 else: 636 else:
570 discard 637 discard
571 drawFrame(engine.vulkan, currentFrame) 638 engine.window.drawFrame(engine.vulkan, currentFrame)
572 currentFrame = (currentFrame + 1) mod MAX_FRAMES_IN_FLIGHT; 639 currentFrame = (currentFrame + 1) mod MAX_FRAMES_IN_FLIGHT;
573 checkVkResult engine.vulkan.device.vkDeviceWaitIdle() 640 checkVkResult engine.vulkan.device.device.vkDeviceWaitIdle()
574 641
575 642
576 proc trash*(engine: Engine) = 643 proc trash*(engine: Engine) =
644 checkVkResult engine.vulkan.device.device.vkDeviceWaitIdle()
577 for i in 0 ..< MAX_FRAMES_IN_FLIGHT: 645 for i in 0 ..< MAX_FRAMES_IN_FLIGHT:
578 engine.vulkan.device.vkDestroySemaphore(engine.vulkan.imageAvailableSemaphores[i], nil) 646 engine.vulkan.device.device.vkDestroySemaphore(engine.vulkan.imageAvailableSemaphores[i], nil)
579 engine.vulkan.device.vkDestroySemaphore(engine.vulkan.renderFinishedSemaphores[i], nil) 647 engine.vulkan.device.device.vkDestroySemaphore(engine.vulkan.renderFinishedSemaphores[i], nil)
580 engine.vulkan.device.vkDestroyFence(engine.vulkan.inFlightFences[i], nil) 648 engine.vulkan.device.device.vkDestroyFence(engine.vulkan.inFlightFences[i], nil)
581 649
582 engine.vulkan.device.vkDestroyCommandPool(engine.vulkan.commandPool, nil) 650 engine.vulkan.device.device.vkDestroyCommandPool(engine.vulkan.commandPool, nil)
583 for framebuffer in engine.vulkan.swapFramebuffers: 651 for framebuffer in engine.vulkan.framebuffers:
584 engine.vulkan.device.vkDestroyFramebuffer(framebuffer, nil) 652 engine.vulkan.device.device.vkDestroyFramebuffer(framebuffer, nil)
585 653
586 engine.vulkan.device.vkDestroyPipeline(engine.vulkan.pipeline.pipeline, nil) 654 engine.vulkan.device.device.vkDestroyPipeline(engine.vulkan.pipeline.pipeline, nil)
587 engine.vulkan.device.vkDestroyPipelineLayout(engine.vulkan.pipeline.layout, nil) 655 engine.vulkan.device.device.vkDestroyPipelineLayout(engine.vulkan.pipeline.layout, nil)
588 engine.vulkan.device.vkDestroyRenderPass(engine.vulkan.pipeline.renderPass, nil) 656 engine.vulkan.device.device.vkDestroyRenderPass(engine.vulkan.renderPass, nil)
589 657
590 for shaderStage in engine.vulkan.pipeline.shaderStages: 658 for shaderStage in engine.vulkan.pipeline.shaderStages:
591 engine.vulkan.device.vkDestroyShaderModule(shaderStage.module, nil) 659 engine.vulkan.device.device.vkDestroyShaderModule(shaderStage.module, nil)
592 660
661 for imageview in engine.vulkan.swapchain.imageviews:
662 engine.vulkan.device.device.vkDestroyImageView(imageview, nil)
663 engine.vulkan.device.device.vkDestroySwapchainKHR(engine.vulkan.swapchain.swapchain, nil)
664 engine.vulkan.instance.vkDestroySurfaceKHR(engine.vulkan.surface, nil)
665 engine.vulkan.device.device.vkDestroyDevice(nil)
666 when ENABLEVULKANVALIDATIONLAYERS:
667 engine.vulkan.instance.vkDestroyDebugUtilsMessengerEXT(engine.vulkan.debugMessenger, nil)
593 glslang_finalize_process() 668 glslang_finalize_process()
594 engine.vulkan.device.vkDestroySwapchainKHR(engine.vulkan.swapChain, nil)
595 engine.vulkan.instance.vkDestroySurfaceKHR(engine.vulkan.surface, nil)
596 engine.vulkan.device.vkDestroyDevice(nil)
597 engine.vulkan.instance.vkDestroyInstance(nil) 669 engine.vulkan.instance.vkDestroyInstance(nil)
598 checkXlibResult engine.display.XDestroyWindow(engine.window) 670 checkXlibResult engine.window.display.XDestroyWindow(engine.window.window)
599 discard engine.display.XCloseDisplay() # always returns 0 671 discard engine.window.display.XCloseDisplay() # always returns 0