| /* | |
| * Copyright 2013 Google Inc. | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| // GM to stress the GPU font cache | |
| // It's not necessary to run this with CPU configs | |
| #include "gm/gm.h" | |
| #include "include/core/SkCanvas.h" | |
| #include "include/core/SkColor.h" | |
| #include "include/core/SkFont.h" | |
| #include "include/core/SkFontStyle.h" | |
| #include "include/core/SkFontTypes.h" | |
| #include "include/core/SkPaint.h" | |
| #include "include/core/SkRefCnt.h" | |
| #include "include/core/SkScalar.h" | |
| #include "include/core/SkSize.h" | |
| #include "include/core/SkString.h" | |
| #include "include/core/SkTypeface.h" | |
| #include "src/gpu/MaskFormat.h" | |
| #include "tools/ToolUtils.h" | |
| #include "tools/fonts/FontToolUtils.h" | |
| #if defined(SK_GANESH) | |
| #include "include/gpu/ganesh/GrContextOptions.h" | |
| #include "include/gpu/ganesh/GrDirectContext.h" | |
| #include "include/private/gpu/ganesh/GrTypesPriv.h" | |
| #include "src/gpu/ganesh/GrDirectContextPriv.h" | |
| #endif | |
| using MaskFormat = skgpu::MaskFormat; | |
| static SkScalar draw_string(SkCanvas* canvas, const SkString& text, SkScalar x, | |
| SkScalar y, const SkFont& font) { | |
| SkPaint paint; | |
| canvas->drawString(text, x, y, font, paint); | |
| return x + font.measureText(text.c_str(), text.size(), SkTextEncoding::kUTF8); | |
| } | |
| class FontCacheGM : public skiagm::GM { | |
| public: | |
| FontCacheGM(bool allowMultipleTextures) : fAllowMultipleTextures(allowMultipleTextures) { | |
| this->setBGColor(SK_ColorLTGRAY); | |
| } | |
| #if defined(SK_GANESH) | |
| void modifyGrContextOptions(GrContextOptions* options) override { | |
| options->fGlyphCacheTextureMaximumBytes = 0; | |
| using Enable = GrContextOptions::Enable; | |
| options->fAllowMultipleGlyphCacheTextures = fAllowMultipleTextures ? Enable::kYes | |
| : Enable::kNo; | |
| } | |
| #endif | |
| protected: | |
| SkString getName() const override { | |
| SkString name("fontcache"); | |
| if (fAllowMultipleTextures) { | |
| name.append("-mt"); | |
| } | |
| return name; | |
| } | |
| SkISize getISize() override { return SkISize::Make(kSize, kSize); } | |
| void onOnceBeforeDraw() override { | |
| fTypefaces[0] = ToolUtils::CreatePortableTypeface("serif", SkFontStyle::Italic()); | |
| fTypefaces[1] = ToolUtils::CreatePortableTypeface("sans-serif", SkFontStyle::Italic()); | |
| fTypefaces[2] = ToolUtils::CreatePortableTypeface("serif", SkFontStyle::Normal()); | |
| fTypefaces[3] = ToolUtils::CreatePortableTypeface("sans-serif", SkFontStyle::Normal()); | |
| fTypefaces[4] = ToolUtils::CreatePortableTypeface("serif", SkFontStyle::Bold()); | |
| fTypefaces[5] = ToolUtils::CreatePortableTypeface("sans-serif", SkFontStyle::Bold()); | |
| } | |
| void onDraw(SkCanvas* canvas) override { | |
| this->drawText(canvas); | |
| #if defined(SK_GANESH) | |
| // Debugging tool for Ganesh. | |
| static const bool kShowAtlas = false; | |
| if (kShowAtlas) { | |
| if (auto dContext = GrAsDirectContext(canvas->recordingContext())) { | |
| auto img = dContext->priv().testingOnly_getFontAtlasImage(MaskFormat::kA8); | |
| canvas->drawImage(img, 0, 0); | |
| } | |
| } | |
| #endif | |
| } | |
| private: | |
| void drawText(SkCanvas* canvas) { | |
| static const int kSizes[] = {8, 9, 10, 11, 12, 13, 18, 20, 25}; | |
| static const SkString kTexts[] = {SkString("ABCDEFGHIJKLMNOPQRSTUVWXYZ"), | |
| SkString("abcdefghijklmnopqrstuvwxyz"), | |
| SkString("0123456789"), | |
| SkString("!@#$%^&*()<>[]{}")}; | |
| SkFont font = ToolUtils::DefaultPortableFont(); | |
| font.setEdging(SkFont::Edging::kAntiAlias); | |
| font.setSubpixel(true); | |
| static const SkScalar kSubPixelInc = 1 / 2.f; | |
| SkScalar x = 0; | |
| SkScalar y = 10; | |
| SkScalar subpixelX = 0; | |
| SkScalar subpixelY = 0; | |
| bool offsetX = true; | |
| if (fAllowMultipleTextures) { | |
| canvas->scale(10, 10); | |
| } | |
| do { | |
| for (auto s : kSizes) { | |
| auto size = 2 * s; | |
| font.setSize(size); | |
| for (const auto& typeface : fTypefaces) { | |
| font.setTypeface(typeface); | |
| for (const auto& text : kTexts) { | |
| x = size + draw_string(canvas, text, x + subpixelX, y + subpixelY, font); | |
| x = SkScalarCeilToScalar(x); | |
| if (x + 100 > kSize) { | |
| x = 0; | |
| y += SkScalarCeilToScalar(size + 3); | |
| if (y > kSize) { | |
| return; | |
| } | |
| } | |
| } | |
| } | |
| (offsetX ? subpixelX : subpixelY) += kSubPixelInc; | |
| offsetX = !offsetX; | |
| } | |
| } while (true); | |
| } | |
| inline static constexpr SkScalar kSize = 1280; | |
| bool fAllowMultipleTextures; | |
| sk_sp<SkTypeface> fTypefaces[6]; | |
| using INHERITED = GM; | |
| }; | |
| ////////////////////////////////////////////////////////////////////////////// | |
| DEF_GM(return new FontCacheGM(/*allowMultipleTextures=*/true)) | |
| DEF_GM(return new FontCacheGM(/*allowMultipleTextures=*/false)) |