Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit b923707

Browse files
[Impeller] remove solid stroke contents and allow strokes/vertices to use color sources (#36896)
1 parent e27e196 commit b923707

15 files changed

+250
-190
lines changed

ci/licenses_golden/licenses_flutter

-2
Original file line numberDiff line numberDiff line change
@@ -1218,8 +1218,6 @@ FILE: ../../../flutter/impeller/entity/contents/runtime_effect_contents.cc
12181218
FILE: ../../../flutter/impeller/entity/contents/runtime_effect_contents.h
12191219
FILE: ../../../flutter/impeller/entity/contents/solid_color_contents.cc
12201220
FILE: ../../../flutter/impeller/entity/contents/solid_color_contents.h
1221-
FILE: ../../../flutter/impeller/entity/contents/solid_stroke_contents.cc
1222-
FILE: ../../../flutter/impeller/entity/contents/solid_stroke_contents.h
12231221
FILE: ../../../flutter/impeller/entity/contents/sweep_gradient_contents.cc
12241222
FILE: ../../../flutter/impeller/entity/contents/sweep_gradient_contents.h
12251223
FILE: ../../../flutter/impeller/entity/contents/text_contents.cc

impeller/aiks/aiks_unittests.cc

+95
Original file line numberDiff line numberDiff line change
@@ -1497,6 +1497,101 @@ TEST_P(AiksTest, SolidStrokesRenderCorrectly) {
14971497
ASSERT_TRUE(OpenPlaygroundHere(callback));
14981498
}
14991499

1500+
TEST_P(AiksTest, GradientStrokesRenderCorrectly) {
1501+
// Compare with https://fiddle.skia.org/c/027392122bec8ac2b5d5de00a4b9bbe2
1502+
bool first_frame = true;
1503+
auto callback = [&](AiksContext& renderer, RenderTarget& render_target) {
1504+
if (first_frame) {
1505+
first_frame = false;
1506+
ImGui::SetNextWindowSize({480, 100});
1507+
ImGui::SetNextWindowPos({100, 550});
1508+
}
1509+
1510+
static float scale = 3;
1511+
static bool add_circle_clip = true;
1512+
const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"};
1513+
const Entity::TileMode tile_modes[] = {
1514+
Entity::TileMode::kClamp, Entity::TileMode::kRepeat,
1515+
Entity::TileMode::kMirror, Entity::TileMode::kDecal};
1516+
static int selected_tile_mode = 0;
1517+
static float alpha = 1;
1518+
1519+
ImGui::Begin("Controls");
1520+
ImGui::SliderFloat("Scale", &scale, 0, 6);
1521+
ImGui::Checkbox("Circle clip", &add_circle_clip);
1522+
ImGui::SliderFloat("Alpha", &alpha, 0, 1);
1523+
ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names,
1524+
sizeof(tile_mode_names) / sizeof(char*));
1525+
ImGui::End();
1526+
1527+
Canvas canvas;
1528+
canvas.Scale(GetContentScale());
1529+
Paint paint;
1530+
paint.color = Color::White();
1531+
canvas.DrawPaint(paint);
1532+
1533+
paint.style = Paint::Style::kStroke;
1534+
paint.color = Color(1.0, 1.0, 1.0, alpha);
1535+
paint.stroke_width = 10;
1536+
auto tile_mode = tile_modes[selected_tile_mode];
1537+
paint.color_source = [tile_mode]() {
1538+
std::vector<Color> colors = {Color{0.9568, 0.2627, 0.2118, 1.0},
1539+
Color{0.1294, 0.5882, 0.9529, 1.0}};
1540+
std::vector<Scalar> stops = {0.0, 1.0};
1541+
Matrix matrix = {
1542+
1, 0, 0, 0, //
1543+
0, 1, 0, 0, //
1544+
0, 0, 1, 0, //
1545+
0, 0, 0, 1 //
1546+
};
1547+
auto contents = std::make_shared<LinearGradientContents>();
1548+
contents->SetEndPoints({0, 0}, {50, 50});
1549+
contents->SetColors(std::move(colors));
1550+
contents->SetStops(std::move(stops));
1551+
contents->SetTileMode(tile_mode);
1552+
contents->SetMatrix(matrix);
1553+
return contents;
1554+
};
1555+
1556+
Path path = PathBuilder{}
1557+
.MoveTo({20, 20})
1558+
.QuadraticCurveTo({60, 20}, {60, 60})
1559+
.Close()
1560+
.MoveTo({60, 20})
1561+
.QuadraticCurveTo({60, 60}, {20, 60})
1562+
.TakePath();
1563+
1564+
canvas.Scale(Vector2(scale, scale));
1565+
1566+
if (add_circle_clip) {
1567+
auto [handle_a, handle_b] = IMPELLER_PLAYGROUND_LINE(
1568+
Point(60, 300), Point(600, 300), 20, Color::Red(), Color::Red());
1569+
1570+
auto screen_to_canvas = canvas.GetCurrentTransformation().Invert();
1571+
Point point_a = screen_to_canvas * handle_a * GetContentScale();
1572+
Point point_b = screen_to_canvas * handle_b * GetContentScale();
1573+
1574+
Point middle = (point_a + point_b) / 2;
1575+
auto radius = point_a.GetDistance(middle);
1576+
canvas.ClipPath(PathBuilder{}.AddCircle(middle, radius).TakePath());
1577+
}
1578+
1579+
for (auto join : {Join::kBevel, Join::kRound, Join::kMiter}) {
1580+
paint.stroke_join = join;
1581+
for (auto cap : {Cap::kButt, Cap::kSquare, Cap::kRound}) {
1582+
paint.stroke_cap = cap;
1583+
canvas.DrawPath(path, paint);
1584+
canvas.Translate({80, 0});
1585+
}
1586+
canvas.Translate({-240, 60});
1587+
}
1588+
1589+
return renderer.Render(canvas.EndRecordingAsPicture(), render_target);
1590+
};
1591+
1592+
ASSERT_TRUE(OpenPlaygroundHere(callback));
1593+
}
1594+
15001595
TEST_P(AiksTest, CoverageOriginShouldBeAccountedForInSubpasses) {
15011596
auto callback = [&](AiksContext& renderer, RenderTarget& render_target) {
15021597
Canvas canvas;

impeller/aiks/canvas.cc

+16-6
Original file line numberDiff line numberDiff line change
@@ -355,16 +355,26 @@ void Canvas::DrawTextFrame(TextFrame text_frame, Point position, Paint paint) {
355355
void Canvas::DrawVertices(Vertices vertices,
356356
BlendMode blend_mode,
357357
Paint paint) {
358-
std::shared_ptr<VerticesContents> contents =
359-
std::make_shared<VerticesContents>();
360-
contents->SetColor(paint.color);
361-
contents->SetBlendMode(blend_mode);
362-
contents->SetGeometry(Geometry::MakeVertices(std::move(vertices)));
358+
auto geometry = Geometry::MakeVertices(std::move(vertices));
359+
363360
Entity entity;
364361
entity.SetTransformation(GetCurrentTransformation());
365362
entity.SetStencilDepth(GetStencilDepth());
366363
entity.SetBlendMode(paint.blend_mode);
367-
entity.SetContents(paint.WithFilters(std::move(contents), true));
364+
365+
if (paint.color_source.has_value()) {
366+
auto& source = paint.color_source.value();
367+
auto contents = source();
368+
contents->SetGeometry(std::move(geometry));
369+
contents->SetAlpha(paint.color.alpha);
370+
entity.SetContents(paint.WithFilters(std::move(contents), true));
371+
} else {
372+
std::shared_ptr<VerticesContents> contents =
373+
std::make_shared<VerticesContents>();
374+
contents->SetColor(paint.color);
375+
contents->SetBlendMode(blend_mode);
376+
entity.SetContents(paint.WithFilters(std::move(contents), true));
377+
}
368378

369379
GetCurrentPass().AddEntity(std::move(entity));
370380
}

impeller/aiks/paint.cc

+19-23
Original file line numberDiff line numberDiff line change
@@ -4,41 +4,37 @@
44

55
#include "impeller/aiks/paint.h"
66
#include "impeller/entity/contents/solid_color_contents.h"
7-
#include "impeller/entity/contents/solid_stroke_contents.h"
87
#include "impeller/entity/geometry.h"
98

109
namespace impeller {
1110

1211
std::shared_ptr<Contents> Paint::CreateContentsForEntity(Path path,
1312
bool cover) const {
13+
std::unique_ptr<Geometry> geometry;
14+
switch (style) {
15+
case Style::kFill:
16+
geometry = cover ? Geometry::MakeCover()
17+
: Geometry::MakeFillPath(std::move(path));
18+
break;
19+
case Style::kStroke:
20+
geometry = cover ? Geometry::MakeCover()
21+
: Geometry::MakeStrokePath(std::move(path), stroke_width,
22+
stroke_miter, stroke_cap,
23+
stroke_join);
24+
break;
25+
}
26+
1427
if (color_source.has_value()) {
1528
auto& source = color_source.value();
1629
auto contents = source();
17-
contents->SetGeometry(cover ? Geometry::MakeCover()
18-
: Geometry::MakeFillPath(std::move(path)));
30+
contents->SetGeometry(std::move(geometry));
1931
contents->SetAlpha(color.alpha);
2032
return contents;
2133
}
22-
23-
switch (style) {
24-
case Style::kFill: {
25-
auto solid_color = std::make_shared<SolidColorContents>();
26-
solid_color->SetGeometry(cover ? Geometry::MakeCover()
27-
: Geometry::MakeFillPath(std::move(path)));
28-
solid_color->SetColor(color);
29-
return solid_color;
30-
}
31-
case Style::kStroke: {
32-
auto solid_stroke = std::make_shared<SolidStrokeContents>();
33-
solid_stroke->SetGeometry(
34-
Geometry::MakeStrokePath(std::move(path), stroke_width, stroke_miter,
35-
stroke_cap, stroke_join));
36-
solid_stroke->SetColor(color);
37-
return solid_stroke;
38-
}
39-
}
40-
41-
return nullptr;
34+
auto solid_color = std::make_shared<SolidColorContents>();
35+
solid_color->SetGeometry(std::move(geometry));
36+
solid_color->SetColor(color);
37+
return solid_color;
4238
}
4339

4440
std::shared_ptr<Contents> Paint::WithFilters(

impeller/aiks/paint.h

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
#include "impeller/entity/contents/filters/filter_contents.h"
1313
#include "impeller/entity/contents/linear_gradient_contents.h"
1414
#include "impeller/entity/contents/radial_gradient_contents.h"
15-
#include "impeller/entity/contents/solid_stroke_contents.h"
1615
#include "impeller/entity/contents/sweep_gradient_contents.h"
1716
#include "impeller/entity/entity.h"
1817
#include "impeller/entity/geometry.h"

impeller/display_list/display_list_dispatcher.cc

-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
#include "impeller/entity/contents/linear_gradient_contents.h"
2626
#include "impeller/entity/contents/radial_gradient_contents.h"
2727
#include "impeller/entity/contents/runtime_effect_contents.h"
28-
#include "impeller/entity/contents/solid_stroke_contents.h"
2928
#include "impeller/entity/contents/sweep_gradient_contents.h"
3029
#include "impeller/entity/contents/tiled_texture_contents.h"
3130
#include "impeller/entity/entity.h"

impeller/entity/BUILD.gn

-2
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,6 @@ impeller_component("entity") {
118118
"contents/runtime_effect_contents.h",
119119
"contents/solid_color_contents.cc",
120120
"contents/solid_color_contents.h",
121-
"contents/solid_stroke_contents.cc",
122-
"contents/solid_stroke_contents.h",
123121
"contents/sweep_gradient_contents.cc",
124122
"contents/sweep_gradient_contents.h",
125123
"contents/text_contents.cc",

impeller/entity/contents/linear_gradient_contents.cc

+17-4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "linear_gradient_contents.h"
66

77
#include "flutter/fml/logging.h"
8+
#include "impeller/entity/contents/clip_contents.h"
89
#include "impeller/entity/contents/content_context.h"
910
#include "impeller/entity/contents/gradient_generator.h"
1011
#include "impeller/entity/entity.h"
@@ -72,13 +73,17 @@ bool LinearGradientContents::Render(const ContentContext& renderer,
7273

7374
Command cmd;
7475
cmd.label = "LinearGradientFill";
75-
cmd.pipeline = renderer.GetLinearGradientFillPipeline(
76-
OptionsFromPassAndEntity(pass, entity));
7776
cmd.stencil_reference = entity.GetStencilDepth();
7877

79-
auto allocator = renderer.GetContext()->GetResourceAllocator();
8078
auto geometry_result =
8179
GetGeometry()->GetPositionBuffer(renderer, entity, pass);
80+
auto options = OptionsFromPassAndEntity(pass, entity);
81+
if (geometry_result.prevent_overdraw) {
82+
options.stencil_compare = CompareFunction::kEqual;
83+
options.stencil_operation = StencilOperation::kIncrementClamp;
84+
}
85+
cmd.pipeline = renderer.GetLinearGradientFillPipeline(options);
86+
8287
cmd.BindVertices(geometry_result.vertex_buffer);
8388
cmd.primitive_type = geometry_result.type;
8489
FS::BindGradientInfo(
@@ -90,7 +95,15 @@ bool LinearGradientContents::Render(const ContentContext& renderer,
9095
cmd, std::move(gradient_texture),
9196
renderer.GetContext()->GetSamplerLibrary()->GetSampler(sampler_desc));
9297
VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info));
93-
return pass.AddCommand(std::move(cmd));
98+
99+
if (!pass.AddCommand(std::move(cmd))) {
100+
return false;
101+
}
102+
103+
if (geometry_result.prevent_overdraw) {
104+
return ClipRestoreContents().Render(renderer, entity, pass);
105+
}
106+
return true;
94107
}
95108

96109
} // namespace impeller

impeller/entity/contents/radial_gradient_contents.cc

+17-4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "radial_gradient_contents.h"
66

77
#include "flutter/fml/logging.h"
8+
#include "impeller/entity/contents/clip_contents.h"
89
#include "impeller/entity/contents/content_context.h"
910
#include "impeller/entity/contents/gradient_generator.h"
1011
#include "impeller/entity/entity.h"
@@ -72,13 +73,17 @@ bool RadialGradientContents::Render(const ContentContext& renderer,
7273

7374
Command cmd;
7475
cmd.label = "RadialGradientFill";
75-
cmd.pipeline = renderer.GetRadialGradientFillPipeline(
76-
OptionsFromPassAndEntity(pass, entity));
7776
cmd.stencil_reference = entity.GetStencilDepth();
7877

79-
auto allocator = renderer.GetContext()->GetResourceAllocator();
8078
auto geometry_result =
8179
GetGeometry()->GetPositionBuffer(renderer, entity, pass);
80+
auto options = OptionsFromPassAndEntity(pass, entity);
81+
if (geometry_result.prevent_overdraw) {
82+
options.stencil_compare = CompareFunction::kEqual;
83+
options.stencil_operation = StencilOperation::kIncrementClamp;
84+
}
85+
cmd.pipeline = renderer.GetRadialGradientFillPipeline(options);
86+
8287
cmd.BindVertices(geometry_result.vertex_buffer);
8388
cmd.primitive_type = geometry_result.type;
8489
FS::BindGradientInfo(
@@ -90,7 +95,15 @@ bool RadialGradientContents::Render(const ContentContext& renderer,
9095
cmd, gradient_texture,
9196
renderer.GetContext()->GetSamplerLibrary()->GetSampler(sampler_desc));
9297
VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info));
93-
return pass.AddCommand(std::move(cmd));
98+
99+
if (!pass.AddCommand(std::move(cmd))) {
100+
return false;
101+
}
102+
103+
if (geometry_result.prevent_overdraw) {
104+
return ClipRestoreContents().Render(renderer, entity, pass);
105+
}
106+
return true;
94107
}
95108

96109
} // namespace impeller

impeller/entity/contents/solid_color_contents.cc

+12-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include "solid_color_contents.h"
66

7+
#include "impeller/entity/contents/clip_contents.h"
78
#include "impeller/entity/contents/content_context.h"
89
#include "impeller/entity/entity.h"
910
#include "impeller/geometry/path.h"
@@ -55,11 +56,17 @@ bool SolidColorContents::Render(const ContentContext& renderer,
5556

5657
Command cmd;
5758
cmd.label = "Solid Fill";
58-
cmd.pipeline =
59-
renderer.GetSolidFillPipeline(OptionsFromPassAndEntity(pass, entity));
6059
cmd.stencil_reference = entity.GetStencilDepth();
6160

6261
auto geometry_result = geometry_->GetPositionBuffer(renderer, entity, pass);
62+
63+
auto options = OptionsFromPassAndEntity(pass, entity);
64+
if (geometry_result.prevent_overdraw) {
65+
options.stencil_compare = CompareFunction::kEqual;
66+
options.stencil_operation = StencilOperation::kIncrementClamp;
67+
}
68+
69+
cmd.pipeline = renderer.GetSolidFillPipeline(options);
6370
cmd.BindVertices(geometry_result.vertex_buffer);
6471
cmd.primitive_type = geometry_result.type;
6572

@@ -76,6 +83,9 @@ bool SolidColorContents::Render(const ContentContext& renderer,
7683
return false;
7784
}
7885

86+
if (geometry_result.prevent_overdraw) {
87+
return ClipRestoreContents().Render(renderer, entity, pass);
88+
}
7989
return true;
8090
}
8191

0 commit comments

Comments
 (0)