OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #ifndef GrBatchFontCache_DEFINED | 8 #ifndef GrBatchFontCache_DEFINED |
9 #define GrBatchFontCache_DEFINED | 9 #define GrBatchFontCache_DEFINED |
10 | 10 |
11 #include "GrBatchAtlas.h" | 11 #include "GrBatchAtlas.h" |
12 #include "GrFontScaler.h" | |
13 #include "GrGlyph.h" | 12 #include "GrGlyph.h" |
14 #include "SkGlyph.h" | 13 #include "SkGlyphCache.h" |
15 #include "SkTDynamicHash.h" | 14 #include "SkTDynamicHash.h" |
16 #include "SkVarAlloc.h" | 15 #include "SkVarAlloc.h" |
17 | 16 |
18 class GrBatchFontCache; | 17 class GrBatchFontCache; |
19 class GrGpu; | 18 class GrGpu; |
20 | 19 |
21 /** | 20 /** |
22 * The GrBatchTextStrike manages a pool of CPU backing memory for GrGlyphs. Th
is backing memory | 21 * The GrBatchTextStrike manages a pool of CPU backing memory for GrGlyphs. Th
is backing memory |
23 * is indexed by a PackedID and GrFontScaler. The GrFontScaler is what actually
creates the mask. | 22 * is indexed by a PackedID and SkGlyphCache. The SkGlyphCache is what actually
creates the mask. |
24 * The GrBatchTextStrike may outlive the generating GrFontScaler. However, it r
etains a copy | 23 * The GrBatchTextStrike may outlive the generating SkGlyphCache. However, it r
etains a copy |
25 * of it's SkDescriptor as a key to access (or regenerate) the GrFontScaler. Gr
BatchTextStrikes are | 24 * of it's SkDescriptor as a key to access (or regenerate) the SkGlyphCache. Gr
BatchTextStrikes are |
26 * created by and owned by a GrBatchFontCache. | 25 * created by and owned by a GrBatchFontCache. |
27 */ | 26 */ |
28 class GrBatchTextStrike : public SkNVRefCnt<GrBatchTextStrike> { | 27 class GrBatchTextStrike : public SkNVRefCnt<GrBatchTextStrike> { |
29 public: | 28 public: |
30 /** Owner is the cache that owns this strike. */ | 29 /** Owner is the cache that owns this strike. */ |
31 GrBatchTextStrike(GrBatchFontCache* owner, const SkDescriptor& fontScalerKey
); | 30 GrBatchTextStrike(GrBatchFontCache* owner, const SkDescriptor& fontScalerKey
); |
32 ~GrBatchTextStrike(); | 31 ~GrBatchTextStrike(); |
33 | 32 |
34 inline GrGlyph* getGlyph(const SkGlyph& skGlyph, GrGlyph::PackedID packed, | 33 inline GrGlyph* getGlyph(const SkGlyph& skGlyph, GrGlyph::PackedID packed, |
35 GrFontScaler* scaler) { | 34 SkGlyphCache* cache) { |
36 GrGlyph* glyph = fCache.find(packed); | 35 GrGlyph* glyph = fCache.find(packed); |
37 if (nullptr == glyph) { | 36 if (nullptr == glyph) { |
38 glyph = this->generateGlyph(skGlyph, packed, scaler); | 37 glyph = this->generateGlyph(skGlyph, packed, cache); |
39 } | 38 } |
40 return glyph; | 39 return glyph; |
41 } | 40 } |
42 | 41 |
43 // This variant of the above function is called by TextBatch. At this point
, it is possible | 42 // This variant of the above function is called by TextBatch. At this point
, it is possible |
44 // that the maskformat of the glyph differs from what we expect. In these c
ases we will just | 43 // that the maskformat of the glyph differs from what we expect. In these c
ases we will just |
45 // draw a clear square. | 44 // draw a clear square. |
46 // skbug:4143 crbug:510931 | 45 // skbug:4143 crbug:510931 |
47 inline GrGlyph* getGlyph(GrGlyph::PackedID packed, | 46 inline GrGlyph* getGlyph(GrGlyph::PackedID packed, |
48 GrMaskFormat expectedMaskFormat, | 47 GrMaskFormat expectedMaskFormat, |
49 GrFontScaler* scaler) { | 48 SkGlyphCache* cache) { |
50 GrGlyph* glyph = fCache.find(packed); | 49 GrGlyph* glyph = fCache.find(packed); |
51 if (nullptr == glyph) { | 50 if (nullptr == glyph) { |
52 // We could return this to the caller, but in practice it adds code
complexity for | 51 // We could return this to the caller, but in practice it adds code
complexity for |
53 // potentially little benefit(ie, if the glyph is not in our font ca
che, then its not | 52 // potentially little benefit(ie, if the glyph is not in our font ca
che, then its not |
54 // in the atlas and we're going to be doing a texture upload anyways
). | 53 // in the atlas and we're going to be doing a texture upload anyways
). |
55 const SkGlyph& skGlyph = scaler->grToSkGlyph(packed); | 54 const SkGlyph& skGlyph = GrToSkGlyph(cache, packed); |
56 glyph = this->generateGlyph(skGlyph, packed, scaler); | 55 glyph = this->generateGlyph(skGlyph, packed, cache); |
57 glyph->fMaskFormat = expectedMaskFormat; | 56 glyph->fMaskFormat = expectedMaskFormat; |
58 } | 57 } |
59 return glyph; | 58 return glyph; |
60 } | 59 } |
61 | 60 |
62 // returns true if glyph successfully added to texture atlas, false otherwis
e. If the glyph's | 61 // returns true if glyph successfully added to texture atlas, false otherwis
e. If the glyph's |
63 // mask format has changed, then addGlyphToAtlas will draw a clear box. Thi
s will almost never | 62 // mask format has changed, then addGlyphToAtlas will draw a clear box. Thi
s will almost never |
64 // happen. | 63 // happen. |
65 // TODO we can handle some of these cases if we really want to, but the long
term solution is to | 64 // TODO we can handle some of these cases if we really want to, but the long
term solution is to |
66 // get the actual glyph image itself when we get the glyph metrics. | 65 // get the actual glyph image itself when we get the glyph metrics. |
67 bool addGlyphToAtlas(GrDrawBatch::Target*, GrGlyph*, GrFontScaler*, | 66 bool addGlyphToAtlas(GrDrawBatch::Target*, GrGlyph*, SkGlyphCache*, |
68 GrMaskFormat expectedMaskFormat); | 67 GrMaskFormat expectedMaskFormat); |
69 | 68 |
70 // testing | 69 // testing |
71 int countGlyphs() const { return fCache.count(); } | 70 int countGlyphs() const { return fCache.count(); } |
72 | 71 |
73 // remove any references to this plot | 72 // remove any references to this plot |
74 void removeID(GrBatchAtlas::AtlasID); | 73 void removeID(GrBatchAtlas::AtlasID); |
75 | 74 |
76 // If a TextStrike is abandoned by the cache, then the caller must get a new
strike | 75 // If a TextStrike is abandoned by the cache, then the caller must get a new
strike |
77 bool isAbandoned() const { return fIsAbandoned; } | 76 bool isAbandoned() const { return fIsAbandoned; } |
78 | 77 |
79 static const SkDescriptor& GetKey(const GrBatchTextStrike& ts) { | 78 static const SkDescriptor& GetKey(const GrBatchTextStrike& ts) { |
80 return *ts.fFontScalerKey.getDesc(); | 79 return *ts.fFontScalerKey.getDesc(); |
81 } | 80 } |
82 | 81 |
83 static uint32_t Hash(const SkDescriptor& desc) { return desc.getChecksum();
} | 82 static uint32_t Hash(const SkDescriptor& desc) { return desc.getChecksum();
} |
84 | 83 |
85 private: | 84 private: |
86 SkTDynamicHash<GrGlyph, GrGlyph::PackedID> fCache; | 85 SkTDynamicHash<GrGlyph, GrGlyph::PackedID> fCache; |
87 SkAutoDescriptor fFontScalerKey; | 86 SkAutoDescriptor fFontScalerKey; |
88 SkVarAlloc fPool; | 87 SkVarAlloc fPool; |
89 | 88 |
90 GrBatchFontCache* fBatchFontCache; | 89 GrBatchFontCache* fBatchFontCache; |
91 int fAtlasedGlyphs; | 90 int fAtlasedGlyphs; |
92 bool fIsAbandoned; | 91 bool fIsAbandoned; |
93 | 92 |
94 GrGlyph* generateGlyph(const SkGlyph&, GrGlyph::PackedID, GrFontScaler*); | 93 static const SkGlyph& GrToSkGlyph(SkGlyphCache* cache, GrGlyph::PackedID id)
{ |
| 94 return cache->getGlyphIDMetrics(GrGlyph::UnpackID(id), |
| 95 GrGlyph::UnpackFixedX(id), |
| 96 GrGlyph::UnpackFixedY(id)); |
| 97 } |
| 98 |
| 99 GrGlyph* generateGlyph(const SkGlyph&, GrGlyph::PackedID, SkGlyphCache*); |
95 | 100 |
96 friend class GrBatchFontCache; | 101 friend class GrBatchFontCache; |
97 }; | 102 }; |
98 | 103 |
99 /* | 104 /* |
100 * GrBatchFontCache manages strikes which are indexed by a GrFontScaler. These
strikes can then be | 105 * GrBatchFontCache manages strikes which are indexed by a SkGlyphCache. These
strikes can then be |
101 * used to individual Glyph Masks. The GrBatchFontCache also manages GrBatchAtl
ases, though this is | 106 * used to individual Glyph Masks. The GrBatchFontCache also manages GrBatchAtl
ases, though this is |
102 * more or less transparent to the client(aside from atlasGeneration, described
below). | 107 * more or less transparent to the client(aside from atlasGeneration, described
below). |
103 * Note - we used to initialize the backing atlas for the GrBatchFontCache at in
itialization time. | 108 * Note - we used to initialize the backing atlas for the GrBatchFontCache at in
itialization time. |
104 * However, this caused a regression, even when the GrBatchFontCache was unused.
We now initialize | 109 * However, this caused a regression, even when the GrBatchFontCache was unused.
We now initialize |
105 * the backing atlases lazily. Its not immediately clear why this improves the
situation. | 110 * the backing atlases lazily. Its not immediately clear why this improves the
situation. |
106 */ | 111 */ |
107 class GrBatchFontCache { | 112 class GrBatchFontCache { |
108 public: | 113 public: |
109 GrBatchFontCache(GrContext*); | 114 GrBatchFontCache(GrContext*); |
110 ~GrBatchFontCache(); | 115 ~GrBatchFontCache(); |
111 // The user of the cache may hold a long-lived ref to the returned strike. H
owever, actions by | 116 // The user of the cache may hold a long-lived ref to the returned strike. H
owever, actions by |
112 // another client of the cache may cause the strike to be purged while it is
still reffed. | 117 // another client of the cache may cause the strike to be purged while it is
still reffed. |
113 // Therefore, the caller must check GrBatchTextStrike::isAbandoned() if ther
e are other | 118 // Therefore, the caller must check GrBatchTextStrike::isAbandoned() if ther
e are other |
114 // interactions with the cache since the strike was received. | 119 // interactions with the cache since the strike was received. |
115 inline GrBatchTextStrike* getStrike(GrFontScaler* scaler) { | 120 inline GrBatchTextStrike* getStrike(const SkGlyphCache* cache) { |
116 GrBatchTextStrike* strike = fCache.find(scaler->getKey()); | 121 GrBatchTextStrike* strike = fCache.find(cache->getDescriptor()); |
117 if (nullptr == strike) { | 122 if (nullptr == strike) { |
118 strike = this->generateStrike(scaler); | 123 strike = this->generateStrike(cache); |
119 } | 124 } |
120 return strike; | 125 return strike; |
121 } | 126 } |
122 | 127 |
123 void freeAll(); | 128 void freeAll(); |
124 | 129 |
125 // if getTexture returns nullptr, the client must not try to use other funct
ions on the | 130 // if getTexture returns nullptr, the client must not try to use other funct
ions on the |
126 // GrBatchFontCache which use the atlas. This function *must* be called fir
st, before other | 131 // GrBatchFontCache which use the atlas. This function *must* be called fir
st, before other |
127 // functions which use the atlas. | 132 // functions which use the atlas. |
128 GrTexture* getTexture(GrMaskFormat format) { | 133 GrTexture* getTexture(GrMaskFormat format) { |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
200 kARGB_GrMaskFormat, | 205 kARGB_GrMaskFormat, |
201 }; | 206 }; |
202 static_assert(SK_ARRAY_COUNT(sAtlasIndices) == kMaskFormatCount, "array_
size_mismatch"); | 207 static_assert(SK_ARRAY_COUNT(sAtlasIndices) == kMaskFormatCount, "array_
size_mismatch"); |
203 | 208 |
204 SkASSERT(sAtlasIndices[format] < kMaskFormatCount); | 209 SkASSERT(sAtlasIndices[format] < kMaskFormatCount); |
205 return sAtlasIndices[format]; | 210 return sAtlasIndices[format]; |
206 } | 211 } |
207 | 212 |
208 bool initAtlas(GrMaskFormat); | 213 bool initAtlas(GrMaskFormat); |
209 | 214 |
210 GrBatchTextStrike* generateStrike(GrFontScaler* scaler) { | 215 GrBatchTextStrike* generateStrike(const SkGlyphCache* cache) { |
211 GrBatchTextStrike* strike = new GrBatchTextStrike(this, scaler->getKey()
); | 216 GrBatchTextStrike* strike = new GrBatchTextStrike(this, cache->getDescri
ptor()); |
212 fCache.add(strike); | 217 fCache.add(strike); |
213 return strike; | 218 return strike; |
214 } | 219 } |
215 | 220 |
216 GrBatchAtlas* getAtlas(GrMaskFormat format) const { | 221 GrBatchAtlas* getAtlas(GrMaskFormat format) const { |
217 int atlasIndex = MaskFormatToAtlasIndex(format); | 222 int atlasIndex = MaskFormatToAtlasIndex(format); |
218 SkASSERT(fAtlases[atlasIndex]); | 223 SkASSERT(fAtlases[atlasIndex]); |
219 return fAtlases[atlasIndex]; | 224 return fAtlases[atlasIndex]; |
220 } | 225 } |
221 | 226 |
222 static void HandleEviction(GrBatchAtlas::AtlasID, void*); | 227 static void HandleEviction(GrBatchAtlas::AtlasID, void*); |
223 | 228 |
224 using StrikeHash = SkTDynamicHash<GrBatchTextStrike, SkDescriptor>; | 229 using StrikeHash = SkTDynamicHash<GrBatchTextStrike, SkDescriptor>; |
225 GrContext* fContext; | 230 GrContext* fContext; |
226 StrikeHash fCache; | 231 StrikeHash fCache; |
227 GrBatchAtlas* fAtlases[kMaskFormatCount]; | 232 GrBatchAtlas* fAtlases[kMaskFormatCount]; |
228 GrBatchTextStrike* fPreserveStrike; | 233 GrBatchTextStrike* fPreserveStrike; |
229 GrBatchAtlasConfig fAtlasConfigs[kMaskFormatCount]; | 234 GrBatchAtlasConfig fAtlasConfigs[kMaskFormatCount]; |
230 }; | 235 }; |
231 | 236 |
232 #endif | 237 #endif |
OLD | NEW |