diff options
author | 2016-03-10 11:10:43 -0800 | |
---|---|---|
committer | 2016-03-10 11:10:43 -0800 | |
commit | cf371bb41b4a0591347a076ce7d83336d4bbc6fb (patch) | |
tree | cd0e34686433786ab2a759ddf619f86faa718931 /src/gpu | |
parent | 4ba051cbcfbd379714250b1fe463c1610e7df04c (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.cpp | 4 | ||||
-rw-r--r-- | src/gpu/batches/GrAtlasTextBatch.cpp | 2 | ||||
-rw-r--r-- | src/gpu/effects/GrDistanceFieldGeoProc.cpp | 95 | ||||
-rw-r--r-- | src/gpu/effects/GrDistanceFieldGeoProc.h | 9 |
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, }; |