From dcec337fa9374bd2a5002c1873229e8b2cfb6672 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Thu, 19 Dec 2024 21:29:22 +0100 Subject: [PATCH] Swapchain code cleanup Use references instead of pointers --- base/VulkanRaytracingSample.cpp | 7 +- base/VulkanSwapChain.cpp | 84 ++++++++----------- base/VulkanSwapChain.h | 12 +-- base/vulkanexamplebase.cpp | 10 +-- .../dynamicrendering/dynamicrendering.cpp | 6 +- .../inputattachments/inputattachments.cpp | 2 +- examples/multisampling/multisampling.cpp | 2 +- examples/shaderobjects/shaderobjects.cpp | 8 +- examples/subpasses/subpasses.cpp | 2 +- examples/triangle/triangle.cpp | 2 +- .../trianglevulkan13/trianglevulkan13.cpp | 6 +- .../variablerateshading.cpp | 9 +- 12 files changed, 65 insertions(+), 85 deletions(-) diff --git a/base/VulkanRaytracingSample.cpp b/base/VulkanRaytracingSample.cpp index b8b0a854..0de2aa13 100644 --- a/base/VulkanRaytracingSample.cpp +++ b/base/VulkanRaytracingSample.cpp @@ -111,10 +111,9 @@ void VulkanRaytracingSample::setupFrameBuffer() frameBufferCreateInfo.layers = 1; // Create frame buffers for every swap chain image - frameBuffers.resize(swapChain.imageCount); - for (uint32_t i = 0; i < frameBuffers.size(); i++) - { - attachments[0] = swapChain.buffers[i].view; + frameBuffers.resize(swapChain.images.size()); + for (uint32_t i = 0; i < frameBuffers.size(); i++) { + attachments[0] = swapChain.imageViews[i]; VK_CHECK_RESULT(vkCreateFramebuffer(device, &frameBufferCreateInfo, nullptr, &frameBuffers[i])); } } diff --git a/base/VulkanSwapChain.cpp b/base/VulkanSwapChain.cpp index 0920c941..342b29dc 100644 --- a/base/VulkanSwapChain.cpp +++ b/base/VulkanSwapChain.cpp @@ -208,7 +208,7 @@ void VulkanSwapChain::setContext(VkInstance instance, VkPhysicalDevice physicalD this->device = device; } -void VulkanSwapChain::create(uint32_t *width, uint32_t *height, bool vsync, bool fullscreen) +void VulkanSwapChain::create(uint32_t& width, uint32_t& height, bool vsync, bool fullscreen) { assert(physicalDevice); assert(device); @@ -221,7 +221,24 @@ void VulkanSwapChain::create(uint32_t *width, uint32_t *height, bool vsync, bool VkSurfaceCapabilitiesKHR surfCaps; VK_CHECK_RESULT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &surfCaps)); - // Get available present modes + VkExtent2D swapchainExtent = {}; + // If width (and height) equals the special value 0xFFFFFFFF, the size of the surface will be set by the swapchain + if (surfCaps.currentExtent.width == (uint32_t)-1) + { + // If the surface size is undefined, the size is set to the size of the images requested + swapchainExtent.width = width; + swapchainExtent.height = height; + } + else + { + // If the surface size is defined, the swap chain size must match + swapchainExtent = surfCaps.currentExtent; + width = surfCaps.currentExtent.width; + height = surfCaps.currentExtent.height; + } + + + // Select a present mode for the swapchain uint32_t presentModeCount; VK_CHECK_RESULT(vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, NULL)); assert(presentModeCount > 0); @@ -229,26 +246,6 @@ void VulkanSwapChain::create(uint32_t *width, uint32_t *height, bool vsync, bool std::vector presentModes(presentModeCount); VK_CHECK_RESULT(vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, presentModes.data())); - VkExtent2D swapchainExtent = {}; - // If width (and height) equals the special value 0xFFFFFFFF, the size of the surface will be set by the swapchain - if (surfCaps.currentExtent.width == (uint32_t)-1) - { - // If the surface size is undefined, the size is set to - // the size of the images requested. - swapchainExtent.width = *width; - swapchainExtent.height = *height; - } - else - { - // If the surface size is defined, the swap chain size must match - swapchainExtent = surfCaps.currentExtent; - *width = surfCaps.currentExtent.width; - *height = surfCaps.currentExtent.height; - } - - - // Select a present mode for the swapchain - // The VK_PRESENT_MODE_FIFO_KHR mode must always be present as per spec // This mode waits for the vertical blank ("v-sync") VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; @@ -348,25 +345,23 @@ void VulkanSwapChain::create(uint32_t *width, uint32_t *height, bool vsync, bool VK_CHECK_RESULT(vkCreateSwapchainKHR(device, &swapchainCI, nullptr, &swapChain)); - // If an existing swap chain is re-created, destroy the old swap chain - // This also cleans up all the presentable images - if (oldSwapchain != VK_NULL_HANDLE) - { - for (uint32_t i = 0; i < imageCount; i++) - { - vkDestroyImageView(device, buffers[i].view, nullptr); + // If an existing swap chain is re-created, destroy the old swap chain and the ressources owned by the application (image views, images are owned by the swap chain) + if (oldSwapchain != VK_NULL_HANDLE) { + for (auto i = 0; i < images.size(); i++) { + vkDestroyImageView(device, imageViews[i], nullptr); } vkDestroySwapchainKHR(device, oldSwapchain, nullptr); } - VK_CHECK_RESULT(vkGetSwapchainImagesKHR(device, swapChain, &imageCount, NULL)); + uint32_t imageCount{ 0 }; + VK_CHECK_RESULT(vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr)); // Get the swap chain images images.resize(imageCount); VK_CHECK_RESULT(vkGetSwapchainImagesKHR(device, swapChain, &imageCount, images.data())); // Get the swap chain buffers containing the image and imageview - buffers.resize(imageCount); - for (uint32_t i = 0; i < imageCount; i++) + imageViews.resize(imageCount); + for (auto i = 0; i < images.size(); i++) { VkImageViewCreateInfo colorAttachmentView = {}; colorAttachmentView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; @@ -385,20 +380,16 @@ void VulkanSwapChain::create(uint32_t *width, uint32_t *height, bool vsync, bool colorAttachmentView.subresourceRange.layerCount = 1; colorAttachmentView.viewType = VK_IMAGE_VIEW_TYPE_2D; colorAttachmentView.flags = 0; - - buffers[i].image = images[i]; - - colorAttachmentView.image = buffers[i].image; - - VK_CHECK_RESULT(vkCreateImageView(device, &colorAttachmentView, nullptr, &buffers[i].view)); + colorAttachmentView.image = images[i]; + VK_CHECK_RESULT(vkCreateImageView(device, &colorAttachmentView, nullptr, &imageViews[i])); } } -VkResult VulkanSwapChain::acquireNextImage(VkSemaphore presentCompleteSemaphore, uint32_t *imageIndex) +VkResult VulkanSwapChain::acquireNextImage(VkSemaphore presentCompleteSemaphore, uint32_t& imageIndex) { // By setting timeout to UINT64_MAX we will always wait until the next image has been acquired or an actual error is thrown // With that we don't have to handle VK_NOT_READY - return vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, presentCompleteSemaphore, (VkFence)nullptr, imageIndex); + return vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, presentCompleteSemaphore, (VkFence)nullptr, &imageIndex); } VkResult VulkanSwapChain::queuePresent(VkQueue queue, uint32_t imageIndex, VkSemaphore waitSemaphore) @@ -421,16 +412,13 @@ VkResult VulkanSwapChain::queuePresent(VkQueue queue, uint32_t imageIndex, VkSem void VulkanSwapChain::cleanup() { - if (swapChain != VK_NULL_HANDLE) - { - for (uint32_t i = 0; i < imageCount; i++) - { - vkDestroyImageView(device, buffers[i].view, nullptr); + if (swapChain != VK_NULL_HANDLE) { + for (auto i = 0; i < images.size(); i++) { + vkDestroyImageView(device, imageViews[i], nullptr); } - } - if (surface != VK_NULL_HANDLE) - { vkDestroySwapchainKHR(device, swapChain, nullptr); + } + if (surface != VK_NULL_HANDLE) { vkDestroySurfaceKHR(instance, surface, nullptr); } surface = VK_NULL_HANDLE; diff --git a/base/VulkanSwapChain.h b/base/VulkanSwapChain.h index 03c69010..bbaa2645 100644 --- a/base/VulkanSwapChain.h +++ b/base/VulkanSwapChain.h @@ -27,11 +27,6 @@ #include #endif -typedef struct _SwapChainBuffers { - VkImage image{ VK_NULL_HANDLE }; - VkImageView view{ VK_NULL_HANDLE }; -} SwapChainBuffer; - class VulkanSwapChain { private: @@ -43,9 +38,8 @@ public: VkFormat colorFormat{}; VkColorSpaceKHR colorSpace{}; VkSwapchainKHR swapChain{ VK_NULL_HANDLE }; - uint32_t imageCount; std::vector images{}; - std::vector buffers{}; + std::vector imageViews{}; uint32_t queueNodeIndex{ UINT32_MAX }; #if defined(VK_USE_PLATFORM_WIN32_KHR) @@ -79,7 +73,7 @@ public: * @param height Pointer to the height of the swapchain (may be adjusted to fit the requirements of the swapchain) * @param vsync (Optional, default = false) Can be used to force vsync-ed rendering (by using VK_PRESENT_MODE_FIFO_KHR as presentation mode) */ - void create(uint32_t* width, uint32_t* height, bool vsync = false, bool fullscreen = false); + void create(uint32_t& width, uint32_t& height, bool vsync = false, bool fullscreen = false); /** * Acquires the next image in the swap chain * @@ -90,7 +84,7 @@ public: * * @return VkResult of the image acquisition */ - VkResult acquireNextImage(VkSemaphore presentCompleteSemaphore, uint32_t* imageIndex); + VkResult acquireNextImage(VkSemaphore presentCompleteSemaphore, uint32_t& imageIndex); /** * Queue an image for presentation * diff --git a/base/vulkanexamplebase.cpp b/base/vulkanexamplebase.cpp index a85a8bbc..d278fd05 100644 --- a/base/vulkanexamplebase.cpp +++ b/base/vulkanexamplebase.cpp @@ -179,7 +179,7 @@ std::string VulkanExampleBase::getWindowTitle() const void VulkanExampleBase::createCommandBuffers() { // Create one command buffer for each swap chain image - drawCmdBuffers.resize(swapChain.imageCount); + drawCmdBuffers.resize(swapChain.images.size()); VkCommandBufferAllocateInfo cmdBufAllocateInfo = vks::initializers::commandBufferAllocateInfo(cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, static_cast(drawCmdBuffers.size())); VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, drawCmdBuffers.data())); } @@ -751,7 +751,7 @@ void VulkanExampleBase::drawUI(const VkCommandBuffer commandBuffer) void VulkanExampleBase::prepareFrame() { // Acquire the next image from the swap chain - VkResult result = swapChain.acquireNextImage(semaphores.presentComplete, ¤tBuffer); + VkResult result = swapChain.acquireNextImage(semaphores.presentComplete, currentBuffer); // Recreate the swapchain if it's no longer compatible with the surface (OUT_OF_DATE) // SRS - If no longer optimal (VK_SUBOPTIMAL_KHR), wait until submitFrame() in case number of swapchain images will change on resize if ((result == VK_ERROR_OUT_OF_DATE_KHR) || (result == VK_SUBOPTIMAL_KHR)) { @@ -3077,11 +3077,11 @@ void VulkanExampleBase::setupDepthStencil() void VulkanExampleBase::setupFrameBuffer() { // Create frame buffers for every swap chain image - frameBuffers.resize(swapChain.imageCount); + frameBuffers.resize(swapChain.images.size()); for (uint32_t i = 0; i < frameBuffers.size(); i++) { const VkImageView attachments[2] = { - swapChain.buffers[i].view, + swapChain.imageViews[i], // Depth/Stencil attachment is the same for all frame buffers depthStencil.view }; @@ -3290,7 +3290,7 @@ void VulkanExampleBase::createSurface() void VulkanExampleBase::createSwapChain() { - swapChain.create(&width, &height, settings.vsync, settings.fullscreen); + swapChain.create(width, height, settings.vsync, settings.fullscreen); } void VulkanExampleBase::OnUpdateUIOverlay(vks::UIOverlay *overlay) {} diff --git a/examples/dynamicrendering/dynamicrendering.cpp b/examples/dynamicrendering/dynamicrendering.cpp index e433202c..b3ac9ebc 100644 --- a/examples/dynamicrendering/dynamicrendering.cpp +++ b/examples/dynamicrendering/dynamicrendering.cpp @@ -104,7 +104,7 @@ public: // This set of barriers prepares the color and depth images for output vks::tools::insertImageMemoryBarrier( drawCmdBuffers[i], - swapChain.buffers[i].image, + swapChain.images[i], 0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, @@ -126,7 +126,7 @@ public: // New structures are used to define the attachments used in dynamic rendering VkRenderingAttachmentInfoKHR colorAttachment{}; colorAttachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR; - colorAttachment.imageView = swapChain.buffers[i].view; + colorAttachment.imageView = swapChain.imageViews[i]; colorAttachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; @@ -173,7 +173,7 @@ public: // This set of barriers prepares the color image for presentation, we don't need to care for the depth image vks::tools::insertImageMemoryBarrier( drawCmdBuffers[i], - swapChain.buffers[i].image, + swapChain.images[i], VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, diff --git a/examples/inputattachments/inputattachments.cpp b/examples/inputattachments/inputattachments.cpp index 106591c9..f562eff6 100644 --- a/examples/inputattachments/inputattachments.cpp +++ b/examples/inputattachments/inputattachments.cpp @@ -210,7 +210,7 @@ public: frameBuffers.resize(swapChain.imageCount); for (uint32_t i = 0; i < frameBuffers.size(); i++) { - views[0] = swapChain.buffers[i].view; + views[0] = swapChain.imageViews[i]; views[1] = attachments[i].color.view; views[2] = attachments[i].depth.view; VK_CHECK_RESULT(vkCreateFramebuffer(device, &frameBufferCI, nullptr, &frameBuffers[i])); diff --git a/examples/multisampling/multisampling.cpp b/examples/multisampling/multisampling.cpp index 0173039d..a39a9cc1 100644 --- a/examples/multisampling/multisampling.cpp +++ b/examples/multisampling/multisampling.cpp @@ -333,7 +333,7 @@ public: frameBuffers.resize(swapChain.imageCount); for (uint32_t i = 0; i < frameBuffers.size(); i++) { - attachments[1] = swapChain.buffers[i].view; + attachments[1] = swapChain.imageViews[i]; VK_CHECK_RESULT(vkCreateFramebuffer(device, &frameBufferCreateInfo, nullptr, &frameBuffers[i])); } } diff --git a/examples/shaderobjects/shaderobjects.cpp b/examples/shaderobjects/shaderobjects.cpp index 18fe3306..3ba4e49e 100644 --- a/examples/shaderobjects/shaderobjects.cpp +++ b/examples/shaderobjects/shaderobjects.cpp @@ -268,11 +268,11 @@ public: for (int32_t i = 0; i < drawCmdBuffers.size(); ++i) { VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo)); - + // Transition color and depth images for drawing vks::tools::insertImageMemoryBarrier( drawCmdBuffers[i], - swapChain.buffers[i].image, + swapChain.images[i], 0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, @@ -294,7 +294,7 @@ public: // New structures are used to define the attachments used in dynamic rendering VkRenderingAttachmentInfoKHR colorAttachment{}; colorAttachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR; - colorAttachment.imageView = swapChain.buffers[i].view; + colorAttachment.imageView = swapChain.imageViews[i]; colorAttachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; @@ -385,7 +385,7 @@ public: // Transition color image for presentation vks::tools::insertImageMemoryBarrier( drawCmdBuffers[i], - swapChain.buffers[i].image, + swapChain.images[i], VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, diff --git a/examples/subpasses/subpasses.cpp b/examples/subpasses/subpasses.cpp index 2b1db51b..e7cee1f1 100644 --- a/examples/subpasses/subpasses.cpp +++ b/examples/subpasses/subpasses.cpp @@ -251,7 +251,7 @@ public: frameBuffers.resize(swapChain.imageCount); for (uint32_t i = 0; i < frameBuffers.size(); i++) { - attachments[0] = swapChain.buffers[i].view; + attachments[0] = swapChain.imageViews[i]; attachments[1] = this->attachments.position.view; attachments[2] = this->attachments.normal.view; attachments[3] = this->attachments.albedo.view; diff --git a/examples/triangle/triangle.cpp b/examples/triangle/triangle.cpp index b8ca7ede..d4ea1432 100644 --- a/examples/triangle/triangle.cpp +++ b/examples/triangle/triangle.cpp @@ -510,7 +510,7 @@ public: { std::array attachments{}; // Color attachment is the view of the swapchain image - attachments[0] = swapChain.buffers[i].view; + attachments[0] = swapChain.imageViews[i]; // Depth/Stencil attachment is the same for all frame buffers due to how depth works with current GPUs attachments[1] = depthStencil.view; diff --git a/examples/trianglevulkan13/trianglevulkan13.cpp b/examples/trianglevulkan13/trianglevulkan13.cpp index e143fa0e..78824c60 100644 --- a/examples/trianglevulkan13/trianglevulkan13.cpp +++ b/examples/trianglevulkan13/trianglevulkan13.cpp @@ -705,13 +705,13 @@ public: VK_CHECK_RESULT(vkBeginCommandBuffer(commandBuffer, &cmdBufInfo)); // With dynamic rendering we need to explicitly add layout transitions by using barriers, this set of barriers prepares the color and depth images for output - vks::tools::insertImageMemoryBarrier(commandBuffer, swapChain.buffers[imageIndex].image, 0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }); + vks::tools::insertImageMemoryBarrier(commandBuffer, swapChain.images[imageIndex], 0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }); vks::tools::insertImageMemoryBarrier(commandBuffer, depthStencil.image, 0, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VkImageSubresourceRange{ VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, 0, 1, 0, 1 }); // New structures are used to define the attachments used in dynamic rendering // Color attachment VkRenderingAttachmentInfo colorAttachment{ VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO }; - colorAttachment.imageView = swapChain.buffers[imageIndex].view; + colorAttachment.imageView = swapChain.imageViews[imageIndex]; colorAttachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; @@ -755,7 +755,7 @@ public: vkCmdEndRendering(commandBuffer); // This barrier prepares the color image for presentation, we don't need to care for the depth image - vks::tools::insertImageMemoryBarrier(commandBuffer, swapChain.buffers[imageIndex].image, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 0, VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_2_NONE, VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }); + vks::tools::insertImageMemoryBarrier(commandBuffer, swapChain.images[imageIndex], VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 0, VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_2_NONE, VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }); VK_CHECK_RESULT(vkEndCommandBuffer(commandBuffer)); // Submit the command buffer to the graphics queue diff --git a/examples/variablerateshading/variablerateshading.cpp b/examples/variablerateshading/variablerateshading.cpp index b2d7c947..6c07987c 100644 --- a/examples/variablerateshading/variablerateshading.cpp +++ b/examples/variablerateshading/variablerateshading.cpp @@ -1,7 +1,7 @@ /* * Vulkan Example - Variable rate shading * -* Copyright (C) 2020-2023 by Sascha Willems - www.saschawillems.de +* Copyright (C) 2020-2024 by Sascha Willems - www.saschawillems.de * * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) */ @@ -91,10 +91,9 @@ void VulkanExample::setupFrameBuffer() frameBufferCreateInfo.layers = 1; // Create frame buffers for every swap chain image - frameBuffers.resize(swapChain.imageCount); - for (uint32_t i = 0; i < frameBuffers.size(); i++) - { - attachments[0] = swapChain.buffers[i].view; + frameBuffers.resize(swapChain.images.size()); + for (uint32_t i = 0; i < frameBuffers.size(); i++) { + attachments[0] = swapChain.imageViews[i]; VK_CHECK_RESULT(vkCreateFramebuffer(device, &frameBufferCreateInfo, nullptr, &frameBuffers[i])); } }