aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Jim Van Verth <jvanverth@google.com>2016-12-07 10:40:09 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2016-12-07 16:48:35 +0000
commit92964124c5ff61729357a51dc212ca5938093e89 (patch)
treee4e4dac59f38efcc87c1e9dfbeb0e68d914efc70 /src
parentd7e16661bb36924b2c8f717c527b876dabb595f3 (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.cpp86
-rw-r--r--src/gpu/batches/GrAADistanceFieldPathRenderer.h4
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) {