diff --git a/bench/GlyphQuadFillBench.cpp b/bench/GlyphQuadFillBench.cpp new file mode 100644 index 0000000000..680a16c2fe --- /dev/null +++ b/bench/GlyphQuadFillBench.cpp @@ -0,0 +1,81 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "bench/Benchmark.h" +#include "include/core/SkFont.h" +#include "include/core/SkTypeface.h" +#include "include/gpu/GrDirectContext.h" +#include "include/gpu/GrRecordingContext.h" +#include "src/core/SkUtils.h" +#include "src/gpu/GrRecordingContextPriv.h" +#include "src/gpu/GrRenderTargetContext.h" +#include "src/gpu/SkGr.h" +#include "src/gpu/text/GrTextBlob.h" +#include "src/utils/SkUTF.h" + + +// From Project Guttenberg. This is UTF-8 text. +static const char* gText = + "Call me Ishmael. Some years ago--never mind how long precisely"; + +class DirectMaskGlyphVertexFillBenchmark : public Benchmark { + bool isSuitableFor(Backend backend) override { + return backend == kGPU_Backend; + } + + const char* onGetName() override { + return "DirectMaskGlyphVertexFillBenchmark"; + } + + void onPerCanvasPreDraw(SkCanvas* canvas) override { + auto typeface = SkTypeface::MakeFromName("monospace", SkFontStyle()); + SkFont font(typeface); + + SkMatrix view = SkMatrix::I(); + size_t len = strlen(gText); + SkGlyphRunBuilder builder; + SkPaint paint; + builder.drawTextUTF8(paint, font, gText, len, {100, 100}); + auto glyphRunList = builder.useGlyphRunList(); + SkASSERT(!glyphRunList.empty()); + fBlob = GrTextBlob::Make(glyphRunList, view); + SkSurfaceProps props{SkSurfaceProps::kLegacyFontHost_InitType}; + auto colorSpace = SkColorSpace::MakeSRGB(); + SkGlyphRunListPainter painter{props, kUnknown_SkColorType, + colorSpace.get(), SkStrikeCache::GlobalStrikeCache()}; + + GrSDFTOptions options{256, 256}; + painter.processGlyphRunList( + glyphRunList, view, props, false, options, fBlob.get()); + + + SkASSERT(fBlob->subRunList().head() != nullptr); + GrAtlasSubRun* subRun = static_cast(fBlob->subRunList().head()); + subRun->testingOnly_packedGlyphIDToGrGlyph(&fCache); + fVertices.reset(new char[subRun->vertexStride() * subRun->glyphCount() * 4]); + } + + void onDraw(int loops, SkCanvas* canvas) override { + GrAtlasSubRun* subRun = static_cast(fBlob->subRunList().head()); + + SkIRect clip = SkIRect::MakeEmpty(); + SkPaint paint; + GrColor grColor = SkColorToPremulGrColor(paint.getColor()); + + for (int loop = 0; loop < loops; loop++) { + subRun->fillVertexData(fVertices.get(), 0, subRun->glyphCount(), + grColor, SkMatrix::I(), {100, 100}, clip); + } + } + +private: + sk_sp fBlob; + GrStrikeCache fCache; + std::unique_ptr fVertices; +}; + +DEF_BENCH(return new DirectMaskGlyphVertexFillBenchmark{}); diff --git a/gn/bench.gni b/gn/bench.gni index 4553ca90fa..79aa70ffdb 100644 --- a/gn/bench.gni +++ b/gn/bench.gni @@ -51,6 +51,7 @@ bench_sources = [ "$_bench/GMBench.cpp", "$_bench/GameBench.cpp", "$_bench/GeometryBench.cpp", + "$_bench/GlyphQuadFillBench.cpp", "$_bench/GrMemoryPoolBench.cpp", "$_bench/GrMipmapBench.cpp", "$_bench/GrQuadBench.cpp", diff --git a/src/gpu/GrDrawOpAtlas.h b/src/gpu/GrDrawOpAtlas.h index a6d1c4e482..373f3e6885 100644 --- a/src/gpu/GrDrawOpAtlas.h +++ b/src/gpu/GrDrawOpAtlas.h @@ -139,7 +139,7 @@ public: SkDEBUGCODE(void validate(const GrDrawOpAtlas*) const;) - PlotLocator fPlotLocator; + PlotLocator fPlotLocator{0, 0, 0}; // The inset padded bounds in the atlas. GrIRect16 fRect{0, 0, 0, 0}; diff --git a/src/gpu/text/GrTextBlob.cpp b/src/gpu/text/GrTextBlob.cpp index 053ee403ef..6c2c9c8edc 100644 --- a/src/gpu/text/GrTextBlob.cpp +++ b/src/gpu/text/GrTextBlob.cpp @@ -142,6 +142,16 @@ SkSpan GrGlyphVector::glyphs() const { return SkMakeSpan(reinterpret_cast(fGlyphs.data()), fGlyphs.size()); } +void GrGlyphVector::packedGlyphIDToGrGlyph(GrStrikeCache* cache) { + if (fStrike == nullptr) { + fStrike = fStrikeSpec.findOrCreateGrStrike(cache); + + for (auto& variant : fGlyphs) { + variant.grGlyph = fStrike->getGlyph(variant.packedGlyphID); + } + } +} + std::tuple GrGlyphVector::regenerateAtlas(int begin, int end, GrMaskFormat maskFormat, int srcPadding, @@ -152,13 +162,7 @@ std::tuple GrGlyphVector::regenerateAtlas(int begin, int end, uint64_t currentAtlasGen = atlasManager->atlasGeneration(maskFormat); - if (fStrike == nullptr) { - fStrike = fStrikeSpec.findOrCreateGrStrike(target->strikeCache()); - - for (auto& variant : fGlyphs) { - variant.grGlyph = fStrike->getGlyph(variant.packedGlyphID); - } - } + this->packedGlyphIDToGrGlyph(target->strikeCache()); if (fAtlasGeneration != currentAtlasGen) { // Calculate the texture coordinates for the vertexes during first use (fAtlasGeneration @@ -366,6 +370,10 @@ GrDirectMaskSubRun::makeAtlasTextOp(const GrClip* clip, const SkMatrixProvider& return {clip, std::move(op)}; } +void GrDirectMaskSubRun::testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache *cache) { + fGlyphs.packedGlyphIDToGrGlyph(cache); +} + std::tuple GrDirectMaskSubRun::regenerateAtlas(int begin, int end, GrMeshDrawOp::Target* target) const { return fGlyphs.regenerateAtlas(begin, end, fMaskFormat, 0, target); @@ -568,6 +576,10 @@ GrTransformedMaskSubRun::makeAtlasTextOp(const GrClip* clip, return {clip, std::move(op)}; } +void GrTransformedMaskSubRun::testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache *cache) { + fGlyphs.packedGlyphIDToGrGlyph(cache); +} + std::tuple GrTransformedMaskSubRun::regenerateAtlas(int begin, int end, GrMeshDrawOp::Target* target) const { return fGlyphs.regenerateAtlas(begin, end, fMaskFormat, 1, target, true); @@ -836,6 +848,10 @@ void GrSDFTSubRun::draw(const GrClip* clip, } } +void GrSDFTSubRun::testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache *cache) { + fGlyphs.packedGlyphIDToGrGlyph(cache); +} + std::tuple GrSDFTSubRun::regenerateAtlas( int begin, int end, GrMeshDrawOp::Target *target) const { diff --git a/src/gpu/text/GrTextBlob.h b/src/gpu/text/GrTextBlob.h index 81dfae2185..1308438b43 100644 --- a/src/gpu/text/GrTextBlob.h +++ b/src/gpu/text/GrTextBlob.h @@ -242,6 +242,8 @@ public: GrColor color, const SkMatrix& drawMatrix, SkPoint drawOrigin, SkIRect clip) const = 0; + virtual void testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache* cache) = 0; + // This call is not thread safe. It should only be called from GrDrawOp::onPrepare which // is single threaded. virtual std::tuple regenerateAtlas( @@ -292,6 +294,9 @@ public: SkSpan glyphs() const; SkScalar strikeToSourceRatio() const { return fStrikeSpec.strikeToSourceRatio(); } + + void packedGlyphIDToGrGlyph(GrStrikeCache* cache); + std::tuple regenerateAtlas( int begin, int end, GrMaskFormat maskFormat, @@ -347,6 +352,8 @@ public: const SkGlyphRunList& glyphRunList, GrRenderTargetContext* rtc) const override; + void testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache *cache) override; + std::tuple regenerateAtlas(int begin, int end, GrMeshDrawOp::Target* target) const override; @@ -405,6 +412,8 @@ public: const SkGlyphRunList& glyphRunList, GrRenderTargetContext* rtc) const override; + void testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache *cache) override; + std::tuple regenerateAtlas( int begin, int end, GrMeshDrawOp::Target* target) const override; @@ -468,6 +477,8 @@ public: const SkGlyphRunList& glyphRunList, GrRenderTargetContext* rtc) const override; + void testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache *cache) override; + std::tuple regenerateAtlas( int begin, int end, GrMeshDrawOp::Target* target) const override;