diff --git a/impeller/renderer/backend/vulkan/allocator_vk.cc b/impeller/renderer/backend/vulkan/allocator_vk.cc index 364b9aa49afbd..d2eced4a1c49e 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.cc +++ b/impeller/renderer/backend/vulkan/allocator_vk.cc @@ -9,6 +9,7 @@ #include "flutter/fml/memory/ref_ptr.h" #include "flutter/fml/trace_event.h" #include "impeller/core/formats.h" +#include "impeller/renderer/backend/vulkan/capabilities_vk.h" #include "impeller/renderer/backend/vulkan/device_buffer_vk.h" #include "impeller/renderer/backend/vulkan/formats_vk.h" #include "impeller/renderer/backend/vulkan/texture_vk.h" @@ -279,14 +280,16 @@ static VmaAllocationCreateFlags ToVmaAllocationCreateFlags(StorageMode mode) { class AllocatedTextureSourceVK final : public TextureSourceVK { public: - AllocatedTextureSourceVK(std::weak_ptr resource_manager, + AllocatedTextureSourceVK(const ContextVK& context, const TextureDescriptor& desc, VmaAllocator allocator, vk::Device device, bool supports_memoryless_textures) - : TextureSourceVK(desc), resource_(std::move(resource_manager)) { + : TextureSourceVK(desc), resource_(context.GetResourceManager()) { FML_DCHECK(desc.format != PixelFormat::kUnknown); - vk::ImageCreateInfo image_info; + vk::StructureChain + image_info_chain; + auto& image_info = image_info_chain.get(); image_info.flags = ToVKImageCreateFlags(desc.type); image_info.imageType = vk::ImageType::e2D; image_info.format = ToVKImageFormat(desc.format); @@ -305,6 +308,27 @@ class AllocatedTextureSourceVK final : public TextureSourceVK { supports_memoryless_textures); image_info.sharingMode = vk::SharingMode::eExclusive; + vk::ImageCompressionFixedRateFlagsEXT frc_rates[1] = { + vk::ImageCompressionFixedRateFlagBitsEXT::eNone}; + + const auto frc_rate = + CapabilitiesVK::Cast(*context.GetCapabilities()) + .GetSupportedFRCRate(desc.compression_type, + FRCFormatDescriptor{image_info}); + if (frc_rate.has_value()) { + // This array must not be in a temporary scope. + frc_rates[0] = frc_rate.value(); + + auto& compression_info = + image_info_chain.get(); + compression_info.pFixedRateFlags = frc_rates; + compression_info.compressionControlPlaneCount = 1u; + compression_info.flags = + vk::ImageCompressionFlagBitsEXT::eFixedRateExplicit; + } else { + image_info_chain.unlink(); + } + VmaAllocationCreateInfo alloc_nfo = {}; alloc_nfo.usage = ToVMAMemoryUsage(); @@ -444,11 +468,11 @@ std::shared_ptr AllocatorVK::OnCreateTexture( return nullptr; } auto source = std::make_shared( - ContextVK::Cast(*context).GetResourceManager(), // - desc, // - allocator_.get(), // - device_holder->GetDevice(), // - supports_memoryless_textures_ // + ContextVK::Cast(*context), // + desc, // + allocator_.get(), // + device_holder->GetDevice(), // + supports_memoryless_textures_ // ); if (!source->IsValid()) { return nullptr; diff --git a/impeller/renderer/backend/vulkan/capabilities_vk.cc b/impeller/renderer/backend/vulkan/capabilities_vk.cc index 7b465b70408c7..252fbb7d64f5e 100644 --- a/impeller/renderer/backend/vulkan/capabilities_vk.cc +++ b/impeller/renderer/backend/vulkan/capabilities_vk.cc @@ -199,6 +199,10 @@ static const char* GetExtensionName(OptionalDeviceExtensionVK ext) { return VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME; case OptionalDeviceExtensionVK::kVKKHRPortabilitySubset: return "VK_KHR_portability_subset"; + case OptionalDeviceExtensionVK::kEXTImageCompressionControl: + return VK_EXT_IMAGE_COMPRESSION_CONTROL_EXTENSION_NAME; + case OptionalDeviceExtensionVK::kEXTImageCompressionControlSwapchain: + return VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_EXTENSION_NAME; case OptionalDeviceExtensionVK::kLast: return "Unknown"; } @@ -398,6 +402,39 @@ CapabilitiesVK::GetEnabledDeviceFeatures( required.samplerYcbcrConversion = supported.samplerYcbcrConversion; } + // VK_EXT_image_compression_control + if (IsExtensionInList( + enabled_extensions.value(), + OptionalDeviceExtensionVK::kEXTImageCompressionControl)) { + auto& required = + required_chain + .get(); + const auto& supported = + supported_chain + .get(); + + required.imageCompressionControl = supported.imageCompressionControl; + } else { + required_chain + .unlink(); + } + + // VK_EXT_image_compression_control_swapchain + if (IsExtensionInList( + enabled_extensions.value(), + OptionalDeviceExtensionVK::kEXTImageCompressionControlSwapchain)) { + auto& required = required_chain.get< + vk::PhysicalDeviceImageCompressionControlSwapchainFeaturesEXT>(); + const auto& supported = supported_chain.get< + vk::PhysicalDeviceImageCompressionControlSwapchainFeaturesEXT>(); + + required.imageCompressionControlSwapchain = + supported.imageCompressionControlSwapchain; + } else { + required_chain.unlink< + vk::PhysicalDeviceImageCompressionControlSwapchainFeaturesEXT>(); + } + // Vulkan 1.1 { auto& required = @@ -434,7 +471,9 @@ void CapabilitiesVK::SetOffscreenFormat(PixelFormat pixel_format) const { default_color_format_ = pixel_format; } -bool CapabilitiesVK::SetPhysicalDevice(const vk::PhysicalDevice& device) { +bool CapabilitiesVK::SetPhysicalDevice( + const vk::PhysicalDevice& device, + const PhysicalDeviceFeatures& enabled_features) { if (HasSuitableColorFormat(device, vk::Format::eR8G8B8A8Unorm)) { default_color_format_ = PixelFormat::kR8G8B8A8UNormInt; } else { @@ -456,6 +495,7 @@ bool CapabilitiesVK::SetPhysicalDevice(const vk::PhysicalDevice& device) { default_stencil_format_ = default_depth_stencil_format_; } + physical_device_ = device; device_properties_ = device.getProperties(); auto physical_properties_2 = @@ -518,6 +558,19 @@ bool CapabilitiesVK::SetPhysicalDevice(const vk::PhysicalDevice& device) { }); } + supports_texture_fixed_rate_compression_ = + enabled_features + .isLinked() && + enabled_features + .get() + .imageCompressionControl; + supports_swapchain_fixed_rate_compression_ = + enabled_features.isLinked< + vk::PhysicalDeviceImageCompressionControlSwapchainFeaturesEXT>() && + enabled_features + .get() + .imageCompressionControlSwapchain; + return true; } @@ -611,4 +664,58 @@ bool CapabilitiesVK::HasExtension(OptionalDeviceExtensionVK ext) const { optional_device_extensions_.end(); } +bool CapabilitiesVK::SupportsTextureFixedRateCompression() const { + return supports_texture_fixed_rate_compression_; +} + +bool CapabilitiesVK::SupportsSwapchainFixedRateCompression() const { + return supports_swapchain_fixed_rate_compression_; +} + +std::optional +CapabilitiesVK::GetSupportedFRCRate(CompressionType compression_type, + const FRCFormatDescriptor& desc) const { + if (compression_type != CompressionType::kLossy) { + return std::nullopt; + } + if (!supports_texture_fixed_rate_compression_) { + return std::nullopt; + } + // There are opportunities to hash and cache the FRCFormatDescriptor if + // needed. + vk::StructureChain + format_chain; + + auto& format_info = format_chain.get(); + + format_info.format = desc.format; + format_info.type = desc.type; + format_info.tiling = desc.tiling; + format_info.usage = desc.usage; + format_info.flags = desc.flags; + + auto& compression = format_chain.get(); + compression.flags = vk::ImageCompressionFlagBitsEXT::eFixedRateExplicit; + + const auto [result, supported] = physical_device_.getImageFormatProperties2< + vk::ImageFormatProperties2, vk::ImageCompressionPropertiesEXT>( + format_chain.get()); + if (result != vk::Result::eSuccess) { + VALIDATION_LOG << "Could not query image format properties: " + << vk::to_string(result); + return std::nullopt; + } + + const auto kIdealFRCRate = vk::ImageCompressionFixedRateFlagBitsEXT::e4Bpc; + + if (supported.get() + .imageCompressionFixedRateFlags & + kIdealFRCRate) { + return kIdealFRCRate; + } + + return std::nullopt; +} + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/capabilities_vk.h b/impeller/renderer/backend/vulkan/capabilities_vk.h index 632a96a4bec01..048ad31091635 100644 --- a/impeller/renderer/backend/vulkan/capabilities_vk.h +++ b/impeller/renderer/backend/vulkan/capabilities_vk.h @@ -7,11 +7,13 @@ #include #include +#include #include #include #include #include "impeller/base/backend_cast.h" +#include "impeller/core/texture_descriptor.h" #include "impeller/renderer/backend/vulkan/vk.h" #include "impeller/renderer/capabilities.h" @@ -131,9 +133,38 @@ enum class OptionalDeviceExtensionVK : uint32_t { /// kVKKHRPortabilitySubset, + //---------------------------------------------------------------------------- + /// For fixed-rate compression of images. + /// + /// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_image_compression_control.html + /// + kEXTImageCompressionControl, + + //---------------------------------------------------------------------------- + /// For fixed-rate compression of swapchain images. + /// + /// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_image_compression_control_swapchain.html + /// + kEXTImageCompressionControlSwapchain, + kLast, }; +struct FRCFormatDescriptor { + vk::Format format = vk::Format::eUndefined; + vk::ImageType type = {}; + vk::ImageTiling tiling = {}; + vk::ImageUsageFlags usage = {}; + vk::ImageCreateFlags flags = {}; + + explicit FRCFormatDescriptor(const vk::ImageCreateInfo& image_info) + : format(image_info.format), + type(image_info.imageType), + tiling(image_info.tiling), + usage(image_info.usage), + flags(image_info.flags) {} +}; + //------------------------------------------------------------------------------ /// @brief The Vulkan layers and extensions wrangler. /// @@ -162,16 +193,19 @@ class CapabilitiesVK final : public Capabilities, std::optional> GetEnabledDeviceExtensions( const vk::PhysicalDevice& physical_device) const; - using PhysicalDeviceFeatures = - vk::StructureChain; + using PhysicalDeviceFeatures = vk::StructureChain< + vk::PhysicalDeviceFeatures2, + vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR, + vk::PhysicalDevice16BitStorageFeatures, + vk::PhysicalDeviceImageCompressionControlFeaturesEXT, + vk::PhysicalDeviceImageCompressionControlSwapchainFeaturesEXT>; std::optional GetEnabledDeviceFeatures( const vk::PhysicalDevice& physical_device) const; [[nodiscard]] bool SetPhysicalDevice( - const vk::PhysicalDevice& physical_device); + const vk::PhysicalDevice& physical_device, + const PhysicalDeviceFeatures& enabled_features); const vk::PhysicalDeviceProperties& GetPhysicalDeviceProperties() const; @@ -219,6 +253,14 @@ class CapabilitiesVK final : public Capabilities, // |Capabilities| PixelFormat GetDefaultGlyphAtlasFormat() const override; + bool SupportsTextureFixedRateCompression() const; + + bool SupportsSwapchainFixedRateCompression() const; + + std::optional GetSupportedFRCRate( + CompressionType compression_type, + const FRCFormatDescriptor& desc) const; + private: bool validations_enabled_ = false; std::map> exts_; @@ -229,9 +271,12 @@ class CapabilitiesVK final : public Capabilities, mutable PixelFormat default_color_format_ = PixelFormat::kUnknown; PixelFormat default_stencil_format_ = PixelFormat::kUnknown; PixelFormat default_depth_stencil_format_ = PixelFormat::kUnknown; + vk::PhysicalDevice physical_device_; vk::PhysicalDeviceProperties device_properties_; bool supports_compute_subgroups_ = false; bool supports_device_transient_textures_ = false; + bool supports_texture_fixed_rate_compression_ = false; + bool supports_swapchain_fixed_rate_compression_ = false; bool is_valid_ = false; bool HasExtension(const std::string& ext) const; diff --git a/impeller/renderer/backend/vulkan/context_vk.cc b/impeller/renderer/backend/vulkan/context_vk.cc index 58f6fa923f96a..d666570b9026b 100644 --- a/impeller/renderer/backend/vulkan/context_vk.cc +++ b/impeller/renderer/backend/vulkan/context_vk.cc @@ -339,7 +339,8 @@ void ContextVK::Setup(Settings settings) { device_holder->device = std::move(device_result.value); } - if (!caps->SetPhysicalDevice(device_holder->physical_device)) { + if (!caps->SetPhysicalDevice(device_holder->physical_device, + *enabled_features)) { VALIDATION_LOG << "Capabilities could not be updated."; return; }