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