From a3a4995607f6dc13204da2f0e2541edac7fffbff Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Tue, 7 Jan 2025 13:51:54 -0800 Subject: [PATCH] [Impeller] disable runtime mipmap generation on Adreno. (#161257) I bypassed the ~compressor~ mip generation. https://github.com/flutter/flutter/issues/160441 https://github.com/flutter/flutter/issues/159876 https://github.com/flutter/flutter/issues/160587 I have no idea how to get this to work. next thing to try is to force mip generation to happen in a square power of 2 texture, and then blit the individual mip regions onto the dest texture. For now, disable, as the issue is quite severe. --- .../renderer/backend/vulkan/blit_pass_vk.cc | 7 ++-- .../renderer/backend/vulkan/blit_pass_vk.h | 5 ++- .../backend/vulkan/command_buffer_vk.cc | 7 +++- .../renderer/backend/vulkan/context_vk.cc | 10 ++++-- .../renderer/backend/vulkan/context_vk.h | 4 +++ .../vulkan/driver_info_vk_unittests.cc | 32 +++++++++++++++++-- .../renderer/backend/vulkan/workarounds_vk.cc | 3 +- .../renderer/backend/vulkan/workarounds_vk.h | 11 ++++++- 8 files changed, 67 insertions(+), 12 deletions(-) diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/blit_pass_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/blit_pass_vk.cc index dd964309c9215..4321c3b808ce5 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/blit_pass_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/blit_pass_vk.cc @@ -44,8 +44,9 @@ static void InsertImageMemoryBarrier(const vk::CommandBuffer& cmd, cmd.pipelineBarrier(src_stage, dst_stage, {}, nullptr, nullptr, barrier); } -BlitPassVK::BlitPassVK(std::shared_ptr command_buffer) - : command_buffer_(std::move(command_buffer)) {} +BlitPassVK::BlitPassVK(std::shared_ptr command_buffer, + const WorkaroundsVK& workarounds) + : command_buffer_(std::move(command_buffer)), workarounds_(workarounds) {} BlitPassVK::~BlitPassVK() = default; @@ -402,7 +403,7 @@ bool BlitPassVK::OnGenerateMipmapCommand(std::shared_ptr texture, const auto size = src.GetTextureDescriptor().size; uint32_t mip_count = src.GetTextureDescriptor().mip_count; - if (mip_count < 2u) { + if (mip_count < 2u || workarounds_.broken_mipmap_generation) { return true; } diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/blit_pass_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/blit_pass_vk.h index 200f7943995b0..44896f6f55d4e 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/blit_pass_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/blit_pass_vk.h @@ -7,6 +7,7 @@ #include "flutter/impeller/base/config.h" #include "impeller/geometry/rect.h" +#include "impeller/renderer/backend/vulkan/workarounds_vk.h" #include "impeller/renderer/blit_pass.h" namespace impeller { @@ -23,8 +24,10 @@ class BlitPassVK final : public BlitPass { friend class CommandBufferVK; std::shared_ptr command_buffer_; + const WorkaroundsVK workarounds_; - explicit BlitPassVK(std::shared_ptr command_buffer); + explicit BlitPassVK(std::shared_ptr command_buffer, + const WorkaroundsVK& workarounds); // |BlitPass| bool IsValid() const override; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/command_buffer_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/command_buffer_vk.cc index 780b423b54a41..32080ca547a63 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/command_buffer_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/command_buffer_vk.cc @@ -72,7 +72,12 @@ std::shared_ptr CommandBufferVK::OnCreateBlitPass() { if (!IsValid()) { return nullptr; } - auto pass = std::shared_ptr(new BlitPassVK(shared_from_this())); + auto context = context_.lock(); + if (!context) { + return nullptr; + } + auto pass = std::shared_ptr(new BlitPassVK( + shared_from_this(), ContextVK::Cast(*context).GetWorkarounds())); if (!pass->IsValid()) { return nullptr; } 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 e2c42562f0c52..c2116930d2153 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc @@ -462,8 +462,8 @@ void ContextVK::Setup(Settings settings) { // Apply workarounds for broken drivers. auto driver_info = std::make_unique(device_holder->physical_device); - WorkaroundsVK workarounds = GetWorkarounds(*driver_info); - caps->ApplyWorkarounds(workarounds); + workarounds_ = GetWorkaroundsFromDriverInfo(*driver_info); + caps->ApplyWorkarounds(workarounds_); device_holder_ = std::move(device_holder); idle_waiter_vk_ = std::make_shared(device_holder_); @@ -484,7 +484,7 @@ void ContextVK::Setup(Settings settings) { device_name_ = std::string(physical_device_properties.deviceName); command_queue_vk_ = std::make_shared(weak_from_this()); should_disable_surface_control_ = settings.disable_surface_control; - should_batch_cmd_buffers_ = !workarounds.batch_submit_command_buffer_timeout; + should_batch_cmd_buffers_ = !workarounds_.batch_submit_command_buffer_timeout; is_valid_ = true; // Create the GPU Tracer later because it depends on state from @@ -741,4 +741,8 @@ bool ContextVK::SubmitOnscreen(std::shared_ptr cmd_buffer) { return EnqueueCommandBuffer(std::move(cmd_buffer)); } +const WorkaroundsVK& ContextVK::GetWorkarounds() const { + return workarounds_; +} + } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.h index fa3282e9d199a..011378f5b1a0f 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.h @@ -21,6 +21,7 @@ #include "impeller/renderer/backend/vulkan/queue_vk.h" #include "impeller/renderer/backend/vulkan/sampler_library_vk.h" #include "impeller/renderer/backend/vulkan/shader_library_vk.h" +#include "impeller/renderer/backend/vulkan/workarounds_vk.h" #include "impeller/renderer/capabilities.h" #include "impeller/renderer/command_buffer.h" #include "impeller/renderer/command_queue.h" @@ -141,6 +142,8 @@ class ContextVK final : public Context, // |Context| void Shutdown() override; + const WorkaroundsVK& GetWorkarounds() const; + void SetOffscreenFormat(PixelFormat pixel_format); template @@ -281,6 +284,7 @@ class ContextVK final : public Context, std::shared_ptr gpu_tracer_; std::shared_ptr command_queue_vk_; std::shared_ptr idle_waiter_vk_; + WorkaroundsVK workarounds_; using DescriptorPoolMap = std::unordered_map>; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/driver_info_vk_unittests.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/driver_info_vk_unittests.cc index b3daa2a9532a3..51d98b1beabe6 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/driver_info_vk_unittests.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/driver_info_vk_unittests.cc @@ -82,7 +82,7 @@ bool CanBatchSubmitTest(std::string_view driver_name, bool qc = true) { prop->deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU; }) .Build(); - return !GetWorkarounds(*context->GetDriverInfo()) + return !GetWorkaroundsFromDriverInfo(*context->GetDriverInfo()) .batch_submit_command_buffer_timeout; } @@ -110,7 +110,7 @@ bool CanUsePrimitiveRestartSubmitTest(std::string_view driver_name, prop->deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU; }) .Build(); - return !GetWorkarounds(*context->GetDriverInfo()) + return !GetWorkaroundsFromDriverInfo(*context->GetDriverInfo()) .slow_primitive_restart_performance; } @@ -123,6 +123,34 @@ TEST(DriverInfoVKTest, CanUsePrimitiveRestart) { EXPECT_TRUE(CanUsePrimitiveRestartSubmitTest("Mali-G51", false)); } +bool CanUseMipgeneration(std::string_view driver_name, bool qc = true) { + auto const context = + MockVulkanContextBuilder() + .SetPhysicalPropertiesCallback( + [&driver_name, qc](VkPhysicalDevice device, + VkPhysicalDeviceProperties* prop) { + if (qc) { + prop->vendorID = 0x168C; // Qualcomm + } else { + prop->vendorID = 0x13B5; // ARM + } + driver_name.copy(prop->deviceName, driver_name.size()); + prop->deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU; + }) + .Build(); + return !GetWorkaroundsFromDriverInfo(*context->GetDriverInfo()) + .broken_mipmap_generation; +} + +TEST(DriverInfoVKTest, CanGenerateMipMaps) { + // Adreno no mips + EXPECT_FALSE(CanUseMipgeneration("Adreno (TM) 540", true)); + EXPECT_FALSE(CanUseMipgeneration("Adreno (TM) 750", true)); + + // Mali A-OK + EXPECT_TRUE(CanUseMipgeneration("Mali-G51", false)); +} + TEST(DriverInfoVKTest, DriverParsingMali) { EXPECT_EQ(GetMaliVersion("Mali-G51-MORE STUFF"), MaliGPU::kG51); EXPECT_EQ(GetMaliVersion("Mali-G51"), MaliGPU::kG51); diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/workarounds_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/workarounds_vk.cc index d77ef7d1bb547..f0d1b0586c002 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/workarounds_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/workarounds_vk.cc @@ -6,7 +6,7 @@ namespace impeller { -WorkaroundsVK GetWorkarounds(DriverInfoVK& driver_info) { +WorkaroundsVK GetWorkaroundsFromDriverInfo(DriverInfoVK& driver_info) { WorkaroundsVK workarounds; const auto& adreno_gpu = driver_info.GetAdrenoGPUInfo(); @@ -15,6 +15,7 @@ WorkaroundsVK GetWorkarounds(DriverInfoVK& driver_info) { workarounds.batch_submit_command_buffer_timeout = true; if (adreno_gpu.has_value()) { workarounds.slow_primitive_restart_performance = true; + workarounds.broken_mipmap_generation = true; if (adreno_gpu.value() >= AdrenoGPU::kAdreno702) { workarounds.batch_submit_command_buffer_timeout = false; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/workarounds_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/workarounds_vk.h index 72e8166c26d40..b2b70bc61d77d 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/workarounds_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/workarounds_vk.h @@ -22,8 +22,17 @@ struct WorkaroundsVK { /// requires the renderer to split up command buffers that could /// be logically combined. bool batch_submit_command_buffer_timeout = false; + + /// Almost all Adreno series GPU (from 600 up to 800) have problems + /// generating mipmaps, resulting in corruption of the mip levels. + /// See: + /// * https://github.com/flutter/flutter/issues/160441 + /// * https://github.com/flutter/flutter/issues/159876 + /// * https://github.com/flutter/flutter/issues/160587 + bool broken_mipmap_generation = false; }; -WorkaroundsVK GetWorkarounds(DriverInfoVK& driver_info); + +WorkaroundsVK GetWorkaroundsFromDriverInfo(DriverInfoVK& driver_info); } // namespace impeller