Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(410)

Side by Side Diff: src/gpu/batches/GrAtlasTextBatch.cpp

Issue 1458233003: Factor out GrAtlasTextBatch fromt GrAtlasTextContext (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: linux build Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/gpu/batches/GrAtlasTextBatch.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright 2015 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 "GrAtlasTextBatch.h"
9
10 #include "GrBatchFontCache.h"
11 #include "GrBatchFlushState.h"
12 #include "GrBatchTest.h"
13 #include "GrResourceProvider.h"
14
15 #include "SkDistanceFieldGen.h"
16 #include "SkGlyphCache.h"
17
18 #include "effects/GrBitmapTextGeoProc.h"
19 #include "effects/GrDistanceFieldGeoProc.h"
20
21 static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
22 unsigned r = SkColorGetR(c);
23 unsigned g = SkColorGetG(c);
24 unsigned b = SkColorGetB(c);
25 return GrColorPackRGBA(r, g, b, 0xff);
26 }
27
28 static const int kDistanceAdjustLumShift = 5;
29
30 SkString GrAtlasTextBatch::dumpInfo() const {
31 SkString str;
32
33 for (int i = 0; i < fGeoCount; ++i) {
34 str.appendf("%d: Color: 0x%08x Trans: %.2f,%.2f Runs: %d\n",
35 i,
36 fGeoData[i].fColor,
37 fGeoData[i].fTransX,
38 fGeoData[i].fTransY,
39 fGeoData[i].fBlob->fRunCount);
40 }
41
42 str.append(INHERITED::dumpInfo());
43 return str;
44 }
45
46 void GrAtlasTextBatch::getInvariantOutputColor(GrInitInvariantOutput* out) const {
47 if (kColorBitmapMask_MaskType == fMaskType) {
48 out->setUnknownFourComponents();
49 } else {
50 out->setKnownFourComponents(fBatch.fColor);
51 }
52 }
53
54 void GrAtlasTextBatch::getInvariantOutputCoverage(GrInitInvariantOutput* out) co nst {
55 switch (fMaskType) {
56 case kGrayscaleDistanceField_MaskType:
57 case kGrayscaleCoverageMask_MaskType:
58 out->setUnknownSingleComponent();
59 break;
60 case kLCDCoverageMask_MaskType:
61 case kLCDDistanceField_MaskType:
62 out->setUnknownOpaqueFourComponents();
63 out->setUsingLCDCoverage();
64 break;
65 case kColorBitmapMask_MaskType:
66 out->setKnownSingleComponent(0xff);
67 }
68 }
69
70 void GrAtlasTextBatch::initBatchTracker(const GrPipelineOptimizations& opt) {
71 // Handle any color overrides
72 if (!opt.readsColor()) {
73 fGeoData[0].fColor = GrColor_ILLEGAL;
74 }
75 opt.getOverrideColorIfSet(&fGeoData[0].fColor);
76
77 // setup batch properties
78 fBatch.fColorIgnored = !opt.readsColor();
79 fBatch.fColor = fGeoData[0].fColor;
80 fBatch.fUsesLocalCoords = opt.readsLocalCoords();
81 fBatch.fCoverageIgnored = !opt.readsCoverage();
82 }
83
84 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.
86 // TODO actually only invert if we don't have RGBA
87 SkMatrix localMatrix;
88 if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix)) {
89 SkDebugf("Cannot invert viewmatrix\n");
90 return;
91 }
92
93 GrTexture* texture = fFontCache->getTexture(this->maskFormat());
94 if (!texture) {
95 SkDebugf("Could not allocate backing texture for atlas\n");
96 return;
97 }
98
99 bool usesDistanceFields = this->usesDistanceFields();
100 GrMaskFormat maskFormat = this->maskFormat();
101 bool isLCD = this->isLCD();
102
103 SkAutoTUnref<const GrGeometryProcessor> gp;
104 if (usesDistanceFields) {
105 gp.reset(this->setupDfProcessor(this->viewMatrix(), fFilteredColor, this ->color(),
106 texture));
107 } else {
108 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kNone _FilterMode);
109 gp.reset(GrBitmapTextGeoProc::Create(this->color(),
110 texture,
111 params,
112 maskFormat,
113 localMatrix,
114 this->usesLocalCoords()));
115 }
116
117 FlushInfo flushInfo;
118 flushInfo.fGlyphsToFlush = 0;
119 size_t vertexStride = gp->getVertexStride();
120 SkASSERT(vertexStride == (usesDistanceFields ?
121 GetVertexStrideDf(maskFormat, isLCD) :
122 GetVertexStride(maskFormat)));
123
124 target->initDraw(gp, this->pipeline());
125
126 int glyphCount = this->numGlyphs();
127 const GrVertexBuffer* vertexBuffer;
128
129 void* vertices = target->makeVertexSpace(vertexStride,
130 glyphCount * kVerticesPerGlyph,
131 &vertexBuffer,
132 &flushInfo.fVertexOffset);
133 flushInfo.fVertexBuffer.reset(SkRef(vertexBuffer));
134 flushInfo.fIndexBuffer.reset(target->resourceProvider()->refQuadIndexBuffer( ));
135 if (!vertices || !flushInfo.fVertexBuffer) {
136 SkDebugf("Could not allocate vertices\n");
137 return;
138 }
139
140 unsigned char* currVertex = reinterpret_cast<unsigned char*>(vertices);
141
142 // We cache some values to avoid going to the glyphcache for the same fontSc aler twice
143 // in a row
144 const SkDescriptor* desc = nullptr;
145 SkGlyphCache* cache = nullptr;
146 GrFontScaler* scaler = nullptr;
147 SkTypeface* typeface = nullptr;
148
149 for (int i = 0; i < fGeoCount; i++) {
150 Geometry& args = fGeoData[i];
151 Blob* blob = args.fBlob;
152 Run& run = blob->fRuns[args.fRun];
153 TextInfo& info = run.fSubRunInfo[args.fSubRun];
154
155 uint64_t currentAtlasGen = fFontCache->atlasGeneration(maskFormat);
156 bool regenerateTextureCoords = info.fAtlasGeneration != currentAtlasGen ||
157 info.fStrike->isAbandoned();
158 bool regenerateColors;
159 if (usesDistanceFields) {
160 regenerateColors = !isLCD && run.fColor != args.fColor;
161 } else {
162 regenerateColors = kA8_GrMaskFormat == maskFormat && run.fColor != a rgs.fColor;
163 }
164 bool regeneratePositions = args.fTransX != 0.f || args.fTransY != 0.f;
165 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex;
166
167 // We regenerate both texture coords and colors in the blob itself, and update the
168 // atlas generation. If we don't end up purging any unused plots, we ca n avoid
169 // regenerating the coords. We could take a finer grained approach to u pdating texture
170 // coords but its not clear if the extra bookkeeping would offset any ga ins.
171 // To avoid looping over the glyphs twice, we do one loop and conditiona lly update color
172 // or coords as needed. One final note, if we have to break a run for a n atlas eviction
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
179 // Because the GrBatchFontCache may evict the strike a blob depends on using for
180 // generating its texture coords, we have to track whether or not th e strike has
181 // been abandoned. If it hasn't been abandoned, then we can use the GrGlyph*s as is
182 // otherwise we have to get the new strike, and use that to get the correct glyphs.
183 // Because we do not have the packed ids, and thus can't look up our glyphs in the
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
192 // We can reuse if we have a valid strike and our descriptors / typeface are the
193 // same. The override descriptor is only for the non distance f ield text within
194 // a run
195 const SkDescriptor* newDesc = (run.fOverrideDescriptor && !usesD istanceFields) ?
196 run.fOverrideDescriptor->getDesc() :
197 run.fDescriptor.getDesc();
198 if (!cache || !SkTypeface::Equal(typeface, run.fTypeface) ||
199 !(desc->equals(*newDesc))) {
200 if (cache) {
201 SkGlyphCache::AttachCache(cache);
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
210 if (info.fStrike->isAbandoned()) {
211 regenerateGlyphs = true;
212 strike = fFontCache->getStrike(scaler);
213 } else {
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 }
298
299 // now copy all vertices
300 size_t byteCount = info.fVertexEndIndex - info.fVertexStartIndex;
301 memcpy(currVertex, blob->fVertices + info.fVertexStartIndex, byteCount);
302
303 currVertex += byteCount;
304 }
305 // Make sure to attach the last cache if applicable
306 if (cache) {
307 SkGlyphCache::AttachCache(cache);
308 }
309 this->flush(target, &flushInfo);
310 }
311
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 ) {
370 GrVertices vertices;
371 int maxGlyphsPerDraw = flushInfo->fIndexBuffer->maxQuads();
372 vertices.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuffer,
373 flushInfo->fIndexBuffer, flushInfo->fVertexOffset,
374 kVerticesPerGlyph, kIndicesPerGlyph, flushInfo->fGlyp hsToFlush,
375 maxGlyphsPerDraw);
376 target->draw(vertices);
377 flushInfo->fVertexOffset += kVerticesPerGlyph * flushInfo->fGlyphsToFlush;
378 flushInfo->fGlyphsToFlush = 0;
379 }
380
381 bool GrAtlasTextBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) {
382 GrAtlasTextBatch* that = t->cast<GrAtlasTextBatch>();
383 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeli ne(),
384 that->bounds(), caps)) {
385 return false;
386 }
387
388 if (fMaskType != that->fMaskType) {
389 return false;
390 }
391
392 if (!this->usesDistanceFields()) {
393 // TODO we can often batch across LCD text if we have dual source blendi ng and don't
394 // have to use the blend constant
395 if (kGrayscaleCoverageMask_MaskType != fMaskType && this->color() != tha t->color()) {
396 return false;
397 }
398 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->vi ewMatrix())) {
399 return false;
400 }
401 } else {
402 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
403 return false;
404 }
405
406 if (fFilteredColor != that->fFilteredColor) {
407 return false;
408 }
409
410 if (fUseBGR != that->fUseBGR) {
411 return false;
412 }
413
414 // TODO see note above
415 if (kLCDDistanceField_MaskType == fMaskType && this->color() != that->co lor()) {
416 return false;
417 }
418 }
419
420 fBatch.fNumGlyphs += that->numGlyphs();
421
422 // Reallocate space for geo data if necessary and then import that's geo dat a.
423 int newGeoCount = that->fGeoCount + fGeoCount;
424 // We assume (and here enforce) that the allocation size is the smallest pow er of two that
425 // is greater than or equal to the number of geometries (and at least
426 // kMinGeometryAllocated).
427 int newAllocSize = GrNextPow2(newGeoCount);
428 int currAllocSize = SkTMax<int>(kMinGeometryAllocated, GrNextPow2(fGeoCount) );
429
430 if (newGeoCount > currAllocSize) {
431 fGeoData.realloc(newAllocSize);
432 }
433
434 memcpy(&fGeoData[fGeoCount], that->fGeoData.get(), that->fGeoCount * sizeof( Geometry));
435 // We steal the ref on the blobs from the other TextBatch and set its count to 0 so that
436 // it doesn't try to unref them.
437 #ifdef SK_DEBUG
438 for (int i = 0; i < that->fGeoCount; ++i) {
439 that->fGeoData.get()[i].fBlob = (Blob*)0x1;
440 }
441 #endif
442 that->fGeoCount = 0;
443 fGeoCount = newGeoCount;
444
445 this->joinBounds(that->bounds());
446 return true;
447 }
448
449 // TODO just use class params
450 // TODO trying to figure out why lcd is so whack
451 GrGeometryProcessor* GrAtlasTextBatch::setupDfProcessor(const SkMatrix& viewMatr ix,
452 SkColor filteredColor,
453 GrColor color, GrTexture * texture) {
454 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBilerp_F ilterMode);
455 bool isLCD = this->isLCD();
456 // set up any flags
457 uint32_t flags = viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffect Flag : 0;
458
459 // see if we need to create a new effect
460 if (isLCD) {
461 flags |= kUseLCD_DistanceFieldEffectFlag;
462 flags |= viewMatrix.rectStaysRect() ? kRectToRect_DistanceFieldEffectFla g : 0;
463 flags |= fUseBGR ? kBGR_DistanceFieldEffectFlag : 0;
464
465 GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor);
466
467 float redCorrection =
468 (*fDistanceAdjustTable)[GrColorUnpackR(colorNoPreMul) >> kDistanceAd justLumShift];
469 float greenCorrection =
470 (*fDistanceAdjustTable)[GrColorUnpackG(colorNoPreMul) >> kDistanceAd justLumShift];
471 float blueCorrection =
472 (*fDistanceAdjustTable)[GrColorUnpackB(colorNoPreMul) >> kDistanceAd justLumShift];
473 GrDistanceFieldLCDTextGeoProc::DistanceAdjust widthAdjust =
474 GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(redCorrection,
475 greenCorrection,
476 blueCorrection);
477
478 return GrDistanceFieldLCDTextGeoProc::Create(color,
479 viewMatrix,
480 texture,
481 params,
482 widthAdjust,
483 flags,
484 this->usesLocalCoords());
485 } else {
486 flags |= kColorAttr_DistanceFieldEffectFlag;
487 #ifdef SK_GAMMA_APPLY_TO_A8
488 U8CPU lum = SkColorSpaceLuminance::computeLuminance(SK_GAMMA_EXPONENT, f ilteredColor);
489 float correction = (*fDistanceAdjustTable)[lum >> kDistanceAdjustLumShif t];
490 return GrDistanceFieldA8TextGeoProc::Create(color,
491 viewMatrix,
492 texture,
493 params,
494 correction,
495 flags,
496 this->usesLocalCoords());
497 #else
498 return GrDistanceFieldA8TextGeoProc::Create(color,
499 viewMatrix,
500 texture,
501 params,
502 flags,
503 this->usesLocalCoords());
504 #endif
505 }
506
507 }
OLDNEW
« no previous file with comments | « src/gpu/batches/GrAtlasTextBatch.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698