| /* | |
| * Copyright 2018 Google LLC | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| // GM to stress TextBlob regeneration and the GPU font cache | |
| // It's not necessary to run this with CPU configs | |
| // | |
| // The point here is to draw a set of text that will fit in one Plot, and then some large | |
| // text. After a flush we draw the first set of text again with a slightly different color, | |
| // and then enough new large text to spill the entire atlas. What *should* happen is that | |
| // the Plot with the first set of text will not get overwritten by the new large text. | |
| #include "gm/gm.h" | |
| #include "include/core/SkCanvas.h" | |
| #include "include/core/SkColor.h" | |
| #include "include/core/SkFont.h" | |
| #include "include/core/SkFontMgr.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/SkTextBlob.h" | |
| #include "include/core/SkTypeface.h" | |
| #include "include/core/SkTypes.h" | |
| #include "include/private/SkTemplates.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/gpu/ganesh/GrRecordingContext.h" | |
| #include "include/private/gpu/ganesh/GrTypesPriv.h" | |
| #include "src/gpu/ganesh/GrDirectContextPriv.h" | |
| #endif | |
| #if defined(SK_GRAPHITE) | |
| #include "include/gpu/graphite/ContextOptions.h" | |
| #endif | |
| using namespace skia_private; | |
| using MaskFormat = skgpu::MaskFormat; | |
| static sk_sp<SkTextBlob> make_blob(const SkString& text, const SkFont& font) { | |
| size_t len = text.size(); | |
| AutoTArray<SkScalar> pos(len); | |
| AutoTArray<SkGlyphID> glyphs(len); | |
| font.textToGlyphs(text.c_str(), len, SkTextEncoding::kUTF8, glyphs); | |
| font.getXPos(glyphs, pos); | |
| return SkTextBlob::MakeFromPosTextH(text.c_str(), len, pos, 0, font); | |
| } | |
| class FontRegenGM : public skiagm::GM { | |
| #if defined(SK_GANESH) | |
| void modifyGrContextOptions(GrContextOptions* options) override { | |
| options->fGlyphCacheTextureMaximumBytes = 0; | |
| options->fAllowMultipleGlyphCacheTextures = GrContextOptions::Enable::kNo; | |
| } | |
| #endif | |
| #if defined(SK_GRAPHITE) | |
| void modifyGraphiteContextOptions(skgpu::graphite::ContextOptions* options) const override { | |
| options->fGlyphCacheTextureMaximumBytes = 0; | |
| options->fAllowMultipleAtlasTextures = false; | |
| } | |
| #endif | |
| SkString getName() const override { return SkString("fontregen"); } | |
| SkISize getISize() override { return {kSize, kSize}; } | |
| void onOnceBeforeDraw() override { | |
| this->setBGColor(SK_ColorLTGRAY); | |
| auto tf = ToolUtils::CreatePortableTypeface("sans-serif", SkFontStyle::Normal()); | |
| static const SkString kTexts[] = { | |
| SkString("abcdefghijklmnopqrstuvwxyz"), | |
| SkString("ABCDEFGHI"), | |
| SkString("NOPQRSTUV") | |
| }; | |
| SkFont font; | |
| font.setEdging(SkFont::Edging::kAntiAlias); | |
| font.setSubpixel(false); | |
| font.setSize(80); | |
| font.setTypeface(tf); | |
| fBlobs[0] = make_blob(kTexts[0], font); | |
| font.setSize(162); | |
| fBlobs[1] = make_blob(kTexts[1], font); | |
| fBlobs[2] = make_blob(kTexts[2], font); | |
| } | |
| DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override { | |
| SkPaint paint; | |
| paint.setColor(SK_ColorBLACK); | |
| canvas->drawTextBlob(fBlobs[0], 10, 80, paint); | |
| canvas->drawTextBlob(fBlobs[1], 10, 225, paint); | |
| #if defined(SK_GANESH) | |
| auto dContext = GrAsDirectContext(canvas->recordingContext()); | |
| if (dContext) { | |
| dContext->flushAndSubmit(); | |
| } | |
| #endif | |
| paint.setColor(0xFF010101); | |
| canvas->drawTextBlob(fBlobs[0], 10, 305, paint); | |
| canvas->drawTextBlob(fBlobs[2], 10, 465, paint); | |
| #if defined(SK_GANESH) | |
| // Debugging tool for Ganesh. | |
| static const bool kShowAtlas = false; | |
| if (kShowAtlas && dContext) { | |
| auto img = dContext->priv().testingOnly_getFontAtlasImage(MaskFormat::kA8); | |
| canvas->drawImage(img, 200, 0); | |
| } | |
| #endif | |
| return DrawResult::kOk; | |
| } | |
| private: | |
| inline static constexpr int kSize = 512; | |
| sk_sp<SkTextBlob> fBlobs[3]; | |
| using INHERITED = GM; | |
| }; | |
| ////////////////////////////////////////////////////////////////////////////// | |
| DEF_GM(return new FontRegenGM()) | |
| /////////////////////////////////////////////////////////////////////////////// | |
| class BadAppleGM : public skiagm::GM { | |
| SkString getName() const override { return SkString("badapple"); } | |
| SkISize getISize() override { return {kSize, kSize}; } | |
| void onOnceBeforeDraw() override { | |
| this->setBGColor(SK_ColorWHITE); | |
| auto fm = ToolUtils::TestFontMgr(); | |
| static const SkString kTexts[] = { | |
| SkString("Meet"), | |
| SkString("iPad Pro"), | |
| }; | |
| SkFont font = ToolUtils::DefaultPortableFont(); | |
| font.setEdging(SkFont::Edging::kSubpixelAntiAlias); | |
| font.setSubpixel(true); | |
| font.setSize(256); | |
| fBlobs[0] = make_blob(kTexts[0], font); | |
| fBlobs[1] = make_blob(kTexts[1], font); | |
| } | |
| void onDraw(SkCanvas* canvas) override { | |
| SkPaint paint; | |
| paint.setColor(0xFF111111); | |
| canvas->drawTextBlob(fBlobs[0], 10, 260, paint); | |
| canvas->drawTextBlob(fBlobs[1], 10, 500, paint); | |
| } | |
| private: | |
| inline static constexpr int kSize = 512; | |
| sk_sp<SkTextBlob> fBlobs[3]; | |
| using INHERITED = GM; | |
| }; | |
| ////////////////////////////////////////////////////////////////////////////// | |
| DEF_GM(return new BadAppleGM()) |