1 /* 2 * Copyright 2017 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "Benchmark.h" 9 #include "SkCanvas.h" 10 #include "SkGlyphCache.h" 11 #include "SkPaint.h" 12 #include "SkPath.h" 13 #include "SkRandom.h" 14 #include "sk_tool_utils.h" 15 16 static constexpr int kScreenWidth = 1500; 17 static constexpr int kScreenHeight = 1500; 18 19 static constexpr int kNumDraws = 2000; 20 21 // I and l are rects on OS X. 22 static constexpr char kGlyphs[] = "ABCDEFGH7JKLMNOPQRSTUVWXYZabcdefghijk1mnopqrstuvwxyz"; 23 static constexpr int kNumGlyphs = sizeof(kGlyphs) - 1; 24 static_assert(52 == kNumGlyphs, "expected 52 glyphs"); 25 26 /* 27 * This class benchmarks drawing many glyphs at random scales and rotations. 28 */ 29 class PathTextBench : public Benchmark { 30 public: PathTextBench(bool clipped,bool uncached)31 PathTextBench(bool clipped, bool uncached) : fClipped(clipped), fUncached(uncached) {} isVisual()32 bool isVisual() override { return true; } 33 34 private: onGetName()35 const char* onGetName() override { 36 fName = "path_text"; 37 if (fClipped) { 38 fName.append("_clipped"); 39 } 40 if (fUncached) { 41 fName.append("_uncached"); 42 } 43 return fName.c_str(); 44 } onGetSize()45 SkIPoint onGetSize() override { return SkIPoint::Make(kScreenWidth, kScreenHeight); } 46 onDelayedSetup()47 void onDelayedSetup() override { 48 SkPaint defaultPaint; 49 SkAutoGlyphCache agc(defaultPaint, nullptr, &SkMatrix::I()); 50 SkGlyphCache* cache = agc.getCache(); 51 for (int i = 0; i < kNumGlyphs; ++i) { 52 SkGlyphID id = cache->unicharToGlyph(kGlyphs[i]); 53 cache->getScalerContext()->getPath(SkPackedGlyphID(id), &fGlyphs[i]); 54 fGlyphs[i].setIsVolatile(fUncached); 55 } 56 57 SkRandom rand; 58 for (int i = 0; i < kNumDraws; ++i) { 59 const SkPath& glyph = fGlyphs[i % kNumGlyphs]; 60 const SkRect& bounds = glyph.getBounds(); 61 float glyphSize = SkTMax(bounds.width(), bounds.height()); 62 63 float t0 = pow(rand.nextF(), 100); 64 float size = (1 - t0) * SkTMin(kScreenWidth, kScreenHeight) / 50 + 65 t0 * SkTMin(kScreenWidth, kScreenHeight) / 3; 66 float scale = size / glyphSize; 67 float t1 = rand.nextF(), t2 = rand.nextF(); 68 fXforms[i].setTranslate((1 - t1) * sqrt(2) * scale/2 * glyphSize + 69 t1 * (kScreenWidth - sqrt(2) * scale/2 * glyphSize), 70 (1 - t2) * sqrt(2) * scale/2 * glyphSize + 71 t2 * (kScreenHeight - sqrt(2) * scale/2 * glyphSize)); 72 fXforms[i].preRotate(rand.nextF() * 360); 73 fXforms[i].preTranslate(-scale/2 * bounds.width(), -scale/2 * bounds.height()); 74 fXforms[i].preScale(scale, scale); 75 fPaints[i].setAntiAlias(true); 76 fPaints[i].setColor(rand.nextU() | 0x80808080); 77 } 78 79 if (fClipped) { 80 fClipPath = sk_tool_utils::make_star(SkRect::MakeIWH(kScreenWidth,kScreenHeight), 11,3); 81 fClipPath.setIsVolatile(fUncached); 82 } 83 } 84 onDraw(int loops,SkCanvas * canvas)85 void onDraw(int loops, SkCanvas* canvas) override { 86 SkAutoCanvasRestore acr(canvas, true); 87 if (fClipped) { 88 canvas->clipPath(fClipPath, SkClipOp::kIntersect, true); 89 } 90 for (int i = 0; i < kNumDraws; ++i) { 91 const SkPath& glyph = fGlyphs[i % kNumGlyphs]; 92 canvas->setMatrix(fXforms[i]); 93 canvas->drawPath(glyph, fPaints[i]); 94 } 95 } 96 97 const bool fClipped; 98 const bool fUncached; 99 SkString fName; 100 SkPath fGlyphs[kNumGlyphs]; 101 SkPaint fPaints[kNumDraws]; 102 SkMatrix fXforms[kNumDraws]; 103 SkPath fClipPath; 104 105 typedef Benchmark INHERITED; 106 }; 107 108 DEF_BENCH(return new PathTextBench(false, false);) 109 DEF_BENCH(return new PathTextBench(false, true);) 110 DEF_BENCH(return new PathTextBench(true, true);) 111