Skip to content
This repository has been archived by the owner on Feb 25, 2025. It is now read-only.

[Impeller] Enable fixed rate compression. #53079

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 32 additions & 8 deletions impeller/renderer/backend/vulkan/allocator_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -279,14 +280,16 @@ static VmaAllocationCreateFlags ToVmaAllocationCreateFlags(StorageMode mode) {

class AllocatedTextureSourceVK final : public TextureSourceVK {
public:
AllocatedTextureSourceVK(std::weak_ptr<ResourceManagerVK> 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<vk::ImageCreateInfo, vk::ImageCompressionControlEXT>
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);
Expand All @@ -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<vk::ImageCompressionControlEXT>();
compression_info.pFixedRateFlags = frc_rates;
compression_info.compressionControlPlaneCount = 1u;
compression_info.flags =
vk::ImageCompressionFlagBitsEXT::eFixedRateExplicit;
} else {
image_info_chain.unlink<vk::ImageCompressionControlEXT>();
}

VmaAllocationCreateInfo alloc_nfo = {};

alloc_nfo.usage = ToVMAMemoryUsage();
Expand Down Expand Up @@ -444,11 +468,11 @@ std::shared_ptr<Texture> AllocatorVK::OnCreateTexture(
return nullptr;
}
auto source = std::make_shared<AllocatedTextureSourceVK>(
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;
Expand Down
109 changes: 108 additions & 1 deletion impeller/renderer/backend/vulkan/capabilities_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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";
}
Expand Down Expand Up @@ -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<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
const auto& supported =
supported_chain
.get<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();

required.imageCompressionControl = supported.imageCompressionControl;
} else {
required_chain
.unlink<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
}

// 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 =
Expand Down Expand Up @@ -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 {
Expand All @@ -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 =
Expand Down Expand Up @@ -518,6 +558,19 @@ bool CapabilitiesVK::SetPhysicalDevice(const vk::PhysicalDevice& device) {
});
}

supports_texture_fixed_rate_compression_ =
enabled_features
.isLinked<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>() &&
enabled_features
.get<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>()
.imageCompressionControl;
supports_swapchain_fixed_rate_compression_ =
enabled_features.isLinked<
vk::PhysicalDeviceImageCompressionControlSwapchainFeaturesEXT>() &&
enabled_features
.get<vk::PhysicalDeviceImageCompressionControlSwapchainFeaturesEXT>()
.imageCompressionControlSwapchain;

return true;
}

Expand Down Expand Up @@ -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<vk::ImageCompressionFixedRateFlagBitsEXT>
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<vk::PhysicalDeviceImageFormatInfo2,
vk::ImageCompressionControlEXT>
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<vk::ImageCompressionControlEXT>();
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<vk::ImageCompressionPropertiesEXT>()
.imageCompressionFixedRateFlags &
kIdealFRCRate) {
return kIdealFRCRate;
}

return std::nullopt;
}

} // namespace impeller
55 changes: 50 additions & 5 deletions impeller/renderer/backend/vulkan/capabilities_vk.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@

#include <cstdint>
#include <map>
#include <optional>
#include <set>
#include <string>
#include <vector>

#include "impeller/base/backend_cast.h"
#include "impeller/core/texture_descriptor.h"
#include "impeller/renderer/backend/vulkan/vk.h"
#include "impeller/renderer/capabilities.h"

Expand Down Expand Up @@ -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.
///
Expand Down Expand Up @@ -162,16 +193,19 @@ class CapabilitiesVK final : public Capabilities,
std::optional<std::vector<std::string>> GetEnabledDeviceExtensions(
const vk::PhysicalDevice& physical_device) const;

using PhysicalDeviceFeatures =
vk::StructureChain<vk::PhysicalDeviceFeatures2,
vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR,
vk::PhysicalDevice16BitStorageFeatures>;
using PhysicalDeviceFeatures = vk::StructureChain<
vk::PhysicalDeviceFeatures2,
vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR,
vk::PhysicalDevice16BitStorageFeatures,
vk::PhysicalDeviceImageCompressionControlFeaturesEXT,
vk::PhysicalDeviceImageCompressionControlSwapchainFeaturesEXT>;

std::optional<PhysicalDeviceFeatures> 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;

Expand Down Expand Up @@ -219,6 +253,14 @@ class CapabilitiesVK final : public Capabilities,
// |Capabilities|
PixelFormat GetDefaultGlyphAtlasFormat() const override;

bool SupportsTextureFixedRateCompression() const;

bool SupportsSwapchainFixedRateCompression() const;

std::optional<vk::ImageCompressionFixedRateFlagBitsEXT> GetSupportedFRCRate(
CompressionType compression_type,
const FRCFormatDescriptor& desc) const;

private:
bool validations_enabled_ = false;
std::map<std::string, std::set<std::string>> exts_;
Expand All @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion impeller/renderer/backend/vulkan/context_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down