646 lines
24 KiB
C++
646 lines
24 KiB
C++
/* Copyright (c) 2019-2025, Arm Limited and Contributors
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 the "License";
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "core/swapchain.h"
|
|
|
|
#include "core/util/logging.hpp"
|
|
#include "device.h"
|
|
#include "image.h"
|
|
|
|
namespace vkb
|
|
{
|
|
namespace
|
|
{
|
|
inline uint32_t choose_image_count(
|
|
uint32_t request_image_count,
|
|
uint32_t min_image_count,
|
|
uint32_t max_image_count)
|
|
{
|
|
if (max_image_count != 0)
|
|
{
|
|
request_image_count = std::min(request_image_count, max_image_count);
|
|
}
|
|
|
|
request_image_count = std::max(request_image_count, min_image_count);
|
|
|
|
return request_image_count;
|
|
}
|
|
|
|
inline uint32_t choose_image_array_layers(
|
|
uint32_t request_image_array_layers,
|
|
uint32_t max_image_array_layers)
|
|
{
|
|
request_image_array_layers = std::min(request_image_array_layers, max_image_array_layers);
|
|
request_image_array_layers = std::max(request_image_array_layers, 1u);
|
|
|
|
return request_image_array_layers;
|
|
}
|
|
|
|
inline VkExtent2D choose_extent(
|
|
VkExtent2D request_extent,
|
|
const VkExtent2D &min_image_extent,
|
|
const VkExtent2D &max_image_extent,
|
|
const VkExtent2D ¤t_extent)
|
|
{
|
|
if (current_extent.width == 0xFFFFFFFF)
|
|
{
|
|
return request_extent;
|
|
}
|
|
|
|
if (request_extent.width < 1 || request_extent.height < 1)
|
|
{
|
|
LOGW("(Swapchain) Image extent ({}, {}) not supported. Selecting ({}, {}).", request_extent.width, request_extent.height, current_extent.width, current_extent.height);
|
|
return current_extent;
|
|
}
|
|
|
|
request_extent.width = std::max(request_extent.width, min_image_extent.width);
|
|
request_extent.width = std::min(request_extent.width, max_image_extent.width);
|
|
|
|
request_extent.height = std::max(request_extent.height, min_image_extent.height);
|
|
request_extent.height = std::min(request_extent.height, max_image_extent.height);
|
|
|
|
return request_extent;
|
|
}
|
|
|
|
inline VkPresentModeKHR choose_present_mode(
|
|
VkPresentModeKHR request_present_mode,
|
|
const std::vector<VkPresentModeKHR> &available_present_modes,
|
|
const std::vector<VkPresentModeKHR> &present_mode_priority_list)
|
|
{
|
|
auto present_mode_it = std::ranges::find(available_present_modes, request_present_mode);
|
|
|
|
if (present_mode_it == available_present_modes.end())
|
|
{
|
|
// If nothing found, always default to FIFO
|
|
VkPresentModeKHR chosen_present_mode = VK_PRESENT_MODE_FIFO_KHR;
|
|
|
|
for (auto &present_mode : present_mode_priority_list)
|
|
{
|
|
if (std::ranges::find(available_present_modes, present_mode) != available_present_modes.end())
|
|
{
|
|
chosen_present_mode = present_mode;
|
|
break;
|
|
}
|
|
}
|
|
|
|
LOGW("(Swapchain) Present mode '{}' not supported. Selecting '{}'.", to_string(request_present_mode), to_string(chosen_present_mode));
|
|
return chosen_present_mode;
|
|
}
|
|
else
|
|
{
|
|
LOGI("(Swapchain) Present mode selected: {}", to_string(request_present_mode));
|
|
return *present_mode_it;
|
|
}
|
|
}
|
|
|
|
inline VkSurfaceFormatKHR choose_surface_format(
|
|
const VkSurfaceFormatKHR requested_surface_format,
|
|
const std::vector<VkSurfaceFormatKHR> &available_surface_formats,
|
|
const std::vector<VkSurfaceFormatKHR> &surface_format_priority_list)
|
|
{
|
|
// Try to find the requested surface format in the supported surface formats
|
|
auto surface_format_it = std::ranges::find_if(
|
|
available_surface_formats,
|
|
[&requested_surface_format](const VkSurfaceFormatKHR &surface) {
|
|
if (surface.format == requested_surface_format.format &&
|
|
surface.colorSpace == requested_surface_format.colorSpace)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
});
|
|
|
|
// If the requested surface format isn't found, then try to request a format from the priority list
|
|
if (surface_format_it == available_surface_formats.end())
|
|
{
|
|
for (auto &surface_format : surface_format_priority_list)
|
|
{
|
|
surface_format_it = std::ranges::find_if(
|
|
available_surface_formats,
|
|
[&surface_format](const VkSurfaceFormatKHR &surface) {
|
|
if (surface.format == surface_format.format &&
|
|
surface.colorSpace == surface_format.colorSpace)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
});
|
|
if (surface_format_it != available_surface_formats.end())
|
|
{
|
|
LOGW("(Swapchain) Surface format ({}) not supported. Selecting ({}).", to_string(requested_surface_format), to_string(*surface_format_it));
|
|
return *surface_format_it;
|
|
}
|
|
}
|
|
|
|
// If nothing found, default to the first supported surface format
|
|
surface_format_it = available_surface_formats.begin();
|
|
LOGW("(Swapchain) Surface format ({}) not supported. Selecting ({}).", to_string(requested_surface_format), to_string(*surface_format_it));
|
|
}
|
|
else
|
|
{
|
|
LOGI("(Swapchain) Surface format selected: {}", to_string(requested_surface_format));
|
|
}
|
|
|
|
return *surface_format_it;
|
|
}
|
|
|
|
inline VkSurfaceTransformFlagBitsKHR choose_transform(
|
|
VkSurfaceTransformFlagBitsKHR request_transform,
|
|
VkSurfaceTransformFlagsKHR supported_transform,
|
|
VkSurfaceTransformFlagBitsKHR current_transform)
|
|
{
|
|
if (request_transform & supported_transform)
|
|
{
|
|
return request_transform;
|
|
}
|
|
|
|
LOGW("(Swapchain) Surface transform '{}' not supported. Selecting '{}'.", to_string(request_transform), to_string(current_transform));
|
|
|
|
return current_transform;
|
|
}
|
|
|
|
inline VkCompositeAlphaFlagBitsKHR choose_composite_alpha(VkCompositeAlphaFlagBitsKHR request_composite_alpha, VkCompositeAlphaFlagsKHR supported_composite_alpha)
|
|
{
|
|
if (request_composite_alpha & supported_composite_alpha)
|
|
{
|
|
return request_composite_alpha;
|
|
}
|
|
|
|
static const std::vector<VkCompositeAlphaFlagBitsKHR> composite_alpha_flags = {
|
|
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
|
|
VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
|
|
VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
|
|
VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR};
|
|
|
|
for (VkCompositeAlphaFlagBitsKHR composite_alpha : composite_alpha_flags)
|
|
{
|
|
if (composite_alpha & supported_composite_alpha)
|
|
{
|
|
LOGW("(Swapchain) Composite alpha '{}' not supported. Selecting '{}.", to_string(request_composite_alpha), to_string(composite_alpha));
|
|
return composite_alpha;
|
|
}
|
|
}
|
|
|
|
throw std::runtime_error("No compatible composite alpha found.");
|
|
}
|
|
|
|
inline bool validate_format_feature(VkImageUsageFlagBits image_usage, VkFormatFeatureFlags supported_features)
|
|
{
|
|
switch (image_usage)
|
|
{
|
|
case VK_IMAGE_USAGE_STORAGE_BIT:
|
|
return VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT & supported_features;
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
inline std::set<VkImageUsageFlagBits> choose_image_usage(const std::set<VkImageUsageFlagBits> &requested_image_usage_flags, VkImageUsageFlags supported_image_usage, VkFormatFeatureFlags supported_features)
|
|
{
|
|
std::set<VkImageUsageFlagBits> validated_image_usage_flags;
|
|
for (auto flag : requested_image_usage_flags)
|
|
{
|
|
if ((flag & supported_image_usage) && validate_format_feature(flag, supported_features))
|
|
{
|
|
validated_image_usage_flags.insert(flag);
|
|
}
|
|
else
|
|
{
|
|
LOGW("(Swapchain) Image usage ({}) requested but not supported.", to_string(flag));
|
|
}
|
|
}
|
|
|
|
if (validated_image_usage_flags.empty())
|
|
{
|
|
// Pick the first format from list of defaults, if supported
|
|
static const std::vector<VkImageUsageFlagBits> image_usage_flags = {
|
|
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
|
|
VK_IMAGE_USAGE_STORAGE_BIT,
|
|
VK_IMAGE_USAGE_SAMPLED_BIT,
|
|
VK_IMAGE_USAGE_TRANSFER_DST_BIT};
|
|
|
|
for (VkImageUsageFlagBits image_usage : image_usage_flags)
|
|
{
|
|
if ((image_usage & supported_image_usage) && validate_format_feature(image_usage, supported_features))
|
|
{
|
|
validated_image_usage_flags.insert(image_usage);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!validated_image_usage_flags.empty())
|
|
{
|
|
// Log image usage flags used
|
|
std::string usage_list;
|
|
for (VkImageUsageFlagBits image_usage : validated_image_usage_flags)
|
|
{
|
|
usage_list += to_string(image_usage) + " ";
|
|
}
|
|
LOGI("(Swapchain) Image usage flags: {}", usage_list);
|
|
}
|
|
else
|
|
{
|
|
throw std::runtime_error("No compatible image usage found.");
|
|
}
|
|
|
|
return validated_image_usage_flags;
|
|
}
|
|
|
|
inline VkImageUsageFlags composite_image_flags(std::set<VkImageUsageFlagBits> &image_usage_flags)
|
|
{
|
|
VkImageUsageFlags image_usage{};
|
|
for (auto flag : image_usage_flags)
|
|
{
|
|
image_usage |= flag;
|
|
}
|
|
return image_usage;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
Swapchain::Swapchain(Swapchain &old_swapchain, const VkExtent2D &extent) :
|
|
Swapchain{old_swapchain,
|
|
old_swapchain.device,
|
|
old_swapchain.surface,
|
|
old_swapchain.properties.present_mode,
|
|
old_swapchain.present_mode_priority_list,
|
|
old_swapchain.surface_format_priority_list,
|
|
extent,
|
|
old_swapchain.properties.image_count,
|
|
old_swapchain.properties.pre_transform,
|
|
old_swapchain.image_usage_flags,
|
|
old_swapchain.requested_compression,
|
|
old_swapchain.requested_compression_fixed_rate}
|
|
{}
|
|
|
|
Swapchain::Swapchain(Swapchain &old_swapchain, const uint32_t image_count) :
|
|
Swapchain{old_swapchain,
|
|
old_swapchain.device,
|
|
old_swapchain.surface,
|
|
old_swapchain.properties.present_mode,
|
|
old_swapchain.present_mode_priority_list,
|
|
old_swapchain.surface_format_priority_list,
|
|
old_swapchain.properties.extent,
|
|
image_count,
|
|
old_swapchain.properties.pre_transform,
|
|
old_swapchain.image_usage_flags,
|
|
old_swapchain.requested_compression,
|
|
old_swapchain.requested_compression_fixed_rate}
|
|
{}
|
|
|
|
Swapchain::Swapchain(Swapchain &old_swapchain, const std::set<VkImageUsageFlagBits> &image_usage_flags) :
|
|
Swapchain{old_swapchain,
|
|
old_swapchain.device,
|
|
old_swapchain.surface,
|
|
old_swapchain.properties.present_mode,
|
|
old_swapchain.present_mode_priority_list,
|
|
old_swapchain.surface_format_priority_list,
|
|
old_swapchain.properties.extent,
|
|
old_swapchain.properties.image_count,
|
|
old_swapchain.properties.pre_transform,
|
|
image_usage_flags,
|
|
old_swapchain.requested_compression,
|
|
old_swapchain.requested_compression_fixed_rate}
|
|
{}
|
|
|
|
Swapchain::Swapchain(Swapchain &old_swapchain, const VkExtent2D &extent, const VkSurfaceTransformFlagBitsKHR transform) :
|
|
Swapchain{old_swapchain,
|
|
old_swapchain.device,
|
|
old_swapchain.surface,
|
|
old_swapchain.properties.present_mode,
|
|
old_swapchain.present_mode_priority_list,
|
|
old_swapchain.surface_format_priority_list,
|
|
extent,
|
|
old_swapchain.properties.image_count,
|
|
transform,
|
|
old_swapchain.image_usage_flags,
|
|
old_swapchain.requested_compression,
|
|
old_swapchain.requested_compression_fixed_rate}
|
|
{}
|
|
|
|
Swapchain::Swapchain(Swapchain &old_swapchain, const VkImageCompressionFlagsEXT requested_compression, const VkImageCompressionFixedRateFlagsEXT requested_compression_fixed_rate) :
|
|
Swapchain{old_swapchain,
|
|
old_swapchain.device,
|
|
old_swapchain.surface,
|
|
old_swapchain.properties.present_mode,
|
|
old_swapchain.present_mode_priority_list,
|
|
old_swapchain.surface_format_priority_list,
|
|
old_swapchain.properties.extent,
|
|
old_swapchain.properties.image_count,
|
|
old_swapchain.properties.pre_transform,
|
|
old_swapchain.image_usage_flags,
|
|
requested_compression,
|
|
requested_compression_fixed_rate}
|
|
{}
|
|
|
|
Swapchain::Swapchain(vkb::core::DeviceC &device,
|
|
VkSurfaceKHR surface,
|
|
const VkPresentModeKHR present_mode,
|
|
std::vector<VkPresentModeKHR> const &present_mode_priority_list,
|
|
const std::vector<VkSurfaceFormatKHR> &surface_format_priority_list,
|
|
const VkExtent2D &extent,
|
|
const uint32_t image_count,
|
|
const VkSurfaceTransformFlagBitsKHR transform,
|
|
const std::set<VkImageUsageFlagBits> &image_usage_flags,
|
|
const VkImageCompressionFlagsEXT requested_compression,
|
|
const VkImageCompressionFixedRateFlagsEXT requested_compression_fixed_rate) :
|
|
Swapchain{*this, device, surface, present_mode, present_mode_priority_list, surface_format_priority_list, extent, image_count, transform, image_usage_flags}
|
|
{
|
|
}
|
|
|
|
Swapchain::Swapchain(Swapchain &old_swapchain,
|
|
vkb::core::DeviceC &device,
|
|
VkSurfaceKHR surface,
|
|
const VkPresentModeKHR present_mode,
|
|
std::vector<VkPresentModeKHR> const &present_mode_priority_list,
|
|
const std::vector<VkSurfaceFormatKHR> &surface_format_priority_list,
|
|
const VkExtent2D &extent,
|
|
const uint32_t image_count,
|
|
const VkSurfaceTransformFlagBitsKHR transform,
|
|
const std::set<VkImageUsageFlagBits> &image_usage_flags,
|
|
const VkImageCompressionFlagsEXT requested_compression,
|
|
const VkImageCompressionFixedRateFlagsEXT requested_compression_fixed_rate) :
|
|
device{device},
|
|
surface{surface},
|
|
requested_compression{requested_compression},
|
|
requested_compression_fixed_rate{requested_compression_fixed_rate}
|
|
{
|
|
this->present_mode_priority_list = present_mode_priority_list;
|
|
this->surface_format_priority_list = surface_format_priority_list;
|
|
|
|
VkSurfaceCapabilitiesKHR surface_capabilities{};
|
|
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(this->device.get_gpu().get_handle(), surface, &surface_capabilities);
|
|
|
|
uint32_t surface_format_count{0U};
|
|
VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(this->device.get_gpu().get_handle(), surface, &surface_format_count, nullptr));
|
|
|
|
std::vector<VkSurfaceFormatKHR> surface_formats(surface_format_count);
|
|
VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(this->device.get_gpu().get_handle(), surface, &surface_format_count, surface_formats.data()));
|
|
|
|
LOGI("Surface supports the following surface formats:");
|
|
for (auto &surface_format : surface_formats)
|
|
{
|
|
LOGI(" \t{}", to_string(surface_format));
|
|
}
|
|
|
|
uint32_t present_mode_count{0U};
|
|
VK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(this->device.get_gpu().get_handle(), surface, &present_mode_count, nullptr));
|
|
|
|
std::vector<VkPresentModeKHR> present_modes(present_mode_count);
|
|
VK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(this->device.get_gpu().get_handle(), surface, &present_mode_count, present_modes.data()));
|
|
|
|
LOGI("Surface supports the following present modes:");
|
|
for (auto &pm : present_modes)
|
|
{
|
|
LOGI(" \t{}", to_string(pm));
|
|
}
|
|
|
|
// Choose best properties based on surface capabilities
|
|
properties.old_swapchain = old_swapchain.get_handle();
|
|
properties.image_count = choose_image_count(image_count, surface_capabilities.minImageCount, surface_capabilities.maxImageCount);
|
|
properties.extent = choose_extent(extent, surface_capabilities.minImageExtent, surface_capabilities.maxImageExtent, surface_capabilities.currentExtent);
|
|
properties.surface_format = choose_surface_format(properties.surface_format, surface_formats, surface_format_priority_list);
|
|
properties.array_layers = choose_image_array_layers(1U, surface_capabilities.maxImageArrayLayers);
|
|
|
|
VkFormatProperties format_properties;
|
|
vkGetPhysicalDeviceFormatProperties(this->device.get_gpu().get_handle(), properties.surface_format.format, &format_properties);
|
|
this->image_usage_flags = choose_image_usage(image_usage_flags, surface_capabilities.supportedUsageFlags, format_properties.optimalTilingFeatures);
|
|
|
|
properties.image_usage = composite_image_flags(this->image_usage_flags);
|
|
properties.pre_transform = choose_transform(transform, surface_capabilities.supportedTransforms, surface_capabilities.currentTransform);
|
|
properties.composite_alpha = choose_composite_alpha(VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR, surface_capabilities.supportedCompositeAlpha);
|
|
properties.present_mode = choose_present_mode(present_mode, present_modes, present_mode_priority_list);
|
|
|
|
VkSwapchainCreateInfoKHR create_info{VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR};
|
|
create_info.minImageCount = properties.image_count;
|
|
create_info.imageExtent = properties.extent;
|
|
create_info.presentMode = properties.present_mode;
|
|
create_info.imageFormat = properties.surface_format.format;
|
|
create_info.imageColorSpace = properties.surface_format.colorSpace;
|
|
create_info.imageArrayLayers = properties.array_layers;
|
|
create_info.imageUsage = properties.image_usage;
|
|
create_info.preTransform = properties.pre_transform;
|
|
create_info.compositeAlpha = properties.composite_alpha;
|
|
create_info.oldSwapchain = properties.old_swapchain;
|
|
create_info.surface = surface;
|
|
|
|
auto fixed_rate_flags = requested_compression_fixed_rate;
|
|
VkImageCompressionControlEXT compression_control{VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT};
|
|
compression_control.flags = requested_compression;
|
|
if (device.is_extension_enabled(VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_EXTENSION_NAME))
|
|
{
|
|
create_info.pNext = &compression_control;
|
|
|
|
if (VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT == requested_compression)
|
|
{
|
|
// Do not support compression for multi-planar formats
|
|
compression_control.compressionControlPlaneCount = 1;
|
|
compression_control.pFixedRateFlags = &fixed_rate_flags;
|
|
}
|
|
else if (VK_IMAGE_COMPRESSION_DISABLED_EXT == requested_compression)
|
|
{
|
|
LOGW("(Swapchain) Disabling default (lossless) compression, which can negatively impact performance")
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (VK_IMAGE_COMPRESSION_DEFAULT_EXT != requested_compression)
|
|
{
|
|
LOGW("(Swapchain) Compression cannot be controlled because VK_EXT_image_compression_control_swapchain is not enabled")
|
|
|
|
this->requested_compression = VK_IMAGE_COMPRESSION_DEFAULT_EXT;
|
|
this->requested_compression_fixed_rate = VK_IMAGE_COMPRESSION_FIXED_RATE_NONE_EXT;
|
|
}
|
|
}
|
|
|
|
VkResult result = vkCreateSwapchainKHR(device.get_handle(), &create_info, nullptr, &handle);
|
|
|
|
if (result != VK_SUCCESS)
|
|
{
|
|
throw VulkanException{result, "Cannot create Swapchain"};
|
|
}
|
|
|
|
uint32_t image_available{0u};
|
|
VK_CHECK(vkGetSwapchainImagesKHR(device.get_handle(), handle, &image_available, nullptr));
|
|
|
|
images.resize(image_available);
|
|
|
|
VK_CHECK(vkGetSwapchainImagesKHR(device.get_handle(), handle, &image_available, images.data()));
|
|
|
|
if (device.is_extension_enabled(VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_EXTENSION_NAME) &&
|
|
VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT == requested_compression)
|
|
{
|
|
// Check if fixed-rate compression was applied
|
|
const auto applied_compression_fixed_rate = vkb::query_applied_compression(device.get_handle(), images[0]).imageCompressionFixedRateFlags;
|
|
|
|
if (applied_compression_fixed_rate != requested_compression_fixed_rate)
|
|
{
|
|
LOGW("(Swapchain) Requested fixed-rate compression ({}) was not applied, instead images use {}",
|
|
image_compression_fixed_rate_flags_to_string(requested_compression_fixed_rate),
|
|
image_compression_fixed_rate_flags_to_string(applied_compression_fixed_rate));
|
|
|
|
this->requested_compression_fixed_rate = applied_compression_fixed_rate;
|
|
|
|
if (VK_IMAGE_COMPRESSION_FIXED_RATE_NONE_EXT == applied_compression_fixed_rate)
|
|
{
|
|
this->requested_compression = VK_IMAGE_COMPRESSION_DEFAULT_EXT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOGI("(Swapchain) Applied fixed-rate compression: {}",
|
|
image_compression_fixed_rate_flags_to_string(applied_compression_fixed_rate));
|
|
}
|
|
}
|
|
}
|
|
|
|
Swapchain::~Swapchain()
|
|
{
|
|
if (handle != VK_NULL_HANDLE)
|
|
{
|
|
vkDestroySwapchainKHR(device.get_handle(), handle, nullptr);
|
|
}
|
|
}
|
|
|
|
Swapchain::Swapchain(Swapchain &&other) :
|
|
device{other.device},
|
|
surface{std::exchange(other.surface, VK_NULL_HANDLE)},
|
|
handle{std::exchange(other.handle, VK_NULL_HANDLE)},
|
|
images{std::exchange(other.images, {})},
|
|
properties{std::exchange(other.properties, {})},
|
|
present_mode_priority_list{std::exchange(other.present_mode_priority_list, {})},
|
|
surface_format_priority_list{std::exchange(other.surface_format_priority_list, {})},
|
|
image_usage_flags{std::move(other.image_usage_flags)}
|
|
{
|
|
}
|
|
|
|
bool Swapchain::is_valid() const
|
|
{
|
|
return handle != VK_NULL_HANDLE;
|
|
}
|
|
|
|
vkb::core::DeviceC &Swapchain::get_device()
|
|
{
|
|
return device;
|
|
}
|
|
|
|
VkSwapchainKHR Swapchain::get_handle() const
|
|
{
|
|
return handle;
|
|
}
|
|
|
|
VkResult Swapchain::acquire_next_image(uint32_t &image_index, VkSemaphore image_acquired_semaphore, VkFence fence) const
|
|
{
|
|
return vkAcquireNextImageKHR(device.get_handle(), handle, std::numeric_limits<uint64_t>::max(), image_acquired_semaphore, fence, &image_index);
|
|
}
|
|
|
|
const VkExtent2D &Swapchain::get_extent() const
|
|
{
|
|
return properties.extent;
|
|
}
|
|
|
|
VkFormat Swapchain::get_format() const
|
|
{
|
|
return properties.surface_format.format;
|
|
}
|
|
|
|
VkSurfaceFormatKHR Swapchain::get_surface_format() const
|
|
{
|
|
return properties.surface_format;
|
|
}
|
|
|
|
const std::vector<VkImage> &Swapchain::get_images() const
|
|
{
|
|
return images;
|
|
}
|
|
|
|
VkSurfaceTransformFlagBitsKHR Swapchain::get_transform() const
|
|
{
|
|
return properties.pre_transform;
|
|
}
|
|
|
|
VkSurfaceKHR Swapchain::get_surface() const
|
|
{
|
|
return surface;
|
|
}
|
|
|
|
VkImageUsageFlags Swapchain::get_usage() const
|
|
{
|
|
return properties.image_usage;
|
|
}
|
|
|
|
VkPresentModeKHR Swapchain::get_present_mode() const
|
|
{
|
|
return properties.present_mode;
|
|
}
|
|
|
|
VkImageCompressionFlagsEXT Swapchain::get_applied_compression() const
|
|
{
|
|
return vkb::query_applied_compression(device.get_handle(), get_images()[0]).imageCompressionFlags;
|
|
}
|
|
|
|
std::vector<Swapchain::SurfaceFormatCompression> Swapchain::query_supported_fixed_rate_compression(vkb::core::DeviceC &device, const VkSurfaceKHR &surface)
|
|
{
|
|
std::vector<SurfaceFormatCompression> surface_format_compression_list;
|
|
|
|
if (device.is_extension_enabled(VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_EXTENSION_NAME))
|
|
{
|
|
if (device.get_gpu().get_instance().is_enabled(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME))
|
|
{
|
|
VkPhysicalDeviceSurfaceInfo2KHR surface_info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR};
|
|
surface_info.surface = surface;
|
|
|
|
uint32_t surface_format_count{0U};
|
|
|
|
VK_CHECK(vkGetPhysicalDeviceSurfaceFormats2KHR(device.get_gpu().get_handle(), &surface_info, &surface_format_count, nullptr));
|
|
|
|
std::vector<VkSurfaceFormat2KHR> surface_formats;
|
|
surface_formats.resize(surface_format_count, {VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR});
|
|
|
|
std::vector<VkImageCompressionPropertiesEXT> compression_properties;
|
|
compression_properties.resize(surface_format_count, {VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT});
|
|
|
|
for (uint32_t i = 0; i < surface_format_count; i++)
|
|
{
|
|
surface_formats[i].pNext = &compression_properties[i];
|
|
}
|
|
|
|
VK_CHECK(vkGetPhysicalDeviceSurfaceFormats2KHR(device.get_gpu().get_handle(), &surface_info, &surface_format_count, surface_formats.data()));
|
|
|
|
surface_format_compression_list.reserve(surface_format_count);
|
|
for (uint32_t i = 0; i < surface_format_count; i++)
|
|
{
|
|
surface_format_compression_list.push_back({surface_formats[i], compression_properties[i]});
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOGW("(Swapchain) To query fixed-rate compression support, instance extension VK_KHR_get_surface_capabilities2 must be enabled")
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOGW("(Swapchain) To query fixed-rate compression support, device extension VK_EXT_image_compression_control_swapchain must be enabled")
|
|
}
|
|
|
|
return surface_format_compression_list;
|
|
}
|
|
} // namespace vkb
|