Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions impeller/entity/geometry/stroke_path_geometry.cc
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,44 @@ CapProc<VertexWriter> GetCapProc(Cap stroke_cap) {
}
} // namespace

std::vector<SolidFillVertexShader::PerVertexData>
StrokePathGeometry::GenerateSolidStrokeVertices(const Path::Polyline& polyline,
Scalar stroke_width,
Scalar miter_limit,
Join stroke_join,
Cap stroke_cap,
Scalar scale) {
auto scaled_miter_limit = stroke_width * miter_limit * 0.5f;
auto join_proc = GetJoinProc<PositionWriter>(stroke_join);
auto cap_proc = GetCapProc<PositionWriter>(stroke_cap);
StrokeGenerator stroke_generator(polyline, stroke_width, scaled_miter_limit,
join_proc, cap_proc, scale);
PositionWriter vtx_builder;
stroke_generator.Generate(vtx_builder);
return vtx_builder.GetData();
}

std::vector<TextureFillVertexShader::PerVertexData>
StrokePathGeometry::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) {
auto scaled_miter_limit = stroke_width * miter_limit * 0.5f;
auto join_proc = GetJoinProc<PositionUVWriter>(stroke_join);
auto cap_proc = GetCapProc<PositionUVWriter>(stroke_cap);
StrokeGenerator stroke_generator(polyline, stroke_width, scaled_miter_limit,
join_proc, cap_proc, scale);
PositionUVWriter vtx_builder(texture_origin, texture_size, effect_transform);
stroke_generator.Generate(vtx_builder);
return vtx_builder.GetData();
}

StrokePathGeometry::StrokePathGeometry(const Path& path,
Scalar stroke_width,
Scalar miter_limit,
Expand Down
21 changes: 21 additions & 0 deletions impeller/entity/geometry/stroke_path_geometry.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,27 @@ class StrokePathGeometry final : public Geometry {
// |Geometry|
std::optional<Rect> GetCoverage(const Matrix& transform) const override;

// Private for benchmarking and debugging
static std::vector<SolidFillVertexShader::PerVertexData>
GenerateSolidStrokeVertices(const Path::Polyline& polyline,
Scalar stroke_width,
Scalar miter_limit,
Join stroke_join,
Cap stroke_cap,
Scalar 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);
friend class ImpellerBenchmarkAccessor;

bool SkipRendering() const;

Path path_;
Expand Down
1 change: 1 addition & 0 deletions impeller/geometry/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ executable("geometry_benchmarks") {
sources = [ "geometry_benchmarks.cc" ]
deps = [
":geometry",
"../entity",
"../tessellator",
"//flutter/benchmarking",
]
Expand Down
100 changes: 100 additions & 0 deletions impeller/geometry/geometry_benchmarks.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,45 @@

#include "flutter/benchmarking/benchmarking.h"

#include "flutter/impeller/entity/solid_fill.vert.h"
#include "flutter/impeller/entity/texture_fill.vert.h"

#include "impeller/entity/geometry/stroke_path_geometry.h"
#include "impeller/geometry/path.h"
#include "impeller/geometry/path_builder.h"
#include "impeller/tessellator/tessellator.h"

namespace impeller {

class ImpellerBenchmarkAccessor {
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 {
/// A path with many connected cubic components, including
/// overlaps/self-intersections/multi-contour.
Expand Down Expand Up @@ -64,6 +97,48 @@ static void BM_Polyline(benchmark::State& state, Args&&... args) {
state.counters["TotalPointCount"] = point_count;
}

template <class... Args>
static void BM_StrokePolyline(benchmark::State& state, Args&&... args) {
auto args_tuple = std::make_tuple(std::move(args)...);
auto path = std::get<Path>(args_tuple);
auto cap = std::get<Cap>(args_tuple);
auto join = std::get<Join>(args_tuple);
auto generate_uv = std::get<bool>(args_tuple);

const Scalar stroke_width = 5.0f;
const Scalar miter_limit = 10.0f;
const Scalar scale = 1.0f;
const Point texture_origin = Point(0, 0);
const Size texture_size = Size(100, 100);
const Matrix effect_transform = Matrix::MakeScale({2.0f, 2.0f, 1.0f});

auto points = std::make_unique<std::vector<Point>>();
points->reserve(2048);
auto polyline =
path.CreatePolyline(1.0f, std::move(points),
[&points](Path::Polyline::PointBufferPtr reclaimed) {
points = std::move(reclaimed);
});

size_t point_count = 0u;
size_t single_point_count = 0u;
while (state.KeepRunning()) {
if (generate_uv) {
auto vertices = ImpellerBenchmarkAccessor::GenerateSolidStrokeVerticesUV(
polyline, stroke_width, miter_limit, join, cap, scale, //
texture_origin, texture_size, effect_transform);
single_point_count = vertices.size();
} else {
auto vertices = ImpellerBenchmarkAccessor::GenerateSolidStrokeVertices(
polyline, stroke_width, miter_limit, join, cap, scale);
single_point_count = vertices.size();
}
point_count += single_point_count;
}
state.counters["SinglePointCount"] = single_point_count;
state.counters["TotalPointCount"] = point_count;
}

template <class... Args>
static void BM_Convex(benchmark::State& state, Args&&... args) {
auto args_tuple = std::make_tuple(std::move(args)...);
Expand All @@ -82,11 +157,36 @@ static void BM_Convex(benchmark::State& state, Args&&... args) {
state.counters["TotalPointCount"] = point_count;
}

#define MAKE_STROKE_BENCHMARK_CAPTURE(path, cap, join) \
BENCHMARK_CAPTURE(BM_StrokePolyline, stroke_##path##_##cap##_##join, \
Create##path(), Cap::k##cap, Join::k##join, false)

#define MAKE_STROKE_BENCHMARK_CAPTURE_UV(path, cap, join) \
BENCHMARK_CAPTURE(BM_StrokePolyline, stroke_##path##_##cap##_##join##_uv, \
Create##path(), Cap::k##cap, Join::k##join, true)

#define MAKE_STROKE_BENCHMARK_CAPTURE_CAPS_JOINS(path, uv) \
MAKE_STROKE_BENCHMARK_CAPTURE##uv(path, Butt, Bevel); \
MAKE_STROKE_BENCHMARK_CAPTURE##uv(path, Butt, Miter); \
MAKE_STROKE_BENCHMARK_CAPTURE##uv(path, Butt, Round); \
MAKE_STROKE_BENCHMARK_CAPTURE##uv(path, Square, Bevel); \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why leave off combos like Square + Miter?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could add them. I just thought that we should test one attribute at a time, as I describe in the "notes" comment above.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, yeah - makes sense. I don't think we need the full combinatorial set.

Copy link
Contributor Author

@flar flar Feb 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though all combinations are tested for both uv and non-uv. I could go either way on filling out the rest of the cap/join combinations. Note that it would take us from 5 to 9 variations * 2 path types * UV/nonUV

MAKE_STROKE_BENCHMARK_CAPTURE##uv(path, Round, Bevel)

#define MAKE_STROKE_BENCHMARK_CAPTURE_UVS(path) \
MAKE_STROKE_BENCHMARK_CAPTURE_CAPS_JOINS(path, ); \
MAKE_STROKE_BENCHMARK_CAPTURE_CAPS_JOINS(path, _UV)

BENCHMARK_CAPTURE(BM_Polyline, cubic_polyline, CreateCubic(), false);
BENCHMARK_CAPTURE(BM_Polyline, cubic_polyline_tess, CreateCubic(), true);
MAKE_STROKE_BENCHMARK_CAPTURE_UVS(Cubic);

BENCHMARK_CAPTURE(BM_Polyline, quad_polyline, CreateQuadratic(), false);
BENCHMARK_CAPTURE(BM_Polyline, quad_polyline_tess, CreateQuadratic(), true);
MAKE_STROKE_BENCHMARK_CAPTURE_UVS(Quadratic);

BENCHMARK_CAPTURE(BM_Convex, rrect_convex, CreateRRect(), true);
MAKE_STROKE_BENCHMARK_CAPTURE(RRect, Butt, Bevel);
MAKE_STROKE_BENCHMARK_CAPTURE_UV(RRect, Butt, Bevel);

namespace {

Expand Down