OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright 2016 Google Inc. | |
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 "GrAtlasTextBlob.h" | |
9 | |
10 #include "GrBatchFlushState.h" | |
11 | |
12 #include "SkDistanceFieldGen.h" | |
13 #include "SkGlyphCache.h" | |
14 | |
15 #include "batches/GrAtlasTextBatch.h" | |
16 | |
17 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
18 // A large template to handle regenerating the vertices of a textblob with as fe w branches as | |
19 // possible | |
20 template <bool regenPos, bool regenCol, bool regenTexCoords> | |
21 inline void regen_vertices(intptr_t vertex, const GrGlyph* glyph, size_t vertexS tride, | |
22 bool useDistanceFields, SkScalar transX, SkScalar tra nsY, | |
23 GrColor color) { | |
24 int u0, v0, u1, v1; | |
25 if (regenTexCoords) { | |
26 SkASSERT(glyph); | |
27 int width = glyph->fBounds.width(); | |
28 int height = glyph->fBounds.height(); | |
29 | |
30 if (useDistanceFields) { | |
31 u0 = glyph->fAtlasLocation.fX + SK_DistanceFieldInset; | |
32 v0 = glyph->fAtlasLocation.fY + SK_DistanceFieldInset; | |
33 u1 = u0 + width - 2 * SK_DistanceFieldInset; | |
34 v1 = v0 + height - 2 * SK_DistanceFieldInset; | |
35 } else { | |
36 u0 = glyph->fAtlasLocation.fX; | |
37 v0 = glyph->fAtlasLocation.fY; | |
38 u1 = u0 + width; | |
39 v1 = v0 + height; | |
40 } | |
41 } | |
42 | |
43 // This is a bit wonky, but sometimes we have LCD text, in which case we won 't have color | |
44 // vertices, hence vertexStride - sizeof(SkIPoint16) | |
45 intptr_t colorOffset = sizeof(SkPoint); | |
46 intptr_t texCoordOffset = vertexStride - sizeof(SkIPoint16); | |
47 | |
48 // V0 | |
49 if (regenPos) { | |
50 SkPoint* point = reinterpret_cast<SkPoint*>(vertex); | |
51 point->fX += transX; | |
52 point->fY += transY; | |
53 } | |
54 | |
55 if (regenCol) { | |
56 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + colorOffset); | |
57 *vcolor = color; | |
58 } | |
59 | |
60 if (regenTexCoords) { | |
61 SkIPoint16* textureCoords = reinterpret_cast<SkIPoint16*>(vertex + texCo ordOffset); | |
62 textureCoords->set(u0, v0); | |
63 } | |
64 vertex += vertexStride; | |
65 | |
66 // V1 | |
67 if (regenPos) { | |
68 SkPoint* point = reinterpret_cast<SkPoint*>(vertex); | |
69 point->fX += transX; | |
70 point->fY += transY; | |
71 } | |
72 | |
73 if (regenCol) { | |
74 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + colorOffset); | |
75 *vcolor = color; | |
76 } | |
77 | |
78 if (regenTexCoords) { | |
79 SkIPoint16* textureCoords = reinterpret_cast<SkIPoint16*>(vertex + texCo ordOffset); | |
80 textureCoords->set(u0, v1); | |
81 } | |
82 vertex += vertexStride; | |
83 | |
84 // V2 | |
85 if (regenPos) { | |
86 SkPoint* point = reinterpret_cast<SkPoint*>(vertex); | |
87 point->fX += transX; | |
88 point->fY += transY; | |
89 } | |
90 | |
91 if (regenCol) { | |
92 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + colorOffset); | |
93 *vcolor = color; | |
94 } | |
95 | |
96 if (regenTexCoords) { | |
97 SkIPoint16* textureCoords = reinterpret_cast<SkIPoint16*>(vertex + texCo ordOffset); | |
98 textureCoords->set(u1, v1); | |
99 } | |
100 vertex += vertexStride; | |
101 | |
102 // V3 | |
103 if (regenPos) { | |
104 SkPoint* point = reinterpret_cast<SkPoint*>(vertex); | |
105 point->fX += transX; | |
106 point->fY += transY; | |
107 } | |
108 | |
109 if (regenCol) { | |
110 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + colorOffset); | |
111 *vcolor = color; | |
112 } | |
113 | |
114 if (regenTexCoords) { | |
115 SkIPoint16* textureCoords = reinterpret_cast<SkIPoint16*>(vertex + texCo ordOffset); | |
116 textureCoords->set(u1, v0); | |
117 } | |
118 } | |
119 | |
120 template <bool regenPos, bool regenCol, bool regenTexCoords, bool regenGlyphs> | |
121 void GrAtlasTextBlob::regenInBatch(GrDrawBatch::Target* target, | |
122 GrBatchFontCache* fontCache, | |
jvanverth1
2016/02/12 18:51:38
indenting
| |
123 GrBlobRegenHelper *helper, | |
124 Run* run, | |
125 Run::SubRunInfo* info, SkGlyphCach e** cache, | |
126 SkTypeface** typeface, GrFontScale r** scaler, | |
127 const SkDescriptor** desc, | |
128 int glyphCount, size_t vertexStrid e, | |
129 GrColor color, SkScalar transX, | |
130 SkScalar transY) const { | |
131 static_assert(!regenGlyphs || regenTexCoords, "must regenTexCoords along reg enGlyphs"); | |
132 GrBatchTextStrike* strike = nullptr; | |
133 if (regenTexCoords) { | |
134 info->resetBulkUseToken(); | |
135 | |
136 // We can reuse if we have a valid strike and our descriptors / typeface are the | |
137 // same. The override descriptor is only for the non distance field tex t within | |
138 // a run | |
139 const SkDescriptor* newDesc = (run->fOverrideDescriptor && !info->drawAs DistanceFields()) ? | |
140 run->fOverrideDescriptor->getDesc() : | |
141 run->fDescriptor.getDesc(); | |
142 if (!*cache || !SkTypeface::Equal(*typeface, run->fTypeface) || | |
143 !((*desc)->equals(*newDesc))) { | |
144 if (*cache) { | |
145 SkGlyphCache::AttachCache(*cache); | |
146 } | |
147 *desc = newDesc; | |
148 *cache = SkGlyphCache::DetachCache(run->fTypeface, *desc); | |
149 *scaler = GrTextContext::GetGrFontScaler(*cache); | |
150 *typeface = run->fTypeface; | |
151 } | |
152 | |
153 if (regenGlyphs) { | |
154 strike = fontCache->getStrike(*scaler); | |
155 } else { | |
156 strike = info->strike(); | |
157 } | |
158 } | |
159 | |
160 bool brokenRun = false; | |
161 for (int glyphIdx = 0; glyphIdx < glyphCount; glyphIdx++) { | |
162 GrGlyph* glyph = nullptr; | |
163 if (regenTexCoords) { | |
164 size_t glyphOffset = glyphIdx + info->glyphStartIndex(); | |
165 | |
166 if (regenGlyphs) { | |
167 // Get the id from the old glyph, and use the new strike to look up | |
168 // the glyph. | |
169 GrGlyph::PackedID id = fGlyphs[glyphOffset]->fPackedID; | |
170 fGlyphs[glyphOffset] = strike->getGlyph(id, info->maskFormat(), *scaler); | |
171 SkASSERT(id == fGlyphs[glyphOffset]->fPackedID); | |
172 } | |
173 glyph = fGlyphs[glyphOffset]; | |
174 SkASSERT(glyph && glyph->fMaskFormat == info->maskFormat()); | |
175 | |
176 if (!fontCache->hasGlyph(glyph) && | |
177 !strike->addGlyphToAtlas(target, glyph, *scaler, info->maskForma t())) { | |
178 helper->flush(); | |
179 brokenRun = glyphIdx > 0; | |
180 | |
181 SkDEBUGCODE(bool success =) strike->addGlyphToAtlas(target, | |
182 glyph, | |
183 *scaler, | |
184 info->maskFo rmat()); | |
185 SkASSERT(success); | |
186 } | |
187 fontCache->addGlyphToBulkAndSetUseToken(info->bulkUseToken(), glyph, | |
188 target->currentToken()); | |
189 } | |
190 | |
191 intptr_t vertex = reinterpret_cast<intptr_t>(fVertices); | |
192 vertex += info->vertexStartIndex(); | |
193 vertex += vertexStride * glyphIdx * GrAtlasTextBatch::kVerticesPerGlyph; | |
194 regen_vertices<regenPos, regenCol, regenTexCoords>(vertex, glyph, vertex Stride, | |
195 info->drawAsDistanceF ields(), transX, | |
196 transY, color); | |
197 helper->incGlyphCount(); | |
198 } | |
199 | |
200 // We may have changed the color so update it here | |
201 info->setColor(color); | |
202 if (regenTexCoords) { | |
203 if (regenGlyphs) { | |
204 info->setStrike(strike); | |
205 } | |
206 info->setAtlasGeneration(brokenRun ? GrBatchAtlas::kInvalidAtlasGenerati on : | |
207 fontCache->atlasGeneration(info->maskFormat())) ; | |
208 } | |
209 } | |
210 | |
211 enum RegenMask { | |
212 kNoRegen = 0x0, | |
213 kRegenPos = 0x1, | |
214 kRegenCol = 0x2, | |
215 kRegenTex = 0x4, | |
216 kRegenGlyph = 0x8 | kRegenTex, // we have to regenerate the texture coords w hen we regen glyphs | |
217 | |
218 // combinations | |
219 kRegenPosCol = kRegenPos | kRegenCol, | |
220 kRegenPosTex = kRegenPos | kRegenTex, | |
221 kRegenPosTexGlyph = kRegenPos | kRegenGlyph, | |
222 kRegenPosColTex = kRegenPos | kRegenCol | kRegenTex, | |
223 kRegenPosColTexGlyph = kRegenPos | kRegenCol | kRegenGlyph, | |
224 kRegenColTex = kRegenCol | kRegenTex, | |
225 kRegenColTexGlyph = kRegenCol | kRegenGlyph, | |
226 }; | |
227 | |
228 #define REGEN_ARGS target, fontCache, helper, &run, &info, cache, typeface, scal er, desc, \ | |
229 *glyphCount, vertexStride, color, transX, transY | |
230 | |
231 void GrAtlasTextBlob::regenInBatch(GrDrawBatch::Target* target, | |
232 GrBatchFontCache* fontCache, | |
233 GrBlobRegenHelper *helper, | |
234 int runIndex, int subRunIndex, SkGlyphCache** cache, | |
235 SkTypeface** typeface, GrFontScaler** scaler, | |
236 const SkDescriptor** desc, size_t vertexStrid e, | |
237 GrColor color, SkScalar transX, | |
238 SkScalar transY, | |
239 void** vertices, size_t* byteCount, int* glyp hCount) { | |
240 Run& run = fRuns[runIndex]; | |
241 Run::SubRunInfo& info = run.fSubRunInfo[subRunIndex]; | |
242 | |
243 uint64_t currentAtlasGen = fontCache->atlasGeneration(info.maskFormat()); | |
244 | |
245 // Because the GrBatchFontCache may evict the strike a blob depends on using for | |
246 // generating its texture coords, we have to track whether or not the strike has | |
247 // been abandoned. If it hasn't been abandoned, then we can use the GrGlyph *s as is | |
248 // otherwise we have to get the new strike, and use that to get the correct glyphs. | |
249 // Because we do not have the packed ids, and thus can't look up our glyphs in the | |
250 // new strike, we instead keep our ref to the old strike and use the packed ids from | |
251 // it. These ids will still be valid as long as we hold the ref. When we a re done | |
252 // updating our cache of the GrGlyph*s, we drop our ref on the old strike | |
253 bool regenerateGlyphs = info.strike()->isAbandoned(); | |
254 bool regenerateTextureCoords = info.atlasGeneration() != currentAtlasGen || | |
255 regenerateGlyphs; | |
256 bool regenerateColors = kARGB_GrMaskFormat != info.maskFormat() && | |
257 info.color() != color; | |
258 bool regeneratePositions = transX != 0.f || transY != 0.f; | |
259 *glyphCount = info.glyphCount(); | |
260 | |
261 uint32_t regenMaskBits = kNoRegen; | |
262 regenMaskBits |= regeneratePositions ? kRegenPos : 0; | |
263 regenMaskBits |= regenerateColors ? kRegenCol : 0; | |
264 regenMaskBits |= regenerateTextureCoords ? kRegenTex : 0; | |
265 regenMaskBits |= regenerateGlyphs ? kRegenGlyph : 0; | |
266 RegenMask regenMask = (RegenMask)regenMaskBits; | |
267 | |
268 switch (regenMask) { | |
269 case kRegenPos: this->regenInBatch<true, false, false, false>(REGEN_ARGS ); break; | |
270 case kRegenCol: this->regenInBatch<false, true, false, false>(REGEN_ARGS ); break; | |
271 case kRegenTex: this->regenInBatch<false, false, true, false>(REGEN_ARGS ); break; | |
272 case kRegenGlyph: this->regenInBatch<false, false, true, true>(REGEN_ARG S); break; | |
273 | |
274 // combinations | |
275 case kRegenPosCol: this->regenInBatch<true, true, false, false>(REGEN_AR GS); break; | |
276 case kRegenPosTex: this->regenInBatch<true, false, true, false>(REGEN_AR GS); break; | |
277 case kRegenPosTexGlyph: this->regenInBatch<true, false, true, true>(REGE N_ARGS); break; | |
278 case kRegenPosColTex: this->regenInBatch<true, true, true, false>(REGEN_ ARGS); break; | |
279 case kRegenPosColTexGlyph: this->regenInBatch<true, true, true, true>(RE GEN_ARGS); break; | |
280 case kRegenColTex: this->regenInBatch<false, true, true, false>(REGEN_AR GS); break; | |
281 case kRegenColTexGlyph: this->regenInBatch<false, true, true, true>(REGE N_ARGS); break; | |
282 case kNoRegen: | |
283 helper->incGlyphCount(*glyphCount); | |
284 | |
285 // set use tokens for all of the glyphs in our subrun. This is only valid if we | |
286 // have a valid atlas generation | |
287 fontCache->setUseTokenBulk(*info.bulkUseToken(), target->currentToke n(), | |
288 info.maskFormat()); | |
289 break; | |
290 } | |
291 | |
292 *byteCount = info.byteCount(); | |
293 *vertices = fVertices + info.vertexStartIndex(); | |
294 } | |
OLD | NEW |