| /* | |
| * Copyright 2011 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" | |
| #include "include/core/SkCanvas.h" | |
| #include "include/core/SkPaint.h" | |
| #include "include/core/SkShader.h" | |
| #include "include/core/SkString.h" | |
| #include "include/core/SkVertices.h" | |
| #include "src/core/SkRandom.h" | |
| #include "tools/DecodeUtils.h" | |
| #include "tools/Resources.h" | |
| #include <array> | |
| // Just want to trigger perspective handling, not dramatically change size | |
| static void tiny_persp_effect(SkCanvas* canvas) { | |
| SkMatrix m; | |
| m.reset(); | |
| m[7] = 0.000001f; | |
| canvas->concat(m); | |
| } | |
| enum VertFlags { | |
| kColors_VertFlag = 1 << 0, | |
| kTexture_VertFlag = 1 << 1, | |
| kPersp_VertFlag = 1 << 2, | |
| kBilerp_VertFlag = 1 << 3, | |
| }; | |
| class VertBench : public Benchmark { | |
| SkString fName; | |
| static constexpr int W = 64*2; | |
| static constexpr int H = 48*2; | |
| static constexpr int ROW = 20; | |
| static constexpr int COL = 20; | |
| static constexpr int PTS = (ROW + 1) * (COL + 1); | |
| static constexpr int IDX = ROW * COL * 6; | |
| sk_sp<SkShader> fShader; | |
| SkPoint fPts[PTS], fTex[PTS]; | |
| SkColor fColors[PTS]; | |
| uint16_t fIdx[IDX]; | |
| unsigned fFlags; | |
| static void load_2_tris(uint16_t idx[], int x, int y, int rb) { | |
| int n = y * rb + x; | |
| idx[0] = n; idx[1] = n + 1; idx[2] = rb + n + 1; | |
| idx[3] = n; idx[4] = rb + n + 1; idx[5] = n + rb; | |
| } | |
| void onDelayedSetup() override { | |
| if (fFlags & kTexture_VertFlag) { | |
| auto img = ToolUtils::GetResourceAsImage("images/mandrill_256.png"); | |
| if (img) { | |
| SkFilterMode fm = (fFlags & kBilerp_VertFlag) ? SkFilterMode::kLinear | |
| : SkFilterMode::kNearest; | |
| fShader = img->makeShader(SkSamplingOptions(fm)); | |
| } | |
| } | |
| } | |
| public: | |
| VertBench(unsigned flags) : fFlags(flags) { | |
| const SkScalar dx = SkIntToScalar(W) / COL; | |
| const SkScalar dy = SkIntToScalar(H) / COL; | |
| SkPoint* pts = fPts; | |
| uint16_t* idx = fIdx; | |
| SkScalar yy = 0; | |
| for (int y = 0; y <= ROW; y++) { | |
| SkScalar xx = 0; | |
| for (int x = 0; x <= COL; ++x) { | |
| pts->set(xx, yy); | |
| pts += 1; | |
| xx += dx; | |
| if (x < COL && y < ROW) { | |
| load_2_tris(idx, x, y, COL + 1); | |
| for (int i = 0; i < 6; i++) { | |
| SkASSERT(idx[i] < PTS); | |
| } | |
| idx += 6; | |
| } | |
| } | |
| yy += dy; | |
| } | |
| SkASSERT(PTS == pts - fPts); | |
| SkASSERT(IDX == idx - fIdx); | |
| // We want to store texs in a separate array, so the blitters don't "cheat" and | |
| // skip the (normal) step of computing the new local-matrix. This is the common case | |
| // we think in the wild (where the texture coordinates are different from the positions. | |
| memcpy(fTex, fPts, sizeof(fPts)); | |
| SkRandom rand; | |
| for (int i = 0; i < PTS; ++i) { | |
| fColors[i] = rand.nextU() | (0xFF << 24); | |
| } | |
| fName.set("verts"); | |
| if (fFlags & kTexture_VertFlag) { | |
| fName.append("_textures"); | |
| } | |
| if (fFlags & kColors_VertFlag) { | |
| fName.append("_colors"); | |
| } | |
| if (fFlags & kPersp_VertFlag) { | |
| fName.append("_persp"); | |
| } | |
| if (fFlags & kBilerp_VertFlag) { | |
| fName.append("_bilerp"); | |
| } | |
| } | |
| protected: | |
| const char* onGetName() override { return fName.c_str(); } | |
| void onDraw(int loops, SkCanvas* canvas) override { | |
| SkPaint paint; | |
| this->setupPaint(&paint); | |
| paint.setShader(fShader); | |
| if (fFlags & kPersp_VertFlag) { | |
| tiny_persp_effect(canvas); | |
| } | |
| const SkPoint* texs = (fFlags & kTexture_VertFlag) ? fTex : nullptr; | |
| const SkColor* cols = (fFlags & kColors_VertFlag) ? fColors : nullptr; | |
| auto verts = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, PTS, | |
| fPts, texs, cols, IDX, fIdx); | |
| for (int i = 0; i < loops; i++) { | |
| canvas->drawVertices(verts, SkBlendMode::kModulate, paint); | |
| } | |
| } | |
| private: | |
| using INHERITED = Benchmark; | |
| }; | |
| DEF_BENCH(return new VertBench(kTexture_VertFlag | kPersp_VertFlag);) | |
| DEF_BENCH(return new VertBench(kTexture_VertFlag | kPersp_VertFlag | kBilerp_VertFlag);) | |
| DEF_BENCH(return new VertBench(kColors_VertFlag | kPersp_VertFlag);) | |
| DEF_BENCH(return new VertBench(kTexture_VertFlag);) | |
| DEF_BENCH(return new VertBench(kTexture_VertFlag | kBilerp_VertFlag);) | |
| DEF_BENCH(return new VertBench(kColors_VertFlag);) | |
| DEF_BENCH(return new VertBench(kColors_VertFlag | kTexture_VertFlag);) | |
| DEF_BENCH(return new VertBench(kColors_VertFlag | kTexture_VertFlag | kBilerp_VertFlag);) | |
| ///////////////////////////////////////////////////////////////////////////////////////////////// | |
| #include "include/core/SkRSXform.h" | |
| #include "src/core/SkRandom.h" | |
| #include "tools/Resources.h" | |
| enum AtlasFlags { | |
| kColors_Flag = 1 << 0, | |
| kRotate_Flag = 1 << 1, | |
| kPersp_Flag = 1 << 2, | |
| }; | |
| class AtlasBench : public Benchmark { | |
| unsigned fFlags; | |
| SkString fName; | |
| static constexpr int W = 640; | |
| static constexpr int H = 480; | |
| static constexpr int N = 10*1000; | |
| sk_sp<SkImage> fAtlas; | |
| std::array<SkRSXform, N> fXforms; | |
| std::array<SkRect, N> fRects; | |
| SkColor fColors[N]; | |
| public: | |
| AtlasBench(unsigned flags) : fFlags(flags) { | |
| fName.printf("drawAtlas"); | |
| if (flags & kColors_Flag) { | |
| fName.append("_colors"); | |
| } | |
| if (flags & kRotate_Flag) { | |
| fName.append("_rotated"); | |
| } | |
| if (flags & kPersp_Flag) { | |
| fName.append("_persp"); | |
| } | |
| } | |
| ~AtlasBench() override {} | |
| protected: | |
| const char* onGetName() override { return fName.c_str(); } | |
| void onDelayedSetup() override { | |
| fAtlas = ToolUtils::GetResourceAsImage("images/mandrill_256.png"); | |
| if (fAtlas) { | |
| fAtlas = fAtlas->makeRasterImage(nullptr); | |
| } | |
| const SkScalar imageW = fAtlas->width(); | |
| const SkScalar imageH = fAtlas->height(); | |
| SkScalar scos = 1; | |
| SkScalar ssin = 0; | |
| if (fFlags & kRotate_Flag) { | |
| scos = 0.866025403784439f; // sqrt(3)/2 | |
| ssin = 0.5f; | |
| } | |
| SkRandom rand; | |
| for (int i = 0; i < N; ++i) { | |
| fRects[i] = SkRect::MakeXYWH(rand.nextF() * (imageW - 8), | |
| rand.nextF() * (imageH - 8), 8, 8); | |
| fColors[i] = rand.nextU() | 0xFF000000; | |
| fXforms[i] = SkRSXform::Make(scos, ssin, rand.nextF() * W, rand.nextF() * H); | |
| } | |
| } | |
| void onDraw(int loops, SkCanvas* canvas) override { | |
| const SkRect* cullRect = nullptr; | |
| const SkPaint* paintPtr = nullptr; | |
| const SkColor* colors = nullptr; | |
| if (fFlags & kColors_Flag) { | |
| colors = fColors; | |
| } | |
| if (fFlags & kPersp_Flag) { | |
| tiny_persp_effect(canvas); | |
| } | |
| for (int i = 0; i < loops; i++) { | |
| canvas->drawAtlas(fAtlas.get(), fXforms, fRects, | |
| {colors, colors ? (size_t)N : 0}, SkBlendMode::kModulate, | |
| SkSamplingOptions(), cullRect, paintPtr); | |
| } | |
| } | |
| private: | |
| using INHERITED = Benchmark; | |
| }; | |
| //DEF_BENCH(return new AtlasBench(0);) | |
| //DEF_BENCH(return new AtlasBench(kColors_Flag);) | |
| DEF_BENCH(return new AtlasBench(0);) | |
| DEF_BENCH(return new AtlasBench(kRotate_Flag);) | |
| DEF_BENCH(return new AtlasBench(kPersp_Flag);) | |
| DEF_BENCH(return new AtlasBench(kColors_Flag);) | |
| DEF_BENCH(return new AtlasBench(kColors_Flag | kRotate_Flag);) | |