Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit ea93c5d

Browse files
[Impeller] Add a TextureGLES API for wrapping a framebuffer and use it to implement OpenGL FBO targets in the embedder library (#51269)
The Linux embedder is rendering to a FlutterOpenGLFramebuffer that specifies an OpenGL FBO. This API allows the embedder to create a color attachment that wraps the FBO so that the render pass will bind to that FBO during encoding.
1 parent 357876e commit ea93c5d

File tree

6 files changed

+57
-19
lines changed

6 files changed

+57
-19
lines changed

impeller/renderer/backend/gles/render_pass_gles.cc

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -170,19 +170,22 @@ struct RenderPassData {
170170
}
171171
});
172172

173-
const auto is_default_fbo =
174-
TextureGLES::Cast(*pass_data.color_attachment).IsWrapped();
173+
TextureGLES& color_gles = TextureGLES::Cast(*pass_data.color_attachment);
174+
const bool is_default_fbo = color_gles.IsWrapped();
175175

176-
if (!is_default_fbo) {
176+
if (is_default_fbo) {
177+
if (color_gles.GetFBO().has_value()) {
178+
// NOLINTNEXTLINE(bugprone-unchecked-optional-access)
179+
gl.BindFramebuffer(GL_FRAMEBUFFER, *color_gles.GetFBO());
180+
}
181+
} else {
177182
// Create and bind an offscreen FBO.
178183
gl.GenFramebuffers(1u, &fbo);
179184
gl.BindFramebuffer(GL_FRAMEBUFFER, fbo);
180185

181-
if (auto color = TextureGLES::Cast(pass_data.color_attachment.get())) {
182-
if (!color->SetAsFramebufferAttachment(
183-
GL_FRAMEBUFFER, TextureGLES::AttachmentType::kColor0)) {
184-
return false;
185-
}
186+
if (!color_gles.SetAsFramebufferAttachment(
187+
GL_FRAMEBUFFER, TextureGLES::AttachmentType::kColor0)) {
188+
return false;
186189
}
187190

188191
if (auto depth = TextureGLES::Cast(pass_data.depth_attachment.get())) {

impeller/renderer/backend/gles/texture_gles.cc

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,21 +68,30 @@ HandleType ToHandleType(TextureGLES::Type type) {
6868
}
6969

7070
TextureGLES::TextureGLES(ReactorGLES::Ref reactor, TextureDescriptor desc)
71-
: TextureGLES(std::move(reactor), desc, false) {}
71+
: TextureGLES(std::move(reactor), desc, false, std::nullopt) {}
7272

7373
TextureGLES::TextureGLES(ReactorGLES::Ref reactor,
7474
TextureDescriptor desc,
7575
enum IsWrapped wrapped)
76-
: TextureGLES(std::move(reactor), desc, true) {}
76+
: TextureGLES(std::move(reactor), desc, true, std::nullopt) {}
77+
78+
std::shared_ptr<TextureGLES> TextureGLES::WrapFBO(ReactorGLES::Ref reactor,
79+
TextureDescriptor desc,
80+
GLuint fbo) {
81+
return std::shared_ptr<TextureGLES>(
82+
new TextureGLES(std::move(reactor), desc, true, fbo));
83+
}
7784

7885
TextureGLES::TextureGLES(std::shared_ptr<ReactorGLES> reactor,
7986
TextureDescriptor desc,
80-
bool is_wrapped)
87+
bool is_wrapped,
88+
std::optional<GLuint> fbo)
8189
: Texture(desc),
8290
reactor_(std::move(reactor)),
8391
type_(GetTextureTypeFromDescriptor(GetTextureDescriptor())),
8492
handle_(reactor_->CreateHandle(ToHandleType(type_))),
85-
is_wrapped_(is_wrapped) {
93+
is_wrapped_(is_wrapped),
94+
wrapped_fbo_(fbo) {
8695
// Ensure the texture descriptor itself is valid.
8796
if (!GetTextureDescriptor().IsValid()) {
8897
VALIDATION_LOG << "Invalid texture descriptor.";

impeller/renderer/backend/gles/texture_gles.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ class TextureGLES final : public Texture,
3232
TextureDescriptor desc,
3333
IsWrapped wrapped);
3434

35+
static std::shared_ptr<TextureGLES> WrapFBO(ReactorGLES::Ref reactor,
36+
TextureDescriptor desc,
37+
GLuint fbo);
38+
3539
// |Texture|
3640
~TextureGLES() override;
3741

@@ -54,6 +58,8 @@ class TextureGLES final : public Texture,
5458

5559
bool IsWrapped() const { return is_wrapped_; }
5660

61+
std::optional<GLuint> GetFBO() const { return wrapped_fbo_; }
62+
5763
private:
5864
friend class AllocatorMTL;
5965

@@ -62,11 +68,13 @@ class TextureGLES final : public Texture,
6268
HandleGLES handle_;
6369
mutable bool contents_initialized_ = false;
6470
const bool is_wrapped_;
71+
const std::optional<GLuint> wrapped_fbo_;
6572
bool is_valid_ = false;
6673

6774
TextureGLES(std::shared_ptr<ReactorGLES> reactor,
6875
TextureDescriptor desc,
69-
bool is_wrapped);
76+
bool is_wrapped,
77+
std::optional<GLuint> fbo);
7078

7179
// |Texture|
7280
void SetLabel(std::string_view label) override;

shell/platform/embedder/embedder.cc

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -979,9 +979,8 @@ MakeRenderTargetFromBackingStoreImpeller(
979979
color0_tex.storage_mode = impeller::StorageMode::kDevicePrivate;
980980

981981
impeller::ColorAttachment color0;
982-
color0.texture = std::make_shared<impeller::TextureGLES>(
983-
gl_context.GetReactor(), color0_tex,
984-
impeller::TextureGLES::IsWrapped::kWrapped);
982+
color0.texture = impeller::TextureGLES::WrapFBO(
983+
gl_context.GetReactor(), color0_tex, framebuffer->name);
985984
color0.clear_color = impeller::Color::DarkSlateGray();
986985
color0.load_action = impeller::LoadAction::kClear;
987986
color0.store_action = impeller::StoreAction::kStore;

shell/platform/embedder/tests/embedder_gl_unittests.cc

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4747,7 +4747,8 @@ TEST_F(EmbedderTest,
47474747
}
47484748

47494749
TEST_F(EmbedderTest, CanRenderWithImpellerOpenGL) {
4750-
auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
4750+
EmbedderTestContextGL& context = static_cast<EmbedderTestContextGL&>(
4751+
GetEmbedderContext(EmbedderTestContextType::kOpenGLContext));
47514752
EmbedderConfigBuilder builder(context);
47524753

47534754
bool present_called = false;
@@ -4768,6 +4769,24 @@ TEST_F(EmbedderTest, CanRenderWithImpellerOpenGL) {
47684769
auto engine = builder.LaunchEngine();
47694770
ASSERT_TRUE(engine.is_valid());
47704771

4772+
// Bind to an arbitrary FBO in order to verify that Impeller binds to the
4773+
// provided FBO during rendering.
4774+
typedef void (*glGenFramebuffersProc)(GLsizei n, GLuint* ids);
4775+
typedef void (*glBindFramebufferProc)(GLenum target, GLuint framebuffer);
4776+
auto glGenFramebuffers = reinterpret_cast<glGenFramebuffersProc>(
4777+
context.GLGetProcAddress("glGenFramebuffers"));
4778+
auto glBindFramebuffer = reinterpret_cast<glBindFramebufferProc>(
4779+
context.GLGetProcAddress("glBindFramebuffer"));
4780+
const flutter::Shell& shell = ToEmbedderEngine(engine.get())->GetShell();
4781+
fml::AutoResetWaitableEvent raster_event;
4782+
shell.GetTaskRunners().GetRasterTaskRunner()->PostTask([&] {
4783+
GLuint fbo;
4784+
glGenFramebuffers(1, &fbo);
4785+
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
4786+
raster_event.Signal();
4787+
});
4788+
raster_event.Wait();
4789+
47714790
// Send a window metrics events so frames may be scheduled.
47724791
FlutterWindowMetricsEvent event = {};
47734792
event.struct_size = sizeof(event);

shell/platform/embedder/tests/embedder_test_context_gl.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ class EmbedderTestContextGL : public EmbedderTestContext {
6262
void GLPopulateExistingDamage(const intptr_t id,
6363
FlutterDamage* existing_damage);
6464

65+
void* GLGetProcAddress(const char* name);
66+
6567
protected:
6668
virtual void SetupCompositor() override;
6769

@@ -88,8 +90,6 @@ class EmbedderTestContextGL : public EmbedderTestContext {
8890

8991
bool GLMakeResourceCurrent();
9092

91-
void* GLGetProcAddress(const char* name);
92-
9393
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderTestContextGL);
9494
};
9595

0 commit comments

Comments
 (0)