Skip to content

Commit

Permalink
[Impeller] Enable MSAA for OpenGLES: Take 2. (flutter#47030)
Browse files Browse the repository at this point in the history
Closes flutter/flutter#130045.

Continues the work started in
flutter#46381. _This is PR supercedes
flutter#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

<details>

<summary>History</summary>

<br>

**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 flutter#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.

<details>

<summary>Example App</summary>

```dart
import 'package:flutter/material.dart';

void main() {
  runApp(const MainApp());
}

class MainApp extends StatefulWidget {
  const MainApp({super.key});

  @OverRide
  State<MainApp> createState() => _MainAppState();
}

class _MainAppState extends State<MainApp> {
  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,
            ),
          ),
        ),
      ),
    );
  }
}

```

</details>

<details>

<summary>Screenshots</summary>


![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)

</details>

<details>

<summary>Open GL Commands during MSAA Render</summary>

```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()
```

</details>

<details>

<summary>AGI Trace</summary>

<img width="590" alt="Screenshot 2023-10-17 at 3 21 44 PM"
src="https://github.com/flutter/engine/assets/168174/ce9fa65c-9a2b-4b82-9f67-af5373d119c1">

<img width="336" alt="Screenshot 2023-10-17 at 3 21 51 PM"
src="https://github.com/flutter/engine/assets/168174/8016029a-ec6d-4c18-b200-50c6485656fa">

</details>

~~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 ^

</details>
  • Loading branch information
matanlurey authored Oct 24, 2023
1 parent 6ea0f9a commit 09f1d27
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 95 deletions.
15 changes: 14 additions & 1 deletion impeller/renderer/backend/gles/capabilities_gles.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions impeller/renderer/backend/gles/capabilities_gles.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion impeller/renderer/backend/gles/formats_gles.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ constexpr std::optional<GLenum> 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:
Expand Down
51 changes: 45 additions & 6 deletions impeller/renderer/backend/gles/render_pass_gles.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -125,6 +127,7 @@ struct RenderPassData {
Scalar clear_depth = 1.0;

std::shared_ptr<Texture> color_attachment;
std::shared_ptr<Texture> resolve_attachment;
std::shared_ptr<Texture> depth_attachment;
std::shared_ptr<Texture> stencil_attachment;

Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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<GLenum> attachments;

Expand Down Expand Up @@ -498,11 +541,6 @@ struct RenderPassData {
attachments.data() // size
);
}
#ifdef IMPELLER_DEBUG
if (is_default_fbo) {
tracer->MarkFrameEnd(gl);
}
#endif // IMPELLER_DEBUG

return true;
}
Expand Down Expand Up @@ -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 =
Expand All @@ -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;
Expand Down
122 changes: 36 additions & 86 deletions impeller/renderer/backend/gles/texture_gles.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -21,19 +22,22 @@ static TextureGLES::Type GetTextureTypeFromDescriptor(
const auto usage = static_cast<TextureUsageMask>(desc.usage);
const auto render_target =
static_cast<TextureUsageMask>(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();
Expand Down Expand Up @@ -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:
Expand All @@ -133,52 +146,9 @@ struct TexImage2DData {
}

TexImage2DData(PixelFormat pixel_format,
std::shared_ptr<const fml::Mapping> 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<const fml::Mapping> mapping)
: TexImage2DData(pixel_format) {
data = std::move(mapping);
}

bool IsValid() const { return is_valid_; }
Expand Down Expand Up @@ -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.";
Expand All @@ -382,7 +353,6 @@ void TextureGLES::InitializeContentsIfNecessary() const {
nullptr // data
);
}

} break;
case Type::kRenderBuffer: {
auto render_buffer_format =
Expand All @@ -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;
}
}
}

Expand All @@ -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.";
Expand All @@ -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;
}
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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;
}

Expand Down
2 changes: 1 addition & 1 deletion impeller/renderer/backend/gles/texture_gles.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ class TextureGLES final : public Texture,
public:
enum class Type {
kTexture,
kTextureMultisampled,
kRenderBuffer,
kRenderBufferMultisampled,
};

enum class IsWrapped {
Expand Down

0 comments on commit 09f1d27

Please sign in to comment.