| 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 |