mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Update embedder support for Impeller/OpenGL to load some missing shaders and configure a depth attachment (flutter/engine#50416)
This commit is contained in:
parent
4cdf45c587
commit
5b220df694
@ -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.";
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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",
|
||||
]
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
};
|
||||
|
||||
@ -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 |
@ -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,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user