1/*
2 * Copyright 2013 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 the GPU font cache
9// It's not necessary to run this with CPU configs
10
11#include "gm.h"
12
13#if SK_SUPPORT_GPU
14
15#include "GrContext.h"
16#include "GrContextOptions.h"
17#include "SkCanvas.h"
18#include "SkGraphics.h"
19#include "SkImage.h"
20#include "SkTypeface.h"
21#include "gm.h"
22#include "sk_tool_utils.h"
23
24static SkScalar draw_string(SkCanvas* canvas, const SkString& text, SkScalar x,
25                           SkScalar y, const SkPaint& paint) {
26    canvas->drawString(text, x, y, paint);
27    return x + paint.measureText(text.c_str(), text.size());
28}
29
30class FontCacheGM : public skiagm::GM {
31public:
32    FontCacheGM(GrContextOptions::Enable allowMultipleTextures)
33        : fAllowMultipleTextures(allowMultipleTextures) {
34        this->setBGColor(SK_ColorLTGRAY);
35    }
36
37    void modifyGrContextOptions(GrContextOptions* options) override {
38        options->fGlyphCacheTextureMaximumBytes = 0;
39        options->fAllowMultipleGlyphCacheTextures = fAllowMultipleTextures;
40    }
41
42protected:
43    SkString onShortName() override {
44        SkString name("fontcache");
45        if (GrContextOptions::Enable::kYes == fAllowMultipleTextures) {
46            name.append("-mt");
47        }
48        return name;
49    }
50
51    SkISize onISize() override { return SkISize::Make(kSize, kSize); }
52
53    void onOnceBeforeDraw() override {
54        fTypefaces[0] = sk_tool_utils::create_portable_typeface("serif", SkFontStyle::Italic());
55        fTypefaces[1] = sk_tool_utils::create_portable_typeface("sans-serif",SkFontStyle::Italic());
56        fTypefaces[2] = sk_tool_utils::create_portable_typeface("serif", SkFontStyle::Normal());
57        fTypefaces[3] =
58                sk_tool_utils::create_portable_typeface("sans-serif", SkFontStyle::Normal());
59        fTypefaces[4] = sk_tool_utils::create_portable_typeface("serif", SkFontStyle::Bold());
60        fTypefaces[5] = sk_tool_utils::create_portable_typeface("sans-serif", SkFontStyle::Bold());
61    }
62
63    void onDraw(SkCanvas* canvas) override {
64        GrRenderTargetContext* renderTargetContext =
65            canvas->internal_private_accessTopLayerRenderTargetContext();
66        if (!renderTargetContext) {
67            skiagm::GM::DrawGpuOnlyMessage(canvas);
68            return;
69        }
70
71        canvas->clear(SK_ColorLTGRAY);
72        this->drawText(canvas);
73        //  Debugging tool for GPU.
74        static const bool kShowAtlas = false;
75        if (kShowAtlas) {
76            if (auto ctx = canvas->getGrContext()) {
77                auto img = ctx->getFontAtlasImage_ForTesting(kA8_GrMaskFormat);
78                canvas->drawImage(img, 0, 0);
79            }
80        }
81    }
82
83private:
84    void drawText(SkCanvas* canvas) {
85        static const int kSizes[] = {8, 9, 10, 11, 12, 13, 18, 20, 25};
86
87        static const SkString kTexts[] = {SkString("ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
88                                          SkString("abcdefghijklmnopqrstuvwxyz"),
89                                          SkString("0123456789"),
90                                          SkString("!@#$%^&*()<>[]{}")};
91        SkPaint paint;
92        paint.setAntiAlias(true);
93        paint.setLCDRenderText(false);
94        paint.setSubpixelText(true);
95
96        static const SkScalar kSubPixelInc = 1 / 2.f;
97        SkScalar x = 0;
98        SkScalar y = 10;
99        SkScalar subpixelX = 0;
100        SkScalar subpixelY = 0;
101        bool offsetX = true;
102
103        if (GrContextOptions::Enable::kYes == fAllowMultipleTextures) {
104            canvas->scale(10, 10);
105        }
106
107        do {
108            for (auto s : kSizes) {
109                auto size = 2 * s;
110                paint.setTextSize(size);
111                for (const auto& typeface : fTypefaces) {
112                    paint.setTypeface(typeface);
113                    for (const auto& text : kTexts) {
114                        x = size + draw_string(canvas, text, x + subpixelX, y + subpixelY, paint);
115                        x = SkScalarCeilToScalar(x);
116                        if (x + 100 > kSize) {
117                            x = 0;
118                            y += SkScalarCeilToScalar(size + 3);
119                            if (y > kSize) {
120                                return;
121                            }
122                        }
123                    }
124                }
125                (offsetX ? subpixelX : subpixelY) += kSubPixelInc;
126                offsetX = !offsetX;
127            }
128        } while (true);
129    }
130
131    static constexpr SkScalar kSize = 1280;
132
133    GrContextOptions::Enable fAllowMultipleTextures;
134    sk_sp<SkTypeface> fTypefaces[6];
135    typedef GM INHERITED;
136};
137
138constexpr SkScalar FontCacheGM::kSize;
139
140//////////////////////////////////////////////////////////////////////////////
141
142DEF_GM(return new FontCacheGM(GrContextOptions::Enable::kNo))
143DEF_GM(return new FontCacheGM(GrContextOptions::Enable::kYes))
144
145#endif
146