Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
9 changes: 7 additions & 2 deletions impeller/display_list/canvas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1663,10 +1663,15 @@ bool Canvas::BlitToOnscreen() {
auto offscreen_target = render_passes_.back()
.inline_pass_context->GetPassTarget()
.GetRenderTarget();

// Unlike other backends the blit to restore the onscreen fails for GLES
// if the src is a multisample framebuffer, even if we specifically target
// the non-multisampled resolve of the dst.
bool is_gles_and_must_skip_blit = renderer_.GetContext()->GetBackendType() ==
Context::BackendType::kOpenGLES;
if (renderer_.GetContext()
->GetCapabilities()
->SupportsTextureToTextureBlits()) {
->SupportsTextureToTextureBlits() &&
!is_gles_and_must_skip_blit) {
auto blit_pass = command_buffer->CreateBlitPass();
blit_pass->AddCopy(offscreen_target.GetRenderTargetTexture(),
render_target_.GetRenderTargetTexture());
Expand Down
5 changes: 5 additions & 0 deletions impeller/renderer/backend/gles/capabilities_gles.cc
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,12 @@ CapabilitiesGLES::CapabilitiesGLES(const ProcTableGLES& gl) {
gl.GetIntegerv(GL_MAX_SAMPLES_EXT, &value);
supports_offscreen_msaa_ = value >= 4;
}
} else if (desc->GetGlVersion().major_version >= 3 && desc->IsES()) {
GLint value = 0;
gl.GetIntegerv(GL_MAX_SAMPLES, &value);
supports_offscreen_msaa_ = value >= 4;
}

is_es_ = desc->IsES();
is_angle_ = desc->IsANGLE();
}
Expand Down
1 change: 1 addition & 0 deletions impeller/renderer/backend/gles/proc_table_gles.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ void(glDepthRange)(GLdouble n, GLdouble f);
PROC(UniformBlockBinding); \
PROC(BindBufferRange); \
PROC(WaitSync); \
PROC(RenderbufferStorageMultisample) \
PROC(BlitFramebuffer);

#define FOR_EACH_IMPELLER_EXT_PROC(PROC) \
Expand Down
59 changes: 54 additions & 5 deletions impeller/renderer/backend/gles/render_pass_gles.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

#include <cstdint>

#include "flutter/fml/trace_event.h"
#include "fml/closure.h"
#include "fml/logging.h"
#include "impeller/base/validation.h"
Expand Down Expand Up @@ -130,6 +129,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 @@ -196,8 +196,6 @@ void RenderPassGLES::ResetGLState(const ProcTableGLES& gl) {
const std::vector<TextureAndSampler>& bound_textures,
const std::vector<BufferResource>& bound_buffers,
const std::shared_ptr<GPUTracerGLES>& tracer) {
TRACE_EVENT0("impeller", "RenderPassGLES::EncodeCommandsInReactor");

const auto& gl = reactor.GetProcTable();
#ifdef IMPELLER_DEBUG
tracer->MarkFrameStart(gl);
Expand Down Expand Up @@ -514,6 +512,55 @@ void RenderPassGLES::ResetGLState(const ProcTableGLES& gl) {
}
}

if (pass_data.resolve_attachment &&
!gl.GetCapabilities()->SupportsImplicitResolvingMSAA() &&
!is_default_fbo) {
FML_DCHECK(pass_data.resolve_attachment != pass_data.color_attachment);
// Perform multisample resolve via blit.
// Create and bind a resolve FBO.
GLuint resolve_fbo;
gl.GenFramebuffers(1u, &resolve_fbo);
gl.BindFramebuffer(GL_FRAMEBUFFER, resolve_fbo);

if (!TextureGLES::Cast(*pass_data.resolve_attachment)
.SetAsFramebufferAttachment(
GL_FRAMEBUFFER, TextureGLES::AttachmentType::kColor0)) {
return false;
}

auto status = gl.CheckFramebufferStatus(GL_FRAMEBUFFER);
if (gl.CheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
VALIDATION_LOG << "Could not create a complete frambuffer: "
<< DebugToFramebufferError(status);
return false;
}

// Bind MSAA renderbuffer to read framebuffer.
gl.BindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, resolve_fbo);

RenderPassGLES::ResetGLState(gl);
auto size = pass_data.color_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
);

gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, GL_NONE);
gl.BindFramebuffer(GL_READ_FRAMEBUFFER, GL_NONE);
gl.DeleteFramebuffers(1u, &resolve_fbo);
// Rebind the original FBO so that we can discard it below.
gl.BindFramebuffer(GL_FRAMEBUFFER, fbo);
}

if (gl.DiscardFramebufferEXT.IsAvailable()) {
std::array<GLenum, 3> attachments;
size_t attachment_count = 0;
Expand Down Expand Up @@ -574,6 +621,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 @@ -583,8 +631,9 @@ bool RenderPassGLES::OnEncodeCommands(const Context& context) const {
// 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;
pass_data->discard_color_attachment =
pass_data->discard_color_attachment &&
!context.GetCapabilities()->SupportsImplicitResolvingMSAA();
}

//----------------------------------------------------------------------------
Expand Down
50 changes: 35 additions & 15 deletions impeller/renderer/backend/gles/texture_gles.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,18 @@ static bool IsDepthStencilFormat(PixelFormat format) {
}

static TextureGLES::Type GetTextureTypeFromDescriptor(
const TextureDescriptor& desc) {
const TextureDescriptor& desc,
bool supports_implict_msaa) {
const auto usage = static_cast<TextureUsageMask>(desc.usage);
const auto render_target = TextureUsage::kRenderTarget;
const auto is_msaa = desc.sample_count == SampleCount::kCount4;
if (usage == render_target && IsDepthStencilFormat(desc.format)) {
return is_msaa ? TextureGLES::Type::kRenderBufferMultisampled
: TextureGLES::Type::kRenderBuffer;
}
return is_msaa ? TextureGLES::Type::kTextureMultisampled
return is_msaa ? (supports_implict_msaa
? TextureGLES::Type::kTextureMultisampled
: TextureGLES::Type::kRenderBufferMultisampled)
: TextureGLES::Type::kTexture;
}

Expand Down Expand Up @@ -192,7 +195,11 @@ TextureGLES::TextureGLES(std::shared_ptr<ReactorGLES> reactor,
std::optional<HandleGLES> external_handle)
: Texture(desc),
reactor_(std::move(reactor)),
type_(GetTextureTypeFromDescriptor(GetTextureDescriptor())),
type_(
GetTextureTypeFromDescriptor(GetTextureDescriptor(),
reactor_->GetProcTable()
.GetCapabilities()
->SupportsImplicitResolvingMSAA())),
handle_(external_handle.has_value()
? external_handle.value()
: reactor_->CreateUntrackedHandle(ToHandleType(type_))),
Expand Down Expand Up @@ -367,7 +374,7 @@ static std::optional<GLenum> ToRenderBufferFormat(PixelFormat format) {
switch (format) {
case PixelFormat::kB8G8R8A8UNormInt:
case PixelFormat::kR8G8B8A8UNormInt:
return GL_RGBA4;
return GL_RGBA8;
case PixelFormat::kR32G32B32A32Float:
return GL_RGBA32F;
case PixelFormat::kR16G16B16A16Float:
Expand Down Expand Up @@ -450,19 +457,32 @@ void TextureGLES::InitializeContentsIfNecessary() const {
{
TRACE_EVENT0("impeller", "RenderBufferStorageInitialization");
if (type_ == Type::kRenderBufferMultisampled) {
gl.RenderbufferStorageMultisampleEXT(
GL_RENDERBUFFER, // target
4, // samples
render_buffer_format.value(), // internal format
size.width, // width
size.height // height
);
// BEWARE: these functions are not at all equivalent! the extensions
// are from EXT_multisampled_render_to_texture and cannot be used
// with regular GLES 3.0 multisampled renderbuffers/textures.
if (gl.GetCapabilities()->SupportsImplicitResolvingMSAA()) {
gl.RenderbufferStorageMultisampleEXT(
/*target=*/GL_RENDERBUFFER, //
/*samples=*/4, //
/*internal_format=*/render_buffer_format.value(), //
/*width=*/size.width, //
/*height=*/size.height //
);
} else {
gl.RenderbufferStorageMultisample(
/*target=*/GL_RENDERBUFFER, //
/*samples=*/4, //
/*internal_format=*/render_buffer_format.value(), //
/*width=*/size.width, //
/*height=*/size.height //
);
}
} else {
gl.RenderbufferStorage(
GL_RENDERBUFFER, // target
render_buffer_format.value(), // internal format
size.width, // width
size.height // height
/*target=*/GL_RENDERBUFFER, //
/*internal_format=*/render_buffer_format.value(), //
/*width=*/size.width, //
/*height=*/size.height //
);
}
}
Expand Down
Loading