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

Commit ec065be

Browse files
[Impeller] support GLES 3.0 MSAA without extension. (#56705)
Adds multisampling support for GLES devices without GL_EXT_multisampled_render_to_texture provided they are at least GLES 3.0 to support mutlisampled render buffers. Fixes flutter/flutter#158360 Fixes flutter/flutter#157951 TBD: should we prefer renderbuffer 3.0 approach over multisample_render_to_texture?
1 parent c2b2d1c commit ec065be

File tree

5 files changed

+102
-23
lines changed

5 files changed

+102
-23
lines changed

impeller/display_list/canvas.cc

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1667,10 +1667,15 @@ bool Canvas::BlitToOnscreen() {
16671667
auto offscreen_target = render_passes_.back()
16681668
.inline_pass_context->GetPassTarget()
16691669
.GetRenderTarget();
1670-
1670+
// Unlike other backends the blit to restore the onscreen fails for GLES
1671+
// if the src is a multisample framebuffer, even if we specifically target
1672+
// the non-multisampled resolve of the dst.
1673+
bool is_gles_and_must_skip_blit = renderer_.GetContext()->GetBackendType() ==
1674+
Context::BackendType::kOpenGLES;
16711675
if (renderer_.GetContext()
16721676
->GetCapabilities()
1673-
->SupportsTextureToTextureBlits()) {
1677+
->SupportsTextureToTextureBlits() &&
1678+
!is_gles_and_must_skip_blit) {
16741679
auto blit_pass = command_buffer->CreateBlitPass();
16751680
blit_pass->AddCopy(offscreen_target.GetRenderTargetTexture(),
16761681
render_target_.GetRenderTargetTexture());

impeller/renderer/backend/gles/capabilities_gles.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,11 @@ CapabilitiesGLES::CapabilitiesGLES(const ProcTableGLES& gl) {
125125

126126
// We hard-code 4x MSAA, so let's make sure it's supported.
127127
GLint value = 0;
128-
gl.GetIntegerv(GL_MAX_SAMPLES_EXT, &value);
128+
gl.GetIntegerv(GL_MAX_SAMPLES, &value);
129+
supports_offscreen_msaa_ = value >= 4;
130+
} else if (desc->GetGlVersion().major_version >= 3 && desc->IsES()) {
131+
GLint value = 0;
132+
gl.GetIntegerv(GL_MAX_SAMPLES, &value);
129133
supports_offscreen_msaa_ = value >= 4;
130134
}
131135
is_es_ = desc->IsES();

impeller/renderer/backend/gles/proc_table_gles.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ void(glDepthRange)(GLdouble n, GLdouble f);
242242
PROC(FenceSync); \
243243
PROC(DeleteSync); \
244244
PROC(WaitSync); \
245+
PROC(RenderbufferStorageMultisample) \
245246
PROC(BlitFramebuffer);
246247

247248
#define FOR_EACH_IMPELLER_EXT_PROC(PROC) \

impeller/renderer/backend/gles/render_pass_gles.cc

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
#include <cstdint>
88

99
#include "GLES3/gl3.h"
10-
#include "flutter/fml/trace_event.h"
1110
#include "fml/closure.h"
1211
#include "fml/logging.h"
1312
#include "impeller/base/validation.h"
@@ -127,6 +126,7 @@ struct RenderPassData {
127126
Scalar clear_depth = 1.0;
128127

129128
std::shared_ptr<Texture> color_attachment;
129+
std::shared_ptr<Texture> resolve_attachment;
130130
std::shared_ptr<Texture> depth_attachment;
131131
std::shared_ptr<Texture> stencil_attachment;
132132

@@ -191,8 +191,6 @@ void RenderPassGLES::ResetGLState(const ProcTableGLES& gl) {
191191
const ReactorGLES& reactor,
192192
const std::vector<Command>& commands,
193193
const std::shared_ptr<GPUTracerGLES>& tracer) {
194-
TRACE_EVENT0("impeller", "RenderPassGLES::EncodeCommandsInReactor");
195-
196194
const auto& gl = reactor.GetProcTable();
197195
#ifdef IMPELLER_DEBUG
198196
tracer->MarkFrameStart(gl);
@@ -490,6 +488,55 @@ void RenderPassGLES::ResetGLState(const ProcTableGLES& gl) {
490488
}
491489
}
492490

491+
if (pass_data.resolve_attachment &&
492+
!gl.GetCapabilities()->SupportsImplicitResolvingMSAA() &&
493+
!is_default_fbo) {
494+
FML_DCHECK(pass_data.resolve_attachment != pass_data.color_attachment);
495+
// Perform multisample resolve via blit.
496+
// Create and bind a resolve FBO.
497+
GLuint resolve_fbo;
498+
gl.GenFramebuffers(1u, &resolve_fbo);
499+
gl.BindFramebuffer(GL_FRAMEBUFFER, resolve_fbo);
500+
501+
if (!TextureGLES::Cast(*pass_data.resolve_attachment)
502+
.SetAsFramebufferAttachment(
503+
GL_FRAMEBUFFER, TextureGLES::AttachmentType::kColor0)) {
504+
return false;
505+
}
506+
507+
auto status = gl.CheckFramebufferStatus(GL_FRAMEBUFFER);
508+
if (gl.CheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
509+
VALIDATION_LOG << "Could not create a complete frambuffer: "
510+
<< DebugToFramebufferError(status);
511+
return false;
512+
}
513+
514+
// Bind MSAA renderbuffer to read framebuffer.
515+
gl.BindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
516+
gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, resolve_fbo);
517+
518+
RenderPassGLES::ResetGLState(gl);
519+
auto size = pass_data.color_attachment->GetSize();
520+
521+
gl.BlitFramebuffer(0, // srcX0
522+
0, // srcY0
523+
size.width, // srcX1
524+
size.height, // srcY1
525+
0, // dstX0
526+
0, // dstY0
527+
size.width, // dstX1
528+
size.height, // dstY1
529+
GL_COLOR_BUFFER_BIT, // mask
530+
GL_NEAREST // filter
531+
);
532+
533+
gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, GL_NONE);
534+
gl.BindFramebuffer(GL_READ_FRAMEBUFFER, GL_NONE);
535+
gl.DeleteFramebuffers(1u, &resolve_fbo);
536+
// Rebind the original FBO so that we can discard it below.
537+
gl.BindFramebuffer(GL_FRAMEBUFFER, fbo);
538+
}
539+
493540
if (gl.DiscardFramebufferEXT.IsAvailable()) {
494541
std::vector<GLenum> attachments;
495542

@@ -547,6 +594,7 @@ bool RenderPassGLES::OnEncodeCommands(const Context& context) const {
547594
/// Setup color data.
548595
///
549596
pass_data->color_attachment = color0.texture;
597+
pass_data->resolve_attachment = color0.resolve_texture;
550598
pass_data->clear_color = color0.clear_color;
551599
pass_data->clear_color_attachment = CanClearAttachment(color0.load_action);
552600
pass_data->discard_color_attachment =
@@ -556,8 +604,9 @@ bool RenderPassGLES::OnEncodeCommands(const Context& context) const {
556604
// resolved when we bind the texture to the framebuffer. We don't need to
557605
// discard the attachment when we are done.
558606
if (color0.resolve_texture) {
559-
FML_DCHECK(context.GetCapabilities()->SupportsImplicitResolvingMSAA());
560-
pass_data->discard_color_attachment = false;
607+
pass_data->discard_color_attachment =
608+
pass_data->discard_color_attachment &&
609+
!context.GetCapabilities()->SupportsImplicitResolvingMSAA();
561610
}
562611

563612
//----------------------------------------------------------------------------

impeller/renderer/backend/gles/texture_gles.cc

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,18 @@ static bool IsDepthStencilFormat(PixelFormat format) {
4545
}
4646

4747
static TextureGLES::Type GetTextureTypeFromDescriptor(
48-
const TextureDescriptor& desc) {
48+
const TextureDescriptor& desc,
49+
bool supports_implict_msaa) {
4950
const auto usage = static_cast<TextureUsageMask>(desc.usage);
5051
const auto render_target = TextureUsage::kRenderTarget;
5152
const auto is_msaa = desc.sample_count == SampleCount::kCount4;
5253
if (usage == render_target && IsDepthStencilFormat(desc.format)) {
5354
return is_msaa ? TextureGLES::Type::kRenderBufferMultisampled
5455
: TextureGLES::Type::kRenderBuffer;
5556
}
56-
return is_msaa ? TextureGLES::Type::kTextureMultisampled
57+
return is_msaa ? (supports_implict_msaa
58+
? TextureGLES::Type::kTextureMultisampled
59+
: TextureGLES::Type::kRenderBufferMultisampled)
5760
: TextureGLES::Type::kTexture;
5861
}
5962

@@ -190,7 +193,11 @@ TextureGLES::TextureGLES(std::shared_ptr<ReactorGLES> reactor,
190193
std::optional<HandleGLES> external_handle)
191194
: Texture(desc),
192195
reactor_(std::move(reactor)),
193-
type_(GetTextureTypeFromDescriptor(GetTextureDescriptor())),
196+
type_(
197+
GetTextureTypeFromDescriptor(GetTextureDescriptor(),
198+
reactor_->GetProcTable()
199+
.GetCapabilities()
200+
->SupportsImplicitResolvingMSAA())),
194201
handle_(external_handle.has_value()
195202
? external_handle.value()
196203
: reactor_->CreateHandle(ToHandleType(type_))),
@@ -362,7 +369,7 @@ static std::optional<GLenum> ToRenderBufferFormat(PixelFormat format) {
362369
switch (format) {
363370
case PixelFormat::kB8G8R8A8UNormInt:
364371
case PixelFormat::kR8G8B8A8UNormInt:
365-
return GL_RGBA4;
372+
return GL_RGBA8;
366373
case PixelFormat::kR32G32B32A32Float:
367374
return GL_RGBA32F;
368375
case PixelFormat::kR16G16B16A16Float:
@@ -445,19 +452,32 @@ void TextureGLES::InitializeContentsIfNecessary() const {
445452
{
446453
TRACE_EVENT0("impeller", "RenderBufferStorageInitialization");
447454
if (type_ == Type::kRenderBufferMultisampled) {
448-
gl.RenderbufferStorageMultisampleEXT(
449-
GL_RENDERBUFFER, // target
450-
4, // samples
451-
render_buffer_format.value(), // internal format
452-
size.width, // width
453-
size.height // height
454-
);
455+
// BEWARE: these functions are not at all equivalent! the extensions
456+
// are from EXT_multisampled_render_to_texture and cannot be used
457+
// with regular GLES 3.0 multisampled renderbuffers/textures.
458+
if (gl.GetCapabilities()->SupportsImplicitResolvingMSAA()) {
459+
gl.RenderbufferStorageMultisampleEXT(
460+
/*target=*/GL_RENDERBUFFER, //
461+
/*samples=*/4, //
462+
/*internal_format=*/render_buffer_format.value(), //
463+
/*width=*/size.width, //
464+
/*height=*/size.height //
465+
);
466+
} else {
467+
gl.RenderbufferStorageMultisample(
468+
/*target=*/GL_RENDERBUFFER, //
469+
/*samples=*/4, //
470+
/*internal_format=*/render_buffer_format.value(), //
471+
/*width=*/size.width, //
472+
/*height=*/size.height //
473+
);
474+
}
455475
} else {
456476
gl.RenderbufferStorage(
457-
GL_RENDERBUFFER, // target
458-
render_buffer_format.value(), // internal format
459-
size.width, // width
460-
size.height // height
477+
/*target=*/GL_RENDERBUFFER, //
478+
/*internal_format=*/render_buffer_format.value(), //
479+
/*width=*/size.width, //
480+
/*height=*/size.height //
461481
);
462482
}
463483
}

0 commit comments

Comments
 (0)