[Impeller] cache and reuse openGL framebuffer attachments. (flutter/engine#56746)

Creating and attaching textures/render buffers to a FBO is an expensive operation. Similar to how we cache vulkan framebuffers/render passes, we can cache the FBO object on the color0 texture to avoid extra state invalidation.

Part of https://github.com/flutter/flutter/issues/159177
This commit is contained in:
Jonah Williams 2024-11-22 09:43:43 -08:00 committed by GitHub
parent d3a6012bfa
commit 7e786d8dc8
3 changed files with 50 additions and 28 deletions

View File

@ -207,13 +207,6 @@ void RenderPassGLES::ResetGLState(const ProcTableGLES& gl) {
}
GLuint fbo = GL_NONE;
fml::ScopedCleanupClosure delete_fbo([&gl, &fbo]() {
if (fbo != GL_NONE) {
gl.BindFramebuffer(GL_FRAMEBUFFER, GL_NONE);
gl.DeleteFramebuffers(1u, &fbo);
}
});
TextureGLES& color_gles = TextureGLES::Cast(*pass_data.color_attachment);
const bool is_default_fbo = color_gles.IsWrapped();
@ -224,33 +217,41 @@ void RenderPassGLES::ResetGLState(const ProcTableGLES& gl) {
}
} else {
// Create and bind an offscreen FBO.
gl.GenFramebuffers(1u, &fbo);
gl.BindFramebuffer(GL_FRAMEBUFFER, fbo);
auto cached_fbo = color_gles.GetCachedFBO();
if (cached_fbo != GL_NONE) {
fbo = cached_fbo;
gl.BindFramebuffer(GL_FRAMEBUFFER, fbo);
} else {
gl.GenFramebuffers(1u, &fbo);
color_gles.SetCachedFBO(fbo);
gl.BindFramebuffer(GL_FRAMEBUFFER, fbo);
if (!color_gles.SetAsFramebufferAttachment(
GL_FRAMEBUFFER, TextureGLES::AttachmentType::kColor0)) {
return false;
}
if (auto depth = TextureGLES::Cast(pass_data.depth_attachment.get())) {
if (!depth->SetAsFramebufferAttachment(
GL_FRAMEBUFFER, TextureGLES::AttachmentType::kDepth)) {
if (!color_gles.SetAsFramebufferAttachment(
GL_FRAMEBUFFER, TextureGLES::AttachmentType::kColor0)) {
return false;
}
}
if (auto stencil = TextureGLES::Cast(pass_data.stencil_attachment.get())) {
if (!stencil->SetAsFramebufferAttachment(
GL_FRAMEBUFFER, TextureGLES::AttachmentType::kStencil)) {
if (auto depth = TextureGLES::Cast(pass_data.depth_attachment.get())) {
if (!depth->SetAsFramebufferAttachment(
GL_FRAMEBUFFER, TextureGLES::AttachmentType::kDepth)) {
return false;
}
}
if (auto stencil =
TextureGLES::Cast(pass_data.stencil_attachment.get())) {
if (!stencil->SetAsFramebufferAttachment(
GL_FRAMEBUFFER, TextureGLES::AttachmentType::kStencil)) {
return false;
}
}
auto status = gl.CheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
VALIDATION_LOG << "Could not create a complete frambuffer: "
<< DebugToFramebufferError(status);
return false;
}
}
auto status = gl.CheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
VALIDATION_LOG << "Could not create a complete frambuffer: "
<< DebugToFramebufferError(status);
return false;
}
}
gl.ClearColor(pass_data.clear_color.red, // red

View File

@ -217,6 +217,9 @@ TextureGLES::TextureGLES(std::shared_ptr<ReactorGLES> reactor,
// |Texture|
TextureGLES::~TextureGLES() {
reactor_->CollectHandle(handle_);
if (cached_fbo_ != GL_NONE) {
reactor_->GetProcTable().DeleteFramebuffers(1, &cached_fbo_);
}
}
// |Texture|
@ -645,4 +648,12 @@ std::optional<HandleGLES> TextureGLES::GetSyncFence() const {
return fence_;
}
void TextureGLES::SetCachedFBO(GLuint fbo) {
cached_fbo_ = fbo;
}
GLuint TextureGLES::GetCachedFBO() const {
return cached_fbo_;
}
} // namespace impeller

View File

@ -130,6 +130,15 @@ class TextureGLES final : public Texture,
///
void SetFence(HandleGLES fence);
/// Store the FBO object for recycling in the 2D renderer.
///
/// The color0 texture used by the 2D renderer will use this texture
/// object to store the associated FBO the first time it is used.
void SetCachedFBO(GLuint fbo);
/// Retrieve the cached FBO object, or GL_NONE if there is no object.
GLuint GetCachedFBO() const;
// Visible for testing.
std::optional<HandleGLES> GetSyncFence() const;
@ -141,6 +150,7 @@ class TextureGLES final : public Texture,
mutable std::bitset<6> slices_initialized_ = 0;
const bool is_wrapped_;
const std::optional<GLuint> wrapped_fbo_;
GLuint cached_fbo_ = GL_NONE;
bool is_valid_ = false;
TextureGLES(std::shared_ptr<ReactorGLES> reactor,