Chromium Code Reviews| 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 |