blob: e2d4fe13ad8356de6c11bb71a7cccf305c452960 [file] [log] [blame]
Brian Salomon18923f92017-11-06 16:26:02 -05001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Robert Phillipsc4039ea2018-03-01 11:36:45 -05008#include "GrAtlasManager.h"
Brian Salomon18923f92017-11-06 16:26:02 -05009#include "GrAtlasTextBlob.h"
10#include "GrTextUtils.h"
11#include "SkDistanceFieldGen.h"
12#include "SkGlyphCache.h"
13#include "ops/GrAtlasTextOp.h"
14
15using Regenerator = GrAtlasTextBlob::VertexRegenerator;
16
17enum RegenMask {
18 kNoRegen = 0x0,
19 kRegenPos = 0x1,
20 kRegenCol = 0x2,
21 kRegenTex = 0x4,
22 kRegenGlyph = 0x8 | kRegenTex, // we have to regenerate the texture coords when we regen glyphs
23
24 // combinations
25 kRegenPosCol = kRegenPos | kRegenCol,
26 kRegenPosTex = kRegenPos | kRegenTex,
27 kRegenPosTexGlyph = kRegenPos | kRegenGlyph,
28 kRegenPosColTex = kRegenPos | kRegenCol | kRegenTex,
29 kRegenPosColTexGlyph = kRegenPos | kRegenCol | kRegenGlyph,
30 kRegenColTex = kRegenCol | kRegenTex,
31 kRegenColTexGlyph = kRegenCol | kRegenGlyph,
32};
33
34////////////////////////////////////////////////////////////////////////////////////////////////////
35// A large template to handle regenerating the vertices of a textblob with as few branches as
36// possible
37template <bool regenPos, bool regenCol, bool regenTexCoords>
38inline void regen_vertices(char* vertex, const GrGlyph* glyph, size_t vertexStride,
39 bool useDistanceFields, SkScalar transX, SkScalar transY,
40 GrColor color) {
41 uint16_t u0, v0, u1, v1;
Jim Van Verthfc4f7682018-01-25 16:26:25 -050042#ifdef DISPLAY_PAGE_INDEX
43 // Enable this to visualize the page from which each glyph is being drawn.
44 // Green Red Magenta Cyan -> 0 1 2 3; Black -> error
45 SkColor hackColor;
46#endif
Brian Salomon18923f92017-11-06 16:26:02 -050047 if (regenTexCoords) {
48 SkASSERT(glyph);
49 int width = glyph->fBounds.width();
50 int height = glyph->fBounds.height();
51
52 if (useDistanceFields) {
53 u0 = glyph->fAtlasLocation.fX + SK_DistanceFieldInset;
54 v0 = glyph->fAtlasLocation.fY + SK_DistanceFieldInset;
55 u1 = u0 + width - 2 * SK_DistanceFieldInset;
56 v1 = v0 + height - 2 * SK_DistanceFieldInset;
57 } else {
58 u0 = glyph->fAtlasLocation.fX;
59 v0 = glyph->fAtlasLocation.fY;
60 u1 = u0 + width;
61 v1 = v0 + height;
62 }
63 // We pack the 2bit page index in the low bit of the u and v texture coords
64 uint32_t pageIndex = glyph->pageIndex();
65 SkASSERT(pageIndex < 4);
66 uint16_t uBit = (pageIndex >> 1) & 0x1;
67 uint16_t vBit = pageIndex & 0x1;
68 u0 <<= 1;
69 u0 |= uBit;
70 v0 <<= 1;
71 v0 |= vBit;
72 u1 <<= 1;
73 u1 |= uBit;
74 v1 <<= 1;
75 v1 |= vBit;
Jim Van Verthfc4f7682018-01-25 16:26:25 -050076#ifdef DISPLAY_PAGE_INDEX
77 switch (pageIndex) {
78 case 0:
79 hackColor = SK_ColorGREEN;
80 break;
81 case 1:
82 hackColor = SK_ColorRED;
83 break;
84 case 2:
85 hackColor = SK_ColorMAGENTA;
86 break;
87 case 3:
88 hackColor = SK_ColorCYAN;
89 break;
90 default:
91 hackColor = SK_ColorBLACK;
92 break;
93 }
94#endif
Brian Salomon18923f92017-11-06 16:26:02 -050095 }
96
97 // This is a bit wonky, but sometimes we have LCD text, in which case we won't have color
98 // vertices, hence vertexStride - sizeof(SkIPoint16)
Brian Salomon18923f92017-11-06 16:26:02 -050099 intptr_t texCoordOffset = vertexStride - sizeof(SkIPoint16);
Brian Salomon5c6ac642017-12-19 11:09:32 -0500100 intptr_t colorOffset = texCoordOffset - sizeof(GrColor);
Brian Salomon18923f92017-11-06 16:26:02 -0500101
102 // V0
103 if (regenPos) {
104 SkPoint* point = reinterpret_cast<SkPoint*>(vertex);
105 point->fX += transX;
106 point->fY += transY;
107 }
108
109 if (regenCol) {
110 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + colorOffset);
111 *vcolor = color;
112 }
113
114 if (regenTexCoords) {
115 uint16_t* textureCoords = reinterpret_cast<uint16_t*>(vertex + texCoordOffset);
116 textureCoords[0] = u0;
117 textureCoords[1] = v0;
Jim Van Verthfc4f7682018-01-25 16:26:25 -0500118#ifdef DISPLAY_PAGE_INDEX
119 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + colorOffset);
120 *vcolor = hackColor;
121#endif
Brian Salomon18923f92017-11-06 16:26:02 -0500122 }
123 vertex += vertexStride;
124
125 // V1
126 if (regenPos) {
127 SkPoint* point = reinterpret_cast<SkPoint*>(vertex);
128 point->fX += transX;
129 point->fY += transY;
130 }
131
132 if (regenCol) {
133 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + colorOffset);
134 *vcolor = color;
135 }
136
137 if (regenTexCoords) {
138 uint16_t* textureCoords = reinterpret_cast<uint16_t*>(vertex + texCoordOffset);
139 textureCoords[0] = u0;
140 textureCoords[1] = v1;
Jim Van Verthfc4f7682018-01-25 16:26:25 -0500141#ifdef DISPLAY_PAGE_INDEX
142 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + colorOffset);
143 *vcolor = hackColor;
144#endif
Brian Salomon18923f92017-11-06 16:26:02 -0500145 }
146 vertex += vertexStride;
147
148 // V2
149 if (regenPos) {
150 SkPoint* point = reinterpret_cast<SkPoint*>(vertex);
151 point->fX += transX;
152 point->fY += transY;
153 }
154
155 if (regenCol) {
156 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + colorOffset);
157 *vcolor = color;
158 }
159
160 if (regenTexCoords) {
161 uint16_t* textureCoords = reinterpret_cast<uint16_t*>(vertex + texCoordOffset);
162 textureCoords[0] = u1;
163 textureCoords[1] = v0;
Jim Van Verthfc4f7682018-01-25 16:26:25 -0500164#ifdef DISPLAY_PAGE_INDEX
165 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + colorOffset);
166 *vcolor = hackColor;
167#endif
Brian Salomon18923f92017-11-06 16:26:02 -0500168 }
169 vertex += vertexStride;
170
171 // V3
172 if (regenPos) {
173 SkPoint* point = reinterpret_cast<SkPoint*>(vertex);
174 point->fX += transX;
175 point->fY += transY;
176 }
177
178 if (regenCol) {
179 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + colorOffset);
180 *vcolor = color;
181 }
182
183 if (regenTexCoords) {
184 uint16_t* textureCoords = reinterpret_cast<uint16_t*>(vertex + texCoordOffset);
185 textureCoords[0] = u1;
186 textureCoords[1] = v1;
Jim Van Verthfc4f7682018-01-25 16:26:25 -0500187#ifdef DISPLAY_PAGE_INDEX
188 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + colorOffset);
189 *vcolor = hackColor;
190#endif
Brian Salomon18923f92017-11-06 16:26:02 -0500191 }
192}
193
Robert Phillips4bc70112018-03-01 10:24:02 -0500194Regenerator::VertexRegenerator(GrResourceProvider* resourceProvider, GrAtlasTextBlob* blob,
195 int runIdx, int subRunIdx,
Brian Salomon18923f92017-11-06 16:26:02 -0500196 const SkMatrix& viewMatrix, SkScalar x, SkScalar y, GrColor color,
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500197 GrDeferredUploadTarget* uploadTarget, GrGlyphCache* glyphCache,
Herb Derby7956b592018-03-22 16:10:30 -0400198 GrAtlasManager* fullAtlasManager, SkExclusiveStrikePtr* lazyCache)
Robert Phillips4bc70112018-03-01 10:24:02 -0500199 : fResourceProvider(resourceProvider)
200 , fViewMatrix(viewMatrix)
Brian Salomon18923f92017-11-06 16:26:02 -0500201 , fBlob(blob)
202 , fUploadTarget(uploadTarget)
203 , fGlyphCache(glyphCache)
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500204 , fFullAtlasManager(fullAtlasManager)
Brian Salomon18923f92017-11-06 16:26:02 -0500205 , fLazyCache(lazyCache)
206 , fRun(&blob->fRuns[runIdx])
207 , fSubRun(&blob->fRuns[runIdx].fSubRunInfo[subRunIdx])
Brian Salomon18923f92017-11-06 16:26:02 -0500208 , fColor(color) {
209 // Compute translation if any
210 fSubRun->computeTranslation(fViewMatrix, x, y, &fTransX, &fTransY);
211
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500212 // Because the GrGlyphCache may evict the strike a blob depends on using for
Brian Salomon18923f92017-11-06 16:26:02 -0500213 // generating its texture coords, we have to track whether or not the strike has
214 // been abandoned. If it hasn't been abandoned, then we can use the GrGlyph*s as is
215 // otherwise we have to get the new strike, and use that to get the correct glyphs.
216 // Because we do not have the packed ids, and thus can't look up our glyphs in the
217 // new strike, we instead keep our ref to the old strike and use the packed ids from
218 // it. These ids will still be valid as long as we hold the ref. When we are done
219 // updating our cache of the GrGlyph*s, we drop our ref on the old strike
220 if (fSubRun->strike()->isAbandoned()) {
221 fRegenFlags |= kRegenGlyph;
222 fRegenFlags |= kRegenTex;
223 }
224 if (kARGB_GrMaskFormat != fSubRun->maskFormat() && fSubRun->color() != color) {
225 fRegenFlags |= kRegenCol;
226 }
227 if (0.f != fTransX || 0.f != fTransY) {
228 fRegenFlags |= kRegenPos;
229 }
230}
231
232template <bool regenPos, bool regenCol, bool regenTexCoords, bool regenGlyphs>
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500233bool Regenerator::doRegen(Regenerator::Result* result) {
Brian Salomon18923f92017-11-06 16:26:02 -0500234 static_assert(!regenGlyphs || regenTexCoords, "must regenTexCoords along regenGlyphs");
Robert Phillipscaf1ebb2018-03-01 14:28:44 -0500235 sk_sp<GrTextStrike> strike;
Brian Salomon18923f92017-11-06 16:26:02 -0500236 if (regenTexCoords) {
237 fSubRun->resetBulkUseToken();
238
239 const SkDescriptor* desc = (fRun->fOverrideDescriptor && !fSubRun->drawAsDistanceFields())
240 ? fRun->fOverrideDescriptor->getDesc()
241 : fRun->fDescriptor.getDesc();
242
243 if (!*fLazyCache || (*fLazyCache)->getDescriptor() != *desc) {
244 SkScalerContextEffects effects;
245 effects.fPathEffect = fRun->fPathEffect.get();
Brian Salomon18923f92017-11-06 16:26:02 -0500246 effects.fMaskFilter = fRun->fMaskFilter.get();
Herb Derby8c4cbf42018-03-09 15:28:04 -0500247 *fLazyCache =
Herb Derbyfa996902018-04-18 11:36:12 -0400248 SkStrikeCache::FindOrCreateStrikeExclusive(*desc, effects, *fRun->fTypeface);
Brian Salomon18923f92017-11-06 16:26:02 -0500249 }
250
251 if (regenGlyphs) {
252 strike = fGlyphCache->getStrike(fLazyCache->get());
253 } else {
Robert Phillipscaf1ebb2018-03-01 14:28:44 -0500254 strike = fSubRun->refStrike();
Brian Salomon18923f92017-11-06 16:26:02 -0500255 }
256 }
257
Brian Salomon5c6ac642017-12-19 11:09:32 -0500258 bool hasW = fSubRun->hasWCoord();
Brian Salomon5c6ac642017-12-19 11:09:32 -0500259 auto vertexStride = GetVertexStride(fSubRun->maskFormat(), hasW);
Brian Salomon18923f92017-11-06 16:26:02 -0500260 char* currVertex = fBlob->fVertices + fSubRun->vertexStartIndex() +
Brian Salomondeb53cc2017-11-08 13:50:53 -0500261 fCurrGlyph * kVerticesPerGlyph * vertexStride;
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500262 result->fFirstVertex = currVertex;
Brian Salomon18923f92017-11-06 16:26:02 -0500263
264 for (int glyphIdx = fCurrGlyph; glyphIdx < (int)fSubRun->glyphCount(); glyphIdx++) {
265 GrGlyph* glyph = nullptr;
266 if (regenTexCoords) {
267 size_t glyphOffset = glyphIdx + fSubRun->glyphStartIndex();
268
269 if (regenGlyphs) {
270 // Get the id from the old glyph, and use the new strike to lookup
271 // the glyph.
272 GrGlyph::PackedID id = fBlob->fGlyphs[glyphOffset]->fPackedID;
273 fBlob->fGlyphs[glyphOffset] =
274 strike->getGlyph(id, fSubRun->maskFormat(), fLazyCache->get());
275 SkASSERT(id == fBlob->fGlyphs[glyphOffset]->fPackedID);
276 }
277 glyph = fBlob->fGlyphs[glyphOffset];
278 SkASSERT(glyph && glyph->fMaskFormat == fSubRun->maskFormat());
279
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500280 if (!fFullAtlasManager->hasGlyph(glyph)) {
281 GrDrawOpAtlas::ErrorCode code;
282 code = strike->addGlyphToAtlas(fResourceProvider, fUploadTarget, fGlyphCache,
283 fFullAtlasManager, glyph,
284 fLazyCache->get(), fSubRun->maskFormat(),
285 fSubRun->hasScaledGlyphs());
286 if (GrDrawOpAtlas::ErrorCode::kError == code) {
287 // Something horrible has happened - drop the op
288 return false;
289 }
290 else if (GrDrawOpAtlas::ErrorCode::kTryAgain == code) {
291 fBrokenRun = glyphIdx > 0;
292 result->fFinished = false;
293 return true;
294 }
Brian Salomon18923f92017-11-06 16:26:02 -0500295 }
Robert Phillips40a29d72018-01-18 12:59:22 -0500296 auto tokenTracker = fUploadTarget->tokenTracker();
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500297 fFullAtlasManager->addGlyphToBulkAndSetUseToken(fSubRun->bulkUseToken(), glyph,
298 tokenTracker->nextDrawToken());
Brian Salomon18923f92017-11-06 16:26:02 -0500299 }
300
Brian Salomondeb53cc2017-11-08 13:50:53 -0500301 regen_vertices<regenPos, regenCol, regenTexCoords>(currVertex, glyph, vertexStride,
Brian Salomon18923f92017-11-06 16:26:02 -0500302 fSubRun->drawAsDistanceFields(), fTransX,
303 fTransY, fColor);
Brian Salomondeb53cc2017-11-08 13:50:53 -0500304 currVertex += vertexStride * GrAtlasTextOp::kVerticesPerGlyph;
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500305 ++result->fGlyphsRegenerated;
Brian Salomon18923f92017-11-06 16:26:02 -0500306 ++fCurrGlyph;
307 }
308
309 // We may have changed the color so update it here
310 fSubRun->setColor(fColor);
311 if (regenTexCoords) {
312 if (regenGlyphs) {
Robert Phillipscaf1ebb2018-03-01 14:28:44 -0500313 fSubRun->setStrike(std::move(strike));
Brian Salomon18923f92017-11-06 16:26:02 -0500314 }
315 fSubRun->setAtlasGeneration(fBrokenRun
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500316 ? GrDrawOpAtlas::kInvalidAtlasGeneration
317 : fFullAtlasManager->atlasGeneration(fSubRun->maskFormat()));
Brian Salomon18923f92017-11-06 16:26:02 -0500318 }
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500319 return true;
Brian Salomon18923f92017-11-06 16:26:02 -0500320}
321
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500322bool Regenerator::regenerate(Regenerator::Result* result) {
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500323 uint64_t currentAtlasGen = fFullAtlasManager->atlasGeneration(fSubRun->maskFormat());
Brian Salomon18923f92017-11-06 16:26:02 -0500324 // If regenerate() is called multiple times then the atlas gen may have changed. So we check
325 // this each time.
326 if (fSubRun->atlasGeneration() != currentAtlasGen) {
327 fRegenFlags |= kRegenTex;
328 }
329
330 switch (static_cast<RegenMask>(fRegenFlags)) {
331 case kRegenPos:
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500332 return this->doRegen<true, false, false, false>(result);
Brian Salomon18923f92017-11-06 16:26:02 -0500333 case kRegenCol:
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500334 return this->doRegen<false, true, false, false>(result);
Brian Salomon18923f92017-11-06 16:26:02 -0500335 case kRegenTex:
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500336 return this->doRegen<false, false, true, false>(result);
Brian Salomon18923f92017-11-06 16:26:02 -0500337 case kRegenGlyph:
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500338 return this->doRegen<false, false, true, true>(result);
Brian Salomon18923f92017-11-06 16:26:02 -0500339
340 // combinations
341 case kRegenPosCol:
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500342 return this->doRegen<true, true, false, false>(result);
Brian Salomon18923f92017-11-06 16:26:02 -0500343 case kRegenPosTex:
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500344 return this->doRegen<true, false, true, false>(result);
Brian Salomon18923f92017-11-06 16:26:02 -0500345 case kRegenPosTexGlyph:
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500346 return this->doRegen<true, false, true, true>(result);
Brian Salomon18923f92017-11-06 16:26:02 -0500347 case kRegenPosColTex:
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500348 return this->doRegen<true, true, true, false>(result);
Brian Salomon18923f92017-11-06 16:26:02 -0500349 case kRegenPosColTexGlyph:
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500350 return this->doRegen<true, true, true, true>(result);
Brian Salomon18923f92017-11-06 16:26:02 -0500351 case kRegenColTex:
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500352 return this->doRegen<false, true, true, false>(result);
Brian Salomon18923f92017-11-06 16:26:02 -0500353 case kRegenColTexGlyph:
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500354 return this->doRegen<false, true, true, true>(result);
Brian Salomon18923f92017-11-06 16:26:02 -0500355 case kNoRegen: {
Brian Salomon5c6ac642017-12-19 11:09:32 -0500356 bool hasW = fSubRun->hasWCoord();
357 auto vertexStride = GetVertexStride(fSubRun->maskFormat(), hasW);
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500358 result->fFinished = true;
359 result->fGlyphsRegenerated = fSubRun->glyphCount() - fCurrGlyph;
360 result->fFirstVertex = fBlob->fVertices + fSubRun->vertexStartIndex() +
361 fCurrGlyph * kVerticesPerGlyph * vertexStride;
Brian Salomon18923f92017-11-06 16:26:02 -0500362 fCurrGlyph = fSubRun->glyphCount();
363
364 // set use tokens for all of the glyphs in our subrun. This is only valid if we
365 // have a valid atlas generation
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500366 fFullAtlasManager->setUseTokenBulk(*fSubRun->bulkUseToken(),
367 fUploadTarget->tokenTracker()->nextDrawToken(),
368 fSubRun->maskFormat());
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500369 return true;
Brian Salomon18923f92017-11-06 16:26:02 -0500370 }
371 }
372 SK_ABORT("Should not get here");
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500373 return false;
Brian Salomon18923f92017-11-06 16:26:02 -0500374}