135 lines
4.1 KiB
C++
135 lines
4.1 KiB
C++
#include <ranges>
|
|
#include <renderer/vk/context/swapchain.hpp>
|
|
|
|
namespace lt::renderer::vk {
|
|
|
|
Swapchain::Swapchain(const Device &device, const Surface &surface): m_device(device.vk())
|
|
{
|
|
auto *physical_device = device.physical();
|
|
|
|
auto capabilities = VkSurfaceCapabilitiesKHR {};
|
|
vkc(vk_get_physical_device_surface_capabilities(physical_device, surface.vk(), &capabilities));
|
|
|
|
auto count = uint32_t { 0 };
|
|
vkc(vk_get_physical_device_surface_formats(physical_device, surface.vk(), &count, nullptr));
|
|
|
|
auto formats = std::vector<VkSurfaceFormatKHR>(count);
|
|
vkc(vk_get_physical_device_surface_formats(
|
|
physical_device,
|
|
surface.vk(),
|
|
&count,
|
|
formats.data()
|
|
));
|
|
ensure(!formats.empty(), "Surface has no formats!");
|
|
|
|
// TODO(Light): parameterize
|
|
constexpr auto desired_swapchain_image_count = uint32_t { 3 };
|
|
const auto surface_format = formats.front();
|
|
const auto queue_indices = device.get_family_indices();
|
|
|
|
auto create_info = VkSwapchainCreateInfoKHR {
|
|
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
|
|
.surface = surface.vk(),
|
|
.minImageCount = get_optimal_image_count(capabilities, desired_swapchain_image_count),
|
|
.imageFormat = surface_format.format,
|
|
.imageColorSpace = surface_format.colorSpace,
|
|
.imageExtent = surface.get_framebuffer_size(),
|
|
.imageArrayLayers = 1u,
|
|
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
|
|
.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
.queueFamilyIndexCount = queue_indices.size(),
|
|
.pQueueFamilyIndices = queue_indices.data(),
|
|
.preTransform = capabilities.currentTransform,
|
|
.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
|
|
.presentMode = VK_PRESENT_MODE_FIFO_RELAXED_KHR, // TODO(Light): parameterize
|
|
.clipped = VK_TRUE,
|
|
.oldSwapchain = nullptr,
|
|
};
|
|
|
|
vkc(vk_create_swapchain_khr(device.vk(), &create_info, nullptr, &m_swapchain));
|
|
vkc(vk_device_wait_idle(device.vk()));
|
|
|
|
auto image_count = uint32_t { 0u };
|
|
vk_get_swapchain_images_khr(device.vk(), m_swapchain, &image_count, nullptr);
|
|
|
|
m_swapchain_images.resize(image_count);
|
|
m_swapchain_image_views.resize(image_count);
|
|
vk_get_swapchain_images_khr(device.vk(), m_swapchain, &image_count, m_swapchain_images.data());
|
|
|
|
for (auto [image, view] : std::views::zip(m_swapchain_images, m_swapchain_image_views))
|
|
{
|
|
auto create_info = VkImageViewCreateInfo {
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
|
.image = image,
|
|
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
|
.format = surface_format.format,
|
|
.components = VkComponentMapping {
|
|
.r = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
.g = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
.b = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
.a = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
},
|
|
.subresourceRange = VkImageSubresourceRange {
|
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
|
.baseMipLevel = 0u,
|
|
.levelCount = 1u,
|
|
.baseArrayLayer = 0u,
|
|
.layerCount = 1u,
|
|
}
|
|
};
|
|
|
|
vkc(vk_create_image_view(device.vk(), &create_info, nullptr, &view));
|
|
}
|
|
}
|
|
|
|
Swapchain::~Swapchain()
|
|
{
|
|
try
|
|
{
|
|
if (m_device)
|
|
{
|
|
vkc(vk_device_wait_idle(m_device));
|
|
for (auto &view : m_swapchain_image_views)
|
|
{
|
|
vk_destroy_image_view(m_device, view, nullptr);
|
|
}
|
|
|
|
vk_destroy_swapchain_khr(m_device, m_swapchain, nullptr);
|
|
}
|
|
}
|
|
catch (const std::exception &exp)
|
|
{
|
|
log_err("Failed to destroy swapchain:");
|
|
log_err("\twhat: {}", exp.what());
|
|
}
|
|
}
|
|
|
|
[[nodiscard]] auto Swapchain::get_optimal_image_count(
|
|
VkSurfaceCapabilitiesKHR capabilities,
|
|
uint32_t desired_image_count
|
|
) const -> uint32_t
|
|
{
|
|
const auto min_image_count = capabilities.minImageCount;
|
|
const auto max_image_count = capabilities.maxImageCount;
|
|
|
|
const auto has_max_limit = max_image_count != 0;
|
|
|
|
// Desired image count is in range
|
|
if ((!has_max_limit || max_image_count >= desired_image_count)
|
|
&& min_image_count <= desired_image_count)
|
|
{
|
|
return desired_image_count;
|
|
}
|
|
|
|
// Fall-back to 2 if in ange
|
|
if (min_image_count <= 2 && max_image_count >= 2)
|
|
{
|
|
return 2;
|
|
}
|
|
|
|
// Fall-back to min_image_count
|
|
return min_image_count;
|
|
}
|
|
|
|
|
|
} // namespace lt::renderer::vk
|