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 
39 class GrRenderTargetContext;
40 
make_blob(const SkString & text,const SkFont & font)41 static sk_sp<SkTextBlob> make_blob(const SkString& text, const SkFont& font) {
42     size_t len = text.size();
43     SkAutoTArray<SkScalar>  pos(len);
44     SkAutoTArray<SkGlyphID> glyphs(len);
45 
46     font.textToGlyphs(text.c_str(), len, SkTextEncoding::kUTF8, glyphs.get(), len);
47     font.getXPos(glyphs.get(), len, pos.get());
48     return SkTextBlob::MakeFromPosTextH(text.c_str(), len, pos.get(), 0, font);
49 }
50 
51 class FontRegenGM : public skiagm::GpuGM {
52 
modifyGrContextOptions(GrContextOptions * options)53     void modifyGrContextOptions(GrContextOptions* options) override {
54         options->fGlyphCacheTextureMaximumBytes = 0;
55         options->fAllowMultipleGlyphCacheTextures = GrContextOptions::Enable::kNo;
56     }
57 
onShortName()58     SkString onShortName() override { return SkString("fontregen"); }
59 
onISize()60     SkISize onISize() override { return {kSize, kSize}; }
61 
onOnceBeforeDraw()62     void onOnceBeforeDraw() override {
63         this->setBGColor(SK_ColorLTGRAY);
64 
65         auto tf = ToolUtils::create_portable_typeface("sans-serif", SkFontStyle::Normal());
66 
67         static const SkString kTexts[] = {
68             SkString("abcdefghijklmnopqrstuvwxyz"),
69             SkString("ABCDEFGHI"),
70             SkString("NOPQRSTUV")
71         };
72 
73         SkFont font;
74         font.setEdging(SkFont::Edging::kAntiAlias);
75         font.setSubpixel(false);
76         font.setSize(80);
77         font.setTypeface(tf);
78 
79         fBlobs[0] = make_blob(kTexts[0], font);
80         font.setSize(162);
81         fBlobs[1] = make_blob(kTexts[1], font);
82         fBlobs[2] = make_blob(kTexts[2], font);
83     }
84 
onDraw(GrRecordingContext * context,GrRenderTargetContext *,SkCanvas * canvas)85     void onDraw(GrRecordingContext* context, GrRenderTargetContext*, SkCanvas* canvas) override {
86         auto direct = context->asDirectContext();
87         if (!direct) {
88             return;
89         }
90 
91         SkPaint paint;
92         paint.setColor(SK_ColorBLACK);
93         canvas->drawTextBlob(fBlobs[0], 10, 80, paint);
94         canvas->drawTextBlob(fBlobs[1], 10, 225, paint);
95         direct->flushAndSubmit();
96 
97         paint.setColor(0xFF010101);
98         canvas->drawTextBlob(fBlobs[0], 10, 305, paint);
99         canvas->drawTextBlob(fBlobs[2], 10, 465, paint);
100 
101         //  Debugging tool for GPU.
102         static const bool kShowAtlas = false;
103         if (kShowAtlas) {
104             auto img = direct->priv().testingOnly_getFontAtlasImage(kA8_GrMaskFormat);
105             canvas->drawImage(img, 200, 0);
106         }
107     }
108 
109 private:
110     static constexpr int kSize = 512;
111 
112     sk_sp<SkTextBlob> fBlobs[3];
113     using INHERITED = GM;
114 };
115 
116 //////////////////////////////////////////////////////////////////////////////
117 
118 DEF_GM(return new FontRegenGM())
119 
120 ///////////////////////////////////////////////////////////////////////////////
121 
122 class BadAppleGM : public skiagm::GpuGM {
123 
onShortName()124     SkString onShortName() override { return SkString("badapple"); }
125 
onISize()126     SkISize onISize() override { return {kSize, kSize}; }
127 
onOnceBeforeDraw()128     void onOnceBeforeDraw() override {
129         this->setBGColor(SK_ColorWHITE);
130         auto fm = SkFontMgr::RefDefault();
131 
132         static const SkString kTexts[] = {
133                 SkString("Meet"),
134                 SkString("iPad Pro"),
135         };
136 
137         SkFont font;
138         font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
139         font.setSubpixel(true);
140         font.setSize(256);
141 
142         fBlobs[0] = make_blob(kTexts[0], font);
143         fBlobs[1] = make_blob(kTexts[1], font);
144     }
145 
onDraw(GrRecordingContext * context,GrRenderTargetContext *,SkCanvas * canvas)146     void onDraw(GrRecordingContext* context, GrRenderTargetContext*, SkCanvas* canvas) override {
147         SkPaint paint;
148         paint.setColor(0xFF111111);
149         canvas->drawTextBlob(fBlobs[0], 10, 260, paint);
150         canvas->drawTextBlob(fBlobs[1], 10, 500, paint);
151     }
152 
153 private:
154     static constexpr int kSize = 512;
155 
156     sk_sp<SkTextBlob> fBlobs[3];
157     using INHERITED = GM;
158 };
159 
160 //////////////////////////////////////////////////////////////////////////////
161 
162 DEF_GM(return new BadAppleGM())
163