[Impeller] consolidate transforms in PositionUVWriter (flutter/engine#50635)
Consolidates the 3 coordinate operations in the PositionUVWriter into a single transform for efficiency.
This commit is contained in:
@@ -4,9 +4,77 @@
|
||||
|
||||
#include "flutter/testing/testing.h"
|
||||
#include "impeller/entity/geometry/geometry.h"
|
||||
#include "impeller/entity/geometry/stroke_path_geometry.h"
|
||||
#include "impeller/geometry/geometry_asserts.h"
|
||||
#include "impeller/geometry/path_builder.h"
|
||||
|
||||
inline ::testing::AssertionResult SolidVerticesNear(
|
||||
std::vector<impeller::SolidFillVertexShader::PerVertexData> a,
|
||||
std::vector<impeller::SolidFillVertexShader::PerVertexData> b) {
|
||||
if (a.size() != b.size()) {
|
||||
return ::testing::AssertionFailure() << "Colors length does not match";
|
||||
}
|
||||
for (auto i = 0u; i < b.size(); i++) {
|
||||
if (!PointNear(a[i].position, b[i].position)) {
|
||||
return ::testing::AssertionFailure() << "Positions are not equal.";
|
||||
}
|
||||
}
|
||||
return ::testing::AssertionSuccess();
|
||||
}
|
||||
|
||||
inline ::testing::AssertionResult TextureVerticesNear(
|
||||
std::vector<impeller::TextureFillVertexShader::PerVertexData> a,
|
||||
std::vector<impeller::TextureFillVertexShader::PerVertexData> b) {
|
||||
if (a.size() != b.size()) {
|
||||
return ::testing::AssertionFailure() << "Colors length does not match";
|
||||
}
|
||||
for (auto i = 0u; i < b.size(); i++) {
|
||||
if (!PointNear(a[i].position, b[i].position)) {
|
||||
return ::testing::AssertionFailure() << "Positions are not equal.";
|
||||
}
|
||||
if (!PointNear(a[i].texture_coords, b[i].texture_coords)) {
|
||||
return ::testing::AssertionFailure() << "Texture coords are not equal.";
|
||||
}
|
||||
}
|
||||
return ::testing::AssertionSuccess();
|
||||
}
|
||||
|
||||
#define EXPECT_SOLID_VERTICES_NEAR(a, b) \
|
||||
EXPECT_PRED2(&::SolidVerticesNear, a, b)
|
||||
#define EXPECT_TEXTURE_VERTICES_NEAR(a, b) \
|
||||
EXPECT_PRED2(&::TextureVerticesNear, a, b)
|
||||
|
||||
namespace impeller {
|
||||
|
||||
class ImpellerEntityUnitTestAccessor {
|
||||
public:
|
||||
static std::vector<SolidFillVertexShader::PerVertexData>
|
||||
GenerateSolidStrokeVertices(const Path::Polyline& polyline,
|
||||
Scalar stroke_width,
|
||||
Scalar miter_limit,
|
||||
Join stroke_join,
|
||||
Cap stroke_cap,
|
||||
Scalar scale) {
|
||||
return StrokePathGeometry::GenerateSolidStrokeVertices(
|
||||
polyline, stroke_width, miter_limit, stroke_join, stroke_cap, scale);
|
||||
}
|
||||
|
||||
static std::vector<TextureFillVertexShader::PerVertexData>
|
||||
GenerateSolidStrokeVerticesUV(const Path::Polyline& polyline,
|
||||
Scalar stroke_width,
|
||||
Scalar miter_limit,
|
||||
Join stroke_join,
|
||||
Cap stroke_cap,
|
||||
Scalar scale,
|
||||
Point texture_origin,
|
||||
Size texture_size,
|
||||
const Matrix& effect_transform) {
|
||||
return StrokePathGeometry::GenerateSolidStrokeVerticesUV(
|
||||
polyline, stroke_width, miter_limit, stroke_join, stroke_cap, scale,
|
||||
texture_origin, texture_size, effect_transform);
|
||||
}
|
||||
};
|
||||
|
||||
namespace testing {
|
||||
|
||||
TEST(EntityGeometryTest, RectGeometryCoversArea) {
|
||||
@@ -71,5 +139,74 @@ TEST(EntityGeometryTest, RoundRectGeometryCoversArea) {
|
||||
EXPECT_TRUE(geometry->CoversArea({}, Rect::MakeLTRB(1, 30, 99, 70)));
|
||||
}
|
||||
|
||||
TEST(EntityGeometryTest, StrokePathGeometryTransformOfLine) {
|
||||
auto path =
|
||||
PathBuilder().AddLine(Point(100, 100), Point(200, 100)).TakePath();
|
||||
auto points = std::make_unique<std::vector<Point>>();
|
||||
auto polyline =
|
||||
path.CreatePolyline(1.0f, std::move(points),
|
||||
[&points](Path::Polyline::PointBufferPtr reclaimed) {
|
||||
points = std::move(reclaimed);
|
||||
});
|
||||
|
||||
auto vertices = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
|
||||
polyline, 10.0f, 10.0f, Join::kBevel, Cap::kButt, 1.0);
|
||||
|
||||
std::vector<SolidFillVertexShader::PerVertexData> expected = {
|
||||
{.position = Point(100.0f, 105.0f)}, //
|
||||
{.position = Point(100.0f, 95.0f)}, //
|
||||
{.position = Point(100.0f, 105.0f)}, //
|
||||
{.position = Point(100.0f, 95.0f)}, //
|
||||
{.position = Point(200.0f, 105.0f)}, //
|
||||
{.position = Point(200.0f, 95.0f)}, //
|
||||
{.position = Point(200.0f, 105.0f)}, //
|
||||
{.position = Point(200.0f, 95.0f)}, //
|
||||
};
|
||||
|
||||
EXPECT_SOLID_VERTICES_NEAR(vertices, expected);
|
||||
|
||||
{
|
||||
auto uv_vertices =
|
||||
ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVerticesUV(
|
||||
polyline, 10.0f, 10.0f, Join::kBevel, Cap::kButt, 1.0, //
|
||||
Point(50.0f, 40.0f), Size(20.0f, 40.0f),
|
||||
Matrix::MakeScale({8.0f, 4.0f, 1.0f}));
|
||||
// uvx = ((x * 8) - 50) / 20
|
||||
// uvy = ((y * 4) - 40) / 40
|
||||
auto uv = [](const Point& p) {
|
||||
return Point(((p.x * 8.0f) - 50.0f) / 20.0f,
|
||||
((p.y * 4.0f) - 40.0f) / 40.0f);
|
||||
};
|
||||
std::vector<TextureFillVertexShader::PerVertexData> uv_expected;
|
||||
for (size_t i = 0; i < expected.size(); i++) {
|
||||
auto p = expected[i].position;
|
||||
uv_expected.push_back({.position = p, .texture_coords = uv(p)});
|
||||
}
|
||||
|
||||
EXPECT_TEXTURE_VERTICES_NEAR(uv_vertices, uv_expected);
|
||||
}
|
||||
|
||||
{
|
||||
auto uv_vertices =
|
||||
ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVerticesUV(
|
||||
polyline, 10.0f, 10.0f, Join::kBevel, Cap::kButt, 1.0, //
|
||||
Point(50.0f, 40.0f), Size(20.0f, 40.0f),
|
||||
Matrix::MakeTranslation({8.0f, 4.0f}));
|
||||
// uvx = ((x + 8) - 50) / 20
|
||||
// uvy = ((y + 4) - 40) / 40
|
||||
auto uv = [](const Point& p) {
|
||||
return Point(((p.x + 8.0f) - 50.0f) / 20.0f,
|
||||
((p.y + 4.0f) - 40.0f) / 40.0f);
|
||||
};
|
||||
std::vector<TextureFillVertexShader::PerVertexData> uv_expected;
|
||||
for (size_t i = 0; i < expected.size(); i++) {
|
||||
auto p = expected[i].position;
|
||||
uv_expected.push_back({.position = p, .texture_coords = uv(p)});
|
||||
}
|
||||
|
||||
EXPECT_TEXTURE_VERTICES_NEAR(uv_vertices, uv_expected);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace impeller
|
||||
|
||||
@@ -49,9 +49,9 @@ class PositionUVWriter {
|
||||
PositionUVWriter(Point texture_origin,
|
||||
Size texture_coverage,
|
||||
const Matrix& effect_transform)
|
||||
: texture_origin_(texture_origin),
|
||||
texture_coverage_(texture_coverage),
|
||||
effect_transform_(effect_transform) {}
|
||||
: uv_transform_(Matrix::MakeScale(1 / texture_coverage) *
|
||||
Matrix::MakeTranslation(-texture_origin) *
|
||||
effect_transform) {}
|
||||
|
||||
const std::vector<TextureFillVertexShader::PerVertexData>& GetData() const {
|
||||
return data_;
|
||||
@@ -60,15 +60,13 @@ class PositionUVWriter {
|
||||
void AppendVertex(const Point& point) {
|
||||
data_.emplace_back(TextureFillVertexShader::PerVertexData{
|
||||
.position = point,
|
||||
.texture_coords =
|
||||
effect_transform_ * (point - texture_origin_) / texture_coverage_});
|
||||
.texture_coords = uv_transform_ * point,
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<TextureFillVertexShader::PerVertexData> data_ = {};
|
||||
const Point texture_origin_;
|
||||
const Size texture_coverage_;
|
||||
const Matrix effect_transform_;
|
||||
const Matrix uv_transform_;
|
||||
};
|
||||
|
||||
template <typename VertexWriter>
|
||||
|
||||
@@ -66,7 +66,9 @@ class StrokePathGeometry final : public Geometry {
|
||||
Point texture_origin,
|
||||
Size texture_size,
|
||||
const Matrix& effect_transform);
|
||||
|
||||
friend class ImpellerBenchmarkAccessor;
|
||||
friend class ImpellerEntityUnitTestAccessor;
|
||||
|
||||
bool SkipRendering() const;
|
||||
|
||||
|
||||
@@ -131,7 +131,7 @@ constexpr TSize<T> operator*(U s, const TSize<T>& p) {
|
||||
|
||||
template <class T, class U, class = std::enable_if_t<std::is_arithmetic_v<U>>>
|
||||
constexpr TSize<T> operator/(U s, const TSize<T>& p) {
|
||||
return {static_cast<T>(s) / p.x, static_cast<T>(s) / p.y};
|
||||
return {static_cast<T>(s) / p.width, static_cast<T>(s) / p.height};
|
||||
}
|
||||
|
||||
using Size = TSize<Scalar>;
|
||||
|
||||
Reference in New Issue
Block a user