|
|
|
|
@@ -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;
|
|
|
|
|
}
|
|
|
|
|
|