From eee7308d1f79c2913285dc606f2d90726d09cc40 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Thu, 29 Jun 2023 15:16:57 -0700 Subject: [PATCH] [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 --- .../renderer/backend/gles/context_gles.cc | 1 + .../renderer/backend/metal/context_mtl.mm | 1 + .../renderer/backend/vulkan/allocator_vk.cc | 62 +++++++++++++------ .../renderer/backend/vulkan/allocator_vk.h | 4 +- .../backend/vulkan/capabilities_vk.cc | 20 ++++++ .../renderer/backend/vulkan/capabilities_vk.h | 4 ++ .../renderer/backend/vulkan/context_vk.cc | 3 +- .../flutter/impeller/renderer/capabilities.cc | 14 +++++ .../flutter/impeller/renderer/capabilities.h | 5 ++ .../renderer/capabilities_unittests.cc | 1 + 10 files changed, 95 insertions(+), 20 deletions(-) diff --git a/engine/src/flutter/impeller/renderer/backend/gles/context_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/context_gles.cc index 4f590e2b2d7..34b095d46ab 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/context_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/context_gles.cc @@ -76,6 +76,7 @@ ContextGLES::ContextGLES(std::unique_ptr gl, .SetSupportsReadFromResolve(false) .SetSupportsReadFromOnscreenTexture(false) .SetSupportsDecalTileMode(false) + .SetSupportsMemorylessTextures(false) .Build(); } diff --git a/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.mm b/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.mm index 223762608b1..db2c1fef0cc 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.mm +++ b/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.mm @@ -64,6 +64,7 @@ static std::unique_ptr InferMetalCapabilities( .SetSupportsComputeSubgroups(DeviceSupportsComputeSubgroups(device)) .SetSupportsReadFromResolve(true) .SetSupportsReadFromOnscreenTexture(true) + .SetSupportsMemorylessTextures(true) .Build(); } diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/allocator_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/allocator_vk.cc index cf9794d9ecf..a94eba6b16b 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/allocator_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/allocator_vk.cc @@ -21,7 +21,8 @@ AllocatorVK::AllocatorVK(std::weak_ptr context, const std::shared_ptr& 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(get_instance_proc_address); @@ -92,6 +93,7 @@ AllocatorVK::AllocatorVK(std::weak_ptr 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 AllocatorVK::OnCreateTexture( if (!device_holder) { return nullptr; } - auto source = - std::make_shared(desc, // - allocator_, // - device_holder->GetDevice() // - ); + auto source = std::make_shared( + desc, // + allocator_, // + device_holder->GetDevice(), // + supports_memoryless_textures_ // + ); if (!source->IsValid()) { return nullptr; } @@ -369,7 +394,8 @@ std::shared_ptr 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 = {}; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/allocator_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/allocator_vk.h index 64b9ba4c2ac..fba13f2b7cf 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/allocator_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/allocator_vk.h @@ -31,6 +31,7 @@ class AllocatorVK final : public Allocator { std::weak_ptr device_holder_; ISize max_texture_size_; bool is_valid_ = false; + bool supports_memoryless_textures_ = false; AllocatorVK(std::weak_ptr context, uint32_t vulkan_api_version, @@ -38,7 +39,8 @@ class AllocatorVK final : public Allocator { const std::shared_ptr& 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; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.cc index 84585b84ec3..a09c13b568e 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.cc @@ -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_; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.h index 98614011206..ffa96d46bc9 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.h @@ -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; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc index 3af8a62fbbc..0b1fc69001e 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc @@ -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()) { diff --git a/engine/src/flutter/impeller/renderer/capabilities.cc b/engine/src/flutter/impeller/renderer/capabilities.cc index 9e2c9201bb6..d0c9f623480 100644 --- a/engine/src/flutter/impeller/renderer/capabilities.cc +++ b/engine/src/flutter/impeller/renderer/capabilities.cc @@ -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 CapabilitiesBuilder::Build() { return std::unique_ptr(new StandardCapabilities( // has_threading_restrictions_, // @@ -215,6 +228,7 @@ std::unique_ptr 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) // )); diff --git a/engine/src/flutter/impeller/renderer/capabilities.h b/engine/src/flutter/impeller/renderer/capabilities.h index 6fb1118dd7c..87a7f9df088 100644 --- a/engine/src/flutter/impeller/renderer/capabilities.h +++ b/engine/src/flutter/impeller/renderer/capabilities.h @@ -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 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 default_color_format_ = std::nullopt; std::optional default_stencil_format_ = std::nullopt; diff --git a/engine/src/flutter/impeller/renderer/capabilities_unittests.cc b/engine/src/flutter/impeller/renderer/capabilities_unittests.cc index 1dc9d17e3c6..9d8a9f38627 100644 --- a/engine/src/flutter/impeller/renderer/capabilities_unittests.cc +++ b/engine/src/flutter/impeller/renderer/capabilities_unittests.cc @@ -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