-
Notifications
You must be signed in to change notification settings - Fork 6k
[Impeller] Enable MSAA for OpenGLES: Take 2. #47030
Changes from all 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 |
---|---|---|
|
@@ -185,7 +185,7 @@ constexpr std::optional<GLenum> ToTextureTarget(TextureType type) { | |
case TextureType::kTexture2D: | ||
return GL_TEXTURE_2D; | ||
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,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) { | ||
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. 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 +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; | ||
|
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,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; | ||
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) 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. 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 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(); | ||
|
@@ -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; | ||
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 think this is a combined depth stencil format, like kD24UnormS8Uint below. This is fine to use now but we should investigate if there is a stencil-only format. 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. Sg, I'll add it the MSAA next steps issue and added a TODO here. |
||
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; | ||
} | ||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.