[stable] fix validation check when restoring to onscreen with BDF and mips. (#165430)
cherry-pick of https://github.com/flutter/flutter/pull/165098
## Impacted Users
Impeller users developing on the Android Emulator (or some old hardware)
## Impact Description
Crash in the Flutter app
## Workaround (Is there a workaround for this issue?)
Use a real android device.
## Risk (What is the risk level of this cherry-pick?)
## Test Coverage (Are you confident that your fix is well-tested by automated tests?)
Yes, there is an integration test that captures most of the problem.
## Validation Steps (What are the steps to validate that this fix works?)
https://github.com/flutter/flutter/issues/163421 has reproduction steps
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 61338d2..aca6463 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -27,6 +27,9 @@
## Flutter 3.29 Changes
### [3.29.3](https://github.com/flutter/flutter/releases/tag/3.29.3)
+- [flutter/163421](https://github.com/flutter/flutter/issues/163421) - Impeller,
+ Android, Fixes Android Emulator crash when navigating to routes with backdrop
+ blurs.
- [flutter/165166](https://github.com/flutter/flutter/pull/165166) - Impeller,
All platforms, Text that is scaled over 48x renders incorrectly.
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 d8264f9..a19b705 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"
@@ -31,6 +32,7 @@
#include "impeller/display_list/dl_image_impeller.h"
#include "impeller/geometry/path_builder.h"
#include "impeller/geometry/scalar.h"
+#include "impeller/playground/playground.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkPath.h"
@@ -1137,5 +1139,26 @@
EXPECT_EQ(texture, nullptr);
}
+TEST_P(AiksTest, DisplayListToTextureWithMipGenerationOnGLES) {
+ if (GetBackend() != PlaygroundBackend::kOpenGLES) {
+ GTEST_SKIP() << "Only relevant for GLES";
+ }
+ DisplayListBuilder builder;
+
+ std::shared_ptr<DlImageFilter> 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 24fc418..5563b35 100644
--- a/engine/src/flutter/impeller/display_list/canvas.cc
+++ b/engine/src/flutter/impeller/display_list/canvas.cc
@@ -1695,7 +1695,6 @@
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(),
@@ -1739,6 +1738,24 @@
}
}
+bool Canvas::EnsureFinalMipmapGeneration() const {
+ if (!render_target_.GetRenderTargetTexture()->NeedsMipmapGeneration()) {
+ return true;
+ }
+ std::shared_ptr<CommandBuffer> cmd_buffer =
+ renderer_.GetContext()->CreateCommandBuffer();
+ if (!cmd_buffer) {
+ return false;
+ }
+ std::shared_ptr<BlitPass> 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();
@@ -1752,7 +1769,9 @@
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 fe3d3b1..f31c306 100644
--- a/engine/src/flutter/impeller/display_list/canvas.h
+++ b/engine/src/flutter/impeller/display_list/canvas.h
@@ -261,6 +261,10 @@
// 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_;