1 /*
2 * Copyright 2022 Google LLC
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 #include "src/gpu/text/GrGlyphVector.h"
9
10 #include "src/core/SkReadBuffer.h"
11 #include "src/core/SkStrikeCache.h"
12 #include "src/core/SkStrikeSpec.h"
13 #include "src/core/SkWriteBuffer.h"
14 #include "src/gpu/text/GrAtlasManager.h"
15
GrGlyphVector(sk_sp<SkStrike> && strike,SkSpan<Variant> glyphs)16 GrGlyphVector::GrGlyphVector(sk_sp<SkStrike>&& strike, SkSpan<Variant> glyphs)
17 : fStrike{std::move(strike)}
18 , fGlyphs{glyphs} {
19 SkASSERT(fStrike != nullptr);
20 SkASSERT(fGlyphs.size() > 0);
21 }
22
Make(sk_sp<SkStrike> && strike,SkSpan<SkGlyphVariant> glyphs,GrSubRunAllocator * alloc)23 GrGlyphVector GrGlyphVector::Make(
24 sk_sp<SkStrike>&& strike, SkSpan<SkGlyphVariant> glyphs, GrSubRunAllocator* alloc) {
25 SkASSERT(strike != nullptr);
26 SkASSERT(glyphs.size() > 0);
27 Variant* variants = alloc->makePODArray<Variant>(glyphs.size());
28 for (auto [i, gv] : SkMakeEnumerate(glyphs)) {
29 variants[i] = gv.glyph()->getPackedID();
30 }
31
32 return GrGlyphVector{std::move(strike), SkMakeSpan(variants, glyphs.size())};
33 }
34
MakeFromBuffer(SkReadBuffer & buffer,GrSubRunAllocator * alloc)35 std::optional<GrGlyphVector> GrGlyphVector::MakeFromBuffer(SkReadBuffer& buffer,
36 GrSubRunAllocator* alloc) {
37 auto descriptor = SkAutoDescriptor::MakeFromBuffer(buffer);
38 if (!descriptor.has_value()) { return {}; }
39
40 sk_sp<SkStrike> strike = SkStrikeCache::GlobalStrikeCache()->findStrike(*descriptor->getDesc());
41
42 int32_t glyphCount = buffer.read32();
43 // Since the glyph count can never be zero. There was a buffer reading problem.
44 if (glyphCount == 0) { return {}; }
45
46 // Make sure we can do the multiply in the check below and not overflow an int.
47 if ((int)(INT_MAX / sizeof(uint32_t)) < glyphCount) { return {}; }
48
49 // Check for enough bytes to populate the packedGlyphID array. If not enought something has
50 // gone wrong.
51 if (glyphCount * sizeof(uint32_t) > buffer.available()) { return {}; }
52
53 Variant* variants = alloc->makePODArray<Variant>(glyphCount);
54 for (int i = 0; i < glyphCount; i++) {
55 variants[i].packedGlyphID = SkPackedGlyphID(buffer.readUInt());
56 }
57 return {GrGlyphVector{std::move(strike), SkMakeSpan(variants, glyphCount)}};
58 }
59
flatten(SkWriteBuffer & buffer)60 void GrGlyphVector::flatten(SkWriteBuffer& buffer) {
61 // There should never be a glyph vector with zero glyphs.
62 SkASSERT(fGlyphs.size() != 0);
63 if (!fStrike) { SK_ABORT("Can't flatten with already drawn."); }
64
65 fStrike->getDescriptor().flatten(buffer);
66
67 // Write out the span of packedGlyphIDs.
68 buffer.write32(SkTo<int32_t>(fGlyphs.size()));
69 for (auto variant : fGlyphs) {
70 buffer.writeUInt(variant.packedGlyphID.value());
71 }
72 }
73
glyphs() const74 SkSpan<const GrGlyph*> GrGlyphVector::glyphs() const {
75 return SkMakeSpan(reinterpret_cast<const GrGlyph**>(fGlyphs.data()), fGlyphs.size());
76 }
77
78 // packedGlyphIDToGrGlyph must be run in single-threaded mode.
79 // If fStrike != nullptr then the conversion to GrGlyph* has not happened.
packedGlyphIDToGrGlyph(GrStrikeCache * cache)80 void GrGlyphVector::packedGlyphIDToGrGlyph(GrStrikeCache* cache) {
81 if (fStrike != nullptr) {
82 fGrStrike = cache->findOrCreateStrike(fStrike->strikeSpec());
83
84 for (auto& variant : fGlyphs) {
85 variant.grGlyph = fGrStrike->getGlyph(variant.packedGlyphID);
86 }
87
88 // Drop the ref on the strike that was taken in the SkGlyphRunPainter process* methods.
89 fStrike = nullptr;
90 }
91 }
92
regenerateAtlas(int begin,int end,GrMaskFormat maskFormat,int srcPadding,GrMeshDrawTarget * target,bool bilerpPadding)93 std::tuple<bool, int> GrGlyphVector::regenerateAtlas(int begin, int end,
94 GrMaskFormat maskFormat,
95 int srcPadding,
96 GrMeshDrawTarget* target,
97 bool bilerpPadding) {
98 GrAtlasManager* atlasManager = target->atlasManager();
99 GrDeferredUploadTarget* uploadTarget = target->deferredUploadTarget();
100
101 uint64_t currentAtlasGen = atlasManager->atlasGeneration(maskFormat);
102
103 this->packedGlyphIDToGrGlyph(target->strikeCache());
104
105 if (fAtlasGeneration != currentAtlasGen) {
106 // Calculate the texture coordinates for the vertexes during first use (fAtlasGeneration
107 // is set to kInvalidAtlasGeneration) or the atlas has changed in subsequent calls..
108 fBulkUseToken.reset();
109
110 SkBulkGlyphMetricsAndImages metricsAndImages{fGrStrike->strikeSpec()};
111
112 // Update the atlas information in the GrStrike.
113 auto tokenTracker = uploadTarget->tokenTracker();
114 auto glyphs = fGlyphs.subspan(begin, end - begin);
115 int glyphsPlacedInAtlas = 0;
116 bool success = true;
117 for (const Variant& variant : glyphs) {
118 GrGlyph* grGlyph = variant.grGlyph;
119 SkASSERT(grGlyph != nullptr);
120
121 if (!atlasManager->hasGlyph(maskFormat, grGlyph)) {
122 const SkGlyph& skGlyph = *metricsAndImages.glyph(grGlyph->fPackedID);
123 auto code = atlasManager->addGlyphToAtlas(
124 skGlyph, grGlyph, srcPadding, target->resourceProvider(),
125 uploadTarget, bilerpPadding);
126 if (code != GrDrawOpAtlas::ErrorCode::kSucceeded) {
127 success = code != GrDrawOpAtlas::ErrorCode::kError;
128 break;
129 }
130 }
131 atlasManager->addGlyphToBulkAndSetUseToken(
132 &fBulkUseToken, maskFormat, grGlyph,
133 tokenTracker->nextDrawToken());
134 glyphsPlacedInAtlas++;
135 }
136
137 // Update atlas generation if there are no more glyphs to put in the atlas.
138 if (success && begin + glyphsPlacedInAtlas == SkCount(fGlyphs)) {
139 // Need to get the freshest value of the atlas' generation because
140 // updateTextureCoordinates may have changed it.
141 fAtlasGeneration = atlasManager->atlasGeneration(maskFormat);
142 }
143
144 return {success, glyphsPlacedInAtlas};
145 } else {
146 // The atlas hasn't changed, so our texture coordinates are still valid.
147 if (end == SkCount(fGlyphs)) {
148 // The atlas hasn't changed and the texture coordinates are all still valid. Update
149 // all the plots used to the new use token.
150 atlasManager->setUseTokenBulk(fBulkUseToken,
151 uploadTarget->tokenTracker()->nextDrawToken(),
152 maskFormat);
153 }
154 return {true, end - begin};
155 }
156 }
157
158