Created swapchain object.
Manages most of the present-related stuff. Still need to move some queue submits inside of it though
This commit is contained in:
40
include/vulkan/basalt_swapchain.h
Normal file
40
include/vulkan/basalt_swapchain.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "vulkan/basalt_device.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace basalt
|
||||||
|
{
|
||||||
|
class Swapchain
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Swapchain(const Swapchain& src) = delete;
|
||||||
|
Swapchain& operator =(const Swapchain& src) = delete;
|
||||||
|
Swapchain(Swapchain&& src) = delete;
|
||||||
|
Swapchain& operator =(Swapchain&& src) = delete;
|
||||||
|
|
||||||
|
|
||||||
|
Swapchain(basalt::Device& device, basalt::Window& window,
|
||||||
|
const std::initializer_list<VkSurfaceFormatKHR>& allowed_formats,
|
||||||
|
const std::initializer_list<VkPresentModeKHR> allowed_present_modes);
|
||||||
|
~Swapchain();
|
||||||
|
|
||||||
|
void create_framebuffers(VkRenderPass render_pass);
|
||||||
|
void wait_and_reset(bool wait_all=VK_TRUE, u64 timeout=UINT64_MAX);
|
||||||
|
u32 acquire_next_image(VkFence fence=VK_NULL_HANDLE, u64 timeout=UINT64_MAX);
|
||||||
|
|
||||||
|
basalt::darray<VkSemaphore> semaphores_image_available;
|
||||||
|
basalt::darray<VkSemaphore> semaphores_render_finished;
|
||||||
|
basalt::darray<VkFence> fences_in_flight;
|
||||||
|
basalt::SwapchainSupportDetails details;
|
||||||
|
basalt::darray<VkImage> swapchain_images;
|
||||||
|
basalt::darray<VkImageView> swapchain_image_views;
|
||||||
|
basalt::darray<VkFramebuffer> framebuffers;
|
||||||
|
basalt::Device* device = nullptr;
|
||||||
|
basalt::Window* window = nullptr;
|
||||||
|
VkSwapchainKHR swapchain = VK_NULL_HANDLE;
|
||||||
|
VkExtent2D swapchain_extent;
|
||||||
|
u32 image_count = -1;
|
||||||
|
u32 max_frames_in_flight = 2;
|
||||||
|
u32 current_frame = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
149
src/vulkan/basalt_swapchain.cpp
Normal file
149
src/vulkan/basalt_swapchain.cpp
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
#include "vulkan/basalt_swapchain.h"
|
||||||
|
|
||||||
|
basalt::Swapchain::Swapchain(basalt::Device& device, basalt::Window& window,
|
||||||
|
const std::initializer_list<VkSurfaceFormatKHR>& allowed_formats,
|
||||||
|
const std::initializer_list<VkPresentModeKHR> allowed_present_modes) :
|
||||||
|
details(device, window), device(&device), window(&window),
|
||||||
|
swapchain_images(MEMORY_TAG_CLASS_ARRAY | MEMORY_TAG_ZONE_ENGINE | MEMORY_TAG_ALIGN_ANY),
|
||||||
|
swapchain_image_views(MEMORY_TAG_CLASS_ARRAY | MEMORY_TAG_ZONE_ENGINE | MEMORY_TAG_ALIGN_ANY),
|
||||||
|
framebuffers(MEMORY_TAG_CLASS_ARRAY | MEMORY_TAG_ZONE_ENGINE | MEMORY_TAG_ALIGN_ANY),
|
||||||
|
semaphores_image_available(MEMORY_TAG_CLASS_ARRAY | MEMORY_TAG_ZONE_ENGINE | MEMORY_TAG_ALIGN_ANY),
|
||||||
|
semaphores_render_finished(MEMORY_TAG_CLASS_ARRAY | MEMORY_TAG_ZONE_ENGINE | MEMORY_TAG_ALIGN_ANY),
|
||||||
|
fences_in_flight(MEMORY_TAG_CLASS_ARRAY | MEMORY_TAG_ZONE_ENGINE | MEMORY_TAG_ALIGN_ANY)
|
||||||
|
{
|
||||||
|
this->image_count = details.surface_capabilities.minImageCount + 1;
|
||||||
|
BCLAMP(this->image_count, details.surface_capabilities.minImageCount, details.surface_capabilities.maxImageCount);
|
||||||
|
if (this->image_count == 0)
|
||||||
|
this->image_count = details.surface_capabilities.minImageCount + 1;
|
||||||
|
|
||||||
|
VkSwapchainCreateInfoKHR ci = {VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR};
|
||||||
|
ci.surface = window;
|
||||||
|
ci.minImageCount = this->image_count;
|
||||||
|
ci.imageFormat = details.get_surface_format(allowed_formats).format;
|
||||||
|
ci.imageColorSpace = details.get_surface_format(allowed_formats).colorSpace;
|
||||||
|
ci.imageExtent = details.get_framebuffer_extent(window);
|
||||||
|
ci.imageArrayLayers = 1;
|
||||||
|
ci.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||||
|
ci.presentMode = details.get_present_mode(allowed_present_modes);
|
||||||
|
ci.clipped = VK_TRUE;
|
||||||
|
ci.oldSwapchain = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
ci.preTransform = details.surface_capabilities.currentTransform;
|
||||||
|
ci.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||||
|
u32 queue_family_indicies[] = { device.phys->indicies.graphics, device.phys->indicies.present };
|
||||||
|
if (device.phys->indicies.graphics == device.phys->indicies.present)
|
||||||
|
{
|
||||||
|
ci.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
ci.queueFamilyIndexCount = 0;
|
||||||
|
ci.pQueueFamilyIndices = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ci.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||||
|
ci.queueFamilyIndexCount = sizeof(queue_family_indicies)/sizeof(queue_family_indicies[0]);
|
||||||
|
ci.pQueueFamilyIndices = queue_family_indicies;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkResult err = VK_SUCCESS;
|
||||||
|
this->swapchain_extent = ci.imageExtent;
|
||||||
|
VK_ASSERT(vkCreateSwapchainKHR(device, &ci, device.ctx->vk_alloc, &this->swapchain), "Failed to create swapchain\n\tAt %s:%d\n\tError %s\n");
|
||||||
|
|
||||||
|
u32 n_images = 0;
|
||||||
|
vkGetSwapchainImagesKHR(device, this->swapchain, &n_images, nullptr);
|
||||||
|
this->swapchain_images.resize(n_images);
|
||||||
|
vkGetSwapchainImagesKHR(device, this->swapchain, &n_images, this->swapchain_images.m_pdata);
|
||||||
|
this->swapchain_images.resize(n_images);
|
||||||
|
|
||||||
|
this->swapchain_image_views.reserve(n_images);
|
||||||
|
for (u32 i = 0; i < n_images; ++i)
|
||||||
|
{
|
||||||
|
VkImageViewCreateInfo view_ci = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
|
||||||
|
view_ci.image = swapchain_images[i];
|
||||||
|
view_ci.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
|
view_ci.format = this->details.cached_format.format;
|
||||||
|
view_ci.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
view_ci.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
view_ci.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
view_ci.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
view_ci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
view_ci.subresourceRange.baseMipLevel = 0;
|
||||||
|
view_ci.subresourceRange.levelCount = 1;
|
||||||
|
view_ci.subresourceRange.baseArrayLayer = 0;
|
||||||
|
view_ci.subresourceRange.layerCount = 1;
|
||||||
|
|
||||||
|
VK_ASSERT(vkCreateImageView(device, &view_ci, device.ctx->vk_alloc, &swapchain_image_views[i]), "Failed to create image view\n\tAt %s:%d\n\tError %s\n\tImage index: %u\n", i);
|
||||||
|
}
|
||||||
|
swapchain_image_views.m_nelements = n_images;
|
||||||
|
|
||||||
|
VkSemaphoreCreateInfo semaphore_ci = {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
|
||||||
|
VkFenceCreateInfo fence_ci = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO};
|
||||||
|
fence_ci.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||||
|
|
||||||
|
semaphores_image_available.resize(max_frames_in_flight);
|
||||||
|
fences_in_flight.resize(max_frames_in_flight);
|
||||||
|
for (u32 i = 0; i < max_frames_in_flight; ++i)
|
||||||
|
{
|
||||||
|
VK_ASSERT(vkCreateSemaphore(device, &semaphore_ci, device.ctx->vk_alloc, semaphores_image_available.m_pdata+i), "Failed to create image available semaphore\n\tAt %s:%d\n\tError %s\n");
|
||||||
|
VK_ASSERT(vkCreateFence(device, &fence_ci, device.ctx->vk_alloc, fences_in_flight.m_pdata+i), "Failed to create in-flight fence\n\tAt %s:%d\n\tError %s\n");
|
||||||
|
}
|
||||||
|
semaphores_render_finished.resize(image_count);
|
||||||
|
for (u32 i = 0; i < image_count; ++i)
|
||||||
|
VK_ASSERT(vkCreateSemaphore(device, &semaphore_ci, device.ctx->vk_alloc, semaphores_render_finished.m_pdata+i), "Failed to create render finished semaphore\n\tAt %s:%d\n\tError %s\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
basalt::Swapchain::~Swapchain()
|
||||||
|
{
|
||||||
|
vkDeviceWaitIdle(device->logical);
|
||||||
|
|
||||||
|
for (u32 i = 0; i < max_frames_in_flight; ++i)
|
||||||
|
{
|
||||||
|
vkDestroySemaphore(device->logical, semaphores_image_available.m_pdata[i], device->ctx->vk_alloc);
|
||||||
|
vkDestroyFence(device->logical, fences_in_flight.m_pdata[i], device->ctx->vk_alloc);
|
||||||
|
}
|
||||||
|
for (u32 i = 0; i < image_count; ++i)
|
||||||
|
vkDestroySemaphore(device->logical, semaphores_render_finished.m_pdata[i], device->ctx->vk_alloc);
|
||||||
|
|
||||||
|
for (VkFramebuffer& buffer : framebuffers)
|
||||||
|
vkDestroyFramebuffer(*device, buffer, device->ctx->vk_alloc);
|
||||||
|
for (VkImageView& view : this->swapchain_image_views)
|
||||||
|
vkDestroyImageView(*this->device, view, this->device->ctx->vk_alloc);
|
||||||
|
vkDestroySwapchainKHR(*device, this->swapchain, device->ctx->vk_alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void basalt::Swapchain::create_framebuffers(VkRenderPass render_pass)
|
||||||
|
{
|
||||||
|
if (framebuffers.m_nelements != 0)
|
||||||
|
{
|
||||||
|
for (VkFramebuffer& buffer : framebuffers)
|
||||||
|
vkDestroyFramebuffer(*device, buffer, device->ctx->vk_alloc);
|
||||||
|
}
|
||||||
|
VkResult err = VK_SUCCESS;
|
||||||
|
framebuffers.reserve(swapchain_image_views.m_nelements);
|
||||||
|
for (size_t i = 0; i < swapchain_image_views.m_nelements; ++i)
|
||||||
|
{
|
||||||
|
VkFramebufferCreateInfo ci = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO};
|
||||||
|
ci.pNext = VK_NULL_HANDLE;
|
||||||
|
ci.flags = 0;
|
||||||
|
ci.renderPass = render_pass;
|
||||||
|
ci.attachmentCount = 1;
|
||||||
|
ci.pAttachments = swapchain_image_views.m_pdata + i;
|
||||||
|
ci.width = swapchain_extent.width;
|
||||||
|
ci.height = swapchain_extent.height;
|
||||||
|
ci.layers = 1;
|
||||||
|
VK_ASSERT(vkCreateFramebuffer(*device, &ci, device->ctx->vk_alloc, framebuffers.m_pdata+i), "Failed to create framebuffer\n\tAt %s:%d\n\tError %s\n\tIndex: %llu\n", i);
|
||||||
|
}
|
||||||
|
framebuffers.m_nelements = swapchain_image_views.m_nelements;
|
||||||
|
}
|
||||||
|
|
||||||
|
void basalt::Swapchain::wait_and_reset(bool wait_all, u64 timeout)
|
||||||
|
{
|
||||||
|
vkWaitForFences(device->logical, 1, &fences_in_flight.m_pdata[current_frame], wait_all, timeout);
|
||||||
|
vkResetFences(device->logical, 1, &fences_in_flight.m_pdata[current_frame]);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 basalt::Swapchain::acquire_next_image(VkFence fence, u64 timeout)
|
||||||
|
{
|
||||||
|
u32 img = -1;
|
||||||
|
vkAcquireNextImageKHR(device->logical, swapchain, timeout, semaphores_image_available[current_frame], fence, &img);
|
||||||
|
return img;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user