comparison src/engine.nim @ 5:4ed9cb098315

add: structure code for crossplatform, add some input handling + bugfixes
author Sam <sam@basx.dev>
date Thu, 22 Dec 2022 00:06:40 +0700
parents af9183acb173
children 1134f41a49e9
comparison
equal deleted inserted replaced
4:af9183acb173 5:4ed9cb098315
4 import std/logging 4 import std/logging
5 5
6 6
7 import ./vulkan 7 import ./vulkan
8 import ./vulkan_helpers 8 import ./vulkan_helpers
9 import ./xlib_helpers 9 import ./window
10 import ./events
10 11
11 import ./glslang/glslang 12 import ./glslang/glslang
12 13
13 const MAX_FRAMES_IN_FLIGHT = 2 14 const MAX_FRAMES_IN_FLIGHT = 2
14 15
38 layout(location = 0) in vec3 fragColor; 39 layout(location = 0) in vec3 fragColor;
39 void main() { 40 void main() {
40 outColor = vec4(fragColor, 1.0); 41 outColor = vec4(fragColor, 1.0);
41 }""" 42 }"""
42 43
43 import
44 x11/xlib,
45 x11/x
46
47 const VULKAN_VERSION = VK_MAKE_API_VERSION(0'u32, 1'u32, 2'u32, 0'u32) 44 const VULKAN_VERSION = VK_MAKE_API_VERSION(0'u32, 1'u32, 2'u32, 0'u32)
48 45
49 type 46 type
50 Device = object 47 Device = object
51 physicalDevice: PhysicalDevice 48 physicalDevice: PhysicalDevice
60 imageviews: seq[VkImageView] 57 imageviews: seq[VkImageView]
61 RenderPipeline = object 58 RenderPipeline = object
62 shaderStages*: seq[VkPipelineShaderStageCreateInfo] 59 shaderStages*: seq[VkPipelineShaderStageCreateInfo]
63 layout*: VkPipelineLayout 60 layout*: VkPipelineLayout
64 pipeline*: VkPipeline 61 pipeline*: VkPipeline
65 viewport*: VkViewport
66 scissor*: VkRect2D
67 QueueFamily = object 62 QueueFamily = object
68 properties*: VkQueueFamilyProperties 63 properties*: VkQueueFamilyProperties
69 hasSurfaceSupport*: bool 64 hasSurfaceSupport*: bool
70 PhysicalDevice = object 65 PhysicalDevice = object
71 device*: VkPhysicalDevice 66 device*: VkPhysicalDevice
72 extensions*: seq[string] 67 extensions*: seq[string]
73 properties*: VkPhysicalDeviceProperties 68 properties*: VkPhysicalDeviceProperties
74 features*: VkPhysicalDeviceFeatures 69 features*: VkPhysicalDeviceFeatures
75 queueFamilies*: seq[QueueFamily] 70 queueFamilies*: seq[QueueFamily]
76 surfaceCapabilities*: VkSurfaceCapabilitiesKHR 71 formats: seq[VkSurfaceFormatKHR]
77 surfaceFormats: seq[VkSurfaceFormatKHR]
78 presentModes: seq[VkPresentModeKHR] 72 presentModes: seq[VkPresentModeKHR]
79 Vulkan* = object 73 Vulkan* = object
80 debugMessenger: VkDebugUtilsMessengerEXT 74 debugMessenger: VkDebugUtilsMessengerEXT
81 instance*: VkInstance 75 instance*: VkInstance
82 deviceList*: seq[PhysicalDevice] 76 deviceList*: seq[PhysicalDevice]
91 commandPool*: VkCommandPool 85 commandPool*: VkCommandPool
92 commandBuffers*: array[MAX_FRAMES_IN_FLIGHT, VkCommandBuffer] 86 commandBuffers*: array[MAX_FRAMES_IN_FLIGHT, VkCommandBuffer]
93 imageAvailableSemaphores*: array[MAX_FRAMES_IN_FLIGHT, VkSemaphore] 87 imageAvailableSemaphores*: array[MAX_FRAMES_IN_FLIGHT, VkSemaphore]
94 renderFinishedSemaphores*: array[MAX_FRAMES_IN_FLIGHT, VkSemaphore] 88 renderFinishedSemaphores*: array[MAX_FRAMES_IN_FLIGHT, VkSemaphore]
95 inFlightFences*: array[MAX_FRAMES_IN_FLIGHT, VkFence] 89 inFlightFences*: array[MAX_FRAMES_IN_FLIGHT, VkFence]
96 Window* = object
97 display*: PDisplay
98 window*: x.Window
99 Engine* = object 90 Engine* = object
100 vulkan*: Vulkan 91 vulkan*: Vulkan
101 window: Window 92 window: NativeWindow
102
103 93
104 proc getAllPhysicalDevices(instance: VkInstance, surface: VkSurfaceKHR): seq[PhysicalDevice] = 94 proc getAllPhysicalDevices(instance: VkInstance, surface: VkSurfaceKHR): seq[PhysicalDevice] =
105 for vulkanPhysicalDevice in getVulkanPhysicalDevices(instance): 95 for vulkanPhysicalDevice in getVulkanPhysicalDevices(instance):
106 var device = PhysicalDevice(device: vulkanPhysicalDevice, extensions: getDeviceExtensions(vulkanPhysicalDevice)) 96 var device = PhysicalDevice(device: vulkanPhysicalDevice, extensions: getDeviceExtensions(vulkanPhysicalDevice))
107 vkGetPhysicalDeviceProperties(vulkanPhysicalDevice, addr(device.properties)) 97 vkGetPhysicalDeviceProperties(vulkanPhysicalDevice, addr(device.properties))
108 vkGetPhysicalDeviceFeatures(vulkanPhysicalDevice, addr(device.features)) 98 vkGetPhysicalDeviceFeatures(vulkanPhysicalDevice, addr(device.features))
109 checkVkResult vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vulkanPhysicalDevice, surface, addr(device.surfaceCapabilities)) 99 device.formats = vulkanPhysicalDevice.getDeviceSurfaceFormats(surface)
110 device.surfaceFormats = getDeviceSurfaceFormats(vulkanPhysicalDevice, surface) 100 device.presentModes = vulkanPhysicalDevice.getDeviceSurfacePresentModes(surface)
111 device.presentModes = getDeviceSurfacePresentModes(vulkanPhysicalDevice, surface)
112 101
113 debug(&"Physical device nr {int(vulkanPhysicalDevice)} {cleanString(device.properties.deviceName)}") 102 debug(&"Physical device nr {int(vulkanPhysicalDevice)} {cleanString(device.properties.deviceName)}")
114 for i, queueFamilyProperty in enumerate(getQueueFamilies(vulkanPhysicalDevice)): 103 for i, queueFamilyProperty in enumerate(getQueueFamilies(vulkanPhysicalDevice)):
115 var hasSurfaceSupport: VkBool32 = VK_FALSE 104 var hasSurfaceSupport: VkBool32 = VK_FALSE
116 checkVkResult vkGetPhysicalDeviceSurfaceSupportKHR(vulkanPhysicalDevice, uint32(i), surface, addr(hasSurfaceSupport)) 105 checkVkResult vkGetPhysicalDeviceSurfaceSupportKHR(vulkanPhysicalDevice, uint32(i), surface, addr(hasSurfaceSupport))
119 108
120 result.add(device) 109 result.add(device)
121 110
122 proc filterForDevice(devices: seq[PhysicalDevice]): seq[(PhysicalDevice, uint32, uint32)] = 111 proc filterForDevice(devices: seq[PhysicalDevice]): seq[(PhysicalDevice, uint32, uint32)] =
123 for device in devices: 112 for device in devices:
124 if not (device.surfaceFormats.len > 0 and device.presentModes.len > 0 and "VK_KHR_swapchain" in device.extensions): 113 if not (device.formats.len > 0 and device.presentModes.len > 0 and "VK_KHR_swapchain" in device.extensions):
125 continue 114 continue
126 var graphicsQueueFamily = high(uint32) 115 var graphicsQueueFamily = high(uint32)
127 var presentationQueueFamily = high(uint32) 116 var presentationQueueFamily = high(uint32)
128 for i, queueFamily in enumerate(device.queueFamilies): 117 for i, queueFamily in enumerate(device.queueFamilies):
129 if queueFamily.hasSurfaceSupport: 118 if queueFamily.hasSurfaceSupport:
135 124
136 for (device, graphicsQueueFamily, presentationQueueFamily) in result: 125 for (device, graphicsQueueFamily, presentationQueueFamily) in result:
137 debug(&"Viable device: {cleanString(device.properties.deviceName)} (graphics queue family {graphicsQueueFamily}, presentation queue family {presentationQueueFamily})") 126 debug(&"Viable device: {cleanString(device.properties.deviceName)} (graphics queue family {graphicsQueueFamily}, presentation queue family {presentationQueueFamily})")
138 127
139 128
140 proc getFrameDimension(window: Window, capabilities: VkSurfaceCapabilitiesKHR): VkExtent2D = 129 proc getFrameDimension(window: NativeWindow, device: VkPhysicalDevice, surface: VkSurfaceKHR): VkExtent2D =
130 let capabilities = device.getSurfaceCapabilities(surface)
141 if capabilities.currentExtent.width != high(uint32): 131 if capabilities.currentExtent.width != high(uint32):
142 return capabilities.currentExtent 132 return capabilities.currentExtent
143 else: 133 else:
144 let (width, height) = window.display.xlibFramebufferSize(window.window) 134 let (width, height) = window.size()
145 return VkExtent2D( 135 return VkExtent2D(
146 width: min(max(uint32(width), capabilities.minImageExtent.width), capabilities.maxImageExtent.width), 136 width: min(max(uint32(width), capabilities.minImageExtent.width), capabilities.maxImageExtent.width),
147 height: min(max(uint32(height), capabilities.minImageExtent.height), capabilities.maxImageExtent.height), 137 height: min(max(uint32(height), capabilities.minImageExtent.height), capabilities.maxImageExtent.height),
148 ) 138 )
149 139
163 pfnUserCallback: debugCallback, 153 pfnUserCallback: debugCallback,
164 pUserData: nil, 154 pUserData: nil,
165 ) 155 )
166 checkVkResult instance.vkCreateDebugUtilsMessengerEXT(addr(createInfo), nil, addr(result)) 156 checkVkResult instance.vkCreateDebugUtilsMessengerEXT(addr(createInfo), nil, addr(result))
167 157
168 proc createVulkanSurface(instance: VkInstance, window: Window): VkSurfaceKHR =
169 var surfaceCreateInfo = VkXlibSurfaceCreateInfoKHR(
170 sType: VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
171 dpy: window.display,
172 window: window.window,
173 )
174 checkVkResult vkCreateXlibSurfaceKHR(instance, addr(surfaceCreateInfo), nil, addr(result))
175
176 proc setupVulkanDeviceAndQueues(instance: VkInstance, surface: VkSurfaceKHR): Device = 158 proc setupVulkanDeviceAndQueues(instance: VkInstance, surface: VkSurfaceKHR): Device =
177 let usableDevices = instance.getAllPhysicalDevices(surface).filterForDevice() 159 let usableDevices = instance.getAllPhysicalDevices(surface).filterForDevice()
178 if len(usableDevices) == 0: 160 if len(usableDevices) == 0:
179 raise newException(Exception, "No suitable graphics device found") 161 raise newException(Exception, "No suitable graphics device found")
180 result.physicalDevice = usableDevices[0][0] 162 result.physicalDevice = usableDevices[0][0]
189 result.graphicsQueueFamily, 171 result.graphicsQueueFamily,
190 result.presentationQueueFamily, 172 result.presentationQueueFamily,
191 ) 173 )
192 174
193 proc setupSwapChain(device: VkDevice, physicalDevice: PhysicalDevice, surface: VkSurfaceKHR, dimension: VkExtent2D, surfaceFormat: VkSurfaceFormatKHR): Swapchain = 175 proc setupSwapChain(device: VkDevice, physicalDevice: PhysicalDevice, surface: VkSurfaceKHR, dimension: VkExtent2D, surfaceFormat: VkSurfaceFormatKHR): Swapchain =
176
177 let capabilities = physicalDevice.device.getSurfaceCapabilities(surface)
194 var selectedPresentationMode = getPresentMode(physicalDevice.presentModes) 178 var selectedPresentationMode = getPresentMode(physicalDevice.presentModes)
195 # setup swapchain 179 # setup swapchain
196 var swapchainCreateInfo = VkSwapchainCreateInfoKHR( 180 var swapchainCreateInfo = VkSwapchainCreateInfoKHR(
197 sType: VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, 181 sType: VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
198 surface: surface, 182 surface: surface,
199 minImageCount: max(physicalDevice.surfaceCapabilities.minImageCount + 1, physicalDevice.surfaceCapabilities.maxImageCount), 183 minImageCount: max(capabilities.minImageCount + 1, capabilities.maxImageCount),
200 imageFormat: surfaceFormat.format, 184 imageFormat: surfaceFormat.format,
201 imageColorSpace: surfaceFormat.colorSpace, 185 imageColorSpace: surfaceFormat.colorSpace,
202 imageExtent: dimension, 186 imageExtent: dimension,
203 imageArrayLayers: 1, 187 imageArrayLayers: 1,
204 imageUsage: VkImageUsageFlags(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT), 188 imageUsage: VkImageUsageFlags(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT),
205 # VK_SHARING_MODE_CONCURRENT no supported (i.e cannot use different queue families for drawing to swap surface?) 189 # VK_SHARING_MODE_CONCURRENT no supported (i.e cannot use different queue families for drawing to swap surface?)
206 imageSharingMode: VK_SHARING_MODE_EXCLUSIVE, 190 imageSharingMode: VK_SHARING_MODE_EXCLUSIVE,
207 preTransform: physicalDevice.surfaceCapabilities.currentTransform, 191 preTransform: capabilities.currentTransform,
208 compositeAlpha: VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, 192 compositeAlpha: VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
209 presentMode: selectedPresentationMode, 193 presentMode: selectedPresentationMode,
210 clipped: VK_TRUE, 194 clipped: VK_TRUE,
211 oldSwapchain: VkSwapchainKHR(0), 195 oldSwapchain: VkSwapchainKHR(0),
212 ) 196 )
306 topology: VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 290 topology: VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
307 primitiveRestartEnable: VK_FALSE, 291 primitiveRestartEnable: VK_FALSE,
308 ) 292 )
309 293
310 # setup viewport 294 # setup viewport
311 result.viewport = VkViewport(
312 x: 0.0,
313 y: 0.0,
314 width: (float) frameDimension.width,
315 height: (float) frameDimension.height,
316 minDepth: 0.0,
317 maxDepth: 1.0,
318 )
319 result.scissor = VkRect2D(
320 offset: VkOffset2D(x: 0, y: 0),
321 extent: frameDimension
322 )
323 var viewportState = VkPipelineViewportStateCreateInfo( 295 var viewportState = VkPipelineViewportStateCreateInfo(
324 sType: VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, 296 sType: VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
325 viewportCount: 1, 297 viewportCount: 1,
326 pViewports: addr(result.viewport),
327 scissorCount: 1, 298 scissorCount: 1,
328 pScissors: addr(result.scissor),
329 ) 299 )
330 300
331 # rasterizerization config 301 # rasterizerization config
332 var 302 var
333 rasterizer = VkPipelineRasterizationStateCreateInfo( 303 rasterizer = VkPipelineRasterizationStateCreateInfo(
424 height: dimension.height, 394 height: dimension.height,
425 layers: 1, 395 layers: 1,
426 ) 396 )
427 checkVkResult device.vkCreateFramebuffer(addr(framebufferInfo), nil, addr(result[i])) 397 checkVkResult device.vkCreateFramebuffer(addr(framebufferInfo), nil, addr(result[i]))
428 398
399 proc trash(device: VkDevice, swapchain: Swapchain, framebuffers: seq[VkFramebuffer]) =
400 for framebuffer in framebuffers:
401 device.vkDestroyFramebuffer(framebuffer, nil)
402 for imageview in swapchain.imageviews:
403 device.vkDestroyImageView(imageview, nil)
404 device.vkDestroySwapchainKHR(swapchain.swapchain, nil)
405
429 proc recreateSwapchain(vulkan: Vulkan): (Swapchain, seq[VkFramebuffer]) = 406 proc recreateSwapchain(vulkan: Vulkan): (Swapchain, seq[VkFramebuffer]) =
407 debug(&"Recreate swapchain with dimension {vulkan.frameDimension}")
430 checkVkResult vulkan.device.device.vkDeviceWaitIdle() 408 checkVkResult vulkan.device.device.vkDeviceWaitIdle()
431 for framebuffer in vulkan.framebuffers: 409
432 vulkan.device.device.vkDestroyFramebuffer(framebuffer, nil) 410 vulkan.device.device.trash(vulkan.swapchain, vulkan.framebuffers)
433 for imageview in vulkan.swapchain.imageviews:
434 vulkan.device.device.vkDestroyImageView(imageview, nil)
435 vulkan.device.device.vkDestroySwapchainKHR(vulkan.swapchain.swapchain, nil)
436 411
437 result[0] = vulkan.device.device.setupSwapChain( 412 result[0] = vulkan.device.device.setupSwapChain(
438 vulkan.device.physicalDevice, 413 vulkan.device.physicalDevice,
439 vulkan.surface, 414 vulkan.surface,
440 vulkan.frameDimension, 415 vulkan.frameDimension,
481 checkVkResult device.vkCreateSemaphore(addr(semaphoreInfo), nil, addr(result[1][i])) 456 checkVkResult device.vkCreateSemaphore(addr(semaphoreInfo), nil, addr(result[1][i]))
482 checkVkResult device.vkCreateFence(addr(fenceInfo), nil, addr(result[2][i])) 457 checkVkResult device.vkCreateFence(addr(fenceInfo), nil, addr(result[2][i]))
483 458
484 proc igniteEngine*(): Engine = 459 proc igniteEngine*(): Engine =
485 460
486 # init X11 window 461 result.window = createWindow("Hello triangle")
487 (result.window.display, result.window.window) = xlibInit()
488 462
489 # setup vulkan functions 463 # setup vulkan functions
490 vkLoad1_0() 464 vkLoad1_0()
491 vkLoad1_1() 465 vkLoad1_1()
492 vkLoad1_2() 466 vkLoad1_2()
498 result.vulkan.debugMessenger = result.vulkan.instance.setupDebugLog() 472 result.vulkan.debugMessenger = result.vulkan.instance.setupDebugLog()
499 result.vulkan.surface = result.vulkan.instance.createVulkanSurface(result.window) 473 result.vulkan.surface = result.vulkan.instance.createVulkanSurface(result.window)
500 result.vulkan.device = result.vulkan.instance.setupVulkanDeviceAndQueues(result.vulkan.surface) 474 result.vulkan.device = result.vulkan.instance.setupVulkanDeviceAndQueues(result.vulkan.surface)
501 475
502 # get basic frame information 476 # get basic frame information
503 result.vulkan.surfaceFormat = result.vulkan.device.physicalDevice.surfaceFormats.getSuitableSurfaceFormat() 477 result.vulkan.surfaceFormat = result.vulkan.device.physicalDevice.formats.getSuitableSurfaceFormat()
504 result.vulkan.frameDimension = result.window.getFrameDimension(result.vulkan.device.physicalDevice.surfaceCapabilities) 478 result.vulkan.frameDimension = result.window.getFrameDimension(result.vulkan.device.physicalDevice.device, result.vulkan.surface)
505 479
506 # setup swapchain and render pipeline 480 # setup swapchain and render pipeline
507 result.vulkan.swapchain = result.vulkan.device.device.setupSwapChain( 481 result.vulkan.swapchain = result.vulkan.device.device.setupSwapChain(
508 result.vulkan.device.physicalDevice, 482 result.vulkan.device.physicalDevice,
509 result.vulkan.surface, 483 result.vulkan.surface,
528 result.vulkan.renderFinishedSemaphores, 502 result.vulkan.renderFinishedSemaphores,
529 result.vulkan.inFlightFences, 503 result.vulkan.inFlightFences,
530 ) = result.vulkan.device.device.setupSyncPrimitives() 504 ) = result.vulkan.device.device.setupSyncPrimitives()
531 505
532 506
533 proc recordCommandBuffer(renderPass: VkRenderPass, pipeline: var RenderPipeline, commandBuffer: VkCommandBuffer, framebuffer: VkFramebuffer) = 507 proc recordCommandBuffer(renderPass: VkRenderPass, pipeline: VkPipeline, commandBuffer: VkCommandBuffer, framebuffer: VkFramebuffer, frameDimension: VkExtent2D) =
534 var beginInfo = VkCommandBufferBeginInfo(
535 sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
536 pInheritanceInfo: nil,
537 )
538 checkVkResult commandBuffer.vkBeginCommandBuffer(addr(beginInfo))
539
540 var 508 var
509 beginInfo = VkCommandBufferBeginInfo(
510 sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
511 pInheritanceInfo: nil,
512 )
541 clearColor = VkClearValue(color: VkClearColorValue(float32: [0.2'f, 0.2'f, 0.2'f, 1.0'f])) 513 clearColor = VkClearValue(color: VkClearColorValue(float32: [0.2'f, 0.2'f, 0.2'f, 1.0'f]))
542 renderPassInfo = VkRenderPassBeginInfo( 514 renderPassInfo = VkRenderPassBeginInfo(
543 sType: VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, 515 sType: VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
544 renderPass: renderPass, 516 renderPass: renderPass,
545 framebuffer: framebuffer, 517 framebuffer: framebuffer,
546 renderArea: VkRect2D( 518 renderArea: VkRect2D(
547 offset: VkOffset2D(x: 0, y: 0), 519 offset: VkOffset2D(x: 0, y: 0),
548 extent: VkExtent2D( 520 extent: frameDimension,
549 width: uint32(pipeline.viewport.width),
550 height: uint32(pipeline.viewport.height)
551 ),
552 ), 521 ),
553 clearValueCount: 1, 522 clearValueCount: 1,
554 pClearValues: addr(clearColor), 523 pClearValues: addr(clearColor),
555 ) 524 )
525 viewport = VkViewport(
526 x: 0.0,
527 y: 0.0,
528 width: (float) frameDimension.width,
529 height: (float) frameDimension.height,
530 minDepth: 0.0,
531 maxDepth: 1.0,
532 )
533 scissor = VkRect2D(
534 offset: VkOffset2D(x: 0, y: 0),
535 extent: frameDimension
536 )
537 checkVkResult commandBuffer.vkBeginCommandBuffer(addr(beginInfo))
556 commandBuffer.vkCmdBeginRenderPass(addr(renderPassInfo), VK_SUBPASS_CONTENTS_INLINE) 538 commandBuffer.vkCmdBeginRenderPass(addr(renderPassInfo), VK_SUBPASS_CONTENTS_INLINE)
557 commandBuffer.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipeline) 539 commandBuffer.vkCmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline)
558 540 commandBuffer.vkCmdSetViewport(firstViewport=0, viewportCount=1, addr(viewport))
559 commandBuffer.vkCmdSetViewport(firstViewport=0, viewportCount=1, addr(pipeline.viewport)) 541 commandBuffer.vkCmdSetScissor(firstScissor=0, scissorCount=1, addr(scissor))
560 commandBuffer.vkCmdSetScissor(firstScissor=0, scissorCount=1, addr(pipeline.scissor))
561 commandBuffer.vkCmdDraw(vertexCount=3, instanceCount=1, firstVertex=0, firstInstance=0) 542 commandBuffer.vkCmdDraw(vertexCount=3, instanceCount=1, firstVertex=0, firstInstance=0)
562 commandBuffer.vkCmdEndRenderPass() 543 commandBuffer.vkCmdEndRenderPass()
563 checkVkResult commandBuffer.vkEndCommandBuffer() 544 checkVkResult commandBuffer.vkEndCommandBuffer()
564 545
565 proc drawFrame(window: Window, vulkan: var Vulkan, currentFrame: int) = 546 proc drawFrame(window: NativeWindow, vulkan: var Vulkan, currentFrame: int, resized: bool) =
566 checkVkResult vulkan.device.device.vkWaitForFences(1, addr(vulkan.inFlightFences[currentFrame]), VK_TRUE, high(uint64)) 547 checkVkResult vulkan.device.device.vkWaitForFences(1, addr(vulkan.inFlightFences[currentFrame]), VK_TRUE, high(uint64))
567 checkVkResult vulkan.device.device.vkResetFences(1, addr(vulkan.inFlightFences[currentFrame]))
568 var bufferImageIndex: uint32 548 var bufferImageIndex: uint32
569 let nextImageResult = vulkan.device.device.vkAcquireNextImageKHR( 549 let nextImageResult = vulkan.device.device.vkAcquireNextImageKHR(
570 vulkan.swapchain.swapchain, 550 vulkan.swapchain.swapchain,
571 high(uint64), 551 high(uint64),
572 vulkan.imageAvailableSemaphores[currentFrame], 552 vulkan.imageAvailableSemaphores[currentFrame],
573 VkFence(0), 553 VkFence(0),
574 addr(bufferImageIndex) 554 addr(bufferImageIndex)
575 ) 555 )
576 if nextImageResult == VK_ERROR_OUT_OF_DATE_KHR: 556 if nextImageResult == VK_ERROR_OUT_OF_DATE_KHR:
577 vulkan.frameDimension = window.getFrameDimension(vulkan.device.physicalDevice.surfaceCapabilities) 557 vulkan.frameDimension = window.getFrameDimension(vulkan.device.physicalDevice.device, vulkan.surface)
578 (vulkan.swapchain, vulkan.framebuffers) = vulkan.recreateSwapchain() 558 (vulkan.swapchain, vulkan.framebuffers) = vulkan.recreateSwapchain()
579 return 559 return
560 elif not (nextImageResult in [VK_SUCCESS, VK_SUBOPTIMAL_KHR]):
561 raise newException(Exception, "Vulkan error: vkAcquireNextImageKHR returned " & $nextImageResult)
562 checkVkResult vulkan.device.device.vkResetFences(1, addr(vulkan.inFlightFences[currentFrame]))
580 563
581 checkVkResult vulkan.commandBuffers[currentFrame].vkResetCommandBuffer(VkCommandBufferResetFlags(0)) 564 checkVkResult vulkan.commandBuffers[currentFrame].vkResetCommandBuffer(VkCommandBufferResetFlags(0))
582 vulkan.renderPass.recordCommandBuffer(vulkan.pipeline, vulkan.commandBuffers[currentFrame], vulkan.framebuffers[bufferImageIndex]) 565 vulkan.renderPass.recordCommandBuffer(vulkan.pipeline.pipeline, vulkan.commandBuffers[currentFrame], vulkan.framebuffers[bufferImageIndex], vulkan.frameDimension)
583 var 566 var
584 waitSemaphores = [vulkan.imageAvailableSemaphores[currentFrame]] 567 waitSemaphores = [vulkan.imageAvailableSemaphores[currentFrame]]
585 waitStages = [VkPipelineStageFlags(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)] 568 waitStages = [VkPipelineStageFlags(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)]
586 signalSemaphores = [vulkan.renderFinishedSemaphores[currentFrame]] 569 signalSemaphores = [vulkan.renderFinishedSemaphores[currentFrame]]
587 submitInfo = VkSubmitInfo( 570 submitInfo = VkSubmitInfo(
605 pImageIndices: addr(bufferImageIndex), 588 pImageIndices: addr(bufferImageIndex),
606 pResults: nil, 589 pResults: nil,
607 ) 590 )
608 let presentResult = vkQueuePresentKHR(vulkan.device.presentationQueue, addr(presentInfo)) 591 let presentResult = vkQueuePresentKHR(vulkan.device.presentationQueue, addr(presentInfo))
609 592
610 if presentResult == VK_ERROR_OUT_OF_DATE_KHR or presentResult == VK_SUBOPTIMAL_KHR: 593 if presentResult == VK_ERROR_OUT_OF_DATE_KHR or presentResult == VK_SUBOPTIMAL_KHR or resized:
611 vulkan.frameDimension = window.getFrameDimension(vulkan.device.physicalDevice.surfaceCapabilities) 594 vulkan.frameDimension = window.getFrameDimension(vulkan.device.physicalDevice.device, vulkan.surface)
612 (vulkan.swapchain, vulkan.framebuffers) = vulkan.recreateSwapchain() 595 (vulkan.swapchain, vulkan.framebuffers) = vulkan.recreateSwapchain()
613 return
614 596
615 597
616 proc fullThrottle*(engine: var Engine) = 598 proc fullThrottle*(engine: var Engine) =
617 var 599 var
618 event: XEvent
619 killed = false 600 killed = false
620 currentFrame = 0 601 currentFrame = 0
602 resized = false
621 603
622 while not killed: 604 while not killed:
623 while engine.window.display.XPending() > 0 and not killed: 605 for event in engine.window.pendingEvents():
624 discard engine.window.display.XNextEvent(addr(event)) 606 case event.eventType:
625 case event.theType 607 of Quit:
626 of ClientMessage:
627 if cast[Atom](event.xclient.data.l[0]) == deleteMessage:
628 killed = true 608 killed = true
629 of KeyPress: 609 of ResizedWindow:
630 let key = XLookupKeysym(cast[PXKeyEvent](addr(event)), 0) 610 resized = true
631 if key == XK_Escape: 611 of KeyDown:
632 killed = true 612 echo event
633 of ConfigureNotify: 613 if event.key == Escape:
634 engine.vulkan.frameDimension = engine.window.getFrameDimension(engine.vulkan.device.physicalDevice.surfaceCapabilities) 614 killed = true
635 (engine.vulkan.swapchain, engine.vulkan.framebuffers) = engine.vulkan.recreateSwapchain() 615 else:
636 else: 616 discard
637 discard 617 engine.window.drawFrame(engine.vulkan, currentFrame, resized)
638 engine.window.drawFrame(engine.vulkan, currentFrame) 618 resized = false
639 currentFrame = (currentFrame + 1) mod MAX_FRAMES_IN_FLIGHT; 619 currentFrame = (currentFrame + 1) mod MAX_FRAMES_IN_FLIGHT;
640 checkVkResult engine.vulkan.device.device.vkDeviceWaitIdle() 620 checkVkResult engine.vulkan.device.device.vkDeviceWaitIdle()
641 621
642
643 proc trash*(engine: Engine) = 622 proc trash*(engine: Engine) =
623 engine.vulkan.device.device.trash(engine.vulkan.swapchain, engine.vulkan.framebuffers)
644 checkVkResult engine.vulkan.device.device.vkDeviceWaitIdle() 624 checkVkResult engine.vulkan.device.device.vkDeviceWaitIdle()
625
645 for i in 0 ..< MAX_FRAMES_IN_FLIGHT: 626 for i in 0 ..< MAX_FRAMES_IN_FLIGHT:
646 engine.vulkan.device.device.vkDestroySemaphore(engine.vulkan.imageAvailableSemaphores[i], nil) 627 engine.vulkan.device.device.vkDestroySemaphore(engine.vulkan.imageAvailableSemaphores[i], nil)
647 engine.vulkan.device.device.vkDestroySemaphore(engine.vulkan.renderFinishedSemaphores[i], nil) 628 engine.vulkan.device.device.vkDestroySemaphore(engine.vulkan.renderFinishedSemaphores[i], nil)
648 engine.vulkan.device.device.vkDestroyFence(engine.vulkan.inFlightFences[i], nil) 629 engine.vulkan.device.device.vkDestroyFence(engine.vulkan.inFlightFences[i], nil)
649 630
650 engine.vulkan.device.device.vkDestroyCommandPool(engine.vulkan.commandPool, nil) 631 engine.vulkan.device.device.vkDestroyCommandPool(engine.vulkan.commandPool, nil)
651 for framebuffer in engine.vulkan.framebuffers:
652 engine.vulkan.device.device.vkDestroyFramebuffer(framebuffer, nil)
653
654 engine.vulkan.device.device.vkDestroyPipeline(engine.vulkan.pipeline.pipeline, nil) 632 engine.vulkan.device.device.vkDestroyPipeline(engine.vulkan.pipeline.pipeline, nil)
655 engine.vulkan.device.device.vkDestroyPipelineLayout(engine.vulkan.pipeline.layout, nil) 633 engine.vulkan.device.device.vkDestroyPipelineLayout(engine.vulkan.pipeline.layout, nil)
656 engine.vulkan.device.device.vkDestroyRenderPass(engine.vulkan.renderPass, nil) 634 engine.vulkan.device.device.vkDestroyRenderPass(engine.vulkan.renderPass, nil)
657 635
658 for shaderStage in engine.vulkan.pipeline.shaderStages: 636 for shaderStage in engine.vulkan.pipeline.shaderStages:
659 engine.vulkan.device.device.vkDestroyShaderModule(shaderStage.module, nil) 637 engine.vulkan.device.device.vkDestroyShaderModule(shaderStage.module, nil)
660 638
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) 639 engine.vulkan.instance.vkDestroySurfaceKHR(engine.vulkan.surface, nil)
665 engine.vulkan.device.device.vkDestroyDevice(nil) 640 engine.vulkan.device.device.vkDestroyDevice(nil)
666 when ENABLEVULKANVALIDATIONLAYERS: 641 when ENABLEVULKANVALIDATIONLAYERS:
667 engine.vulkan.instance.vkDestroyDebugUtilsMessengerEXT(engine.vulkan.debugMessenger, nil) 642 engine.vulkan.instance.vkDestroyDebugUtilsMessengerEXT(engine.vulkan.debugMessenger, nil)
668 glslang_finalize_process() 643 glslang_finalize_process()
669 engine.vulkan.instance.vkDestroyInstance(nil) 644 engine.vulkan.instance.vkDestroyInstance(nil)
670 checkXlibResult engine.window.display.XDestroyWindow(engine.window.window) 645 engine.window.trash()
671 discard engine.window.display.XCloseDisplay() # always returns 0