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 u0, v0, u1, v1; |
| 29 if (regenTexCoords) { |
| 30 SkASSERT(glyph); |
| 31 int width = glyph->fBounds.width(); |
| 32 int 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 |
| 47 // This is a bit wonky, but sometimes we have LCD text, in which case we won
't 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> |
| 129 inline void GrAtlasTextBatch::regenBlob(Target* target, FlushInfo* flushInfo, Bl
ob* blob, Run* run, |
| 130 TextInfo* info, SkGlyphCache** cache, |
| 131 SkTypeface** typeface, GrFontScaler** sc
aler, |
| 132 const SkDescriptor** desc, const GrGeome
tryProcessor* gp, |
| 133 int glyphCount, size_t vertexStride, |
| 134 GrColor color, SkScalar transX, SkScalar
transY) { |
| 135 static_assert(!regenGlyphs || regenTexCoords, "must regenTexCoords along reg
enGlyphs"); |
| 136 GrBatchTextStrike* strike = nullptr; |
| 137 if (regenTexCoords) { |
| 138 info->fBulkUseToken.reset(); |
| 139 |
| 140 // We can reuse if we have a valid strike and our descriptors / typeface
are the |
| 141 // same. The override descriptor is only for the non distance field tex
t within |
| 142 // a run |
| 143 const SkDescriptor* newDesc = (run->fOverrideDescriptor && !this->usesDi
stanceFields()) ? |
| 144 run->fOverrideDescriptor->getDesc() : |
| 145 run->fDescriptor.getDesc(); |
| 146 if (!*cache || !SkTypeface::Equal(*typeface, run->fTypeface) || |
| 147 !((*desc)->equals(*newDesc))) { |
| 148 if (*cache) { |
| 149 SkGlyphCache::AttachCache(*cache); |
| 150 } |
| 151 *desc = newDesc; |
| 152 *cache = SkGlyphCache::DetachCache(run->fTypeface, *desc); |
| 153 *scaler = GrTextContext::GetGrFontScaler(*cache); |
| 154 strike = info->fStrike; |
| 155 *typeface = run->fTypeface; |
| 156 } |
| 157 |
| 158 if (regenGlyphs) { |
| 159 strike = fFontCache->getStrike(*scaler); |
| 160 } else { |
| 161 strike = info->fStrike; |
| 162 } |
| 163 } |
| 164 |
| 165 bool brokenRun = false; |
| 166 for (int glyphIdx = 0; glyphIdx < glyphCount; glyphIdx++) { |
| 167 GrGlyph* glyph = nullptr; |
| 168 if (regenTexCoords) { |
| 169 size_t glyphOffset = glyphIdx + info->fGlyphStartIndex; |
| 170 |
| 171 glyph = blob->fGlyphs[glyphOffset]; |
| 172 GrGlyph::PackedID id = glyph->fPackedID; |
| 173 const SkGlyph& skGlyph = (*scaler)->grToSkGlyph(id); |
| 174 if (regenGlyphs) { |
| 175 // Get the id from the old glyph, and use the new strike to look
up |
| 176 // the glyph. |
| 177 blob->fGlyphs[glyphOffset] = strike->getGlyph(skGlyph, id, this-
>maskFormat(), |
| 178 *scaler); |
| 179 } |
| 180 glyph = blob->fGlyphs[glyphOffset]; |
| 181 SkASSERT(glyph); |
| 182 SkASSERT(id == glyph->fPackedID); |
| 183 // We want to be able to assert this but cannot for testing purposes
. |
| 184 // once skbug:4143 has landed we can revist this assert |
| 185 //SkASSERT(glyph->fMaskFormat == this->maskFormat()); |
| 186 |
| 187 if (!fFontCache->hasGlyph(glyph) && |
| 188 !strike->addGlyphToAtlas(target, glyph, *scaler, skGlyph, this->
maskFormat())) { |
| 189 this->flush(target, flushInfo); |
| 190 target->initDraw(gp, this->pipeline()); |
| 191 brokenRun = glyphIdx > 0; |
| 192 |
| 193 SkDEBUGCODE(bool success =) strike->addGlyphToAtlas(target, |
| 194 glyph, |
| 195 *scaler, |
| 196 skGlyph, |
| 197 this->maskFo
rmat()); |
| 198 SkASSERT(success); |
| 199 } |
| 200 fFontCache->addGlyphToBulkAndSetUseToken(&info->fBulkUseToken, glyph
, |
| 201 target->currentToken()); |
| 202 } |
| 203 |
| 204 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices); |
| 205 vertex += info->fVertexStartIndex; |
| 206 vertex += vertexStride * glyphIdx * GrAtlasTextBatch::kVerticesPerGlyph; |
| 207 regen_vertices<regenPos, regenCol, regenTexCoords>(vertex, glyph, vertex
Stride, |
| 208 this->usesDistanceFie
lds(), transX, |
| 209 transY, color); |
| 210 flushInfo->fGlyphsToFlush++; |
| 211 } |
| 212 |
| 213 // We my have changed the color so update it here |
| 214 run->fColor = color; |
| 215 if (regenTexCoords) { |
| 216 if (regenGlyphs) { |
| 217 info->fStrike.reset(SkRef(strike)); |
| 218 } |
| 219 info->fAtlasGeneration = brokenRun ? GrBatchAtlas::kInvalidAtlasGenerati
on : |
| 220 fFontCache->atlasGeneration(this->m
askFormat()); |
| 221 } |
| 222 } |
| 223 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
| 224 |
21 static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) { | 225 static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) { |
22 unsigned r = SkColorGetR(c); | 226 unsigned r = SkColorGetR(c); |
23 unsigned g = SkColorGetG(c); | 227 unsigned g = SkColorGetG(c); |
24 unsigned b = SkColorGetB(c); | 228 unsigned b = SkColorGetB(c); |
25 return GrColorPackRGBA(r, g, b, 0xff); | 229 return GrColorPackRGBA(r, g, b, 0xff); |
26 } | 230 } |
27 | 231 |
28 static const int kDistanceAdjustLumShift = 5; | 232 static const int kDistanceAdjustLumShift = 5; |
29 | 233 |
30 SkString GrAtlasTextBatch::dumpInfo() const { | 234 SkString GrAtlasTextBatch::dumpInfo() const { |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
74 } | 278 } |
75 opt.getOverrideColorIfSet(&fGeoData[0].fColor); | 279 opt.getOverrideColorIfSet(&fGeoData[0].fColor); |
76 | 280 |
77 // setup batch properties | 281 // setup batch properties |
78 fBatch.fColorIgnored = !opt.readsColor(); | 282 fBatch.fColorIgnored = !opt.readsColor(); |
79 fBatch.fColor = fGeoData[0].fColor; | 283 fBatch.fColor = fGeoData[0].fColor; |
80 fBatch.fUsesLocalCoords = opt.readsLocalCoords(); | 284 fBatch.fUsesLocalCoords = opt.readsLocalCoords(); |
81 fBatch.fCoverageIgnored = !opt.readsCoverage(); | 285 fBatch.fCoverageIgnored = !opt.readsCoverage(); |
82 } | 286 } |
83 | 287 |
| 288 enum RegenMask { |
| 289 kNoRegen = 0x0, |
| 290 kRegenPos = 0x1, |
| 291 kRegenCol = 0x2, |
| 292 kRegenTex = 0x4, |
| 293 kRegenGlyph = 0x8 | kRegenTex, // we have to regenerate the texture coords w
hen we regen glyphs |
| 294 |
| 295 // combinations |
| 296 kRegenPosCol = kRegenPos | kRegenCol, |
| 297 kRegenPosTex = kRegenPos | kRegenTex, |
| 298 kRegenPosTexGlyph = kRegenPos | kRegenGlyph, |
| 299 kRegenPosColTex = kRegenPos | kRegenCol | kRegenTex, |
| 300 kRegenPosColTexGlyph = kRegenPos | kRegenCol | kRegenGlyph, |
| 301 kRegenColTex = kRegenCol | kRegenTex, |
| 302 kRegenColTexGlyph = kRegenCol | kRegenGlyph, |
| 303 }; |
| 304 |
| 305 #define REGEN_ARGS target, &flushInfo, blob, &run, &info, &cache, &typeface, &sc
aler, &desc, gp, \ |
| 306 glyphCount, vertexStride, args.fColor, args.fTransX, args.fTr
ansY |
| 307 |
84 void GrAtlasTextBatch::onPrepareDraws(Target* target) { | 308 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. | 309 // 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 | 310 // TODO actually only invert if we don't have RGBA |
87 SkMatrix localMatrix; | 311 SkMatrix localMatrix; |
88 if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix)) { | 312 if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix)) { |
89 SkDebugf("Cannot invert viewmatrix\n"); | 313 SkDebugf("Cannot invert viewmatrix\n"); |
90 return; | 314 return; |
91 } | 315 } |
92 | 316 |
93 GrTexture* texture = fFontCache->getTexture(this->maskFormat()); | 317 GrTexture* texture = fFontCache->getTexture(this->maskFormat()); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
146 GrFontScaler* scaler = nullptr; | 370 GrFontScaler* scaler = nullptr; |
147 SkTypeface* typeface = nullptr; | 371 SkTypeface* typeface = nullptr; |
148 | 372 |
149 for (int i = 0; i < fGeoCount; i++) { | 373 for (int i = 0; i < fGeoCount; i++) { |
150 Geometry& args = fGeoData[i]; | 374 Geometry& args = fGeoData[i]; |
151 Blob* blob = args.fBlob; | 375 Blob* blob = args.fBlob; |
152 Run& run = blob->fRuns[args.fRun]; | 376 Run& run = blob->fRuns[args.fRun]; |
153 TextInfo& info = run.fSubRunInfo[args.fSubRun]; | 377 TextInfo& info = run.fSubRunInfo[args.fSubRun]; |
154 | 378 |
155 uint64_t currentAtlasGen = fFontCache->atlasGeneration(maskFormat); | 379 uint64_t currentAtlasGen = fFontCache->atlasGeneration(maskFormat); |
| 380 |
| 381 // Because the GrBatchFontCache may evict the strike a blob depends on u
sing for |
| 382 // generating its texture coords, we have to track whether or not the st
rike has |
| 383 // been abandoned. If it hasn't been abandoned, then we can use the GrG
lyph*s as is |
| 384 // otherwise we have to get the new strike, and use that to get the corr
ect glyphs. |
| 385 // Because we do not have the packed ids, and thus can't look up our gly
phs in the |
| 386 // new strike, we instead keep our ref to the old strike and use the pac
ked ids from |
| 387 // it. These ids will still be valid as long as we hold the ref. When
we are done |
| 388 // updating our cache of the GrGlyph*s, we drop our ref on the old strik
e |
| 389 bool regenerateGlyphs = info.fStrike->isAbandoned(); |
156 bool regenerateTextureCoords = info.fAtlasGeneration != currentAtlasGen
|| | 390 bool regenerateTextureCoords = info.fAtlasGeneration != currentAtlasGen
|| |
157 info.fStrike->isAbandoned(); | 391 regenerateGlyphs; |
158 bool regenerateColors; | 392 bool regenerateColors; |
159 if (usesDistanceFields) { | 393 if (usesDistanceFields) { |
160 regenerateColors = !isLCD && run.fColor != args.fColor; | 394 regenerateColors = !isLCD && run.fColor != args.fColor; |
161 } else { | 395 } else { |
162 regenerateColors = kA8_GrMaskFormat == maskFormat && run.fColor != a
rgs.fColor; | 396 regenerateColors = kA8_GrMaskFormat == maskFormat && run.fColor != a
rgs.fColor; |
163 } | 397 } |
164 bool regeneratePositions = args.fTransX != 0.f || args.fTransY != 0.f; | 398 bool regeneratePositions = args.fTransX != 0.f || args.fTransY != 0.f; |
165 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; | 399 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; |
166 | 400 |
167 // We regenerate both texture coords and colors in the blob itself, and
update the | 401 uint32_t regenMaskBits = kNoRegen; |
168 // atlas generation. If we don't end up purging any unused plots, we ca
n avoid | 402 regenMaskBits |= regeneratePositions ? kRegenPos : 0; |
169 // regenerating the coords. We could take a finer grained approach to u
pdating texture | 403 regenMaskBits |= regenerateColors ? kRegenCol : 0; |
170 // coords but its not clear if the extra bookkeeping would offset any ga
ins. | 404 regenMaskBits |= regenerateTextureCoords ? kRegenTex : 0; |
171 // To avoid looping over the glyphs twice, we do one loop and conditiona
lly update color | 405 regenMaskBits |= regenerateGlyphs ? kRegenGlyph : 0; |
172 // or coords as needed. One final note, if we have to break a run for a
n atlas eviction | 406 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 | 407 |
179 // Because the GrBatchFontCache may evict the strike a blob depends
on using for | 408 switch (regenMask) { |
180 // generating its texture coords, we have to track whether or not th
e strike has | 409 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 | 410 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. | 411 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 | 412 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 | 413 |
192 // We can reuse if we have a valid strike and our descriptors /
typeface are the | 414 // combinations |
193 // same. The override descriptor is only for the non distance f
ield text within | 415 case kRegenPosCol: this->regenBlob<true, true, false, false>(REGEN_A
RGS); break; |
194 // a run | 416 case kRegenPosTex: this->regenBlob<true, false, true, false>(REGEN_A
RGS); break; |
195 const SkDescriptor* newDesc = (run.fOverrideDescriptor && !usesD
istanceFields) ? | 417 case kRegenPosTexGlyph: this->regenBlob<true, false, true, true>(REG
EN_ARGS); break; |
196 run.fOverrideDescriptor->getDesc()
: | 418 case kRegenPosColTex: this->regenBlob<true, true, true, false>(REGEN
_ARGS); break; |
197 run.fDescriptor.getDesc(); | 419 case kRegenPosColTexGlyph: this->regenBlob<true, true, true, true>(R
EGEN_ARGS); break; |
198 if (!cache || !SkTypeface::Equal(typeface, run.fTypeface) || | 420 case kRegenColTex: this->regenBlob<false, true, true, false>(REGEN_A
RGS); break; |
199 !(desc->equals(*newDesc))) { | 421 case kRegenColTexGlyph: this->regenBlob<false, true, true, true>(REG
EN_ARGS); break; |
200 if (cache) { | 422 case kNoRegen: |
201 SkGlyphCache::AttachCache(cache); | 423 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 | 424 |
210 if (info.fStrike->isAbandoned()) { | 425 // set use tokens for all of the glyphs in our subrun. This is
only valid if we |
211 regenerateGlyphs = true; | 426 // have a valid atlas generation |
212 strike = fFontCache->getStrike(scaler); | 427 fFontCache->setUseTokenBulk(info.fBulkUseToken, target->currentT
oken(), maskFormat); |
213 } else { | 428 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 } | 429 } |
298 | 430 |
299 // now copy all vertices | 431 // now copy all vertices |
300 size_t byteCount = info.fVertexEndIndex - info.fVertexStartIndex; | 432 size_t byteCount = info.fVertexEndIndex - info.fVertexStartIndex; |
301 memcpy(currVertex, blob->fVertices + info.fVertexStartIndex, byteCount); | 433 memcpy(currVertex, blob->fVertices + info.fVertexStartIndex, byteCount); |
302 | 434 |
303 currVertex += byteCount; | 435 currVertex += byteCount; |
304 } | 436 } |
| 437 |
305 // Make sure to attach the last cache if applicable | 438 // Make sure to attach the last cache if applicable |
306 if (cache) { | 439 if (cache) { |
307 SkGlyphCache::AttachCache(cache); | 440 SkGlyphCache::AttachCache(cache); |
308 } | 441 } |
309 this->flush(target, &flushInfo); | 442 this->flush(target, &flushInfo); |
310 } | 443 } |
311 | 444 |
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
) { | 445 void GrAtlasTextBatch::flush(GrVertexBatch::Target* target, FlushInfo* flushInfo
) { |
370 GrVertices vertices; | 446 GrVertices vertices; |
371 int maxGlyphsPerDraw = flushInfo->fIndexBuffer->maxQuads(); | 447 int maxGlyphsPerDraw = flushInfo->fIndexBuffer->maxQuads(); |
372 vertices.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuffer, | 448 vertices.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuffer, |
373 flushInfo->fIndexBuffer, flushInfo->fVertexOffset, | 449 flushInfo->fIndexBuffer, flushInfo->fVertexOffset, |
374 kVerticesPerGlyph, kIndicesPerGlyph, flushInfo->fGlyp
hsToFlush, | 450 kVerticesPerGlyph, kIndicesPerGlyph, flushInfo->fGlyp
hsToFlush, |
375 maxGlyphsPerDraw); | 451 maxGlyphsPerDraw); |
376 target->draw(vertices); | 452 target->draw(vertices); |
377 flushInfo->fVertexOffset += kVerticesPerGlyph * flushInfo->fGlyphsToFlush; | 453 flushInfo->fVertexOffset += kVerticesPerGlyph * flushInfo->fGlyphsToFlush; |
378 flushInfo->fGlyphsToFlush = 0; | 454 flushInfo->fGlyphsToFlush = 0; |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
498 return GrDistanceFieldA8TextGeoProc::Create(color, | 574 return GrDistanceFieldA8TextGeoProc::Create(color, |
499 viewMatrix, | 575 viewMatrix, |
500 texture, | 576 texture, |
501 params, | 577 params, |
502 flags, | 578 flags, |
503 this->usesLocalCoords()); | 579 this->usesLocalCoords()); |
504 #endif | 580 #endif |
505 } | 581 } |
506 | 582 |
507 } | 583 } |
OLD | NEW |