mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[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:

---
## 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 #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](346624ecc5/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>


</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>
This commit is contained in:
parent
9900774b34
commit
49b4523152
@ -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 {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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<Texture> color_attachment;
|
||||
std::shared_ptr<Texture> resolve_attachment;
|
||||
std::shared_ptr<Texture> depth_attachment;
|
||||
std::shared_ptr<Texture> 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<GLenum> 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;
|
||||
|
||||
@ -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<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();
|
||||
@ -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<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_; }
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -17,8 +17,8 @@ class TextureGLES final : public Texture,
|
||||
public:
|
||||
enum class Type {
|
||||
kTexture,
|
||||
kTextureMultisampled,
|
||||
kRenderBuffer,
|
||||
kRenderBufferMultisampled,
|
||||
};
|
||||
|
||||
enum class IsWrapped {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user