diff options
author | Jim Van Verth <jvanverth@google.com> | 2016-12-07 10:40:09 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2016-12-07 16:48:35 +0000 |
commit | 92964124c5ff61729357a51dc212ca5938093e89 (patch) | |
tree | e4e4dac59f38efcc87c1e9dfbeb0e68d914efc70 /src | |
parent | d7e16661bb36924b2c8f717c527b876dabb595f3 (diff) |
Fix SDF generation for pixel-aligned paths
BUG=668550
Change-Id: Ib496db82c7391aca61b31afaeb5445260170cc49
Reviewed-on: https://skia-review.googlesource.com/5549
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/gpu/batches/GrAADistanceFieldPathRenderer.cpp | 86 | ||||
-rw-r--r-- | src/gpu/batches/GrAADistanceFieldPathRenderer.h | 4 |
2 files changed, 46 insertions, 44 deletions
diff --git a/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp b/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp index b06c503041..e61b1cbd33 100644 --- a/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp +++ b/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp @@ -248,9 +248,16 @@ private: const SkRect& bounds = args.fShape.bounds(); SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); SkScalar size = maxScale * maxDim; - uint32_t desiredDimension; - if (size <= kSmallMIP) { + SkScalar desiredDimension; + // For minimizing (or the common case of identity) transforms, we try to + // create the DF at the appropriately sized native src-space path resolution. + // In the majority of cases this will yield a crisper rendering. + if (size <= maxDim && maxDim < kSmallMIP) { + desiredDimension = maxDim; + } else if (size <= kSmallMIP) { desiredDimension = kSmallMIP; + } else if (size <= maxDim) { + desiredDimension = maxDim; } else if (size <= kMediumMIP) { desiredDimension = kMediumMIP; } else { @@ -258,7 +265,7 @@ private: } // check to see if path is cached - ShapeData::Key key(args.fShape, desiredDimension); + ShapeData::Key key(args.fShape, SkScalarCeilToInt(desiredDimension)); ShapeData* shapeData = fShapeCache->find(key); if (nullptr == shapeData || !atlas->hasID(shapeData->fID)) { // Remove the stale cache entry @@ -268,6 +275,7 @@ private: delete shapeData; } SkScalar scale = desiredDimension/maxDim; + shapeData = new ShapeData; if (!this->addPathToAtlas(target, &flushInfo, @@ -275,7 +283,7 @@ private: shapeData, args.fShape, args.fAntiAlias, - desiredDimension, + SkScalarCeilToInt(desiredDimension), scale)) { delete shapeData; SkDebugf("Can't rasterize path\n"); @@ -311,29 +319,25 @@ private: scaledBounds.fTop *= scale; scaledBounds.fRight *= scale; scaledBounds.fBottom *= scale; - // move the origin to an integer boundary (gives better results) - SkScalar dx = SkScalarFraction(scaledBounds.fLeft); - SkScalar dy = SkScalarFraction(scaledBounds.fTop); + // subtract out integer portion of origin + // (SDF created will be placed with fractional offset burnt in) + SkScalar dx = SkScalarFloorToInt(scaledBounds.fLeft); + SkScalar dy = SkScalarFloorToInt(scaledBounds.fTop); scaledBounds.offset(-dx, -dy); // get integer boundary SkIRect devPathBounds; scaledBounds.roundOut(&devPathBounds); // pad to allow room for antialiasing const int intPad = SkScalarCeilToInt(kAntiAliasPad); - // pre-move origin (after outset, will be 0,0) - int width = devPathBounds.width(); - int height = devPathBounds.height(); - devPathBounds.fLeft = intPad; - devPathBounds.fTop = intPad; - devPathBounds.fRight = intPad + width; - devPathBounds.fBottom = intPad + height; - devPathBounds.outset(intPad, intPad); + // place devBounds at origin + int width = devPathBounds.width() + 2*intPad; + int height = devPathBounds.height() + 2*intPad; + devPathBounds = SkIRect::MakeWH(width, height); // draw path to bitmap SkMatrix drawMatrix; - drawMatrix.setTranslate(-bounds.left(), -bounds.top()); - drawMatrix.postScale(scale, scale); - drawMatrix.postTranslate(kAntiAliasPad, kAntiAliasPad); + drawMatrix.setScale(scale, scale); + drawMatrix.postTranslate(intPad - dx, intPad - dy); // setup bitmap backing SkASSERT(devPathBounds.fLeft == 0); @@ -378,7 +382,7 @@ private: // add to atlas SkIPoint16 atlasLocation; GrBatchAtlas::AtlasID id; - if (!atlas->addToAtlas(&id, target, width, height, dfStorage.get(), &atlasLocation)) { + if (!atlas->addToAtlas(&id, target, width, height, dfStorage.get(), &atlasLocation)) { this->flush(target, flushInfo); if (!atlas->addToAtlas(&id, target, width, height, dfStorage.get(), &atlasLocation)) { return false; @@ -387,22 +391,20 @@ private: // add to cache shapeData->fKey.set(shape, dimension); - shapeData->fScale = scale; shapeData->fID = id; - // change the scaled rect to match the size of the inset distance field - scaledBounds.fRight = scaledBounds.fLeft + - SkIntToScalar(devPathBounds.width() - 2*SK_DistanceFieldInset); - scaledBounds.fBottom = scaledBounds.fTop + - SkIntToScalar(devPathBounds.height() - 2*SK_DistanceFieldInset); - // shift the origin to the correct place relative to the distance field - // need to also restore the fractional translation - scaledBounds.offset(-SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPad + dx, - -SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPad + dy); - shapeData->fBounds = scaledBounds; - // origin we render from is inset from distance field edge - atlasLocation.fX += SK_DistanceFieldInset; - atlasLocation.fY += SK_DistanceFieldInset; - shapeData->fAtlasLocation = atlasLocation; + + // set the bounds rect to match the size and placement of the distance field in the atlas + shapeData->fBounds.setXYWH(atlasLocation.fX + SK_DistanceFieldPad, + atlasLocation.fY + SK_DistanceFieldPad, + width - 2*SK_DistanceFieldPad, + height - 2*SK_DistanceFieldPad); + // we also need to store the transformation from texture space to the original path's space + // which is a simple uniform scale and translate + shapeData->fScaleToDev = SkScalarInvert(scale); + dx -= SK_DistanceFieldPad + kAntiAliasPad; + dy -= SK_DistanceFieldPad + kAntiAliasPad; + shapeData->fTranslateToDev = SkPoint::Make((-atlasLocation.fX + dx)*shapeData->fScaleToDev, + (-atlasLocation.fY + dy)*shapeData->fScaleToDev); fShapeCache->add(shapeData); fShapeList->addToTail(shapeData); @@ -426,11 +428,14 @@ private: SkScalar width = shapeData->fBounds.width(); SkScalar height = shapeData->fBounds.height(); - SkScalar invScale = 1.0f / shapeData->fScale; + // transform texture bounds to the original path's space + SkScalar invScale = shapeData->fScaleToDev; dx *= invScale; dy *= invScale; width *= invScale; height *= invScale; + dx += shapeData->fTranslateToDev.fX; + dy += shapeData->fTranslateToDev.fY; SkPoint* positions = reinterpret_cast<SkPoint*>(offset); @@ -445,15 +450,12 @@ private: *colorPtr = color; } - const SkScalar tx = SkIntToScalar(shapeData->fAtlasLocation.fX); - const SkScalar ty = SkIntToScalar(shapeData->fAtlasLocation.fY); - // vertex texture coords SkPoint* textureCoords = (SkPoint*)(offset + sizeof(SkPoint) + sizeof(GrColor)); - textureCoords->setRectFan(tx / texture->width(), - ty / texture->height(), - (tx + shapeData->fBounds.width()) / texture->width(), - (ty + shapeData->fBounds.height()) / texture->height(), + textureCoords->setRectFan((shapeData->fBounds.fLeft) / texture->width(), + (shapeData->fBounds.fTop) / texture->height(), + (shapeData->fBounds.fRight)/texture->width(), + (shapeData->fBounds.fBottom)/texture->height(), vertexStride); } diff --git a/src/gpu/batches/GrAADistanceFieldPathRenderer.h b/src/gpu/batches/GrAADistanceFieldPathRenderer.h index 171108af91..7bb90229c4 100644 --- a/src/gpu/batches/GrAADistanceFieldPathRenderer.h +++ b/src/gpu/batches/GrAADistanceFieldPathRenderer.h @@ -70,10 +70,10 @@ private: SkAutoSTArray<24, uint32_t> fKey; }; Key fKey; - SkScalar fScale; GrBatchAtlas::AtlasID fID; SkRect fBounds; - SkIPoint16 fAtlasLocation; + SkScalar fScaleToDev; + SkPoint fTranslateToDev; SK_DECLARE_INTERNAL_LLIST_INTERFACE(ShapeData); static inline const Key& GetKey(const ShapeData& data) { |