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

Side by Side Diff: src/gpu/GrAtlasTextContext.cpp

Issue 1092283002: Add support for rotating / scaling / translating gpu cached distance field textblobs (Closed) Base URL: https://skia.googlesource.com/skia.git@atdfopt3
Patch Set: adding comment Created 5 years, 8 months 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
« src/gpu/GrAtlasTextContext.h ('K') | « src/gpu/GrAtlasTextContext.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
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 #include "GrAtlasTextContext.h" 7 #include "GrAtlasTextContext.h"
8 8
9 #include "GrAtlas.h" 9 #include "GrAtlas.h"
10 #include "GrBatch.h" 10 #include "GrBatch.h"
(...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after
275 blob.fStrokeInfo.fJoin != paint.getStrokeJoin())) { 275 blob.fStrokeInfo.fJoin != paint.getStrokeJoin())) {
276 return true; 276 return true;
277 } 277 }
278 278
279 // Identical viewmatrices and we can reuse in all cases 279 // Identical viewmatrices and we can reuse in all cases
280 if (blob.fViewMatrix.cheapEqualTo(viewMatrix) && x == blob.fX && y == blob.f Y) { 280 if (blob.fViewMatrix.cheapEqualTo(viewMatrix) && x == blob.fX && y == blob.f Y) {
281 return false; 281 return false;
282 } 282 }
283 283
284 // Mixed blobs can't be regenerated at this point 284 // Mixed blobs can't be regenerated at this point
285 SkASSERT(blob.fHasBitmap || blob.fHasDistanceField);
286 if (blob.fHasBitmap && blob.fHasDistanceField) { 285 if (blob.fHasBitmap && blob.fHasDistanceField) {
287 return true; 286 return true;
288 } 287 }
289 288
290 // TODO distance fields can handle many of these conditions 289 if (blob.fHasBitmap) {
291 if (blob.fViewMatrix.getScaleX() != viewMatrix.getScaleX() || 290 if (blob.fViewMatrix.getScaleX() != viewMatrix.getScaleX() ||
292 blob.fViewMatrix.getScaleY() != viewMatrix.getScaleY() || 291 blob.fViewMatrix.getScaleY() != viewMatrix.getScaleY() ||
293 blob.fViewMatrix.getSkewX() != viewMatrix.getSkewX() || 292 blob.fViewMatrix.getSkewX() != viewMatrix.getSkewX() ||
294 blob.fViewMatrix.getSkewY() != viewMatrix.getSkewY()) { 293 blob.fViewMatrix.getSkewY() != viewMatrix.getSkewY()) {
295 return true; 294 return true;
296 } 295 }
297 296
298 if (blob.fHasBitmap) {
299 // We can update the positions in the cachedtextblobs without regenerati ng the whole blob, 297 // We can update the positions in the cachedtextblobs without regenerati ng the whole blob,
300 // but only for integer translations. 298 // but only for integer translations.
301 // This cool bit of math will determine the necessary translation to app ly to the already 299 // This cool bit of math will determine the necessary translation to app ly to the already
302 // generated vertex coordinates to move them to the correct position 300 // generated vertex coordinates to move them to the correct position
303 SkScalar transX = viewMatrix.getTranslateX() + 301 SkScalar transX = viewMatrix.getTranslateX() +
304 viewMatrix.getScaleX() * (x - blob.fX) + 302 viewMatrix.getScaleX() * (x - blob.fX) +
305 viewMatrix.getSkewX() * (y - blob.fY) - 303 viewMatrix.getSkewX() * (y - blob.fY) -
306 blob.fViewMatrix.getTranslateX(); 304 blob.fViewMatrix.getTranslateX();
307 SkScalar transY = viewMatrix.getTranslateY() + 305 SkScalar transY = viewMatrix.getTranslateY() +
308 viewMatrix.getSkewY() * (x - blob.fX) + 306 viewMatrix.getSkewY() * (x - blob.fX) +
(...skipping 13 matching lines...) Expand all
322 blob.fTotalYError += SkScalarAbs(SkScalarFraction(transY)); 320 blob.fTotalYError += SkScalarAbs(SkScalarFraction(transY));
323 if (blob.fTotalXError > kMinDiscernableTranslation || 321 if (blob.fTotalXError > kMinDiscernableTranslation ||
324 blob.fTotalYError > kMinDiscernableTranslation) { 322 blob.fTotalYError > kMinDiscernableTranslation) {
325 SkDebugf("Exceeding error threshold for bitmap text translation"); 323 SkDebugf("Exceeding error threshold for bitmap text translation");
326 } 324 }
327 #endif 325 #endif
328 (*outTransX) = transX; 326 (*outTransX) = transX;
329 (*outTransY) = transY; 327 (*outTransY) = transY;
330 } else { 328 } else {
331 // blob.fHasDistanceFields 329 // blob.fHasDistanceFields
332 // TODO figure out the regen formula 330 // A scale outside of [blob.fMaxMinScale, blob.fMinMaxScale] would resul t in a different
333 return true; 331 // distance field being generated, so we have to regenerate in those cas es
332 SkScalar newMaxScale = viewMatrix.getMaxScale();
333 SkScalar oldMaxScale = blob.fViewMatrix.getMaxScale();
334 SkScalar scaleAdjust = newMaxScale / oldMaxScale;
335 if (scaleAdjust < blob.fMaxMinScale || scaleAdjust > blob.fMinMaxScale) {
336 return true;
337 }
338
339 (*outTransX) = x - blob.fX;
340 (*outTransY) = y - blob.fY;
334 } 341 }
335 342
336 return false; 343 return false;
337 } 344 }
338 345
339 346
340 inline SkGlyphCache* GrAtlasTextContext::setupCache(BitmapTextBlob::Run* run, 347 inline SkGlyphCache* GrAtlasTextContext::setupCache(BitmapTextBlob::Run* run,
341 const SkPaint& skPaint, 348 const SkPaint& skPaint,
342 const SkMatrix* viewMatrix, 349 const SkMatrix* viewMatrix,
343 bool noGamma) { 350 bool noGamma) {
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
496 newRun.fVertexEndIndex = lastRun.fVertexEndIndex; 503 newRun.fVertexEndIndex = lastRun.fVertexEndIndex;
497 504
498 newRun.fGlyphStartIndex = lastRun.fGlyphEndIndex; 505 newRun.fGlyphStartIndex = lastRun.fGlyphEndIndex;
499 newRun.fGlyphEndIndex = lastRun.fGlyphEndIndex; 506 newRun.fGlyphEndIndex = lastRun.fGlyphEndIndex;
500 } 507 }
501 508
502 if (canDrawAsDistanceFields(runPaint, viewMatrix)) { 509 if (canDrawAsDistanceFields(runPaint, viewMatrix)) {
503 cacheBlob->fHasDistanceField = true; 510 cacheBlob->fHasDistanceField = true;
504 SkPaint dfPaint = runPaint; 511 SkPaint dfPaint = runPaint;
505 SkScalar textRatio; 512 SkScalar textRatio;
506 this->initDistanceFieldPaint(&dfPaint, &textRatio, viewMatrix); 513 this->initDistanceFieldPaint(cacheBlob, &dfPaint, &textRatio, viewMa trix);
507 Run& runIdx = cacheBlob->fRuns[run]; 514 Run& runIdx = cacheBlob->fRuns[run];
508 PerSubRunInfo& subRun = runIdx.fSubRunInfo.back(); 515 PerSubRunInfo& subRun = runIdx.fSubRunInfo.back();
509 subRun.fUseLCDText = runPaint.isLCDRenderText(); 516 subRun.fUseLCDText = runPaint.isLCDRenderText();
510 subRun.fDrawAsDistanceFields = true; 517 subRun.fDrawAsDistanceFields = true;
511 518
512 SkGlyphCache* cache = this->setupCache(&cacheBlob->fRuns[run], dfPai nt, NULL, true); 519 SkGlyphCache* cache = this->setupCache(&cacheBlob->fRuns[run], dfPai nt, NULL, true);
513 520
514 SkTDArray<char> fallbackTxt; 521 SkTDArray<char> fallbackTxt;
515 SkTDArray<SkScalar> fallbackPos; 522 SkTDArray<SkScalar> fallbackPos;
516 SkPoint dfOffset; 523 SkPoint dfOffset;
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
574 SkGlyphCache::AttachCache(cache); 581 SkGlyphCache::AttachCache(cache);
575 } 582 }
576 583
577 if (drawFilter) { 584 if (drawFilter) {
578 // A draw filter may change the paint arbitrarily, so we must re-see d in this case. 585 // A draw filter may change the paint arbitrarily, so we must re-see d in this case.
579 runPaint = skPaint; 586 runPaint = skPaint;
580 } 587 }
581 } 588 }
582 } 589 }
583 590
584 inline void GrAtlasTextContext::initDistanceFieldPaint(SkPaint* skPaint, SkScala r* textRatio, 591 inline void GrAtlasTextContext::initDistanceFieldPaint(BitmapTextBlob* blob,
592 SkPaint* skPaint,
593 SkScalar* textRatio,
585 const SkMatrix& viewMatri x) { 594 const SkMatrix& viewMatri x) {
586 // getMaxScale doesn't support perspective, so neither do we at the moment 595 // getMaxScale doesn't support perspective, so neither do we at the moment
587 SkASSERT(!viewMatrix.hasPerspective()); 596 SkASSERT(!viewMatrix.hasPerspective());
588 SkScalar maxScale = viewMatrix.getMaxScale(); 597 SkScalar maxScale = viewMatrix.getMaxScale();
589 SkScalar textSize = skPaint->getTextSize(); 598 SkScalar textSize = skPaint->getTextSize();
590 SkScalar scaledTextSize = textSize; 599 SkScalar scaledTextSize = textSize;
591 // if we have non-unity scale, we need to choose our base text size 600 // if we have non-unity scale, we need to choose our base text size
592 // based on the SkPaint's text size multiplied by the max scale factor 601 // based on the SkPaint's text size multiplied by the max scale factor
593 // TODO: do we need to do this if we're scaling down (i.e. maxScale < 1)? 602 // TODO: do we need to do this if we're scaling down (i.e. maxScale < 1)?
594 if (maxScale > 0 && !SkScalarNearlyEqual(maxScale, SK_Scalar1)) { 603 if (maxScale > 0 && !SkScalarNearlyEqual(maxScale, SK_Scalar1)) {
595 scaledTextSize *= maxScale; 604 scaledTextSize *= maxScale;
596 } 605 }
597 606
607 // We have three sizes of distance field text, and within each size 'bucket' there is a floor
608 // and ceiling. A scale outside of this range would require regenerating th e distance fields
609 SkScalar dfMaskScaleFloor;
610 SkScalar dfMaskScaleCeil;
598 if (scaledTextSize <= kSmallDFFontLimit) { 611 if (scaledTextSize <= kSmallDFFontLimit) {
612 dfMaskScaleFloor = kMinDFFontSize;
613 dfMaskScaleCeil = kMediumDFFontLimit;
599 *textRatio = textSize / kSmallDFFontSize; 614 *textRatio = textSize / kSmallDFFontSize;
600 skPaint->setTextSize(SkIntToScalar(kSmallDFFontSize)); 615 skPaint->setTextSize(SkIntToScalar(kSmallDFFontSize));
601 } else if (scaledTextSize <= kMediumDFFontLimit) { 616 } else if (scaledTextSize <= kMediumDFFontLimit) {
617 dfMaskScaleFloor = kMediumDFFontLimit;
618 dfMaskScaleCeil = kLargeDFFontSize;
602 *textRatio = textSize / kMediumDFFontSize; 619 *textRatio = textSize / kMediumDFFontSize;
603 skPaint->setTextSize(SkIntToScalar(kMediumDFFontSize)); 620 skPaint->setTextSize(SkIntToScalar(kMediumDFFontSize));
604 } else { 621 } else {
622 dfMaskScaleFloor = kLargeDFFontSize;
623 dfMaskScaleCeil = 2 * kLargeDFFontSize;
605 *textRatio = textSize / kLargeDFFontSize; 624 *textRatio = textSize / kLargeDFFontSize;
606 skPaint->setTextSize(SkIntToScalar(kLargeDFFontSize)); 625 skPaint->setTextSize(SkIntToScalar(kLargeDFFontSize));
607 } 626 }
608 627
628 // Because there can be multiple runs in the blob, we want the overall maxMi nScale, and
629 // minMaxScale to make regeneration decisions
jvanverth1 2015/04/21 15:29:47 A little more detail in a comment on how this work
630 blob->fMaxMinScale = SkMaxScalar(dfMaskScaleFloor / scaledTextSize, blob->fM axMinScale);
631 blob->fMinMaxScale = SkMinScalar(dfMaskScaleCeil / scaledTextSize, blob->fMi nMaxScale);
632
609 skPaint->setLCDRenderText(false); 633 skPaint->setLCDRenderText(false);
610 skPaint->setAutohinted(false); 634 skPaint->setAutohinted(false);
611 skPaint->setHinting(SkPaint::kNormal_Hinting); 635 skPaint->setHinting(SkPaint::kNormal_Hinting);
612 skPaint->setSubpixelText(true); 636 skPaint->setSubpixelText(true);
613 } 637 }
614 638
615 inline void GrAtlasTextContext::fallbackDrawPosText(BitmapTextBlob* blob, 639 inline void GrAtlasTextContext::fallbackDrawPosText(BitmapTextBlob* blob,
616 int runIndex, 640 int runIndex,
617 GrRenderTarget* rt, const Gr Clip& clip, 641 GrRenderTarget* rt, const Gr Clip& clip,
618 const GrPaint& paint, 642 const GrPaint& paint,
(...skipping 19 matching lines...) Expand all
638 SkGlyphCache::AttachCache(cache); 662 SkGlyphCache::AttachCache(cache);
639 } 663 }
640 664
641 inline GrAtlasTextContext::BitmapTextBlob* 665 inline GrAtlasTextContext::BitmapTextBlob*
642 GrAtlasTextContext::setupDFBlob(int glyphCount, const SkPaint& origPaint, 666 GrAtlasTextContext::setupDFBlob(int glyphCount, const SkPaint& origPaint,
643 const SkMatrix& viewMatrix, SkGlyphCache** cache , 667 const SkMatrix& viewMatrix, SkGlyphCache** cache ,
644 SkPaint* dfPaint, SkScalar* textRatio) { 668 SkPaint* dfPaint, SkScalar* textRatio) {
645 BitmapTextBlob* blob = fCache->createBlob(glyphCount, 1, kGrayTextVASize); 669 BitmapTextBlob* blob = fCache->createBlob(glyphCount, 1, kGrayTextVASize);
646 670
647 *dfPaint = origPaint; 671 *dfPaint = origPaint;
648 this->initDistanceFieldPaint(dfPaint, textRatio, viewMatrix); 672 this->initDistanceFieldPaint(blob, dfPaint, textRatio, viewMatrix);
649 blob->fViewMatrix = viewMatrix; 673 blob->fViewMatrix = viewMatrix;
650 Run& run = blob->fRuns[0]; 674 Run& run = blob->fRuns[0];
651 PerSubRunInfo& subRun = run.fSubRunInfo.back(); 675 PerSubRunInfo& subRun = run.fSubRunInfo.back();
652 subRun.fUseLCDText = origPaint.isLCDRenderText(); 676 subRun.fUseLCDText = origPaint.isLCDRenderText();
653 subRun.fDrawAsDistanceFields = true; 677 subRun.fDrawAsDistanceFields = true;
654 678
655 *cache = this->setupCache(&blob->fRuns[0], *dfPaint, NULL, true); 679 *cache = this->setupCache(&blob->fRuns[0], *dfPaint, NULL, true);
656 return blob; 680 return blob;
657 } 681 }
658 682
(...skipping 1458 matching lines...) Expand 10 before | Expand all | Expand 10 after
2117 pipelineBuilder.setFromPaint(grPaint, rt, clip); 2141 pipelineBuilder.setFromPaint(grPaint, rt, clip);
2118 2142
2119 GrColor color = grPaint.getColor(); 2143 GrColor color = grPaint.getColor();
2120 for (int run = 0; run < cacheBlob->fRunCount; run++) { 2144 for (int run = 0; run < cacheBlob->fRunCount; run++) {
2121 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, 0, 0, sk Paint); 2145 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, 0, 0, sk Paint);
2122 } 2146 }
2123 2147
2124 // Now flush big glyphs 2148 // Now flush big glyphs
2125 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, 0, 0); 2149 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, 0, 0);
2126 } 2150 }
OLDNEW
« src/gpu/GrAtlasTextContext.h ('K') | « src/gpu/GrAtlasTextContext.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698