Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 21 additions & 16 deletions impeller/renderer/backend/gles/capabilities_gles.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ static const constexpr char* kNvidiaTextureBorderClampExt =
static const constexpr char* kOESTextureBorderClampExt =
"GL_OES_texture_border_clamp";

// https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_multisampled_render_to_texture.txt
static const constexpr char* kMultisampledRenderToTextureExt =
"GL_EXT_multisampled_render_to_texture2";

CapabilitiesGLES::CapabilitiesGLES(const ProcTableGLES& gl) {
{
GLint value = 0;
Expand All @@ -32,7 +36,9 @@ CapabilitiesGLES::CapabilitiesGLES(const ProcTableGLES& gl) {
max_cube_map_texture_size = value;
}

if (gl.GetDescription()->IsES()) {
auto const desc = gl.GetDescription();

if (desc->IsES()) {
GLint value = 0;
gl.GetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &value);
max_fragment_uniform_vectors = value;
Expand All @@ -56,7 +62,7 @@ CapabilitiesGLES::CapabilitiesGLES(const ProcTableGLES& gl) {
max_texture_size = ISize{value, value};
}

if (gl.GetDescription()->IsES()) {
if (desc->IsES()) {
GLint value = 0;
gl.GetIntegerv(GL_MAX_VARYING_VECTORS, &value);
max_varying_vectors = value;
Expand All @@ -74,7 +80,7 @@ CapabilitiesGLES::CapabilitiesGLES(const ProcTableGLES& gl) {
max_vertex_texture_image_units = value;
}

if (gl.GetDescription()->IsES()) {
if (desc->IsES()) {
GLint value = 0;
gl.GetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &value);
max_vertex_uniform_vectors = value;
Expand All @@ -92,31 +98,26 @@ CapabilitiesGLES::CapabilitiesGLES(const ProcTableGLES& gl) {
num_compressed_texture_formats = value;
}

if (gl.GetDescription()->IsES()) {
if (desc->IsES()) {
GLint value = 0;
gl.GetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &value);
num_shader_binary_formats = value;
}

supports_framebuffer_fetch_ =
gl.GetDescription()->HasExtension(kFramebufferFetchExt);
supports_framebuffer_fetch_ = desc->HasExtension(kFramebufferFetchExt);

if (gl.GetDescription()->HasExtension(kTextureBorderClampExt) ||
gl.GetDescription()->HasExtension(kNvidiaTextureBorderClampExt) ||
gl.GetDescription()->HasExtension(kOESTextureBorderClampExt)) {
if (desc->HasExtension(kTextureBorderClampExt) ||
desc->HasExtension(kNvidiaTextureBorderClampExt) ||
desc->HasExtension(kOESTextureBorderClampExt)) {
supports_decal_sampler_address_mode_ = true;
}

if (gl.GetDescription()->HasExtension(
"GL_EXT_multisampled_render_to_texture2") &&
// 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()) {
if (desc->HasExtension(kMultisampledRenderToTextureExt)) {
supports_implicit_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);

supports_offscreen_msaa_ = value >= 4;
}
}
Expand All @@ -140,6 +141,10 @@ bool CapabilitiesGLES::SupportsOffscreenMSAA() const {
return supports_offscreen_msaa_;
}

bool CapabilitiesGLES::SupportsImplicitResolvingMSAA() const {
return supports_implicit_msaa_;
}

bool CapabilitiesGLES::SupportsSSBO() const {
return false;
}
Expand Down
4 changes: 4 additions & 0 deletions impeller/renderer/backend/gles/capabilities_gles.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ class CapabilitiesGLES final
// |Capabilities|
bool SupportsOffscreenMSAA() const override;

// |Capabilities|
bool SupportsImplicitResolvingMSAA() const override;

// |Capabilities|
bool SupportsSSBO() const override;

Expand Down Expand Up @@ -119,6 +122,7 @@ class CapabilitiesGLES final
bool supports_framebuffer_fetch_ = false;
bool supports_decal_sampler_address_mode_ = false;
bool supports_offscreen_msaa_ = false;
bool supports_implicit_msaa_ = false;
};

} // namespace impeller
57 changes: 9 additions & 48 deletions impeller/renderer/backend/gles/render_pass_gles.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "impeller/renderer/backend/gles/render_pass_gles.h"

#include "GLES3/gl3.h"
#include "flutter/fml/trace_event.h"
#include "fml/closure.h"
#include "fml/logging.h"
Expand Down Expand Up @@ -127,7 +128,6 @@ 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 @@ -474,52 +474,6 @@ 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;
fml::ScopedCleanupClosure delete_draw_fbo([&gl, &draw_fbo, fbo]() {
if (draw_fbo != GL_NONE) {
gl.BindFramebuffer(GL_FRAMEBUFFER, fbo);
gl.DeleteFramebuffers(1u, &draw_fbo);
}
});

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 @@ -576,12 +530,19 @@ 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 =
CanDiscardAttachmentWhenDone(color0.store_action);

// When we are using EXT_multisampled_render_to_texture, it is implicitly
// resolved when we bind the texture to the framebuffer. We don't need to
// discard the attachment when we are done.
if (color0.resolve_texture) {
FML_DCHECK(context.GetCapabilities()->SupportsImplicitResolvingMSAA());
pass_data->discard_color_attachment = false;
}

//----------------------------------------------------------------------------
/// Setup depth data.
///
Expand Down
5 changes: 5 additions & 0 deletions impeller/renderer/backend/vulkan/capabilities_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,11 @@ bool CapabilitiesVK::SupportsOffscreenMSAA() const {
return true;
}

// |Capabilities|
bool CapabilitiesVK::SupportsImplicitResolvingMSAA() const {
return false;
}

// |Capabilities|
bool CapabilitiesVK::SupportsSSBO() const {
return true;
Expand Down
3 changes: 3 additions & 0 deletions impeller/renderer/backend/vulkan/capabilities_vk.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ class CapabilitiesVK final : public Capabilities,
// |Capabilities|
bool SupportsOffscreenMSAA() const override;

// |Capabilities|
bool SupportsImplicitResolvingMSAA() const override;

// |Capabilities|
bool SupportsSSBO() const override;

Expand Down
3 changes: 3 additions & 0 deletions impeller/renderer/capabilities.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ class StandardCapabilities final : public Capabilities {
return supports_offscreen_msaa_;
}

// |Capabilities|
bool SupportsImplicitResolvingMSAA() const override { return false; }

// |Capabilities|
bool SupportsSSBO() const override { return supports_ssbo_; }

Expand Down
5 changes: 5 additions & 0 deletions impeller/renderer/capabilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ class Capabilities {
/// color/stencil textures.
virtual bool SupportsOffscreenMSAA() const = 0;

/// @brief Whether the context backend supports multisampled rendering to
/// the on-screen surface without requiring an explicit resolve of
/// the MSAA color attachment.
virtual bool SupportsImplicitResolvingMSAA() const = 0;

/// @brief Whether the context backend supports binding Shader Storage Buffer
/// Objects (SSBOs) to pipelines.
virtual bool SupportsSSBO() const = 0;
Expand Down
16 changes: 16 additions & 0 deletions impeller/renderer/render_target.cc
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,11 @@ RenderTarget RenderTarget::CreateOffscreenMSAA(
color0_tex_desc.size = size;
color0_tex_desc.usage = static_cast<uint64_t>(TextureUsage::kRenderTarget);

if (context.GetCapabilities()->SupportsImplicitResolvingMSAA()) {
// See below ("SupportsImplicitResolvingMSAA") for more details.
color0_tex_desc.storage_mode = StorageMode::kDevicePrivate;
}

auto color0_msaa_tex = allocator.CreateTexture(color0_tex_desc);
if (!color0_msaa_tex) {
VALIDATION_LOG << "Could not create multisample color texture.";
Expand Down Expand Up @@ -322,6 +327,17 @@ RenderTarget RenderTarget::CreateOffscreenMSAA(
color0.texture = color0_msaa_tex;
color0.resolve_texture = color0_resolve_tex;

if (context.GetCapabilities()->SupportsImplicitResolvingMSAA()) {
// If implicit MSAA is supported, then the resolve texture is not needed
// because the multisample texture is automatically resolved. We instead
// provide a view of the multisample texture as the resolve texture (because
// the HAL does expect a resolve texture).
//
// In practice, this is used for GLES 2.0 EXT_multisampled_render_to_texture
// https://registry.khronos.org/OpenGL/extensions/EXT/EXT_multisampled_render_to_texture.txt
color0.resolve_texture = color0_msaa_tex;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should technically create some sort of "Wrapped" texture with the same descriptor but with sample count set to 1? We might need to expand on what wrapped means. Though if it doesn't cause any problems as is maybe we just leave it.

}

target.SetColorAttachment(color0, 0u);

// Create MSAA stencil texture.
Expand Down