@@ -130,6 +130,7 @@ struct RenderPassData {
130130 Scalar clear_depth = 1.0 ;
131131
132132 std::shared_ptr<Texture> color_attachment;
133+ std::shared_ptr<Texture> resolve_attachment;
133134 std::shared_ptr<Texture> depth_attachment;
134135 std::shared_ptr<Texture> stencil_attachment;
135136
@@ -214,6 +215,7 @@ void RenderPassGLES::ResetGLState(const ProcTableGLES& gl) {
214215 TextureGLES& color_gles = TextureGLES::Cast (*pass_data.color_attachment );
215216 const bool is_default_fbo = color_gles.IsWrapped ();
216217
218+ std::optional<GLuint> fbo = 0 ;
217219 if (is_default_fbo) {
218220 if (color_gles.GetFBO ().has_value ()) {
219221 // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
@@ -222,7 +224,7 @@ void RenderPassGLES::ResetGLState(const ProcTableGLES& gl) {
222224 } else {
223225 // Create and bind an offscreen FBO.
224226 if (!color_gles.GetCachedFBO ().IsDead ()) {
225- auto fbo = reactor.GetGLHandle (color_gles.GetCachedFBO ());
227+ fbo = reactor.GetGLHandle (color_gles.GetCachedFBO ());
226228 if (!fbo.has_value ()) {
227229 return false ;
228230 }
@@ -231,7 +233,7 @@ void RenderPassGLES::ResetGLState(const ProcTableGLES& gl) {
231233 HandleGLES cached_fbo =
232234 reactor.CreateUntrackedHandle (HandleType::kFrameBuffer );
233235 color_gles.SetCachedFBO (cached_fbo);
234- auto fbo = reactor.GetGLHandle (cached_fbo);
236+ fbo = reactor.GetGLHandle (cached_fbo);
235237 if (!fbo.has_value ()) {
236238 return false ;
237239 }
@@ -520,6 +522,54 @@ void RenderPassGLES::ResetGLState(const ProcTableGLES& gl) {
520522 }
521523 }
522524
525+ if (pass_data.resolve_attachment &&
526+ !gl.GetCapabilities ()->SupportsImplicitResolvingMSAA () &&
527+ !is_default_fbo) {
528+ FML_DCHECK (pass_data.resolve_attachment != pass_data.color_attachment );
529+ // Perform multisample resolve via blit.
530+ // Create and bind a resolve FBO.
531+ GLuint resolve_fbo;
532+ gl.GenFramebuffers (1u , &resolve_fbo);
533+ gl.BindFramebuffer (GL_FRAMEBUFFER, resolve_fbo);
534+
535+ if (!TextureGLES::Cast (*pass_data.resolve_attachment )
536+ .SetAsFramebufferAttachment (
537+ GL_FRAMEBUFFER, TextureGLES::AttachmentType::kColor0 )) {
538+ return false ;
539+ }
540+
541+ auto status = gl.CheckFramebufferStatus (GL_FRAMEBUFFER);
542+ if (gl.CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
543+ VALIDATION_LOG << " Could not create a complete frambuffer: "
544+ << DebugToFramebufferError (status);
545+ return false ;
546+ }
547+
548+ // Bind MSAA renderbuffer to read framebuffer.
549+ gl.BindFramebuffer (GL_READ_FRAMEBUFFER, fbo.value ());
550+ gl.BindFramebuffer (GL_DRAW_FRAMEBUFFER, resolve_fbo);
551+
552+ RenderPassGLES::ResetGLState (gl);
553+ auto size = pass_data.color_attachment ->GetSize ();
554+
555+ gl.BlitFramebuffer (/* srcX0=*/ 0 ,
556+ /* srcY0=*/ 0 ,
557+ /* srcX1=*/ size.width ,
558+ /* srcY1=*/ size.height ,
559+ /* dstX0=*/ 0 ,
560+ /* dstY0=*/ 0 ,
561+ /* dstX1=*/ size.width ,
562+ /* dstY1=*/ size.height ,
563+ /* mask=*/ GL_COLOR_BUFFER_BIT,
564+ /* filter=*/ GL_NEAREST);
565+
566+ gl.BindFramebuffer (GL_DRAW_FRAMEBUFFER, GL_NONE);
567+ gl.BindFramebuffer (GL_READ_FRAMEBUFFER, GL_NONE);
568+ gl.DeleteFramebuffers (1u , &resolve_fbo);
569+ // Rebind the original FBO so that we can discard it below.
570+ gl.BindFramebuffer (GL_FRAMEBUFFER, fbo.value ());
571+ }
572+
523573 if (gl.DiscardFramebufferEXT .IsAvailable ()) {
524574 std::array<GLenum, 3 > attachments;
525575 size_t attachment_count = 0 ;
@@ -580,17 +630,21 @@ bool RenderPassGLES::OnEncodeCommands(const Context& context) const {
580630 // / Setup color data.
581631 // /
582632 pass_data->color_attachment = color0.texture ;
633+ pass_data->resolve_attachment = color0.resolve_texture ;
583634 pass_data->clear_color = color0.clear_color ;
584635 pass_data->clear_color_attachment = CanClearAttachment (color0.load_action );
585636 pass_data->discard_color_attachment =
586637 CanDiscardAttachmentWhenDone (color0.store_action );
587638
588639 // When we are using EXT_multisampled_render_to_texture, it is implicitly
589640 // resolved when we bind the texture to the framebuffer. We don't need to
590- // discard the attachment when we are done.
641+ // discard the attachment when we are done. If not using
642+ // EXT_multisampled_render_to_texture but still using MSAA we discard the
643+ // attachment as normal.
591644 if (color0.resolve_texture ) {
592- FML_DCHECK (context.GetCapabilities ()->SupportsImplicitResolvingMSAA ());
593- pass_data->discard_color_attachment = false ;
645+ pass_data->discard_color_attachment =
646+ pass_data->discard_color_attachment &&
647+ !context.GetCapabilities ()->SupportsImplicitResolvingMSAA ();
594648 }
595649
596650 // ----------------------------------------------------------------------------
0 commit comments