From f48fb5b14f7a55cc1d2363605f35b5d6062f83c0 Mon Sep 17 00:00:00 2001 From: Kearwood Gilbert Date: Sun, 3 Apr 2022 21:49:54 -0700 Subject: [PATCH] Vulkan Refactoring - Implemented KRSwapchain --- kraken/CMakeLists.txt | 1 + kraken/KRDevice.cpp | 80 +++++++++- kraken/KRDevice.h | 4 + kraken/KRPipelineManager.cpp | 7 +- kraken/KRPresentationThread.cpp | 11 +- kraken/KRRenderPass.cpp | 7 +- kraken/KRSurface.cpp | 258 +++----------------------------- kraken/KRSurface.h | 14 +- kraken/KRSwapchain.cpp | 232 ++++++++++++++++++++++++++++ kraken/KRSwapchain.h | 66 ++++++++ 10 files changed, 420 insertions(+), 260 deletions(-) create mode 100644 kraken/KRSwapchain.cpp create mode 100644 kraken/KRSwapchain.h diff --git a/kraken/CMakeLists.txt b/kraken/CMakeLists.txt index 7043d4e..aaa8081 100644 --- a/kraken/CMakeLists.txt +++ b/kraken/CMakeLists.txt @@ -28,6 +28,7 @@ add_sources(KRRenderPass.cpp) add_sources(KRSurface.cpp) add_sources(KRSurfaceManager.cpp) add_sources(KRStreamerThread.cpp) +add_sources(KRSwapchain.cpp) IF(APPLE) add_sources(KREngine.mm) diff --git a/kraken/KRDevice.cpp b/kraken/KRDevice.cpp index 925f999..68b6fce 100644 --- a/kraken/KRDevice.cpp +++ b/kraken/KRDevice.cpp @@ -233,4 +233,82 @@ VmaAllocator KRDevice::getAllocator() { assert(m_allocator != VK_NULL_HANDLE); return m_allocator; -} \ No newline at end of file +} + +KrResult KRDevice::selectSurfaceFormat(VkSurfaceKHR& surface, VkSurfaceFormatKHR& selectedFormat) +{ + + std::vector surfaceFormats; + uint32_t formatCount = 0; + if (vkGetPhysicalDeviceSurfaceFormatsKHR(m_device, surface, &formatCount, nullptr) != VK_SUCCESS) { + return KR_ERROR_VULKAN_SWAP_CHAIN; + } + + if (formatCount != 0) { + surfaceFormats.resize(formatCount); + if (vkGetPhysicalDeviceSurfaceFormatsKHR(m_device, surface, &formatCount, surfaceFormats.data()) != VK_SUCCESS) { + return KR_ERROR_VULKAN_SWAP_CHAIN; + } + } + + selectedFormat = surfaceFormats[0]; + for (const auto& availableFormat : surfaceFormats) { + if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { + selectedFormat = availableFormat; + break; + } + } + return KR_SUCCESS; +} + +KrResult KRDevice::selectDepthFormat(VkFormat& selectedDepthFormat) +{ + selectedDepthFormat = VK_FORMAT_UNDEFINED; + VkFormatFeatureFlags requiredFeatures = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT; + std::vector candidateFormats; + candidateFormats.push_back(VK_FORMAT_D32_SFLOAT_S8_UINT); + candidateFormats.push_back(VK_FORMAT_D24_UNORM_S8_UINT); + for (VkFormat format : candidateFormats) { + VkFormatProperties props; + vkGetPhysicalDeviceFormatProperties(m_device, format, &props); + + if ((props.optimalTilingFeatures & requiredFeatures) == requiredFeatures) { + selectedDepthFormat = format; + break; + } + } + + if (selectedDepthFormat == VK_FORMAT_UNDEFINED) { + return KR_ERROR_VULKAN_DEPTHBUFFER; + } + + return KR_SUCCESS; +} + +KrResult KRDevice::selectPresentMode(VkSurfaceKHR& surface, VkPresentModeKHR& selectedPresentMode) +{ + // VK_PRESENT_MODE_FIFO_KHR is always available + selectedPresentMode = VK_PRESENT_MODE_FIFO_KHR; + + std::vector surfacePresentModes; + + uint32_t presentModeCount = 0; + if (vkGetPhysicalDeviceSurfacePresentModesKHR(m_device, surface, &presentModeCount, nullptr) != VK_SUCCESS) { + return KR_ERROR_VULKAN_SWAP_CHAIN; + } + + if (presentModeCount != 0) { + surfacePresentModes.resize(presentModeCount); + if (vkGetPhysicalDeviceSurfacePresentModesKHR(m_device, surface, &presentModeCount, surfacePresentModes.data()) != VK_SUCCESS) { + return KR_ERROR_VULKAN_SWAP_CHAIN; + } + } + + // Try to find a better mode + for (const auto& availablePresentMode : surfacePresentModes) { + if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) { + selectedPresentMode = availablePresentMode; + } + } + return KR_SUCCESS; +} diff --git a/kraken/KRDevice.h b/kraken/KRDevice.h index a4d1d95..7659c46 100644 --- a/kraken/KRDevice.h +++ b/kraken/KRDevice.h @@ -49,6 +49,10 @@ public: VmaAllocator getAllocator(); + KrResult selectSurfaceFormat(VkSurfaceKHR& surface, VkSurfaceFormatKHR& surfaceFormat); + KrResult selectDepthFormat(VkFormat& selectedDepthFormat); + KrResult selectPresentMode(VkSurfaceKHR& surface, VkPresentModeKHR& selectedPresentMode); + VkPhysicalDevice m_device; VkDevice m_logicalDevice; VkPhysicalDeviceProperties m_deviceProperties; diff --git a/kraken/KRPipelineManager.cpp b/kraken/KRPipelineManager.cpp index db4b9c8..9883d10 100644 --- a/kraken/KRPipelineManager.cpp +++ b/kraken/KRPipelineManager.cpp @@ -36,6 +36,7 @@ #include "KRDirectionalLight.h" #include "KRSpotLight.h" #include "KRPointLight.h" +#include "KRSwapchain.h" #ifndef ANDROID #include "glslang/Public/ShaderLang.h" @@ -67,9 +68,9 @@ KRPipeline* KRPipelineManager::getPipeline(KRSurface& surface, KRRenderPass& ren std::pair > key; key.first = shader_name; key.second.push_back(surface.m_deviceHandle); - key.second.push_back(surface.m_swapChainImageFormat); - key.second.push_back(surface.m_swapChainExtent.width); - key.second.push_back(surface.m_swapChainExtent.height); + key.second.push_back(surface.m_swapChain->m_imageFormat); + key.second.push_back(surface.m_swapChain->m_extent.width); + key.second.push_back(surface.m_swapChain->m_extent.height); key.second.push_back(vertexAttributes); key.second.push_back(modelFormat); // TODO - Add renderPass unique identifier to key diff --git a/kraken/KRPresentationThread.cpp b/kraken/KRPresentationThread.cpp index d320109..1f5d3c1 100644 --- a/kraken/KRPresentationThread.cpp +++ b/kraken/KRPresentationThread.cpp @@ -31,6 +31,7 @@ #include "KRPresentationThread.h" #include "KRRenderPass.h" +#include "KRSwapchain.h" KRPresentationThread::KRPresentationThread(KRContext& context) : KRContextObject(context) @@ -116,15 +117,15 @@ void KRPresentationThread::renderFrame() break; } bool resized = false; - if (surface.m_swapChainExtent.width != surfaceCapabilities.currentExtent.width || - surface.m_swapChainExtent.height != surfaceCapabilities.currentExtent.height) { + if (surface.m_swapChain->m_extent.width != surfaceCapabilities.currentExtent.width || + surface.m_swapChain->m_extent.height != surfaceCapabilities.currentExtent.height) { // We can't rely on VK_ERROR_OUT_OF_DATE_KHR to always signal when a resize has happend. // This must also be checked for explicitly. resized = true; } uint32_t imageIndex = 0; - VkResult result = vkAcquireNextImageKHR(device.m_logicalDevice, surface.m_swapChain, UINT64_MAX, surface.m_imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex); + VkResult result = vkAcquireNextImageKHR(device.m_logicalDevice, surface.m_swapChain->m_swapChain, UINT64_MAX, surface.m_imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex); if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || resized) { // TODO - Must explicitly detect resize and trigger swapchain re-creation as well @@ -154,7 +155,7 @@ void KRPresentationThread::renderFrame() // TODO - This needs to be moved to the Render thread... float deltaTime = 0.005; // TODO - Replace dummy value if (scene) { - scene->renderFrame(commandBuffer, surface, 0, deltaTime, surface.m_swapChainExtent.width, surface.m_swapChainExtent.height); + scene->renderFrame(commandBuffer, surface, 0, deltaTime, surface.m_swapChain->m_extent.width, surface.m_swapChain->m_extent.height); } if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS) { @@ -187,7 +188,7 @@ void KRPresentationThread::renderFrame() presentInfo.waitSemaphoreCount = 1; presentInfo.pWaitSemaphores = signalSemaphores; presentInfo.swapchainCount = 1; - presentInfo.pSwapchains = &surface.m_swapChain; + presentInfo.pSwapchains = &surface.m_swapChain->m_swapChain; presentInfo.pImageIndices = &imageIndex; presentInfo.pResults = nullptr; vkQueuePresentKHR(device.m_graphicsQueue, &presentInfo); diff --git a/kraken/KRRenderPass.cpp b/kraken/KRRenderPass.cpp index 5940bb4..a9d3901 100644 --- a/kraken/KRRenderPass.cpp +++ b/kraken/KRRenderPass.cpp @@ -30,7 +30,8 @@ // #include "KRRenderPass.h" -#include "KRSurface.h"" +#include "KRSurface.h" +#include "KRSwapchain.h" KRRenderPass::KRRenderPass(KRContext& context) : KRContextObject(context) @@ -126,9 +127,9 @@ void KRRenderPass::begin(VkCommandBuffer& commandBuffer, KRSurface& surface) VkRenderPassBeginInfo renderPassInfo{}; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; renderPassInfo.renderPass = m_renderPass; - renderPassInfo.framebuffer = surface.m_swapChainFramebuffers[surface.m_frameIndex % surface.m_swapChainFramebuffers.size()]; + renderPassInfo.framebuffer = surface.m_swapChain->m_framebuffers[surface.m_frameIndex % surface.m_swapChain->m_framebuffers.size()]; renderPassInfo.renderArea.offset = { 0, 0 }; - renderPassInfo.renderArea.extent = surface.m_swapChainExtent; + renderPassInfo.renderArea.extent = surface.m_swapChain->m_extent; renderPassInfo.clearValueCount = static_cast(clearValues.size()); renderPassInfo.pClearValues = clearValues.data(); diff --git a/kraken/KRSurface.cpp b/kraken/KRSurface.cpp index 86163ae..2146018 100644 --- a/kraken/KRSurface.cpp +++ b/kraken/KRSurface.cpp @@ -30,6 +30,7 @@ // #include "KRSurface.h" +#include "KRSwapchain.h" #include "KRRenderPass.h" #ifdef WIN32 @@ -43,18 +44,12 @@ KRSurface::KRSurface(KRContext& context) #endif , m_deviceHandle(VK_NULL_HANDLE) , m_surface(VK_NULL_HANDLE) - , m_swapChain(VK_NULL_HANDLE) - , m_swapChainImageFormat(VK_FORMAT_UNDEFINED) - , m_swapChainExtent({ 0, 0 }) - , m_depthImageFormat(VK_FORMAT_UNDEFINED) - , m_depthImage(VK_NULL_HANDLE) - , m_depthImageAllocation(VK_NULL_HANDLE) - , m_depthImageView(VK_NULL_HANDLE) , m_imageAvailableSemaphore(VK_NULL_HANDLE) , m_renderFinishedSemaphore(VK_NULL_HANDLE) , m_frameIndex(0) { m_forwardOpaquePass = std::make_unique(context); + m_swapChain = std::make_unique(context); } KRSurface::~KRSurface() @@ -119,222 +114,41 @@ void KRSurface::destroy() KrResult KRSurface::createSwapChain() { + std::unique_ptr& device = m_pContext->getDeviceManager()->getDevice(m_deviceHandle); + KrResult res = KR_SUCCESS; + VkSurfaceFormatKHR selectedSurfaceFormat{}; + res =device->selectSurfaceFormat(m_surface, selectedSurfaceFormat); + if (res != KR_SUCCESS) return res; + + VkFormat depthImageFormat = VK_FORMAT_UNDEFINED; + res = device->selectDepthFormat(depthImageFormat); + if (res != KR_SUCCESS) { + return res; + } + VkSurfaceCapabilitiesKHR surfaceCapabilities{}; vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device->m_device, m_surface, &surfaceCapabilities); - std::vector surfaceFormats; - uint32_t formatCount = 0; - vkGetPhysicalDeviceSurfaceFormatsKHR(device->m_device, m_surface, &formatCount, nullptr); - - if (formatCount != 0) { - surfaceFormats.resize(formatCount); - vkGetPhysicalDeviceSurfaceFormatsKHR(device->m_device, m_surface, &formatCount, surfaceFormats.data()); - } - - std::vector surfacePresentModes; - - uint32_t presentModeCount = 0; - vkGetPhysicalDeviceSurfacePresentModesKHR(device->m_device, m_surface, &presentModeCount, nullptr); - - if (presentModeCount != 0) { - surfacePresentModes.resize(presentModeCount); - vkGetPhysicalDeviceSurfacePresentModesKHR(device->m_device, m_surface, &presentModeCount, surfacePresentModes.data()); - } - - VkSurfaceFormatKHR selectedSurfaceFormat = surfaceFormats[0]; - for (const auto& availableFormat : surfaceFormats) { - if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - selectedSurfaceFormat = availableFormat; - break; - } - } - - // VK_PRESENT_MODE_FIFO_KHR is always available - VkPresentModeKHR selectedPresentMode = VK_PRESENT_MODE_FIFO_KHR; - - // Try to find a better mode - for (const auto& availablePresentMode : surfacePresentModes) { - if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) { - selectedPresentMode = availablePresentMode; - } - } - VkExtent2D swapExtent; if (surfaceCapabilities.currentExtent.width != UINT32_MAX) { swapExtent = surfaceCapabilities.currentExtent; - } - else { + } else { const uint32_t MAX_WIDTH = 8192; const uint32_t MAX_HEIGHT = 8192; swapExtent.width = std::max(surfaceCapabilities.minImageExtent.width, std::min(surfaceCapabilities.maxImageExtent.width, MAX_WIDTH)); swapExtent.height = std::max(surfaceCapabilities.minImageExtent.height, std::min(surfaceCapabilities.maxImageExtent.height, MAX_HEIGHT)); } - m_swapChainExtent = swapExtent; uint32_t imageCount = surfaceCapabilities.minImageCount + 1; if (surfaceCapabilities.maxImageCount > 0 && imageCount > surfaceCapabilities.maxImageCount) { imageCount = surfaceCapabilities.maxImageCount; } - VkSwapchainCreateInfoKHR swapChainCreateInfo{}; - swapChainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - swapChainCreateInfo.surface = m_surface; - swapChainCreateInfo.minImageCount = imageCount; - swapChainCreateInfo.imageFormat = selectedSurfaceFormat.format; - swapChainCreateInfo.imageColorSpace = selectedSurfaceFormat.colorSpace; - swapChainCreateInfo.imageExtent = swapExtent; - swapChainCreateInfo.imageArrayLayers = 1; - swapChainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - uint32_t queueFamilyIndices[] = { - device->m_graphicsFamilyQueueIndex, - device->m_computeFamilyQueueIndex - }; - if (device->m_graphicsFamilyQueueIndex == device->m_computeFamilyQueueIndex) { - swapChainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; - swapChainCreateInfo.queueFamilyIndexCount = 0; - swapChainCreateInfo.pQueueFamilyIndices = nullptr; - } - else { - swapChainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; - swapChainCreateInfo.queueFamilyIndexCount = 2; - swapChainCreateInfo.pQueueFamilyIndices = queueFamilyIndices; - } - - swapChainCreateInfo.preTransform = surfaceCapabilities.currentTransform; - swapChainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - swapChainCreateInfo.presentMode = selectedPresentMode; - swapChainCreateInfo.clipped = VK_TRUE; - swapChainCreateInfo.oldSwapchain = VK_NULL_HANDLE; - - if (vkCreateSwapchainKHR(device->m_logicalDevice, &swapChainCreateInfo, nullptr, &m_swapChain) != VK_SUCCESS) { - return KR_ERROR_VULKAN_SWAP_CHAIN; - } - - vkGetSwapchainImagesKHR(device->m_logicalDevice, m_swapChain, &imageCount, nullptr); - m_swapChainImages.resize(imageCount); - vkGetSwapchainImagesKHR(device->m_logicalDevice, m_swapChain, &imageCount, m_swapChainImages.data()); - - m_swapChainImageFormat = selectedSurfaceFormat.format; - - m_swapChainImageViews.resize(m_swapChainImages.size()); - for (size_t i = 0; i < m_swapChainImages.size(); i++) { - VkImageViewCreateInfo createInfo{}; - createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - createInfo.image = m_swapChainImages[i]; - createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - createInfo.format = m_swapChainImageFormat; - createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - createInfo.subresourceRange.baseMipLevel = 0; - createInfo.subresourceRange.levelCount = 1; - createInfo.subresourceRange.baseArrayLayer = 0; - createInfo.subresourceRange.layerCount = 1; - if (vkCreateImageView(device->m_logicalDevice, &createInfo, nullptr, &m_swapChainImageViews[i]) != VK_SUCCESS) { - return KR_ERROR_VULKAN_SWAP_CHAIN; - } - } - - m_depthImageFormat = VK_FORMAT_UNDEFINED; - VkFormatFeatureFlags requiredFeatures = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT; - std::vector candidateFormats; - candidateFormats.push_back(VK_FORMAT_D32_SFLOAT_S8_UINT); - candidateFormats.push_back(VK_FORMAT_D24_UNORM_S8_UINT); - for (VkFormat format : candidateFormats) { - VkFormatProperties props; - vkGetPhysicalDeviceFormatProperties(device->m_device, format, &props); - - if ((props.optimalTilingFeatures & requiredFeatures) == requiredFeatures) { - m_depthImageFormat = format; - break; - } - } - - if (m_depthImageFormat == VK_FORMAT_UNDEFINED) { - return KR_ERROR_VULKAN_DEPTHBUFFER; - } - - /* - createImage(swapChainExtent.width, swapChainExtent.height, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, depthImage, depthImageMemory); - depthImageView = createImageView(depthImage, depthFormat); - */ - { - VkImageCreateInfo imageInfo{}; - imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - imageInfo.imageType = VK_IMAGE_TYPE_2D; - imageInfo.extent.width = m_swapChainExtent.width; - imageInfo.extent.height = m_swapChainExtent.height; - imageInfo.extent.depth = 1; - imageInfo.mipLevels = 1; - imageInfo.arrayLayers = 1; - imageInfo.format = m_depthImageFormat; - imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; - imageInfo.flags = 0; - - VmaAllocator allocator = device->getAllocator(); - VmaAllocationCreateInfo allocationCreateInfo{}; - allocationCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; - allocationCreateInfo.requiredFlags = VkMemoryPropertyFlags(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - - if (vmaCreateImage(allocator, &imageInfo, &allocationCreateInfo, &m_depthImage, &m_depthImageAllocation, nullptr) != VK_SUCCESS) { - return KR_ERROR_VULKAN_DEPTHBUFFER; - } - - VkImageViewCreateInfo viewInfo{}; - viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - viewInfo.image = m_depthImage; - viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - viewInfo.format = m_depthImageFormat; - viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - viewInfo.subresourceRange.baseMipLevel = 0; - viewInfo.subresourceRange.levelCount = 1; - viewInfo.subresourceRange.baseArrayLayer = 0; - viewInfo.subresourceRange.layerCount = 1; - - if (vkCreateImageView(device->m_logicalDevice, &viewInfo, nullptr, &m_depthImageView) != VK_SUCCESS) { - return KR_ERROR_VULKAN_DEPTHBUFFER; - } - - /* - TODO - Track memory usage - - VkMemoryRequirements memRequirements; - vkGetImageMemoryRequirements(device->m_logicalDevice, m_depthImage, &memRequirements); - */ - } - - createRenderPasses(); - - m_swapChainFramebuffers.resize(m_swapChainImageViews.size()); - - for (size_t i = 0; i < m_swapChainImageViews.size(); i++) { - std::array attachments = { - m_swapChainImageViews[i], - m_depthImageView - }; - - VkFramebufferCreateInfo framebufferInfo{}; - framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - framebufferInfo.renderPass = m_forwardOpaquePass->m_renderPass; - framebufferInfo.attachmentCount = static_cast(attachments.size()); - framebufferInfo.pAttachments = attachments.data(); - framebufferInfo.width = m_swapChainExtent.width; - framebufferInfo.height = m_swapChainExtent.height; - framebufferInfo.layers = 1; - - if (vkCreateFramebuffer(device->m_logicalDevice, &framebufferInfo, nullptr, &m_swapChainFramebuffers[i]) != VK_SUCCESS) { - return KR_ERROR_VULKAN_FRAMEBUFFER; - } - } + m_forwardOpaquePass->create(*device, selectedSurfaceFormat.format, depthImageFormat); + m_swapChain->create(*device, m_surface, selectedSurfaceFormat, depthImageFormat, swapExtent, imageCount, *m_forwardOpaquePass); return KR_SUCCESS; } @@ -347,33 +161,9 @@ void KRSurface::destroySwapChain() std::unique_ptr& device = m_pContext->getDeviceManager()->getDevice(m_deviceHandle); // TODO - Handle device removal if (device) { - for (auto framebuffer : m_swapChainFramebuffers) { - vkDestroyFramebuffer(device->m_logicalDevice, framebuffer, nullptr); - } - - for (auto imageView : m_swapChainImageViews) { - vkDestroyImageView(device->m_logicalDevice, imageView, nullptr); - } - - if (m_swapChain != VK_NULL_HANDLE) { - vkDestroySwapchainKHR(device->m_logicalDevice, m_swapChain, nullptr); - m_swapChain = VK_NULL_HANDLE; - } + m_swapChain->destroy(*device); } - if (m_depthImageView) { - vkDestroyImageView(device->m_logicalDevice, m_depthImageView, nullptr); - m_depthImageView = VK_NULL_HANDLE; - } - - if (m_depthImage) { - vmaDestroyImage(device->getAllocator(), m_depthImage, m_depthImageAllocation); - m_depthImage = VK_NULL_HANDLE; - m_depthImageAllocation = VK_NULL_HANDLE; - } - - m_swapChainFramebuffers.clear(); - m_swapChainImageViews.clear(); } KrResult KRSurface::recreateSwapChain() @@ -386,12 +176,6 @@ KrResult KRSurface::recreateSwapChain() return result; } -void KRSurface::createRenderPasses() -{ - std::unique_ptr& device = m_pContext->getDeviceManager()->getDevice(m_deviceHandle); - m_forwardOpaquePass->create(*device, m_swapChainImageFormat, m_depthImageFormat); -} - std::unique_ptr& KRSurface::getDevice() { return m_pContext->getDeviceManager()->getDevice(m_deviceHandle); @@ -399,17 +183,17 @@ std::unique_ptr& KRSurface::getDevice() uint32_t KRSurface::getWidth() const { - return m_swapChainExtent.width; + return m_swapChain->m_extent.width; } uint32_t KRSurface::getHeight() const { - return m_swapChainExtent.height; + return m_swapChain->m_extent.height; } VkFormat KRSurface::getDepthFormat() const { - return m_depthImageFormat; + return m_swapChain->m_depthFormat; } diff --git a/kraken/KRSurface.h b/kraken/KRSurface.h index 9ad098f..41bcec1 100644 --- a/kraken/KRSurface.h +++ b/kraken/KRSurface.h @@ -37,6 +37,7 @@ class KRDevice; class KRRenderPass; +class KRSwapchain; class KRSurface : public KRContextObject { @@ -58,7 +59,6 @@ public: KrResult initialize(); KrResult recreateSwapChain(); - void createRenderPasses(); KRRenderPass& getForwardOpaquePass(); void endFrame(); @@ -68,19 +68,11 @@ public: #endif KrDeviceHandle m_deviceHandle; VkSurfaceKHR m_surface; - VkSwapchainKHR m_swapChain; - std::vector m_swapChainImages; - VkFormat m_swapChainImageFormat; - VkExtent2D m_swapChainExtent; - std::vector m_swapChainImageViews; - std::vector m_swapChainFramebuffers; - VkFormat m_depthImageFormat; - VkImage m_depthImage; - VmaAllocation m_depthImageAllocation; - VkImageView m_depthImageView; + VkSemaphore m_imageAvailableSemaphore; VkSemaphore m_renderFinishedSemaphore; + std::unique_ptr m_swapChain; std::unique_ptr m_forwardOpaquePass; // TODO - This needs to be advanced per swap chain diff --git a/kraken/KRSwapchain.cpp b/kraken/KRSwapchain.cpp new file mode 100644 index 0000000..609a4ad --- /dev/null +++ b/kraken/KRSwapchain.cpp @@ -0,0 +1,232 @@ +// +// KRSwapchain.cpp +// Kraken Engine +// +// Copyright 2021 Kearwood Gilbert. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other materials +// provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// The views and conclusions contained in the software and documentation are those of the +// authors and should not be interpreted as representing official policies, either expressed +// or implied, of Kearwood Gilbert. +// + +#include "KRSwapchain.h" +#include "KRRenderPass.h" + +KRSwapchain::KRSwapchain(KRContext& context) + : KRContextObject(context) + , m_swapChain(VK_NULL_HANDLE) + , m_extent({ 0, 0 }) + , m_imageFormat(VK_FORMAT_UNDEFINED) + , m_depthFormat(VK_FORMAT_UNDEFINED) + , m_depthImage(VK_NULL_HANDLE) + , m_depthImageAllocation(VK_NULL_HANDLE) + , m_depthImageView(VK_NULL_HANDLE) +{ + +} + +KRSwapchain::~KRSwapchain() +{ + assert(m_swapChain == VK_NULL_HANDLE); +} + +KrResult KRSwapchain::create(KRDevice& device, VkSurfaceKHR& surface, VkSurfaceFormatKHR& surfaceFormat, VkFormat depthFormat, VkExtent2D& extent, uint32_t imageCount, const KRRenderPass& renderPass) +{ + KrResult res = KR_SUCCESS; + + m_extent = extent; + VkSurfaceCapabilitiesKHR surfaceCapabilities{}; + if (vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device.m_device, surface, &surfaceCapabilities) != VK_SUCCESS) { + return KR_ERROR_VULKAN_SWAP_CHAIN; + } + + VkPresentModeKHR selectedPresentMode; + res = device.selectPresentMode(surface, selectedPresentMode); + if (res != KR_SUCCESS) return res; + + m_imageFormat = surfaceFormat.format; + m_depthFormat = depthFormat; + + VkSwapchainCreateInfoKHR swapChainCreateInfo{}; + swapChainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + swapChainCreateInfo.surface = surface; + swapChainCreateInfo.minImageCount = imageCount; + swapChainCreateInfo.imageFormat = surfaceFormat.format; + swapChainCreateInfo.imageColorSpace = surfaceFormat.colorSpace; + swapChainCreateInfo.imageExtent = extent; + swapChainCreateInfo.imageArrayLayers = 1; + swapChainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + + uint32_t queueFamilyIndices[] = { + device.m_graphicsFamilyQueueIndex, + device.m_computeFamilyQueueIndex + }; + if (device.m_graphicsFamilyQueueIndex == device.m_computeFamilyQueueIndex) { + swapChainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + swapChainCreateInfo.queueFamilyIndexCount = 0; + swapChainCreateInfo.pQueueFamilyIndices = nullptr; + } + else { + swapChainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + swapChainCreateInfo.queueFamilyIndexCount = 2; + swapChainCreateInfo.pQueueFamilyIndices = queueFamilyIndices; + } + + swapChainCreateInfo.preTransform = surfaceCapabilities.currentTransform; + swapChainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + swapChainCreateInfo.presentMode = selectedPresentMode; + swapChainCreateInfo.clipped = VK_TRUE; + swapChainCreateInfo.oldSwapchain = VK_NULL_HANDLE; + + if (vkCreateSwapchainKHR(device.m_logicalDevice, &swapChainCreateInfo, nullptr, &m_swapChain) != VK_SUCCESS) { + return KR_ERROR_VULKAN_SWAP_CHAIN; + } + + vkGetSwapchainImagesKHR(device.m_logicalDevice, m_swapChain, &imageCount, nullptr); + m_images.resize(imageCount); + vkGetSwapchainImagesKHR(device.m_logicalDevice, m_swapChain, &imageCount, m_images.data()); + + m_imageViews.resize(m_images.size()); + for (size_t i = 0; i < m_images.size(); i++) { + VkImageViewCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + createInfo.image = m_images[i]; + createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + createInfo.format = m_imageFormat; + createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + createInfo.subresourceRange.baseMipLevel = 0; + createInfo.subresourceRange.levelCount = 1; + createInfo.subresourceRange.baseArrayLayer = 0; + createInfo.subresourceRange.layerCount = 1; + if (vkCreateImageView(device.m_logicalDevice, &createInfo, nullptr, &m_imageViews[i]) != VK_SUCCESS) { + return KR_ERROR_VULKAN_SWAP_CHAIN; + } + } + + + { + VkImageCreateInfo imageInfo{}; + imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageInfo.imageType = VK_IMAGE_TYPE_2D; + imageInfo.extent.width = m_extent.width; + imageInfo.extent.height = m_extent.height; + imageInfo.extent.depth = 1; + imageInfo.mipLevels = 1; + imageInfo.arrayLayers = 1; + imageInfo.format = depthFormat; + imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageInfo.flags = 0; + + VmaAllocator allocator = device.getAllocator(); + VmaAllocationCreateInfo allocationCreateInfo{}; + allocationCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; + allocationCreateInfo.requiredFlags = VkMemoryPropertyFlags(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + if (vmaCreateImage(allocator, &imageInfo, &allocationCreateInfo, &m_depthImage, &m_depthImageAllocation, nullptr) != VK_SUCCESS) { + return KR_ERROR_VULKAN_DEPTHBUFFER; + } + + VkImageViewCreateInfo viewInfo{}; + viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewInfo.image = m_depthImage; + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.format = depthFormat; + viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + viewInfo.subresourceRange.baseMipLevel = 0; + viewInfo.subresourceRange.levelCount = 1; + viewInfo.subresourceRange.baseArrayLayer = 0; + viewInfo.subresourceRange.layerCount = 1; + + if (vkCreateImageView(device.m_logicalDevice, &viewInfo, nullptr, &m_depthImageView) != VK_SUCCESS) { + return KR_ERROR_VULKAN_DEPTHBUFFER; + } + + /* + TODO - Track memory usage + + VkMemoryRequirements memRequirements; + vkGetImageMemoryRequirements(device->m_logicalDevice, m_depthImage, &memRequirements); + */ + } + + m_framebuffers.resize(m_imageViews.size()); + + for (size_t i = 0; i < m_imageViews.size(); i++) { + std::array attachments = { + m_imageViews[i], + m_depthImageView + }; + + VkFramebufferCreateInfo framebufferInfo{}; + framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebufferInfo.renderPass = renderPass.m_renderPass; + framebufferInfo.attachmentCount = static_cast(attachments.size()); + framebufferInfo.pAttachments = attachments.data(); + framebufferInfo.width = m_extent.width; + framebufferInfo.height = m_extent.height; + framebufferInfo.layers = 1; + + if (vkCreateFramebuffer(device.m_logicalDevice, &framebufferInfo, nullptr, &m_framebuffers[i]) != VK_SUCCESS) { + return KR_ERROR_VULKAN_FRAMEBUFFER; + } + } + return KR_SUCCESS; +} + +void KRSwapchain::destroy(KRDevice& device) +{ + for (auto framebuffer : m_framebuffers) { + vkDestroyFramebuffer(device.m_logicalDevice, framebuffer, nullptr); + } + + for (auto imageView : m_imageViews) { + vkDestroyImageView(device.m_logicalDevice, imageView, nullptr); + } + + if (m_swapChain != VK_NULL_HANDLE) { + vkDestroySwapchainKHR(device.m_logicalDevice, m_swapChain, nullptr); + m_swapChain = VK_NULL_HANDLE; + } + + if (m_depthImageView) { + vkDestroyImageView(device.m_logicalDevice, m_depthImageView, nullptr); + m_depthImageView = VK_NULL_HANDLE; + } + + if (m_depthImage) { + vmaDestroyImage(device.getAllocator(), m_depthImage, m_depthImageAllocation); + m_depthImage = VK_NULL_HANDLE; + m_depthImageAllocation = VK_NULL_HANDLE; + } + + m_framebuffers.clear(); + m_imageViews.clear(); +} diff --git a/kraken/KRSwapchain.h b/kraken/KRSwapchain.h new file mode 100644 index 0000000..d9039aa --- /dev/null +++ b/kraken/KRSwapchain.h @@ -0,0 +1,66 @@ +// +// KRSwapchain.h +// Kraken Engine +// +// Copyright 2021 Kearwood Gilbert. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other materials +// provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// The views and conclusions contained in the software and documentation are those of the +// authors and should not be interpreted as representing official policies, either expressed +// or implied, of Kearwood Gilbert. +// + + + +#ifndef KRSWAPCHAIN_H +#define KRSWAPCHAIN_H + +#include "KREngine-common.h" +#include "KRContext.h" + +class KRRenderPass; + +class KRSwapchain : public KRContextObject +{ +public: + KRSwapchain(KRContext& context); + ~KRSwapchain(); + + KrResult create(KRDevice& device, VkSurfaceKHR& surface, VkSurfaceFormatKHR& surfaceFormat, VkFormat depthFormat, VkExtent2D& extent, uint32_t imageCount, const KRRenderPass& renderPass); + void destroy(KRDevice& device); + + VkSwapchainKHR m_swapChain; + VkExtent2D m_extent; + VkFormat m_imageFormat; + VkFormat m_depthFormat; + + VkImage m_depthImage; + VmaAllocation m_depthImageAllocation; + VkImageView m_depthImageView; + + std::vector m_images; + std::vector m_imageViews; + std::vector m_framebuffers; + +}; + +#endif KRSWAPCHAIN_H