Skip to content

Commit 6b64b25

Browse files
flarsealesj
authored andcommitted
[Impeller] consolidate transforms in PositionUVWriter (flutter#50635)
Consolidates the 3 coordinate operations in the PositionUVWriter into a single transform for efficiency.
1 parent ca8e323 commit 6b64b25

File tree

4 files changed

+146
-9
lines changed

4 files changed

+146
-9
lines changed

impeller/entity/geometry/geometry_unittests.cc

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,77 @@
44

55
#include "flutter/testing/testing.h"
66
#include "impeller/entity/geometry/geometry.h"
7+
#include "impeller/entity/geometry/stroke_path_geometry.h"
8+
#include "impeller/geometry/geometry_asserts.h"
79
#include "impeller/geometry/path_builder.h"
810

11+
inline ::testing::AssertionResult SolidVerticesNear(
12+
std::vector<impeller::SolidFillVertexShader::PerVertexData> a,
13+
std::vector<impeller::SolidFillVertexShader::PerVertexData> b) {
14+
if (a.size() != b.size()) {
15+
return ::testing::AssertionFailure() << "Colors length does not match";
16+
}
17+
for (auto i = 0u; i < b.size(); i++) {
18+
if (!PointNear(a[i].position, b[i].position)) {
19+
return ::testing::AssertionFailure() << "Positions are not equal.";
20+
}
21+
}
22+
return ::testing::AssertionSuccess();
23+
}
24+
25+
inline ::testing::AssertionResult TextureVerticesNear(
26+
std::vector<impeller::TextureFillVertexShader::PerVertexData> a,
27+
std::vector<impeller::TextureFillVertexShader::PerVertexData> b) {
28+
if (a.size() != b.size()) {
29+
return ::testing::AssertionFailure() << "Colors length does not match";
30+
}
31+
for (auto i = 0u; i < b.size(); i++) {
32+
if (!PointNear(a[i].position, b[i].position)) {
33+
return ::testing::AssertionFailure() << "Positions are not equal.";
34+
}
35+
if (!PointNear(a[i].texture_coords, b[i].texture_coords)) {
36+
return ::testing::AssertionFailure() << "Texture coords are not equal.";
37+
}
38+
}
39+
return ::testing::AssertionSuccess();
40+
}
41+
42+
#define EXPECT_SOLID_VERTICES_NEAR(a, b) \
43+
EXPECT_PRED2(&::SolidVerticesNear, a, b)
44+
#define EXPECT_TEXTURE_VERTICES_NEAR(a, b) \
45+
EXPECT_PRED2(&::TextureVerticesNear, a, b)
46+
947
namespace impeller {
48+
49+
class ImpellerEntityUnitTestAccessor {
50+
public:
51+
static std::vector<SolidFillVertexShader::PerVertexData>
52+
GenerateSolidStrokeVertices(const Path::Polyline& polyline,
53+
Scalar stroke_width,
54+
Scalar miter_limit,
55+
Join stroke_join,
56+
Cap stroke_cap,
57+
Scalar scale) {
58+
return StrokePathGeometry::GenerateSolidStrokeVertices(
59+
polyline, stroke_width, miter_limit, stroke_join, stroke_cap, scale);
60+
}
61+
62+
static std::vector<TextureFillVertexShader::PerVertexData>
63+
GenerateSolidStrokeVerticesUV(const Path::Polyline& polyline,
64+
Scalar stroke_width,
65+
Scalar miter_limit,
66+
Join stroke_join,
67+
Cap stroke_cap,
68+
Scalar scale,
69+
Point texture_origin,
70+
Size texture_size,
71+
const Matrix& effect_transform) {
72+
return StrokePathGeometry::GenerateSolidStrokeVerticesUV(
73+
polyline, stroke_width, miter_limit, stroke_join, stroke_cap, scale,
74+
texture_origin, texture_size, effect_transform);
75+
}
76+
};
77+
1078
namespace testing {
1179

1280
TEST(EntityGeometryTest, RectGeometryCoversArea) {
@@ -71,5 +139,74 @@ TEST(EntityGeometryTest, RoundRectGeometryCoversArea) {
71139
EXPECT_TRUE(geometry->CoversArea({}, Rect::MakeLTRB(1, 30, 99, 70)));
72140
}
73141

142+
TEST(EntityGeometryTest, StrokePathGeometryTransformOfLine) {
143+
auto path =
144+
PathBuilder().AddLine(Point(100, 100), Point(200, 100)).TakePath();
145+
auto points = std::make_unique<std::vector<Point>>();
146+
auto polyline =
147+
path.CreatePolyline(1.0f, std::move(points),
148+
[&points](Path::Polyline::PointBufferPtr reclaimed) {
149+
points = std::move(reclaimed);
150+
});
151+
152+
auto vertices = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
153+
polyline, 10.0f, 10.0f, Join::kBevel, Cap::kButt, 1.0);
154+
155+
std::vector<SolidFillVertexShader::PerVertexData> expected = {
156+
{.position = Point(100.0f, 105.0f)}, //
157+
{.position = Point(100.0f, 95.0f)}, //
158+
{.position = Point(100.0f, 105.0f)}, //
159+
{.position = Point(100.0f, 95.0f)}, //
160+
{.position = Point(200.0f, 105.0f)}, //
161+
{.position = Point(200.0f, 95.0f)}, //
162+
{.position = Point(200.0f, 105.0f)}, //
163+
{.position = Point(200.0f, 95.0f)}, //
164+
};
165+
166+
EXPECT_SOLID_VERTICES_NEAR(vertices, expected);
167+
168+
{
169+
auto uv_vertices =
170+
ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVerticesUV(
171+
polyline, 10.0f, 10.0f, Join::kBevel, Cap::kButt, 1.0, //
172+
Point(50.0f, 40.0f), Size(20.0f, 40.0f),
173+
Matrix::MakeScale({8.0f, 4.0f, 1.0f}));
174+
// uvx = ((x * 8) - 50) / 20
175+
// uvy = ((y * 4) - 40) / 40
176+
auto uv = [](const Point& p) {
177+
return Point(((p.x * 8.0f) - 50.0f) / 20.0f,
178+
((p.y * 4.0f) - 40.0f) / 40.0f);
179+
};
180+
std::vector<TextureFillVertexShader::PerVertexData> uv_expected;
181+
for (size_t i = 0; i < expected.size(); i++) {
182+
auto p = expected[i].position;
183+
uv_expected.push_back({.position = p, .texture_coords = uv(p)});
184+
}
185+
186+
EXPECT_TEXTURE_VERTICES_NEAR(uv_vertices, uv_expected);
187+
}
188+
189+
{
190+
auto uv_vertices =
191+
ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVerticesUV(
192+
polyline, 10.0f, 10.0f, Join::kBevel, Cap::kButt, 1.0, //
193+
Point(50.0f, 40.0f), Size(20.0f, 40.0f),
194+
Matrix::MakeTranslation({8.0f, 4.0f}));
195+
// uvx = ((x + 8) - 50) / 20
196+
// uvy = ((y + 4) - 40) / 40
197+
auto uv = [](const Point& p) {
198+
return Point(((p.x + 8.0f) - 50.0f) / 20.0f,
199+
((p.y + 4.0f) - 40.0f) / 40.0f);
200+
};
201+
std::vector<TextureFillVertexShader::PerVertexData> uv_expected;
202+
for (size_t i = 0; i < expected.size(); i++) {
203+
auto p = expected[i].position;
204+
uv_expected.push_back({.position = p, .texture_coords = uv(p)});
205+
}
206+
207+
EXPECT_TEXTURE_VERTICES_NEAR(uv_vertices, uv_expected);
208+
}
209+
}
210+
74211
} // namespace testing
75212
} // namespace impeller

impeller/entity/geometry/stroke_path_geometry.cc

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ class PositionUVWriter {
4949
PositionUVWriter(Point texture_origin,
5050
Size texture_coverage,
5151
const Matrix& effect_transform)
52-
: texture_origin_(texture_origin),
53-
texture_coverage_(texture_coverage),
54-
effect_transform_(effect_transform) {}
52+
: uv_transform_(Matrix::MakeScale(1 / texture_coverage) *
53+
Matrix::MakeTranslation(-texture_origin) *
54+
effect_transform) {}
5555

5656
const std::vector<TextureFillVertexShader::PerVertexData>& GetData() const {
5757
return data_;
@@ -60,15 +60,13 @@ class PositionUVWriter {
6060
void AppendVertex(const Point& point) {
6161
data_.emplace_back(TextureFillVertexShader::PerVertexData{
6262
.position = point,
63-
.texture_coords =
64-
effect_transform_ * (point - texture_origin_) / texture_coverage_});
63+
.texture_coords = uv_transform_ * point,
64+
});
6565
}
6666

6767
private:
6868
std::vector<TextureFillVertexShader::PerVertexData> data_ = {};
69-
const Point texture_origin_;
70-
const Size texture_coverage_;
71-
const Matrix effect_transform_;
69+
const Matrix uv_transform_;
7270
};
7371

7472
template <typename VertexWriter>

impeller/entity/geometry/stroke_path_geometry.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ class StrokePathGeometry final : public Geometry {
6666
Point texture_origin,
6767
Size texture_size,
6868
const Matrix& effect_transform);
69+
6970
friend class ImpellerBenchmarkAccessor;
71+
friend class ImpellerEntityUnitTestAccessor;
7072

7173
bool SkipRendering() const;
7274

impeller/geometry/size.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ constexpr TSize<T> operator*(U s, const TSize<T>& p) {
131131

132132
template <class T, class U, class = std::enable_if_t<std::is_arithmetic_v<U>>>
133133
constexpr TSize<T> operator/(U s, const TSize<T>& p) {
134-
return {static_cast<T>(s) / p.x, static_cast<T>(s) / p.y};
134+
return {static_cast<T>(s) / p.width, static_cast<T>(s) / p.height};
135135
}
136136

137137
using Size = TSize<Scalar>;

0 commit comments

Comments
 (0)