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 |
