2020-04-23 21:52:24 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2020 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "bench/Benchmark.h"
|
2020-07-06 17:45:34 +00:00
|
|
|
#include "include/gpu/GrDirectContext.h"
|
2020-05-14 01:18:46 +00:00
|
|
|
#include "src/core/SkPathPriv.h"
|
2021-05-21 21:54:23 +00:00
|
|
|
#include "src/core/SkRectPriv.h"
|
2020-10-14 15:23:11 +00:00
|
|
|
#include "src/gpu/GrDirectContextPriv.h"
|
2021-05-11 14:00:12 +00:00
|
|
|
#include "src/gpu/geometry/GrWangsFormula.h"
|
2020-11-09 21:13:39 +00:00
|
|
|
#include "src/gpu/mock/GrMockOpTarget.h"
|
2020-05-24 20:55:54 +00:00
|
|
|
#include "src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h"
|
2021-06-02 01:22:05 +00:00
|
|
|
#include "src/gpu/tessellate/GrPathCurveTessellator.h"
|
|
|
|
#include "src/gpu/tessellate/GrPathWedgeTessellator.h"
|
2021-04-20 06:45:50 +00:00
|
|
|
#include "src/gpu/tessellate/GrStrokeFixedCountTessellator.h"
|
2021-02-04 16:47:40 +00:00
|
|
|
#include "src/gpu/tessellate/GrStrokeHardwareTessellator.h"
|
2020-04-28 05:40:03 +00:00
|
|
|
#include "tools/ToolUtils.h"
|
2020-12-09 23:46:22 +00:00
|
|
|
#include <vector>
|
2020-04-23 21:52:24 +00:00
|
|
|
|
2021-06-01 19:40:03 +00:00
|
|
|
using ShaderFlags = GrStrokeTessellationShader::ShaderFlags;
|
2021-02-18 18:29:49 +00:00
|
|
|
|
2020-04-23 21:52:24 +00:00
|
|
|
// This is the number of cubics in desk_chalkboard.skp. (There are no quadratics in the chalkboard.)
|
|
|
|
constexpr static int kNumCubicsInChalkboard = 47182;
|
|
|
|
|
2020-11-09 21:13:39 +00:00
|
|
|
static sk_sp<GrDirectContext> make_mock_context() {
|
|
|
|
GrMockOptions mockOptions;
|
|
|
|
mockOptions.fDrawInstancedSupport = true;
|
|
|
|
mockOptions.fMaxTessellationSegments = 64;
|
|
|
|
mockOptions.fMapBufferFlags = GrCaps::kCanMap_MapFlag;
|
|
|
|
mockOptions.fConfigOptions[(int)GrColorType::kAlpha_8].fRenderability =
|
|
|
|
GrMockOptions::ConfigOptions::Renderability::kMSAA;
|
|
|
|
mockOptions.fConfigOptions[(int)GrColorType::kAlpha_8].fTexturable = true;
|
|
|
|
mockOptions.fIntegerSupport = true;
|
|
|
|
|
|
|
|
GrContextOptions ctxOptions;
|
|
|
|
ctxOptions.fGpuPathRenderers = GpuPathRenderers::kTessellation;
|
2021-02-25 00:41:44 +00:00
|
|
|
ctxOptions.fEnableExperimentalHardwareTessellation = true;
|
2020-11-09 21:13:39 +00:00
|
|
|
|
|
|
|
return GrDirectContext::MakeMock(&mockOptions, ctxOptions);
|
|
|
|
}
|
|
|
|
|
2021-05-21 21:54:23 +00:00
|
|
|
static SkPath make_cubic_path(int maxPow2) {
|
2020-04-23 21:52:24 +00:00
|
|
|
SkRandom rand;
|
|
|
|
SkPath path;
|
|
|
|
for (int i = 0; i < kNumCubicsInChalkboard/2; ++i) {
|
2021-05-21 21:54:23 +00:00
|
|
|
float x = std::ldexp(rand.nextF(), (i % maxPow2)) / 1e3f;
|
2020-04-23 21:52:24 +00:00
|
|
|
path.cubicTo(111.625f*x, 308.188f*x, 764.62f*x, -435.688f*x, 742.63f*x, 85.187f*x);
|
|
|
|
path.cubicTo(764.62f*x, -435.688f*x, 111.625f*x, 308.188f*x, 0, 0);
|
|
|
|
}
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
2021-02-04 18:07:03 +00:00
|
|
|
static SkPath make_conic_path() {
|
|
|
|
SkRandom rand;
|
|
|
|
SkPath path;
|
|
|
|
for (int i = 0; i < kNumCubicsInChalkboard / 40; ++i) {
|
|
|
|
for (int j = -10; j <= 10; j++) {
|
|
|
|
const float x = std::ldexp(rand.nextF(), (i % 18)) / 1e3f;
|
|
|
|
const float w = std::ldexp(1 + rand.nextF(), j);
|
|
|
|
path.conicTo(111.625f * x, 308.188f * x, 764.62f * x, -435.688f * x, w);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
2021-08-26 13:56:55 +00:00
|
|
|
// This serves as a base class for benchmarking individual methods on PathTessellateOp.
|
2021-01-15 20:12:50 +00:00
|
|
|
class PathTessellateBenchmark : public Benchmark {
|
2020-04-23 21:52:24 +00:00
|
|
|
public:
|
2021-01-15 20:12:50 +00:00
|
|
|
PathTessellateBenchmark(const char* subName, const SkPath& p, const SkMatrix& m)
|
|
|
|
: fPath(p), fMatrix(m) {
|
2020-04-23 21:52:24 +00:00
|
|
|
fName.printf("tessellate_%s", subName);
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* onGetName() override { return fName.c_str(); }
|
|
|
|
bool isSuitableFor(Backend backend) final { return backend == kNonRendering_Backend; }
|
|
|
|
|
2021-01-15 20:12:50 +00:00
|
|
|
protected:
|
2020-11-03 21:09:16 +00:00
|
|
|
void onDelayedSetup() override {
|
2020-11-09 21:13:39 +00:00
|
|
|
fTarget = std::make_unique<GrMockOpTarget>(make_mock_context());
|
2020-11-03 21:09:16 +00:00
|
|
|
}
|
|
|
|
|
2020-04-23 21:52:24 +00:00
|
|
|
void onDraw(int loops, SkCanvas*) final {
|
2020-11-03 21:09:16 +00:00
|
|
|
if (!fTarget->mockContext()) {
|
2020-05-27 15:43:34 +00:00
|
|
|
SkDebugf("ERROR: could not create mock context.");
|
|
|
|
return;
|
|
|
|
}
|
2020-04-23 21:52:24 +00:00
|
|
|
for (int i = 0; i < loops; ++i) {
|
2021-01-15 20:12:50 +00:00
|
|
|
this->runBench();
|
2020-11-03 21:09:16 +00:00
|
|
|
fTarget->resetAllocator();
|
2020-04-23 21:52:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-15 20:12:50 +00:00
|
|
|
virtual void runBench() = 0;
|
2020-04-23 21:52:24 +00:00
|
|
|
|
|
|
|
SkString fName;
|
2021-01-15 20:12:50 +00:00
|
|
|
std::unique_ptr<GrMockOpTarget> fTarget;
|
|
|
|
const SkPath fPath;
|
2021-01-29 20:22:33 +00:00
|
|
|
const SkMatrix fMatrix;
|
2020-04-23 21:52:24 +00:00
|
|
|
};
|
|
|
|
|
2021-01-15 20:12:50 +00:00
|
|
|
#define DEF_PATH_TESS_BENCH(NAME, PATH, MATRIX) \
|
|
|
|
class PathTessellateBenchmark_##NAME : public PathTessellateBenchmark { \
|
2020-05-24 20:55:54 +00:00
|
|
|
public: \
|
2021-01-15 20:12:50 +00:00
|
|
|
PathTessellateBenchmark_##NAME() : PathTessellateBenchmark(#NAME, (PATH), (MATRIX)) {} \
|
|
|
|
void runBench() override; \
|
2020-05-24 20:55:54 +00:00
|
|
|
}; \
|
2021-01-15 20:12:50 +00:00
|
|
|
DEF_BENCH( return new PathTessellateBenchmark_##NAME(); ); \
|
|
|
|
void PathTessellateBenchmark_##NAME::runBench()
|
2020-05-14 01:18:46 +00:00
|
|
|
|
2021-07-27 16:00:12 +00:00
|
|
|
static const SkMatrix gAlmostIdentity = SkMatrix::MakeAll(
|
|
|
|
1.0001f, 0.0001f, 0.0001f,
|
|
|
|
-.0001f, 0.9999f, -.0001f,
|
|
|
|
0, 0, 1);
|
|
|
|
|
|
|
|
DEF_PATH_TESS_BENCH(GrPathCurveTessellator, make_cubic_path(8), SkMatrix::I()) {
|
2021-05-25 16:11:46 +00:00
|
|
|
SkArenaAlloc arena(1024);
|
2021-06-09 19:49:43 +00:00
|
|
|
GrPipeline noVaryingsPipeline(GrScissorTest::kDisabled, SkBlendMode::kSrcOver,
|
|
|
|
GrSwizzle::RGBA());
|
2021-06-02 01:22:05 +00:00
|
|
|
auto tess = GrPathCurveTessellator::Make(&arena, fMatrix, SK_PMColor4fTRANSPARENT,
|
2021-06-09 22:28:11 +00:00
|
|
|
GrPathCurveTessellator::DrawInnerFan::kNo,
|
2021-06-08 22:25:46 +00:00
|
|
|
fTarget->caps().minPathVerbsForHwTessellation(),
|
2021-06-09 19:49:43 +00:00
|
|
|
noVaryingsPipeline, fTarget->caps());
|
2021-07-28 15:43:52 +00:00
|
|
|
tess->prepare(fTarget.get(), SkRectPriv::MakeLargest(), {gAlmostIdentity, fPath},
|
|
|
|
fPath.countVerbs());
|
2020-05-24 20:55:54 +00:00
|
|
|
}
|
2020-05-21 21:50:48 +00:00
|
|
|
|
2021-05-21 21:54:23 +00:00
|
|
|
DEF_PATH_TESS_BENCH(GrPathWedgeTessellator, make_cubic_path(8), SkMatrix::I()) {
|
2021-05-25 16:11:46 +00:00
|
|
|
SkArenaAlloc arena(1024);
|
2021-06-09 19:49:43 +00:00
|
|
|
GrPipeline noVaryingsPipeline(GrScissorTest::kDisabled, SkBlendMode::kSrcOver,
|
|
|
|
GrSwizzle::RGBA());
|
2021-06-09 06:12:59 +00:00
|
|
|
auto tess = GrPathWedgeTessellator::Make(&arena, fMatrix, SK_PMColor4fTRANSPARENT,
|
|
|
|
fTarget->caps().minPathVerbsForHwTessellation(),
|
2021-06-09 19:49:43 +00:00
|
|
|
noVaryingsPipeline, fTarget->caps());
|
2021-07-28 15:43:52 +00:00
|
|
|
tess->prepare(fTarget.get(), SkRectPriv::MakeLargest(), {gAlmostIdentity, fPath},
|
|
|
|
fPath.countVerbs());
|
2020-05-24 20:55:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void benchmark_wangs_formula_cubic_log2(const SkMatrix& matrix, const SkPath& path) {
|
|
|
|
int sum = 0;
|
|
|
|
GrVectorXform xform(matrix);
|
|
|
|
for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
|
|
|
|
if (verb == SkPathVerb::kCubic) {
|
|
|
|
sum += GrWangsFormula::cubic_log2(4, pts, xform);
|
|
|
|
}
|
2020-05-24 20:48:56 +00:00
|
|
|
}
|
2020-05-24 20:55:54 +00:00
|
|
|
// Don't let the compiler optimize away GrWangsFormula::cubic_log2.
|
|
|
|
if (sum <= 0) {
|
|
|
|
SK_ABORT("sum should be > 0.");
|
2020-05-24 20:48:56 +00:00
|
|
|
}
|
2020-05-24 20:55:54 +00:00
|
|
|
}
|
2020-05-24 20:06:12 +00:00
|
|
|
|
2021-05-21 21:54:23 +00:00
|
|
|
DEF_PATH_TESS_BENCH(wangs_formula_cubic_log2, make_cubic_path(18), SkMatrix::I()) {
|
2021-01-15 20:12:50 +00:00
|
|
|
benchmark_wangs_formula_cubic_log2(fMatrix, fPath);
|
2020-05-24 20:55:54 +00:00
|
|
|
}
|
2020-05-24 20:06:12 +00:00
|
|
|
|
2021-05-21 21:54:23 +00:00
|
|
|
DEF_PATH_TESS_BENCH(wangs_formula_cubic_log2_scale, make_cubic_path(18),
|
2021-01-15 20:12:50 +00:00
|
|
|
SkMatrix::Scale(1.1f, 0.9f)) {
|
|
|
|
benchmark_wangs_formula_cubic_log2(fMatrix, fPath);
|
2020-05-24 20:55:54 +00:00
|
|
|
}
|
|
|
|
|
2021-05-21 21:54:23 +00:00
|
|
|
DEF_PATH_TESS_BENCH(wangs_formula_cubic_log2_affine, make_cubic_path(18),
|
2021-01-15 20:12:50 +00:00
|
|
|
SkMatrix::MakeAll(.9f,0.9f,0, 1.1f,1.1f,0, 0,0,1)) {
|
|
|
|
benchmark_wangs_formula_cubic_log2(fMatrix, fPath);
|
2020-05-24 20:55:54 +00:00
|
|
|
}
|
|
|
|
|
2021-02-04 18:07:03 +00:00
|
|
|
static void benchmark_wangs_formula_conic(const SkMatrix& matrix, const SkPath& path) {
|
|
|
|
int sum = 0;
|
|
|
|
GrVectorXform xform(matrix);
|
|
|
|
for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
|
|
|
|
if (verb == SkPathVerb::kConic) {
|
2021-06-02 18:00:01 +00:00
|
|
|
sum += GrWangsFormula::conic(4, pts, *w, xform);
|
2021-02-04 18:07:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Don't let the compiler optimize away GrWangsFormula::conic.
|
|
|
|
if (sum <= 0) {
|
|
|
|
SK_ABORT("sum should be > 0.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void benchmark_wangs_formula_conic_log2(const SkMatrix& matrix, const SkPath& path) {
|
|
|
|
int sum = 0;
|
|
|
|
GrVectorXform xform(matrix);
|
|
|
|
for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
|
|
|
|
if (verb == SkPathVerb::kConic) {
|
2021-06-02 18:00:01 +00:00
|
|
|
sum += GrWangsFormula::conic_log2(4, pts, *w, xform);
|
2021-02-04 18:07:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Don't let the compiler optimize away GrWangsFormula::conic.
|
|
|
|
if (sum <= 0) {
|
|
|
|
SK_ABORT("sum should be > 0.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DEF_PATH_TESS_BENCH(wangs_formula_conic, make_conic_path(), SkMatrix::I()) {
|
|
|
|
benchmark_wangs_formula_conic(fMatrix, fPath);
|
|
|
|
}
|
|
|
|
|
|
|
|
DEF_PATH_TESS_BENCH(wangs_formula_conic_log2, make_conic_path(), SkMatrix::I()) {
|
|
|
|
benchmark_wangs_formula_conic_log2(fMatrix, fPath);
|
|
|
|
}
|
|
|
|
|
2020-09-23 17:07:20 +00:00
|
|
|
DEF_PATH_TESS_BENCH(middle_out_triangulation,
|
|
|
|
ToolUtils::make_star(SkRect::MakeWH(500, 500), kNumCubicsInChalkboard),
|
2021-01-15 20:12:50 +00:00
|
|
|
SkMatrix::I()) {
|
2021-03-31 16:40:29 +00:00
|
|
|
sk_sp<const GrBuffer> buffer;
|
2020-05-24 20:55:54 +00:00
|
|
|
int baseVertex;
|
2021-05-14 20:48:54 +00:00
|
|
|
GrVertexWriter vertexWriter = static_cast<SkPoint*>(fTarget->makeVertexSpace(
|
2021-03-31 16:40:29 +00:00
|
|
|
sizeof(SkPoint), kNumCubicsInChalkboard, &buffer, &baseVertex));
|
2021-07-26 17:27:05 +00:00
|
|
|
int numTrianglesWritten;
|
2021-07-27 16:00:12 +00:00
|
|
|
GrMiddleOutPolygonTriangulator::WritePathInnerFan(std::move(vertexWriter), 0, 0,
|
|
|
|
gAlmostIdentity, fPath, &numTrianglesWritten);
|
2020-05-24 20:55:54 +00:00
|
|
|
}
|
2020-09-23 17:07:20 +00:00
|
|
|
|
2021-02-22 19:13:49 +00:00
|
|
|
using PathStrokeList = GrStrokeTessellator::PathStrokeList;
|
2021-05-26 16:21:56 +00:00
|
|
|
using MakeTessellatorFn = std::unique_ptr<GrStrokeTessellator>(*)(ShaderFlags, const GrShaderCaps&,
|
|
|
|
const SkMatrix&, PathStrokeList*,
|
2021-05-14 21:57:39 +00:00
|
|
|
std::array<float, 2>, const
|
|
|
|
SkRect&);
|
2021-04-20 06:45:50 +00:00
|
|
|
|
2021-05-14 21:57:39 +00:00
|
|
|
static std::unique_ptr<GrStrokeTessellator> make_hw_tessellator(
|
2021-05-26 16:21:56 +00:00
|
|
|
ShaderFlags shaderFlags, const GrShaderCaps& shaderCaps, const SkMatrix& viewMatrix,
|
|
|
|
PathStrokeList* pathStrokeList, std::array<float, 2> matrixMinMaxScales,
|
|
|
|
const SkRect& strokeCullBounds) {
|
2021-07-01 17:17:53 +00:00
|
|
|
return std::make_unique<GrStrokeHardwareTessellator>(shaderCaps, shaderFlags, viewMatrix,
|
2021-05-26 16:21:56 +00:00
|
|
|
pathStrokeList, matrixMinMaxScales,
|
|
|
|
strokeCullBounds);
|
2021-04-20 06:45:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static std::unique_ptr<GrStrokeTessellator> make_fixed_count_tessellator(
|
2021-07-01 16:58:55 +00:00
|
|
|
ShaderFlags shaderFlags, const GrShaderCaps& shaderCaps, const SkMatrix& viewMatrix,
|
2021-05-26 16:21:56 +00:00
|
|
|
PathStrokeList* pathStrokeList, std::array<float, 2> matrixMinMaxScales,
|
|
|
|
const SkRect& strokeCullBounds) {
|
2021-07-01 17:17:53 +00:00
|
|
|
return std::make_unique<GrStrokeFixedCountTessellator>(shaderCaps, shaderFlags, viewMatrix,
|
|
|
|
pathStrokeList, matrixMinMaxScales,
|
|
|
|
strokeCullBounds);
|
2021-04-20 06:45:50 +00:00
|
|
|
}
|
|
|
|
|
2021-02-22 19:13:49 +00:00
|
|
|
using MakePathStrokesFn = std::vector<PathStrokeList>(*)();
|
|
|
|
|
|
|
|
static std::vector<PathStrokeList> make_simple_cubic_path() {
|
|
|
|
auto path = SkPath().moveTo(0, 0);
|
|
|
|
for (int i = 0; i < kNumCubicsInChalkboard/2; ++i) {
|
|
|
|
path.cubicTo(100, 0, 50, 100, 100, 100);
|
|
|
|
path.cubicTo(0, -100, 200, 100, 0, 0);
|
|
|
|
}
|
|
|
|
SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
|
|
|
|
stroke.setStrokeStyle(8);
|
|
|
|
stroke.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kMiter_Join, 4);
|
|
|
|
return {{path, stroke, SK_PMColor4fWHITE}};
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generates a list of paths that resemble the MotionMark benchmark.
|
|
|
|
static std::vector<PathStrokeList> make_motionmark_paths() {
|
|
|
|
std::vector<PathStrokeList> pathStrokes;
|
|
|
|
SkRandom rand;
|
|
|
|
for (int i = 0; i < 8702; ++i) {
|
|
|
|
// The number of paths with a given number of verbs in the MotionMark bench gets cut in half
|
|
|
|
// every time the number of verbs increases by 1.
|
|
|
|
int numVerbs = 28 - SkNextLog2(rand.nextRangeU(0, (1 << 27) - 1));
|
|
|
|
SkPath path;
|
|
|
|
for (int j = 0; j < numVerbs; ++j) {
|
|
|
|
switch (rand.nextU() & 3) {
|
|
|
|
case 0:
|
|
|
|
case 1:
|
|
|
|
path.lineTo(rand.nextRangeF(0, 150), rand.nextRangeF(0, 150));
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if (rand.nextULessThan(10) == 0) {
|
|
|
|
// Cusp.
|
|
|
|
auto [x, y] = (path.isEmpty())
|
|
|
|
? SkPoint{0,0}
|
|
|
|
: SkPathPriv::PointData(path)[path.countPoints() - 1];
|
|
|
|
path.quadTo(x + rand.nextRangeF(0, 150), y, x - rand.nextRangeF(0, 150), y);
|
|
|
|
} else {
|
|
|
|
path.quadTo(rand.nextRangeF(0, 150), rand.nextRangeF(0, 150),
|
|
|
|
rand.nextRangeF(0, 150), rand.nextRangeF(0, 150));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
if (rand.nextULessThan(10) == 0) {
|
|
|
|
// Cusp.
|
|
|
|
float y = (path.isEmpty())
|
|
|
|
? 0 : SkPathPriv::PointData(path)[path.countPoints() - 1].fY;
|
|
|
|
path.cubicTo(rand.nextRangeF(0, 150), y, rand.nextRangeF(0, 150), y,
|
|
|
|
rand.nextRangeF(0, 150), y);
|
|
|
|
} else {
|
|
|
|
path.cubicTo(rand.nextRangeF(0, 150), rand.nextRangeF(0, 150),
|
|
|
|
rand.nextRangeF(0, 150), rand.nextRangeF(0, 150),
|
|
|
|
rand.nextRangeF(0, 150), rand.nextRangeF(0, 150));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
|
|
|
|
// The number of paths with a given stroke width in the MotionMark bench gets cut in half
|
|
|
|
// every time the stroke width increases by 1.
|
|
|
|
float strokeWidth = 21 - log2f(rand.nextRangeF(0, 1 << 20));
|
|
|
|
stroke.setStrokeStyle(strokeWidth);
|
|
|
|
stroke.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kBevel_Join, 0);
|
|
|
|
pathStrokes.emplace_back(path, stroke, SK_PMColor4fWHITE);
|
|
|
|
}
|
|
|
|
return pathStrokes;
|
|
|
|
}
|
|
|
|
|
2021-04-20 06:45:50 +00:00
|
|
|
class TessPrepareBench : public Benchmark {
|
2020-11-02 19:43:06 +00:00
|
|
|
public:
|
2021-04-20 06:45:50 +00:00
|
|
|
TessPrepareBench(MakePathStrokesFn makePathStrokesFn, MakeTessellatorFn makeTessellatorFn,
|
|
|
|
ShaderFlags shaderFlags, float matrixScale, const char* suffix)
|
|
|
|
: fMakePathStrokesFn(makePathStrokesFn)
|
|
|
|
, fMakeTessellatorFn(makeTessellatorFn)
|
2021-02-24 23:30:34 +00:00
|
|
|
, fShaderFlags(shaderFlags)
|
2021-02-22 19:13:49 +00:00
|
|
|
, fMatrixScale(matrixScale) {
|
2021-04-20 06:45:50 +00:00
|
|
|
fName.printf("tessellate_%s", suffix);
|
2020-11-02 19:43:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
const char* onGetName() override { return fName.c_str(); }
|
2020-09-23 17:07:20 +00:00
|
|
|
bool isSuitableFor(Backend backend) final { return backend == kNonRendering_Backend; }
|
|
|
|
|
|
|
|
void onDelayedSetup() override {
|
2020-11-09 21:13:39 +00:00
|
|
|
fTarget = std::make_unique<GrMockOpTarget>(make_mock_context());
|
2020-11-03 21:09:16 +00:00
|
|
|
if (!fTarget->mockContext()) {
|
2020-09-23 17:07:20 +00:00
|
|
|
SkDebugf("ERROR: could not create mock context.");
|
|
|
|
return;
|
|
|
|
}
|
2021-02-22 19:13:49 +00:00
|
|
|
|
|
|
|
fPathStrokes = fMakePathStrokesFn();
|
|
|
|
for (size_t i = 0; i < fPathStrokes.size(); ++i) {
|
|
|
|
if (i + 1 < fPathStrokes.size()) {
|
|
|
|
fPathStrokes[i].fNext = &fPathStrokes[i + 1];
|
|
|
|
}
|
|
|
|
fTotalVerbCount += fPathStrokes[i].fPath.countVerbs();
|
|
|
|
}
|
2021-04-20 06:45:50 +00:00
|
|
|
|
2021-05-26 16:21:56 +00:00
|
|
|
fTessellator = fMakeTessellatorFn(fShaderFlags, *fTarget->caps().shaderCaps(),
|
|
|
|
SkMatrix::Scale(fMatrixScale, fMatrixScale),
|
2021-05-14 21:57:39 +00:00
|
|
|
fPathStrokes.data(), {fMatrixScale, fMatrixScale},
|
2021-05-21 21:54:23 +00:00
|
|
|
SkRectPriv::MakeLargest());
|
2021-02-22 19:13:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void onDraw(int loops, SkCanvas*) final {
|
2020-09-23 17:07:20 +00:00
|
|
|
for (int i = 0; i < loops; ++i) {
|
2021-04-20 06:45:50 +00:00
|
|
|
fTessellator->prepare(fTarget.get(), fTotalVerbCount);
|
2021-02-22 19:13:49 +00:00
|
|
|
fTarget->resetAllocator();
|
2020-09-23 17:07:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-02 19:43:06 +00:00
|
|
|
SkString fName;
|
2021-02-22 19:13:49 +00:00
|
|
|
MakePathStrokesFn fMakePathStrokesFn;
|
2021-04-20 06:45:50 +00:00
|
|
|
MakeTessellatorFn fMakeTessellatorFn;
|
2021-02-24 23:30:34 +00:00
|
|
|
const ShaderFlags fShaderFlags;
|
2021-02-22 19:13:49 +00:00
|
|
|
float fMatrixScale;
|
2020-11-09 21:13:39 +00:00
|
|
|
std::unique_ptr<GrMockOpTarget> fTarget;
|
2021-02-22 19:13:49 +00:00
|
|
|
std::vector<PathStrokeList> fPathStrokes;
|
2021-04-20 06:45:50 +00:00
|
|
|
std::unique_ptr<GrStrokeTessellator> fTessellator;
|
2021-02-22 19:13:49 +00:00
|
|
|
SkArenaAlloc fPersistentArena{1024};
|
|
|
|
int fTotalVerbCount = 0;
|
2020-09-23 17:07:20 +00:00
|
|
|
};
|
|
|
|
|
2021-04-20 06:45:50 +00:00
|
|
|
DEF_BENCH(return new TessPrepareBench(
|
|
|
|
make_simple_cubic_path, make_hw_tessellator, ShaderFlags::kNone, 1,
|
|
|
|
"GrStrokeHardwareTessellator");
|
|
|
|
)
|
|
|
|
|
|
|
|
DEF_BENCH(return new TessPrepareBench(
|
|
|
|
make_simple_cubic_path, make_hw_tessellator, ShaderFlags::kNone, 5,
|
|
|
|
"GrStrokeHardwareTessellator_one_chop");
|
|
|
|
)
|
|
|
|
|
|
|
|
DEF_BENCH(return new TessPrepareBench(
|
|
|
|
make_motionmark_paths, make_hw_tessellator, ShaderFlags::kDynamicStroke, 1,
|
|
|
|
"GrStrokeHardwareTessellator_motionmark");
|
|
|
|
)
|
|
|
|
|
|
|
|
DEF_BENCH(return new TessPrepareBench(
|
|
|
|
make_simple_cubic_path, make_fixed_count_tessellator, ShaderFlags::kNone, 1,
|
|
|
|
"GrStrokeFixedCountTessellator");
|
2021-02-24 23:30:34 +00:00
|
|
|
)
|
|
|
|
|
2021-04-20 06:45:50 +00:00
|
|
|
DEF_BENCH(return new TessPrepareBench(
|
|
|
|
make_simple_cubic_path, make_fixed_count_tessellator, ShaderFlags::kNone, 5,
|
|
|
|
"GrStrokeFixedCountTessellator_one_chop");
|
2021-02-24 23:30:34 +00:00
|
|
|
)
|
|
|
|
|
2021-04-20 06:45:50 +00:00
|
|
|
DEF_BENCH(return new TessPrepareBench(
|
|
|
|
make_motionmark_paths, make_fixed_count_tessellator, ShaderFlags::kDynamicStroke, 1,
|
|
|
|
"GrStrokeFixedCountTessellator_motionmark");
|
2021-02-24 23:30:34 +00:00
|
|
|
)
|