Mercurial > games > semicongine
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 |