Skip to content

Commit

Permalink
[Impeller] Simplify convex tessellation (#47957)
Browse files Browse the repository at this point in the history
Removes usage of index buffer and adds zig-zagging triangle strip. Could also be adapted emplace directly into host 
buffer.

Benchmark is https://flutter-engine-perf.skia.org/e/?queries=test%3DBM_Convex_rrect_convex

Umbrella issue: flutter/flutter#138004
  • Loading branch information
jonahwilliams authored Nov 15, 2023
1 parent d7ca057 commit ae30d33
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 54 deletions.
21 changes: 21 additions & 0 deletions impeller/aiks/aiks_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "impeller/geometry/constants.h"
#include "impeller/geometry/geometry_asserts.h"
#include "impeller/geometry/matrix.h"
#include "impeller/geometry/path.h"
#include "impeller/geometry/path_builder.h"
#include "impeller/golden_tests/golden_playground_test.h"
#include "impeller/playground/widgets.h"
Expand Down Expand Up @@ -3492,6 +3493,26 @@ TEST_P(AiksTest, CanCanvasDrawPictureWithAdvancedBlend) {
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}

TEST_P(AiksTest, CanDrawMultiContourConvexPath) {
PathBuilder builder = {};
for (auto i = 0; i < 10; i++) {
if (i % 2 == 0) {
builder.AddCircle(Point(100 + 50 * i, 100 + 50 * i), 100);
} else {
builder.MoveTo({100.f + 50.f * i - 100, 100.f + 50.f * i});
builder.LineTo({100.f + 50.f * i, 100.f + 50.f * i - 100});
builder.LineTo({100.f + 50.f * i - 100, 100.f + 50.f * i - 100});
builder.Close();
}
}
builder.SetConvexity(Convexity::kConvex);

Canvas canvas;
canvas.DrawPath(builder.TakePath(), {.color = Color::Red().WithAlpha(0.4)});

ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}

TEST_P(AiksTest, CanCanvasDrawPictureWithBackdropFilter) {
Canvas subcanvas;
subcanvas.SaveLayer({}, {},
Expand Down
18 changes: 6 additions & 12 deletions impeller/entity/geometry/fill_path_geometry.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,16 @@ GeometryResult FillPathGeometry::GetPositionBuffer(

if (path_.GetFillType() == FillType::kNonZero && //
path_.IsConvex()) {
auto [points, indices] = renderer.GetTessellator()->TessellateConvex(
auto points = renderer.GetTessellator()->TessellateConvex(
path_, entity.GetTransformation().GetMaxBasisLength());

vertex_buffer.vertex_buffer = host_buffer.Emplace(
points.data(), points.size() * sizeof(Point), alignof(Point));
vertex_buffer.index_buffer = host_buffer.Emplace(
indices.data(), indices.size() * sizeof(uint16_t), alignof(uint16_t));
vertex_buffer.vertex_count = indices.size();
vertex_buffer.index_type = IndexType::k16bit;
vertex_buffer.index_buffer = {}, vertex_buffer.vertex_count = points.size();
vertex_buffer.index_type = IndexType::kNone;

return GeometryResult{
.type = PrimitiveType::kTriangle,
.type = PrimitiveType::kTriangleStrip,
.vertex_buffer = vertex_buffer,
.transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
entity.GetTransformation(),
Expand Down Expand Up @@ -86,24 +84,20 @@ GeometryResult FillPathGeometry::GetPositionUVBuffer(

if (path_.GetFillType() == FillType::kNonZero && //
path_.IsConvex()) {
auto [points, indices] = renderer.GetTessellator()->TessellateConvex(
auto points = renderer.GetTessellator()->TessellateConvex(
path_, entity.GetTransformation().GetMaxBasisLength());

VertexBufferBuilder<VS::PerVertexData> vertex_builder;
vertex_builder.Reserve(points.size());
vertex_builder.ReserveIndices(indices.size());
for (auto i = 0u; i < points.size(); i++) {
VS::PerVertexData data;
data.position = points[i];
data.texture_coords = uv_transform * points[i];
vertex_builder.AppendVertex(data);
}
for (auto i = 0u; i < indices.size(); i++) {
vertex_builder.AppendIndex(indices[i]);
}

return GeometryResult{
.type = PrimitiveType::kTriangle,
.type = PrimitiveType::kTriangleStrip,
.vertex_buffer =
vertex_builder.CreateVertexBuffer(pass.GetTransientsBuffer()),
.transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
Expand Down
6 changes: 3 additions & 3 deletions impeller/geometry/geometry_benchmarks.cc
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ static void BM_Convex(benchmark::State& state, Args&&... args) {
auto points = std::make_unique<std::vector<Point>>();
points->reserve(2048);
while (state.KeepRunning()) {
auto [points, index] = tess.TessellateConvex(path, 1.0f);
single_point_count = index.size();
point_count += index.size();
auto points = tess.TessellateConvex(path, 1.0f);
single_point_count = points.size();
point_count += points.size();
}
state.counters["SinglePointCount"] = single_point_count;
state.counters["TotalPointCount"] = point_count;
Expand Down
39 changes: 25 additions & 14 deletions impeller/tessellator/tessellator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -231,10 +231,9 @@ Tessellator::Result Tessellator::Tessellate(const Path& path,
return Result::kSuccess;
}

std::pair<std::vector<Point>, std::vector<uint16_t>>
Tessellator::TessellateConvex(const Path& path, Scalar tolerance) {
std::vector<Point> Tessellator::TessellateConvex(const Path& path,
Scalar tolerance) {
std::vector<Point> output;
std::vector<uint16_t> indices;

point_buffer_->clear();
auto polyline =
Expand All @@ -243,29 +242,41 @@ Tessellator::TessellateConvex(const Path& path, Scalar tolerance) {
point_buffer_ = std::move(point_buffer);
});

output.reserve(polyline.points->size() +
(4 * (polyline.contours.size() - 1)));
for (auto j = 0u; j < polyline.contours.size(); j++) {
auto [start, end] = polyline.GetContourPointBounds(j);
auto center = polyline.GetPoint(start);
auto first_point = polyline.GetPoint(start);

// Some polygons will not self close and an additional triangle
// must be inserted, others will self close and we need to avoid
// inserting an extra triangle.
if (polyline.GetPoint(end - 1) == polyline.GetPoint(start)) {
if (polyline.GetPoint(end - 1) == first_point) {
end--;
}
output.emplace_back(center);
output.emplace_back(polyline.GetPoint(start + 1));

for (auto i = start + 2; i < end; i++) {
const auto& point_b = polyline.GetPoint(i);
output.emplace_back(point_b);
if (j > 0) {
// Triangle strip break.
output.emplace_back(output.back());
output.emplace_back(first_point);
output.emplace_back(first_point);
} else {
output.emplace_back(first_point);
}

indices.emplace_back(0);
indices.emplace_back(i - 1);
indices.emplace_back(i);
size_t a = start + 1;
size_t b = end - 1;
while (a < b) {
output.emplace_back(polyline.GetPoint(a));
output.emplace_back(polyline.GetPoint(b));
a++;
b--;
}
if (a == b) {
output.emplace_back(polyline.GetPoint(a));
}
}
return std::make_pair(output, indices);
return output;
}

void DestroyTessellator(TESStesselator* tessellator) {
Expand Down
7 changes: 2 additions & 5 deletions impeller/tessellator/tessellator.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,9 @@ class Tessellator {
/// Matrix::GetMaxBasisLength of the CTM applied to the
/// path for rendering.
///
/// @return A point vector containing the vertices and a vector of indices
/// into the point vector.
/// @return A point vector containing the vertices in triangle strip format.
///
std::pair<std::vector<Point>, std::vector<uint16_t>> TessellateConvex(
const Path& path,
Scalar tolerance);
std::vector<Point> TessellateConvex(const Path& path, Scalar tolerance);

private:
/// Used for polyline generation.
Expand Down
33 changes: 13 additions & 20 deletions impeller/tessellator/tessellator_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -129,34 +129,27 @@ TEST(TessellatorTest, TessellateConvex) {
{
Tessellator t;
// Sanity check simple rectangle.
auto [pts, indices] = t.TessellateConvex(
auto pts = t.TessellateConvex(
PathBuilder{}.AddRect(Rect::MakeLTRB(0, 0, 10, 10)).TakePath(), 1.0);

std::vector<Point> expected = {
{0, 0}, {10, 0}, {10, 10}, {0, 10}, //
{0, 0}, {10, 0}, {0, 10}, {10, 10}, //
};
std::vector<uint16_t> expected_indices = {0, 1, 2, 0, 2, 3};
ASSERT_EQ(pts, expected);
ASSERT_EQ(indices, expected_indices);
EXPECT_EQ(pts, expected);
}

{
Tessellator t;
auto [pts, indices] =
t.TessellateConvex(PathBuilder{}
.AddRect(Rect::MakeLTRB(0, 0, 10, 10))
.AddRect(Rect::MakeLTRB(20, 20, 30, 30))
.TakePath(),
1.0);

std::vector<Point> expected = {
{0, 0}, {10, 0}, {10, 10}, {0, 10}, //
{20, 20}, {30, 20}, {30, 30}, {20, 30} //
};
std::vector<uint16_t> expected_indices = {0, 1, 2, 0, 2, 3,
0, 6, 7, 0, 7, 8};
ASSERT_EQ(pts, expected);
ASSERT_EQ(indices, expected_indices);
auto pts = t.TessellateConvex(PathBuilder{}
.AddRect(Rect::MakeLTRB(0, 0, 10, 10))
.AddRect(Rect::MakeLTRB(20, 20, 30, 30))
.TakePath(),
1.0);

std::vector<Point> expected = {{0, 0}, {10, 0}, {0, 10}, {10, 10},
{10, 10}, {20, 20}, {20, 20}, {30, 20},
{20, 30}, {30, 30}};
EXPECT_EQ(pts, expected);
}
}

Expand Down

0 comments on commit ae30d33

Please sign in to comment.