[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.
This commit is contained in:
Jonah Williams
2025-03-13 10:55:02 -07:00
committed by GitHub
parent 2b8aea7bd4
commit c38f0b7aae
3 changed files with 48 additions and 2 deletions

View File

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

View File

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

View File

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