blob: 440c626fd1a45995a144db5c5efa0db60a1716fd [file] [edit]
/*
* Copyright 2026 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "bench/Benchmark.h"
#include "bench/Tiger.h"
#include "include/core/SkPath.h"
#include "include/private/SkTArray.h"
#include "src/gpu/ganesh/geometry/GrPathUtils.h"
#include "src/gpu/graphite/sparse_strips/Flatten.h"
#include "src/gpu/graphite/sparse_strips/Polyline.h"
#include <vector>
namespace {
using namespace skgpu::graphite;
template <FlattenMode kMode> class FlattenBench : public Benchmark {
public:
FlattenBench() : fPaths(Tiger::GetTigerPaths()) {
fName.printf("SparseStrips_Flatten_%s", kMode == FlattenMode::kScalar ? "Scalar" : "SIMD");
}
protected:
const char* onGetName() override { return fName.c_str(); }
void onDraw(int loops, SkCanvas*) override {
Flatten flattener;
Polyline polyline;
for (int i = 0; i < loops; ++i) {
for (auto& path : fPaths) {
flattener.processPaths<kMode>(
path, SkMatrix(), Tiger::kTigerWidthF, Tiger::kTigerHeightF, &polyline);
}
polyline.reset();
}
}
private:
SkString fName;
std::vector<SkPath> fPaths;
};
class GrLegacyBench : public Benchmark {
public:
// Match the tolerances of Flatten.
static constexpr SkScalar kTolerance = Flatten::kQuadErrTolerance;
static constexpr SkScalar kToleranceSqd = Flatten::kQuadTolerance2;
GrLegacyBench() : fName("SparseStrips_FlattenLegacy_Ganesh"), fPaths(Tiger::GetTigerPaths()) {}
protected:
const char* onGetName() override { return fName.c_str(); }
void onDraw(int loops, SkCanvas*) override {
SkAutoConicToQuads converter;
skia_private::TArray<SkPoint> pointBuffer;
skia_private::TArray<SkPoint, true> cubicQuadsBuffer;
for (int i = 0; i < loops; ++i) {
for (auto& path : fPaths) {
SkPath::Iter iter(path, false);
SkPoint pts[4];
SkPath::Verb verb;
while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
switch (verb) {
case SkPath::kMove_Verb:
case SkPath::kLine_Verb:
pointBuffer.push_back(pts[0]);
if (verb == SkPath::kLine_Verb) {
pointBuffer.push_back(pts[1]);
}
break;
case SkPath::kQuad_Verb: {
this->flattenQuad(pts, &pointBuffer);
break;
}
case SkPath::kConic_Verb: {
const SkPoint* quadPts =
converter.computeQuads(pts, iter.conicWeight(), kTolerance);
int quadCount = converter.countQuads();
for (int j = 0; j < quadCount; ++j) {
this->flattenQuad(&quadPts[j * 2], &pointBuffer);
}
break;
}
case SkPath::kCubic_Verb: {
cubicQuadsBuffer.clear();
GrPathUtils::convertCubicToQuads(pts, kTolerance, &cubicQuadsBuffer);
int quadCount = cubicQuadsBuffer.empty()
? 0
: (cubicQuadsBuffer.size() - 1) / 2;
for (int j = 0; j < quadCount; ++j) {
this->flattenQuad(&cubicQuadsBuffer[j * 2], &pointBuffer);
}
break;
}
case SkPath::kClose_Verb:
default:
break;
}
}
}
pointBuffer.clear();
}
}
private:
void flattenQuad(const SkPoint pts[3], skia_private::TArray<SkPoint>* pointBuffer) const {
uint32_t count = GrPathUtils::quadraticPointCount(pts, kTolerance);
SkPoint* outPtr = pointBuffer->push_back_n(count);
GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2], kToleranceSqd, &outPtr, count);
}
SkString fName;
std::vector<SkPath> fPaths;
};
} // namespace
DEF_BENCH(return (new FlattenBench<skgpu::graphite::FlattenMode::kScalar>());)
DEF_BENCH(return (new FlattenBench<skgpu::graphite::FlattenMode::kSimd>());)
DEF_BENCH(return (new GrLegacyBench());)