[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.
This commit is contained in:
Jonah Williams 2025-01-07 13:51:54 -08:00 committed by GitHub
parent ad5e1fe300
commit a3a4995607
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 67 additions and 12 deletions

View File

@ -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<CommandBufferVK> command_buffer)
: command_buffer_(std::move(command_buffer)) {}
BlitPassVK::BlitPassVK(std::shared_ptr<CommandBufferVK> 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> 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;
}

View File

@ -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<CommandBufferVK> command_buffer_;
const WorkaroundsVK workarounds_;
explicit BlitPassVK(std::shared_ptr<CommandBufferVK> command_buffer);
explicit BlitPassVK(std::shared_ptr<CommandBufferVK> command_buffer,
const WorkaroundsVK& workarounds);
// |BlitPass|
bool IsValid() const override;

View File

@ -72,7 +72,12 @@ std::shared_ptr<BlitPass> CommandBufferVK::OnCreateBlitPass() {
if (!IsValid()) {
return nullptr;
}
auto pass = std::shared_ptr<BlitPassVK>(new BlitPassVK(shared_from_this()));
auto context = context_.lock();
if (!context) {
return nullptr;
}
auto pass = std::shared_ptr<BlitPassVK>(new BlitPassVK(
shared_from_this(), ContextVK::Cast(*context).GetWorkarounds()));
if (!pass->IsValid()) {
return nullptr;
}

View File

@ -462,8 +462,8 @@ void ContextVK::Setup(Settings settings) {
// Apply workarounds for broken drivers.
auto driver_info =
std::make_unique<DriverInfoVK>(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<IdleWaiterVK>(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<CommandQueueVK>(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<CommandBuffer> cmd_buffer) {
return EnqueueCommandBuffer(std::move(cmd_buffer));
}
const WorkaroundsVK& ContextVK::GetWorkarounds() const {
return workarounds_;
}
} // namespace impeller

View File

@ -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 <typename T>
@ -281,6 +284,7 @@ class ContextVK final : public Context,
std::shared_ptr<GPUTracerVK> gpu_tracer_;
std::shared_ptr<CommandQueue> command_queue_vk_;
std::shared_ptr<const IdleWaiter> idle_waiter_vk_;
WorkaroundsVK workarounds_;
using DescriptorPoolMap =
std::unordered_map<std::thread::id, std::shared_ptr<DescriptorPoolVK>>;

View File

@ -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);

View File

@ -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;

View File

@ -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