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

Commit c7e2ba7

Browse files
authored
[Impeller] Switch from glBlitFramebuffer to implicit MSAA resolution. (#47282)
Closes flutter/flutter#137093. This widens supports from Open GLES 3.x to Open GLES 2.x, and uses [ARM GPU Best Practices](https://developer.arm.com/documentation/101897/0301/Fragment-shading/Multisampling-for-OpenGL-ES): > Do not use `glBlitFramebuffer()` to implement a multisample resolve. This PR: - Removes usage of `glBlitFramebuffer` - Adds the capability check, `SupportsImplicitResolvingMSAA`, which is `false` outside of GLES - Does not discard color attachments resolved by `EXT_multisampled_render_to_texture` (done implicitly) I spoke to @jonahwilliams about the changes to the HAL, who I believe also talked to @bdero about it. The short explantation is that, with the `EXT_multisampled_render_to_texture`, we can be more efficient by letting GLES perform multisampled rendering for us (no per-sample data is written out). See also https://registry.khronos.org/OpenGL/extensions/EXT/EXT_multisampled_render_to_texture.txt for details.
1 parent 4f87c20 commit c7e2ba7

File tree

8 files changed

+66
-64
lines changed

8 files changed

+66
-64
lines changed

impeller/renderer/backend/gles/capabilities_gles.cc

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ static const constexpr char* kNvidiaTextureBorderClampExt =
1919
static const constexpr char* kOESTextureBorderClampExt =
2020
"GL_OES_texture_border_clamp";
2121

22+
// https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_multisampled_render_to_texture.txt
23+
static const constexpr char* kMultisampledRenderToTextureExt =
24+
"GL_EXT_multisampled_render_to_texture2";
25+
2226
CapabilitiesGLES::CapabilitiesGLES(const ProcTableGLES& gl) {
2327
{
2428
GLint value = 0;
@@ -32,7 +36,9 @@ CapabilitiesGLES::CapabilitiesGLES(const ProcTableGLES& gl) {
3236
max_cube_map_texture_size = value;
3337
}
3438

35-
if (gl.GetDescription()->IsES()) {
39+
auto const desc = gl.GetDescription();
40+
41+
if (desc->IsES()) {
3642
GLint value = 0;
3743
gl.GetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &value);
3844
max_fragment_uniform_vectors = value;
@@ -56,7 +62,7 @@ CapabilitiesGLES::CapabilitiesGLES(const ProcTableGLES& gl) {
5662
max_texture_size = ISize{value, value};
5763
}
5864

59-
if (gl.GetDescription()->IsES()) {
65+
if (desc->IsES()) {
6066
GLint value = 0;
6167
gl.GetIntegerv(GL_MAX_VARYING_VECTORS, &value);
6268
max_varying_vectors = value;
@@ -74,7 +80,7 @@ CapabilitiesGLES::CapabilitiesGLES(const ProcTableGLES& gl) {
7480
max_vertex_texture_image_units = value;
7581
}
7682

77-
if (gl.GetDescription()->IsES()) {
83+
if (desc->IsES()) {
7884
GLint value = 0;
7985
gl.GetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &value);
8086
max_vertex_uniform_vectors = value;
@@ -92,31 +98,26 @@ CapabilitiesGLES::CapabilitiesGLES(const ProcTableGLES& gl) {
9298
num_compressed_texture_formats = value;
9399
}
94100

95-
if (gl.GetDescription()->IsES()) {
101+
if (desc->IsES()) {
96102
GLint value = 0;
97103
gl.GetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &value);
98104
num_shader_binary_formats = value;
99105
}
100106

101-
supports_framebuffer_fetch_ =
102-
gl.GetDescription()->HasExtension(kFramebufferFetchExt);
107+
supports_framebuffer_fetch_ = desc->HasExtension(kFramebufferFetchExt);
103108

104-
if (gl.GetDescription()->HasExtension(kTextureBorderClampExt) ||
105-
gl.GetDescription()->HasExtension(kNvidiaTextureBorderClampExt) ||
106-
gl.GetDescription()->HasExtension(kOESTextureBorderClampExt)) {
109+
if (desc->HasExtension(kTextureBorderClampExt) ||
110+
desc->HasExtension(kNvidiaTextureBorderClampExt) ||
111+
desc->HasExtension(kOESTextureBorderClampExt)) {
107112
supports_decal_sampler_address_mode_ = true;
108113
}
109114

110-
if (gl.GetDescription()->HasExtension(
111-
"GL_EXT_multisampled_render_to_texture2") &&
112-
// The current implementation of MSAA support in Impeller GLES requires
113-
// the use of glBlitFramebuffer, which is not available on all GLES
114-
// implementations. We can't use MSAA on these platforms yet.
115-
gl.BlitFramebuffer.IsAvailable()) {
115+
if (desc->HasExtension(kMultisampledRenderToTextureExt)) {
116+
supports_implicit_msaa_ = true;
117+
116118
// We hard-code 4x MSAA, so let's make sure it's supported.
117119
GLint value = 0;
118120
gl.GetIntegerv(GL_MAX_SAMPLES_EXT, &value);
119-
120121
supports_offscreen_msaa_ = value >= 4;
121122
}
122123
}
@@ -140,6 +141,10 @@ bool CapabilitiesGLES::SupportsOffscreenMSAA() const {
140141
return supports_offscreen_msaa_;
141142
}
142143

144+
bool CapabilitiesGLES::SupportsImplicitResolvingMSAA() const {
145+
return supports_implicit_msaa_;
146+
}
147+
143148
bool CapabilitiesGLES::SupportsSSBO() const {
144149
return false;
145150
}

impeller/renderer/backend/gles/capabilities_gles.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ class CapabilitiesGLES final
7676
// |Capabilities|
7777
bool SupportsOffscreenMSAA() const override;
7878

79+
// |Capabilities|
80+
bool SupportsImplicitResolvingMSAA() const override;
81+
7982
// |Capabilities|
8083
bool SupportsSSBO() const override;
8184

@@ -119,6 +122,7 @@ class CapabilitiesGLES final
119122
bool supports_framebuffer_fetch_ = false;
120123
bool supports_decal_sampler_address_mode_ = false;
121124
bool supports_offscreen_msaa_ = false;
125+
bool supports_implicit_msaa_ = false;
122126
};
123127

124128
} // namespace impeller

impeller/renderer/backend/gles/render_pass_gles.cc

Lines changed: 9 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include "impeller/renderer/backend/gles/render_pass_gles.h"
66

7+
#include "GLES3/gl3.h"
78
#include "flutter/fml/trace_event.h"
89
#include "fml/closure.h"
910
#include "fml/logging.h"
@@ -127,7 +128,6 @@ struct RenderPassData {
127128
Scalar clear_depth = 1.0;
128129

129130
std::shared_ptr<Texture> color_attachment;
130-
std::shared_ptr<Texture> resolve_attachment;
131131
std::shared_ptr<Texture> depth_attachment;
132132
std::shared_ptr<Texture> stencil_attachment;
133133

@@ -474,52 +474,6 @@ struct RenderPassData {
474474
}
475475
}
476476

477-
// When we have a resolve_attachment, MSAA is being used. We blit from the
478-
// MSAA FBO to the resolve FBO, otherwise the resolve FBO ends up being
479-
// incomplete (because it has no attachments).
480-
//
481-
// Note that this only works on OpenGLES 3.0+, or put another way, in older
482-
// versions of OpenGLES, MSAA is not currently supported by Impeller. It's
483-
// possible to work around this issue a few different ways (not yet done).
484-
//
485-
// TODO(matanlurey): See https://github.com/flutter/flutter/issues/137093.
486-
if (!is_default_fbo && pass_data.resolve_attachment) {
487-
// MSAA should not be enabled if BlitFramebuffer is not available.
488-
FML_DCHECK(gl.BlitFramebuffer.IsAvailable());
489-
490-
GLuint draw_fbo = GL_NONE;
491-
fml::ScopedCleanupClosure delete_draw_fbo([&gl, &draw_fbo, fbo]() {
492-
if (draw_fbo != GL_NONE) {
493-
gl.BindFramebuffer(GL_FRAMEBUFFER, fbo);
494-
gl.DeleteFramebuffers(1u, &draw_fbo);
495-
}
496-
});
497-
498-
gl.GenFramebuffers(1u, &draw_fbo);
499-
gl.BindFramebuffer(GL_FRAMEBUFFER, draw_fbo);
500-
501-
auto resolve = TextureGLES::Cast(pass_data.resolve_attachment.get());
502-
if (!resolve->SetAsFramebufferAttachment(
503-
GL_FRAMEBUFFER, TextureGLES::AttachmentPoint::kColor0)) {
504-
return false;
505-
}
506-
507-
gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, draw_fbo);
508-
gl.BindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
509-
auto size = pass_data.resolve_attachment->GetSize();
510-
gl.BlitFramebuffer(0, // srcX0
511-
0, // srcY0
512-
size.width, // srcX1
513-
size.height, // srcY1
514-
0, // dstX0
515-
0, // dstY0
516-
size.width, // dstX1
517-
size.height, // dstY1
518-
GL_COLOR_BUFFER_BIT, // mask
519-
GL_NEAREST // filter
520-
);
521-
}
522-
523477
if (gl.DiscardFramebufferEXT.IsAvailable()) {
524478
std::vector<GLenum> attachments;
525479

@@ -576,12 +530,19 @@ bool RenderPassGLES::OnEncodeCommands(const Context& context) const {
576530
/// Setup color data.
577531
///
578532
pass_data->color_attachment = color0.texture;
579-
pass_data->resolve_attachment = color0.resolve_texture;
580533
pass_data->clear_color = color0.clear_color;
581534
pass_data->clear_color_attachment = CanClearAttachment(color0.load_action);
582535
pass_data->discard_color_attachment =
583536
CanDiscardAttachmentWhenDone(color0.store_action);
584537

538+
// When we are using EXT_multisampled_render_to_texture, it is implicitly
539+
// resolved when we bind the texture to the framebuffer. We don't need to
540+
// discard the attachment when we are done.
541+
if (color0.resolve_texture) {
542+
FML_DCHECK(context.GetCapabilities()->SupportsImplicitResolvingMSAA());
543+
pass_data->discard_color_attachment = false;
544+
}
545+
585546
//----------------------------------------------------------------------------
586547
/// Setup depth data.
587548
///

impeller/renderer/backend/vulkan/capabilities_vk.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,11 @@ bool CapabilitiesVK::SupportsOffscreenMSAA() const {
409409
return true;
410410
}
411411

412+
// |Capabilities|
413+
bool CapabilitiesVK::SupportsImplicitResolvingMSAA() const {
414+
return false;
415+
}
416+
412417
// |Capabilities|
413418
bool CapabilitiesVK::SupportsSSBO() const {
414419
return true;

impeller/renderer/backend/vulkan/capabilities_vk.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ class CapabilitiesVK final : public Capabilities,
6060
// |Capabilities|
6161
bool SupportsOffscreenMSAA() const override;
6262

63+
// |Capabilities|
64+
bool SupportsImplicitResolvingMSAA() const override;
65+
6366
// |Capabilities|
6467
bool SupportsSSBO() const override;
6568

impeller/renderer/capabilities.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ class StandardCapabilities final : public Capabilities {
2020
return supports_offscreen_msaa_;
2121
}
2222

23+
// |Capabilities|
24+
bool SupportsImplicitResolvingMSAA() const override { return false; }
25+
2326
// |Capabilities|
2427
bool SupportsSSBO() const override { return supports_ssbo_; }
2528

impeller/renderer/capabilities.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ class Capabilities {
1919
/// color/stencil textures.
2020
virtual bool SupportsOffscreenMSAA() const = 0;
2121

22+
/// @brief Whether the context backend supports multisampled rendering to
23+
/// the on-screen surface without requiring an explicit resolve of
24+
/// the MSAA color attachment.
25+
virtual bool SupportsImplicitResolvingMSAA() const = 0;
26+
2227
/// @brief Whether the context backend supports binding Shader Storage Buffer
2328
/// Objects (SSBOs) to pipelines.
2429
virtual bool SupportsSSBO() const = 0;

impeller/renderer/render_target.cc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,11 @@ RenderTarget RenderTarget::CreateOffscreenMSAA(
286286
color0_tex_desc.size = size;
287287
color0_tex_desc.usage = static_cast<uint64_t>(TextureUsage::kRenderTarget);
288288

289+
if (context.GetCapabilities()->SupportsImplicitResolvingMSAA()) {
290+
// See below ("SupportsImplicitResolvingMSAA") for more details.
291+
color0_tex_desc.storage_mode = StorageMode::kDevicePrivate;
292+
}
293+
289294
auto color0_msaa_tex = allocator.CreateTexture(color0_tex_desc);
290295
if (!color0_msaa_tex) {
291296
VALIDATION_LOG << "Could not create multisample color texture.";
@@ -322,6 +327,17 @@ RenderTarget RenderTarget::CreateOffscreenMSAA(
322327
color0.texture = color0_msaa_tex;
323328
color0.resolve_texture = color0_resolve_tex;
324329

330+
if (context.GetCapabilities()->SupportsImplicitResolvingMSAA()) {
331+
// If implicit MSAA is supported, then the resolve texture is not needed
332+
// because the multisample texture is automatically resolved. We instead
333+
// provide a view of the multisample texture as the resolve texture (because
334+
// the HAL does expect a resolve texture).
335+
//
336+
// In practice, this is used for GLES 2.0 EXT_multisampled_render_to_texture
337+
// https://registry.khronos.org/OpenGL/extensions/EXT/EXT_multisampled_render_to_texture.txt
338+
color0.resolve_texture = color0_msaa_tex;
339+
}
340+
325341
target.SetColorAttachment(color0, 0u);
326342

327343
// Create MSAA stencil texture.

0 commit comments

Comments
 (0)