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

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
« no previous file with comments | « 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 269 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 must be regenerated. We could probably figure out a way to d o integer scrolls 284 // Mixed blobs must be regenerated. We could probably figure out a way to d o integer scrolls
285 // for mixed blobs if this becomes an issue. 285 // for mixed blobs if this becomes an issue.
286 if (blob.hasBitmap() && blob.hasDistanceField()) { 286 if (blob.hasBitmap() && blob.hasDistanceField()) {
287 return true; 287 return true;
288 } 288 }
289 289
290 // TODO distance fields can handle many of these conditions
291 if (blob.fViewMatrix.getScaleX() != viewMatrix.getScaleX() ||
292 blob.fViewMatrix.getScaleY() != viewMatrix.getScaleY() ||
293 blob.fViewMatrix.getSkewX() != viewMatrix.getSkewX() ||
294 blob.fViewMatrix.getSkewY() != viewMatrix.getSkewY()) {
295 return true;
296 }
297
298 if (blob.hasBitmap()) { 290 if (blob.hasBitmap()) {
291 if (blob.fViewMatrix.getScaleX() != viewMatrix.getScaleX() ||
292 blob.fViewMatrix.getScaleY() != viewMatrix.getScaleY() ||
293 blob.fViewMatrix.getSkewX() != viewMatrix.getSkewX() ||
294 blob.fViewMatrix.getSkewY() != viewMatrix.getSkewY()) {
295 return true;
296 }
297
299 // We can update the positions in the cachedtextblobs without regenerati ng the whole blob, 298 // We can update the positions in the cachedtextblobs without regenerati ng the whole blob,
300 // but only for integer translations. 299 // but only for integer translations.
301 // This cool bit of math will determine the necessary translation to app ly to the already 300 // 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 301 // generated vertex coordinates to move them to the correct position
303 SkScalar transX = viewMatrix.getTranslateX() + 302 SkScalar transX = viewMatrix.getTranslateX() +
304 viewMatrix.getScaleX() * (x - blob.fX) + 303 viewMatrix.getScaleX() * (x - blob.fX) +
305 viewMatrix.getSkewX() * (y - blob.fY) - 304 viewMatrix.getSkewX() * (y - blob.fY) -
306 blob.fViewMatrix.getTranslateX(); 305 blob.fViewMatrix.getTranslateX();
307 SkScalar transY = viewMatrix.getTranslateY() + 306 SkScalar transY = viewMatrix.getTranslateY() +
308 viewMatrix.getSkewY() * (x - blob.fX) + 307 viewMatrix.getSkewY() * (x - blob.fX) +
(...skipping 12 matching lines...) Expand all
321 blob.fTotalXError += SkScalarAbs(SkScalarFraction(transX)); 320 blob.fTotalXError += SkScalarAbs(SkScalarFraction(transX));
322 blob.fTotalYError += SkScalarAbs(SkScalarFraction(transY)); 321 blob.fTotalYError += SkScalarAbs(SkScalarFraction(transY));
323 if (blob.fTotalXError > kMinDiscernableTranslation || 322 if (blob.fTotalXError > kMinDiscernableTranslation ||
324 blob.fTotalYError > kMinDiscernableTranslation) { 323 blob.fTotalYError > kMinDiscernableTranslation) {
325 SkDebugf("Exceeding error threshold for bitmap text translation"); 324 SkDebugf("Exceeding error threshold for bitmap text translation");
326 } 325 }
327 #endif 326 #endif
328 (*outTransX) = transX; 327 (*outTransX) = transX;
329 (*outTransY) = transY; 328 (*outTransY) = transY;
330 } else { 329 } else {
331 // blob.hasDistanceField() 330 SkASSERT(blob.hasDistanceField());
332 // TODO figure out the regen formula 331 // A scale outside of [blob.fMaxMinScale, blob.fMinMaxScale] would resul t in a different
333 return true; 332 // distance field being generated, so we have to regenerate in those cas es
333 SkScalar newMaxScale = viewMatrix.getMaxScale();
334 SkScalar oldMaxScale = blob.fViewMatrix.getMaxScale();
335 SkScalar scaleAdjust = newMaxScale / oldMaxScale;
336 if (scaleAdjust < blob.fMaxMinScale || scaleAdjust > blob.fMinMaxScale) {
337 return true;
338 }
339
340 (*outTransX) = x - blob.fX;
341 (*outTransY) = y - blob.fY;
334 } 342 }
335 343
336 return false; 344 return false;
337 } 345 }
338 346
339 347
340 inline SkGlyphCache* GrAtlasTextContext::setupCache(BitmapTextBlob::Run* run, 348 inline SkGlyphCache* GrAtlasTextContext::setupCache(BitmapTextBlob::Run* run,
341 const SkPaint& skPaint, 349 const SkPaint& skPaint,
342 const SkMatrix* viewMatrix, 350 const SkMatrix* viewMatrix,
343 bool noGamma) { 351 bool noGamma) {
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
496 newRun.fVertexEndIndex = lastRun.fVertexEndIndex; 504 newRun.fVertexEndIndex = lastRun.fVertexEndIndex;
497 505
498 newRun.fGlyphStartIndex = lastRun.fGlyphEndIndex; 506 newRun.fGlyphStartIndex = lastRun.fGlyphEndIndex;
499 newRun.fGlyphEndIndex = lastRun.fGlyphEndIndex; 507 newRun.fGlyphEndIndex = lastRun.fGlyphEndIndex;
500 } 508 }
501 509
502 if (this->canDrawAsDistanceFields(runPaint, viewMatrix)) { 510 if (this->canDrawAsDistanceFields(runPaint, viewMatrix)) {
503 cacheBlob->setHasDistanceField(); 511 cacheBlob->setHasDistanceField();
504 SkPaint dfPaint = runPaint; 512 SkPaint dfPaint = runPaint;
505 SkScalar textRatio; 513 SkScalar textRatio;
506 this->initDistanceFieldPaint(&dfPaint, &textRatio, viewMatrix); 514 this->initDistanceFieldPaint(cacheBlob, &dfPaint, &textRatio, viewMa trix);
507 Run& runIdx = cacheBlob->fRuns[run]; 515 Run& runIdx = cacheBlob->fRuns[run];
508 PerSubRunInfo& subRun = runIdx.fSubRunInfo.back(); 516 PerSubRunInfo& subRun = runIdx.fSubRunInfo.back();
509 subRun.fUseLCDText = runPaint.isLCDRenderText(); 517 subRun.fUseLCDText = runPaint.isLCDRenderText();
510 subRun.fDrawAsDistanceFields = true; 518 subRun.fDrawAsDistanceFields = true;
511 519
512 SkGlyphCache* cache = this->setupCache(&cacheBlob->fRuns[run], dfPai nt, NULL, true); 520 SkGlyphCache* cache = this->setupCache(&cacheBlob->fRuns[run], dfPai nt, NULL, true);
513 521
514 SkTDArray<char> fallbackTxt; 522 SkTDArray<char> fallbackTxt;
515 SkTDArray<SkScalar> fallbackPos; 523 SkTDArray<SkScalar> fallbackPos;
516 SkPoint dfOffset; 524 SkPoint dfOffset;
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
574 SkGlyphCache::AttachCache(cache); 582 SkGlyphCache::AttachCache(cache);
575 } 583 }
576 584
577 if (drawFilter) { 585 if (drawFilter) {
578 // A draw filter may change the paint arbitrarily, so we must re-see d in this case. 586 // A draw filter may change the paint arbitrarily, so we must re-see d in this case.
579 runPaint = skPaint; 587 runPaint = skPaint;
580 } 588 }
581 } 589 }
582 } 590 }
583 591
584 inline void GrAtlasTextContext::initDistanceFieldPaint(SkPaint* skPaint, SkScala r* textRatio, 592 inline void GrAtlasTextContext::initDistanceFieldPaint(BitmapTextBlob* blob,
593 SkPaint* skPaint,
594 SkScalar* textRatio,
585 const SkMatrix& viewMatri x) { 595 const SkMatrix& viewMatri x) {
586 // getMaxScale doesn't support perspective, so neither do we at the moment 596 // getMaxScale doesn't support perspective, so neither do we at the moment
587 SkASSERT(!viewMatrix.hasPerspective()); 597 SkASSERT(!viewMatrix.hasPerspective());
588 SkScalar maxScale = viewMatrix.getMaxScale(); 598 SkScalar maxScale = viewMatrix.getMaxScale();
589 SkScalar textSize = skPaint->getTextSize(); 599 SkScalar textSize = skPaint->getTextSize();
590 SkScalar scaledTextSize = textSize; 600 SkScalar scaledTextSize = textSize;
591 // if we have non-unity scale, we need to choose our base text size 601 // 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 602 // 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)? 603 // TODO: do we need to do this if we're scaling down (i.e. maxScale < 1)?
594 if (maxScale > 0 && !SkScalarNearlyEqual(maxScale, SK_Scalar1)) { 604 if (maxScale > 0 && !SkScalarNearlyEqual(maxScale, SK_Scalar1)) {
595 scaledTextSize *= maxScale; 605 scaledTextSize *= maxScale;
596 } 606 }
597 607
608 // We have three sizes of distance field text, and within each size 'bucket' there is a floor
609 // and ceiling. A scale outside of this range would require regenerating th e distance fields
610 SkScalar dfMaskScaleFloor;
611 SkScalar dfMaskScaleCeil;
598 if (scaledTextSize <= kSmallDFFontLimit) { 612 if (scaledTextSize <= kSmallDFFontLimit) {
613 dfMaskScaleFloor = kMinDFFontSize;
614 dfMaskScaleCeil = kMediumDFFontLimit;
599 *textRatio = textSize / kSmallDFFontSize; 615 *textRatio = textSize / kSmallDFFontSize;
600 skPaint->setTextSize(SkIntToScalar(kSmallDFFontSize)); 616 skPaint->setTextSize(SkIntToScalar(kSmallDFFontSize));
601 } else if (scaledTextSize <= kMediumDFFontLimit) { 617 } else if (scaledTextSize <= kMediumDFFontLimit) {
618 dfMaskScaleFloor = kMediumDFFontLimit;
619 dfMaskScaleCeil = kLargeDFFontSize;
602 *textRatio = textSize / kMediumDFFontSize; 620 *textRatio = textSize / kMediumDFFontSize;
603 skPaint->setTextSize(SkIntToScalar(kMediumDFFontSize)); 621 skPaint->setTextSize(SkIntToScalar(kMediumDFFontSize));
604 } else { 622 } else {
623 dfMaskScaleFloor = kLargeDFFontSize;
624 dfMaskScaleCeil = 2 * kLargeDFFontSize;
605 *textRatio = textSize / kLargeDFFontSize; 625 *textRatio = textSize / kLargeDFFontSize;
606 skPaint->setTextSize(SkIntToScalar(kLargeDFFontSize)); 626 skPaint->setTextSize(SkIntToScalar(kLargeDFFontSize));
607 } 627 }
608 628
629 // Because there can be multiple runs in the blob, we want the overall maxMi nScale, and
630 // minMaxScale to make regeneration decisions. Specifically, we want the ma ximum minimum scale
631 // we can tolerate before we'd drop to a lower mip size, and the minimum max imum scale we can
632 // tolerate before we'd have to move to a large mip size. When we actually test these values
633 // we look at the delta in scale between the new viewmatrix and the old view matrix, and test
634 // against these values to decide if we can reuse or not(ie, will a given sc ale change our mip
635 // level)
636 blob->fMaxMinScale = SkMaxScalar(dfMaskScaleFloor / scaledTextSize, blob->fM axMinScale);
637 blob->fMinMaxScale = SkMinScalar(dfMaskScaleCeil / scaledTextSize, blob->fMi nMaxScale);
638
609 skPaint->setLCDRenderText(false); 639 skPaint->setLCDRenderText(false);
610 skPaint->setAutohinted(false); 640 skPaint->setAutohinted(false);
611 skPaint->setHinting(SkPaint::kNormal_Hinting); 641 skPaint->setHinting(SkPaint::kNormal_Hinting);
612 skPaint->setSubpixelText(true); 642 skPaint->setSubpixelText(true);
613 } 643 }
614 644
615 inline void GrAtlasTextContext::fallbackDrawPosText(BitmapTextBlob* blob, 645 inline void GrAtlasTextContext::fallbackDrawPosText(BitmapTextBlob* blob,
616 int runIndex, 646 int runIndex,
617 GrRenderTarget* rt, const Gr Clip& clip, 647 GrRenderTarget* rt, const Gr Clip& clip,
618 const GrPaint& paint, 648 const GrPaint& paint,
(...skipping 19 matching lines...) Expand all
638 SkGlyphCache::AttachCache(cache); 668 SkGlyphCache::AttachCache(cache);
639 } 669 }
640 670
641 inline GrAtlasTextContext::BitmapTextBlob* 671 inline GrAtlasTextContext::BitmapTextBlob*
642 GrAtlasTextContext::setupDFBlob(int glyphCount, const SkPaint& origPaint, 672 GrAtlasTextContext::setupDFBlob(int glyphCount, const SkPaint& origPaint,
643 const SkMatrix& viewMatrix, SkGlyphCache** cache , 673 const SkMatrix& viewMatrix, SkGlyphCache** cache ,
644 SkPaint* dfPaint, SkScalar* textRatio) { 674 SkPaint* dfPaint, SkScalar* textRatio) {
645 BitmapTextBlob* blob = fCache->createBlob(glyphCount, 1, kGrayTextVASize); 675 BitmapTextBlob* blob = fCache->createBlob(glyphCount, 1, kGrayTextVASize);
646 676
647 *dfPaint = origPaint; 677 *dfPaint = origPaint;
648 this->initDistanceFieldPaint(dfPaint, textRatio, viewMatrix); 678 this->initDistanceFieldPaint(blob, dfPaint, textRatio, viewMatrix);
649 blob->fViewMatrix = viewMatrix; 679 blob->fViewMatrix = viewMatrix;
650 Run& run = blob->fRuns[0]; 680 Run& run = blob->fRuns[0];
651 PerSubRunInfo& subRun = run.fSubRunInfo.back(); 681 PerSubRunInfo& subRun = run.fSubRunInfo.back();
652 subRun.fUseLCDText = origPaint.isLCDRenderText(); 682 subRun.fUseLCDText = origPaint.isLCDRenderText();
653 subRun.fDrawAsDistanceFields = true; 683 subRun.fDrawAsDistanceFields = true;
654 684
655 *cache = this->setupCache(&blob->fRuns[0], *dfPaint, NULL, true); 685 *cache = this->setupCache(&blob->fRuns[0], *dfPaint, NULL, true);
656 return blob; 686 return blob;
657 } 687 }
658 688
(...skipping 1458 matching lines...) Expand 10 before | Expand all | Expand 10 after
2117 pipelineBuilder.setFromPaint(grPaint, rt, clip); 2147 pipelineBuilder.setFromPaint(grPaint, rt, clip);
2118 2148
2119 GrColor color = grPaint.getColor(); 2149 GrColor color = grPaint.getColor();
2120 for (int run = 0; run < cacheBlob->fRunCount; run++) { 2150 for (int run = 0; run < cacheBlob->fRunCount; run++) {
2121 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, 0, 0, sk Paint); 2151 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, 0, 0, sk Paint);
2122 } 2152 }
2123 2153
2124 // Now flush big glyphs 2154 // Now flush big glyphs
2125 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, 0, 0); 2155 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, 0, 0);
2126 } 2156 }
OLDNEW
« no previous file with comments | « src/gpu/GrAtlasTextContext.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698