From 4aa93cbf61c27f020dd51cbb189f2be2d65ea939 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Fri, 23 Feb 2024 11:52:19 -0800 Subject: [PATCH] [Impeller] Compute UV coordinates lazily in PositionUVWriter (flutter/engine#50879) The stroking code was performing texture coordinate conversion on each created vertex. Since there were often very few calculations needed for each vertex, interspersing a coordinate transform with each vertex append was clogging up the code. This change will defer the calculation of the texture coordinates until the end of the stroking process so that the polyline widening code can do its job efficiently and then later the coordinate conversion code can do its job also efficiently in a tight loop. This change also opened up the opportunity to optimize a common case (no effect transform) even more than before. --- .../entity/geometry/geometry_unittests.cc | 20 +++++++++++ .../entity/geometry/stroke_path_geometry.cc | 34 ++++++++++++++----- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/engine/src/flutter/impeller/entity/geometry/geometry_unittests.cc b/engine/src/flutter/impeller/entity/geometry/geometry_unittests.cc index 56354c1ad48..c56c16613bd 100644 --- a/engine/src/flutter/impeller/entity/geometry/geometry_unittests.cc +++ b/engine/src/flutter/impeller/entity/geometry/geometry_unittests.cc @@ -165,6 +165,26 @@ TEST(EntityGeometryTest, StrokePathGeometryTransformOfLine) { 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()); + // uvx = (x - 50) / 20 + // uvy = (y - 40) / 40 + auto uv = [](const Point& p) { + return Point((p.x - 50.0f) / 20.0f, // + (p.y - 40.0f) / 40.0f); + }; + std::vector 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( diff --git a/engine/src/flutter/impeller/entity/geometry/stroke_path_geometry.cc b/engine/src/flutter/impeller/entity/geometry/stroke_path_geometry.cc index ba3d2fe8cd5..2f0f988e403 100644 --- a/engine/src/flutter/impeller/entity/geometry/stroke_path_geometry.cc +++ b/engine/src/flutter/impeller/entity/geometry/stroke_path_geometry.cc @@ -47,27 +47,45 @@ class PositionWriter { class PositionUVWriter { public: - PositionUVWriter(Point texture_origin, - Size texture_coverage, + PositionUVWriter(const Point& texture_origin, + const Size& texture_size, const Matrix& effect_transform) - : uv_transform_(Matrix::MakeScale(1 / texture_coverage) * - Matrix::MakeTranslation(-texture_origin) * - effect_transform) {} + : texture_origin_(texture_origin), + texture_size_(texture_size), + effect_transform_(effect_transform) {} - const std::vector& GetData() const { + const std::vector& GetData() { + if (effect_transform_.IsIdentity()) { + auto origin = texture_origin_; + auto scale = 1.0 / texture_size_; + + for (auto& pvd : data_) { + pvd.texture_coords = (pvd.position - origin) * scale; + } + } else { + auto texture_rect = Rect::MakeOriginSize(texture_origin_, texture_size_); + Matrix uv_transform = + texture_rect.GetNormalizingTransform() * effect_transform_; + + for (auto& pvd : data_) { + pvd.texture_coords = uv_transform * pvd.position; + } + } return data_; } void AppendVertex(const Point& point) { data_.emplace_back(TextureFillVertexShader::PerVertexData{ .position = point, - .texture_coords = uv_transform_ * point, + // .texture_coords = default, will be filled in during |GetData()| }); } private: std::vector data_ = {}; - const Matrix uv_transform_; + const Point texture_origin_; + const Size texture_size_; + const Matrix effect_transform_; }; template