[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_;