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 "SkPaint.h" 11 #include "SkPath.h" 12 #include "SkRandom.h" 13 #include "SkStrike.h" 14 #include "SkStrikeCache.h" 15 #include "sk_tool_utils.h" 16 17 static constexpr int kScreenWidth = 1500; 18 static constexpr int kScreenHeight = 1500; 19 20 static constexpr int kNumDraws = 2000; 21 22 // I and l are rects on OS X. 23 static constexpr char kGlyphs[] = "ABCDEFGH7JKLMNOPQRSTUVWXYZabcdefghijk1mnopqrstuvwxyz"; 24 static constexpr int kNumGlyphs = sizeof(kGlyphs) - 1; 25 static_assert(52 == kNumGlyphs, "expected 52 glyphs"); 26 27 /* 28 * This class benchmarks drawing many glyphs at random scales and rotations. 29 */ 30 class PathTextBench : public Benchmark { 31 public: PathTextBench(bool clipped,bool uncached)32 PathTextBench(bool clipped, bool uncached) : fClipped(clipped), fUncached(uncached) {} 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 SkFont defaultFont; 49 auto cache = SkStrikeCache::FindOrCreateStrikeWithNoDeviceExclusive(defaultFont); 50 for (int i = 0; i < kNumGlyphs; ++i) { 51 SkPackedGlyphID id(defaultFont.unicharToGlyph(kGlyphs[i])); 52 sk_ignore_unused_variable(cache->getScalerContext()->getPath(id, &fGlyphs[i])); 53 fGlyphs[i].setIsVolatile(fUncached); 54 } 55 56 SkRandom rand; 57 for (int i = 0; i < kNumDraws; ++i) { 58 const SkPath& glyph = fGlyphs[i % kNumGlyphs]; 59 const SkRect& bounds = glyph.getBounds(); 60 float glyphSize = SkTMax(bounds.width(), bounds.height()); 61 62 float t0 = pow(rand.nextF(), 100); 63 float size = (1 - t0) * SkTMin(kScreenWidth, kScreenHeight) / 50 + 64 t0 * SkTMin(kScreenWidth, kScreenHeight) / 3; 65 float scale = size / glyphSize; 66 float t1 = rand.nextF(), t2 = rand.nextF(); 67 fXforms[i].setTranslate((1 - t1) * sqrt(2) * scale/2 * glyphSize + 68 t1 * (kScreenWidth - sqrt(2) * scale/2 * glyphSize), 69 (1 - t2) * sqrt(2) * scale/2 * glyphSize + 70 t2 * (kScreenHeight - sqrt(2) * scale/2 * glyphSize)); 71 fXforms[i].preRotate(rand.nextF() * 360); 72 fXforms[i].preTranslate(-scale/2 * bounds.width(), -scale/2 * bounds.height()); 73 fXforms[i].preScale(scale, scale); 74 fPaints[i].setAntiAlias(true); 75 fPaints[i].setColor(rand.nextU() | 0x80808080); 76 } 77 78 if (fClipped) { 79 fClipPath = sk_tool_utils::make_star(SkRect::MakeIWH(kScreenWidth,kScreenHeight), 11,3); 80 fClipPath.setIsVolatile(fUncached); 81 } 82 } 83 onDraw(int loops,SkCanvas * canvas)84 void onDraw(int loops, SkCanvas* canvas) override { 85 SkAutoCanvasRestore acr(canvas, true); 86 if (fClipped) { 87 canvas->clipPath(fClipPath, SkClipOp::kIntersect, true); 88 } 89 for (int i = 0; i < kNumDraws; ++i) { 90 const SkPath& glyph = fGlyphs[i % kNumGlyphs]; 91 canvas->setMatrix(fXforms[i]); 92 canvas->drawPath(glyph, fPaints[i]); 93 } 94 } 95 96 const bool fClipped; 97 const bool fUncached; 98 SkString fName; 99 SkPath fGlyphs[kNumGlyphs]; 100 SkPaint fPaints[kNumDraws]; 101 SkMatrix fXforms[kNumDraws]; 102 SkPath fClipPath; 103 104 typedef Benchmark INHERITED; 105 }; 106 107 DEF_BENCH(return new PathTextBench(false, false);) 108 DEF_BENCH(return new PathTextBench(false, true);) 109 DEF_BENCH(return new PathTextBench(true, true);) 110