diff --git a/impeller/renderer/backend/gles/render_pass_gles.cc b/impeller/renderer/backend/gles/render_pass_gles.cc index 6cc570ff05570..fb707139a7b1a 100644 --- a/impeller/renderer/backend/gles/render_pass_gles.cc +++ b/impeller/renderer/backend/gles/render_pass_gles.cc @@ -170,19 +170,22 @@ struct RenderPassData { } }); - const auto is_default_fbo = - TextureGLES::Cast(*pass_data.color_attachment).IsWrapped(); + TextureGLES& color_gles = TextureGLES::Cast(*pass_data.color_attachment); + const bool is_default_fbo = color_gles.IsWrapped(); - if (!is_default_fbo) { + if (is_default_fbo) { + if (color_gles.GetFBO().has_value()) { + // NOLINTNEXTLINE(bugprone-unchecked-optional-access) + gl.BindFramebuffer(GL_FRAMEBUFFER, *color_gles.GetFBO()); + } + } else { // Create and bind an offscreen FBO. gl.GenFramebuffers(1u, &fbo); gl.BindFramebuffer(GL_FRAMEBUFFER, fbo); - if (auto color = TextureGLES::Cast(pass_data.color_attachment.get())) { - if (!color->SetAsFramebufferAttachment( - GL_FRAMEBUFFER, TextureGLES::AttachmentType::kColor0)) { - return false; - } + if (!color_gles.SetAsFramebufferAttachment( + GL_FRAMEBUFFER, TextureGLES::AttachmentType::kColor0)) { + return false; } if (auto depth = TextureGLES::Cast(pass_data.depth_attachment.get())) { diff --git a/impeller/renderer/backend/gles/texture_gles.cc b/impeller/renderer/backend/gles/texture_gles.cc index 23e867bc069df..c656b0d7d0ec2 100644 --- a/impeller/renderer/backend/gles/texture_gles.cc +++ b/impeller/renderer/backend/gles/texture_gles.cc @@ -68,21 +68,30 @@ HandleType ToHandleType(TextureGLES::Type type) { } TextureGLES::TextureGLES(ReactorGLES::Ref reactor, TextureDescriptor desc) - : TextureGLES(std::move(reactor), desc, false) {} + : TextureGLES(std::move(reactor), desc, false, std::nullopt) {} TextureGLES::TextureGLES(ReactorGLES::Ref reactor, TextureDescriptor desc, enum IsWrapped wrapped) - : TextureGLES(std::move(reactor), desc, true) {} + : TextureGLES(std::move(reactor), desc, true, std::nullopt) {} + +std::shared_ptr TextureGLES::WrapFBO(ReactorGLES::Ref reactor, + TextureDescriptor desc, + GLuint fbo) { + return std::shared_ptr( + new TextureGLES(std::move(reactor), desc, true, fbo)); +} TextureGLES::TextureGLES(std::shared_ptr reactor, TextureDescriptor desc, - bool is_wrapped) + bool is_wrapped, + std::optional fbo) : Texture(desc), reactor_(std::move(reactor)), type_(GetTextureTypeFromDescriptor(GetTextureDescriptor())), handle_(reactor_->CreateHandle(ToHandleType(type_))), - is_wrapped_(is_wrapped) { + is_wrapped_(is_wrapped), + wrapped_fbo_(fbo) { // Ensure the texture descriptor itself is valid. if (!GetTextureDescriptor().IsValid()) { VALIDATION_LOG << "Invalid texture descriptor."; diff --git a/impeller/renderer/backend/gles/texture_gles.h b/impeller/renderer/backend/gles/texture_gles.h index adfc2e49d4b90..5a8c3a79b33b2 100644 --- a/impeller/renderer/backend/gles/texture_gles.h +++ b/impeller/renderer/backend/gles/texture_gles.h @@ -32,6 +32,10 @@ class TextureGLES final : public Texture, TextureDescriptor desc, IsWrapped wrapped); + static std::shared_ptr WrapFBO(ReactorGLES::Ref reactor, + TextureDescriptor desc, + GLuint fbo); + // |Texture| ~TextureGLES() override; @@ -54,6 +58,8 @@ class TextureGLES final : public Texture, bool IsWrapped() const { return is_wrapped_; } + std::optional GetFBO() const { return wrapped_fbo_; } + private: friend class AllocatorMTL; @@ -62,11 +68,13 @@ class TextureGLES final : public Texture, HandleGLES handle_; mutable bool contents_initialized_ = false; const bool is_wrapped_; + const std::optional wrapped_fbo_; bool is_valid_ = false; TextureGLES(std::shared_ptr reactor, TextureDescriptor desc, - bool is_wrapped); + bool is_wrapped, + std::optional fbo); // |Texture| void SetLabel(std::string_view label) override; diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index 52e49646c009a..5b89bcfbc61a1 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -979,9 +979,8 @@ MakeRenderTargetFromBackingStoreImpeller( color0_tex.storage_mode = impeller::StorageMode::kDevicePrivate; impeller::ColorAttachment color0; - color0.texture = std::make_shared( - gl_context.GetReactor(), color0_tex, - impeller::TextureGLES::IsWrapped::kWrapped); + color0.texture = impeller::TextureGLES::WrapFBO( + gl_context.GetReactor(), color0_tex, framebuffer->name); color0.clear_color = impeller::Color::DarkSlateGray(); color0.load_action = impeller::LoadAction::kClear; color0.store_action = impeller::StoreAction::kStore; diff --git a/shell/platform/embedder/tests/embedder_gl_unittests.cc b/shell/platform/embedder/tests/embedder_gl_unittests.cc index 0720e54a458de..0d01bc19187c7 100644 --- a/shell/platform/embedder/tests/embedder_gl_unittests.cc +++ b/shell/platform/embedder/tests/embedder_gl_unittests.cc @@ -4747,7 +4747,8 @@ TEST_F(EmbedderTest, } TEST_F(EmbedderTest, CanRenderWithImpellerOpenGL) { - auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext); + EmbedderTestContextGL& context = static_cast( + GetEmbedderContext(EmbedderTestContextType::kOpenGLContext)); EmbedderConfigBuilder builder(context); bool present_called = false; @@ -4768,6 +4769,24 @@ TEST_F(EmbedderTest, CanRenderWithImpellerOpenGL) { auto engine = builder.LaunchEngine(); ASSERT_TRUE(engine.is_valid()); + // Bind to an arbitrary FBO in order to verify that Impeller binds to the + // provided FBO during rendering. + typedef void (*glGenFramebuffersProc)(GLsizei n, GLuint* ids); + typedef void (*glBindFramebufferProc)(GLenum target, GLuint framebuffer); + auto glGenFramebuffers = reinterpret_cast( + context.GLGetProcAddress("glGenFramebuffers")); + auto glBindFramebuffer = reinterpret_cast( + context.GLGetProcAddress("glBindFramebuffer")); + const flutter::Shell& shell = ToEmbedderEngine(engine.get())->GetShell(); + fml::AutoResetWaitableEvent raster_event; + shell.GetTaskRunners().GetRasterTaskRunner()->PostTask([&] { + GLuint fbo; + glGenFramebuffers(1, &fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + raster_event.Signal(); + }); + raster_event.Wait(); + // Send a window metrics events so frames may be scheduled. FlutterWindowMetricsEvent event = {}; event.struct_size = sizeof(event); diff --git a/shell/platform/embedder/tests/embedder_test_context_gl.h b/shell/platform/embedder/tests/embedder_test_context_gl.h index 3241b318d8d45..f23f98faeffe6 100644 --- a/shell/platform/embedder/tests/embedder_test_context_gl.h +++ b/shell/platform/embedder/tests/embedder_test_context_gl.h @@ -62,6 +62,8 @@ class EmbedderTestContextGL : public EmbedderTestContext { void GLPopulateExistingDamage(const intptr_t id, FlutterDamage* existing_damage); + void* GLGetProcAddress(const char* name); + protected: virtual void SetupCompositor() override; @@ -88,8 +90,6 @@ class EmbedderTestContextGL : public EmbedderTestContext { bool GLMakeResourceCurrent(); - void* GLGetProcAddress(const char* name); - FML_DISALLOW_COPY_AND_ASSIGN(EmbedderTestContextGL); };