[Impeller] Enable fixed-rate compression support in Vulkan. (flutter/engine#53292)
Fixes https://github.com/flutter/flutter/issues/129501
This commit is contained in:
parent
0fa80539c5
commit
412e42ae83
@ -10,6 +10,7 @@
|
||||
#include "flutter/fml/trace_event.h"
|
||||
#include "impeller/base/allocation_size.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"
|
||||
@ -280,14 +281,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);
|
||||
@ -306,6 +309,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();
|
||||
@ -445,11 +469,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;
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "impeller/renderer/backend/vulkan/capabilities_vk.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
|
||||
#include "impeller/base/validation.h"
|
||||
#include "impeller/core/formats.h"
|
||||
@ -199,6 +200,8 @@ 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::kLast:
|
||||
return "Unknown";
|
||||
}
|
||||
@ -371,6 +374,17 @@ CapabilitiesVK::GetEnabledDeviceFeatures(
|
||||
}
|
||||
|
||||
PhysicalDeviceFeatures supported_chain;
|
||||
|
||||
// Swiftshader seems to be fussy about just this structure even being in the
|
||||
// chain. Just unlink it if its not supported. We already perform an
|
||||
// extensions check on the other side when reading.
|
||||
if (!IsExtensionInList(
|
||||
enabled_extensions.value(),
|
||||
OptionalDeviceExtensionVK::kEXTImageCompressionControl)) {
|
||||
supported_chain
|
||||
.unlink<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>();
|
||||
}
|
||||
|
||||
device.getFeatures2(&supported_chain.get());
|
||||
|
||||
PhysicalDeviceFeatures required_chain;
|
||||
@ -398,6 +412,23 @@ 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>();
|
||||
}
|
||||
|
||||
// Vulkan 1.1
|
||||
{
|
||||
auto& required =
|
||||
@ -434,7 +465,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 +489,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 +552,13 @@ bool CapabilitiesVK::SetPhysicalDevice(const vk::PhysicalDevice& device) {
|
||||
});
|
||||
}
|
||||
|
||||
supports_texture_fixed_rate_compression_ =
|
||||
enabled_features
|
||||
.isLinked<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>() &&
|
||||
enabled_features
|
||||
.get<vk::PhysicalDeviceImageCompressionControlFeaturesEXT>()
|
||||
.imageCompressionControl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -611,4 +652,61 @@ bool CapabilitiesVK::HasExtension(OptionalDeviceExtensionVK ext) const {
|
||||
optional_device_extensions_.end();
|
||||
}
|
||||
|
||||
bool CapabilitiesVK::SupportsTextureFixedRateCompression() const {
|
||||
return supports_texture_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;
|
||||
|
||||
const auto kIdealFRCRate = vk::ImageCompressionFixedRateFlagBitsEXT::e4Bpc;
|
||||
|
||||
std::array<vk::ImageCompressionFixedRateFlagsEXT, 1u> rates = {kIdealFRCRate};
|
||||
|
||||
auto& compression = format_chain.get<vk::ImageCompressionControlEXT>();
|
||||
compression.flags = vk::ImageCompressionFlagBitsEXT::eFixedRateExplicit;
|
||||
compression.compressionControlPlaneCount = rates.size();
|
||||
compression.pFixedRateFlags = rates.data();
|
||||
|
||||
const auto [result, supported] = physical_device_.getImageFormatProperties2<
|
||||
vk::ImageFormatProperties2, vk::ImageCompressionPropertiesEXT>(
|
||||
format_chain.get());
|
||||
|
||||
if (result != vk::Result::eSuccess ||
|
||||
!supported.isLinked<vk::ImageCompressionPropertiesEXT>()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const auto& compression_props =
|
||||
supported.get<vk::ImageCompressionPropertiesEXT>();
|
||||
|
||||
if ((compression_props.imageCompressionFlags &
|
||||
vk::ImageCompressionFlagBitsEXT::eFixedRateExplicit) &&
|
||||
(compression_props.imageCompressionFixedRateFlags & kIdealFRCRate)) {
|
||||
return kIdealFRCRate;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
@ -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"
|
||||
|
||||
@ -131,9 +133,36 @@ 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,
|
||||
|
||||
kLast,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @brief A pixel format and usage that is sufficient to check if images
|
||||
/// of that format and usage are suitable for use with fixed-rate
|
||||
/// compression.
|
||||
///
|
||||
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.
|
||||
///
|
||||
@ -165,13 +194,15 @@ class CapabilitiesVK final : public Capabilities,
|
||||
using PhysicalDeviceFeatures =
|
||||
vk::StructureChain<vk::PhysicalDeviceFeatures2,
|
||||
vk::PhysicalDeviceSamplerYcbcrConversionFeaturesKHR,
|
||||
vk::PhysicalDevice16BitStorageFeatures>;
|
||||
vk::PhysicalDevice16BitStorageFeatures,
|
||||
vk::PhysicalDeviceImageCompressionControlFeaturesEXT>;
|
||||
|
||||
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;
|
||||
|
||||
@ -219,6 +250,25 @@ class CapabilitiesVK final : public Capabilities,
|
||||
// |Capabilities|
|
||||
PixelFormat GetDefaultGlyphAtlasFormat() const override;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @return If fixed-rate compression for non-onscreen surfaces is
|
||||
/// supported.
|
||||
///
|
||||
bool SupportsTextureFixedRateCompression() const;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Get the fixed compression rate supported by the context for
|
||||
/// the given format and usage.
|
||||
///
|
||||
/// @param[in] compression_type The compression type.
|
||||
/// @param[in] desc The format and usage of the image.
|
||||
///
|
||||
/// @return The supported fixed compression rate.
|
||||
///
|
||||
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_;
|
||||
@ -229,9 +279,11 @@ 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 is_valid_ = false;
|
||||
|
||||
bool HasExtension(const std::string& ext) const;
|
||||
|
@ -338,7 +338,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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user