From 49b4523152e185fba450c0bbbafd4375eb76eef1 Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Tue, 24 Oct 2023 11:01:00 -0700 Subject: [PATCH] [Impeller] Enable MSAA for OpenGLES: Take 2. (flutter/engine#47030) Closes https://github.com/flutter/flutter/issues/130045. Continues the work started in https://github.com/flutter/engine/pull/46381. _This is PR supercedes https://github.com/flutter/engine/pull/46688._ It's worth calling out the mechanism we're using is only supported in OpenGL 3.0+, so we'll need a different solution (either by default, or when Blit is not available) to get proper device support. I'll file an issue before merging. ## Status Appears to work! I validated it on a local demo app, flutter_gallery, and Wonderous. Example: ![flutter_05](https://github.com/flutter/engine/assets/168174/36f41602-511c-4b62-95d6-e09b56f89566) --- ## Background
History
**Still blocked**, but MSAA is working provided you use a phone with OpenGLES 3.0+. The last bit is getting stencil attachments to work again (they currently crash with a `GL_INVALID_OPERATION`). Compared to #46688, we''ve corrected some incorrect OpenGL calls and assumptions - for example we now have both multi-sampled textures similar to the [`MultisampledFBO.cpp`](https://github.com/ARM-software/opengl-es-sdk-for-android/blob/master/samples/advanced_samples/MultisampledFBO/jni/MultisampledFBO.cpp#L702) example. After doing so, the GL driver is successfully called, and no errors or crashes persist. Yay! We did need to use [`glBlitFramebuffer`](https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glBlitFramebuffer.xhtml) to move from the resolve texture to the color attachment, and referenced some other [example code](https://github.com/VictorGordan/opengl-tutorials/blob/346624ecc5a03f0f6d1d19247db0cc68d21bb7a5/YoutubeOpenGL%2027%20-%20Normal%20Maps/Main.cpp#L274) for that.
Example App ```dart import 'package:flutter/material.dart'; void main() { runApp(const MainApp()); } class MainApp extends StatefulWidget { const MainApp({super.key}); @override State createState() => _MainAppState(); } class _MainAppState extends State { bool msaa = true; @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: const Text('Force offscreen MSAA'), actions: [ Switch( value: msaa, onChanged: (value) { setState(() { msaa = value; }); }, ), ], ), body: Center( child: ForceOffscreenMSAA(opaque: !msaa), ), ), ); } } // Draws 2 overlapping circles (BoxDecoration/BoxShape) wrapped in 50% opacity. class ForceOffscreenMSAA extends StatelessWidget { final bool opaque; const ForceOffscreenMSAA({required this.opaque, super.key}); @override Widget build(BuildContext context) { return Opacity( opacity: opaque ? 1.0 : 0.5, child: const DecoratedBox( decoration: BoxDecoration( shape: BoxShape.circle, color: Colors.red, ), child: SizedBox( width: 300, height: 300, child: DecoratedBox( decoration: BoxDecoration( shape: BoxShape.circle, color: Colors.green, ), ), ), ), ); } } ```
Screenshots ![Disabled](https://github.com/flutter/engine/assets/168174/0b00e278-fb8f-468d-b5ae-896341789d3f) ![Enabled](https://github.com/flutter/engine/assets/168174/045d056a-2a23-4a27-be9a-b8fbc3e60fb8)
Open GL Commands during MSAA Render ```txt glClearStencil(, 0) glDisable(, 3089) glDisable(, 2929) glDisable(, 2960) glDisable(, 2884) glDisable(, 3042) glColorMask(, 1, 1, 1, 1) glClear(, 17664) glPushDebugGroupKHR(, 33354, 1367, 10, Solid Fill) glDisable(, 3042) glColorMask(, , , , ) glEnable(, 2960) glStencilOpSeparate(, 1032, 7680, 7680, 7680) glStencilFuncSeparate(, 1032, 514, 0, 4294967295) glStencilMaskSeparate(, 1032, 4294967295) glDisable(, 2929) glViewport(, 0, 0, 787, 787) glDisable(, 3089) glDisable(, 2884) glFrontFace(, 2304) glGenBuffers(, 1, 0x6f9900a578) glBindBuffer(, 34962, 1) glBufferData(, 34962, 4480, , 35044) glUseProgram(, 56) glEnableVertexAttribArray(, 0) glVertexAttribPointer(, 0, 2, 5126, 0, 8, 0x0) glUniformMatrix4fv(, 0, 1, 0, 0xb4000070aadbc860) glUniform4fv(, 1, 1, 0xb4000070aadbc8a0) glBindBuffer(, 34963, 1) glDrawElements(, 4, 426, 5123, 0x480) glDisableVertexAttribArray(, 0) glUseProgram(, 0) glPopDebugGroupKHR() glPushDebugGroupKHR(, 33354, 1369, 10, Solid Fill) glDisable(, 3042) glColorMask(, , , , ) glEnable(, 2960) glStencilOpSeparate(, 1032, 7680, 7680, 7680) glStencilFuncSeparate(, 1032, 514, 0, 4294967295) glStencilMaskSeparate(, 1032, 4294967295) glDisable(, 2929) glViewport(, 0, 0, 787, 787) glDisable(, 3089) glDisable(, 2884) glFrontFace(, 2304) glBindBuffer(, 34962, 1) glUseProgram(, 56) glEnableVertexAttribArray(, 0) glVertexAttribPointer(, 0, 2, 5126, 0, 8, 0x880) glUniformMatrix4fv(, 0, 1, 0, 0xb4000070aadbd160) glUniform4fv(, 1, 1, 0xb4000070aadbd1a0) glBindBuffer(, 34963, 1) glDrawElements(, 4, 426, 5123, 0xd00) glDisableVertexAttribArray(, 0) glUseProgram(, 0) glPopDebugGroupKHR() glDiscardFramebufferEXT(, 36160, 3, 0xb4000071cad5b590) glBindFramebuffer(, 36160, 0) glDeleteFramebuffers(, 1, 0x6f9900b25c) glPopDebugGroupKHR() glDeleteBuffers(, 1, 0x6f9900ce98) glDebugMessageControlKHR(, 4352, 4352, 4352, 0, nullptr, 1) glPushDebugGroupKHR(, 33354, 1370, 39, EntityPass Render Pass: Depth=0 Count=0) glClearColor(, 1, 0.984314, 0.996078, 1) glClearStencil(, 0) glDisable(, 3089) glDisable(, 2929) glDisable(, 2960) glDisable(, 2884) glDisable(, 3042) glColorMask(, 1, 1, 1, 1) glClear(, 17664) glPushDebugGroupKHR(, 33354, 1371, 21, Texture Fill: Subpass) glEnable(, 3042) glBlendFuncSeparate(, 1, 771, 1, 771) glBlendEquationSeparate(, 32774, 32774) glColorMask(, , , , ) glEnable(, 2960) glStencilOpSeparate(, 1032, 7680, 7680, 7680) glStencilFuncSeparate(, 1032, 514, 0, 4294967295) glStencilMaskSeparate(, 1032, 4294967295) glDisable(, 2929) glViewport(, 0, 0, 1080, 2029) glDisable(, 3089) glDisable(, 2884) glFrontFace(, 2304) glGenBuffers(, 1, 0x6f9900bfc8) glBindBuffer(, 34962, 1) glBufferData(, 34962, 11360, , 35044) glUseProgram(, 57) glEnableVertexAttribArray(, 0) glVertexAttribPointer(, 0, 2, 5126, 0, 16, 0x0) glEnableVertexAttribArray(, 1) glVertexAttribPointer(, 1, 2, 5126, 0, 16, 0x8) glUniformMatrix4fv(, 1, 1, 0, 0xb40000705ad2f200) glUniform1fv(, 2, 1, 0xb40000705ad2f240) glUniform1fv(, 3, 1, 0xb40000705ad2f244) glActiveTexture(, 33984) glBindTexture(, 3553, 1) glTexParameteri(, 3553, 10241, 9728) glTexParameteri(, 3553, 10240, 9728) glTexParameteri(, 3553, 10242, 33071) glTexParameteri(, 3553, 10243, 33071) glUniform1i(, 0, 0) glDrawArrays(, 5, 0, 4) glDisableVertexAttribArray(, 0) glDisableVertexAttribArray(, 1) glUseProgram(, 0) glPopDebugGroupKHR() glPushDebugGroupKHR(, 33354, 1373, 10, Solid Fill) glDisable(, 3042) glColorMask(, , , , ) glEnable(, 2960) glStencilOpSeparate(, 1032, 7680, 7680, 7680) glStencilFuncSeparate(, 1032, 514, 0, 4294967295) glStencilMaskSeparate(, 1032, 4294967295) glDisable(, 2929) glViewport(, 0, 0, 1080, 2029) glDisable(, 3089) glDisable(, 2884) glFrontFace(, 2304) glBindBuffer(, 34962, 1) glUseProgram(, 58) glEnableVertexAttribArray(, 0) glVertexAttribPointer(, 0, 2, 5126, 0, 8, 0x180) glUniformMatrix4fv(, 0, 1, 0, 0xb40000705ad2f300) glUniform4fv(, 1, 1, 0xb40000705ad2f340) glDrawArrays(, 5, 0, 4) glDisableVertexAttribArray(, 0) glUseProgram(, 0) glPopDebugGroupKHR() glPushDebugGroupKHR(, 33354, 1374, 14, Intersect Clip) glEnable(, 3042) glBlendFuncSeparate(, 0, 1, 0, 1) glBlendEquationSeparate(, 32774, 32774) glColorMask(, glEnable(, 2960) glStencilOpSeparate(, 1032, 7680, 7680, 7682) glStencilFuncSeparate(, 1032, 514, 0, 4294967295) glStencilMaskSeparate(, 1032, 4294967295) glDisable(, 2929) glViewport(, 0, 0, 1080, 2029) glDisable(, 3089) glDisable(, 2884) glFrontFace(, 2304) glBindBuffer(, 34962, 1) glUseProgram(, 59) glEnableVertexAttribArray(, 0) glVertexAttribPointer(, 0, 2, 5126, 0, 8, 0x280) glUniformMatrix4fv(, 0, 1, 0, 0xb40000705ad2f400) glDrawArrays(, 5, 0, 4) glDisableVertexAttribArray(, 0) glUseProgram(, 0) glPopDebugGroupKHR() glPushDebugGroupKHR(, 33354, 1375, 9, TextFrame) glEnable(, 3042) glBlendFuncSeparate(, 1, 771, 1, 771) glBlendEquationSeparate(, 32774, 32774) glColorMask(, , , , ) glEnable(, 2960) glStencilOpSeparate(, 1032, 7680, 7680, 7680) glStencilFuncSeparate(, 1032, 514, 1, 4294967295) glStencilMaskSeparate(, 1032, 4294967295) glDisable(, 2929) glViewport(, 0, 0, 1080, 2029) glDisable(, 3089) glDisable(, 2884) glFrontFace(, 2304) glBindBuffer(, 34962, 1) glUseProgram(, 60) glEnableVertexAttribArray(, 0) glVertexAttribPointer(, 0, 4, 5126, 0, 48, 0x4c0) glEnableVertexAttribArray(, 3) glVertexAttribPointer(, 3, 2, 5126, 0, 48, 0x4e8) glEnableVertexAttribArray(, 1) glVertexAttribPointer(, 1, 4, 5126, 0, 48, 0x4d0) glEnableVertexAttribArray(, 2) glVertexAttribPointer(, 2, 2, 5126, 0, 48, 0x4e0) glUniformMatrix4fv(, 1, 1, 0, 0xb40000705ad2f500) glUniformMatrix4fv(, 2, 1, 0, 0xb40000705ad2f540) glUniform2fv(, 3, 1, 0xb40000705ad2f580) glUniform2fv(, 4, 1, 0xb40000705ad2f588) glUniform4fv(, 5, 1, 0xb40000705ad2f590) glUniform1fv(, 6, 1, 0xb40000705ad2f5a0) glActiveTexture(, 33984) glBindTexture(, 3553, 2) glTexParameteri(, 3553, 10241, 9728) glTexParameteri(, 3553, 10240, 9728) glTexParameteri(, 3553, 10242, 33071) glTexParameteri(, 3553, 10243, 33071) glUniform1i(, 0, 0) glDrawArrays(, 4, 0, 120) glDisableVertexAttribArray(, 0) glDisableVertexAttribArray(, 3) glDisableVertexAttribArray(, 1) glDisableVertexAttribArray(, 2) glUseProgram(, 0) glPopDebugGroupKHR() glPushDebugGroupKHR(, 33354, 1376, 10, Solid Fill) glDisable(, 3042) glColorMask(, , , , ) glEnable(, 2960) glStencilOpSeparate(, 1032, 7680, 7680, 7680) glStencilFuncSeparate(, 1032, 514, 1, 4294967295) glStencilMaskSeparate(, 1032, 4294967295) glDisable(, 2929) glViewport(, 0, 0, 1080, 2029) glDisable(, 3089) glDisable(, 2884) glFrontFace(, 2304) glBindBuffer(, 34962, 1) glUseProgram(, 61) glEnableVertexAttribArray(, 0) glVertexAttribPointer(, 0, 2, 5126, 0, 8, 0x1b40) glUniformMatrix4fv(, 0, 1, 0, 0xb40000705ad30f00) glUniform4fv(, 1, 1, 0xb40000705ad30f40) glBindBuffer(, 34963, 1) glDrawElements(, 4, 144, 5123, 0x1cd0) glDisableVertexAttribArray(, 0) glUseProgram(, 0) glPopDebugGroupKHR() glPushDebugGroupKHR(, 33354, 1377, 10, Solid Fill) glDisable(, 3042) glColorMask(, , , , ) glEnable(, 2960) glStencilOpSeparate(, 1032, 7680, 7680, 7680) glStencilFuncSeparate(, 1032, 514, 1, 4294967295) glStencilMaskSeparate(, 1032, 4294967295) glDisable(, 2929) glViewport(, 0, 0, 1080, 2029) glDisable(, 3089) glDisable(, 2884) glFrontFace(, 2304) glBindBuffer(, 34962, 1) glUseProgram(, 61) glEnableVertexAttribArray(, 0) glVertexAttribPointer(, 0, 2, 5126, 0, 8, 0x1e80) glUniformMatrix4fv(, 0, 1, 0, 0xb40000705ad31200) glUniform4fv(, 1, 1, 0xb40000705ad31240) glBindBuffer(, 34963, 1) glDrawElements(, 4, 114, 5123, 0x1fc0) glDisableVertexAttribArray(, 0) glUseProgram(, 0) glPopDebugGroupKHR() glPushDebugGroupKHR(, 33354, 1378, 12, Restore Clip) glEnable(, 3042) glBlendFuncSeparate(, 0, 1, 0, 1) glBlendEquationSeparate(, 32774, 32774) glColorMask(, glEnable(, 2960) glStencilOpSeparate(, 1032, 7680, 7680, 7681) glStencilFuncSeparate(, 1032, 513, 0, 4294967295) glStencilMaskSeparate(, 1032, 4294967295) glDisable(, 2929) glViewport(, 0, 0, 1080, 2029) glDisable(, 3089) glDisable(, 2884) glFrontFace(, 2304) glBindBuffer(, 34962, 1) glUseProgram(, 62) glEnableVertexAttribArray(, 0) glVertexAttribPointer(, 0, 2, 5126, 0, 8, 0x2180) glUniformMatrix4fv(, 0, 1, 0, 0xb40000705ad31300) glDrawArrays(, 5, 0, 4) glDisableVertexAttribArray(, 0) glUseProgram(, 0) glPopDebugGroupKHR() glPushDebugGroupKHR(, 33354, 1379, 12, RRect Shadow) glEnable(, 3042) glBlendFuncSeparate(, 1, 771, 1, 771) glBlendEquationSeparate(, 32774, 32774) glColorMask(, , , , ) glEnable(, 2960) glStencilOpSeparate(, 1032, 7680, 7680, 7680) glStencilFuncSeparate(, 1032, 514, 0, 4294967295) glStencilMaskSeparate(, 1032, 4294967295) glDisable(, 2929) glViewport(, 0, 0, 1080, 2029) glDisable(, 3089) glDisable(, 2884) glFrontFace(, 2304) glBindBuffer(, 34962, 1) glUseProgram(, 63) glEnableVertexAttribArray(, 0) glVertexAttribPointer(, 0, 2, 5126, 0, 8, 0x2240) glUniformMatrix4fv(, 0, 1, 0, 0xb40000705ad31400) glUniform4fv(, 1, 1, 0xb40000705ad31500) glUniform2fv(, 2, 1, 0xb40000705ad31510) glUniform1fv(, 3, 1, 0xb40000705ad31518) glUniform1fv(, 4, 1, 0xb40000705ad3151c) glDrawArrays(, 5, 0, 4) glDisableVertexAttribArray(, 0) glUseProgram(, 0) glPopDebugGroupKHR() glPushDebugGroupKHR(, 33354, 1380, 10, Solid Fill) glEnable(, 3042) glBlendFuncSeparate(, 1, 771, 1, 771) glBlendEquationSeparate(, 32774, 32774) glColorMask(, , , , ) glEnable(, 2960) glStencilOpSeparate(, 1032, 7680, 7680, 7680) glStencilFuncSeparate(, 1032, 514, 0, 4294967295) glStencilMaskSeparate(, 1032, 4294967295) glDisable(, 2929) glViewport(, 0, 0, 1080, 2029) glDisable(, 3089) glDisable(, 2884) glFrontFace(, 2304) glBindBuffer(, 34962, 1) glUseProgram(, 64) glEnableVertexAttribArray(, 0) glVertexAttribPointer(, 0, 2, 5126, 0, 8, 0x2420) glUniformMatrix4fv(, 0, 1, 0, 0xb40000705ad31600) glUniform4fv(, 1, 1, 0xb40000705ad31640) glDrawArrays(, 5, 0, 4) glDisableVertexAttribArray(, 0) glUseProgram(, 0) glPopDebugGroupKHR() glPushDebugGroupKHR(, 33354, 1381, 9, TextFrame) glEnable(, 3042) glBlendFuncSeparate(, 1, 771, 1, 771) glBlendEquationSeparate(, 32774, 32774) glColorMask(, , , , ) glEnable(, 2960) glStencilOpSeparate(, 1032, 7680, 7680, 7680) glStencilFuncSeparate(, 1032, 514, 0, 4294967295) glStencilMaskSeparate(, 1032, 4294967295) glDisable(, 2929) glViewport(, 0, 0, 1080, 2029) glDisable(, 3089) glDisable(, 2884) glFrontFace(, 2304) glBindBuffer(, 34962, 1) glUseProgram(, 60) glEnableVertexAttribArray(, 0) glVertexAttribPointer(, 0, 4, 5126, 0, 48, 0x26c0) glEnableVertexAttribArray(, 3) glVertexAttribPointer(, 3, 2, 5126, 0, 48, 0x26e8) glEnableVertexAttribArray(, 1) glVertexAttribPointer(, 1, 4, 5126, 0, 48, 0x26d0) glEnableVertexAttribArray(, 2) glVertexAttribPointer(, 2, 2, 5126, 0, 48, 0x26e0) glUniformMatrix4fv(, 1, 1, 0, 0xb40000705ad31700) glUniformMatrix4fv(, 2, 1, 0, 0xb40000705ad31740) glUniform2fv(, 3, 1, 0xb40000705ad31780) glUniform2fv(, 4, 1, 0xb40000705ad31788) glUniform4fv(, 5, 1, 0xb40000705ad31790) glUniform1fv(, 6, 1, 0xb40000705ad317a0) glActiveTexture(, 33984) glBindTexture(, 3553, 2) glTexParameteri(, 3553, 10241, 9729) glTexParameteri(, 3553, 10240, 9729) glTexParameteri(, 3553, 10242, 33071) glTexParameteri(, 3553, 10243, 33071) glUniform1i(, 0, 0) glDrawArrays(, 4, 0, 30) glDisableVertexAttribArray(, 0) glDisableVertexAttribArray(, 3) glDisableVertexAttribArray(, 1) glDisableVertexAttribArray(, 2) glUseProgram(, 0) glPopDebugGroupKHR() glDiscardFramebufferEXT(, 36160, 2, 0xb4000071cad5b310) glPopDebugGroupKHR() ```
AGI Trace Screenshot 2023-10-17 at 3 21 44 PM Screenshot 2023-10-17 at 3 21 51 PM
~~As you can see, with MSAA enabled I get a weird mostly-blank artifact (or sometimes entirely blank).~~ UPDATE: FIXED. What we tried (h/t @jonahwilliams): - [x] Using AGI (with the ANGLE adapter, see also [these oddities](https://developer.android.com/agi/troubleshooting#game_failure_after_using_agi)), see [CircleOpacityTrace.gfxtrace.zip](https://github.com/flutter/engine/files/12966311/CircleOpacityTrace.gfxtrace.zip). - [x] Print debugging the commands (see above) - [x] Commenting out `gl.DiscardFramebufferEXT` optimizations - [x] Render Doc (I need to use a Samsung phone old enough to have OpenGLES) /cc @jonahwilliams to add anything else ^
--- .../backend/gles/capabilities_gles.cc | 15 ++- .../renderer/backend/gles/capabilities_gles.h | 1 + .../renderer/backend/gles/formats_gles.h | 2 +- .../renderer/backend/gles/render_pass_gles.cc | 51 +++++++- .../renderer/backend/gles/texture_gles.cc | 122 ++++++------------ .../renderer/backend/gles/texture_gles.h | 2 +- 6 files changed, 98 insertions(+), 95 deletions(-) diff --git a/engine/src/flutter/impeller/renderer/backend/gles/capabilities_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/capabilities_gles.cc index 37bd3e665d9..54ac1e70d3e 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/capabilities_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/capabilities_gles.cc @@ -106,6 +106,19 @@ CapabilitiesGLES::CapabilitiesGLES(const ProcTableGLES& gl) { gl.GetDescription()->HasExtension(kOESTextureBorderClampExt)) { supports_decal_sampler_address_mode_ = true; } + + if (gl.GetDescription()->HasExtension( + "GL_EXT_multisampled_render_to_texture") && + // The current implementation of MSAA support in Impeller GLES requires + // the use of glBlitFramebuffer, which is not available on all GLES + // implementations. We can't use MSAA on these platforms yet. + gl.BlitFramebuffer.IsAvailable()) { + // We hard-code 4x MSAA, so let's make sure it's supported. + GLint value = 0; + gl.GetIntegerv(GL_MAX_SAMPLES_EXT, &value); + + supports_offscreen_msaa_ = value >= 4; + } } size_t CapabilitiesGLES::GetMaxTextureUnits(ShaderStage stage) const { @@ -124,7 +137,7 @@ size_t CapabilitiesGLES::GetMaxTextureUnits(ShaderStage stage) const { } bool CapabilitiesGLES::SupportsOffscreenMSAA() const { - return false; + return supports_offscreen_msaa_; } bool CapabilitiesGLES::SupportsSSBO() const { diff --git a/engine/src/flutter/impeller/renderer/backend/gles/capabilities_gles.h b/engine/src/flutter/impeller/renderer/backend/gles/capabilities_gles.h index 3bcd0cfd85d..edb9a1b33bb 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/capabilities_gles.h +++ b/engine/src/flutter/impeller/renderer/backend/gles/capabilities_gles.h @@ -118,6 +118,7 @@ class CapabilitiesGLES final private: bool supports_framebuffer_fetch_ = false; bool supports_decal_sampler_address_mode_ = false; + bool supports_offscreen_msaa_ = false; }; } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/gles/formats_gles.h b/engine/src/flutter/impeller/renderer/backend/gles/formats_gles.h index ea56ebb6e51..b4296fbfe26 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/formats_gles.h +++ b/engine/src/flutter/impeller/renderer/backend/gles/formats_gles.h @@ -185,7 +185,7 @@ constexpr std::optional ToTextureTarget(TextureType type) { case TextureType::kTexture2D: return GL_TEXTURE_2D; case TextureType::kTexture2DMultisample: - return std::nullopt; + return GL_TEXTURE_2D; case TextureType::kTextureCube: return GL_TEXTURE_CUBE_MAP; case TextureType::kTextureExternalOES: diff --git a/engine/src/flutter/impeller/renderer/backend/gles/render_pass_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/render_pass_gles.cc index a856feeeff1..5536a3cd6c4 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/render_pass_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/render_pass_gles.cc @@ -6,7 +6,9 @@ #include "flutter/fml/trace_event.h" #include "fml/closure.h" +#include "fml/logging.h" #include "impeller/base/validation.h" +#include "impeller/core/texture_descriptor.h" #include "impeller/renderer/backend/gles/context_gles.h" #include "impeller/renderer/backend/gles/device_buffer_gles.h" #include "impeller/renderer/backend/gles/formats_gles.h" @@ -125,6 +127,7 @@ struct RenderPassData { Scalar clear_depth = 1.0; std::shared_ptr color_attachment; + std::shared_ptr resolve_attachment; std::shared_ptr depth_attachment; std::shared_ptr stencil_attachment; @@ -186,6 +189,7 @@ struct RenderPassData { return false; } } + if (auto depth = TextureGLES::Cast(pass_data.depth_attachment.get())) { if (!depth->SetAsFramebufferAttachment( GL_FRAMEBUFFER, TextureGLES::AttachmentPoint::kDepth)) { @@ -470,6 +474,45 @@ struct RenderPassData { } } + // When we have a resolve_attachment, MSAA is being used. We blit from the + // MSAA FBO to the resolve FBO, otherwise the resolve FBO ends up being + // incomplete (because it has no attachments). + // + // Note that this only works on OpenGLES 3.0+, or put another way, in older + // versions of OpenGLES, MSAA is not currently supported by Impeller. It's + // possible to work around this issue a few different ways (not yet done). + // + // TODO(matanlurey): See https://github.com/flutter/flutter/issues/137093. + if (!is_default_fbo && pass_data.resolve_attachment) { + // MSAA should not be enabled if BlitFramebuffer is not available. + FML_DCHECK(gl.BlitFramebuffer.IsAvailable()); + + GLuint draw_fbo = GL_NONE; + gl.GenFramebuffers(1u, &draw_fbo); + gl.BindFramebuffer(GL_FRAMEBUFFER, draw_fbo); + + auto resolve = TextureGLES::Cast(pass_data.resolve_attachment.get()); + if (!resolve->SetAsFramebufferAttachment( + GL_FRAMEBUFFER, TextureGLES::AttachmentPoint::kColor0)) { + return false; + } + + gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, draw_fbo); + gl.BindFramebuffer(GL_READ_FRAMEBUFFER, fbo); + auto size = pass_data.resolve_attachment->GetSize(); + gl.BlitFramebuffer(0, // srcX0 + 0, // srcY0 + size.width, // srcX1 + size.height, // srcY1 + 0, // dstX0 + 0, // dstY0 + size.width, // dstX1 + size.height, // dstY1 + GL_COLOR_BUFFER_BIT, // mask + GL_NEAREST // filter + ); + } + if (gl.DiscardFramebufferEXT.IsAvailable()) { std::vector attachments; @@ -498,11 +541,6 @@ struct RenderPassData { attachments.data() // size ); } -#ifdef IMPELLER_DEBUG - if (is_default_fbo) { - tracer->MarkFrameEnd(gl); - } -#endif // IMPELLER_DEBUG return true; } @@ -531,6 +569,7 @@ bool RenderPassGLES::OnEncodeCommands(const Context& context) const { /// Setup color data. /// pass_data->color_attachment = color0.texture; + pass_data->resolve_attachment = color0.resolve_texture; pass_data->clear_color = color0.clear_color; pass_data->clear_color_attachment = CanClearAttachment(color0.load_action); pass_data->discard_color_attachment = @@ -548,7 +587,7 @@ bool RenderPassGLES::OnEncodeCommands(const Context& context) const { } //---------------------------------------------------------------------------- - /// Setup depth data. + /// Setup stencil data. /// if (stencil0.has_value()) { pass_data->stencil_attachment = stencil0->texture; diff --git a/engine/src/flutter/impeller/renderer/backend/gles/texture_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/texture_gles.cc index ad8d319150c..c2d4742ae9d 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/texture_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/texture_gles.cc @@ -12,6 +12,7 @@ #include "impeller/base/allocation.h" #include "impeller/base/validation.h" #include "impeller/core/formats.h" +#include "impeller/core/texture_descriptor.h" #include "impeller/renderer/backend/gles/formats_gles.h" namespace impeller { @@ -21,19 +22,22 @@ static TextureGLES::Type GetTextureTypeFromDescriptor( const auto usage = static_cast(desc.usage); const auto render_target = static_cast(TextureUsage::kRenderTarget); - if (usage == render_target) { + const auto is_msaa = desc.sample_count == SampleCount::kCount4; + if (usage == render_target && !is_msaa) { + // TODO(matanlurey): MSAA render buffers? + // See https://github.com/flutter/flutter/issues/137095. return TextureGLES::Type::kRenderBuffer; } - return TextureGLES::Type::kTexture; + return is_msaa ? TextureGLES::Type::kTextureMultisampled + : TextureGLES::Type::kTexture; } HandleType ToHandleType(TextureGLES::Type type) { switch (type) { case TextureGLES::Type::kTexture: + case TextureGLES::Type::kTextureMultisampled: return HandleType::kTexture; case TextureGLES::Type::kRenderBuffer: - // MSAA textures are treated as render buffers. - case TextureGLES::Type::kRenderBufferMultisampled: return HandleType::kRenderBuffer; } FML_UNREACHABLE(); @@ -118,8 +122,17 @@ struct TexImage2DData { external_format = GL_RGBA; type = GL_HALF_FLOAT; break; - case PixelFormat::kUnknown: + // TODO(matanlurey): This is a combined depth stencil format (like + // kD24UnormS8Uint below). We should find a way to use a stencil-only + // format instead. + // + // See https://github.com/flutter/flutter/issues/137094. case PixelFormat::kS8UInt: + internal_format = GL_DEPTH_STENCIL; + external_format = GL_DEPTH_STENCIL; + type = GL_UNSIGNED_INT_24_8; + break; + case PixelFormat::kUnknown: case PixelFormat::kD24UnormS8Uint: case PixelFormat::kD32FloatS8UInt: case PixelFormat::kR8UNormInt: @@ -133,52 +146,9 @@ struct TexImage2DData { } TexImage2DData(PixelFormat pixel_format, - std::shared_ptr mapping) { - switch (pixel_format) { - case PixelFormat::kUnknown: - return; - case PixelFormat::kA8UNormInt: { - internal_format = GL_ALPHA; - external_format = GL_ALPHA; - type = GL_UNSIGNED_BYTE; - data = std::move(mapping); - break; - } - case PixelFormat::kR8G8B8A8UNormInt: { - internal_format = GL_RGBA; - external_format = GL_RGBA; - type = GL_UNSIGNED_BYTE; - data = std::move(mapping); - break; - } - case PixelFormat::kR32G32B32A32Float: { - internal_format = GL_RGBA; - external_format = GL_RGBA; - type = GL_FLOAT; - data = std::move(mapping); - break; - } - case PixelFormat::kR16G16B16A16Float: { - internal_format = GL_RGBA; - external_format = GL_RGBA; - type = GL_HALF_FLOAT; - data = std::move(mapping); - break; - } - case PixelFormat::kR8G8B8A8UNormIntSRGB: - case PixelFormat::kB8G8R8A8UNormInt: - case PixelFormat::kB8G8R8A8UNormIntSRGB: - case PixelFormat::kS8UInt: - case PixelFormat::kD24UnormS8Uint: - case PixelFormat::kD32FloatS8UInt: - case PixelFormat::kR8UNormInt: - case PixelFormat::kR8G8UNormInt: - case PixelFormat::kB10G10R10XRSRGB: - case PixelFormat::kB10G10R10XR: - case PixelFormat::kB10G10R10A10XR: - return; - } - is_valid_ = true; + std::shared_ptr mapping) + : TexImage2DData(pixel_format) { + data = std::move(mapping); } bool IsValid() const { return is_valid_; } @@ -362,7 +332,8 @@ void TextureGLES::InitializeContentsIfNecessary() const { } switch (type_) { - case Type::kTexture: { + case Type::kTexture: + case Type::kTextureMultisampled: { TexImage2DData tex_data(GetTextureDescriptor().format); if (!tex_data.IsValid()) { VALIDATION_LOG << "Invalid format for texture image."; @@ -382,7 +353,6 @@ void TextureGLES::InitializeContentsIfNecessary() const { nullptr // data ); } - } break; case Type::kRenderBuffer: { auto render_buffer_format = @@ -401,26 +371,6 @@ void TextureGLES::InitializeContentsIfNecessary() const { ); } } break; - case Type::kRenderBufferMultisampled: { - auto render_buffer_msaa = - ToRenderBufferFormat(GetTextureDescriptor().format); - if (!render_buffer_msaa.has_value()) { - VALIDATION_LOG << "Invalid format for render-buffer MSAA image."; - return; - } - gl.BindRenderbuffer(GL_RENDERBUFFER, handle.value()); - { - TRACE_EVENT0("impeller", "RenderBufferStorageInitialization"); - gl.RenderbufferStorageMultisampleEXT( - GL_RENDERBUFFER, // target - 4, // samples - render_buffer_msaa.value(), // internal format - size.width, // width - size.height // height - ); - } - break; - } } } @@ -438,7 +388,8 @@ bool TextureGLES::Bind() const { } const auto& gl = reactor_->GetProcTable(); switch (type_) { - case Type::kTexture: { + case Type::kTexture: + case Type::kTextureMultisampled: { const auto target = ToTextureTarget(GetTextureDescriptor().type); if (!target.has_value()) { VALIDATION_LOG << "Could not bind texture of this type."; @@ -447,8 +398,6 @@ bool TextureGLES::Bind() const { gl.BindTexture(target.value(), handle.value()); } break; case Type::kRenderBuffer: - // MSAA textures are treated as render buffers. - case Type::kRenderBufferMultisampled: gl.BindRenderbuffer(GL_RENDERBUFFER, handle.value()); break; } @@ -516,6 +465,7 @@ bool TextureGLES::SetAsFramebufferAttachment(GLenum target, return false; } const auto& gl = reactor_->GetProcTable(); + switch (type_) { case Type::kTexture: gl.FramebufferTexture2D(target, // target @@ -525,16 +475,7 @@ bool TextureGLES::SetAsFramebufferAttachment(GLenum target, 0 // level ); break; - case Type::kRenderBuffer: - gl.FramebufferRenderbuffer(target, // target - ToAttachmentPoint(point), // attachment - GL_RENDERBUFFER, // render-buffer target - handle.value() // render-buffer - ); - break; - case Type::kRenderBufferMultisampled: - // Assume that when MSAA is enabled, we're using 4x MSAA. - FML_DCHECK(GetTextureDescriptor().sample_count == SampleCount::kCount4); + case Type::kTextureMultisampled: gl.FramebufferTexture2DMultisampleEXT( target, // target ToAttachmentPoint(point), // attachment @@ -544,7 +485,16 @@ bool TextureGLES::SetAsFramebufferAttachment(GLenum target, 4 // samples ); break; + case Type::kRenderBuffer: + gl.FramebufferRenderbuffer(target, // target + ToAttachmentPoint(point), // attachment + GL_RENDERBUFFER, // render-buffer target + handle.value() // render-buffer + ); + gl.BindRenderbuffer(GL_RENDERBUFFER, GL_NONE); + break; } + return true; } diff --git a/engine/src/flutter/impeller/renderer/backend/gles/texture_gles.h b/engine/src/flutter/impeller/renderer/backend/gles/texture_gles.h index 7f5cb90e4d0..53a404b8401 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/texture_gles.h +++ b/engine/src/flutter/impeller/renderer/backend/gles/texture_gles.h @@ -17,8 +17,8 @@ class TextureGLES final : public Texture, public: enum class Type { kTexture, + kTextureMultisampled, kRenderBuffer, - kRenderBufferMultisampled, }; enum class IsWrapped {