mirror of
https://github.com/bailwillharr/engine.git
synced 2024-09-21 04:51:18 +00:00
Add swapchain
This commit is contained in:
parent
fecf1cccc5
commit
4d57244151
@ -4,9 +4,7 @@
|
|||||||
#ifdef ENGINE_BUILD_VULKAN
|
#ifdef ENGINE_BUILD_VULKAN
|
||||||
|
|
||||||
#include "gfx_device.hpp"
|
#include "gfx_device.hpp"
|
||||||
|
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "log.hpp"
|
#include "log.hpp"
|
||||||
|
|
||||||
@ -27,9 +25,6 @@
|
|||||||
|
|
||||||
namespace engine {
|
namespace engine {
|
||||||
|
|
||||||
// singleton variable
|
|
||||||
static GFXDevice* s_gfx_device_instance = nullptr;
|
|
||||||
|
|
||||||
// structures
|
// structures
|
||||||
|
|
||||||
struct LayerInfo {
|
struct LayerInfo {
|
||||||
@ -57,10 +52,18 @@ namespace engine {
|
|||||||
VkSwapchainKHR swapchain = VK_NULL_HANDLE;
|
VkSwapchainKHR swapchain = VK_NULL_HANDLE;
|
||||||
|
|
||||||
VkExtent2D extent;
|
VkExtent2D extent;
|
||||||
VkFormat format;
|
VkSurfaceFormatKHR surfaceFormat;
|
||||||
|
VkPresentModeKHR presentMode;
|
||||||
|
|
||||||
std::vector<VkImage> images{};
|
std::vector<VkImage> images{};
|
||||||
std::vector<VkImageView> imageViews{};
|
std::vector<VkImageView> imageViews{};
|
||||||
|
std::vector<VkFramebuffer> framebuffers{};
|
||||||
|
|
||||||
|
VkRenderPass renderpass;
|
||||||
|
|
||||||
|
uint32_t swapchainImageIndex = 0;
|
||||||
|
VkSemaphore acquireSemaphore = VK_NULL_HANDLE;
|
||||||
|
VkSemaphore releaseSemaphore = VK_NULL_HANDLE;
|
||||||
};
|
};
|
||||||
|
|
||||||
// enums
|
// enums
|
||||||
@ -231,45 +234,43 @@ namespace engine {
|
|||||||
throw std::runtime_error("Unable to find the requested queue");
|
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<Queue> queues, SDL_Window* window, VkSurfaceKHR surface, const SwapchainSupportDetails& supportDetails, Swapchain* swapchain)
|
static void createSwapchain(VkDevice device, const std::vector<Queue> queues, SDL_Window* window, VkSurfaceKHR surface, const SwapchainSupportDetails& supportDetails, Swapchain* swapchain)
|
||||||
{
|
{
|
||||||
VkResult res;
|
VkResult res;
|
||||||
|
|
||||||
VkSurfaceFormatKHR chosenSurfaceFormat = supportDetails.formats[0];
|
swapchain->surfaceFormat = supportDetails.formats[0];
|
||||||
|
|
||||||
for (const auto& format : supportDetails.formats) {
|
for (const auto& format : supportDetails.formats) {
|
||||||
if (format.format == VK_FORMAT_B8G8R8A8_SRGB &&
|
if (format.format == VK_FORMAT_B8G8R8A8_SRGB &&
|
||||||
format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
|
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) {
|
for (const auto& presMode : supportDetails.presentModes) {
|
||||||
if (presMode == VK_PRESENT_MODE_MAILBOX_KHR) {
|
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<uint32_t>::max()) {
|
if (supportDetails.caps.currentExtent.width != std::numeric_limits<uint32_t>::max()) {
|
||||||
chosenSwapExtent = supportDetails.caps.currentExtent;
|
swapchain->extent = supportDetails.caps.currentExtent;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// if fb size isn't already found, get it from SDL
|
// if fb size isn't already found, get it from SDL
|
||||||
int width, height;
|
int width, height;
|
||||||
SDL_Vulkan_GetDrawableSize(window, &width, &height);
|
SDL_Vulkan_GetDrawableSize(window, &width, &height);
|
||||||
|
|
||||||
chosenSwapExtent.width = static_cast<uint32_t>(width);
|
swapchain->extent.width = static_cast<uint32_t>(width);
|
||||||
chosenSwapExtent.height = static_cast<uint32_t>(height);
|
swapchain->extent.height = static_cast<uint32_t>(height);
|
||||||
|
|
||||||
chosenSwapExtent.width = std::clamp(
|
swapchain->extent.width = std::clamp(
|
||||||
chosenSwapExtent.width,
|
swapchain->extent.width,
|
||||||
supportDetails.caps.minImageExtent.width, supportDetails.caps.maxImageExtent.width);
|
supportDetails.caps.minImageExtent.width, supportDetails.caps.maxImageExtent.width);
|
||||||
chosenSwapExtent.height = std::clamp(
|
swapchain->extent.height = std::clamp(
|
||||||
chosenSwapExtent.height,
|
swapchain->extent.height,
|
||||||
supportDetails.caps.minImageExtent.height, supportDetails.caps.maxImageExtent.height);
|
supportDetails.caps.minImageExtent.height, supportDetails.caps.maxImageExtent.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,9 +285,9 @@ namespace engine {
|
|||||||
.flags = 0,
|
.flags = 0,
|
||||||
.surface = surface,
|
.surface = surface,
|
||||||
.minImageCount = imageCount,
|
.minImageCount = imageCount,
|
||||||
.imageFormat = chosenSurfaceFormat.format,
|
.imageFormat = swapchain->surfaceFormat.format,
|
||||||
.imageColorSpace = chosenSurfaceFormat.colorSpace,
|
.imageColorSpace = swapchain->surfaceFormat.colorSpace,
|
||||||
.imageExtent = chosenSwapExtent,
|
.imageExtent = swapchain->extent,
|
||||||
.imageArrayLayers = 1,
|
.imageArrayLayers = 1,
|
||||||
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
|
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
|
||||||
.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||||
@ -294,9 +295,9 @@ namespace engine {
|
|||||||
.pQueueFamilyIndices = nullptr,
|
.pQueueFamilyIndices = nullptr,
|
||||||
.preTransform = supportDetails.caps.currentTransform,
|
.preTransform = supportDetails.caps.currentTransform,
|
||||||
.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
|
.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
|
||||||
.presentMode = chosenPresentMode,
|
.presentMode = swapchain->presentMode,
|
||||||
.clipped = VK_TRUE,
|
.clipped = VK_TRUE,
|
||||||
.oldSwapchain = VK_NULL_HANDLE,
|
.oldSwapchain = swapchain->swapchain,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -313,6 +314,11 @@ namespace engine {
|
|||||||
res = vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapchain->swapchain);
|
res = vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapchain->swapchain);
|
||||||
assert(res == VK_SUCCESS);
|
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
|
// get all the image handles
|
||||||
uint32_t swapchainImageCount = 0;
|
uint32_t swapchainImageCount = 0;
|
||||||
res = vkGetSwapchainImagesKHR(device, swapchain->swapchain, &swapchainImageCount, nullptr);
|
res = vkGetSwapchainImagesKHR(device, swapchain->swapchain, &swapchainImageCount, nullptr);
|
||||||
@ -321,19 +327,52 @@ namespace engine {
|
|||||||
res = vkGetSwapchainImagesKHR(device, swapchain->swapchain, &swapchainImageCount, swapchain->images.data());
|
res = vkGetSwapchainImagesKHR(device, swapchain->swapchain, &swapchainImageCount, swapchain->images.data());
|
||||||
assert(res == VK_SUCCESS);
|
assert(res == VK_SUCCESS);
|
||||||
|
|
||||||
swapchain->format = chosenSurfaceFormat.format;
|
// create the render pass
|
||||||
swapchain->extent = chosenSwapExtent;
|
{
|
||||||
|
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
|
VkAttachmentReference colorAttachmentRef{};
|
||||||
swapchain->imageViews.clear();
|
colorAttachmentRef.attachment = 0;
|
||||||
for (VkImage image : swapchain->images) {
|
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{};
|
VkImageViewCreateInfo createInfo{};
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||||
createInfo.pNext = nullptr;
|
createInfo.pNext = nullptr;
|
||||||
createInfo.image = image;
|
createInfo.image = swapchain->images[i];
|
||||||
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
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.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
@ -343,13 +382,40 @@ namespace engine {
|
|||||||
createInfo.subresourceRange.levelCount = 1;
|
createInfo.subresourceRange.levelCount = 1;
|
||||||
createInfo.subresourceRange.baseArrayLayer = 0;
|
createInfo.subresourceRange.baseArrayLayer = 0;
|
||||||
createInfo.subresourceRange.layerCount = 1;
|
createInfo.subresourceRange.layerCount = 1;
|
||||||
|
res = vkCreateImageView(device, &createInfo, nullptr, &swapchain->imageViews[i]);
|
||||||
VkImageView imageView;
|
|
||||||
res = vkCreateImageView(device, &createInfo, nullptr, &imageView);
|
|
||||||
assert(res == VK_SUCCESS);
|
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)
|
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<Impl>();
|
pimpl = std::make_unique<Impl>();
|
||||||
|
|
||||||
VkResult res;
|
VkResult res;
|
||||||
@ -816,9 +876,15 @@ namespace engine {
|
|||||||
{
|
{
|
||||||
TRACE("Destroying GFXDevice...");
|
TRACE("Destroying GFXDevice...");
|
||||||
|
|
||||||
|
vkDestroySemaphore(pimpl->device, pimpl->swapchain.releaseSemaphore, nullptr);
|
||||||
|
vkDestroySemaphore(pimpl->device, pimpl->swapchain.acquireSemaphore, nullptr);
|
||||||
for (VkImageView view : pimpl->swapchain.imageViews) {
|
for (VkImageView view : pimpl->swapchain.imageViews) {
|
||||||
vkDestroyImageView(pimpl->device, view, nullptr);
|
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);
|
vkDestroySwapchainKHR(pimpl->device, pimpl->swapchain.swapchain, nullptr);
|
||||||
|
|
||||||
vmaDestroyAllocator(pimpl->allocator);
|
vmaDestroyAllocator(pimpl->allocator);
|
||||||
@ -828,8 +894,6 @@ namespace engine {
|
|||||||
vkDestroySurfaceKHR(pimpl->instance, pimpl->surface, nullptr);
|
vkDestroySurfaceKHR(pimpl->instance, pimpl->surface, nullptr);
|
||||||
vkDestroyDebugUtilsMessengerEXT(pimpl->instance, pimpl->debugMessenger, nullptr);
|
vkDestroyDebugUtilsMessengerEXT(pimpl->instance, pimpl->debugMessenger, nullptr);
|
||||||
vkDestroyInstance(pimpl->instance, nullptr);
|
vkDestroyInstance(pimpl->instance, nullptr);
|
||||||
|
|
||||||
s_gfx_device_instance = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GFXDevice::draw()
|
void GFXDevice::draw()
|
||||||
|
Loading…
Reference in New Issue
Block a user