1 /*
2 * Copyright 2018 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 // GM to stress TextBlob regeneration and the GPU font cache
9 // It's not necessary to run this with CPU configs
10 //
11 // The point here is to draw a set of text that will fit in one Plot, and then some large
12 // text. After a flush we draw the first set of text again with a slightly different color,
13 // and then enough new large text to spill the entire atlas. What *should* happen is that
14 // the Plot with the first set of text will not get overwritten by the new large text.
15
16 #include "gm/gm.h"
17 #include "include/core/SkCanvas.h"
18 #include "include/core/SkColor.h"
19 #include "include/core/SkFont.h"
20 #include "include/core/SkFontMgr.h"
21 #include "include/core/SkFontStyle.h"
22 #include "include/core/SkFontTypes.h"
23 #include "include/core/SkPaint.h"
24 #include "include/core/SkRefCnt.h"
25 #include "include/core/SkScalar.h"
26 #include "include/core/SkSize.h"
27 #include "include/core/SkString.h"
28 #include "include/core/SkTextBlob.h"
29 #include "include/core/SkTypeface.h"
30 #include "include/core/SkTypes.h"
31 #include "include/gpu/GrContextOptions.h"
32 #include "include/gpu/GrDirectContext.h"
33 #include "include/gpu/GrRecordingContext.h"
34 #include "include/private/GrTypesPriv.h"
35 #include "include/private/SkTemplates.h"
36 #include "src/gpu/GrDirectContextPriv.h"
37 #include "tools/ToolUtils.h"
38
make_blob(const SkString & text,const SkFont & font)39 static sk_sp<SkTextBlob> make_blob(const SkString& text, const SkFont& font) {
40 size_t len = text.size();
41 SkAutoTArray<SkScalar> pos(len);
42 SkAutoTArray<SkGlyphID> glyphs(len);
43
44 font.textToGlyphs(text.c_str(), len, SkTextEncoding::kUTF8, glyphs.get(), len);
45 font.getXPos(glyphs.get(), len, pos.get());
46 return SkTextBlob::MakeFromPosTextH(text.c_str(), len, pos.get(), 0, font);
47 }
48
49 class FontRegenGM : public skiagm::GM {
50
modifyGrContextOptions(GrContextOptions * options)51 void modifyGrContextOptions(GrContextOptions* options) override {
52 options->fGlyphCacheTextureMaximumBytes = 0;
53 options->fAllowMultipleGlyphCacheTextures = GrContextOptions::Enable::kNo;
54 }
55
onShortName()56 SkString onShortName() override { return SkString("fontregen"); }
57
onISize()58 SkISize onISize() override { return {kSize, kSize}; }
59
onOnceBeforeDraw()60 void onOnceBeforeDraw() override {
61 this->setBGColor(SK_ColorLTGRAY);
62
63 auto tf = ToolUtils::create_portable_typeface("sans-serif", SkFontStyle::Normal());
64
65 static const SkString kTexts[] = {
66 SkString("abcdefghijklmnopqrstuvwxyz"),
67 SkString("ABCDEFGHI"),
68 SkString("NOPQRSTUV")
69 };
70
71 SkFont font;
72 font.setEdging(SkFont::Edging::kAntiAlias);
73 font.setSubpixel(false);
74 font.setSize(80);
75 font.setTypeface(tf);
76
77 fBlobs[0] = make_blob(kTexts[0], font);
78 font.setSize(162);
79 fBlobs[1] = make_blob(kTexts[1], font);
80 fBlobs[2] = make_blob(kTexts[2], font);
81 }
82
onDraw(SkCanvas * canvas,SkString * errorMsg)83 DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
84 auto dContext = GrAsDirectContext(canvas->recordingContext());
85 if (!dContext) {
86 *errorMsg = "GPU-specific";
87 return DrawResult::kSkip;
88 }
89
90 SkPaint paint;
91 paint.setColor(SK_ColorBLACK);
92 canvas->drawTextBlob(fBlobs[0], 10, 80, paint);
93 canvas->drawTextBlob(fBlobs[1], 10, 225, paint);
94 dContext->flushAndSubmit();
95
96 paint.setColor(0xFF010101);
97 canvas->drawTextBlob(fBlobs[0], 10, 305, paint);
98 canvas->drawTextBlob(fBlobs[2], 10, 465, paint);
99
100 // Debugging tool for GPU.
101 static const bool kShowAtlas = false;
102 if (kShowAtlas) {
103 auto img = dContext->priv().testingOnly_getFontAtlasImage(kA8_GrMaskFormat);
104 canvas->drawImage(img, 200, 0);
105 }
106
107 return DrawResult::kOk;
108 }
109
110 private:
111 inline static constexpr int kSize = 512;
112
113 sk_sp<SkTextBlob> fBlobs[3];
114 using INHERITED = GM;
115 };
116
117 //////////////////////////////////////////////////////////////////////////////
118
119 DEF_GM(return new FontRegenGM())
120
121 ///////////////////////////////////////////////////////////////////////////////
122
123 class BadAppleGM : public skiagm::GM {
124
onShortName()125 SkString onShortName() override { return SkString("badapple"); }
126
onISize()127 SkISize onISize() override { return {kSize, kSize}; }
128
onOnceBeforeDraw()129 void onOnceBeforeDraw() override {
130 this->setBGColor(SK_ColorWHITE);
131 auto fm = SkFontMgr::RefDefault();
132
133 static const SkString kTexts[] = {
134 SkString("Meet"),
135 SkString("iPad Pro"),
136 };
137
138 SkFont font;
139 font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
140 font.setSubpixel(true);
141 font.setSize(256);
142
143 fBlobs[0] = make_blob(kTexts[0], font);
144 fBlobs[1] = make_blob(kTexts[1], font);
145 }
146
onDraw(SkCanvas * canvas)147 void onDraw(SkCanvas* canvas) override {
148 SkPaint paint;
149 paint.setColor(0xFF111111);
150 canvas->drawTextBlob(fBlobs[0], 10, 260, paint);
151 canvas->drawTextBlob(fBlobs[1], 10, 500, paint);
152 }
153
154 private:
155 inline static constexpr int kSize = 512;
156
157 sk_sp<SkTextBlob> fBlobs[3];
158 using INHERITED = GM;
159 };
160
161 //////////////////////////////////////////////////////////////////////////////
162
163 DEF_GM(return new BadAppleGM())
164