• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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