mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[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:
parent
d3a6012bfa
commit
7e786d8dc8
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user