[Impeller] Check for lazy memory support. (flutter/engine#43339)

Some Android devices do not support the memory type eLazilyAllocated, which we use for MSAA and stencil textures. These textures were falling back to device local in dedicated allocations, which are expensive to both allocate and free. The dedicated allocation is implied by asking for eLazilyAllocated

Instead, perform a check for support for this memory type. Never request dedicated allocations (at least not until we have a compelling use case)

This should fix https://github.com/flutter/flutter/issues/129737

https://github.com/flutter/flutter/issues/129784
This commit is contained in:
Jonah Williams 2023-06-29 15:16:57 -07:00 committed by GitHub
parent 2523231c29
commit eee7308d1f
10 changed files with 95 additions and 20 deletions

View File

@ -76,6 +76,7 @@ ContextGLES::ContextGLES(std::unique_ptr<ProcTableGLES> gl,
.SetSupportsReadFromResolve(false)
.SetSupportsReadFromOnscreenTexture(false)
.SetSupportsDecalTileMode(false)
.SetSupportsMemorylessTextures(false)
.Build();
}

View File

@ -64,6 +64,7 @@ static std::unique_ptr<Capabilities> InferMetalCapabilities(
.SetSupportsComputeSubgroups(DeviceSupportsComputeSubgroups(device))
.SetSupportsReadFromResolve(true)
.SetSupportsReadFromOnscreenTexture(true)
.SetSupportsMemorylessTextures(true)
.Build();
}

View File

@ -21,7 +21,8 @@ AllocatorVK::AllocatorVK(std::weak_ptr<Context> context,
const std::shared_ptr<DeviceHolder>& device_holder,
const vk::Instance& instance,
PFN_vkGetInstanceProcAddr get_instance_proc_address,
PFN_vkGetDeviceProcAddr get_device_proc_address)
PFN_vkGetDeviceProcAddr get_device_proc_address,
const CapabilitiesVK& capabilities)
: context_(std::move(context)), device_holder_(device_holder) {
TRACE_EVENT0("impeller", "CreateAllocatorVK");
vk_ = fml::MakeRefCounted<vulkan::VulkanProcTable>(get_instance_proc_address);
@ -92,6 +93,7 @@ AllocatorVK::AllocatorVK(std::weak_ptr<Context> context,
return;
}
allocator_ = allocator;
supports_memoryless_textures_ = capabilities.SupportsMemorylessTextures();
is_valid_ = true;
}
@ -112,9 +114,11 @@ ISize AllocatorVK::GetMaxTextureSizeSupported() const {
return max_texture_size_;
}
static constexpr vk::ImageUsageFlags ToVKImageUsageFlags(PixelFormat format,
TextureUsageMask usage,
StorageMode mode) {
static constexpr vk::ImageUsageFlags ToVKImageUsageFlags(
PixelFormat format,
TextureUsageMask usage,
StorageMode mode,
bool supports_memoryless_textures) {
vk::ImageUsageFlags vk_usage;
switch (mode) {
@ -122,7 +126,9 @@ static constexpr vk::ImageUsageFlags ToVKImageUsageFlags(PixelFormat format,
case StorageMode::kDevicePrivate:
break;
case StorageMode::kDeviceTransient:
vk_usage |= vk::ImageUsageFlagBits::eTransientAttachment;
if (supports_memoryless_textures) {
vk_usage |= vk::ImageUsageFlagBits::eTransientAttachment;
}
break;
}
@ -170,7 +176,25 @@ static constexpr VmaMemoryUsage ToVMAMemoryUsage() {
return VMA_MEMORY_USAGE_AUTO;
}
static constexpr VkMemoryPropertyFlags ToVKMemoryPropertyFlags(
static constexpr VkMemoryPropertyFlags ToVKTextureMemoryPropertyFlags(
StorageMode mode,
bool supports_memoryless_textures) {
switch (mode) {
case StorageMode::kHostVisible:
return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
case StorageMode::kDevicePrivate:
return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
case StorageMode::kDeviceTransient:
if (supports_memoryless_textures) {
return VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT |
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
}
return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
}
FML_UNREACHABLE();
}
static constexpr VkMemoryPropertyFlags ToVKBufferMemoryPropertyFlags(
StorageMode mode) {
switch (mode) {
case StorageMode::kHostVisible:
@ -198,9 +222,6 @@ static VmaAllocationCreateFlags ToVmaAllocationCreateFlags(StorageMode mode,
}
return flags;
case StorageMode::kDevicePrivate:
if (is_texture) {
flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
}
return flags;
case StorageMode::kDeviceTransient:
return flags;
@ -212,7 +233,8 @@ class AllocatedTextureSourceVK final : public TextureSourceVK {
public:
AllocatedTextureSourceVK(const TextureDescriptor& desc,
VmaAllocator allocator,
vk::Device device)
vk::Device device,
bool supports_memoryless_textures)
: TextureSourceVK(desc) {
TRACE_EVENT0("impeller", "CreateDeviceTexture");
vk::ImageCreateInfo image_info;
@ -230,13 +252,15 @@ class AllocatedTextureSourceVK final : public TextureSourceVK {
image_info.tiling = vk::ImageTiling::eOptimal;
image_info.initialLayout = vk::ImageLayout::eUndefined;
image_info.usage =
ToVKImageUsageFlags(desc.format, desc.usage, desc.storage_mode);
ToVKImageUsageFlags(desc.format, desc.usage, desc.storage_mode,
supports_memoryless_textures);
image_info.sharingMode = vk::SharingMode::eExclusive;
VmaAllocationCreateInfo alloc_nfo = {};
alloc_nfo.usage = ToVMAMemoryUsage();
alloc_nfo.preferredFlags = ToVKMemoryPropertyFlags(desc.storage_mode);
alloc_nfo.preferredFlags = ToVKTextureMemoryPropertyFlags(
desc.storage_mode, supports_memoryless_textures);
alloc_nfo.flags = ToVmaAllocationCreateFlags(desc.storage_mode, true);
auto create_info_native =
@ -340,11 +364,12 @@ std::shared_ptr<Texture> AllocatorVK::OnCreateTexture(
if (!device_holder) {
return nullptr;
}
auto source =
std::make_shared<AllocatedTextureSourceVK>(desc, //
allocator_, //
device_holder->GetDevice() //
);
auto source = std::make_shared<AllocatedTextureSourceVK>(
desc, //
allocator_, //
device_holder->GetDevice(), //
supports_memoryless_textures_ //
);
if (!source->IsValid()) {
return nullptr;
}
@ -369,7 +394,8 @@ std::shared_ptr<DeviceBuffer> AllocatorVK::OnCreateBuffer(
VmaAllocationCreateInfo allocation_info = {};
allocation_info.usage = ToVMAMemoryUsage();
allocation_info.preferredFlags = ToVKMemoryPropertyFlags(desc.storage_mode);
allocation_info.preferredFlags =
ToVKBufferMemoryPropertyFlags(desc.storage_mode);
allocation_info.flags = ToVmaAllocationCreateFlags(desc.storage_mode, false);
VkBuffer buffer = {};

View File

@ -31,6 +31,7 @@ class AllocatorVK final : public Allocator {
std::weak_ptr<DeviceHolder> device_holder_;
ISize max_texture_size_;
bool is_valid_ = false;
bool supports_memoryless_textures_ = false;
AllocatorVK(std::weak_ptr<Context> context,
uint32_t vulkan_api_version,
@ -38,7 +39,8 @@ class AllocatorVK final : public Allocator {
const std::shared_ptr<DeviceHolder>& device_holder,
const vk::Instance& instance,
PFN_vkGetInstanceProcAddr get_instance_proc_address,
PFN_vkGetDeviceProcAddr get_device_proc_address);
PFN_vkGetDeviceProcAddr get_device_proc_address,
const CapabilitiesVK& capabilities);
// |Allocator|
bool IsValid() const;

View File

@ -348,6 +348,21 @@ bool CapabilitiesVK::SetPhysicalDevice(const vk::PhysicalDevice& device) {
.supportedOperations &
vk::SubgroupFeatureFlagBits::eArithmetic);
{
// Query texture support.
// TODO(jonahwilliams):
// https://github.com/flutter/flutter/issues/129784
vk::PhysicalDeviceMemoryProperties memory_properties;
device.getMemoryProperties(&memory_properties);
for (auto i = 0u; i < memory_properties.memoryTypeCount; i++) {
if (memory_properties.memoryTypes[i].propertyFlags &
vk::MemoryPropertyFlagBits::eLazilyAllocated) {
supports_memoryless_textures_ = true;
}
}
}
// Determine the optional device extensions this physical device supports.
{
optional_device_extensions_.clear();
@ -422,6 +437,11 @@ bool CapabilitiesVK::SupportsDecalTileMode() const {
return true;
}
// |Capabilities|
bool CapabilitiesVK::SupportsMemorylessTextures() const {
return supports_memoryless_textures_;
}
// |Capabilities|
PixelFormat CapabilitiesVK::GetDefaultColorFormat() const {
return color_format_;

View File

@ -90,6 +90,9 @@ class CapabilitiesVK final : public Capabilities,
// |Capabilities|
bool SupportsDecalTileMode() const override;
// |Capabilities|
bool SupportsMemorylessTextures() const override;
// |Capabilities|
PixelFormat GetDefaultColorFormat() const override;
@ -104,6 +107,7 @@ class CapabilitiesVK final : public Capabilities,
PixelFormat depth_stencil_format_ = PixelFormat::kUnknown;
vk::PhysicalDeviceProperties device_properties_;
bool supports_compute_subgroups_ = false;
bool supports_memoryless_textures_ = false;
bool is_valid_ = false;
bool HasExtension(const std::string& ext) const;

View File

@ -332,7 +332,8 @@ void ContextVK::Setup(Settings settings) {
device_holder, //
device_holder->instance.get(), //
dispatcher.vkGetInstanceProcAddr, //
dispatcher.vkGetDeviceProcAddr //
dispatcher.vkGetDeviceProcAddr, //
*caps //
));
if (!allocator->IsValid()) {

View File

@ -76,6 +76,10 @@ class StandardCapabilities final : public Capabilities {
return default_stencil_format_;
}
bool SupportsMemorylessTextures() const override {
return supports_memoryless_textures_;
}
private:
StandardCapabilities(bool has_threading_restrictions,
bool supports_offscreen_msaa,
@ -88,6 +92,7 @@ class StandardCapabilities final : public Capabilities {
bool supports_read_from_onscreen_texture,
bool supports_read_from_resolve,
bool supports_decal_tile_mode,
bool supports_memoryless_textures,
PixelFormat default_color_format,
PixelFormat default_stencil_format)
: has_threading_restrictions_(has_threading_restrictions),
@ -102,6 +107,7 @@ class StandardCapabilities final : public Capabilities {
supports_read_from_onscreen_texture),
supports_read_from_resolve_(supports_read_from_resolve),
supports_decal_tile_mode_(supports_decal_tile_mode),
supports_memoryless_textures_(supports_memoryless_textures),
default_color_format_(default_color_format),
default_stencil_format_(default_stencil_format) {}
@ -118,6 +124,7 @@ class StandardCapabilities final : public Capabilities {
bool supports_read_from_onscreen_texture_ = false;
bool supports_read_from_resolve_ = false;
bool supports_decal_tile_mode_ = false;
bool supports_memoryless_textures_ = false;
PixelFormat default_color_format_ = PixelFormat::kUnknown;
PixelFormat default_stencil_format_ = PixelFormat::kUnknown;
@ -202,6 +209,12 @@ CapabilitiesBuilder& CapabilitiesBuilder::SetSupportsDecalTileMode(bool value) {
return *this;
}
CapabilitiesBuilder& CapabilitiesBuilder::SetSupportsMemorylessTextures(
bool value) {
supports_memoryless_textures_ = value;
return *this;
}
std::unique_ptr<Capabilities> CapabilitiesBuilder::Build() {
return std::unique_ptr<StandardCapabilities>(new StandardCapabilities( //
has_threading_restrictions_, //
@ -215,6 +228,7 @@ std::unique_ptr<Capabilities> CapabilitiesBuilder::Build() {
supports_read_from_onscreen_texture_, //
supports_read_from_resolve_, //
supports_decal_tile_mode_, //
supports_memoryless_textures_, //
default_color_format_.value_or(PixelFormat::kUnknown), //
default_stencil_format_.value_or(PixelFormat::kUnknown) //
));

View File

@ -37,6 +37,8 @@ class Capabilities {
virtual bool SupportsDecalTileMode() const = 0;
virtual bool SupportsMemorylessTextures() const = 0;
virtual PixelFormat GetDefaultColorFormat() const = 0;
virtual PixelFormat GetDefaultStencilFormat() const = 0;
@ -79,6 +81,8 @@ class CapabilitiesBuilder {
CapabilitiesBuilder& SetSupportsDecalTileMode(bool value);
CapabilitiesBuilder& SetSupportsMemorylessTextures(bool value);
std::unique_ptr<Capabilities> Build();
private:
@ -93,6 +97,7 @@ class CapabilitiesBuilder {
bool supports_read_from_onscreen_texture_ = false;
bool supports_read_from_resolve_ = false;
bool supports_decal_tile_mode_ = false;
bool supports_memoryless_textures_ = false;
std::optional<PixelFormat> default_color_format_ = std::nullopt;
std::optional<PixelFormat> default_stencil_format_ = std::nullopt;

View File

@ -29,6 +29,7 @@ CAPABILITY_TEST(SupportsComputeSubgroups, false);
CAPABILITY_TEST(SupportsReadFromOnscreenTexture, false);
CAPABILITY_TEST(SupportsReadFromResolve, false);
CAPABILITY_TEST(SupportsDecalTileMode, false);
CAPABILITY_TEST(SupportsMemorylessTextures, false);
} // namespace testing
} // namespace impeller