blob: e0811587e42301279539433495c4893f230baf2f [file] [log] [blame]
joshualittddd22d82016-02-16 06:47:52 -08001/*
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
8#include "GrAtlasTextBlob.h"
9
Brian Salomon742e31d2016-12-07 17:06:19 -050010#include "GrOpFlushState.h"
joshualitt8e84a1e2016-02-16 11:09:25 -080011#include "GrTextUtils.h"
joshualittddd22d82016-02-16 06:47:52 -080012
13#include "SkDistanceFieldGen.h"
14#include "SkGlyphCache.h"
15
Brian Salomon89527432016-12-16 09:52:16 -050016#include "ops/GrAtlasTextOp.h"
joshualittddd22d82016-02-16 06:47:52 -080017
18////////////////////////////////////////////////////////////////////////////////////////////////////
19// A large template to handle regenerating the vertices of a textblob with as few branches as
20// possible
21template <bool regenPos, bool regenCol, bool regenTexCoords>
22inline void regen_vertices(intptr_t vertex, const GrGlyph* glyph, size_t vertexStride,
23 bool useDistanceFields, SkScalar transX, SkScalar transY,
24 GrColor color) {
Robert Phillips8296e752017-08-25 08:45:21 -040025 uint16_t u0, v0, u1, v1;
joshualittddd22d82016-02-16 06:47:52 -080026 if (regenTexCoords) {
27 SkASSERT(glyph);
28 int width = glyph->fBounds.width();
29 int height = glyph->fBounds.height();
30
31 if (useDistanceFields) {
32 u0 = glyph->fAtlasLocation.fX + SK_DistanceFieldInset;
33 v0 = glyph->fAtlasLocation.fY + SK_DistanceFieldInset;
34 u1 = u0 + width - 2 * SK_DistanceFieldInset;
35 v1 = v0 + height - 2 * SK_DistanceFieldInset;
36 } else {
37 u0 = glyph->fAtlasLocation.fX;
38 v0 = glyph->fAtlasLocation.fY;
39 u1 = u0 + width;
40 v1 = v0 + height;
41 }
Jim Van Vertheafa64b2017-09-18 10:05:00 -040042 // We pack the 2bit page index in the low bit of the u and v texture coords
43 uint32_t pageIndex = glyph->pageIndex();
44 SkASSERT(pageIndex < 4);
45 uint16_t uBit = (pageIndex >> 1) & 0x1;
46 uint16_t vBit = pageIndex & 0x1;
Jim Van Verth6a7a7042017-09-11 11:04:10 -040047 u0 <<= 1;
Jim Van Vertheafa64b2017-09-18 10:05:00 -040048 u0 |= uBit;
Jim Van Verth6a7a7042017-09-11 11:04:10 -040049 v0 <<= 1;
Jim Van Vertheafa64b2017-09-18 10:05:00 -040050 v0 |= vBit;
Jim Van Verth6a7a7042017-09-11 11:04:10 -040051 u1 <<= 1;
Jim Van Vertheafa64b2017-09-18 10:05:00 -040052 u1 |= uBit;
Jim Van Verth6a7a7042017-09-11 11:04:10 -040053 v1 <<= 1;
Jim Van Vertheafa64b2017-09-18 10:05:00 -040054 v1 |= vBit;
joshualittddd22d82016-02-16 06:47:52 -080055 }
56
57 // This is a bit wonky, but sometimes we have LCD text, in which case we won't have color
58 // vertices, hence vertexStride - sizeof(SkIPoint16)
59 intptr_t colorOffset = sizeof(SkPoint);
60 intptr_t texCoordOffset = vertexStride - sizeof(SkIPoint16);
61
62 // V0
63 if (regenPos) {
64 SkPoint* point = reinterpret_cast<SkPoint*>(vertex);
65 point->fX += transX;
66 point->fY += transY;
67 }
68
69 if (regenCol) {
70 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + colorOffset);
71 *vcolor = color;
72 }
73
74 if (regenTexCoords) {
jvanverth7023a002016-02-22 11:25:32 -080075 uint16_t* textureCoords = reinterpret_cast<uint16_t*>(vertex + texCoordOffset);
Robert Phillips8296e752017-08-25 08:45:21 -040076 textureCoords[0] = u0;
77 textureCoords[1] = v0;
joshualittddd22d82016-02-16 06:47:52 -080078 }
79 vertex += vertexStride;
80
81 // V1
82 if (regenPos) {
83 SkPoint* point = reinterpret_cast<SkPoint*>(vertex);
84 point->fX += transX;
85 point->fY += transY;
86 }
87
88 if (regenCol) {
89 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + colorOffset);
90 *vcolor = color;
91 }
92
93 if (regenTexCoords) {
jvanverth7023a002016-02-22 11:25:32 -080094 uint16_t* textureCoords = reinterpret_cast<uint16_t*>(vertex + texCoordOffset);
Robert Phillips8296e752017-08-25 08:45:21 -040095 textureCoords[0] = u0;
96 textureCoords[1] = v1;
joshualittddd22d82016-02-16 06:47:52 -080097 }
98 vertex += vertexStride;
99
100 // V2
101 if (regenPos) {
102 SkPoint* point = reinterpret_cast<SkPoint*>(vertex);
103 point->fX += transX;
104 point->fY += transY;
105 }
106
107 if (regenCol) {
108 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + colorOffset);
109 *vcolor = color;
110 }
111
112 if (regenTexCoords) {
jvanverth7023a002016-02-22 11:25:32 -0800113 uint16_t* textureCoords = reinterpret_cast<uint16_t*>(vertex + texCoordOffset);
Robert Phillips8296e752017-08-25 08:45:21 -0400114 textureCoords[0] = u1;
Brian Salomon57caa662017-10-18 12:21:05 +0000115 textureCoords[1] = v0;
joshualittddd22d82016-02-16 06:47:52 -0800116 }
117 vertex += vertexStride;
118
119 // V3
120 if (regenPos) {
121 SkPoint* point = reinterpret_cast<SkPoint*>(vertex);
122 point->fX += transX;
123 point->fY += transY;
124 }
125
126 if (regenCol) {
127 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + colorOffset);
128 *vcolor = color;
129 }
130
131 if (regenTexCoords) {
jvanverth7023a002016-02-22 11:25:32 -0800132 uint16_t* textureCoords = reinterpret_cast<uint16_t*>(vertex + texCoordOffset);
Robert Phillips8296e752017-08-25 08:45:21 -0400133 textureCoords[0] = u1;
Brian Salomon57caa662017-10-18 12:21:05 +0000134 textureCoords[1] = v1;
joshualittddd22d82016-02-16 06:47:52 -0800135 }
136}
137
138template <bool regenPos, bool regenCol, bool regenTexCoords, bool regenGlyphs>
Brian Salomon29b60c92017-10-31 14:42:10 -0400139void GrAtlasTextBlob::regenInOp(GrDeferredUploadTarget* target, GrAtlasGlyphCache* fontCache,
Brian Salomon344ec422016-12-15 10:58:41 -0500140 GrBlobRegenHelper* helper, Run* run, Run::SubRunInfo* info,
141 SkAutoGlyphCache* lazyCache, int glyphCount, size_t vertexStride,
142 GrColor color, SkScalar transX, SkScalar transY) const {
bsalomond1c71fd2016-05-19 12:51:46 -0700143 SkASSERT(lazyCache);
joshualittddd22d82016-02-16 06:47:52 -0800144 static_assert(!regenGlyphs || regenTexCoords, "must regenTexCoords along regenGlyphs");
Brian Salomonf856fd12016-12-16 14:24:34 -0500145 GrAtlasTextStrike* strike = nullptr;
joshualittddd22d82016-02-16 06:47:52 -0800146 if (regenTexCoords) {
147 info->resetBulkUseToken();
148
bsalomond1c71fd2016-05-19 12:51:46 -0700149 const SkDescriptor* desc = (run->fOverrideDescriptor && !info->drawAsDistanceFields())
150 ? run->fOverrideDescriptor->getDesc()
151 : run->fDescriptor.getDesc();
152
153 if (!*lazyCache || (*lazyCache)->getDescriptor() != *desc) {
bsalomon8b6fa5e2016-05-19 16:23:47 -0700154 SkScalerContextEffects effects;
155 effects.fPathEffect = run->fPathEffect.get();
156 effects.fRasterizer = run->fRasterizer.get();
157 effects.fMaskFilter = run->fMaskFilter.get();
Hal Canary144caf52016-11-07 17:57:18 -0500158 lazyCache->reset(SkGlyphCache::DetachCache(run->fTypeface.get(), effects, desc));
joshualittddd22d82016-02-16 06:47:52 -0800159 }
160
161 if (regenGlyphs) {
bsalomond1c71fd2016-05-19 12:51:46 -0700162 strike = fontCache->getStrike(lazyCache->get());
joshualittddd22d82016-02-16 06:47:52 -0800163 } else {
164 strike = info->strike();
165 }
166 }
167
168 bool brokenRun = false;
Jim Van Verth5698c8a2017-10-12 10:18:44 -0400169 intptr_t vertex = reinterpret_cast<intptr_t>(fVertices);
170 vertex += info->vertexStartIndex();
joshualittddd22d82016-02-16 06:47:52 -0800171 for (int glyphIdx = 0; glyphIdx < glyphCount; glyphIdx++) {
172 GrGlyph* glyph = nullptr;
173 if (regenTexCoords) {
174 size_t glyphOffset = glyphIdx + info->glyphStartIndex();
175
176 if (regenGlyphs) {
177 // Get the id from the old glyph, and use the new strike to lookup
178 // the glyph.
179 GrGlyph::PackedID id = fGlyphs[glyphOffset]->fPackedID;
bsalomond1c71fd2016-05-19 12:51:46 -0700180 fGlyphs[glyphOffset] = strike->getGlyph(id, info->maskFormat(), lazyCache->get());
joshualittddd22d82016-02-16 06:47:52 -0800181 SkASSERT(id == fGlyphs[glyphOffset]->fPackedID);
182 }
183 glyph = fGlyphs[glyphOffset];
184 SkASSERT(glyph && glyph->fMaskFormat == info->maskFormat());
185
186 if (!fontCache->hasGlyph(glyph) &&
bsalomond1c71fd2016-05-19 12:51:46 -0700187 !strike->addGlyphToAtlas(target, glyph, lazyCache->get(), info->maskFormat())) {
joshualittddd22d82016-02-16 06:47:52 -0800188 helper->flush();
189 brokenRun = glyphIdx > 0;
190
191 SkDEBUGCODE(bool success =) strike->addGlyphToAtlas(target,
192 glyph,
bsalomond1c71fd2016-05-19 12:51:46 -0700193 lazyCache->get(),
joshualittddd22d82016-02-16 06:47:52 -0800194 info->maskFormat());
195 SkASSERT(success);
196 }
197 fontCache->addGlyphToBulkAndSetUseToken(info->bulkUseToken(), glyph,
bsalomon342bfc22016-04-01 06:06:20 -0700198 target->nextDrawToken());
joshualittddd22d82016-02-16 06:47:52 -0800199 }
200
joshualittddd22d82016-02-16 06:47:52 -0800201 regen_vertices<regenPos, regenCol, regenTexCoords>(vertex, glyph, vertexStride,
Jim Van Verth58c3cce2017-10-19 15:50:24 -0400202 info->drawAsDistanceFields(),
203 transX, transY, color);
Jim Van Verth5698c8a2017-10-12 10:18:44 -0400204 vertex += vertexStride * GrAtlasTextOp::kVerticesPerGlyph;
joshualittddd22d82016-02-16 06:47:52 -0800205 helper->incGlyphCount();
206 }
207
208 // We may have changed the color so update it here
209 info->setColor(color);
210 if (regenTexCoords) {
211 if (regenGlyphs) {
212 info->setStrike(strike);
213 }
Brian Salomon2ee084e2016-12-16 18:59:19 -0500214 info->setAtlasGeneration(brokenRun ? GrDrawOpAtlas::kInvalidAtlasGeneration
215 : fontCache->atlasGeneration(info->maskFormat()));
joshualittddd22d82016-02-16 06:47:52 -0800216 }
217}
218
219enum RegenMask {
220 kNoRegen = 0x0,
221 kRegenPos = 0x1,
222 kRegenCol = 0x2,
223 kRegenTex = 0x4,
224 kRegenGlyph = 0x8 | kRegenTex, // we have to regenerate the texture coords when we regen glyphs
225
226 // combinations
bsalomond1c71fd2016-05-19 12:51:46 -0700227 kRegenPosCol = kRegenPos | kRegenCol,
joshualittddd22d82016-02-16 06:47:52 -0800228 kRegenPosTex = kRegenPos | kRegenTex,
229 kRegenPosTexGlyph = kRegenPos | kRegenGlyph,
230 kRegenPosColTex = kRegenPos | kRegenCol | kRegenTex,
231 kRegenPosColTexGlyph = kRegenPos | kRegenCol | kRegenGlyph,
232 kRegenColTex = kRegenCol | kRegenTex,
233 kRegenColTexGlyph = kRegenCol | kRegenGlyph,
234};
235
bsalomond1c71fd2016-05-19 12:51:46 -0700236#define REGEN_ARGS target, fontCache, helper, &run, &info, lazyCache, \
joshualittddd22d82016-02-16 06:47:52 -0800237 *glyphCount, vertexStride, color, transX, transY
238
Brian Salomon29b60c92017-10-31 14:42:10 -0400239void GrAtlasTextBlob::regenInOp(GrDeferredUploadTarget* target, GrAtlasGlyphCache* fontCache,
240 GrBlobRegenHelper* helper, int runIndex, int subRunIndex,
241 SkAutoGlyphCache* lazyCache, size_t vertexStride,
242 const SkMatrix& viewMatrix, SkScalar x, SkScalar y, GrColor color,
Brian Salomon09d994e2016-12-21 11:14:46 -0500243 void** vertices, size_t* byteCount, int* glyphCount) {
joshualittddd22d82016-02-16 06:47:52 -0800244 Run& run = fRuns[runIndex];
245 Run::SubRunInfo& info = run.fSubRunInfo[subRunIndex];
246
247 uint64_t currentAtlasGen = fontCache->atlasGeneration(info.maskFormat());
248
joshualitt8e0ef292016-02-19 14:13:03 -0800249 // Compute translation if any
250 SkScalar transX, transY;
251 info.computeTranslation(viewMatrix, x, y, &transX, &transY);
252
Brian Salomonf856fd12016-12-16 14:24:34 -0500253 // Because the GrAtlasGlyphCache may evict the strike a blob depends on using for
joshualittddd22d82016-02-16 06:47:52 -0800254 // generating its texture coords, we have to track whether or not the strike has
255 // been abandoned. If it hasn't been abandoned, then we can use the GrGlyph*s as is
256 // otherwise we have to get the new strike, and use that to get the correct glyphs.
257 // Because we do not have the packed ids, and thus can't look up our glyphs in the
258 // new strike, we instead keep our ref to the old strike and use the packed ids from
259 // it. These ids will still be valid as long as we hold the ref. When we are done
260 // updating our cache of the GrGlyph*s, we drop our ref on the old strike
261 bool regenerateGlyphs = info.strike()->isAbandoned();
262 bool regenerateTextureCoords = info.atlasGeneration() != currentAtlasGen ||
263 regenerateGlyphs;
264 bool regenerateColors = kARGB_GrMaskFormat != info.maskFormat() &&
265 info.color() != color;
266 bool regeneratePositions = transX != 0.f || transY != 0.f;
267 *glyphCount = info.glyphCount();
268
269 uint32_t regenMaskBits = kNoRegen;
270 regenMaskBits |= regeneratePositions ? kRegenPos : 0;
271 regenMaskBits |= regenerateColors ? kRegenCol : 0;
272 regenMaskBits |= regenerateTextureCoords ? kRegenTex : 0;
273 regenMaskBits |= regenerateGlyphs ? kRegenGlyph : 0;
274 RegenMask regenMask = (RegenMask)regenMaskBits;
275
276 switch (regenMask) {
Brian Salomon344ec422016-12-15 10:58:41 -0500277 case kRegenPos:
278 this->regenInOp<true, false, false, false>(REGEN_ARGS);
279 break;
280 case kRegenCol:
281 this->regenInOp<false, true, false, false>(REGEN_ARGS);
282 break;
283 case kRegenTex:
284 this->regenInOp<false, false, true, false>(REGEN_ARGS);
285 break;
286 case kRegenGlyph:
287 this->regenInOp<false, false, true, true>(REGEN_ARGS);
288 break;
joshualittddd22d82016-02-16 06:47:52 -0800289
Brian Salomon344ec422016-12-15 10:58:41 -0500290 // combinations
291 case kRegenPosCol:
292 this->regenInOp<true, true, false, false>(REGEN_ARGS);
293 break;
294 case kRegenPosTex:
295 this->regenInOp<true, false, true, false>(REGEN_ARGS);
296 break;
297 case kRegenPosTexGlyph:
298 this->regenInOp<true, false, true, true>(REGEN_ARGS);
299 break;
300 case kRegenPosColTex:
301 this->regenInOp<true, true, true, false>(REGEN_ARGS);
302 break;
303 case kRegenPosColTexGlyph:
304 this->regenInOp<true, true, true, true>(REGEN_ARGS);
305 break;
306 case kRegenColTex:
307 this->regenInOp<false, true, true, false>(REGEN_ARGS);
308 break;
309 case kRegenColTexGlyph:
310 this->regenInOp<false, true, true, true>(REGEN_ARGS);
311 break;
joshualittddd22d82016-02-16 06:47:52 -0800312 case kNoRegen:
313 helper->incGlyphCount(*glyphCount);
314
315 // set use tokens for all of the glyphs in our subrun. This is only valid if we
316 // have a valid atlas generation
bsalomon342bfc22016-04-01 06:06:20 -0700317 fontCache->setUseTokenBulk(*info.bulkUseToken(), target->nextDrawToken(),
joshualittddd22d82016-02-16 06:47:52 -0800318 info.maskFormat());
319 break;
320 }
321
322 *byteCount = info.byteCount();
323 *vertices = fVertices + info.vertexStartIndex();
324}