Update embedder support for Impeller/OpenGL to load some missing shaders and configure a depth attachment (flutter/engine#50416)

This commit is contained in:
Jason Simmons 2024-02-13 10:55:10 -08:00 committed by GitHub
parent 4cdf45c587
commit 5b220df694
13 changed files with 136 additions and 33 deletions

View File

@ -15,6 +15,11 @@
namespace impeller {
// This prefix is used in the names of inputs generated by ANGLE's framebuffer
// fetch emulation.
static constexpr std::string_view kAngleInputAttachmentPrefix =
"ANGLEInputAttachment";
BufferBindingsGLES::BufferBindingsGLES() = default;
BufferBindingsGLES::~BufferBindingsGLES() = default;
@ -110,6 +115,17 @@ bool BufferBindingsGLES::ReadUniformsBindings(const ProcTableGLES& gl,
&uniform_type, // type
name.data() // name
);
// Skip unrecognized variables generated by ANGLE.
if (gl.GetCapabilities()->IsANGLE()) {
if (written_count >=
static_cast<GLsizei>(kAngleInputAttachmentPrefix.length()) &&
std::string_view(name.data(), kAngleInputAttachmentPrefix.length()) ==
kAngleInputAttachmentPrefix) {
continue;
}
}
auto location = gl.GetUniformLocation(program, name.data());
if (location == -1) {
VALIDATION_LOG << "Could not query the location of an active uniform.";

View File

@ -117,6 +117,8 @@ CapabilitiesGLES::CapabilitiesGLES(const ProcTableGLES& gl) {
gl.GetIntegerv(GL_MAX_SAMPLES_EXT, &value);
supports_offscreen_msaa_ = value >= 4;
}
is_angle_ = desc->IsANGLE();
}
size_t CapabilitiesGLES::GetMaxTextureUnits(ShaderStage stage) const {
@ -188,4 +190,8 @@ PixelFormat CapabilitiesGLES::GetDefaultDepthStencilFormat() const {
return PixelFormat::kD24UnormS8Uint;
}
bool CapabilitiesGLES::IsANGLE() const {
return is_angle_;
}
} // namespace impeller

View File

@ -74,6 +74,8 @@ class CapabilitiesGLES final
size_t GetMaxTextureUnits(ShaderStage stage) const;
bool IsANGLE() const;
// |Capabilities|
bool SupportsOffscreenMSAA() const override;
@ -121,6 +123,7 @@ class CapabilitiesGLES final
bool supports_decal_sampler_address_mode_ = false;
bool supports_offscreen_msaa_ = false;
bool supports_implicit_msaa_ = false;
bool is_angle_ = false;
};
} // namespace impeller

View File

@ -40,6 +40,10 @@ static bool DetermineIfES(const std::string& version) {
return HasPrefix(version, "OpenGL ES");
}
static bool DetermineIfANGLE(const std::string& version) {
return version.find("ANGLE") != std::string::npos;
}
static std::optional<Version> DetermineVersion(std::string version) {
// Format for OpenGL "OpenGL<space>ES<space><version
// number><space><vendor-specific information>".
@ -81,6 +85,7 @@ DescriptionGLES::DescriptionGLES(const ProcTableGLES& gl)
gl_version_string_(GetGLString(gl, GL_VERSION)),
sl_version_string_(GetGLString(gl, GL_SHADING_LANGUAGE_VERSION)) {
is_es_ = DetermineIfES(gl_version_string_);
is_angle_ = DetermineIfANGLE(gl_version_string_);
auto gl_version = DetermineVersion(gl_version_string_);
if (!gl_version.has_value()) {
@ -164,6 +169,10 @@ bool DescriptionGLES::IsES() const {
return is_es_;
}
bool DescriptionGLES::IsANGLE() const {
return is_angle_;
}
bool DescriptionGLES::HasExtension(const std::string& ext) const {
return extensions_.find(ext) != extensions_.end();
}

View File

@ -34,6 +34,8 @@ class DescriptionGLES {
/// @brief Returns whether GLES includes the debug extension.
bool HasDebugExtension() const;
bool IsANGLE() const;
private:
Version gl_version_;
Version sl_version_;
@ -43,6 +45,7 @@ class DescriptionGLES {
std::string gl_version_string_;
std::string sl_version_string_;
std::set<std::string> extensions_;
bool is_angle_ = false;
bool is_valid_ = false;
DescriptionGLES(const DescriptionGLES&) = delete;

View File

@ -473,23 +473,21 @@ struct RenderPassData {
if (gl.DiscardFramebufferEXT.IsAvailable()) {
std::vector<GLenum> attachments;
// TODO(jonahwilliams): discarding stencil or depth on the default fbo
// causes Angle to discard the entire render target. Until we know the
// reason, default to storing.
bool angle_safe = gl.GetCapabilities()->IsANGLE() ? !is_default_fbo : true;
if (pass_data.discard_color_attachment) {
attachments.push_back(is_default_fbo ? GL_COLOR_EXT
: GL_COLOR_ATTACHMENT0);
}
if (pass_data.discard_depth_attachment) {
if (pass_data.discard_depth_attachment && angle_safe) {
attachments.push_back(is_default_fbo ? GL_DEPTH_EXT
: GL_DEPTH_ATTACHMENT);
}
// TODO(jonahwilliams): discarding the stencil on the default fbo when running
// on Windows causes Angle to discard the entire render target. Until we know
// the reason, default to storing.
#ifdef FML_OS_WIN
if (pass_data.discard_stencil_attachment && !is_default_fbo) {
#else
if (pass_data.discard_stencil_attachment) {
#endif
if (pass_data.discard_stencil_attachment && angle_safe) {
attachments.push_back(is_default_fbo ? GL_STENCIL_EXT
: GL_STENCIL_ATTACHMENT);
}

View File

@ -250,6 +250,7 @@ test_fixtures("fixtures") {
"fixtures/scene_without_custom_compositor.png",
"fixtures/scene_without_custom_compositor_with_xform.png",
"fixtures/snapshot_large_scene.png",
"fixtures/solid_red.png",
"fixtures/verifyb143464703.png",
"fixtures/verifyb143464703_soft_noxform.png",
]

View File

@ -310,22 +310,27 @@ InferOpenGLPlatformViewCreationCallback(
// damage are always 1. Once the function that computes damage implements
// support for multiple damage rectangles, GLPresentInfo should also
// contain the number of damage rectangles.
const size_t num_rects = 1;
std::array<FlutterRect, num_rects> frame_damage_rect = {
SkIRectToFlutterRect(*(gl_present_info.frame_damage))};
std::array<FlutterRect, num_rects> buffer_damage_rect = {
SkIRectToFlutterRect(*(gl_present_info.buffer_damage))};
std::optional<FlutterRect> frame_damage_rect;
if (gl_present_info.frame_damage) {
frame_damage_rect =
SkIRectToFlutterRect(*(gl_present_info.frame_damage));
}
std::optional<FlutterRect> buffer_damage_rect;
if (gl_present_info.buffer_damage) {
buffer_damage_rect =
SkIRectToFlutterRect(*(gl_present_info.buffer_damage));
}
FlutterDamage frame_damage{
.struct_size = sizeof(FlutterDamage),
.num_rects = frame_damage_rect.size(),
.damage = frame_damage_rect.data(),
.num_rects = frame_damage_rect ? size_t{1} : size_t{0},
.damage = frame_damage_rect ? &frame_damage_rect.value() : nullptr,
};
FlutterDamage buffer_damage{
.struct_size = sizeof(FlutterDamage),
.num_rects = buffer_damage_rect.size(),
.damage = buffer_damage_rect.data(),
.num_rects = buffer_damage_rect ? size_t{1} : size_t{0},
.damage = buffer_damage_rect ? &buffer_damage_rect.value() : nullptr,
};
// Construct the present information concerning the frame being rendered.
@ -981,31 +986,44 @@ MakeRenderTargetFromBackingStoreImpeller(
color0.load_action = impeller::LoadAction::kClear;
color0.store_action = impeller::StoreAction::kStore;
impeller::TextureDescriptor stencil0_tex;
stencil0_tex.type = impeller::TextureType::kTexture2D;
stencil0_tex.format = impeller::PixelFormat::kR8G8B8A8UNormInt;
stencil0_tex.size = size;
stencil0_tex.usage = static_cast<impeller::TextureUsageMask>(
impeller::TextureDescriptor depth_stencil_texture_desc;
depth_stencil_texture_desc.type = impeller::TextureType::kTexture2D;
depth_stencil_texture_desc.format = impeller::PixelFormat::kR8G8B8A8UNormInt;
depth_stencil_texture_desc.size = size;
depth_stencil_texture_desc.usage = static_cast<impeller::TextureUsageMask>(
impeller::TextureUsage::kRenderTarget);
stencil0_tex.sample_count = impeller::SampleCount::kCount1;
depth_stencil_texture_desc.sample_count = impeller::SampleCount::kCount1;
auto depth_stencil_tex = std::make_shared<impeller::TextureGLES>(
gl_context.GetReactor(), depth_stencil_texture_desc,
impeller::TextureGLES::IsWrapped::kWrapped);
impeller::DepthAttachment depth0;
depth0.clear_depth = 0;
depth0.texture = depth_stencil_tex;
depth0.load_action = impeller::LoadAction::kClear;
depth0.store_action = impeller::StoreAction::kDontCare;
impeller::StencilAttachment stencil0;
stencil0.clear_stencil = 0;
stencil0.texture = std::make_shared<impeller::TextureGLES>(
gl_context.GetReactor(), stencil0_tex,
impeller::TextureGLES::IsWrapped::kWrapped);
stencil0.texture = depth_stencil_tex;
stencil0.load_action = impeller::LoadAction::kClear;
stencil0.store_action = impeller::StoreAction::kDontCare;
impeller::RenderTarget render_target_desc;
render_target_desc.SetColorAttachment(color0, 0u);
render_target_desc.SetDepthAttachment(depth0);
render_target_desc.SetStencilAttachment(stencil0);
fml::closure framebuffer_destruct =
[callback = framebuffer->destruction_callback,
user_data = framebuffer->user_data]() { callback(user_data); };
return std::make_unique<flutter::EmbedderRenderTargetImpeller>(
backing_store, aiks_context,
std::make_unique<impeller::RenderTarget>(std::move(render_target_desc)),
on_release);
on_release, framebuffer_destruct);
#else
return nullptr;
#endif
@ -1075,7 +1093,7 @@ MakeRenderTargetFromBackingStoreImpeller(
return std::make_unique<flutter::EmbedderRenderTargetImpeller>(
backing_store, aiks_context,
std::make_unique<impeller::RenderTarget>(std::move(render_target_desc)),
on_release);
on_release, fml::closure());
#else
return nullptr;
#endif

View File

@ -13,15 +13,22 @@ EmbedderRenderTargetImpeller::EmbedderRenderTargetImpeller(
FlutterBackingStore backing_store,
std::shared_ptr<impeller::AiksContext> aiks_context,
std::unique_ptr<impeller::RenderTarget> impeller_target,
fml::closure on_release)
fml::closure on_release,
fml::closure framebuffer_destruction_callback)
: EmbedderRenderTarget(backing_store, std::move(on_release)),
aiks_context_(std::move(aiks_context)),
impeller_target_(std::move(impeller_target)) {
impeller_target_(std::move(impeller_target)),
framebuffer_destruction_callback_(
std::move(framebuffer_destruction_callback)) {
FML_DCHECK(aiks_context_);
FML_DCHECK(impeller_target_);
}
EmbedderRenderTargetImpeller::~EmbedderRenderTargetImpeller() = default;
EmbedderRenderTargetImpeller::~EmbedderRenderTargetImpeller() {
if (framebuffer_destruction_callback_) {
framebuffer_destruction_callback_();
}
}
sk_sp<SkSurface> EmbedderRenderTargetImpeller::GetSkiaSurface() const {
return nullptr;

View File

@ -15,7 +15,8 @@ class EmbedderRenderTargetImpeller final : public EmbedderRenderTarget {
FlutterBackingStore backing_store,
std::shared_ptr<impeller::AiksContext> aiks_context,
std::unique_ptr<impeller::RenderTarget> impeller_target,
fml::closure on_release);
fml::closure on_release,
fml::closure framebuffer_destruction_callback);
// |EmbedderRenderTarget|
~EmbedderRenderTargetImpeller() override;
@ -35,6 +36,7 @@ class EmbedderRenderTargetImpeller final : public EmbedderRenderTarget {
private:
std::shared_ptr<impeller::AiksContext> aiks_context_;
std::unique_ptr<impeller::RenderTarget> impeller_target_;
fml::closure framebuffer_destruction_callback_;
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderRenderTargetImpeller);
};

View File

@ -7,6 +7,8 @@
#include <utility>
#include "impeller/entity/gles/entity_shaders_gles.h"
#include "impeller/entity/gles/framebuffer_blend_shaders_gles.h"
#include "impeller/entity/gles/modern_shaders_gles.h"
#include "impeller/renderer/backend/gles/context_gles.h"
#include "impeller/renderer/backend/gles/proc_table_gles.h"
@ -68,6 +70,12 @@ EmbedderSurfaceGLImpeller::EmbedderSurfaceGLImpeller(
std::make_shared<fml::NonOwnedMapping>(
impeller_entity_shaders_gles_data,
impeller_entity_shaders_gles_length),
std::make_shared<fml::NonOwnedMapping>(
impeller_modern_shaders_gles_data,
impeller_modern_shaders_gles_length),
std::make_shared<fml::NonOwnedMapping>(
impeller_framebuffer_blend_shaders_gles_data,
impeller_framebuffer_blend_shaders_gles_length),
#if IMPELLER_ENABLE_3D
std::make_shared<fml::NonOwnedMapping>(
impeller_scene_shaders_gles_data, impeller_scene_shaders_gles_length),

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -26,6 +26,7 @@
#include "flutter/fml/thread.h"
#include "flutter/lib/ui/painting/image.h"
#include "flutter/runtime/dart_vm.h"
#include "flutter/shell/platform/embedder/embedder_surface_gl_impeller.h"
#include "flutter/shell/platform/embedder/tests/embedder_assertions.h"
#include "flutter/shell/platform/embedder/tests/embedder_config_builder.h"
#include "flutter/shell/platform/embedder/tests/embedder_test.h"
@ -4699,6 +4700,37 @@ TEST_F(EmbedderTest,
latch.Wait();
}
TEST_F(EmbedderTest, CanRenderWithImpellerOpenGL) {
auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext);
EmbedderConfigBuilder builder(context);
builder.AddCommandLineArgument("--enable-impeller");
builder.SetDartEntrypoint("draw_solid_red");
builder.SetOpenGLRendererConfig(SkISize::Make(800, 600));
builder.SetCompositor();
builder.SetRenderTargetType(
EmbedderTestBackingStoreProducer::RenderTargetType::kOpenGLFramebuffer);
auto rendered_scene = context.GetNextSceneImage();
auto engine = builder.LaunchEngine();
ASSERT_TRUE(engine.is_valid());
// Send a window metrics events so frames may be scheduled.
FlutterWindowMetricsEvent event = {};
event.struct_size = sizeof(event);
event.width = 800;
event.height = 600;
event.pixel_ratio = 1.0;
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
kSuccess);
ASSERT_TRUE(ImageMatchesFixture(
FixtureNameForBackend(EmbedderTestContextType::kOpenGLContext,
"solid_red.png"),
rendered_scene));
}
INSTANTIATE_TEST_SUITE_P(
EmbedderTestGlVk,
EmbedderTestMultiBackend,