mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[Impeller] Switch from glBlitFramebuffer to implicit MSAA resolution. (flutter/engine#47282)
Closes https://github.com/flutter/flutter/issues/137093. This widens supports from Open GLES 3.x to Open GLES 2.x, and uses [ARM GPU Best Practices](https://developer.arm.com/documentation/101897/0301/Fragment-shading/Multisampling-for-OpenGL-ES): > Do not use `glBlitFramebuffer()` to implement a multisample resolve. This PR: - Removes usage of `glBlitFramebuffer` - Adds the capability check, `SupportsImplicitResolvingMSAA`, which is `false` outside of GLES - Does not discard color attachments resolved by `EXT_multisampled_render_to_texture` (done implicitly) I spoke to @jonahwilliams about the changes to the HAL, who I believe also talked to @bdero about it. The short explantation is that, with the `EXT_multisampled_render_to_texture`, we can be more efficient by letting GLES perform multisampled rendering for us (no per-sample data is written out). See also https://registry.khronos.org/OpenGL/extensions/EXT/EXT_multisampled_render_to_texture.txt for details.
This commit is contained in:
parent
0307c66cbb
commit
52d45d8af1
@ -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;
|
||||
@ -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;
|
||||
@ -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;
|
||||
@ -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;
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -76,6 +76,9 @@ class CapabilitiesGLES final
|
||||
// |Capabilities|
|
||||
bool SupportsOffscreenMSAA() const override;
|
||||
|
||||
// |Capabilities|
|
||||
bool SupportsImplicitResolvingMSAA() const override;
|
||||
|
||||
// |Capabilities|
|
||||
bool SupportsSSBO() const override;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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"
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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.
|
||||
///
|
||||
|
||||
@ -409,6 +409,11 @@ bool CapabilitiesVK::SupportsOffscreenMSAA() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
// |Capabilities|
|
||||
bool CapabilitiesVK::SupportsImplicitResolvingMSAA() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
// |Capabilities|
|
||||
bool CapabilitiesVK::SupportsSSBO() const {
|
||||
return true;
|
||||
|
||||
@ -60,6 +60,9 @@ class CapabilitiesVK final : public Capabilities,
|
||||
// |Capabilities|
|
||||
bool SupportsOffscreenMSAA() const override;
|
||||
|
||||
// |Capabilities|
|
||||
bool SupportsImplicitResolvingMSAA() const override;
|
||||
|
||||
// |Capabilities|
|
||||
bool SupportsSSBO() const override;
|
||||
|
||||
|
||||
@ -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_; }
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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.";
|
||||
@ -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;
|
||||
}
|
||||
|
||||
target.SetColorAttachment(color0, 0u);
|
||||
|
||||
// Create MSAA stencil texture.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user