From 4d572441518882515f65ae48e802b0da78034b71 Mon Sep 17 00:00:00 2001 From: bailwillharr Date: Tue, 18 Oct 2022 12:11:45 +0100 Subject: [PATCH] Add swapchain --- src/gfx_device_vulkan.cpp | 152 +++++++++++++++++++++++++++----------- 1 file changed, 108 insertions(+), 44 deletions(-) diff --git a/src/gfx_device_vulkan.cpp b/src/gfx_device_vulkan.cpp index 2777cbc..5e74aba 100644 --- a/src/gfx_device_vulkan.cpp +++ b/src/gfx_device_vulkan.cpp @@ -4,9 +4,7 @@ #ifdef ENGINE_BUILD_VULKAN #include "gfx_device.hpp" - #include "util.hpp" - #include "config.h" #include "log.hpp" @@ -27,9 +25,6 @@ namespace engine { - // singleton variable - static GFXDevice* s_gfx_device_instance = nullptr; - // structures struct LayerInfo { @@ -57,10 +52,18 @@ namespace engine { VkSwapchainKHR swapchain = VK_NULL_HANDLE; VkExtent2D extent; - VkFormat format; + VkSurfaceFormatKHR surfaceFormat; + VkPresentModeKHR presentMode; std::vector images{}; std::vector imageViews{}; + std::vector framebuffers{}; + + VkRenderPass renderpass; + + uint32_t swapchainImageIndex = 0; + VkSemaphore acquireSemaphore = VK_NULL_HANDLE; + VkSemaphore releaseSemaphore = VK_NULL_HANDLE; }; // enums @@ -231,45 +234,43 @@ namespace engine { throw std::runtime_error("Unable to find the requested queue"); } + // This is called not just on initialisation, but also when the window is resized. static void createSwapchain(VkDevice device, const std::vector queues, SDL_Window* window, VkSurfaceKHR surface, const SwapchainSupportDetails& supportDetails, Swapchain* swapchain) { VkResult res; - VkSurfaceFormatKHR chosenSurfaceFormat = supportDetails.formats[0]; - + swapchain->surfaceFormat = supportDetails.formats[0]; for (const auto& format : supportDetails.formats) { if (format.format == VK_FORMAT_B8G8R8A8_SRGB && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - chosenSurfaceFormat = format; // prefer using srgb non linear colors + swapchain->surfaceFormat = format; // prefer using srgb non linear colors } } - VkPresentModeKHR chosenPresentMode = VK_PRESENT_MODE_FIFO_KHR; + swapchain->presentMode = VK_PRESENT_MODE_FIFO_KHR; // This mode is always available for (const auto& presMode : supportDetails.presentModes) { if (presMode == VK_PRESENT_MODE_MAILBOX_KHR) { - chosenPresentMode = presMode; // this mode allows uncapped FPS while also avoiding screen tearing + swapchain->presentMode = presMode; // this mode allows uncapped FPS while also avoiding screen tearing } } - VkExtent2D chosenSwapExtent{}; - if (supportDetails.caps.currentExtent.width != std::numeric_limits::max()) { - chosenSwapExtent = supportDetails.caps.currentExtent; + swapchain->extent = supportDetails.caps.currentExtent; } else { // if fb size isn't already found, get it from SDL int width, height; SDL_Vulkan_GetDrawableSize(window, &width, &height); - chosenSwapExtent.width = static_cast(width); - chosenSwapExtent.height = static_cast(height); + swapchain->extent.width = static_cast(width); + swapchain->extent.height = static_cast(height); - chosenSwapExtent.width = std::clamp( - chosenSwapExtent.width, + swapchain->extent.width = std::clamp( + swapchain->extent.width, supportDetails.caps.minImageExtent.width, supportDetails.caps.maxImageExtent.width); - chosenSwapExtent.height = std::clamp( - chosenSwapExtent.height, + swapchain->extent.height = std::clamp( + swapchain->extent.height, supportDetails.caps.minImageExtent.height, supportDetails.caps.maxImageExtent.height); } @@ -284,9 +285,9 @@ namespace engine { .flags = 0, .surface = surface, .minImageCount = imageCount, - .imageFormat = chosenSurfaceFormat.format, - .imageColorSpace = chosenSurfaceFormat.colorSpace, - .imageExtent = chosenSwapExtent, + .imageFormat = swapchain->surfaceFormat.format, + .imageColorSpace = swapchain->surfaceFormat.colorSpace, + .imageExtent = swapchain->extent, .imageArrayLayers = 1, .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, @@ -294,9 +295,9 @@ namespace engine { .pQueueFamilyIndices = nullptr, .preTransform = supportDetails.caps.currentTransform, .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, - .presentMode = chosenPresentMode, + .presentMode = swapchain->presentMode, .clipped = VK_TRUE, - .oldSwapchain = VK_NULL_HANDLE, + .oldSwapchain = swapchain->swapchain, }; @@ -313,6 +314,11 @@ namespace engine { res = vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapchain->swapchain); assert(res == VK_SUCCESS); + if (createInfo.oldSwapchain != VK_NULL_HANDLE) { + // if recreating swapchain, destroy old one + vkDestroySwapchainKHR(device, createInfo.oldSwapchain, nullptr); + } + // get all the image handles uint32_t swapchainImageCount = 0; res = vkGetSwapchainImagesKHR(device, swapchain->swapchain, &swapchainImageCount, nullptr); @@ -321,19 +327,52 @@ namespace engine { res = vkGetSwapchainImagesKHR(device, swapchain->swapchain, &swapchainImageCount, swapchain->images.data()); assert(res == VK_SUCCESS); - swapchain->format = chosenSurfaceFormat.format; - swapchain->extent = chosenSwapExtent; + // create the render pass + { + VkAttachmentDescription colorAttachment{}; + colorAttachment.format = swapchain->surfaceFormat.format; + colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; + colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - // create image views - swapchain->imageViews.clear(); - for (VkImage image : swapchain->images) { + VkAttachmentReference colorAttachmentRef{}; + colorAttachmentRef.attachment = 0; + colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpass{}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &colorAttachmentRef; + + VkRenderPassCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + createInfo.attachmentCount = 1; + createInfo.pAttachments = &colorAttachment; + createInfo.subpassCount = 1; + createInfo.pSubpasses = &subpass; + + //if (swapchain->renderpass != VK_NULL_HANDLE) { + // vkDestroyRenderPass(device, swapchain->renderpass, nullptr); + // swapchain->renderpass = VK_NULL_HANDLE; + //} + res = vkCreateRenderPass(device, &createInfo, nullptr, &swapchain->renderpass); + } + + // create image views and framebuffers + swapchain->imageViews.resize(swapchain->images.size()); + swapchain->framebuffers.resize(swapchain->images.size()); + for (int i = 0; i < swapchain->images.size(); i++) { VkImageViewCreateInfo createInfo{}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.pNext = nullptr; - createInfo.image = image; + createInfo.image = swapchain->images[i]; createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - createInfo.format = swapchain->format; + createInfo.format = swapchain->surfaceFormat.format; createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; @@ -343,13 +382,40 @@ namespace engine { createInfo.subresourceRange.levelCount = 1; createInfo.subresourceRange.baseArrayLayer = 0; createInfo.subresourceRange.layerCount = 1; - - VkImageView imageView; - res = vkCreateImageView(device, &createInfo, nullptr, &imageView); + res = vkCreateImageView(device, &createInfo, nullptr, &swapchain->imageViews[i]); assert(res == VK_SUCCESS); - swapchain->imageViews.push_back(imageView); + VkImageView attachments[] = { + swapchain->imageViews[i] + }; + VkFramebufferCreateInfo framebufferInfo{}; + framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebufferInfo.renderPass = swapchain->renderpass; + framebufferInfo.attachmentCount = 1; + framebufferInfo.pAttachments = attachments; + framebufferInfo.width = swapchain->extent.width; + framebufferInfo.height = swapchain->extent.height; + framebufferInfo.layers = 1; + + if (swapchain->framebuffers[i] != VK_NULL_HANDLE) { + vkDestroyFramebuffer(device, swapchain->framebuffers[i], nullptr); + } + res = vkCreateFramebuffer(device, &framebufferInfo, nullptr, &swapchain->framebuffers[i]); + assert(res == VK_SUCCESS); + + } + + // create the swapchain semaphores + VkSemaphoreCreateInfo semaphoreInfo{}; + semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + if (swapchain->acquireSemaphore == VK_NULL_HANDLE) { + res = vkCreateSemaphore(device, &semaphoreInfo, nullptr, &swapchain->acquireSemaphore); + assert(res == VK_SUCCESS); + } + if (swapchain->releaseSemaphore == VK_NULL_HANDLE) { + res = vkCreateSemaphore(device, &semaphoreInfo, nullptr, &swapchain->releaseSemaphore); + assert(res == VK_SUCCESS); } } @@ -377,12 +443,6 @@ namespace engine { GFXDevice::GFXDevice(const char* appName, const char* appVersion, SDL_Window* window) { - // ensure there is only one instance of this class - if (s_gfx_device_instance != nullptr) { - throw std::runtime_error("Multiple gfxdevice classes cannot be created"); - } - s_gfx_device_instance = this; - pimpl = std::make_unique(); VkResult res; @@ -816,9 +876,15 @@ namespace engine { { TRACE("Destroying GFXDevice..."); + vkDestroySemaphore(pimpl->device, pimpl->swapchain.releaseSemaphore, nullptr); + vkDestroySemaphore(pimpl->device, pimpl->swapchain.acquireSemaphore, nullptr); for (VkImageView view : pimpl->swapchain.imageViews) { vkDestroyImageView(pimpl->device, view, nullptr); } + for (VkFramebuffer fb : pimpl->swapchain.framebuffers) { + vkDestroyFramebuffer(pimpl->device, fb, nullptr); + } + vkDestroyRenderPass(pimpl->device, pimpl->swapchain.renderpass, nullptr); vkDestroySwapchainKHR(pimpl->device, pimpl->swapchain.swapchain, nullptr); vmaDestroyAllocator(pimpl->allocator); @@ -828,8 +894,6 @@ namespace engine { vkDestroySurfaceKHR(pimpl->instance, pimpl->surface, nullptr); vkDestroyDebugUtilsMessengerEXT(pimpl->instance, pimpl->debugMessenger, nullptr); vkDestroyInstance(pimpl->instance, nullptr); - - s_gfx_device_instance = nullptr; } void GFXDevice::draw()