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