Skip to content

Commit 4c75fe6

Browse files
bderodnfield
authored andcommitted
Set path for linear gradient contents; don't fail renders for failed tessellations (#162)
1 parent 120c0b6 commit 4c75fe6

15 files changed

+123
-26
lines changed

impeller/BUILD.gn

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ config("impeller_public_config") {
2020
if (is_win) {
2121
defines += [
2222
"_USE_MATH_DEFINES",
23+
2324
# TODO(dnfield): https://github.com/flutter/flutter/issues/50053
2425
"_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING",
2526
]
@@ -55,6 +56,7 @@ executable("impeller_unittests") {
5556
"blobcat:blobcat_unittests",
5657
"compiler:compiler_unittests",
5758
"geometry:geometry_unittests",
59+
"tessellator:tessellator_unittests",
5860
]
5961

6062
if (impeller_supports_rendering) {

impeller/aiks/paint.cc

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ namespace impeller {
1111
std::shared_ptr<Contents> Paint::CreateContentsForEntity(Path path,
1212
bool cover) const {
1313
if (contents) {
14+
contents->SetPath(std::move(path));
1415
return contents;
1516
}
1617

impeller/aiks/paint.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "flutter/fml/macros.h"
1010
#include "impeller/entity/contents/contents.h"
1111
#include "impeller/entity/contents/filters/filter_contents.h"
12+
#include "impeller/entity/contents/linear_gradient_contents.h"
1213
#include "impeller/entity/contents/solid_stroke_contents.h"
1314
#include "impeller/entity/entity.h"
1415
#include "impeller/geometry/color.h"
@@ -27,14 +28,15 @@ struct Paint {
2728
};
2829

2930
Color color = Color::Black();
31+
std::shared_ptr<LinearGradientContents> contents;
32+
3033
Scalar stroke_width = 0.0;
3134
SolidStrokeContents::Cap stroke_cap = SolidStrokeContents::Cap::kButt;
3235
SolidStrokeContents::Join stroke_join = SolidStrokeContents::Join::kMiter;
3336
Scalar stroke_miter = 4.0;
3437
Style style = Style::kFill;
3538
Entity::BlendMode blend_mode = Entity::BlendMode::kSourceOver;
3639
std::optional<MaskBlur> mask_blur;
37-
std::shared_ptr<Contents> contents;
3840

3941
/// @brief Wrap this paint's configured filters to the given contents.
4042
/// @param[in] input The contents to wrap with paint's filters.

impeller/entity/contents/linear_gradient_contents.cc

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

55
#include "linear_gradient_contents.h"
66

7+
#include "flutter/fml/logging.h"
78
#include "impeller/entity/contents/content_context.h"
89
#include "impeller/entity/entity.h"
910
#include "impeller/renderer/render_pass.h"
@@ -58,7 +59,11 @@ bool LinearGradientContents::Render(const ContentContext& renderer,
5859
vtx.vertices = point;
5960
vertices_builder.AppendVertex(vtx);
6061
});
61-
if (!result) {
62+
63+
if (result == Tessellator::Result::kInputError) {
64+
return true;
65+
}
66+
if (result == Tessellator::Result::kTessellationError) {
6267
return false;
6368
}
6469
}

impeller/entity/contents/solid_color_contents.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ VertexBuffer SolidColorContents::CreateSolidFillVertices(const Path& path,
5050
vtx.vertices = point;
5151
vtx_builder.AppendVertex(vtx);
5252
});
53-
if (!tesselation_result) {
53+
if (tesselation_result != Tessellator::Result::kSuccess) {
5454
return {};
5555
}
5656

impeller/entity/contents/solid_stroke_contents.cc

+3-3
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,9 @@ bool SolidStrokeContents::Render(const ContentContext& renderer,
201201
auto smoothing = SmoothingApproximation(
202202
5.0 / (stroke_size_ * entity.GetTransformation().GetMaxBasisLength()),
203203
0.0, 0.0);
204-
cmd.BindVertices(CreateSolidStrokeVertices(
205-
path_, pass.GetTransientsBuffer(), cap_proc_, join_proc_,
206-
miter_limit_, smoothing));
204+
cmd.BindVertices(CreateSolidStrokeVertices(path_, pass.GetTransientsBuffer(),
205+
cap_proc_, join_proc_,
206+
miter_limit_, smoothing));
207207
VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info));
208208
VS::BindStrokeInfo(cmd,
209209
pass.GetTransientsBuffer().EmplaceUniform(stroke_info));

impeller/entity/contents/texture_contents.cc

+5-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,11 @@ bool TextureContents::Render(const ContentContext& renderer,
8181
texture_size;
8282
vertex_builder.AppendVertex(data);
8383
});
84-
if (!tess_result) {
84+
85+
if (tess_result == Tessellator::Result::kInputError) {
86+
return true;
87+
}
88+
if (tess_result == Tessellator::Result::kTessellationError) {
8589
return false;
8690
}
8791
}

impeller/entity/entity_unittests.cc

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "impeller/playground/widgets.h"
1919
#include "impeller/renderer/render_pass.h"
2020
#include "impeller/renderer/vertex_buffer_builder.h"
21+
#include "impeller/tessellator/tessellator.h"
2122
#include "third_party/imgui/imgui.h"
2223

2324
namespace impeller {

impeller/geometry/geometry_unittests.cc

+13
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,19 @@ TEST(GeometryTest, QuaternionLerp) {
264264
ASSERT_QUATERNION_NEAR(q3, expected);
265265
}
266266

267+
TEST(GeometryTest, EmptyPath) {
268+
auto path = PathBuilder{}.TakePath();
269+
ASSERT_EQ(path.GetComponentCount(), 1u);
270+
271+
ContourComponent c;
272+
path.GetContourComponentAtIndex(0, c);
273+
ASSERT_POINT_NEAR(c.destination, Point());
274+
275+
Path::Polyline polyline = path.CreatePolyline();
276+
ASSERT_TRUE(polyline.points.empty());
277+
ASSERT_TRUE(polyline.contours.empty());
278+
}
279+
267280
TEST(GeometryTest, SimplePath) {
268281
Path path;
269282

impeller/renderer/renderer_unittests.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,8 @@ TEST_P(RendererTest, CanRenderInstanced) {
279279

280280
VertexBufferBuilder<VS::PerVertexData> builder;
281281

282-
ASSERT_TRUE(
282+
ASSERT_EQ(
283+
Tessellator::Result::kSuccess,
283284
Tessellator{}.Tessellate(FillType::kPositive,
284285
PathBuilder{}
285286
.AddRect(Rect::MakeXYWH(10, 10, 100, 100))

impeller/tessellator/BUILD.gn

+10-2
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,9 @@ impeller_component("tessellator_shared") {
2323
output_name = "tessellator"
2424
}
2525

26-
2726
sources = [
28-
"c/tessellator.h",
2927
"c/tessellator.cc",
28+
"c/tessellator.h",
3029
"tessellator.cc",
3130
"tessellator.h",
3231
]
@@ -36,3 +35,12 @@ impeller_component("tessellator_shared") {
3635
"//third_party/libtess2",
3736
]
3837
}
38+
39+
impeller_component("tessellator_unittests") {
40+
testonly = true
41+
sources = [ "tessellator_unittests.cc" ]
42+
deps = [
43+
":tessellator",
44+
"//flutter/testing",
45+
]
46+
}

impeller/tessellator/c/tessellator.cc

+5-5
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,11 @@ struct Vertices* Tessellate(PathBuilder* builder,
4747
auto polyline = path.CreatePolyline(smoothing);
4848

4949
std::vector<float> points;
50-
if (!Tessellator{}.Tessellate(path.GetFillType(), polyline,
51-
[&points](Point vertex) {
52-
points.push_back(vertex.x);
53-
points.push_back(vertex.y);
54-
})) {
50+
if (Tessellator{}.Tessellate(path.GetFillType(), polyline,
51+
[&points](Point vertex) {
52+
points.push_back(vertex.x);
53+
points.push_back(vertex.y);
54+
}) != Tessellator::Result::kSuccess) {
5555
return nullptr;
5656
}
5757

impeller/tessellator/tessellator.cc

+11-7
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,15 @@ static void DestroyTessellator(TESStesselator* tessellator) {
3434
}
3535
}
3636

37-
bool Tessellator::Tessellate(FillType fill_type,
38-
const Path::Polyline& polyline,
39-
VertexCallback callback) const {
37+
Tessellator::Result Tessellator::Tessellate(FillType fill_type,
38+
const Path::Polyline& polyline,
39+
VertexCallback callback) const {
4040
if (!callback) {
41-
return false;
41+
return Result::kInputError;
42+
}
43+
44+
if (polyline.points.empty()) {
45+
return Result::kInputError;
4246
}
4347

4448
using CTessellator =
@@ -49,7 +53,7 @@ bool Tessellator::Tessellate(FillType fill_type,
4953
DestroyTessellator);
5054

5155
if (!tessellator) {
52-
return false;
56+
return Result::kTessellationError;
5357
}
5458

5559
constexpr int kVertexSize = 2;
@@ -85,7 +89,7 @@ bool Tessellator::Tessellate(FillType fill_type,
8589
);
8690

8791
if (result != 1) {
88-
return false;
92+
return Result::kTessellationError;
8993
}
9094

9195
// TODO(csg): This copy can be elided entirely for the current use case.
@@ -109,7 +113,7 @@ bool Tessellator::Tessellate(FillType fill_type,
109113
callback(vtx);
110114
}
111115

112-
return true;
116+
return Result::kSuccess;
113117
}
114118

115119
} // namespace impeller

impeller/tessellator/tessellator.h

+10-4
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ enum class WindingOrder {
2626
///
2727
class Tessellator {
2828
public:
29+
enum class Result {
30+
kSuccess,
31+
kInputError,
32+
kTessellationError,
33+
};
34+
2935
Tessellator();
3036

3137
~Tessellator();
@@ -39,11 +45,11 @@ class Tessellator {
3945
/// @param[in] polyline The polyline
4046
/// @param[in] callback The callback
4147
///
42-
/// @return If tessellation was successful.
48+
/// @return The result status of the tessellation.
4349
///
44-
bool Tessellate(FillType fill_type,
45-
const Path::Polyline& polyline,
46-
VertexCallback callback) const;
50+
Tessellator::Result Tessellate(FillType fill_type,
51+
const Path::Polyline& polyline,
52+
VertexCallback callback) const;
4753

4854
private:
4955
FML_DISALLOW_COPY_AND_ASSIGN(Tessellator);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "flutter/testing/testing.h"
6+
#include "gtest/gtest.h"
7+
#include "impeller/geometry/path_builder.h"
8+
#include "impeller/tessellator/tessellator.h"
9+
10+
namespace impeller {
11+
namespace testing {
12+
13+
TEST(TessellatorTest, TessellatorReturnsCorrectResultStatus) {
14+
// Zero points.
15+
{
16+
Tessellator t;
17+
auto polyline = PathBuilder{}.TakePath().CreatePolyline();
18+
Tessellator::Result result =
19+
t.Tessellate(FillType::kPositive, polyline, [](Point point) {});
20+
21+
ASSERT_EQ(polyline.points.size(), 0u);
22+
ASSERT_EQ(result, Tessellator::Result::kInputError);
23+
}
24+
25+
// One point.
26+
{
27+
Tessellator t;
28+
auto polyline = PathBuilder{}.LineTo({0, 0}).TakePath().CreatePolyline();
29+
Tessellator::Result result =
30+
t.Tessellate(FillType::kPositive, polyline, [](Point point) {});
31+
32+
ASSERT_EQ(polyline.points.size(), 1u);
33+
ASSERT_EQ(result, Tessellator::Result::kSuccess);
34+
}
35+
36+
// Two points.
37+
{
38+
Tessellator t;
39+
auto polyline =
40+
PathBuilder{}.AddLine({0, 0}, {0, 1}).TakePath().CreatePolyline();
41+
Tessellator::Result result =
42+
t.Tessellate(FillType::kPositive, polyline, [](Point point) {});
43+
44+
ASSERT_EQ(polyline.points.size(), 2u);
45+
ASSERT_EQ(result, Tessellator::Result::kSuccess);
46+
}
47+
}
48+
49+
} // namespace testing
50+
} // namespace impeller

0 commit comments

Comments
 (0)