Disabled framebuffer caching by physical device

Swapchain is now capable of being recreated in a partially automatic manner (some effort is still required on the developer's side still)
Windows are now allowed to be resizeable
Updated main program to support resizable windows
This commit is contained in:
2025-07-08 23:35:27 +10:00
parent 5e04281094
commit e4258318ee
5 changed files with 144 additions and 82 deletions

View File

@@ -404,8 +404,6 @@ VkPresentModeKHR basalt::SwapchainSupportDetails::get_present_mode(const std::in
VkExtent2D basalt::SwapchainSupportDetails::get_framebuffer_extent(basalt::Window& window)
{
if (this->surface_capabilities.currentExtent.width != -1)
return this->surface_capabilities.currentExtent;
i32 width, height;
glfwGetFramebufferSize(window, &width, &height);
VkExtent2D ext = {

View File

@@ -11,70 +11,10 @@ basalt::Swapchain::Swapchain(basalt::Device& device, basalt::Window& window,
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;
}
this->framebuffers_created = false;
this->create(allowed_formats, allowed_present_modes, VK_NULL_HANDLE);
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;
@@ -110,10 +50,28 @@ basalt::Swapchain::~Swapchain()
vkDestroySwapchainKHR(*device, this->swapchain, device->ctx->vk_alloc);
}
void basalt::Swapchain::recreate(VkRenderPass new_renderpass)
{
swapchain_extent = details.get_framebuffer_extent(*window);
if (swapchain_extent.width == 0 || swapchain_extent.height == 0)
return;
vkDeviceWaitIdle(device->logical);
for (VkImageView& view : this->swapchain_image_views)
vkDestroyImageView(*this->device, view, this->device->ctx->vk_alloc);
vkDestroySwapchainKHR(*device, this->swapchain, device->ctx->vk_alloc);
// TODO: store the prefered format/present list and use them
this->create({ details.cached_format }, { details.cached_present_mode }, VK_NULL_HANDLE);
if (new_renderpass != VK_NULL_HANDLE)
this->create_framebuffers(new_renderpass);
}
void basalt::Swapchain::create_framebuffers(VkRenderPass render_pass)
{
if (framebuffers.m_nelements != 0)
if (framebuffers.m_nelements != 0 || framebuffers_created)
{
vkDeviceWaitIdle(*device);
for (VkFramebuffer& buffer : framebuffers)
vkDestroyFramebuffer(*device, buffer, device->ctx->vk_alloc);
}
@@ -133,17 +91,92 @@ void basalt::Swapchain::create_framebuffers(VkRenderPass render_pass)
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;
framebuffers_created = true;
}
void basalt::Swapchain::wait_and_reset(bool wait_all, u64 timeout)
u32 basalt::Swapchain::wait_acquire_reset(bool wait_all, u64 timeout, VkFence fence)
{
if (!framebuffers_created)
return - 1;
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);
VkResult err = vkAcquireNextImageKHR(device->logical, swapchain, timeout, semaphores_image_available[current_frame], fence, &img);
if (err == VK_ERROR_OUT_OF_DATE_KHR)
{
framebuffers_created = false;
this->recreate();
return -1;
}
BASSERT_FATAL(err == VK_SUCCESS, "Assertion %s failed\n\tFailed to acquire next image of swapchain\n\tAt %s:%d\n\tError %s\n\tSwapchain %p (%p)\n", string_VkResult(err), this, this->swapchain);
vkResetFences(device->logical, 1, &fences_in_flight.m_pdata[current_frame]);
return img;
}
void basalt::Swapchain::create(const std::initializer_list<VkSurfaceFormatKHR>& allowed_formats,
const std::initializer_list<VkPresentModeKHR> allowed_present_modes, VkSwapchainKHR prev_swapchain)
{
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 = prev_swapchain;
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->logical, &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->logical, this->swapchain, &n_images, nullptr);
this->swapchain_images.resize(n_images);
vkGetSwapchainImagesKHR(device->logical, 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->logical, &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;
}

View File

@@ -37,7 +37,7 @@ basalt::Window::Window(basalt::Context& ctx, uint16_t width, uint16_t height, co
{
glfwInit();
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);
this->window = glfwCreateWindow(width, height, title, nullptr, nullptr);
VkResult err = VK_SUCCESS;