2023-03-12 16:14:55 +00:00
|
|
|
#include <stdexcept>
|
|
|
|
#include <vector>
|
2023-03-13 20:35:15 +00:00
|
|
|
#include <array>
|
2023-03-12 16:14:55 +00:00
|
|
|
#include <algorithm>
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#include <SDL2/SDL_vulkan.h>
|
|
|
|
|
2023-05-01 13:13:35 +00:00
|
|
|
#include "log.h"
|
2023-03-13 17:10:46 +00:00
|
|
|
|
2023-03-12 16:14:55 +00:00
|
|
|
#include "swapchain.h"
|
2023-09-12 18:03:23 +00:00
|
|
|
#include <SDL_syswm.h>
|
2023-03-12 16:14:55 +00:00
|
|
|
|
|
|
|
namespace engine {
|
|
|
|
|
|
|
|
void createSwapchain(Swapchain* sc, const SwapchainInfo& info)
|
|
|
|
{
|
2023-08-22 22:41:08 +00:00
|
|
|
assert(sc != nullptr);
|
2023-03-12 16:14:55 +00:00
|
|
|
sc->device = info.device;
|
2023-03-13 20:27:47 +00:00
|
|
|
sc->allocator = info.allocator;
|
2023-03-12 16:14:55 +00:00
|
|
|
|
2023-03-13 17:10:46 +00:00
|
|
|
LOG_INFO("Recreating swapchain!\n");
|
2023-03-12 16:14:55 +00:00
|
|
|
|
|
|
|
// get surface caps and features
|
|
|
|
VkResult res;
|
|
|
|
res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(info.physicalDevice, info.surface, &sc->surfaceCapabilities);
|
|
|
|
if (res != VK_SUCCESS) throw std::runtime_error("Unable to get surface capabilities!");
|
|
|
|
|
|
|
|
// check there is at least one supported surface format
|
|
|
|
uint32_t surfaceFormatCount = 0;
|
|
|
|
std::vector<VkSurfaceFormatKHR> formats{};
|
|
|
|
res = vkGetPhysicalDeviceSurfaceFormatsKHR(info.physicalDevice, info.surface, &surfaceFormatCount, nullptr);
|
|
|
|
assert(res == VK_SUCCESS);
|
|
|
|
formats.resize(surfaceFormatCount);
|
|
|
|
res = vkGetPhysicalDeviceSurfaceFormatsKHR(info.physicalDevice, info.surface, &surfaceFormatCount, formats.data());
|
|
|
|
assert(res == VK_SUCCESS);
|
|
|
|
|
|
|
|
sc->surfaceFormat = formats[0];
|
|
|
|
for (const auto& format : formats) {
|
|
|
|
if (format.format == VK_FORMAT_B8G8R8A8_SRGB &&
|
|
|
|
format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
|
|
|
|
sc->surfaceFormat = format; // prefer using srgb non linear colors
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// check there is at least one supported present mode
|
|
|
|
uint32_t surfacePresentModeCount = 0;
|
|
|
|
std::vector<VkPresentModeKHR> presentModes{};
|
|
|
|
res = vkGetPhysicalDeviceSurfacePresentModesKHR(info.physicalDevice, info.surface, &surfacePresentModeCount, nullptr);
|
|
|
|
assert(res == VK_SUCCESS);
|
|
|
|
presentModes.resize(surfacePresentModeCount);
|
|
|
|
res = vkGetPhysicalDeviceSurfacePresentModesKHR(info.physicalDevice, info.surface, &surfacePresentModeCount, presentModes.data());
|
|
|
|
assert(res == VK_SUCCESS);
|
|
|
|
|
|
|
|
sc->presentMode = VK_PRESENT_MODE_FIFO_KHR; // This mode is always available
|
|
|
|
if (info.vsync == true) {
|
|
|
|
if (info.waitForPresent == false) {
|
|
|
|
for (const auto& presMode : presentModes) {
|
|
|
|
if (presMode == VK_PRESENT_MODE_MAILBOX_KHR) {
|
|
|
|
sc->presentMode = presMode; // this mode allows V-sync without fixing FPS to refresh rate
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
for (const auto& presMode : presentModes) {
|
|
|
|
if (presMode == VK_PRESENT_MODE_IMMEDIATE_KHR) {
|
|
|
|
sc->presentMode = presMode; // V-sync off
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get min image count */
|
|
|
|
uint32_t minImageCount = sc->surfaceCapabilities.minImageCount + 1;
|
|
|
|
if (sc->surfaceCapabilities.maxImageCount > 0 && minImageCount > sc->surfaceCapabilities.maxImageCount) {
|
|
|
|
minImageCount = sc->surfaceCapabilities.maxImageCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get extent */
|
|
|
|
VkExtent2D oldExtent = sc->extent;
|
|
|
|
if (sc->surfaceCapabilities.currentExtent.width != std::numeric_limits<uint32_t>::max()) {
|
|
|
|
sc->extent = sc->surfaceCapabilities.currentExtent;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// if fb size isn't already found, get it from SDL
|
|
|
|
int width, height;
|
|
|
|
SDL_Vulkan_GetDrawableSize(info.window, &width, &height);
|
|
|
|
|
|
|
|
sc->extent.width = static_cast<uint32_t>(width);
|
|
|
|
sc->extent.height = static_cast<uint32_t>(height);
|
|
|
|
|
|
|
|
sc->extent.width = std::clamp(
|
|
|
|
sc->extent.width,
|
|
|
|
sc->surfaceCapabilities.minImageExtent.width, sc->surfaceCapabilities.maxImageExtent.width);
|
|
|
|
sc->extent.height = std::clamp(
|
|
|
|
sc->extent.height,
|
|
|
|
sc->surfaceCapabilities.minImageExtent.height, sc->surfaceCapabilities.maxImageExtent.height);
|
|
|
|
}
|
|
|
|
if (sc->extent.width == 0 || sc->extent.height == 0) { // preserve extent if the window is minimised
|
|
|
|
sc->extent = oldExtent;
|
|
|
|
}
|
|
|
|
|
2023-03-21 14:18:59 +00:00
|
|
|
/* find depth stencil format to use */
|
|
|
|
VkFormatProperties2 formatProperties{};
|
|
|
|
formatProperties.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
|
|
|
|
vkGetPhysicalDeviceFormatProperties2(info.physicalDevice, VK_FORMAT_D24_UNORM_S8_UINT, &formatProperties);
|
|
|
|
if (formatProperties.formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
|
|
|
|
sc->depthStencilFormat = VK_FORMAT_D24_UNORM_S8_UINT;
|
|
|
|
} else {
|
|
|
|
vkGetPhysicalDeviceFormatProperties2(info.physicalDevice, VK_FORMAT_D16_UNORM, &formatProperties);
|
|
|
|
if (formatProperties.formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
|
|
|
|
sc->depthStencilFormat = VK_FORMAT_D16_UNORM;
|
|
|
|
} else {
|
|
|
|
throw std::runtime_error("Failed to find suitable depth-buffer image format!");
|
|
|
|
}
|
|
|
|
}
|
2023-03-12 16:14:55 +00:00
|
|
|
|
|
|
|
/* create swapchain */
|
|
|
|
|
2023-09-12 18:03:23 +00:00
|
|
|
VkSurfaceFullScreenExclusiveInfoEXT fullscreenInfo{};
|
|
|
|
fullscreenInfo.sType = VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT;
|
|
|
|
fullscreenInfo.pNext = nullptr;
|
|
|
|
fullscreenInfo.fullScreenExclusive = VK_FULL_SCREEN_EXCLUSIVE_ALLOWED_EXT;
|
|
|
|
|
2023-03-12 16:14:55 +00:00
|
|
|
VkSwapchainCreateInfoKHR scInfo{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
|
2023-09-12 18:03:23 +00:00
|
|
|
.pNext = &fullscreenInfo,
|
2023-03-12 16:14:55 +00:00
|
|
|
.flags = 0,
|
|
|
|
.surface = info.surface,
|
|
|
|
.minImageCount = minImageCount,
|
|
|
|
.imageFormat = sc->surfaceFormat.format,
|
|
|
|
.imageColorSpace = sc->surfaceFormat.colorSpace,
|
|
|
|
.imageExtent = sc->extent,
|
|
|
|
.imageArrayLayers = 1,
|
|
|
|
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
|
|
|
|
.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
|
|
.queueFamilyIndexCount = 0, // ignored
|
|
|
|
.pQueueFamilyIndices = nullptr, // ignored
|
|
|
|
.preTransform = sc->surfaceCapabilities.currentTransform,
|
|
|
|
.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
|
|
|
|
.presentMode = sc->presentMode,
|
|
|
|
.clipped = VK_TRUE, // discard parts of the screen not visible
|
|
|
|
.oldSwapchain = sc->swapchain
|
|
|
|
};
|
|
|
|
|
|
|
|
res = vkCreateSwapchainKHR(sc->device, &scInfo, nullptr, &sc->swapchain);
|
|
|
|
if (res != VK_SUCCESS) throw std::runtime_error("Failed to create swapchain!");
|
|
|
|
|
|
|
|
/* if it existed, destroy the old swapchain */
|
|
|
|
if (scInfo.oldSwapchain != VK_NULL_HANDLE) {
|
|
|
|
vkDestroySwapchainKHR(info.device, scInfo.oldSwapchain, nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* create the render pass */
|
|
|
|
if (sc->renderpass != VK_NULL_HANDLE) {
|
|
|
|
vkDestroyRenderPass(sc->device, sc->renderpass, nullptr);
|
|
|
|
}
|
|
|
|
VkAttachmentDescription colorAttachment{
|
|
|
|
.flags = 0,
|
|
|
|
.format = sc->surfaceFormat.format,
|
|
|
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
|
|
|
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
|
|
|
|
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
|
|
|
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, // ignored
|
|
|
|
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, // ignored
|
|
|
|
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
|
|
|
.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
|
|
|
|
};
|
2023-03-13 20:27:47 +00:00
|
|
|
VkAttachmentDescription depthStencilAttachment{
|
|
|
|
.flags = 0,
|
2023-03-15 01:49:03 +00:00
|
|
|
.format = sc->depthStencilFormat,
|
2023-03-13 20:27:47 +00:00
|
|
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
|
|
|
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
|
|
|
|
.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, // the depth buffer is not used after the fragment shader
|
|
|
|
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, // ignored
|
|
|
|
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, // ignored
|
|
|
|
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
|
|
|
.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
|
|
|
|
};
|
|
|
|
std::array<VkAttachmentDescription, 2> attachments { colorAttachment, depthStencilAttachment };
|
2023-03-12 16:14:55 +00:00
|
|
|
VkAttachmentReference colorAttachmentRef{
|
|
|
|
.attachment = 0,
|
|
|
|
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
|
|
|
|
};
|
2023-03-13 20:27:47 +00:00
|
|
|
VkAttachmentReference depthStencilAttachmentRef{
|
|
|
|
.attachment = 1,
|
|
|
|
.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
|
|
|
|
};
|
2023-03-12 16:14:55 +00:00
|
|
|
VkSubpassDescription subpass{
|
|
|
|
.flags = 0,
|
|
|
|
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
|
|
.inputAttachmentCount = 0,
|
|
|
|
.pInputAttachments = nullptr,
|
|
|
|
.colorAttachmentCount = 1,
|
|
|
|
.pColorAttachments = &colorAttachmentRef,
|
|
|
|
.pResolveAttachments = nullptr,
|
2023-03-13 20:27:47 +00:00
|
|
|
.pDepthStencilAttachment = &depthStencilAttachmentRef,
|
2023-03-12 16:14:55 +00:00
|
|
|
.preserveAttachmentCount = 0,
|
|
|
|
.pPreserveAttachments = nullptr,
|
|
|
|
};
|
2023-03-15 01:49:03 +00:00
|
|
|
VkSubpassDependency attachmentDependencies[2] = {
|
|
|
|
{
|
|
|
|
// Depth buffer
|
|
|
|
.srcSubpass = VK_SUBPASS_EXTERNAL,
|
|
|
|
.dstSubpass = 0,
|
2023-03-21 11:03:20 +00:00
|
|
|
.srcStageMask = VK_PIPELINE_STAGE_NONE,
|
2023-03-15 01:49:03 +00:00
|
|
|
.dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
2023-03-21 11:03:20 +00:00
|
|
|
.srcAccessMask = 0,
|
2023-03-15 01:49:03 +00:00
|
|
|
.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
|
|
|
.dependencyFlags = 0,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// Image Layout Transition
|
|
|
|
.srcSubpass = VK_SUBPASS_EXTERNAL,
|
|
|
|
.dstSubpass = 0,
|
2023-03-21 11:03:20 +00:00
|
|
|
.srcStageMask = VK_PIPELINE_STAGE_NONE,
|
2023-03-15 01:49:03 +00:00
|
|
|
.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
|
|
.srcAccessMask = 0,
|
|
|
|
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT,
|
|
|
|
.dependencyFlags = 0,
|
|
|
|
},
|
2023-03-12 16:14:55 +00:00
|
|
|
};
|
|
|
|
VkRenderPassCreateInfo renderPassInfo{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
|
|
|
.pNext = nullptr,
|
|
|
|
.flags = 0,
|
2023-03-15 01:49:03 +00:00
|
|
|
.attachmentCount = (uint32_t)attachments.size(),
|
2023-03-13 20:27:47 +00:00
|
|
|
.pAttachments = attachments.data(),
|
2023-03-12 16:14:55 +00:00
|
|
|
.subpassCount = 1,
|
|
|
|
.pSubpasses = &subpass,
|
2023-03-15 01:49:03 +00:00
|
|
|
.dependencyCount = 2,
|
|
|
|
.pDependencies = attachmentDependencies,
|
2023-03-12 16:14:55 +00:00
|
|
|
};
|
|
|
|
res = vkCreateRenderPass(sc->device, &renderPassInfo, nullptr, &sc->renderpass);
|
|
|
|
if (res != EXIT_SUCCESS) throw std::runtime_error("Failed to create renderpass!");
|
|
|
|
|
|
|
|
// get all the image handles
|
|
|
|
uint32_t swapchainImageCount = 0;
|
|
|
|
res = vkGetSwapchainImagesKHR(info.device, sc->swapchain, &swapchainImageCount, nullptr);
|
|
|
|
assert(res == VK_SUCCESS);
|
|
|
|
std::vector<VkImage> swapchainImages(swapchainImageCount);
|
|
|
|
res = vkGetSwapchainImagesKHR(info.device, sc->swapchain, &swapchainImageCount, swapchainImages.data());
|
|
|
|
assert(res == VK_SUCCESS);
|
|
|
|
|
|
|
|
/* create image view and framebuffer for each image */
|
2023-03-15 01:49:03 +00:00
|
|
|
if (sc->swapchainImages.size() == 0) {
|
|
|
|
sc->swapchainImages.resize(swapchainImageCount);
|
|
|
|
sc->depthImages.resize(swapchainImageCount);
|
|
|
|
sc->framebuffers.resize(swapchainImageCount);
|
|
|
|
}
|
2023-03-12 16:14:55 +00:00
|
|
|
for (uint32_t i = 0; i < swapchainImageCount; i++) {
|
2023-03-15 01:49:03 +00:00
|
|
|
auto& [swapchainImage, swapchainImageView] = sc->swapchainImages.at(i);
|
|
|
|
auto& [depthImage, depthAllocation, depthImageView] = sc->depthImages.at(i);
|
|
|
|
auto& framebuffer = sc->framebuffers.at(i);
|
|
|
|
|
|
|
|
if (swapchainImageView != VK_NULL_HANDLE) vkDestroyImageView(sc->device, swapchainImageView, nullptr);
|
|
|
|
if (depthImageView != VK_NULL_HANDLE) {
|
|
|
|
vkDestroyImageView(sc->device, depthImageView, nullptr);
|
|
|
|
vmaDestroyImage(sc->allocator, depthImage, depthAllocation);
|
|
|
|
}
|
2023-03-12 16:14:55 +00:00
|
|
|
if (framebuffer != VK_NULL_HANDLE) vkDestroyFramebuffer(sc->device, framebuffer, nullptr);
|
|
|
|
|
2023-03-15 01:49:03 +00:00
|
|
|
swapchainImage = swapchainImages[i];
|
2023-03-12 16:14:55 +00:00
|
|
|
|
|
|
|
/* make the image view */
|
|
|
|
VkImageViewCreateInfo viewInfo{};
|
|
|
|
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
|
|
|
viewInfo.pNext = nullptr;
|
|
|
|
viewInfo.flags = 0;
|
2023-03-15 01:49:03 +00:00
|
|
|
viewInfo.image = swapchainImage;
|
2023-03-12 16:14:55 +00:00
|
|
|
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
|
|
viewInfo.format = sc->surfaceFormat.format;
|
|
|
|
viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
|
|
viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
|
|
viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
|
|
viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
|
|
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
|
|
viewInfo.subresourceRange.baseMipLevel = 0;
|
|
|
|
viewInfo.subresourceRange.levelCount = 1;
|
|
|
|
viewInfo.subresourceRange.baseArrayLayer = 0;
|
|
|
|
viewInfo.subresourceRange.layerCount = 1;
|
2023-03-15 01:49:03 +00:00
|
|
|
VkResult res = vkCreateImageView(sc->device, &viewInfo, nullptr, &swapchainImageView);
|
2023-03-12 16:14:55 +00:00
|
|
|
if (res != VK_SUCCESS) throw std::runtime_error("Failed to create image view from swapchain image!");
|
|
|
|
|
2023-03-15 01:49:03 +00:00
|
|
|
/* create the depth buffer */
|
|
|
|
|
|
|
|
VkImageCreateInfo depthImageInfo{};
|
|
|
|
depthImageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
|
|
|
depthImageInfo.pNext = nullptr;
|
|
|
|
depthImageInfo.flags = 0;
|
|
|
|
depthImageInfo.imageType = VK_IMAGE_TYPE_2D;
|
|
|
|
depthImageInfo.format = sc->depthStencilFormat;
|
|
|
|
depthImageInfo.extent.width = sc->extent.width;
|
|
|
|
depthImageInfo.extent.height = sc->extent.height;
|
|
|
|
depthImageInfo.extent.depth = 1;
|
|
|
|
depthImageInfo.mipLevels = 1;
|
|
|
|
depthImageInfo.arrayLayers = 1;
|
|
|
|
depthImageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
|
|
depthImageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
|
|
|
depthImageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
|
|
|
depthImageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
|
|
depthImageInfo.queueFamilyIndexCount = 0; // ignored
|
|
|
|
depthImageInfo.pQueueFamilyIndices = nullptr; // ignored
|
|
|
|
depthImageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
|
|
|
|
|
|
VmaAllocationCreateInfo depthAllocInfo{};
|
|
|
|
depthAllocInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
|
2023-03-21 15:21:24 +00:00
|
|
|
depthAllocInfo.priority = 1.0f; // this is ignored if VK_EXT_memory_priority isn't found
|
|
|
|
|
2023-03-21 16:46:58 +00:00
|
|
|
// "Consider creating them as dedicated allocations using VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT,
|
|
|
|
// especially if they are large or if you plan to destroy and recreate them with different sizes
|
|
|
|
// e.g. when display resolution changes."
|
|
|
|
// https://gpuopen-librariesandsdks.github.io/VulkanMemoryAllocator/html/usage_patterns.html
|
|
|
|
depthAllocInfo.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
|
2023-03-15 01:49:03 +00:00
|
|
|
|
|
|
|
res = vmaCreateImage(sc->allocator, &depthImageInfo, &depthAllocInfo, &depthImage, &depthAllocation, nullptr);
|
|
|
|
if (res != VK_SUCCESS) throw std::runtime_error("Failed to create depth buffer image! Code: " + std::to_string(res));
|
|
|
|
|
|
|
|
VkImageViewCreateInfo depthViewInfo{};
|
|
|
|
depthViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
|
|
|
depthViewInfo.pNext = nullptr;
|
|
|
|
depthViewInfo.flags = 0;
|
|
|
|
depthViewInfo.image = depthImage;
|
|
|
|
depthViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
|
|
depthViewInfo.format = sc->depthStencilFormat;
|
|
|
|
depthViewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
|
|
depthViewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
|
|
depthViewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
|
|
depthViewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
|
|
depthViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
|
|
|
depthViewInfo.subresourceRange.baseMipLevel = 0;
|
|
|
|
depthViewInfo.subresourceRange.levelCount = 1;
|
|
|
|
depthViewInfo.subresourceRange.baseArrayLayer = 0;
|
|
|
|
depthViewInfo.subresourceRange.layerCount = 1;
|
|
|
|
res = vkCreateImageView(info.device, &depthViewInfo, nullptr, &depthImageView);
|
|
|
|
assert(res == VK_SUCCESS);
|
|
|
|
|
2023-03-13 20:27:47 +00:00
|
|
|
std::array<VkImageView, 2> attachments {
|
2023-03-15 01:49:03 +00:00
|
|
|
swapchainImageView, depthImageView
|
2023-03-13 20:27:47 +00:00
|
|
|
};
|
|
|
|
|
2023-03-12 16:14:55 +00:00
|
|
|
VkFramebufferCreateInfo fbInfo{};
|
|
|
|
fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
|
|
|
fbInfo.pNext = nullptr;
|
|
|
|
fbInfo.flags = 0;
|
|
|
|
fbInfo.renderPass = sc->renderpass;
|
2023-03-15 01:49:03 +00:00
|
|
|
fbInfo.attachmentCount = (uint32_t)attachments.size();
|
2023-03-13 20:27:47 +00:00
|
|
|
fbInfo.pAttachments = attachments.data();
|
2023-03-12 16:14:55 +00:00
|
|
|
fbInfo.width = sc->extent.width;
|
|
|
|
fbInfo.height = sc->extent.height;
|
|
|
|
fbInfo.layers = 1;
|
|
|
|
|
|
|
|
res = vkCreateFramebuffer(sc->device, &fbInfo, nullptr, &framebuffer);
|
|
|
|
if (res != VK_SUCCESS) throw std::runtime_error("Failed to create framebuffer for swapchain image!");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void destroySwapchain(const Swapchain& sc)
|
|
|
|
{
|
2023-03-15 01:49:03 +00:00
|
|
|
for (VkFramebuffer framebuffer : sc.framebuffers) {
|
2023-03-12 16:14:55 +00:00
|
|
|
vkDestroyFramebuffer(sc.device, framebuffer, nullptr);
|
2023-03-15 01:49:03 +00:00
|
|
|
}
|
|
|
|
for (const auto& [image, view] : sc.swapchainImages) {
|
|
|
|
vkDestroyImageView(sc.device, view, nullptr);
|
|
|
|
}
|
|
|
|
for (const auto& [image, allocation, view] : sc.depthImages) {
|
2023-03-12 16:14:55 +00:00
|
|
|
vkDestroyImageView(sc.device, view, nullptr);
|
2023-03-15 01:49:03 +00:00
|
|
|
vmaDestroyImage(sc.allocator, image, allocation);
|
2023-03-12 16:14:55 +00:00
|
|
|
}
|
2023-03-15 01:49:03 +00:00
|
|
|
|
2023-03-12 16:14:55 +00:00
|
|
|
vkDestroyRenderPass(sc.device, sc.renderpass, nullptr);
|
|
|
|
vkDestroySwapchainKHR(sc.device, sc.swapchain, nullptr);
|
|
|
|
}
|
|
|
|
|
2023-03-13 20:27:47 +00:00
|
|
|
}
|