1 /* 2 * Copyright 2015 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/SkStream.h" 13 #include "include/core/SkString.h" 14 #include "include/core/SkTextBlob.h" 15 #include "include/core/SkTypeface.h" 16 #include "include/private/SkTemplates.h" 17 #include "include/utils/SkRandom.h" 18 #include "tools/Resources.h" 19 20 #include "tools/ToolUtils.h" 21 22 /* 23 * A trivial test which benchmarks the performance of a textblob with a single run. 24 */ 25 class SkTextBlobBench : public Benchmark { 26 public: SkTextBlobBench()27 SkTextBlobBench() {} 28 onDelayedSetup()29 void onDelayedSetup() override { 30 fFont.setTypeface(ToolUtils::create_portable_typeface("serif", SkFontStyle())); 31 fFont.setSubpixel(true); 32 33 // This text seems representative in both length and letter frequency. 34 const char* text = "Keep your sentences short, but not overly so."; 35 36 fGlyphs.setCount(fFont.countText(text, strlen(text), SkTextEncoding::kUTF8)); 37 fXPos.setCount(fGlyphs.count()); 38 39 fFont.textToGlyphs(text, strlen(text), SkTextEncoding::kUTF8, fGlyphs.begin(), fGlyphs.count()); 40 fFont.getXPos(&fGlyphs[0], fGlyphs.count(), fXPos.begin()); 41 } 42 makeBlob()43 sk_sp<SkTextBlob> makeBlob() { 44 const SkTextBlobBuilder::RunBuffer& run = 45 fBuilder.allocRunPosH(fFont, fGlyphs.count(), 10, nullptr); 46 memcpy(run.glyphs, &fGlyphs[0], fGlyphs.count() * sizeof(uint16_t)); 47 memcpy(run.pos, &fXPos[0], fXPos.count() * sizeof(SkScalar)); 48 return fBuilder.make(); 49 } 50 51 private: 52 SkTextBlobBuilder fBuilder; 53 SkFont fFont; 54 SkTDArray<uint16_t> fGlyphs; 55 SkTDArray<SkScalar> fXPos; 56 57 using INHERITED = Benchmark; 58 }; 59 60 class TextBlobCachedBench : public SkTextBlobBench { onGetName()61 const char* onGetName() override { 62 return "TextBlobCachedBench"; 63 } 64 onDraw(int loops,SkCanvas * canvas)65 void onDraw(int loops, SkCanvas* canvas) override { 66 SkPaint paint; 67 68 auto blob = this->makeBlob(); 69 auto bigLoops = loops * 100; 70 for (int i = 0; i < bigLoops; i++) { 71 // To ensure maximum caching, we just redraw the blob at the same place everytime 72 canvas->drawTextBlob(blob, 0, 0, paint); 73 } 74 } 75 }; 76 DEF_BENCH( return new TextBlobCachedBench(); ) 77 78 class TextBlobFirstTimeBench : public SkTextBlobBench { onGetName()79 const char* onGetName() override { 80 return "TextBlobFirstTimeBench"; 81 } 82 onDraw(int loops,SkCanvas * canvas)83 void onDraw(int loops, SkCanvas* canvas) override { 84 SkPaint paint; 85 86 auto bigLoops = loops * 100; 87 for (int i = 0; i < bigLoops; i++) { 88 canvas->drawTextBlob(this->makeBlob(), 0, 0, paint); 89 } 90 } 91 }; 92 DEF_BENCH( return new TextBlobFirstTimeBench(); ) 93 94 class TextBlobMakeBench : public SkTextBlobBench { onGetName()95 const char* onGetName() override { 96 return "TextBlobMakeBench"; 97 } 98 isSuitableFor(Backend backend)99 bool isSuitableFor(Backend backend) override { 100 return backend == kNonRendering_Backend; 101 } 102 onDraw(int loops,SkCanvas *)103 void onDraw(int loops, SkCanvas*) override { 104 for (int i = 0; i < loops; i++) { 105 for (int inner = 0; inner < 1000; ++inner) { 106 this->makeBlob(); 107 } 108 } 109 } 110 }; 111 DEF_BENCH( return new TextBlobMakeBench(); ) 112