From c38f0b7aaee3651f0eb98c7987da420f4225f504 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Thu, 13 Mar 2025 10:55:02 -0700 Subject: [PATCH] [Impeller] fix validation check when restoring to onscreen with BDF and mips. (#165098) Fixes https://github.com/flutter/flutter/issues/163421 If we restore to the onscreen but need to generate mips (because its a toImage call) then we could miss the mip map generation. This will primarily happen on Android emulators as they do not support framebuffer fetch. --- .../display_list/aiks_dl_unittests.cc | 23 +++++++++++++++++++ .../flutter/impeller/display_list/canvas.cc | 23 +++++++++++++++++-- .../flutter/impeller/display_list/canvas.h | 4 ++++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/engine/src/flutter/impeller/display_list/aiks_dl_unittests.cc b/engine/src/flutter/impeller/display_list/aiks_dl_unittests.cc index e217d56155..0dae345069 100644 --- a/engine/src/flutter/impeller/display_list/aiks_dl_unittests.cc +++ b/engine/src/flutter/impeller/display_list/aiks_dl_unittests.cc @@ -20,6 +20,7 @@ #include "flutter/display_list/dl_paint.h" #include "flutter/testing/testing.h" #include "fml/synchronization/count_down_latch.h" +#include "gtest/gtest.h" #include "imgui.h" #include "impeller/base/validation.h" #include "impeller/core/device_buffer.h" @@ -30,6 +31,7 @@ #include "impeller/display_list/dl_dispatcher.h" #include "impeller/display_list/dl_image_impeller.h" #include "impeller/geometry/scalar.h" +#include "impeller/playground/playground.h" namespace impeller { namespace testing { @@ -1119,5 +1121,26 @@ TEST_P(AiksTest, DisplayListToTextureAllocationFailure) { EXPECT_EQ(texture, nullptr); } +TEST_P(AiksTest, DisplayListToTextureWithMipGenerationOnGLES) { + if (GetBackend() != PlaygroundBackend::kOpenGLES) { + GTEST_SKIP() << "Only relevant for GLES"; + } + DisplayListBuilder builder; + + std::shared_ptr filter = + DlImageFilter::MakeBlur(8, 8, DlTileMode::kClamp); + builder.SaveLayer(std::nullopt, nullptr, filter.get()); + builder.Restore(); + + AiksContext aiks_context(GetContext(), nullptr); + // Use intentionally invalid dimensions that would trigger an allocation + // failure. + auto texture = + DisplayListToTexture(builder.Build(), ISize{10, 10}, aiks_context, + /*reset_host_buffer=*/true, /*generate_mips=*/true); + + EXPECT_FALSE(texture->NeedsMipmapGeneration()); +} + } // namespace testing } // namespace impeller diff --git a/engine/src/flutter/impeller/display_list/canvas.cc b/engine/src/flutter/impeller/display_list/canvas.cc index f3f96425f1..1c60c5857e 100644 --- a/engine/src/flutter/impeller/display_list/canvas.cc +++ b/engine/src/flutter/impeller/display_list/canvas.cc @@ -1718,7 +1718,6 @@ bool Canvas::BlitToOnscreen(bool is_onscreen) { auto offscreen_target = render_passes_.back() .inline_pass_context->GetPassTarget() .GetRenderTarget(); - if (SupportsBlitToOnscreen()) { auto blit_pass = command_buffer->CreateBlitPass(); blit_pass->AddCopy(offscreen_target.GetRenderTargetTexture(), @@ -1762,6 +1761,24 @@ bool Canvas::BlitToOnscreen(bool is_onscreen) { } } +bool Canvas::EnsureFinalMipmapGeneration() const { + if (!render_target_.GetRenderTargetTexture()->NeedsMipmapGeneration()) { + return true; + } + std::shared_ptr cmd_buffer = + renderer_.GetContext()->CreateCommandBuffer(); + if (!cmd_buffer) { + return false; + } + std::shared_ptr blit_pass = cmd_buffer->CreateBlitPass(); + if (!blit_pass) { + return false; + } + blit_pass->GenerateMipmap(render_target_.GetRenderTargetTexture()); + blit_pass->EncodeCommands(); + return renderer_.GetContext()->EnqueueCommandBuffer(std::move(cmd_buffer)); +} + void Canvas::EndReplay() { FML_DCHECK(render_passes_.size() == 1u); render_passes_.back().inline_pass_context->GetRenderPass(); @@ -1775,7 +1792,9 @@ void Canvas::EndReplay() { if (requires_readback_) { BlitToOnscreen(/*is_onscreen_=*/is_onscreen_); } - + if (!EnsureFinalMipmapGeneration()) { + VALIDATION_LOG << "Failed to generate onscreen mipmaps."; + } if (!renderer_.GetContext()->FlushCommandBuffers()) { // Not much we can do. VALIDATION_LOG << "Failed to submit command buffers"; diff --git a/engine/src/flutter/impeller/display_list/canvas.h b/engine/src/flutter/impeller/display_list/canvas.h index 08273caca0..1962d48d5f 100644 --- a/engine/src/flutter/impeller/display_list/canvas.h +++ b/engine/src/flutter/impeller/display_list/canvas.h @@ -263,6 +263,10 @@ class Canvas { // Visible for testing. bool SupportsBlitToOnscreen() const; + /// For picture snapshots we need addition steps to verify that final mipmaps + /// are generated. + bool EnsureFinalMipmapGeneration() const; + private: ContentContext& renderer_; RenderTarget render_target_;