vk_swapchain: Add support for swapping sRGB

We don't know until the game is running if it's using an sRGB color
space or not. Add support for hot-swapping swapchain surface formats.
This commit is contained in:
ReinUsesLisp 2019-12-06 22:41:42 -03:00
parent d49ed4a421
commit f632d00eb1
No known key found for this signature in database
GPG key ID: 2DFC508897B39CFE
2 changed files with 31 additions and 24 deletions

View file

@ -19,12 +19,18 @@
namespace Vulkan { namespace Vulkan {
namespace { namespace {
vk::SurfaceFormatKHR ChooseSwapSurfaceFormat(const std::vector<vk::SurfaceFormatKHR>& formats) {
vk::SurfaceFormatKHR ChooseSwapSurfaceFormat(const std::vector<vk::SurfaceFormatKHR>& formats,
bool srgb) {
if (formats.size() == 1 && formats[0].format == vk::Format::eUndefined) { if (formats.size() == 1 && formats[0].format == vk::Format::eUndefined) {
return {vk::Format::eB8G8R8A8Unorm, vk::ColorSpaceKHR::eSrgbNonlinear}; vk::SurfaceFormatKHR format;
format.format = vk::Format::eB8G8R8A8Unorm;
format.colorSpace = vk::ColorSpaceKHR::eSrgbNonlinear;
return format;
} }
const auto& found = std::find_if(formats.begin(), formats.end(), [](const auto& format) { const auto& found = std::find_if(formats.begin(), formats.end(), [srgb](const auto& format) {
return format.format == vk::Format::eB8G8R8A8Unorm && const auto request_format = srgb ? vk::Format::eB8G8R8A8Srgb : vk::Format::eB8G8R8A8Unorm;
return format.format == request_format &&
format.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear; format.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear;
}); });
return found != formats.end() ? *found : formats[0]; return found != formats.end() ? *found : formats[0];
@ -51,28 +57,26 @@ vk::Extent2D ChooseSwapExtent(const vk::SurfaceCapabilitiesKHR& capabilities, u3
std::min(capabilities.maxImageExtent.height, extent.height)); std::min(capabilities.maxImageExtent.height, extent.height));
return extent; return extent;
} }
} // namespace
} // Anonymous namespace
VKSwapchain::VKSwapchain(vk::SurfaceKHR surface, const VKDevice& device) VKSwapchain::VKSwapchain(vk::SurfaceKHR surface, const VKDevice& device)
: surface{surface}, device{device} {} : surface{surface}, device{device} {}
VKSwapchain::~VKSwapchain() = default; VKSwapchain::~VKSwapchain() = default;
void VKSwapchain::Create(u32 width, u32 height) { void VKSwapchain::Create(u32 width, u32 height, bool srgb) {
const auto dev = device.GetLogical();
const auto& dld = device.GetDispatchLoader(); const auto& dld = device.GetDispatchLoader();
const auto physical_device = device.GetPhysical(); const auto physical_device = device.GetPhysical();
const auto capabilities{physical_device.getSurfaceCapabilitiesKHR(surface, dld)};
const vk::SurfaceCapabilitiesKHR capabilities{
physical_device.getSurfaceCapabilitiesKHR(surface, dld)};
if (capabilities.maxImageExtent.width == 0 || capabilities.maxImageExtent.height == 0) { if (capabilities.maxImageExtent.width == 0 || capabilities.maxImageExtent.height == 0) {
return; return;
} }
dev.waitIdle(dld); device.GetLogical().waitIdle(dld);
Destroy(); Destroy();
CreateSwapchain(capabilities, width, height); CreateSwapchain(capabilities, width, height, srgb);
CreateSemaphores(); CreateSemaphores();
CreateImageViews(); CreateImageViews();
@ -107,7 +111,7 @@ bool VKSwapchain::Present(vk::Semaphore render_semaphore, VKFence& fence) {
break; break;
case vk::Result::eErrorOutOfDateKHR: case vk::Result::eErrorOutOfDateKHR:
if (current_width > 0 && current_height > 0) { if (current_width > 0 && current_height > 0) {
Create(current_width, current_height); Create(current_width, current_height, current_srgb);
recreated = true; recreated = true;
} }
break; break;
@ -129,23 +133,19 @@ bool VKSwapchain::HasFramebufferChanged(const Layout::FramebufferLayout& framebu
} }
void VKSwapchain::CreateSwapchain(const vk::SurfaceCapabilitiesKHR& capabilities, u32 width, void VKSwapchain::CreateSwapchain(const vk::SurfaceCapabilitiesKHR& capabilities, u32 width,
u32 height) { u32 height, bool srgb) {
const auto dev{device.GetLogical()};
const auto& dld{device.GetDispatchLoader()}; const auto& dld{device.GetDispatchLoader()};
const auto physical_device{device.GetPhysical()}; const auto physical_device{device.GetPhysical()};
const auto formats{physical_device.getSurfaceFormatsKHR(surface, dld)};
const auto present_modes{physical_device.getSurfacePresentModesKHR(surface, dld)};
const std::vector<vk::SurfaceFormatKHR> formats{ const vk::SurfaceFormatKHR surface_format{ChooseSwapSurfaceFormat(formats, srgb)};
physical_device.getSurfaceFormatsKHR(surface, dld)};
const std::vector<vk::PresentModeKHR> present_modes{
physical_device.getSurfacePresentModesKHR(surface, dld)};
const vk::SurfaceFormatKHR surface_format{ChooseSwapSurfaceFormat(formats)};
const vk::PresentModeKHR present_mode{ChooseSwapPresentMode(present_modes)}; const vk::PresentModeKHR present_mode{ChooseSwapPresentMode(present_modes)};
extent = ChooseSwapExtent(capabilities, width, height); extent = ChooseSwapExtent(capabilities, width, height);
current_width = extent.width; current_width = extent.width;
current_height = extent.height; current_height = extent.height;
current_srgb = srgb;
u32 requested_image_count{capabilities.minImageCount + 1}; u32 requested_image_count{capabilities.minImageCount + 1};
if (capabilities.maxImageCount > 0 && requested_image_count > capabilities.maxImageCount) { if (capabilities.maxImageCount > 0 && requested_image_count > capabilities.maxImageCount) {
@ -169,6 +169,7 @@ void VKSwapchain::CreateSwapchain(const vk::SurfaceCapabilitiesKHR& capabilities
swapchain_ci.imageSharingMode = vk::SharingMode::eExclusive; swapchain_ci.imageSharingMode = vk::SharingMode::eExclusive;
} }
const auto dev{device.GetLogical()};
swapchain = dev.createSwapchainKHRUnique(swapchain_ci, nullptr, dld); swapchain = dev.createSwapchainKHRUnique(swapchain_ci, nullptr, dld);
images = dev.getSwapchainImagesKHR(*swapchain, dld); images = dev.getSwapchainImagesKHR(*swapchain, dld);

View file

@ -24,7 +24,7 @@ public:
~VKSwapchain(); ~VKSwapchain();
/// Creates (or recreates) the swapchain with a given size. /// Creates (or recreates) the swapchain with a given size.
void Create(u32 width, u32 height); void Create(u32 width, u32 height, bool srgb);
/// Acquires the next image in the swapchain, waits as needed. /// Acquires the next image in the swapchain, waits as needed.
void AcquireNextImage(); void AcquireNextImage();
@ -60,8 +60,13 @@ public:
return image_format; return image_format;
} }
bool GetSrgbState() const {
return current_srgb;
}
private: private:
void CreateSwapchain(const vk::SurfaceCapabilitiesKHR& capabilities, u32 width, u32 height); void CreateSwapchain(const vk::SurfaceCapabilitiesKHR& capabilities, u32 width, u32 height,
bool srgb);
void CreateSemaphores(); void CreateSemaphores();
void CreateImageViews(); void CreateImageViews();
@ -87,6 +92,7 @@ private:
u32 current_width{}; u32 current_width{};
u32 current_height{}; u32 current_height{};
bool current_srgb{};
}; };
} // namespace Vulkan } // namespace Vulkan