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 #include "GrAtlasTextBatch.h" | 8 #include "GrAtlasTextBatch.h" |
9 | 9 |
10 #include "GrBatchFontCache.h" | 10 #include "GrBatchFontCache.h" |
11 #include "GrBatchFlushState.h" | 11 #include "GrBatchFlushState.h" |
12 #include "GrBatchTest.h" | 12 #include "GrBatchTest.h" |
13 #include "GrResourceProvider.h" | 13 #include "GrResourceProvider.h" |
14 | 14 |
15 #include "SkDistanceFieldGen.h" | 15 #include "SkDistanceFieldGen.h" |
16 #include "SkGlyphCache.h" | 16 #include "SkGlyphCache.h" |
17 | 17 |
18 #include "effects/GrBitmapTextGeoProc.h" | 18 #include "effects/GrBitmapTextGeoProc.h" |
19 #include "effects/GrDistanceFieldGeoProc.h" | 19 #include "effects/GrDistanceFieldGeoProc.h" |
20 | 20 |
21 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
22 // A large template to handle regenerating the vertices of a textblob with as fe w branches as | |
23 // possible | |
24 template <bool regenPos, bool regenCol, bool regenTexCoords> | |
25 inline void regen_vertices(intptr_t vertex, const GrGlyph* glyph, size_t vertexS tride, | |
26 bool useDistanceFields, SkScalar transX, SkScalar tra nsY, | |
27 GrColor color) { | |
28 int width, height, u0, v0, u1, v1; | |
29 if (regenTexCoords) { | |
robertphillips
2015/11/23 18:42:52
mv width & height in here ?
| |
30 SkASSERT(glyph); | |
31 width = glyph->fBounds.width(); | |
32 height = glyph->fBounds.height(); | |
33 | |
34 if (useDistanceFields) { | |
35 u0 = glyph->fAtlasLocation.fX + SK_DistanceFieldInset; | |
36 v0 = glyph->fAtlasLocation.fY + SK_DistanceFieldInset; | |
37 u1 = u0 + width - 2 * SK_DistanceFieldInset; | |
38 v1 = v0 + height - 2 * SK_DistanceFieldInset; | |
39 } else { | |
40 u0 = glyph->fAtlasLocation.fX; | |
41 v0 = glyph->fAtlasLocation.fY; | |
42 u1 = u0 + width; | |
43 v1 = v0 + height; | |
44 } | |
45 } | |
46 | |
robertphillips
2015/11/23 18:42:52
won'd -> won't ?
| |
47 // This is a bit wonky, but sometimes we have LCD text, in which case we won 'd have color | |
48 // vertices, hence vertexStride - sizeof(SkIPoint16) | |
49 intptr_t colorOffset = sizeof(SkPoint); | |
50 intptr_t texCoordOffset = vertexStride - sizeof(SkIPoint16); | |
51 | |
52 // V0 | |
53 if (regenPos) { | |
54 SkPoint* point = reinterpret_cast<SkPoint*>(vertex); | |
55 point->fX += transX; | |
56 point->fY += transY; | |
57 } | |
58 | |
59 if (regenCol) { | |
60 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + colorOffset); | |
61 *vcolor = color; | |
62 } | |
63 | |
64 if (regenTexCoords) { | |
65 SkIPoint16* textureCoords = reinterpret_cast<SkIPoint16*>(vertex + texCo ordOffset); | |
66 textureCoords->set(u0, v0); | |
67 } | |
68 vertex += vertexStride; | |
69 | |
70 // V1 | |
71 if (regenPos) { | |
72 SkPoint* point = reinterpret_cast<SkPoint*>(vertex); | |
73 point->fX += transX; | |
74 point->fY += transY; | |
75 } | |
76 | |
77 if (regenCol) { | |
78 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + colorOffset); | |
79 *vcolor = color; | |
80 } | |
81 | |
82 if (regenTexCoords) { | |
83 SkIPoint16* textureCoords = reinterpret_cast<SkIPoint16*>(vertex + texCo ordOffset); | |
84 textureCoords->set(u0, v1); | |
85 } | |
86 vertex += vertexStride; | |
87 | |
88 // V2 | |
89 if (regenPos) { | |
90 SkPoint* point = reinterpret_cast<SkPoint*>(vertex); | |
91 point->fX += transX; | |
92 point->fY += transY; | |
93 } | |
94 | |
95 if (regenCol) { | |
96 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + colorOffset); | |
97 *vcolor = color; | |
98 } | |
99 | |
100 if (regenTexCoords) { | |
101 SkIPoint16* textureCoords = reinterpret_cast<SkIPoint16*>(vertex + texCo ordOffset); | |
102 textureCoords->set(u1, v1); | |
103 } | |
104 vertex += vertexStride; | |
105 | |
106 // V3 | |
107 if (regenPos) { | |
108 SkPoint* point = reinterpret_cast<SkPoint*>(vertex); | |
109 point->fX += transX; | |
110 point->fY += transY; | |
111 } | |
112 | |
113 if (regenCol) { | |
114 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + colorOffset); | |
115 *vcolor = color; | |
116 } | |
117 | |
118 if (regenTexCoords) { | |
119 SkIPoint16* textureCoords = reinterpret_cast<SkIPoint16*>(vertex + texCo ordOffset); | |
120 textureCoords->set(u1, v0); | |
121 } | |
122 } | |
123 | |
124 typedef GrAtlasTextBlob Blob; | |
125 typedef Blob::Run Run; | |
126 typedef Run::SubRunInfo TextInfo; | |
127 | |
128 template <bool regenPos, bool regenCol, bool regenTexCoords, bool regenGlyphs> | |
robertphillips
2015/11/23 18:42:52
That's a lot of parameters ...
| |
129 void GrAtlasTextBatch::regenBlob(Target* target, FlushInfo* flushInfo, Blob* blo b, Run* run, | |
130 TextInfo* info, SkGlyphCache** cache, | |
131 SkTypeface** typeface, GrFontScaler** scaler, | |
132 const SkDescriptor** desc, const GrGeometryProc essor* gp, | |
133 int glyphCount, size_t vertexStride, | |
134 GrColor color, SkScalar transX, SkScalar transY ) { | |
135 GrBatchTextStrike* strike = nullptr; | |
136 if (regenTexCoords) { | |
137 info->fBulkUseToken.reset(); | |
138 | |
139 // We can reuse if we have a valid strike and our descriptors / typeface are the | |
140 // same. The override descriptor is only for the non distance field tex t within | |
141 // a run | |
142 const SkDescriptor* newDesc = (run->fOverrideDescriptor && !this->usesDi stanceFields()) ? | |
143 run->fOverrideDescriptor->getDesc() : | |
144 run->fDescriptor.getDesc(); | |
145 if (!*cache || !SkTypeface::Equal(*typeface, run->fTypeface) || | |
146 !((*desc)->equals(*newDesc))) { | |
147 if (*cache) { | |
148 SkGlyphCache::AttachCache(*cache); | |
149 } | |
150 *desc = newDesc; | |
151 *cache = SkGlyphCache::DetachCache(run->fTypeface, *desc); | |
152 *scaler = GrTextContext::GetGrFontScaler(*cache); | |
153 strike = info->fStrike; | |
154 *typeface = run->fTypeface; | |
155 } | |
156 | |
157 if (regenGlyphs) { | |
158 strike = fFontCache->getStrike(*scaler); | |
159 } else { | |
160 strike = info->fStrike; | |
161 } | |
162 } | |
163 | |
164 bool brokenRun = false; | |
165 for (int glyphIdx = 0; glyphIdx < glyphCount; glyphIdx++) { | |
166 GrGlyph* glyph = nullptr; | |
167 if (regenTexCoords) { | |
168 size_t glyphOffset = glyphIdx + info->fGlyphStartIndex; | |
169 | |
170 glyph = blob->fGlyphs[glyphOffset]; | |
171 GrGlyph::PackedID id = glyph->fPackedID; | |
172 const SkGlyph& skGlyph = (*scaler)->grToSkGlyph(id); | |
173 if (regenGlyphs) { | |
174 // Get the id from the old glyph, and use the new strike to look up | |
175 // the glyph. | |
176 blob->fGlyphs[glyphOffset] = strike->getGlyph(skGlyph, id, this- >maskFormat(), | |
177 *scaler); | |
178 } | |
179 glyph = blob->fGlyphs[glyphOffset]; | |
180 SkASSERT(glyph); | |
181 SkASSERT(id == glyph->fPackedID); | |
182 // We want to be able to assert this but cannot for testing purposes . | |
183 // once skbug:4143 has landed we can revist this assert | |
184 //SkASSERT(glyph->fMaskFormat == this->maskFormat()); | |
185 | |
186 if (!fFontCache->hasGlyph(glyph) && | |
187 !strike->addGlyphToAtlas(target, glyph, *scaler, skGlyph, this-> maskFormat())) { | |
188 this->flush(target, flushInfo); | |
189 target->initDraw(gp, this->pipeline()); | |
190 brokenRun = glyphIdx > 0; | |
191 | |
192 SkDEBUGCODE(bool success =) strike->addGlyphToAtlas(target, | |
193 glyph, | |
194 *scaler, | |
195 skGlyph, | |
196 this->maskFo rmat()); | |
197 SkASSERT(success); | |
198 } | |
199 fFontCache->addGlyphToBulkAndSetUseToken(&info->fBulkUseToken, glyph , | |
200 target->currentToken()); | |
201 } | |
202 | |
203 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices); | |
204 vertex += info->fVertexStartIndex; | |
205 vertex += vertexStride * glyphIdx * GrAtlasTextBatch::kVerticesPerGlyph; | |
206 regen_vertices<regenPos, regenCol, regenTexCoords>(vertex, glyph, vertex Stride, | |
207 this->usesDistanceFie lds(), transX, | |
208 transY, color); | |
209 flushInfo->fGlyphsToFlush++; | |
210 } | |
211 | |
212 // We my have changed the color so update it here | |
213 run->fColor = color; | |
214 if (regenTexCoords) { | |
215 if (regenGlyphs) { | |
216 info->fStrike.reset(SkRef(strike)); | |
217 } | |
218 info->fAtlasGeneration = brokenRun ? GrBatchAtlas::kInvalidAtlasGenerati on : | |
219 fFontCache->atlasGeneration(this->m askFormat()); | |
220 } | |
221 } | |
222 //////////////////////////////////////////////////////////////////////////////// /////////////////// | |
223 | |
21 static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) { | 224 static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) { |
22 unsigned r = SkColorGetR(c); | 225 unsigned r = SkColorGetR(c); |
23 unsigned g = SkColorGetG(c); | 226 unsigned g = SkColorGetG(c); |
24 unsigned b = SkColorGetB(c); | 227 unsigned b = SkColorGetB(c); |
25 return GrColorPackRGBA(r, g, b, 0xff); | 228 return GrColorPackRGBA(r, g, b, 0xff); |
26 } | 229 } |
27 | 230 |
28 static const int kDistanceAdjustLumShift = 5; | 231 static const int kDistanceAdjustLumShift = 5; |
29 | 232 |
30 SkString GrAtlasTextBatch::dumpInfo() const { | 233 SkString GrAtlasTextBatch::dumpInfo() const { |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
74 } | 277 } |
75 opt.getOverrideColorIfSet(&fGeoData[0].fColor); | 278 opt.getOverrideColorIfSet(&fGeoData[0].fColor); |
76 | 279 |
77 // setup batch properties | 280 // setup batch properties |
78 fBatch.fColorIgnored = !opt.readsColor(); | 281 fBatch.fColorIgnored = !opt.readsColor(); |
79 fBatch.fColor = fGeoData[0].fColor; | 282 fBatch.fColor = fGeoData[0].fColor; |
80 fBatch.fUsesLocalCoords = opt.readsLocalCoords(); | 283 fBatch.fUsesLocalCoords = opt.readsLocalCoords(); |
81 fBatch.fCoverageIgnored = !opt.readsCoverage(); | 284 fBatch.fCoverageIgnored = !opt.readsCoverage(); |
82 } | 285 } |
83 | 286 |
287 enum RegenMask { | |
288 kNoRegen = 0x0, | |
289 kRegenPos = 0x1, | |
290 kRegenCol = 0x2, | |
291 kRegenTex = 0x4, | |
292 kRegenGlyph = 0x8 | kRegenTex, // we have to regenerate the texture coords w hen we regen glyphs | |
293 | |
294 // combinations | |
295 kRegenPosCol = kRegenPos | kRegenCol, | |
296 kRegenPosTex = kRegenPos | kRegenTex, | |
297 kRegenPosTexGlyph = kRegenPos | kRegenGlyph, | |
298 kRegenPosColTex = kRegenPos | kRegenCol | kRegenTex, | |
299 kRegenPosColTexGlyph = kRegenPos | kRegenCol | kRegenGlyph, | |
300 kRegenColTex = kRegenCol | kRegenTex, | |
301 kRegenColTexGlyph = kRegenCol | kRegenGlyph, | |
302 }; | |
303 | |
304 #define REGEN_ARGS target, &flushInfo, blob, &run, &info, &cache, &typeface, &sc aler, &desc, gp, \ | |
305 glyphCount, vertexStride, args.fColor, args.fTransX, args.fTr ansY | |
306 | |
84 void GrAtlasTextBatch::onPrepareDraws(Target* target) { | 307 void GrAtlasTextBatch::onPrepareDraws(Target* target) { |
85 // if we have RGB, then we won't have any SkShaders so no need to use a loca lmatrix. | 308 // if we have RGB, then we won't have any SkShaders so no need to use a loca lmatrix. |
86 // TODO actually only invert if we don't have RGBA | 309 // TODO actually only invert if we don't have RGBA |
87 SkMatrix localMatrix; | 310 SkMatrix localMatrix; |
88 if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix)) { | 311 if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix)) { |
89 SkDebugf("Cannot invert viewmatrix\n"); | 312 SkDebugf("Cannot invert viewmatrix\n"); |
90 return; | 313 return; |
91 } | 314 } |
92 | 315 |
93 GrTexture* texture = fFontCache->getTexture(this->maskFormat()); | 316 GrTexture* texture = fFontCache->getTexture(this->maskFormat()); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
146 GrFontScaler* scaler = nullptr; | 369 GrFontScaler* scaler = nullptr; |
147 SkTypeface* typeface = nullptr; | 370 SkTypeface* typeface = nullptr; |
148 | 371 |
149 for (int i = 0; i < fGeoCount; i++) { | 372 for (int i = 0; i < fGeoCount; i++) { |
150 Geometry& args = fGeoData[i]; | 373 Geometry& args = fGeoData[i]; |
151 Blob* blob = args.fBlob; | 374 Blob* blob = args.fBlob; |
152 Run& run = blob->fRuns[args.fRun]; | 375 Run& run = blob->fRuns[args.fRun]; |
153 TextInfo& info = run.fSubRunInfo[args.fSubRun]; | 376 TextInfo& info = run.fSubRunInfo[args.fSubRun]; |
154 | 377 |
155 uint64_t currentAtlasGen = fFontCache->atlasGeneration(maskFormat); | 378 uint64_t currentAtlasGen = fFontCache->atlasGeneration(maskFormat); |
379 | |
380 // Because the GrBatchFontCache may evict the strike a blob depends on u sing for | |
381 // generating its texture coords, we have to track whether or not the st rike has | |
382 // been abandoned. If it hasn't been abandoned, then we can use the GrG lyph*s as is | |
383 // otherwise we have to get the new strike, and use that to get the corr ect glyphs. | |
384 // Because we do not have the packed ids, and thus can't look up our gly phs in the | |
385 // new strike, we instead keep our ref to the old strike and use the pac ked ids from | |
386 // it. These ids will still be valid as long as we hold the ref. When we are done | |
387 // updating our cache of the GrGlyph*s, we drop our ref on the old strik e | |
388 bool regenerateGlyphs = info.fStrike->isAbandoned(); | |
156 bool regenerateTextureCoords = info.fAtlasGeneration != currentAtlasGen || | 389 bool regenerateTextureCoords = info.fAtlasGeneration != currentAtlasGen || |
157 info.fStrike->isAbandoned(); | 390 regenerateGlyphs; |
158 bool regenerateColors; | 391 bool regenerateColors; |
159 if (usesDistanceFields) { | 392 if (usesDistanceFields) { |
160 regenerateColors = !isLCD && run.fColor != args.fColor; | 393 regenerateColors = !isLCD && run.fColor != args.fColor; |
161 } else { | 394 } else { |
162 regenerateColors = kA8_GrMaskFormat == maskFormat && run.fColor != a rgs.fColor; | 395 regenerateColors = kA8_GrMaskFormat == maskFormat && run.fColor != a rgs.fColor; |
163 } | 396 } |
164 bool regeneratePositions = args.fTransX != 0.f || args.fTransY != 0.f; | 397 bool regeneratePositions = args.fTransX != 0.f || args.fTransY != 0.f; |
165 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; | 398 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; |
166 | 399 |
167 // We regenerate both texture coords and colors in the blob itself, and update the | 400 uint32_t regenMaskBits = kNoRegen; |
168 // atlas generation. If we don't end up purging any unused plots, we ca n avoid | 401 regenMaskBits |= regeneratePositions ? kRegenPos : 0; |
169 // regenerating the coords. We could take a finer grained approach to u pdating texture | 402 regenMaskBits |= regenerateColors ? kRegenCol : 0; |
170 // coords but its not clear if the extra bookkeeping would offset any ga ins. | 403 regenMaskBits |= regenerateTextureCoords ? kRegenTex : 0; |
171 // To avoid looping over the glyphs twice, we do one loop and conditiona lly update color | 404 regenMaskBits |= regenerateGlyphs ? kRegenGlyph : 0; |
172 // or coords as needed. One final note, if we have to break a run for a n atlas eviction | 405 RegenMask regenMask = (RegenMask)regenMaskBits; |
173 // then we can't really trust the atlas has all of the correct data. At las evictions | |
174 // should be pretty rare, so we just always regenerate in those cases | |
175 if (regenerateTextureCoords || regenerateColors || regeneratePositions) { | |
176 // first regenerate texture coordinates / colors if need be | |
177 bool brokenRun = false; | |
178 | 406 |
robertphillips
2015/11/23 18:42:52
So we go from Booleans to a mask so we can go thro
| |
179 // Because the GrBatchFontCache may evict the strike a blob depends on using for | 407 switch (regenMask) { |
180 // generating its texture coords, we have to track whether or not th e strike has | 408 case kRegenPos: this->regenBlob<true, false, false, false>(REGEN_ARG S); break; |
181 // been abandoned. If it hasn't been abandoned, then we can use the GrGlyph*s as is | 409 case kRegenCol: this->regenBlob<false, true, false, false>(REGEN_ARG S); break; |
182 // otherwise we have to get the new strike, and use that to get the correct glyphs. | 410 case kRegenTex: this->regenBlob<false, false, true, false>(REGEN_ARG S); break; |
183 // Because we do not have the packed ids, and thus can't look up our glyphs in the | 411 case kRegenGlyph: this->regenBlob<false, false, true, true>(REGEN_AR GS); break; |
184 // new strike, we instead keep our ref to the old strike and use the packed ids from | |
185 // it. These ids will still be valid as long as we hold the ref. W hen we are done | |
186 // updating our cache of the GrGlyph*s, we drop our ref on the old s trike | |
187 bool regenerateGlyphs = false; | |
188 GrBatchTextStrike* strike = nullptr; | |
189 if (regenerateTextureCoords) { | |
190 info.fBulkUseToken.reset(); | |
191 | 412 |
192 // We can reuse if we have a valid strike and our descriptors / typeface are the | 413 // combinations |
193 // same. The override descriptor is only for the non distance f ield text within | 414 case kRegenPosCol: this->regenBlob<true, true, false, false>(REGEN_A RGS); break; |
194 // a run | 415 case kRegenPosTex: this->regenBlob<true, false, true, false>(REGEN_A RGS); break; |
195 const SkDescriptor* newDesc = (run.fOverrideDescriptor && !usesD istanceFields) ? | 416 case kRegenPosTexGlyph: this->regenBlob<true, false, true, true>(REG EN_ARGS); break; |
196 run.fOverrideDescriptor->getDesc() : | 417 case kRegenPosColTex: this->regenBlob<true, true, true, false>(REGEN _ARGS); break; |
197 run.fDescriptor.getDesc(); | 418 case kRegenPosColTexGlyph: this->regenBlob<true, true, true, true>(R EGEN_ARGS); break; |
198 if (!cache || !SkTypeface::Equal(typeface, run.fTypeface) || | 419 case kRegenColTex: this->regenBlob<false, true, true, false>(REGEN_A RGS); break; |
199 !(desc->equals(*newDesc))) { | 420 case kRegenColTexGlyph: this->regenBlob<false, true, true, true>(REG EN_ARGS); break; |
200 if (cache) { | 421 case kNoRegen: |
201 SkGlyphCache::AttachCache(cache); | 422 flushInfo.fGlyphsToFlush += glyphCount; |
202 } | |
203 desc = newDesc; | |
204 cache = SkGlyphCache::DetachCache(run.fTypeface, desc); | |
205 scaler = GrTextContext::GetGrFontScaler(cache); | |
206 strike = info.fStrike; | |
207 typeface = run.fTypeface; | |
208 } | |
209 | 423 |
210 if (info.fStrike->isAbandoned()) { | 424 // set use tokens for all of the glyphs in our subrun. This is only valid if we |
211 regenerateGlyphs = true; | 425 // have a valid atlas generation |
212 strike = fFontCache->getStrike(scaler); | 426 fFontCache->setUseTokenBulk(info.fBulkUseToken, target->currentT oken(), maskFormat); |
213 } else { | 427 break; |
214 strike = info.fStrike; | |
215 } | |
216 } | |
217 | |
218 for (int glyphIdx = 0; glyphIdx < glyphCount; glyphIdx++) { | |
219 if (regenerateTextureCoords) { | |
220 size_t glyphOffset = glyphIdx + info.fGlyphStartIndex; | |
221 | |
222 GrGlyph* glyph = blob->fGlyphs[glyphOffset]; | |
223 GrGlyph::PackedID id = glyph->fPackedID; | |
224 const SkGlyph& skGlyph = scaler->grToSkGlyph(id); | |
225 if (regenerateGlyphs) { | |
226 // Get the id from the old glyph, and use the new strike to lookup | |
227 // the glyph. | |
228 blob->fGlyphs[glyphOffset] = strike->getGlyph(skGlyph, i d, maskFormat, | |
229 scaler); | |
230 } | |
231 glyph = blob->fGlyphs[glyphOffset]; | |
232 SkASSERT(glyph); | |
233 SkASSERT(id == glyph->fPackedID); | |
234 // We want to be able to assert this but cannot for testing purposes. | |
235 // once skbug:4143 has landed we can revist this assert | |
236 //SkASSERT(glyph->fMaskFormat == this->maskFormat()); | |
237 | |
238 if (!fFontCache->hasGlyph(glyph) && | |
239 !strike->addGlyphToAtlas(target, glyph, scaler, skGlyph, maskFormat)) { | |
240 this->flush(target, &flushInfo); | |
241 target->initDraw(gp, this->pipeline()); | |
242 brokenRun = glyphIdx > 0; | |
243 | |
244 SkDEBUGCODE(bool success =) strike->addGlyphToAtlas(targ et, | |
245 glyp h, | |
246 scal er, | |
247 skGl yph, | |
248 mask Format); | |
249 SkASSERT(success); | |
250 } | |
251 fFontCache->addGlyphToBulkAndSetUseToken(&info.fBulkUseToken , glyph, | |
252 target->currentToke n()); | |
253 | |
254 // Texture coords are the last vertex attribute so we get a pointer to the | |
255 // first one and then map with stride in regenerateTextureCo ords | |
256 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices ); | |
257 vertex += info.fVertexStartIndex; | |
258 vertex += vertexStride * glyphIdx * kVerticesPerGlyph; | |
259 vertex += vertexStride - sizeof(SkIPoint16); | |
260 | |
261 this->regenerateTextureCoords(glyph, vertex, vertexStride); | |
262 } | |
263 | |
264 if (regenerateColors) { | |
265 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices ); | |
266 vertex += info.fVertexStartIndex; | |
267 vertex += vertexStride * glyphIdx * kVerticesPerGlyph + size of(SkPoint); | |
268 this->regenerateColors(vertex, vertexStride, args.fColor); | |
269 } | |
270 | |
271 if (regeneratePositions) { | |
272 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices ); | |
273 vertex += info.fVertexStartIndex; | |
274 vertex += vertexStride * glyphIdx * kVerticesPerGlyph; | |
275 SkScalar transX = args.fTransX; | |
276 SkScalar transY = args.fTransY; | |
277 this->regeneratePositions(vertex, vertexStride, transX, tran sY); | |
278 } | |
279 flushInfo.fGlyphsToFlush++; | |
280 } | |
281 | |
282 // We my have changed the color so update it here | |
283 run.fColor = args.fColor; | |
284 if (regenerateTextureCoords) { | |
285 if (regenerateGlyphs) { | |
286 info.fStrike.reset(SkRef(strike)); | |
287 } | |
288 info.fAtlasGeneration = brokenRun ? GrBatchAtlas::kInvalidAtlasG eneration : | |
289 fFontCache->atlasGeneration( maskFormat); | |
290 } | |
291 } else { | |
292 flushInfo.fGlyphsToFlush += glyphCount; | |
293 | |
294 // set use tokens for all of the glyphs in our subrun. This is only valid if we | |
295 // have a valid atlas generation | |
296 fFontCache->setUseTokenBulk(info.fBulkUseToken, target->currentToken (), maskFormat); | |
297 } | 428 } |
298 | 429 |
299 // now copy all vertices | 430 // now copy all vertices |
300 size_t byteCount = info.fVertexEndIndex - info.fVertexStartIndex; | 431 size_t byteCount = info.fVertexEndIndex - info.fVertexStartIndex; |
301 memcpy(currVertex, blob->fVertices + info.fVertexStartIndex, byteCount); | 432 memcpy(currVertex, blob->fVertices + info.fVertexStartIndex, byteCount); |
302 | 433 |
303 currVertex += byteCount; | 434 currVertex += byteCount; |
304 } | 435 } |
436 | |
305 // Make sure to attach the last cache if applicable | 437 // Make sure to attach the last cache if applicable |
306 if (cache) { | 438 if (cache) { |
307 SkGlyphCache::AttachCache(cache); | 439 SkGlyphCache::AttachCache(cache); |
308 } | 440 } |
309 this->flush(target, &flushInfo); | 441 this->flush(target, &flushInfo); |
310 } | 442 } |
311 | 443 |
312 void GrAtlasTextBatch::regenerateTextureCoords(GrGlyph* glyph, intptr_t vertex, | |
313 size_t vertexStride) { | |
314 int width = glyph->fBounds.width(); | |
315 int height = glyph->fBounds.height(); | |
316 | |
317 int u0, v0, u1, v1; | |
318 if (this->usesDistanceFields()) { | |
319 u0 = glyph->fAtlasLocation.fX + SK_DistanceFieldInset; | |
320 v0 = glyph->fAtlasLocation.fY + SK_DistanceFieldInset; | |
321 u1 = u0 + width - 2 * SK_DistanceFieldInset; | |
322 v1 = v0 + height - 2 * SK_DistanceFieldInset; | |
323 } else { | |
324 u0 = glyph->fAtlasLocation.fX; | |
325 v0 = glyph->fAtlasLocation.fY; | |
326 u1 = u0 + width; | |
327 v1 = v0 + height; | |
328 } | |
329 | |
330 SkIPoint16* textureCoords; | |
331 // V0 | |
332 textureCoords = reinterpret_cast<SkIPoint16*>(vertex); | |
333 textureCoords->set(u0, v0); | |
334 vertex += vertexStride; | |
335 | |
336 // V1 | |
337 textureCoords = reinterpret_cast<SkIPoint16*>(vertex); | |
338 textureCoords->set(u0, v1); | |
339 vertex += vertexStride; | |
340 | |
341 // V2 | |
342 textureCoords = reinterpret_cast<SkIPoint16*>(vertex); | |
343 textureCoords->set(u1, v1); | |
344 vertex += vertexStride; | |
345 | |
346 // V3 | |
347 textureCoords = reinterpret_cast<SkIPoint16*>(vertex); | |
348 textureCoords->set(u1, v0); | |
349 } | |
350 | |
351 void GrAtlasTextBatch::regenerateColors(intptr_t vertex, size_t vertexStride, Gr Color color) { | |
352 for (int i = 0; i < kVerticesPerGlyph; i++) { | |
353 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex); | |
354 *vcolor = color; | |
355 vertex += vertexStride; | |
356 } | |
357 } | |
358 | |
359 void GrAtlasTextBatch::regeneratePositions(intptr_t vertex, size_t vertexStride, SkScalar transX, | |
360 SkScalar transY) { | |
361 for (int i = 0; i < kVerticesPerGlyph; i++) { | |
362 SkPoint* point = reinterpret_cast<SkPoint*>(vertex); | |
363 point->fX += transX; | |
364 point->fY += transY; | |
365 vertex += vertexStride; | |
366 } | |
367 } | |
368 | |
369 void GrAtlasTextBatch::flush(GrVertexBatch::Target* target, FlushInfo* flushInfo ) { | 444 void GrAtlasTextBatch::flush(GrVertexBatch::Target* target, FlushInfo* flushInfo ) { |
370 GrVertices vertices; | 445 GrVertices vertices; |
371 int maxGlyphsPerDraw = flushInfo->fIndexBuffer->maxQuads(); | 446 int maxGlyphsPerDraw = flushInfo->fIndexBuffer->maxQuads(); |
372 vertices.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuffer, | 447 vertices.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuffer, |
373 flushInfo->fIndexBuffer, flushInfo->fVertexOffset, | 448 flushInfo->fIndexBuffer, flushInfo->fVertexOffset, |
374 kVerticesPerGlyph, kIndicesPerGlyph, flushInfo->fGlyp hsToFlush, | 449 kVerticesPerGlyph, kIndicesPerGlyph, flushInfo->fGlyp hsToFlush, |
375 maxGlyphsPerDraw); | 450 maxGlyphsPerDraw); |
376 target->draw(vertices); | 451 target->draw(vertices); |
377 flushInfo->fVertexOffset += kVerticesPerGlyph * flushInfo->fGlyphsToFlush; | 452 flushInfo->fVertexOffset += kVerticesPerGlyph * flushInfo->fGlyphsToFlush; |
378 flushInfo->fGlyphsToFlush = 0; | 453 flushInfo->fGlyphsToFlush = 0; |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
498 return GrDistanceFieldA8TextGeoProc::Create(color, | 573 return GrDistanceFieldA8TextGeoProc::Create(color, |
499 viewMatrix, | 574 viewMatrix, |
500 texture, | 575 texture, |
501 params, | 576 params, |
502 flags, | 577 flags, |
503 this->usesLocalCoords()); | 578 this->usesLocalCoords()); |
504 #endif | 579 #endif |
505 } | 580 } |
506 | 581 |
507 } | 582 } |
OLD | NEW |