Implements anti-aliased lines (#164734)
issue: https://github.com/flutter/flutter/issues/138682 design doc: https://docs.google.com/document/d/19I6ToHCMlSgSava-niFWzMLGJEAd-rYiBQEGOMu8IJg/edit?tab=t.0 This puts an experimental line drawing approach behind the following flags: - iOS: `FLTAntialiasLines` boolean, default NO - Android: `io.flutter.embedding.android.ImpellerAntialiasLines` boolean, default false Right now they just support DrawLines and don't support line caps. A test was added that works as a playground for vulkan, opengles and metal. Only the Metal version was turned into a golden test though here. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This commit is contained in:
@@ -161,6 +161,7 @@
|
||||
../../../flutter/impeller/entity/contents/filters/inputs/filter_input_unittests.cc
|
||||
../../../flutter/impeller/entity/contents/filters/matrix_filter_contents_unittests.cc
|
||||
../../../flutter/impeller/entity/contents/host_buffer_unittests.cc
|
||||
../../../flutter/impeller/entity/contents/line_contents_unittests.cc
|
||||
../../../flutter/impeller/entity/contents/test
|
||||
../../../flutter/impeller/entity/contents/text_contents_unittests.cc
|
||||
../../../flutter/impeller/entity/contents/tiled_texture_contents_unittests.cc
|
||||
|
||||
@@ -51252,6 +51252,8 @@ ORIGIN: ../../../flutter/impeller/entity/contents/framebuffer_blend_contents.cc
|
||||
ORIGIN: ../../../flutter/impeller/entity/contents/framebuffer_blend_contents.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/entity/contents/gradient_generator.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/entity/contents/gradient_generator.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/entity/contents/line_contents.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/entity/contents/line_contents.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/entity/contents/linear_gradient_contents.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/entity/contents/linear_gradient_contents.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/entity/contents/radial_gradient_contents.cc + ../../../flutter/LICENSE
|
||||
@@ -51357,6 +51359,8 @@ ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/radial_gradient_unifo
|
||||
ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/sweep_gradient_fill.frag + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/sweep_gradient_ssbo_fill.frag + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/entity/shaders/gradients/sweep_gradient_uniform_fill.frag + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/entity/shaders/line.frag + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/entity/shaders/line.vert + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/entity/shaders/rrect_blur.frag + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/entity/shaders/rrect_blur.vert + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/entity/shaders/runtime_effect.vert + ../../../flutter/LICENSE
|
||||
@@ -51689,8 +51693,8 @@ ORIGIN: ../../../flutter/impeller/renderer/snapshot.cc + ../../../flutter/LICENS
|
||||
ORIGIN: ../../../flutter/impeller/renderer/snapshot.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/surface.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/surface.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/texture_mipmap.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/texture_mipmap.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/texture_util.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/texture_util.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/threadgroup_sizing_test.comp + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/vertex_buffer_builder.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/vertex_buffer_builder.h + ../../../flutter/LICENSE
|
||||
@@ -54225,6 +54229,8 @@ FILE: ../../../flutter/impeller/entity/contents/framebuffer_blend_contents.cc
|
||||
FILE: ../../../flutter/impeller/entity/contents/framebuffer_blend_contents.h
|
||||
FILE: ../../../flutter/impeller/entity/contents/gradient_generator.cc
|
||||
FILE: ../../../flutter/impeller/entity/contents/gradient_generator.h
|
||||
FILE: ../../../flutter/impeller/entity/contents/line_contents.cc
|
||||
FILE: ../../../flutter/impeller/entity/contents/line_contents.h
|
||||
FILE: ../../../flutter/impeller/entity/contents/linear_gradient_contents.cc
|
||||
FILE: ../../../flutter/impeller/entity/contents/linear_gradient_contents.h
|
||||
FILE: ../../../flutter/impeller/entity/contents/radial_gradient_contents.cc
|
||||
@@ -54330,6 +54336,8 @@ FILE: ../../../flutter/impeller/entity/shaders/gradients/radial_gradient_uniform
|
||||
FILE: ../../../flutter/impeller/entity/shaders/gradients/sweep_gradient_fill.frag
|
||||
FILE: ../../../flutter/impeller/entity/shaders/gradients/sweep_gradient_ssbo_fill.frag
|
||||
FILE: ../../../flutter/impeller/entity/shaders/gradients/sweep_gradient_uniform_fill.frag
|
||||
FILE: ../../../flutter/impeller/entity/shaders/line.frag
|
||||
FILE: ../../../flutter/impeller/entity/shaders/line.vert
|
||||
FILE: ../../../flutter/impeller/entity/shaders/rrect_blur.frag
|
||||
FILE: ../../../flutter/impeller/entity/shaders/rrect_blur.vert
|
||||
FILE: ../../../flutter/impeller/entity/shaders/runtime_effect.vert
|
||||
@@ -54663,8 +54671,8 @@ FILE: ../../../flutter/impeller/renderer/snapshot.cc
|
||||
FILE: ../../../flutter/impeller/renderer/snapshot.h
|
||||
FILE: ../../../flutter/impeller/renderer/surface.cc
|
||||
FILE: ../../../flutter/impeller/renderer/surface.h
|
||||
FILE: ../../../flutter/impeller/renderer/texture_mipmap.cc
|
||||
FILE: ../../../flutter/impeller/renderer/texture_mipmap.h
|
||||
FILE: ../../../flutter/impeller/renderer/texture_util.cc
|
||||
FILE: ../../../flutter/impeller/renderer/texture_util.h
|
||||
FILE: ../../../flutter/impeller/renderer/threadgroup_sizing_test.comp
|
||||
FILE: ../../../flutter/impeller/renderer/vertex_buffer_builder.cc
|
||||
FILE: ../../../flutter/impeller/renderer/vertex_buffer_builder.h
|
||||
|
||||
@@ -231,6 +231,9 @@ struct Settings {
|
||||
// Whether to lazily initialize impeller PSO state.
|
||||
bool impeller_enable_lazy_shader_mode = false;
|
||||
|
||||
// An experimental mode that antialiases lines.
|
||||
bool impeller_antialiased_lines = false;
|
||||
|
||||
// Log a warning during shell initialization if Impeller is not enabled.
|
||||
bool warn_on_impeller_opt_out = false;
|
||||
|
||||
|
||||
@@ -91,7 +91,9 @@ sk_sp<DlImage> DlMetalSurfaceProvider::MakeImpellerImage(const sk_sp<DisplayList
|
||||
|
||||
void DlMetalSurfaceProvider::InitScreenShotter() const {
|
||||
if (!snapshotter_) {
|
||||
snapshotter_.reset(new MetalScreenshotter(/*enable_wide_gamut=*/false));
|
||||
impeller::PlaygroundSwitches switches;
|
||||
switches.enable_wide_gamut = false;
|
||||
snapshotter_.reset(new MetalScreenshotter(switches));
|
||||
auto typographer = impeller::TypographerContextSkia::Make();
|
||||
aiks_context_.reset(
|
||||
new impeller::AiksContext(snapshotter_->GetPlayground().GetContext(), typographer));
|
||||
|
||||
@@ -10,6 +10,8 @@ struct Flags {
|
||||
/// Whether to defer PSO construction until first use. Usage Will introduce
|
||||
/// raster jank.
|
||||
bool lazy_shader_mode = false;
|
||||
/// When turned on DrawLine will use the experimental antialiased path.
|
||||
bool antialiased_lines = false;
|
||||
};
|
||||
} // namespace impeller
|
||||
|
||||
|
||||
@@ -382,6 +382,47 @@ TEST_P(AiksTest, DrawLinesRenderCorrectly) {
|
||||
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, SimpleExperimentAntialiasLines) {
|
||||
DisplayListBuilder builder;
|
||||
builder.Scale(GetContentScale().x, GetContentScale().y);
|
||||
|
||||
builder.DrawPaint(DlPaint(DlColor(0xff111111)));
|
||||
|
||||
DlPaint paint;
|
||||
paint.setColor(DlColor::kGreenYellow());
|
||||
paint.setStrokeWidth(10);
|
||||
|
||||
auto draw = [&builder](DlPaint& paint) {
|
||||
for (auto cap :
|
||||
{DlStrokeCap::kButt, DlStrokeCap::kSquare, DlStrokeCap::kRound}) {
|
||||
paint.setStrokeCap(cap);
|
||||
DlPoint origin = {100, 100};
|
||||
builder.DrawLine(DlPoint(150, 100), DlPoint(250, 100), paint);
|
||||
for (int d = 15; d < 90; d += 15) {
|
||||
Matrix m = Matrix::MakeRotationZ(Degrees(d));
|
||||
Point origin = {100, 100};
|
||||
Point p0 = {50, 0};
|
||||
Point p1 = {150, 0};
|
||||
auto a = origin + m * p0;
|
||||
auto b = origin + m * p1;
|
||||
|
||||
builder.DrawLine(a, b, paint);
|
||||
}
|
||||
builder.DrawLine(DlPoint(100, 150), DlPoint(100, 250), paint);
|
||||
builder.DrawCircle(origin, 35, paint);
|
||||
|
||||
builder.DrawLine(DlPoint(250, 250), DlPoint(250, 250), paint);
|
||||
|
||||
builder.Translate(250, 0);
|
||||
}
|
||||
builder.Translate(-750, 250);
|
||||
};
|
||||
|
||||
draw(paint);
|
||||
|
||||
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, DrawRectStrokesRenderCorrectly) {
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "impeller/entity/contents/content_context.h"
|
||||
#include "impeller/entity/contents/filters/filter_contents.h"
|
||||
#include "impeller/entity/contents/framebuffer_blend_contents.h"
|
||||
#include "impeller/entity/contents/line_contents.h"
|
||||
#include "impeller/entity/contents/solid_rrect_blur_contents.h"
|
||||
#include "impeller/entity/contents/text_contents.h"
|
||||
#include "impeller/entity/contents/texture_contents.h"
|
||||
@@ -459,9 +460,19 @@ void Canvas::DrawLine(const Point& p0,
|
||||
entity.SetTransform(GetCurrentTransform());
|
||||
entity.SetBlendMode(paint.blend_mode);
|
||||
|
||||
LineGeometry geom(p0, p1, paint.stroke_width, paint.stroke_cap);
|
||||
AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint,
|
||||
/*reuse_depth=*/reuse_depth);
|
||||
auto geometry = std::make_unique<LineGeometry>(p0, p1, paint.stroke_width,
|
||||
paint.stroke_cap);
|
||||
|
||||
if (renderer_.GetContext()->GetFlags().antialiased_lines &&
|
||||
!paint.color_filter && !paint.invert_colors && !paint.image_filter &&
|
||||
!paint.mask_blur_descriptor.has_value() && !paint.color_source) {
|
||||
auto contents = LineContents::Make(std::move(geometry), paint.color);
|
||||
entity.SetContents(std::move(contents));
|
||||
AddRenderEntityToCurrentPass(entity, reuse_depth);
|
||||
} else {
|
||||
AddRenderEntityWithFiltersToCurrentPass(entity, geometry.get(), paint,
|
||||
/*reuse_depth=*/reuse_depth);
|
||||
}
|
||||
}
|
||||
|
||||
void Canvas::DrawRect(const Rect& rect, const Paint& paint) {
|
||||
|
||||
@@ -35,6 +35,8 @@ impeller_shaders("entity_shaders") {
|
||||
"shaders/gradients/radial_gradient_uniform_fill.frag",
|
||||
"shaders/gradients/sweep_gradient_fill.frag",
|
||||
"shaders/gradients/sweep_gradient_uniform_fill.frag",
|
||||
"shaders/line.frag",
|
||||
"shaders/line.vert",
|
||||
"shaders/rrect_blur.vert",
|
||||
"shaders/rrect_blur.frag",
|
||||
"shaders/runtime_effect.vert",
|
||||
@@ -159,6 +161,8 @@ impeller_component("entity") {
|
||||
"contents/framebuffer_blend_contents.h",
|
||||
"contents/gradient_generator.cc",
|
||||
"contents/gradient_generator.h",
|
||||
"contents/line_contents.cc",
|
||||
"contents/line_contents.h",
|
||||
"contents/linear_gradient_contents.cc",
|
||||
"contents/linear_gradient_contents.h",
|
||||
"contents/radial_gradient_contents.cc",
|
||||
@@ -254,6 +258,7 @@ impeller_component("entity_unittests") {
|
||||
"contents/filters/inputs/filter_input_unittests.cc",
|
||||
"contents/filters/matrix_filter_contents_unittests.cc",
|
||||
"contents/host_buffer_unittests.cc",
|
||||
"contents/line_contents_unittests.cc",
|
||||
"contents/text_contents_unittests.cc",
|
||||
"contents/tiled_texture_contents_unittests.cc",
|
||||
"draw_order_resolver_unittests.cc",
|
||||
|
||||
@@ -36,6 +36,15 @@ namespace impeller {
|
||||
///
|
||||
class ColorSourceContents : public Contents {
|
||||
public:
|
||||
using BindFragmentCallback = std::function<bool(RenderPass& pass)>;
|
||||
using PipelineBuilderCallback =
|
||||
std::function<PipelineRef(ContentContextOptions)>;
|
||||
using CreateGeometryCallback =
|
||||
std::function<GeometryResult(const ContentContext& renderer,
|
||||
const Entity& entity,
|
||||
RenderPass& pass,
|
||||
const Geometry* geom)>;
|
||||
|
||||
ColorSourceContents();
|
||||
|
||||
~ColorSourceContents() override;
|
||||
@@ -99,41 +108,21 @@ class ColorSourceContents : public Contents {
|
||||
// |Contents|
|
||||
void SetInheritedOpacity(Scalar opacity) override;
|
||||
|
||||
protected:
|
||||
using BindFragmentCallback = std::function<bool(RenderPass& pass)>;
|
||||
using PipelineBuilderCallback =
|
||||
std::function<PipelineRef(ContentContextOptions)>;
|
||||
using CreateGeometryCallback =
|
||||
std::function<GeometryResult(const ContentContext& renderer,
|
||||
const Entity& entity,
|
||||
RenderPass& pass,
|
||||
const Geometry* geom)>;
|
||||
|
||||
static GeometryResult DefaultCreateGeometryCallback(
|
||||
const ContentContext& renderer,
|
||||
const Entity& entity,
|
||||
RenderPass& pass,
|
||||
const Geometry* geom) {
|
||||
return geom->GetPositionBuffer(renderer, entity, pass);
|
||||
}
|
||||
|
||||
/// @brief Whether the entity should be treated as non-opaque due to stroke
|
||||
/// geometry requiring alpha for coverage.
|
||||
bool AppliesAlphaForStrokeCoverage(const Matrix& transform) const;
|
||||
|
||||
template <typename VertexShaderT>
|
||||
bool DrawGeometry(const ContentContext& renderer,
|
||||
const Entity& entity,
|
||||
RenderPass& pass,
|
||||
const PipelineBuilderCallback& pipeline_callback,
|
||||
typename VertexShaderT::FrameInfo frame_info,
|
||||
const BindFragmentCallback& bind_fragment_callback,
|
||||
bool force_stencil = false,
|
||||
const CreateGeometryCallback& create_geom_callback =
|
||||
DefaultCreateGeometryCallback) const {
|
||||
static bool DrawGeometry(const Contents* contents,
|
||||
const Geometry* geometry,
|
||||
const ContentContext& renderer,
|
||||
const Entity& entity,
|
||||
RenderPass& pass,
|
||||
const PipelineBuilderCallback& pipeline_callback,
|
||||
typename VertexShaderT::FrameInfo frame_info,
|
||||
const BindFragmentCallback& bind_fragment_callback,
|
||||
bool force_stencil = false,
|
||||
const CreateGeometryCallback& create_geom_callback =
|
||||
DefaultCreateGeometryCallback) {
|
||||
auto options = OptionsFromPassAndEntity(pass, entity);
|
||||
|
||||
GeometryResult::Mode geometry_mode = GetGeometry()->GetResultMode();
|
||||
GeometryResult::Mode geometry_mode = geometry->GetResultMode();
|
||||
bool do_cover_draw = false;
|
||||
Rect cover_area = {};
|
||||
|
||||
@@ -151,7 +140,7 @@ class ColorSourceContents : public Contents {
|
||||
/// Stencil preparation draw.
|
||||
|
||||
GeometryResult stencil_geometry_result =
|
||||
GetGeometry()->GetPositionBuffer(renderer, entity, pass);
|
||||
geometry->GetPositionBuffer(renderer, entity, pass);
|
||||
if (stencil_geometry_result.vertex_buffer.vertex_count == 0u) {
|
||||
return true;
|
||||
}
|
||||
@@ -194,7 +183,7 @@ class ColorSourceContents : public Contents {
|
||||
|
||||
options.blend_mode = entity.GetBlendMode();
|
||||
options.stencil_mode = ContentContextOptions::StencilMode::kCoverCompare;
|
||||
std::optional<Rect> maybe_cover_area = GetGeometry()->GetCoverage({});
|
||||
std::optional<Rect> maybe_cover_area = geometry->GetCoverage({});
|
||||
if (!maybe_cover_area.has_value()) {
|
||||
return true;
|
||||
}
|
||||
@@ -207,8 +196,7 @@ class ColorSourceContents : public Contents {
|
||||
RectGeometry geom(cover_area);
|
||||
geometry_result = create_geom_callback(renderer, entity, pass, &geom);
|
||||
} else {
|
||||
geometry_result =
|
||||
create_geom_callback(renderer, entity, pass, GetGeometry());
|
||||
geometry_result = create_geom_callback(renderer, entity, pass, geometry);
|
||||
}
|
||||
|
||||
if (geometry_result.vertex_buffer.vertex_count == 0u) {
|
||||
@@ -261,11 +249,47 @@ class ColorSourceContents : public Contents {
|
||||
if (geometry_result.mode == GeometryResult::Mode::kPreventOverdraw &&
|
||||
options.blend_mode != BlendMode::kSrc) {
|
||||
return RenderClipRestore(renderer, pass, entity.GetClipDepth(),
|
||||
GetCoverage(entity));
|
||||
contents->GetCoverage(entity));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
static GeometryResult DefaultCreateGeometryCallback(
|
||||
const ContentContext& renderer,
|
||||
const Entity& entity,
|
||||
RenderPass& pass,
|
||||
const Geometry* geom) {
|
||||
return geom->GetPositionBuffer(renderer, entity, pass);
|
||||
}
|
||||
|
||||
/// @brief Whether the entity should be treated as non-opaque due to stroke
|
||||
/// geometry requiring alpha for coverage.
|
||||
bool AppliesAlphaForStrokeCoverage(const Matrix& transform) const;
|
||||
|
||||
template <typename VertexShaderT>
|
||||
bool DrawGeometry(const ContentContext& renderer,
|
||||
const Entity& entity,
|
||||
RenderPass& pass,
|
||||
const PipelineBuilderCallback& pipeline_callback,
|
||||
typename VertexShaderT::FrameInfo frame_info,
|
||||
const BindFragmentCallback& bind_fragment_callback,
|
||||
bool force_stencil = false,
|
||||
const CreateGeometryCallback& create_geom_callback =
|
||||
DefaultCreateGeometryCallback) const {
|
||||
//
|
||||
return DrawGeometry<VertexShaderT>(this, //
|
||||
GetGeometry(), //
|
||||
renderer, //
|
||||
entity, //
|
||||
pass, //
|
||||
pipeline_callback, //
|
||||
frame_info, //
|
||||
bind_fragment_callback, //
|
||||
force_stencil, //
|
||||
create_geom_callback);
|
||||
}
|
||||
|
||||
private:
|
||||
const Geometry* geometry_ = nullptr;
|
||||
Matrix inverse_matrix_;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "impeller/renderer/pipeline_descriptor.h"
|
||||
#include "impeller/renderer/pipeline_library.h"
|
||||
#include "impeller/renderer/render_target.h"
|
||||
#include "impeller/renderer/texture_mipmap.h"
|
||||
#include "impeller/renderer/texture_util.h"
|
||||
#include "impeller/tessellator/tessellator.h"
|
||||
#include "impeller/typographer/typographer_context.h"
|
||||
|
||||
@@ -329,6 +329,7 @@ ContentContext::ContentContext(
|
||||
solid_fill_pipelines_.CreateDefault(*context_, options);
|
||||
texture_pipelines_.CreateDefault(*context_, options);
|
||||
fast_gradient_pipelines_.CreateDefault(*context_, options);
|
||||
line_pipelines_.CreateDefault(*context_, options);
|
||||
|
||||
if (context_->GetCapabilities()->SupportsSSBO()) {
|
||||
linear_gradient_ssbo_fill_pipelines_.CreateDefault(*context_, options);
|
||||
@@ -1159,6 +1160,10 @@ PipelineRef ContentContext::GetDrawVerticesUberShader(
|
||||
return GetPipeline(vertices_uber_shader_, opts);
|
||||
}
|
||||
|
||||
PipelineRef ContentContext::GetLinePipeline(ContentContextOptions opts) const {
|
||||
return GetPipeline(line_pipelines_, opts);
|
||||
}
|
||||
|
||||
#ifdef IMPELLER_ENABLE_OPENGLES
|
||||
PipelineRef ContentContext::GetDownsampleTextureGlesPipeline(
|
||||
ContentContextOptions opts) const {
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
#include "impeller/entity/glyph_atlas.frag.h"
|
||||
#include "impeller/entity/glyph_atlas.vert.h"
|
||||
#include "impeller/entity/gradient_fill.vert.h"
|
||||
#include "impeller/entity/line.frag.h"
|
||||
#include "impeller/entity/line.vert.h"
|
||||
#include "impeller/entity/linear_gradient_fill.frag.h"
|
||||
#include "impeller/entity/linear_to_srgb_filter.frag.h"
|
||||
#include "impeller/entity/morphology_filter.frag.h"
|
||||
@@ -147,6 +149,7 @@ using FramebufferBlendScreenPipeline = FramebufferBlendPipelineHandle;
|
||||
using FramebufferBlendSoftLightPipeline = FramebufferBlendPipelineHandle;
|
||||
using GaussianBlurPipeline = RenderPipelineHandle<FilterPositionUvVertexShader, GaussianFragmentShader>;
|
||||
using GlyphAtlasPipeline = RenderPipelineHandle<GlyphAtlasVertexShader, GlyphAtlasFragmentShader>;
|
||||
using LinePipeline = RenderPipelineHandle<LineVertexShader, LineFragmentShader>;
|
||||
using LinearGradientFillPipeline = GradientPipelineHandle<LinearGradientFillFragmentShader>;
|
||||
using LinearGradientSSBOFillPipeline = GradientPipelineHandle<LinearGradientSsboFillFragmentShader>;
|
||||
using LinearGradientUniformFillPipeline = GradientPipelineHandle<LinearGradientUniformFillFragmentShader>;
|
||||
@@ -352,6 +355,7 @@ class ContentContext {
|
||||
PipelineRef GetFramebufferBlendSoftLightPipeline(ContentContextOptions opts) const;
|
||||
PipelineRef GetGaussianBlurPipeline(ContentContextOptions opts) const;
|
||||
PipelineRef GetGlyphAtlasPipeline(ContentContextOptions opts) const;
|
||||
PipelineRef GetLinePipeline(ContentContextOptions opts) const;
|
||||
PipelineRef GetLinearGradientFillPipeline(ContentContextOptions opts) const;
|
||||
PipelineRef GetLinearGradientSSBOFillPipeline(ContentContextOptions opts) const;
|
||||
PipelineRef GetLinearGradientUniformFillPipeline(ContentContextOptions opts) const;
|
||||
@@ -645,6 +649,7 @@ class ContentContext {
|
||||
mutable Variants<FramebufferBlendSoftLightPipeline> framebuffer_blend_softlight_pipelines_;
|
||||
mutable Variants<GaussianBlurPipeline> gaussian_blur_pipelines_;
|
||||
mutable Variants<GlyphAtlasPipeline> glyph_atlas_pipelines_;
|
||||
mutable Variants<LinePipeline> line_pipelines_;
|
||||
mutable Variants<LinearGradientFillPipeline> linear_gradient_fill_pipelines_;
|
||||
mutable Variants<LinearGradientSSBOFillPipeline> linear_gradient_ssbo_fill_pipelines_;
|
||||
mutable Variants<LinearGradientUniformFillPipeline> linear_gradient_uniform_fill_pipelines_;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "impeller/core/formats.h"
|
||||
#include "impeller/core/texture.h"
|
||||
#include "impeller/renderer/context.h"
|
||||
#include "impeller/renderer/texture_util.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
@@ -25,29 +26,9 @@ std::shared_ptr<Texture> CreateGradientTexture(
|
||||
texture_descriptor.storage_mode = impeller::StorageMode::kHostVisible;
|
||||
texture_descriptor.format = PixelFormat::kR8G8B8A8UNormInt;
|
||||
texture_descriptor.size = {gradient_data.texture_size, 1};
|
||||
auto texture =
|
||||
context->GetResourceAllocator()->CreateTexture(texture_descriptor);
|
||||
if (!texture) {
|
||||
FML_DLOG(ERROR) << "Could not create Impeller texture.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto data_mapping =
|
||||
std::make_shared<fml::DataMapping>(gradient_data.color_bytes);
|
||||
auto buffer =
|
||||
context->GetResourceAllocator()->CreateBufferWithCopy(*data_mapping);
|
||||
|
||||
auto cmd_buffer = context->CreateCommandBuffer();
|
||||
auto blit_pass = cmd_buffer->CreateBlitPass();
|
||||
blit_pass->AddCopy(DeviceBuffer::AsBufferView(std::move(buffer)), texture);
|
||||
|
||||
if (!blit_pass->EncodeCommands() ||
|
||||
!context->GetCommandQueue()->Submit({std::move(cmd_buffer)}).ok()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
texture->SetLabel(impeller::SPrintF("Gradient(%p)", texture.get()).c_str());
|
||||
return texture;
|
||||
return CreateTexture(texture_descriptor, gradient_data.color_bytes, context,
|
||||
"Gradient");
|
||||
}
|
||||
|
||||
std::vector<StopData> CreateGradientColors(const std::vector<Color>& colors,
|
||||
|
||||
188
engine/src/flutter/impeller/entity/contents/line_contents.cc
Normal file
188
engine/src/flutter/impeller/entity/contents/line_contents.cc
Normal file
@@ -0,0 +1,188 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "impeller/entity/contents/line_contents.h"
|
||||
#include "impeller/entity/contents/clip_contents.h"
|
||||
#include "impeller/entity/contents/color_source_contents.h"
|
||||
#include "impeller/entity/geometry/rect_geometry.h"
|
||||
#include "impeller/renderer/texture_util.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
using VS = LinePipeline::VertexShader;
|
||||
using FS = LinePipeline::FragmentShader;
|
||||
|
||||
namespace {
|
||||
using BindFragmentCallback = std::function<bool(RenderPass& pass)>;
|
||||
using PipelineBuilderCallback =
|
||||
std::function<PipelineRef(ContentContextOptions)>;
|
||||
using CreateGeometryCallback =
|
||||
std::function<GeometryResult(const ContentContext& renderer,
|
||||
const Entity& entity,
|
||||
RenderPass& pass,
|
||||
const Geometry* geometry)>;
|
||||
|
||||
const int32_t kCurveResolution = 32;
|
||||
const Scalar kSampleRadius = 0.5f;
|
||||
|
||||
struct LineInfo {
|
||||
Vector3 e0;
|
||||
Vector3 e1;
|
||||
Vector3 e2;
|
||||
Vector3 e3;
|
||||
};
|
||||
|
||||
LineInfo CalculateLineInfo(Point p0, Point p1, Scalar width, Scalar radius) {
|
||||
Vector2 diff = p0 - p1;
|
||||
float k = 2.0 / ((2.0 * radius + width) * sqrt(diff.Dot(diff)));
|
||||
|
||||
return LineInfo{
|
||||
.e0 = Vector3(k * (p0.y - p1.y), //
|
||||
k * (p1.x - p0.x), //
|
||||
1.0 + k * (p0.x * p1.y - p1.x * p0.y)),
|
||||
.e1 = Vector3(
|
||||
k * (p1.x - p0.x), //
|
||||
k * (p1.y - p0.y), //
|
||||
1.0 + k * (p0.x * p0.x + p0.y * p0.y - p0.x * p1.x - p0.y * p1.y)),
|
||||
.e2 = Vector3(k * (p1.y - p0.y), //
|
||||
k * (p0.x - p1.x), //
|
||||
1.0 + k * (p1.x * p0.y - p0.x * p1.y)),
|
||||
.e3 = Vector3(
|
||||
k * (p0.x - p1.x), //
|
||||
k * (p0.y - p1.y), //
|
||||
1.0 + k * (p1.x * p1.x + p1.y * p1.y - p0.x * p1.x - p0.y * p1.y)),
|
||||
};
|
||||
}
|
||||
|
||||
uint8_t DoubleToUint8(double x) {
|
||||
return static_cast<uint8_t>(std::clamp(std::round(x * 255.0), 0.0, 255.0));
|
||||
}
|
||||
|
||||
/// See also: CreateGradientTexture
|
||||
std::shared_ptr<Texture> CreateCurveTexture(
|
||||
Scalar width,
|
||||
const std::shared_ptr<impeller::Context>& context) {
|
||||
//
|
||||
impeller::TextureDescriptor texture_descriptor;
|
||||
texture_descriptor.storage_mode = impeller::StorageMode::kHostVisible;
|
||||
texture_descriptor.format = PixelFormat::kR8UNormInt;
|
||||
texture_descriptor.size = {kCurveResolution, 1};
|
||||
|
||||
std::vector<uint8_t> curve_data;
|
||||
curve_data.reserve(kCurveResolution);
|
||||
for (int i = 0; i < kCurveResolution; ++i) {
|
||||
double norm = (static_cast<double>(i) + 1.0) / 32.0;
|
||||
double loc = norm * (kSampleRadius + width / 2.0);
|
||||
double den = kSampleRadius * 2.0 + 1.0;
|
||||
curve_data.push_back(DoubleToUint8(loc / den));
|
||||
}
|
||||
|
||||
return CreateTexture(texture_descriptor, curve_data, context, "LineCurve");
|
||||
}
|
||||
|
||||
GeometryResult CreateGeometry(const ContentContext& renderer,
|
||||
const Entity& entity,
|
||||
RenderPass& pass,
|
||||
const Geometry* geometry) {
|
||||
using PerVertexData = LineVertexShader::PerVertexData;
|
||||
const LineGeometry* line_geometry =
|
||||
static_cast<const LineGeometry*>(geometry);
|
||||
|
||||
auto& transform = entity.GetTransform();
|
||||
|
||||
Point corners[4];
|
||||
if (!LineGeometry::ComputeCorners(
|
||||
corners, transform,
|
||||
/*extend_endpoints=*/line_geometry->GetCap() != Cap::kButt,
|
||||
line_geometry->GetP0(), line_geometry->GetP1(),
|
||||
line_geometry->GetWidth() + kSampleRadius)) {
|
||||
return kEmptyResult;
|
||||
}
|
||||
|
||||
auto& host_buffer = renderer.GetTransientsBuffer();
|
||||
|
||||
size_t count = 4;
|
||||
LineInfo line_info =
|
||||
CalculateLineInfo(line_geometry->GetP0(), line_geometry->GetP1(),
|
||||
line_geometry->GetWidth(), kSampleRadius);
|
||||
BufferView vertex_buffer = host_buffer.Emplace(
|
||||
count * sizeof(PerVertexData), alignof(PerVertexData),
|
||||
[&corners, &line_info](uint8_t* buffer) {
|
||||
auto vertices = reinterpret_cast<PerVertexData*>(buffer);
|
||||
for (auto& corner : corners) {
|
||||
*vertices++ = {
|
||||
.position = corner,
|
||||
.e0 = line_info.e0,
|
||||
.e1 = line_info.e1,
|
||||
.e2 = line_info.e2,
|
||||
.e3 = line_info.e3,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
std::shared_ptr<Texture> curve_texture =
|
||||
CreateCurveTexture(line_geometry->GetWidth(), renderer.GetContext());
|
||||
|
||||
SamplerDescriptor sampler_desc;
|
||||
sampler_desc.min_filter = MinMagFilter::kLinear;
|
||||
sampler_desc.mag_filter = MinMagFilter::kLinear;
|
||||
|
||||
FS::BindCurve(
|
||||
pass, curve_texture,
|
||||
renderer.GetContext()->GetSamplerLibrary()->GetSampler(sampler_desc));
|
||||
|
||||
return GeometryResult{
|
||||
.type = PrimitiveType::kTriangleStrip,
|
||||
.vertex_buffer =
|
||||
{
|
||||
.vertex_buffer = vertex_buffer,
|
||||
.vertex_count = count,
|
||||
.index_type = IndexType::kNone,
|
||||
},
|
||||
.transform = entity.GetShaderTransform(pass),
|
||||
};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<LineContents> LineContents::Make(
|
||||
std::unique_ptr<LineGeometry> geometry,
|
||||
Color color) {
|
||||
return std::unique_ptr<LineContents>(
|
||||
new LineContents(std::move(geometry), color));
|
||||
}
|
||||
|
||||
LineContents::LineContents(std::unique_ptr<LineGeometry> geometry, Color color)
|
||||
: geometry_(std::move(geometry)), color_(color) {}
|
||||
|
||||
bool LineContents::Render(const ContentContext& renderer,
|
||||
const Entity& entity,
|
||||
RenderPass& pass) const {
|
||||
auto& host_buffer = renderer.GetTransientsBuffer();
|
||||
|
||||
VS::FrameInfo frame_info;
|
||||
FS::FragInfo frag_info;
|
||||
frag_info.color = color_.Premultiply();
|
||||
|
||||
PipelineBuilderCallback pipeline_callback =
|
||||
[&renderer](ContentContextOptions options) {
|
||||
return renderer.GetLinePipeline(options);
|
||||
};
|
||||
return ColorSourceContents::DrawGeometry<VS>(
|
||||
this, geometry_.get(), renderer, entity, pass, pipeline_callback,
|
||||
frame_info,
|
||||
/*bind_fragment_callback=*/
|
||||
[&frag_info, &host_buffer](RenderPass& pass) {
|
||||
FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));
|
||||
pass.SetCommandLabel("Line");
|
||||
return true;
|
||||
},
|
||||
/*force_stencil=*/false,
|
||||
/*create_geom_callback=*/CreateGeometry);
|
||||
}
|
||||
|
||||
std::optional<Rect> LineContents::GetCoverage(const Entity& entity) const {
|
||||
return geometry_->GetCoverage(entity.GetTransform());
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
34
engine/src/flutter/impeller/entity/contents/line_contents.h
Normal file
34
engine/src/flutter/impeller/entity/contents/line_contents.h
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef FLUTTER_IMPELLER_ENTITY_CONTENTS_LINE_CONTENTS_H_
|
||||
#define FLUTTER_IMPELLER_ENTITY_CONTENTS_LINE_CONTENTS_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "flutter/impeller/entity/contents/contents.h"
|
||||
#include "flutter/impeller/entity/geometry/line_geometry.h"
|
||||
|
||||
namespace impeller {
|
||||
class LineContents : public Contents {
|
||||
public:
|
||||
static std::unique_ptr<LineContents> Make(
|
||||
std::unique_ptr<LineGeometry> geometry,
|
||||
Color color);
|
||||
|
||||
bool Render(const ContentContext& renderer,
|
||||
const Entity& entity,
|
||||
RenderPass& pass) const override;
|
||||
|
||||
std::optional<Rect> GetCoverage(const Entity& entity) const override;
|
||||
|
||||
private:
|
||||
explicit LineContents(std::unique_ptr<LineGeometry> geometry, Color color);
|
||||
|
||||
std::unique_ptr<LineGeometry> geometry_;
|
||||
Color color_;
|
||||
};
|
||||
} // namespace impeller
|
||||
|
||||
#endif // FLUTTER_IMPELLER_ENTITY_CONTENTS_LINE_CONTENTS_H_
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "impeller/entity/contents/line_contents.h"
|
||||
#include "third_party/googletest/googletest/include/gtest/gtest.h"
|
||||
|
||||
namespace impeller {
|
||||
namespace testing {
|
||||
|
||||
TEST(LineContents, Create) {
|
||||
Path path;
|
||||
Scalar width = 5.0f;
|
||||
auto geometry = std::make_unique<LineGeometry>(
|
||||
/*p0=*/Point{0, 0}, //
|
||||
/*p1=*/Point{100, 100}, //
|
||||
/*width=*/width, //
|
||||
/*cap=*/Cap::kSquare);
|
||||
std::unique_ptr<LineContents> contents =
|
||||
LineContents::Make(std::move(geometry), Color(1.f, 0.f, 0.f, 1.f));
|
||||
EXPECT_TRUE(contents);
|
||||
Entity entity;
|
||||
std::optional<Rect> coverage = contents->GetCoverage(entity);
|
||||
EXPECT_TRUE(coverage.has_value());
|
||||
if (coverage.has_value()) {
|
||||
Scalar lip = sqrt((width * width) / 2.f);
|
||||
EXPECT_EQ(*coverage,
|
||||
Rect::MakeXYWH(-lip, -lip, 100 + 2 * lip, 100 + 2 * lip));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace impeller
|
||||
@@ -119,7 +119,6 @@ class Geometry {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
protected:
|
||||
static GeometryResult ComputePositionGeometry(
|
||||
const ContentContext& renderer,
|
||||
const Tessellator::VertexGenerator& generator,
|
||||
|
||||
@@ -26,13 +26,16 @@ Scalar LineGeometry::ComputePixelHalfWidth(const Matrix& transform,
|
||||
}
|
||||
|
||||
Vector2 LineGeometry::ComputeAlongVector(const Matrix& transform,
|
||||
bool allow_zero_length) const {
|
||||
Scalar stroke_half_width = ComputePixelHalfWidth(transform, width_);
|
||||
bool allow_zero_length,
|
||||
Point p0,
|
||||
Point p1,
|
||||
Scalar width) {
|
||||
Scalar stroke_half_width = ComputePixelHalfWidth(transform, width);
|
||||
if (stroke_half_width < kEhCloseEnough) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto along = p1_ - p0_;
|
||||
auto along = p1 - p0;
|
||||
Scalar length = along.GetLength();
|
||||
if (length < kEhCloseEnough) {
|
||||
if (!allow_zero_length) {
|
||||
@@ -47,17 +50,20 @@ Vector2 LineGeometry::ComputeAlongVector(const Matrix& transform,
|
||||
|
||||
bool LineGeometry::ComputeCorners(Point corners[4],
|
||||
const Matrix& transform,
|
||||
bool extend_endpoints) const {
|
||||
auto along = ComputeAlongVector(transform, extend_endpoints);
|
||||
bool extend_endpoints,
|
||||
Point p0,
|
||||
Point p1,
|
||||
Scalar width) {
|
||||
auto along = ComputeAlongVector(transform, extend_endpoints, p0, p1, width);
|
||||
if (along.IsZero()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto across = Vector2(along.y, -along.x);
|
||||
corners[0] = p0_ - across;
|
||||
corners[1] = p1_ - across;
|
||||
corners[2] = p0_ + across;
|
||||
corners[3] = p1_ + across;
|
||||
corners[0] = p0 - across;
|
||||
corners[1] = p1 - across;
|
||||
corners[2] = p0 + across;
|
||||
corners[3] = p1 + across;
|
||||
if (extend_endpoints) {
|
||||
corners[0] -= along;
|
||||
corners[1] += along;
|
||||
@@ -86,7 +92,8 @@ GeometryResult LineGeometry::GetPositionBuffer(const ContentContext& renderer,
|
||||
}
|
||||
|
||||
Point corners[4];
|
||||
if (!ComputeCorners(corners, transform, cap_ == Cap::kSquare)) {
|
||||
if (!ComputeCorners(corners, transform, cap_ == Cap::kSquare, p0_, p1_,
|
||||
width_)) {
|
||||
return kEmptyResult;
|
||||
}
|
||||
|
||||
@@ -118,7 +125,8 @@ GeometryResult LineGeometry::GetPositionBuffer(const ContentContext& renderer,
|
||||
std::optional<Rect> LineGeometry::GetCoverage(const Matrix& transform) const {
|
||||
Point corners[4];
|
||||
// Note: MSAA boolean doesn't matter for coverage computation.
|
||||
if (!ComputeCorners(corners, transform, cap_ != Cap::kButt)) {
|
||||
if (!ComputeCorners(corners, transform, cap_ != Cap::kButt, p0_, p1_,
|
||||
width_)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,20 @@ class LineGeometry final : public Geometry {
|
||||
|
||||
Scalar ComputeAlphaCoverage(const Matrix& transform) const override;
|
||||
|
||||
private:
|
||||
// |Geometry|
|
||||
std::optional<Rect> GetCoverage(const Matrix& transform) const override;
|
||||
|
||||
Point GetP0() const { return p0_; }
|
||||
Point GetP1() const { return p1_; }
|
||||
Scalar GetWidth() const { return width_; }
|
||||
Cap GetCap() const { return cap_; }
|
||||
|
||||
static Vector2 ComputeAlongVector(const Matrix& transform,
|
||||
bool allow_zero_length,
|
||||
Point p0,
|
||||
Point p1,
|
||||
Scalar width);
|
||||
|
||||
// Computes the 4 corners of a rectangle that defines the line and
|
||||
// possibly extended endpoints which will be rendered under the given
|
||||
// transform, and returns true if such a rectangle is defined.
|
||||
@@ -40,21 +53,19 @@ class LineGeometry final : public Geometry {
|
||||
// if the calling code is planning to draw the round caps on the ends.
|
||||
//
|
||||
// @return true if the transform and width were not degenerate
|
||||
bool ComputeCorners(Point corners[4],
|
||||
const Matrix& transform,
|
||||
bool extend_endpoints) const;
|
||||
|
||||
Vector2 ComputeAlongVector(const Matrix& transform,
|
||||
bool allow_zero_length) const;
|
||||
static bool ComputeCorners(Point corners[4],
|
||||
const Matrix& transform,
|
||||
bool extend_endpoints,
|
||||
Point p0,
|
||||
Point p1,
|
||||
Scalar width);
|
||||
|
||||
private:
|
||||
// |Geometry|
|
||||
GeometryResult GetPositionBuffer(const ContentContext& renderer,
|
||||
const Entity& entity,
|
||||
RenderPass& pass) const override;
|
||||
|
||||
// |Geometry|
|
||||
std::optional<Rect> GetCoverage(const Matrix& transform) const override;
|
||||
|
||||
Point p0_;
|
||||
Point p1_;
|
||||
Scalar width_;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include "impeller/entity/entity_pass_target.h"
|
||||
#include "impeller/renderer/command_buffer.h"
|
||||
#include "impeller/renderer/render_pass.h"
|
||||
#include "impeller/renderer/texture_mipmap.h"
|
||||
#include "impeller/renderer/texture_util.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
|
||||
44
engine/src/flutter/impeller/entity/shaders/line.frag
Normal file
44
engine/src/flutter/impeller/entity/shaders/line.frag
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
precision mediump float;
|
||||
|
||||
#include <impeller/types.glsl>
|
||||
|
||||
uniform FragInfo {
|
||||
vec4 color;
|
||||
}
|
||||
frag_info;
|
||||
|
||||
uniform sampler2D curve;
|
||||
|
||||
highp in vec2 v_position;
|
||||
// These should be `flat` but that doesn't work in our glsl compiler. It
|
||||
// shouldn't make any visual difference.
|
||||
highp in vec3 v_e0;
|
||||
highp in vec3 v_e1;
|
||||
highp in vec3 v_e2;
|
||||
highp in vec3 v_e3;
|
||||
|
||||
out vec4 frag_color;
|
||||
|
||||
float lookup(float x) {
|
||||
return texture(curve, vec2(x, 0)).r;
|
||||
}
|
||||
|
||||
float CalculateLine() {
|
||||
vec3 pos = vec3(v_position.xy, 1.0);
|
||||
vec4 d = vec4(dot(pos, v_e0), dot(pos, v_e1), dot(pos, v_e2), dot(pos, v_e3));
|
||||
|
||||
if (any(lessThan(d, vec4(0.0)))) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return lookup(min(d.x, d.z)) * lookup(min(d.y, d.w));
|
||||
}
|
||||
|
||||
void main() {
|
||||
float line = CalculateLine();
|
||||
frag_color = vec4(frag_info.color.xyz, line);
|
||||
}
|
||||
32
engine/src/flutter/impeller/entity/shaders/line.vert
Normal file
32
engine/src/flutter/impeller/entity/shaders/line.vert
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <impeller/types.glsl>
|
||||
|
||||
uniform FrameInfo {
|
||||
mat4 mvp;
|
||||
}
|
||||
frame_info;
|
||||
|
||||
in vec2 position;
|
||||
|
||||
in vec3 e0;
|
||||
in vec3 e1;
|
||||
in vec3 e2;
|
||||
in vec3 e3;
|
||||
|
||||
out vec2 v_position;
|
||||
out vec3 v_e0;
|
||||
out vec3 v_e1;
|
||||
out vec3 v_e2;
|
||||
out vec3 v_e3;
|
||||
|
||||
void main() {
|
||||
gl_Position = frame_info.mvp * vec4(position, 0.0, 1.0);
|
||||
v_position = position;
|
||||
v_e0 = e0;
|
||||
v_e1 = e1;
|
||||
v_e2 = e2;
|
||||
v_e3 = e3;
|
||||
}
|
||||
@@ -155,7 +155,11 @@ void GoldenPlaygroundTest::SetUp() {
|
||||
setenv("VK_ICD_FILENAMES", icd_path.c_str(), 1);
|
||||
|
||||
std::string test_name = GetTestName();
|
||||
bool enable_wide_gamut = test_name.find("WideGamut_") != std::string::npos;
|
||||
PlaygroundSwitches switches;
|
||||
switches.enable_wide_gamut =
|
||||
test_name.find("WideGamut_") != std::string::npos;
|
||||
switches.flags.antialiased_lines =
|
||||
test_name.find("ExperimentAntialiasLines_") != std::string::npos;
|
||||
switch (GetParam()) {
|
||||
case PlaygroundBackend::kMetal:
|
||||
if (!DoesSupportWideGamutTests()) {
|
||||
@@ -163,12 +167,16 @@ void GoldenPlaygroundTest::SetUp() {
|
||||
<< "This metal device doesn't support wide gamut golden tests.";
|
||||
}
|
||||
pimpl_->screenshotter =
|
||||
std::make_unique<testing::MetalScreenshotter>(enable_wide_gamut);
|
||||
std::make_unique<testing::MetalScreenshotter>(switches);
|
||||
break;
|
||||
case PlaygroundBackend::kVulkan: {
|
||||
if (enable_wide_gamut) {
|
||||
if (switches.enable_wide_gamut) {
|
||||
GTEST_SKIP() << "Vulkan doesn't support wide gamut golden tests.";
|
||||
}
|
||||
if (switches.flags.antialiased_lines) {
|
||||
GTEST_SKIP()
|
||||
<< "Vulkan doesn't support antialiased lines golden tests.";
|
||||
}
|
||||
const std::unique_ptr<PlaygroundImpl>& playground =
|
||||
GetSharedVulkanPlayground(/*enable_validations=*/true);
|
||||
pimpl_->screenshotter =
|
||||
@@ -176,9 +184,13 @@ void GoldenPlaygroundTest::SetUp() {
|
||||
break;
|
||||
}
|
||||
case PlaygroundBackend::kOpenGLES: {
|
||||
if (enable_wide_gamut) {
|
||||
if (switches.enable_wide_gamut) {
|
||||
GTEST_SKIP() << "OpenGLES doesn't support wide gamut golden tests.";
|
||||
}
|
||||
if (switches.flags.antialiased_lines) {
|
||||
GTEST_SKIP()
|
||||
<< "OpenGLES doesn't support antialiased lines golden tests.";
|
||||
}
|
||||
FML_CHECK(::glfwInit() == GLFW_TRUE);
|
||||
PlaygroundSwitches playground_switches;
|
||||
playground_switches.use_angle = true;
|
||||
|
||||
@@ -49,12 +49,17 @@ bool SaveScreenshot(std::unique_ptr<Screenshot> screenshot) {
|
||||
WorkingDirectory::Instance()->GetFilenamePath(filename));
|
||||
}
|
||||
|
||||
PlaygroundSwitches GetPlaygroundSwitches() {
|
||||
PlaygroundSwitches switches;
|
||||
switches.enable_wide_gamut = false;
|
||||
return switches;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
class GoldenTests : public ::testing::Test {
|
||||
public:
|
||||
GoldenTests()
|
||||
: screenshotter_(new MetalScreenshotter(/*enable_wide_gamut=*/false)) {}
|
||||
: screenshotter_(new MetalScreenshotter(GetPlaygroundSwitches())) {}
|
||||
|
||||
MetalScreenshotter& Screenshotter() { return *screenshotter_; }
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace testing {
|
||||
/// playground backend.
|
||||
class MetalScreenshotter : public Screenshotter {
|
||||
public:
|
||||
explicit MetalScreenshotter(bool enable_wide_gamut);
|
||||
explicit MetalScreenshotter(const PlaygroundSwitches& switches);
|
||||
|
||||
std::unique_ptr<Screenshot> MakeScreenshot(
|
||||
AiksContext& aiks_context,
|
||||
|
||||
@@ -13,10 +13,8 @@
|
||||
namespace impeller {
|
||||
namespace testing {
|
||||
|
||||
MetalScreenshotter::MetalScreenshotter(bool enable_wide_gamut) {
|
||||
MetalScreenshotter::MetalScreenshotter(const PlaygroundSwitches& switches) {
|
||||
FML_CHECK(::glfwInit() == GLFW_TRUE);
|
||||
PlaygroundSwitches switches;
|
||||
switches.enable_wide_gamut = enable_wide_gamut;
|
||||
playground_ = PlaygroundImpl::Create(PlaygroundBackend::kMetal, switches);
|
||||
}
|
||||
|
||||
|
||||
@@ -133,8 +133,9 @@ std::shared_ptr<Context> PlaygroundImplGLES::GetContext() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto context = ContextGLES::Create(
|
||||
Flags{}, std::move(gl), ShaderLibraryMappingsForPlayground(), true);
|
||||
auto context =
|
||||
ContextGLES::Create(switches_.flags, std::move(gl),
|
||||
ShaderLibraryMappingsForPlayground(), true);
|
||||
if (!context) {
|
||||
FML_LOG(ERROR) << "Could not create context.";
|
||||
return nullptr;
|
||||
|
||||
@@ -77,7 +77,7 @@ PlaygroundImplMTL::PlaygroundImplMTL(PlaygroundSwitches switches)
|
||||
}
|
||||
|
||||
auto context = ContextMTL::Create(
|
||||
impeller::Flags{}, ShaderLibraryMappingsForPlayground(),
|
||||
switches.flags, ShaderLibraryMappingsForPlayground(),
|
||||
is_gpu_disabled_sync_switch_, "Playground Library",
|
||||
switches.enable_wide_gamut
|
||||
? std::optional<PixelFormat>(PixelFormat::kB10G10R10A10XR)
|
||||
|
||||
@@ -95,8 +95,9 @@ PlaygroundImplVK::PlaygroundImplVK(PlaygroundSwitches switches)
|
||||
context_settings.enable_validation = switches_.enable_vulkan_validation;
|
||||
context_settings.fatal_missing_validations =
|
||||
switches_.enable_vulkan_validation;
|
||||
context_settings.flags = switches_.flags;
|
||||
|
||||
auto context_vk = ContextVK::Create(Flags{}, std::move(context_settings));
|
||||
auto context_vk = ContextVK::Create(std::move(context_settings));
|
||||
if (!context_vk || !context_vk->IsValid()) {
|
||||
VALIDATION_LOG << "Could not create Vulkan context in the playground.";
|
||||
return;
|
||||
|
||||
@@ -65,6 +65,9 @@ void PlaygroundTest::SetUp() {
|
||||
return;
|
||||
}
|
||||
|
||||
switches.flags.antialiased_lines =
|
||||
test_name.find("ExperimentAntialiasLines/") != std::string::npos;
|
||||
|
||||
SetupContext(GetParam(), switches);
|
||||
SetupWindow();
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <optional>
|
||||
|
||||
#include "flutter/fml/command_line.h"
|
||||
#include "impeller/base/flags.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
@@ -34,6 +35,8 @@ struct PlaygroundSwitches {
|
||||
|
||||
bool enable_wide_gamut = false;
|
||||
|
||||
Flags flags;
|
||||
|
||||
PlaygroundSwitches();
|
||||
|
||||
explicit PlaygroundSwitches(const fml::CommandLine& args);
|
||||
|
||||
@@ -73,8 +73,8 @@ impeller_component("renderer") {
|
||||
"snapshot.h",
|
||||
"surface.cc",
|
||||
"surface.h",
|
||||
"texture_mipmap.cc",
|
||||
"texture_mipmap.h",
|
||||
"texture_util.cc",
|
||||
"texture_util.h",
|
||||
"vertex_buffer_builder.cc",
|
||||
"vertex_buffer_builder.h",
|
||||
"vertex_descriptor.cc",
|
||||
|
||||
@@ -34,7 +34,7 @@ std::shared_ptr<Context> CreateContext() {
|
||||
settings.enable_gpu_tracing = false;
|
||||
settings.enable_surface_control = false;
|
||||
|
||||
return ContextVK::Create(impeller::Flags{}, std::move(settings));
|
||||
return ContextVK::Create(std::move(settings));
|
||||
}
|
||||
|
||||
TEST(AndroidVulkanTest, CanImportRGBA) {
|
||||
|
||||
@@ -102,9 +102,8 @@ static std::optional<QueueIndexVK> PickQueue(const vk::PhysicalDevice& device,
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::shared_ptr<ContextVK> ContextVK::Create(const Flags& flags,
|
||||
Settings settings) {
|
||||
auto context = std::shared_ptr<ContextVK>(new ContextVK(flags));
|
||||
std::shared_ptr<ContextVK> ContextVK::Create(Settings settings) {
|
||||
auto context = std::shared_ptr<ContextVK>(new ContextVK(settings.flags));
|
||||
context->Setup(std::move(settings));
|
||||
if (!context->IsValid()) {
|
||||
return nullptr;
|
||||
|
||||
@@ -85,6 +85,7 @@ class ContextVK final : public Context,
|
||||
bool enable_surface_control = false;
|
||||
/// If validations are requested but cannot be enabled, log a fatal error.
|
||||
bool fatal_missing_validations = false;
|
||||
Flags flags;
|
||||
|
||||
std::optional<EmbedderData> embedder_data;
|
||||
|
||||
@@ -98,8 +99,7 @@ class ContextVK final : public Context,
|
||||
/// Visible for testing.
|
||||
static size_t ChooseThreadCountForWorkers(size_t hardware_concurrency);
|
||||
|
||||
static std::shared_ptr<ContextVK> Create(const Flags& flags,
|
||||
Settings settings);
|
||||
static std::shared_ptr<ContextVK> Create(Settings settings);
|
||||
|
||||
uint64_t GetHash() const { return hash_; }
|
||||
|
||||
|
||||
@@ -955,8 +955,7 @@ std::shared_ptr<ContextVK> MockVulkanContextBuilder::Build() {
|
||||
g_format_properties_callback = format_properties_callback_;
|
||||
g_physical_device_properties_callback = physical_properties_callback_;
|
||||
settings.embedder_data = embedder_data_;
|
||||
std::shared_ptr<ContextVK> result =
|
||||
ContextVK::Create(Flags{}, std::move(settings));
|
||||
std::shared_ptr<ContextVK> result = ContextVK::Create(std::move(settings));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "impeller/renderer/texture_mipmap.h"
|
||||
#include "impeller/renderer/blit_pass.h"
|
||||
#include "impeller/renderer/command_buffer.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
fml::Status AddMipmapGeneration(
|
||||
const std::shared_ptr<CommandBuffer>& command_buffer,
|
||||
const std::shared_ptr<Context>& context,
|
||||
const std::shared_ptr<Texture>& texture) {
|
||||
std::shared_ptr<BlitPass> blit_pass = command_buffer->CreateBlitPass();
|
||||
bool success = blit_pass->GenerateMipmap(texture);
|
||||
if (!success) {
|
||||
return fml::Status(fml::StatusCode::kUnknown, "");
|
||||
}
|
||||
success = blit_pass->EncodeCommands();
|
||||
if (!success) {
|
||||
return fml::Status(fml::StatusCode::kUnknown, "");
|
||||
}
|
||||
return fml::Status();
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
53
engine/src/flutter/impeller/renderer/texture_util.cc
Normal file
53
engine/src/flutter/impeller/renderer/texture_util.cc
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "impeller/renderer/texture_util.h"
|
||||
#include "impeller/renderer/blit_pass.h"
|
||||
#include "impeller/renderer/command_buffer.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
std::shared_ptr<Texture> CreateTexture(
|
||||
const TextureDescriptor& texture_descriptor,
|
||||
const std::vector<uint8_t>& data,
|
||||
const std::shared_ptr<impeller::Context>& context,
|
||||
std::string_view debug_label) {
|
||||
std::shared_ptr<Texture> texture =
|
||||
context->GetResourceAllocator()->CreateTexture(texture_descriptor);
|
||||
|
||||
auto data_mapping =
|
||||
std::make_shared<fml::NonOwnedMapping>(data.data(), data.size());
|
||||
std::shared_ptr<DeviceBuffer> buffer =
|
||||
context->GetResourceAllocator()->CreateBufferWithCopy(*data_mapping);
|
||||
|
||||
std::shared_ptr<CommandBuffer> cmd_buffer = context->CreateCommandBuffer();
|
||||
std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
|
||||
blit_pass->AddCopy(DeviceBuffer::AsBufferView(std::move(buffer)), texture);
|
||||
|
||||
if (!blit_pass->EncodeCommands() ||
|
||||
!context->GetCommandQueue()->Submit({std::move(cmd_buffer)}).ok()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
texture->SetLabel(debug_label);
|
||||
return texture;
|
||||
}
|
||||
|
||||
fml::Status AddMipmapGeneration(
|
||||
const std::shared_ptr<CommandBuffer>& command_buffer,
|
||||
const std::shared_ptr<Context>& context,
|
||||
const std::shared_ptr<Texture>& texture) {
|
||||
std::shared_ptr<BlitPass> blit_pass = command_buffer->CreateBlitPass();
|
||||
bool success = blit_pass->GenerateMipmap(texture);
|
||||
if (!success) {
|
||||
return fml::Status(fml::StatusCode::kUnknown, "");
|
||||
}
|
||||
success = blit_pass->EncodeCommands();
|
||||
if (!success) {
|
||||
return fml::Status(fml::StatusCode::kUnknown, "");
|
||||
}
|
||||
return fml::Status();
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
@@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef FLUTTER_IMPELLER_RENDERER_TEXTURE_MIPMAP_H_
|
||||
#define FLUTTER_IMPELLER_RENDERER_TEXTURE_MIPMAP_H_
|
||||
#ifndef FLUTTER_IMPELLER_RENDERER_TEXTURE_UTIL_H_
|
||||
#define FLUTTER_IMPELLER_RENDERER_TEXTURE_UTIL_H_
|
||||
|
||||
#include "flutter/fml/status.h"
|
||||
#include "impeller/core/texture.h"
|
||||
@@ -12,6 +12,12 @@
|
||||
|
||||
namespace impeller {
|
||||
|
||||
std::shared_ptr<Texture> CreateTexture(
|
||||
const TextureDescriptor& texture_descriptor,
|
||||
const std::vector<uint8_t>& data,
|
||||
const std::shared_ptr<impeller::Context>& context,
|
||||
std::string_view debug_label);
|
||||
|
||||
/// Adds a blit command to the render pass.
|
||||
[[nodiscard]] fml::Status AddMipmapGeneration(
|
||||
const std::shared_ptr<CommandBuffer>& command_buffer,
|
||||
@@ -20,4 +26,4 @@ namespace impeller {
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
#endif // FLUTTER_IMPELLER_RENDERER_TEXTURE_MIPMAP_H_
|
||||
#endif // FLUTTER_IMPELLER_RENDERER_TEXTURE_UTIL_H_
|
||||
@@ -53,8 +53,9 @@ ScopedObject<Context> ContextVK::Create(const Settings& settings) {
|
||||
impeller_settings.enable_validation = true;
|
||||
sContextVKProcAddressCallback = settings.instance_proc_address_callback;
|
||||
impeller_settings.proc_address_callback = ContextVKGetInstanceProcAddress;
|
||||
auto impeller_context = impeller::ContextVK::Create(
|
||||
impeller::Flags{}, std::move(impeller_settings));
|
||||
impeller_settings.flags = impeller::Flags{};
|
||||
auto impeller_context =
|
||||
impeller::ContextVK::Create(std::move(impeller_settings));
|
||||
sContextVKProcAddressCallback = nullptr;
|
||||
if (!impeller_context) {
|
||||
VALIDATION_LOG << "Could not create Impeller context.";
|
||||
|
||||
@@ -4418,6 +4418,278 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"flutter/impeller/entity/gles/line.frag.gles": {
|
||||
"Mali-G78": {
|
||||
"core": "Mali-G78",
|
||||
"filename": "flutter/impeller/entity/gles/line.frag.gles",
|
||||
"has_side_effects": false,
|
||||
"has_uniform_computation": false,
|
||||
"modifies_coverage": false,
|
||||
"reads_color_buffer": false,
|
||||
"type": "Fragment",
|
||||
"uses_late_zs_test": false,
|
||||
"uses_late_zs_update": false,
|
||||
"variants": {
|
||||
"Main": {
|
||||
"fp16_arithmetic": 6,
|
||||
"has_stack_spilling": false,
|
||||
"performance": {
|
||||
"longest_path_bound_pipelines": [
|
||||
"varying"
|
||||
],
|
||||
"longest_path_cycles": [
|
||||
0.21875,
|
||||
0.140625,
|
||||
0.21875,
|
||||
0.0,
|
||||
0.0,
|
||||
1.75,
|
||||
0.5
|
||||
],
|
||||
"pipelines": [
|
||||
"arith_total",
|
||||
"arith_fma",
|
||||
"arith_cvt",
|
||||
"arith_sfu",
|
||||
"load_store",
|
||||
"varying",
|
||||
"texture"
|
||||
],
|
||||
"shortest_path_bound_pipelines": [
|
||||
"varying"
|
||||
],
|
||||
"shortest_path_cycles": [
|
||||
0.140625,
|
||||
0.125,
|
||||
0.140625,
|
||||
0.0,
|
||||
0.0,
|
||||
1.75,
|
||||
0.0
|
||||
],
|
||||
"total_bound_pipelines": [
|
||||
"varying"
|
||||
],
|
||||
"total_cycles": [
|
||||
0.21875,
|
||||
0.140625,
|
||||
0.21875,
|
||||
0.0,
|
||||
0.0,
|
||||
1.75,
|
||||
0.5
|
||||
]
|
||||
},
|
||||
"stack_spill_bytes": 0,
|
||||
"thread_occupancy": 100,
|
||||
"uniform_registers_used": 4,
|
||||
"work_registers_used": 24
|
||||
}
|
||||
}
|
||||
},
|
||||
"Mali-T880": {
|
||||
"core": "Mali-T880",
|
||||
"filename": "flutter/impeller/entity/gles/line.frag.gles",
|
||||
"has_uniform_computation": false,
|
||||
"type": "Fragment",
|
||||
"variants": {
|
||||
"Main": {
|
||||
"has_stack_spilling": false,
|
||||
"performance": {
|
||||
"longest_path_bound_pipelines": [
|
||||
"load_store"
|
||||
],
|
||||
"longest_path_cycles": [
|
||||
3.299999952316284,
|
||||
5.0,
|
||||
2.0
|
||||
],
|
||||
"pipelines": [
|
||||
"arithmetic",
|
||||
"load_store",
|
||||
"texture"
|
||||
],
|
||||
"shortest_path_bound_pipelines": [
|
||||
"load_store"
|
||||
],
|
||||
"shortest_path_cycles": [
|
||||
2.309999942779541,
|
||||
5.0,
|
||||
0.0
|
||||
],
|
||||
"total_bound_pipelines": [
|
||||
"load_store"
|
||||
],
|
||||
"total_cycles": [
|
||||
3.6666667461395264,
|
||||
5.0,
|
||||
2.0
|
||||
]
|
||||
},
|
||||
"thread_occupancy": 100,
|
||||
"uniform_registers_used": 1,
|
||||
"work_registers_used": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"flutter/impeller/entity/gles/line.vert.gles": {
|
||||
"Mali-G78": {
|
||||
"core": "Mali-G78",
|
||||
"filename": "flutter/impeller/entity/gles/line.vert.gles",
|
||||
"has_uniform_computation": false,
|
||||
"type": "Vertex",
|
||||
"variants": {
|
||||
"Position": {
|
||||
"fp16_arithmetic": 0,
|
||||
"has_stack_spilling": false,
|
||||
"performance": {
|
||||
"longest_path_bound_pipelines": [
|
||||
"load_store"
|
||||
],
|
||||
"longest_path_cycles": [
|
||||
0.140625,
|
||||
0.140625,
|
||||
0.0,
|
||||
0.0,
|
||||
2.0,
|
||||
0.0
|
||||
],
|
||||
"pipelines": [
|
||||
"arith_total",
|
||||
"arith_fma",
|
||||
"arith_cvt",
|
||||
"arith_sfu",
|
||||
"load_store",
|
||||
"texture"
|
||||
],
|
||||
"shortest_path_bound_pipelines": [
|
||||
"load_store"
|
||||
],
|
||||
"shortest_path_cycles": [
|
||||
0.140625,
|
||||
0.140625,
|
||||
0.0,
|
||||
0.0,
|
||||
2.0,
|
||||
0.0
|
||||
],
|
||||
"total_bound_pipelines": [
|
||||
"load_store"
|
||||
],
|
||||
"total_cycles": [
|
||||
0.140625,
|
||||
0.140625,
|
||||
0.0,
|
||||
0.0,
|
||||
2.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
"stack_spill_bytes": 0,
|
||||
"thread_occupancy": 100,
|
||||
"uniform_registers_used": 20,
|
||||
"work_registers_used": 32
|
||||
},
|
||||
"Varying": {
|
||||
"fp16_arithmetic": null,
|
||||
"has_stack_spilling": false,
|
||||
"performance": {
|
||||
"longest_path_bound_pipelines": [
|
||||
"load_store"
|
||||
],
|
||||
"longest_path_cycles": [
|
||||
0.09375,
|
||||
0.0,
|
||||
0.09375,
|
||||
0.0,
|
||||
10.0,
|
||||
0.0
|
||||
],
|
||||
"pipelines": [
|
||||
"arith_total",
|
||||
"arith_fma",
|
||||
"arith_cvt",
|
||||
"arith_sfu",
|
||||
"load_store",
|
||||
"texture"
|
||||
],
|
||||
"shortest_path_bound_pipelines": [
|
||||
"load_store"
|
||||
],
|
||||
"shortest_path_cycles": [
|
||||
0.09375,
|
||||
0.0,
|
||||
0.09375,
|
||||
0.0,
|
||||
10.0,
|
||||
0.0
|
||||
],
|
||||
"total_bound_pipelines": [
|
||||
"load_store"
|
||||
],
|
||||
"total_cycles": [
|
||||
0.09375,
|
||||
0.0,
|
||||
0.09375,
|
||||
0.0,
|
||||
10.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
"stack_spill_bytes": 0,
|
||||
"thread_occupancy": 100,
|
||||
"uniform_registers_used": 8,
|
||||
"work_registers_used": 19
|
||||
}
|
||||
}
|
||||
},
|
||||
"Mali-T880": {
|
||||
"core": "Mali-T880",
|
||||
"filename": "flutter/impeller/entity/gles/line.vert.gles",
|
||||
"has_uniform_computation": false,
|
||||
"type": "Vertex",
|
||||
"variants": {
|
||||
"Main": {
|
||||
"has_stack_spilling": false,
|
||||
"performance": {
|
||||
"longest_path_bound_pipelines": [
|
||||
"load_store"
|
||||
],
|
||||
"longest_path_cycles": [
|
||||
2.640000104904175,
|
||||
12.0,
|
||||
0.0
|
||||
],
|
||||
"pipelines": [
|
||||
"arithmetic",
|
||||
"load_store",
|
||||
"texture"
|
||||
],
|
||||
"shortest_path_bound_pipelines": [
|
||||
"load_store"
|
||||
],
|
||||
"shortest_path_cycles": [
|
||||
2.640000104904175,
|
||||
12.0,
|
||||
0.0
|
||||
],
|
||||
"total_bound_pipelines": [
|
||||
"load_store"
|
||||
],
|
||||
"total_cycles": [
|
||||
2.6666667461395264,
|
||||
12.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
"thread_occupancy": 100,
|
||||
"uniform_registers_used": 5,
|
||||
"work_registers_used": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"flutter/impeller/entity/gles/linear_gradient_fill.frag.gles": {
|
||||
"Mali-G78": {
|
||||
"core": "Mali-G78",
|
||||
@@ -7966,6 +8238,188 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"flutter/impeller/entity/line.frag.vkspv": {
|
||||
"Mali-G78": {
|
||||
"core": "Mali-G78",
|
||||
"filename": "flutter/impeller/entity/line.frag.vkspv",
|
||||
"has_side_effects": false,
|
||||
"has_uniform_computation": true,
|
||||
"modifies_coverage": false,
|
||||
"reads_color_buffer": false,
|
||||
"type": "Fragment",
|
||||
"uses_late_zs_test": false,
|
||||
"uses_late_zs_update": false,
|
||||
"variants": {
|
||||
"Main": {
|
||||
"fp16_arithmetic": 15,
|
||||
"has_stack_spilling": false,
|
||||
"performance": {
|
||||
"longest_path_bound_pipelines": [
|
||||
"varying"
|
||||
],
|
||||
"longest_path_cycles": [
|
||||
0.1875,
|
||||
0.140625,
|
||||
0.1875,
|
||||
0.1875,
|
||||
0.0,
|
||||
1.75,
|
||||
0.5
|
||||
],
|
||||
"pipelines": [
|
||||
"arith_total",
|
||||
"arith_fma",
|
||||
"arith_cvt",
|
||||
"arith_sfu",
|
||||
"load_store",
|
||||
"varying",
|
||||
"texture"
|
||||
],
|
||||
"shortest_path_bound_pipelines": [
|
||||
"varying"
|
||||
],
|
||||
"shortest_path_cycles": [
|
||||
0.1875,
|
||||
0.125,
|
||||
0.140625,
|
||||
0.1875,
|
||||
0.0,
|
||||
1.75,
|
||||
0.0
|
||||
],
|
||||
"total_bound_pipelines": [
|
||||
"varying"
|
||||
],
|
||||
"total_cycles": [
|
||||
0.1875,
|
||||
0.140625,
|
||||
0.1875,
|
||||
0.1875,
|
||||
0.0,
|
||||
1.75,
|
||||
0.5
|
||||
]
|
||||
},
|
||||
"stack_spill_bytes": 0,
|
||||
"thread_occupancy": 100,
|
||||
"uniform_registers_used": 6,
|
||||
"work_registers_used": 18
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"flutter/impeller/entity/line.vert.vkspv": {
|
||||
"Mali-G78": {
|
||||
"core": "Mali-G78",
|
||||
"filename": "flutter/impeller/entity/line.vert.vkspv",
|
||||
"has_uniform_computation": true,
|
||||
"type": "Vertex",
|
||||
"variants": {
|
||||
"Position": {
|
||||
"fp16_arithmetic": 0,
|
||||
"has_stack_spilling": false,
|
||||
"performance": {
|
||||
"longest_path_bound_pipelines": [
|
||||
"load_store"
|
||||
],
|
||||
"longest_path_cycles": [
|
||||
0.125,
|
||||
0.125,
|
||||
0.0,
|
||||
0.0,
|
||||
2.0,
|
||||
0.0
|
||||
],
|
||||
"pipelines": [
|
||||
"arith_total",
|
||||
"arith_fma",
|
||||
"arith_cvt",
|
||||
"arith_sfu",
|
||||
"load_store",
|
||||
"texture"
|
||||
],
|
||||
"shortest_path_bound_pipelines": [
|
||||
"load_store"
|
||||
],
|
||||
"shortest_path_cycles": [
|
||||
0.125,
|
||||
0.125,
|
||||
0.0,
|
||||
0.0,
|
||||
2.0,
|
||||
0.0
|
||||
],
|
||||
"total_bound_pipelines": [
|
||||
"load_store"
|
||||
],
|
||||
"total_cycles": [
|
||||
0.125,
|
||||
0.125,
|
||||
0.0,
|
||||
0.0,
|
||||
2.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
"stack_spill_bytes": 0,
|
||||
"thread_occupancy": 100,
|
||||
"uniform_registers_used": 28,
|
||||
"work_registers_used": 32
|
||||
},
|
||||
"Varying": {
|
||||
"fp16_arithmetic": null,
|
||||
"has_stack_spilling": false,
|
||||
"performance": {
|
||||
"longest_path_bound_pipelines": [
|
||||
"load_store"
|
||||
],
|
||||
"longest_path_cycles": [
|
||||
0.046875,
|
||||
0.0,
|
||||
0.046875,
|
||||
0.0,
|
||||
10.0,
|
||||
0.0
|
||||
],
|
||||
"pipelines": [
|
||||
"arith_total",
|
||||
"arith_fma",
|
||||
"arith_cvt",
|
||||
"arith_sfu",
|
||||
"load_store",
|
||||
"texture"
|
||||
],
|
||||
"shortest_path_bound_pipelines": [
|
||||
"load_store"
|
||||
],
|
||||
"shortest_path_cycles": [
|
||||
0.046875,
|
||||
0.0,
|
||||
0.046875,
|
||||
0.0,
|
||||
10.0,
|
||||
0.0
|
||||
],
|
||||
"total_bound_pipelines": [
|
||||
"load_store"
|
||||
],
|
||||
"total_cycles": [
|
||||
0.046875,
|
||||
0.0,
|
||||
0.046875,
|
||||
0.0,
|
||||
10.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
"stack_spill_bytes": 0,
|
||||
"thread_occupancy": 100,
|
||||
"uniform_registers_used": 20,
|
||||
"work_registers_used": 22
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"flutter/impeller/entity/linear_gradient_fill.frag.vkspv": {
|
||||
"Mali-G78": {
|
||||
"core": "Mali-G78",
|
||||
|
||||
@@ -40,7 +40,8 @@ ShellTestPlatformViewMetal::ShellTestPlatformViewMetal(
|
||||
id<MTLDevice> device = nil;
|
||||
if (GetSettings().enable_impeller) {
|
||||
impeller_context_ =
|
||||
[[FlutterDarwinContextMetalImpeller alloc] init:is_gpu_disabled_sync_switch];
|
||||
[[FlutterDarwinContextMetalImpeller alloc] init:impeller::Flags {}
|
||||
gpuDisabledSyncSwitch:is_gpu_disabled_sync_switch];
|
||||
FML_CHECK(impeller_context_.context);
|
||||
device = impeller_context_.context->GetMTLDevice();
|
||||
} else {
|
||||
|
||||
@@ -534,6 +534,8 @@ Settings SettingsFromCommandLine(const fml::CommandLine& command_line) {
|
||||
|
||||
settings.impeller_enable_lazy_shader_mode =
|
||||
command_line.HasOption(FlagForSwitch(Switch::ImpellerLazyShaderMode));
|
||||
settings.impeller_antialiased_lines =
|
||||
command_line.HasOption(FlagForSwitch(Switch::ImpellerAntialiasLines));
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
@@ -304,6 +304,9 @@ DEF_SWITCH(ImpellerLazyShaderMode,
|
||||
"impeller-lazy-shader-mode",
|
||||
"Whether to defer initialization of all required PSOs for the "
|
||||
"Impeller backend. Defaults to false.")
|
||||
DEF_SWITCH(ImpellerAntialiasLines,
|
||||
"impeller-antialias-lines",
|
||||
"Experimental flag to test drawing lines with antialiasing.")
|
||||
DEF_SWITCHES_END
|
||||
|
||||
void PrintUsage(const std::string& executable_name);
|
||||
|
||||
@@ -48,12 +48,9 @@ static std::shared_ptr<impeller::Context> CreateImpellerContext(
|
||||
settings.enable_validation = p_settings.enable_validation;
|
||||
settings.enable_gpu_tracing = p_settings.enable_gpu_tracing;
|
||||
settings.enable_surface_control = p_settings.enable_surface_control;
|
||||
settings.flags = p_settings.impeller_flags;
|
||||
|
||||
auto context = impeller::ContextVK::Create(
|
||||
impeller::Flags{
|
||||
.lazy_shader_mode = p_settings.enable_lazy_shader_mode,
|
||||
},
|
||||
std::move(settings));
|
||||
auto context = impeller::ContextVK::Create(std::move(settings));
|
||||
|
||||
if (!p_settings.quiet) {
|
||||
if (context && impeller::CapabilitiesVK::Cast(*context->GetCapabilities())
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#define FLUTTER_SHELL_PLATFORM_ANDROID_CONTEXT_ANDROID_CONTEXT_H_
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "flutter/impeller/base/flags.h"
|
||||
#include "flutter/impeller/renderer/context.h"
|
||||
#include "flutter/shell/platform/android/android_rendering_selector.h"
|
||||
#include "third_party/skia/include/gpu/ganesh/GrDirectContext.h"
|
||||
@@ -25,8 +26,8 @@ class AndroidContext {
|
||||
bool enable_validation = false;
|
||||
bool enable_gpu_tracing = false;
|
||||
bool enable_surface_control = false;
|
||||
bool enable_lazy_shader_mode = false;
|
||||
bool quiet = false;
|
||||
impeller::Flags impeller_flags;
|
||||
};
|
||||
|
||||
AndroidRenderingAPI RenderingApi() const;
|
||||
|
||||
@@ -53,6 +53,8 @@ public class FlutterLoader {
|
||||
"io.flutter.embedding.android.EnableSurfaceControl";
|
||||
private static final String IMPELLER_LAZY_SHADER_MODE =
|
||||
"io.flutter.embedding.android.ImpellerLazyShaderInitialization";
|
||||
private static final String IMPELLER_ANTIALIAS_LINES =
|
||||
"io.flutter.embedding.android.ImpellerAntialiasLines";
|
||||
|
||||
/**
|
||||
* Set whether leave or clean up the VM after the last shell shuts down. It can be set from app's
|
||||
@@ -382,6 +384,9 @@ public class FlutterLoader {
|
||||
if (metaData.getBoolean(IMPELLER_LAZY_SHADER_MODE)) {
|
||||
shellArgs.add("--impeller-lazy-shader-mode");
|
||||
}
|
||||
if (metaData.getBoolean(IMPELLER_ANTIALIAS_LINES)) {
|
||||
shellArgs.add("--impeller-antialias-lines");
|
||||
}
|
||||
}
|
||||
|
||||
final String leakVM = isLeakVM(metaData) ? "true" : "false";
|
||||
|
||||
@@ -53,8 +53,10 @@ AndroidContext::ContextSettings CreateContextSettings(
|
||||
settings.enable_gpu_tracing = p_settings.enable_vulkan_gpu_tracing;
|
||||
settings.enable_validation = p_settings.enable_vulkan_validation;
|
||||
settings.enable_surface_control = p_settings.enable_surface_control;
|
||||
settings.enable_lazy_shader_mode =
|
||||
settings.impeller_flags.lazy_shader_mode =
|
||||
p_settings.impeller_enable_lazy_shader_mode;
|
||||
settings.impeller_flags.antialiased_lines =
|
||||
p_settings.impeller_antialiased_lines;
|
||||
return settings;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@@ -25,7 +25,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
/**
|
||||
* Initializes a FlutterDarwinContextMetalImpeller.
|
||||
*/
|
||||
- (instancetype)init:(const std::shared_ptr<const fml::SyncSwitch>&)is_gpu_disabled_sync_switch;
|
||||
- (instancetype)init:(const impeller::Flags&)flags
|
||||
gpuDisabledSyncSwitch:
|
||||
(const std::shared_ptr<const fml::SyncSwitch>&)is_gpu_disabled_sync_switch;
|
||||
|
||||
/**
|
||||
* Creates an external texture with the specified ID and contents.
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
FLUTTER_ASSERT_ARC
|
||||
|
||||
static std::shared_ptr<impeller::ContextMTL> CreateImpellerContext(
|
||||
const impeller::Flags& flags,
|
||||
const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch) {
|
||||
std::vector<std::shared_ptr<fml::Mapping>> shader_mappings = {
|
||||
std::make_shared<fml::NonOwnedMapping>(impeller_entity_shaders_data,
|
||||
@@ -25,16 +26,18 @@ static std::shared_ptr<impeller::ContextMTL> CreateImpellerContext(
|
||||
std::make_shared<fml::NonOwnedMapping>(impeller_framebuffer_blend_shaders_data,
|
||||
impeller_framebuffer_blend_shaders_length),
|
||||
};
|
||||
return impeller::ContextMTL::Create(impeller::Flags{}, shader_mappings,
|
||||
is_gpu_disabled_sync_switch, "Impeller Library");
|
||||
return impeller::ContextMTL::Create(flags, shader_mappings, is_gpu_disabled_sync_switch,
|
||||
"Impeller Library");
|
||||
}
|
||||
|
||||
@implementation FlutterDarwinContextMetalImpeller
|
||||
|
||||
- (instancetype)init:(const std::shared_ptr<const fml::SyncSwitch>&)is_gpu_disabled_sync_switch {
|
||||
- (instancetype)init:(const impeller::Flags&)flags
|
||||
gpuDisabledSyncSwitch:
|
||||
(const std::shared_ptr<const fml::SyncSwitch>&)is_gpu_disabled_sync_switch {
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
_context = CreateImpellerContext(is_gpu_disabled_sync_switch);
|
||||
_context = CreateImpellerContext(flags, is_gpu_disabled_sync_switch);
|
||||
FML_CHECK(_context) << "Could not create Metal Impeller Context.";
|
||||
id<MTLDevice> device = _context->GetMTLDevice();
|
||||
FML_CHECK(device) << "Could not acquire Metal device.";
|
||||
|
||||
@@ -177,6 +177,9 @@ flutter::Settings FLTDefaultSettingsForBundle(NSBundle* bundle, NSProcessInfo* p
|
||||
settings.enable_wide_gamut = enableWideGamut;
|
||||
#endif
|
||||
|
||||
NSNumber* nsAntialiasLines = [mainBundle objectForInfoDictionaryKey:@"FLTAntialiasLines"];
|
||||
settings.impeller_antialiased_lines = (nsAntialiasLines ? nsAntialiasLines.boolValue : NO);
|
||||
|
||||
settings.warn_on_impeller_opt_out = true;
|
||||
|
||||
NSNumber* enableTraceSystrace = [mainBundle objectForInfoDictionaryKey:@"FLTTraceSystrace"];
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "flutter/common/graphics/gl_context_switch.h"
|
||||
#include "flutter/common/graphics/texture.h"
|
||||
#include "flutter/common/settings.h"
|
||||
#include "flutter/fml/concurrent_message_loop.h"
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "flutter/fml/synchronization/sync_switch.h"
|
||||
@@ -54,7 +55,8 @@ class IOSContext {
|
||||
static std::unique_ptr<IOSContext> Create(
|
||||
IOSRenderingAPI api,
|
||||
IOSRenderingBackend backend,
|
||||
const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch);
|
||||
const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch,
|
||||
const Settings& settings);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Collects the context object. This must happen on the thread on
|
||||
|
||||
@@ -21,7 +21,8 @@ IOSContext::~IOSContext() = default;
|
||||
std::unique_ptr<IOSContext> IOSContext::Create(
|
||||
IOSRenderingAPI api,
|
||||
IOSRenderingBackend backend,
|
||||
const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch) {
|
||||
const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch,
|
||||
const Settings& settings) {
|
||||
switch (api) {
|
||||
case IOSRenderingAPI::kSoftware:
|
||||
FML_LOG(IMPORTANT)
|
||||
@@ -37,7 +38,7 @@ std::unique_ptr<IOSContext> IOSContext::Create(
|
||||
FML_LOG(FATAL) << "Impeller opt-out unavailable.";
|
||||
return nullptr;
|
||||
case IOSRenderingBackend::kImpeller:
|
||||
return std::make_unique<IOSContextMetalImpeller>(is_gpu_disabled_sync_switch);
|
||||
return std::make_unique<IOSContextMetalImpeller>(settings, is_gpu_disabled_sync_switch);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace flutter {
|
||||
class IOSContextMetalImpeller final : public IOSContext {
|
||||
public:
|
||||
explicit IOSContextMetalImpeller(
|
||||
const Settings& settings,
|
||||
const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch);
|
||||
|
||||
~IOSContextMetalImpeller();
|
||||
|
||||
@@ -12,11 +12,20 @@
|
||||
FLUTTER_ASSERT_ARC
|
||||
|
||||
namespace flutter {
|
||||
namespace {
|
||||
impeller::Flags SettingsToFlags(const Settings& settings) {
|
||||
return impeller::Flags{
|
||||
.antialiased_lines = settings.impeller_antialiased_lines,
|
||||
};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
IOSContextMetalImpeller::IOSContextMetalImpeller(
|
||||
const Settings& settings,
|
||||
const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch)
|
||||
: darwin_context_metal_impeller_(
|
||||
[[FlutterDarwinContextMetalImpeller alloc] init:is_gpu_disabled_sync_switch]) {
|
||||
: darwin_context_metal_impeller_([[FlutterDarwinContextMetalImpeller alloc]
|
||||
init:SettingsToFlags(settings)
|
||||
gpuDisabledSyncSwitch:is_gpu_disabled_sync_switch]) {
|
||||
if (darwin_context_metal_impeller_.context) {
|
||||
aiks_context_ = std::make_shared<impeller::AiksContext>(
|
||||
darwin_context_metal_impeller_.context, impeller::TypographerContextSkia::Make());
|
||||
|
||||
@@ -64,7 +64,8 @@ PlatformViewIOS::PlatformViewIOS(
|
||||
delegate.OnPlatformViewGetSettings().enable_impeller
|
||||
? IOSRenderingBackend::kImpeller
|
||||
: IOSRenderingBackend::kSkia,
|
||||
is_gpu_disabled_sync_switch),
|
||||
is_gpu_disabled_sync_switch,
|
||||
delegate.OnPlatformViewGetSettings()),
|
||||
platform_views_controller,
|
||||
task_runners) {}
|
||||
|
||||
|
||||
@@ -71,8 +71,7 @@ EmbedderSurfaceVulkanImpeller::EmbedderSurfaceVulkanImpeller(
|
||||
}
|
||||
settings.embedder_data = data;
|
||||
|
||||
context_ =
|
||||
impeller::ContextVK::Create(impeller::Flags{}, std::move(settings));
|
||||
context_ = impeller::ContextVK::Create(std::move(settings));
|
||||
if (!context_) {
|
||||
FML_LOG(ERROR) << "Failed to initialize Vulkan Context.";
|
||||
return;
|
||||
|
||||
@@ -74,11 +74,11 @@ bool ImpellerVulkanContextHolder::Initialize(bool enable_validation) {
|
||||
context_settings.shader_libraries_data = ShaderLibraryMappings();
|
||||
context_settings.cache_directory = fml::paths::GetCachesDirectory();
|
||||
context_settings.enable_validation = enable_validation;
|
||||
// Enable lazy shader mode for faster test execution as most tests
|
||||
// will never render anything at all.
|
||||
context_settings.flags.lazy_shader_mode = true;
|
||||
|
||||
context = impeller::ContextVK::Create(
|
||||
// Enable lazy shader mode for faster test execution as most tests
|
||||
// will never render anything at all.
|
||||
impeller::Flags{.lazy_shader_mode = true}, std::move(context_settings));
|
||||
context = impeller::ContextVK::Create(std::move(context_settings));
|
||||
if (!context || !context->IsValid()) {
|
||||
VALIDATION_LOG << "Could not create Vulkan context.";
|
||||
return false;
|
||||
|
||||
@@ -895,6 +895,7 @@ impeller_Play_AiksTest_SetContentsWithRegion_Vulkan.png
|
||||
impeller_Play_AiksTest_SiblingSaveLayerBoundsAreRespected_Metal.png
|
||||
impeller_Play_AiksTest_SiblingSaveLayerBoundsAreRespected_OpenGLES.png
|
||||
impeller_Play_AiksTest_SiblingSaveLayerBoundsAreRespected_Vulkan.png
|
||||
impeller_Play_AiksTest_SimpleExperimentAntialiasLines_Metal.png
|
||||
impeller_Play_AiksTest_SolidColorCircleMaskBlurTinySigma_Metal.png
|
||||
impeller_Play_AiksTest_SolidColorCircleMaskBlurTinySigma_OpenGLES.png
|
||||
impeller_Play_AiksTest_SolidColorCircleMaskBlurTinySigma_Vulkan.png
|
||||
|
||||
Reference in New Issue
Block a user