-
Notifications
You must be signed in to change notification settings - Fork 6k
[Impeller] Enable MSAA for OpenGLES: Take 2. #47030
Changes from 12 commits
08f4b93
1b2b898
10389b3
d0f1d7c
99e9c68
ce1ffeb
ad5c75b
5964853
118ccd8
64cf63c
29fc11a
29da282
8082acb
fcefcf6
b7b5333
c502394
f47324e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -106,6 +106,21 @@ 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()) { | ||
| supports_offscreen_msaa_ = true; | ||
|
|
||
| // We hard-code 4x MSAA, so let's make sure it's supported. | ||
| GLint value = 0; | ||
| gl.GetIntegerv(GL_MAX_SAMPLES_EXT, &value); | ||
| FML_DCHECK(value == 4) << "Unexpected max samples value: " << value << ". " | ||
|
||
| << "Only 4x MSAA is currently supported."; | ||
| } | ||
| } | ||
|
|
||
| size_t CapabilitiesGLES::GetMaxTextureUnits(ShaderStage stage) const { | ||
|
|
@@ -124,7 +139,7 @@ size_t CapabilitiesGLES::GetMaxTextureUnits(ShaderStage stage) const { | |
| } | ||
|
|
||
| bool CapabilitiesGLES::SupportsOffscreenMSAA() const { | ||
| return false; | ||
| return supports_offscreen_msaa_; | ||
| } | ||
|
|
||
| bool CapabilitiesGLES::SupportsSSBO() const { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -185,7 +185,7 @@ constexpr std::optional<GLenum> ToTextureTarget(TextureType type) { | |
| case TextureType::kTexture2D: | ||
| return GL_TEXTURE_2D; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: Just a |
||
| case TextureType::kTexture2DMultisample: | ||
| return std::nullopt; | ||
| return GL_TEXTURE_2D; | ||
| case TextureType::kTextureCube: | ||
| return GL_TEXTURE_CUBE_MAP; | ||
| case TextureType::kTextureExternalOES: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,7 @@ | |
|
|
||
| #include "flutter/fml/trace_event.h" | ||
| #include "fml/closure.h" | ||
| #include "fml/logging.h" | ||
| #include "impeller/base/validation.h" | ||
| #include "impeller/renderer/backend/gles/context_gles.h" | ||
| #include "impeller/renderer/backend/gles/device_buffer_gles.h" | ||
|
|
@@ -125,6 +126,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,17 +188,23 @@ struct RenderPassData { | |
| return false; | ||
| } | ||
| } | ||
|
|
||
| if (auto depth = TextureGLES::Cast(pass_data.depth_attachment.get())) { | ||
| if (!depth->SetAsFramebufferAttachment( | ||
| GL_FRAMEBUFFER, TextureGLES::AttachmentPoint::kDepth)) { | ||
| return false; | ||
| } | ||
| } | ||
| if (auto stencil = TextureGLES::Cast(pass_data.stencil_attachment.get())) { | ||
| if (!stencil->SetAsFramebufferAttachment( | ||
| GL_FRAMEBUFFER, TextureGLES::AttachmentPoint::kStencil)) { | ||
| return false; | ||
| } | ||
| // TODO: Re-enable before finalizing PR. | ||
| // Causes "Fatal GL Error GL_INVALID_OPERATION(1282) encountered on call | ||
| // to glFramebufferTexture2DMultisampleEXT'". We probably don't want to be | ||
| // using MSAA for the stencil buffer anyway. | ||
|
|
||
| // if (!stencil->SetAsFramebufferAttachment( | ||
| // GL_FRAMEBUFFER, TextureGLES::AttachmentPoint::kStencil)) { | ||
| // return false; | ||
| // } | ||
| } | ||
|
|
||
| auto status = gl.CheckFramebufferStatus(GL_FRAMEBUFFER); | ||
|
|
@@ -470,6 +478,51 @@ 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): | ||
| // | ||
| // Do not use the resolve_texture, and instead use the MSAA texture only. | ||
| // To preview what this would look like (but should not be implemented this | ||
| // way - would impact the HAL): | ||
| // | ||
| // @@ render_target.cc @@ CreateOffscreenMSAA | ||
| // - color0.resolve_texture = color0_resolve_tex; | ||
| // + color0.resolve_texture = color0_msaa_tex; | ||
|
||
| if (!is_default_fbo && pass_data.resolve_attachment) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A missing cap check here for SupportsOffscreenMSAA for paranoia? Instead of the DCHECK for the blit.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We already have cap checks in render target construction. We could add an FML CHECK here but I'd be worried that too many layers of error checking is going to make it hard to find/fix problems. |
||
| // 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 +551,6 @@ struct RenderPassData { | |
| attachments.data() // size | ||
| ); | ||
| } | ||
| #ifdef IMPELLER_DEBUG | ||
| if (is_default_fbo) { | ||
| tracer->MarkFrameEnd(gl); | ||
| } | ||
| #endif // IMPELLER_DEBUG | ||
|
|
||
| return true; | ||
| } | ||
|
|
@@ -531,6 +579,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 +597,7 @@ bool RenderPassGLES::OnEncodeCommands(const Context& context) const { | |
| } | ||
|
|
||
| //---------------------------------------------------------------------------- | ||
| /// Setup depth data. | ||
| /// Setup stencil data. | ||
| /// | ||
| if (stencil0.has_value()) { | ||
| pass_data->stencil_attachment = stencil0->texture; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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,20 @@ 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) { | ||
| return TextureGLES::Type::kRenderBuffer; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe file a bug to investigate if we should investigate RenderBuffer multisampled (now that we have something working)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought we were just getting rid of
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We shouldn't try to mix refactors and feature work. |
||
| } | ||
| 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(); | ||
|
|
@@ -362,7 +364,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 +385,6 @@ void TextureGLES::InitializeContentsIfNecessary() const { | |
| nullptr // data | ||
| ); | ||
| } | ||
|
|
||
| } break; | ||
| case Type::kRenderBuffer: { | ||
| auto render_buffer_format = | ||
|
|
@@ -401,26 +403,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 +420,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 +430,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 +497,7 @@ bool TextureGLES::SetAsFramebufferAttachment(GLenum target, | |
| return false; | ||
| } | ||
| const auto& gl = reactor_->GetProcTable(); | ||
|
|
||
| switch (type_) { | ||
| case Type::kTexture: | ||
| gl.FramebufferTexture2D(target, // target | ||
|
|
@@ -525,16 +507,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 +517,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; | ||
| } | ||
|
|
||
|
|
||

Uh oh!
There was an error while loading. Please reload this page.