mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[Impeller] Add a TextureGLES API for wrapping a framebuffer and use it to implement OpenGL FBO targets in the embedder library (flutter/engine#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.
This commit is contained in:
parent
a16ee1a7ac
commit
1bfca0c056
@ -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())) {
|
||||
|
||||
@ -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> TextureGLES::WrapFBO(ReactorGLES::Ref reactor,
|
||||
TextureDescriptor desc,
|
||||
GLuint fbo) {
|
||||
return std::shared_ptr<TextureGLES>(
|
||||
new TextureGLES(std::move(reactor), desc, true, fbo));
|
||||
}
|
||||
|
||||
TextureGLES::TextureGLES(std::shared_ptr<ReactorGLES> reactor,
|
||||
TextureDescriptor desc,
|
||||
bool is_wrapped)
|
||||
bool is_wrapped,
|
||||
std::optional<GLuint> 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.";
|
||||
|
||||
@ -32,6 +32,10 @@ class TextureGLES final : public Texture,
|
||||
TextureDescriptor desc,
|
||||
IsWrapped wrapped);
|
||||
|
||||
static std::shared_ptr<TextureGLES> 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<GLuint> 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<GLuint> wrapped_fbo_;
|
||||
bool is_valid_ = false;
|
||||
|
||||
TextureGLES(std::shared_ptr<ReactorGLES> reactor,
|
||||
TextureDescriptor desc,
|
||||
bool is_wrapped);
|
||||
bool is_wrapped,
|
||||
std::optional<GLuint> fbo);
|
||||
|
||||
// |Texture|
|
||||
void SetLabel(std::string_view label) override;
|
||||
|
||||
@ -979,9 +979,8 @@ MakeRenderTargetFromBackingStoreImpeller(
|
||||
color0_tex.storage_mode = impeller::StorageMode::kDevicePrivate;
|
||||
|
||||
impeller::ColorAttachment color0;
|
||||
color0.texture = std::make_shared<impeller::TextureGLES>(
|
||||
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;
|
||||
|
||||
@ -4747,7 +4747,8 @@ TEST_F(EmbedderTest,
|
||||
}
|
||||
|
||||
TEST_F(EmbedderTest, CanRenderWithImpellerOpenGL) {
|
||||
auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
|
||||
EmbedderTestContextGL& context = static_cast<EmbedderTestContextGL&>(
|
||||
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<glGenFramebuffersProc>(
|
||||
context.GLGetProcAddress("glGenFramebuffers"));
|
||||
auto glBindFramebuffer = reinterpret_cast<glBindFramebufferProc>(
|
||||
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);
|
||||
|
||||
@ -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);
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user