aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu
diff options
context:
space:
mode:
authorGravatar jvanverth <jvanverth@google.com>2016-03-10 11:10:43 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2016-03-10 11:10:43 -0800
commitcf371bb41b4a0591347a076ce7d83336d4bbc6fb (patch)
treecd0e34686433786ab2a759ddf619f86faa718931 /src/gpu
parent4ba051cbcfbd379714250b1fe463c1610e7df04c (diff)
Use correct gradient calculation for rotated distance fields.
For all uniform scaled matrices, we were using the y coordinate of the y-direction gradient of the v texel space coordinate to scale the distance values. The problem is, if you rotate by 90 degrees this value becomes 0. The correct answer is to take the length of the y-direction gradient. BUG=skia:4864 GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1776383002 Review URL: https://codereview.chromium.org/1776383002
Diffstat (limited to 'src/gpu')
-rw-r--r--src/gpu/batches/GrAADistanceFieldPathRenderer.cpp4
-rw-r--r--src/gpu/batches/GrAtlasTextBatch.cpp2
-rw-r--r--src/gpu/effects/GrDistanceFieldGeoProc.cpp95
-rw-r--r--src/gpu/effects/GrDistanceFieldGeoProc.h9
4 files changed, 81 insertions, 29 deletions
diff --git a/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp b/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp
index 8525eb2fde..b585de963a 100644
--- a/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp
+++ b/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp
@@ -190,8 +190,10 @@ private:
return;
}
+ const SkMatrix& ctm = this->viewMatrix();
uint32_t flags = 0;
- flags |= this->viewMatrix().isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
+ flags |= ctm.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
+ flags |= ctm.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_FilterMode);
diff --git a/src/gpu/batches/GrAtlasTextBatch.cpp b/src/gpu/batches/GrAtlasTextBatch.cpp
index 432322ff7a..1d8d7fe143 100644
--- a/src/gpu/batches/GrAtlasTextBatch.cpp
+++ b/src/gpu/batches/GrAtlasTextBatch.cpp
@@ -261,11 +261,11 @@ GrGeometryProcessor* GrAtlasTextBatch::setupDfProcessor(const SkMatrix& viewMatr
bool isLCD = this->isLCD();
// set up any flags
uint32_t flags = viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
+ flags |= viewMatrix.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
// see if we need to create a new effect
if (isLCD) {
flags |= kUseLCD_DistanceFieldEffectFlag;
- flags |= viewMatrix.rectStaysRect() ? kRectToRect_DistanceFieldEffectFlag : 0;
flags |= fUseBGR ? kBGR_DistanceFieldEffectFlag : 0;
GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor);
diff --git a/src/gpu/effects/GrDistanceFieldGeoProc.cpp b/src/gpu/effects/GrDistanceFieldGeoProc.cpp
index b77a1f5a5d..2182a11758 100644
--- a/src/gpu/effects/GrDistanceFieldGeoProc.cpp
+++ b/src/gpu/effects/GrDistanceFieldGeoProc.cpp
@@ -79,11 +79,13 @@ public:
// add varyings
GrGLSLVertToFrag recipScale(kFloat_GrSLType);
GrGLSLVertToFrag uv(kVec2f_GrSLType);
+ bool isUniformScale = (dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask) ==
+ kUniformScale_DistanceFieldEffectMask;
bool isSimilarity = SkToBool(dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag);
varyingHandler->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision);
vertBuilder->codeAppendf("%s = %s;", uv.vsOut(), dfTexEffect.inTextureCoords()->fName);
- // compute numbers to be hardcoded to convert texture coordinates from int to float
+ // compute numbers to be hardcoded to convert texture coordinates from float to int
SkASSERT(dfTexEffect.numTextures() == 1);
GrTexture* atlas = dfTexEffect.textureAccess(0).getTexture();
SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height()));
@@ -112,15 +114,24 @@ public:
#endif
fragBuilder->codeAppend("float afwidth;");
- if (isSimilarity) {
+ if (isUniformScale) {
// For uniform scale, we adjust for the effect of the transformation on the distance
- // by using the length of the gradient of the texture coordinates. We use st coordinates
- // to ensure we're mapping 1:1 from texel space to pixel space.
+ // by using the length of the gradient of the t coordinate in the y direction.
+ // We use st coordinates to ensure we're mapping 1:1 from texel space to pixel space.
+ // We use the y gradient because there is a bug in the Mali 400 in the x direction.
// this gives us a smooth step across approximately one fragment
- // we use y to work around a Mali400 bug in the x direction
fragBuilder->codeAppendf("afwidth = abs(" SK_DistanceFieldAAFactor "*dFdy(%s.y));",
st.fsIn());
+ } else if (isSimilarity) {
+ // For similarity transform, we adjust the effect of the transformation on the distance
+ // by using the length of the gradient of the texture coordinates. We use st coordinates
+ // to ensure we're mapping 1:1 from texel space to pixel space.
+ // We use the y gradient because there is a bug in the Mali 400 in the x direction.
+
+ // this gives us a smooth step across approximately one fragment
+ fragBuilder->codeAppendf("float st_grad_len = length(dFdy(%s));", st.fsIn());
+ fragBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*st_grad_len);");
} else {
// For general transforms, to determine the amount of correction we multiply a unit
// vector pointing along the SDF gradient direction by the Jacobian of the st coords
@@ -254,15 +265,20 @@ const GrGeometryProcessor* GrDistanceFieldA8TextGeoProc::TestCreate(GrProcessorT
GrTextureParams params(tileModes, d->fRandom->nextBool() ? GrTextureParams::kBilerp_FilterMode :
GrTextureParams::kNone_FilterMode);
+ uint32_t flags = 0;
+ flags |= d->fRandom->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0;
+ if (flags & kSimilarity_DistanceFieldEffectFlag) {
+ flags |= d->fRandom->nextBool() ? kScaleOnly_DistanceFieldEffectFlag : 0;
+ }
+
return GrDistanceFieldA8TextGeoProc::Create(GrRandomColor(d->fRandom),
GrTest::TestMatrix(d->fRandom),
d->fTextures[texIdx], params,
#ifdef SK_GAMMA_APPLY_TO_A8
d->fRandom->nextF(),
#endif
- d->fRandom->nextBool() ?
- kSimilarity_DistanceFieldEffectFlag : 0,
- d->fRandom->nextBool());
+ flags,
+ d->fRandom->nextBool());
}
///////////////////////////////////////////////////////////////////////////////
@@ -335,13 +351,27 @@ public:
kHigh_GrSLPrecision));
fragBuilder->codeAppendf("vec2 st = uv*%s;", textureSizeUniName);
fragBuilder->codeAppend("float afwidth;");
- if (dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag) {
+ bool isUniformScale = (dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask) ==
+ kUniformScale_DistanceFieldEffectMask;
+ bool isSimilarity = SkToBool(dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag);
+ if (isUniformScale) {
// For uniform scale, we adjust for the effect of the transformation on the distance
+ // by using the length of the gradient of the t coordinate in the y direction.
+ // We use st coordinates to ensure we're mapping 1:1 from texel space to pixel space.
+ // We use the y gradient because there is a bug in the Mali 400 in the x direction.
+
+ // this gives us a smooth step across approximately one fragment
+ fragBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*dFdy(st.y));");
+
+ } else if (isSimilarity) {
+ // For similarity transform, we adjust the effect of the transformation on the distance
// by using the length of the gradient of the texture coordinates. We use st coordinates
// to ensure we're mapping 1:1 from texel space to pixel space.
+ // We use the y gradient because there is a bug in the Mali 400 in the x direction.
// this gives us a smooth step across approximately one fragment
- fragBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*dFdy(st.y));");
+ fragBuilder->codeAppend("float st_grad_len = length(dFdy(st));");
+ fragBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*st_grad_len);");
} else {
// For general transforms, to determine the amount of correction we multiply a unit
// vector pointing along the SDF gradient direction by the Jacobian of the st coords
@@ -464,13 +494,18 @@ const GrGeometryProcessor* GrDistanceFieldPathGeoProc::TestCreate(GrProcessorTes
GrTextureParams params(tileModes, d->fRandom->nextBool() ? GrTextureParams::kBilerp_FilterMode
: GrTextureParams::kNone_FilterMode);
+ uint32_t flags = 0;
+ flags |= d->fRandom->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0;
+ if (flags & kSimilarity_DistanceFieldEffectFlag) {
+ flags |= d->fRandom->nextBool() ? kScaleOnly_DistanceFieldEffectFlag : 0;
+ }
+
return GrDistanceFieldPathGeoProc::Create(GrRandomColor(d->fRandom),
GrTest::TestMatrix(d->fRandom),
d->fTextures[texIdx],
params,
- d->fRandom->nextBool() ?
- kSimilarity_DistanceFieldEffectFlag : 0,
- d->fRandom->nextBool());
+ flags,
+ d->fRandom->nextBool());
}
///////////////////////////////////////////////////////////////////////////////
@@ -518,13 +553,15 @@ public:
args.fTransformsOut);
// set up varyings
- bool isUniformScale = SkToBool(dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask);
+ bool isUniformScale = (dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask) ==
+ kUniformScale_DistanceFieldEffectMask;
+ bool isSimilarity = SkToBool(dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag);
GrGLSLVertToFrag recipScale(kFloat_GrSLType);
GrGLSLVertToFrag uv(kVec2f_GrSLType);
varyingHandler->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision);
vertBuilder->codeAppendf("%s = %s;", uv.vsOut(), dfTexEffect.inTextureCoords()->fName);
- // compute numbers to be hardcoded to convert texture coordinates from int to float
+ // compute numbers to be hardcoded to convert texture coordinates from float to int
SkASSERT(dfTexEffect.numTextures() == 1);
GrTexture* atlas = dfTexEffect.textureAccess(0).getTexture();
SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height()));
@@ -555,8 +592,16 @@ public:
fragBuilder->codeAppendf("float delta = %.*f;\n", SK_FLT_DECIMAL_DIG, lcdDelta);
}
if (isUniformScale) {
- fragBuilder->codeAppendf("float dy = abs(dFdy(%s.y));", st.fsIn());
- fragBuilder->codeAppend("vec2 offset = vec2(dy*delta, 0.0);");
+ fragBuilder->codeAppendf("float st_grad_len = abs(dFdy(%s.y));", st.fsIn());
+ fragBuilder->codeAppend("vec2 offset = vec2(st_grad_len*delta, 0.0);");
+ } else if (isSimilarity) {
+ // For a similarity matrix with rotation, the gradient will not be aligned
+ // with the texel coordinate axes, so we need to calculate it.
+ // We use dFdy because of a Mali 400 bug, and rotate -90 degrees to
+ // get the gradient in the x direction.
+ fragBuilder->codeAppendf("vec2 st_grad = dFdy(%s);", st.fsIn());
+ fragBuilder->codeAppend("float st_grad_len = length(st_grad);");
+ fragBuilder->codeAppend("vec2 offset = delta*vec2(st_grad.y, -st_grad.x);");
} else {
fragBuilder->codeAppendf("vec2 st = %s;\n", st.fsIn());
@@ -599,13 +644,14 @@ public:
// transformations, and even then using a single factor seems like a reasonable
// trade-off between quality and speed.
fragBuilder->codeAppend("float afwidth;");
- if (isUniformScale) {
- // For uniform scale, we adjust for the effect of the transformation on the distance
- // by using the length of the gradient of the texture coordinates. We use st coordinates
- // to ensure we're mapping 1:1 from texel space to pixel space.
+ if (isSimilarity) {
+ // For similarity transform (uniform scale-only is a subset of this), we adjust for the
+ // effect of the transformation on the distance by using the length of the gradient of
+ // the texture coordinates. We use st coordinates to ensure we're mapping 1:1 from texel
+ // space to pixel space.
// this gives us a smooth step across approximately one fragment
- fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*dy;");
+ fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*st_grad_len;");
} else {
// For general transforms, to determine the amount of correction we multiply a unit
// vector pointing along the SDF gradient direction by the Jacobian of the st coords
@@ -737,7 +783,10 @@ const GrGeometryProcessor* GrDistanceFieldLCDTextGeoProc::TestCreate(GrProcessor
GrTextureParams::kNone_FilterMode);
DistanceAdjust wa = { 0.0f, 0.1f, -0.1f };
uint32_t flags = kUseLCD_DistanceFieldEffectFlag;
- flags |= d->fRandom->nextBool() ? kUniformScale_DistanceFieldEffectMask : 0;
+ flags |= d->fRandom->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0;
+ if (flags & kSimilarity_DistanceFieldEffectFlag) {
+ flags |= d->fRandom->nextBool() ? kScaleOnly_DistanceFieldEffectFlag : 0;
+ }
flags |= d->fRandom->nextBool() ? kBGR_DistanceFieldEffectFlag : 0;
return GrDistanceFieldLCDTextGeoProc::Create(GrRandomColor(d->fRandom),
GrTest::TestMatrix(d->fRandom),
diff --git a/src/gpu/effects/GrDistanceFieldGeoProc.h b/src/gpu/effects/GrDistanceFieldGeoProc.h
index 46d39f0123..765a531c94 100644
--- a/src/gpu/effects/GrDistanceFieldGeoProc.h
+++ b/src/gpu/effects/GrDistanceFieldGeoProc.h
@@ -18,7 +18,7 @@ class GrInvariantOutput;
enum GrDistanceFieldEffectFlags {
kSimilarity_DistanceFieldEffectFlag = 0x01, // ctm is similarity matrix
- kRectToRect_DistanceFieldEffectFlag = 0x02, // ctm maps rects to rects
+ kScaleOnly_DistanceFieldEffectFlag = 0x02, // ctm has only scale and translate
kUseLCD_DistanceFieldEffectFlag = 0x04, // use lcd text
kBGR_DistanceFieldEffectFlag = 0x08, // lcd display has bgr order
kPortrait_DistanceFieldEffectFlag = 0x10, // lcd display is in portrait mode (not used yet)
@@ -26,12 +26,13 @@ enum GrDistanceFieldEffectFlags {
kInvalid_DistanceFieldEffectFlag = 0x80, // invalid state (for initialization)
kUniformScale_DistanceFieldEffectMask = kSimilarity_DistanceFieldEffectFlag |
- kRectToRect_DistanceFieldEffectFlag,
+ kScaleOnly_DistanceFieldEffectFlag,
// The subset of the flags relevant to GrDistanceFieldA8TextGeoProc
- kNonLCD_DistanceFieldEffectMask = kSimilarity_DistanceFieldEffectFlag,
+ kNonLCD_DistanceFieldEffectMask = kSimilarity_DistanceFieldEffectFlag |
+ kScaleOnly_DistanceFieldEffectFlag,
// The subset of the flags relevant to GrDistanceFieldLCDTextGeoProc
kLCD_DistanceFieldEffectMask = kSimilarity_DistanceFieldEffectFlag |
- kRectToRect_DistanceFieldEffectFlag |
+ kScaleOnly_DistanceFieldEffectFlag |
kUseLCD_DistanceFieldEffectFlag |
kBGR_DistanceFieldEffectFlag,
};