diff --git a/CHANGELOG.md b/CHANGELOG.md index e53f26c5615..44a7df79039 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ INTERNAL NOTE ### [3.29.0](https://github.com/flutter/flutter/releases/tag/3.29.0) Initial stable release. +- [flutter/163304](https://github.com/flutter/flutter/issues/163304) Fixes crash when using backdrop filter on GLES backend. - [flutter/161334](https://github.com/flutter/flutter/issues/161334) Disable Vulkan on certain Xclipse GPU models. ## Flutter 3.27 Changes diff --git a/engine/src/flutter/impeller/display_list/canvas.cc b/engine/src/flutter/impeller/display_list/canvas.cc index 026cf41044f..cccd9130c32 100644 --- a/engine/src/flutter/impeller/display_list/canvas.cc +++ b/engine/src/flutter/impeller/display_list/canvas.cc @@ -1677,6 +1677,14 @@ std::shared_ptr Canvas::FlipBackdrop(Point global_pass_position, return input_texture; } +bool Canvas::SupportsBlitToOnscreen() const { + return renderer_.GetContext() + ->GetCapabilities() + ->SupportsTextureToTextureBlits() && + renderer_.GetContext()->GetBackendType() != + Context::BackendType::kOpenGLES; +} + bool Canvas::BlitToOnscreen(bool is_onscreen) { auto command_buffer = renderer_.GetContext()->CreateCommandBuffer(); command_buffer->SetLabel("EntityPass Root Command Buffer"); @@ -1684,9 +1692,7 @@ bool Canvas::BlitToOnscreen(bool is_onscreen) { .inline_pass_context->GetPassTarget() .GetRenderTarget(); - if (renderer_.GetContext() - ->GetCapabilities() - ->SupportsTextureToTextureBlits()) { + if (SupportsBlitToOnscreen()) { auto blit_pass = command_buffer->CreateBlitPass(); blit_pass->AddCopy(offscreen_target.GetRenderTargetTexture(), render_target_.GetRenderTargetTexture()); diff --git a/engine/src/flutter/impeller/display_list/canvas.h b/engine/src/flutter/impeller/display_list/canvas.h index 0b5e76331e3..fe3d3b1b7ae 100644 --- a/engine/src/flutter/impeller/display_list/canvas.h +++ b/engine/src/flutter/impeller/display_list/canvas.h @@ -251,6 +251,16 @@ class Canvas { // Visible for testing. bool RequiresReadback() const { return requires_readback_; } + // Whether the current device has the capabilities to blit an offscreen + // texture into the onscreen. + // + // This requires the availibility of the blit framebuffer command, but is + // disabled for GLES. A simple glBlitFramebuffer does not support resolving + // different sample counts which may be present in GLES when using MSAA. + // + // Visible for testing. + bool SupportsBlitToOnscreen() const; + private: ContentContext& renderer_; RenderTarget render_target_; diff --git a/engine/src/flutter/impeller/display_list/canvas_unittests.cc b/engine/src/flutter/impeller/display_list/canvas_unittests.cc index ee0f8b2e93d..b2a95e02e53 100644 --- a/engine/src/flutter/impeller/display_list/canvas_unittests.cc +++ b/engine/src/flutter/impeller/display_list/canvas_unittests.cc @@ -14,6 +14,7 @@ #include "impeller/display_list/aiks_unittests.h" #include "impeller/display_list/canvas.h" #include "impeller/geometry/geometry_asserts.h" +#include "impeller/playground/playground.h" #include "impeller/renderer/render_target.h" namespace impeller { @@ -278,5 +279,17 @@ TEST_P(AiksTest, BackdropCountDownWithNestedSaveLayers) { EXPECT_TRUE(canvas->RequiresReadback()); } +TEST_P(AiksTest, SupportsBlitToOnscreen) { + ContentContext context(GetContext(), nullptr); + auto canvas = CreateTestCanvas(context, Rect::MakeLTRB(0, 0, 100, 100), + /*requires_readback=*/true); + + if (GetBackend() == PlaygroundBackend::kOpenGLES) { + EXPECT_FALSE(canvas->SupportsBlitToOnscreen()); + } else { + EXPECT_TRUE(canvas->SupportsBlitToOnscreen()); + } +} + } // namespace testing } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/gles/test/texture_gles_unittests.cc b/engine/src/flutter/impeller/renderer/backend/gles/test/texture_gles_unittests.cc index fd1797209a9..4406a98214e 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/test/texture_gles_unittests.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/test/texture_gles_unittests.cc @@ -65,4 +65,23 @@ TEST_P(TextureGLESTest, CanSetSyncFence) { ASSERT_FALSE(sync_fence.has_value()); } +TEST_P(TextureGLESTest, Binds2DTexture) { + TextureDescriptor desc; + desc.storage_mode = StorageMode::kDevicePrivate; + desc.size = {100, 100}; + desc.format = PixelFormat::kR8G8B8A8UNormInt; + desc.type = TextureType::kTexture2DMultisample; + desc.sample_count = SampleCount::kCount4; + + auto texture = GetContext()->GetResourceAllocator()->CreateTexture(desc); + + ASSERT_TRUE(texture); + + EXPECT_EQ( + TextureGLES::Cast(*texture).ComputeTypeForBinding(GL_READ_FRAMEBUFFER), + TextureGLES::Type::kTexture); + EXPECT_EQ(TextureGLES::Cast(*texture).ComputeTypeForBinding(GL_FRAMEBUFFER), + TextureGLES::Type::kTextureMultisampled); +} + } // namespace impeller::testing diff --git a/engine/src/flutter/impeller/renderer/backend/gles/texture_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/texture_gles.cc index e85aeb37721..39fe43e6b3f 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/texture_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/texture_gles.cc @@ -392,6 +392,15 @@ static std::optional ToRenderBufferFormat(PixelFormat format) { FML_UNREACHABLE(); } +TextureGLES::Type TextureGLES::ComputeTypeForBinding(GLenum target) const { + // When binding to a GL_READ_FRAMEBUFFER, any multisampled + // textures must be bound as single sampled. + if (target == GL_READ_FRAMEBUFFER && type_ == Type::kTextureMultisampled) { + return Type::kTexture; + } + return type_; +} + void TextureGLES::InitializeContentsIfNecessary() const { if (!IsValid() || slices_initialized_[0]) { return; @@ -588,7 +597,7 @@ bool TextureGLES::SetAsFramebufferAttachment( } const auto& gl = reactor_->GetProcTable(); - switch (type_) { + switch (ComputeTypeForBinding(target)) { case Type::kTexture: gl.FramebufferTexture2D(target, // target ToAttachmentType(attachment_type), // attachment diff --git a/engine/src/flutter/impeller/renderer/backend/gles/texture_gles.h b/engine/src/flutter/impeller/renderer/backend/gles/texture_gles.h index 597fb726b21..5d7a18507af 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/texture_gles.h +++ b/engine/src/flutter/impeller/renderer/backend/gles/texture_gles.h @@ -144,6 +144,9 @@ class TextureGLES final : public Texture, // Visible for testing. std::optional GetSyncFence() const; + // visible for testing + Type ComputeTypeForBinding(GLenum target) const; + private: std::shared_ptr reactor_; const Type type_;