diff options
author | jvanverth <jvanverth@google.com> | 2015-04-06 11:38:52 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-04-06 11:38:52 -0700 |
commit | 5b143038cb47763974d2750ed78d436eb6c38bea (patch) | |
tree | 512a1937181862a2151ed2da8762bdf5e6258a70 | |
parent | 9a27e639481882b59a8ef123e0b69a9a719f08b9 (diff) |
Calculate inverse scale for distance field text in vertex shader
This is for the uniform scale case only. Using the dFdx() function on certain
Mali GPUs causes issues because the precision is too low, so we have to
compute 1/scale from the view matrix instead.
BUG=skia:3528
Review URL: https://codereview.chromium.org/1029423003
-rwxr-xr-x | src/gpu/GrDistanceFieldTextContext.cpp | 39 | ||||
-rwxr-xr-x | src/gpu/effects/GrDistanceFieldTextureEffect.cpp | 123 | ||||
-rw-r--r-- | src/gpu/effects/GrDistanceFieldTextureEffect.h | 34 |
3 files changed, 137 insertions, 59 deletions
diff --git a/src/gpu/GrDistanceFieldTextContext.cpp b/src/gpu/GrDistanceFieldTextContext.cpp index 1fe43200c2..66c97c7dc0 100755 --- a/src/gpu/GrDistanceFieldTextContext.cpp +++ b/src/gpu/GrDistanceFieldTextContext.cpp @@ -271,6 +271,12 @@ inline void GrDistanceFieldTextContext::init(GrRenderTarget* rt, const GrClip& c fSkPaint.setAutohinted(false); fSkPaint.setHinting(SkPaint::kNormal_Hinting); fSkPaint.setSubpixelText(true); + + // fix for skia:3528 + // if we're scaling up, include any scaling to match text size in the view matrix + if (fTextRatio > 1.0f) { + fViewMatrix.preScale(fTextRatio, fTextRatio); + } } void GrDistanceFieldTextContext::onDrawText(GrRenderTarget* rt, const GrClip& clip, @@ -483,13 +489,24 @@ void GrDistanceFieldTextContext::setupCoverageEffect(const SkColor& filteredColo kRectToRect_DistanceFieldEffectFlag : 0; bool useBGR = SkPixelGeometryIsBGR(fDeviceProperties.pixelGeometry()); flags |= fUseLCDText && useBGR ? kBGR_DistanceFieldEffectFlag : 0; - + + // fix for skia:3528 + // set the local matrix to correct any text size scaling for gradients et al. + SkMatrix localMatrix; + if (fTextRatio > 1.0f) { + localMatrix.setScale(fTextRatio, fTextRatio); + } else { + localMatrix.reset(); + } + // see if we need to create a new effect if (textureUniqueID != fEffectTextureUniqueID || filteredColor != fEffectColor || flags != fEffectFlags || - !fCachedGeometryProcessor->viewMatrix().cheapEqualTo(fViewMatrix)) { + !fCachedGeometryProcessor->viewMatrix().cheapEqualTo(fViewMatrix) || + !fCachedGeometryProcessor->localMatrix().cheapEqualTo(localMatrix)) { GrColor color = fPaint.getColor(); + if (fUseLCDText) { GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor); @@ -505,6 +522,7 @@ void GrDistanceFieldTextContext::setupCoverageEffect(const SkColor& filteredColo blueCorrection); fCachedGeometryProcessor.reset(GrDistanceFieldLCDTextureEffect::Create(color, fViewMatrix, + localMatrix, fCurrTexture, params, widthAdjust, @@ -518,6 +536,7 @@ void GrDistanceFieldTextContext::setupCoverageEffect(const SkColor& filteredColo float correction = fDistanceAdjustTable[lum >> kDistanceAdjustLumShift]; fCachedGeometryProcessor.reset(GrDistanceFieldTextureEffect::Create(color, fViewMatrix, + localMatrix, fCurrTexture, params, correction, @@ -526,6 +545,7 @@ void GrDistanceFieldTextContext::setupCoverageEffect(const SkColor& filteredColo #else fCachedGeometryProcessor.reset(GrDistanceFieldTextureEffect::Create(color, fViewMatrix, + localMatrix, fCurrTexture, params, flags, @@ -604,12 +624,18 @@ bool GrDistanceFieldTextContext::appendGlyph(GrGlyph::PackedID packed, SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2*SK_DistanceFieldInset); SkScalar scale = fTextRatio; - dx *= scale; - dy *= scale; + // if we're scaling up, using fix for skia:3528 + if (scale > 1.0f) { + sx /= scale; + sy /= scale; + } else { + dx *= scale; + dy *= scale; + width *= scale; + height *= scale; + } sx += dx; sy += dy; - width *= scale; - height *= scale; SkRect glyphRect = SkRect::MakeXYWH(sx, sy, width, height); // check if we clipped out @@ -643,7 +669,6 @@ bool GrDistanceFieldTextContext::appendGlyph(GrGlyph::PackedID packed, this->flush(); SkMatrix ctm; - ctm.setScale(fTextRatio, fTextRatio); ctm.postTranslate(sx - dx, sy - dy); SkPath tmpPath(*glyph->fPath); diff --git a/src/gpu/effects/GrDistanceFieldTextureEffect.cpp b/src/gpu/effects/GrDistanceFieldTextureEffect.cpp index d44c193260..13ca05271c 100755 --- a/src/gpu/effects/GrDistanceFieldTextureEffect.cpp +++ b/src/gpu/effects/GrDistanceFieldTextureEffect.cpp @@ -51,16 +51,6 @@ public: // emit attributes vsBuilder->emitAttributes(dfTexEffect); - GrGLVertToFrag st(kVec2f_GrSLType); - args.fPB->addVarying("IntTextureCoords", &st, kHigh_GrSLPrecision); - vsBuilder->codeAppendf("%s = %s;", st.vsOut(), dfTexEffect.inTextureCoords()->fName); - - GrGLVertToFrag uv(kVec2f_GrSLType); - args.fPB->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision); - // this is only used with text, so our texture bounds always match the glyph atlas - vsBuilder->codeAppendf("%s = vec2(" GR_FONT_ATLAS_A8_RECIP_WIDTH ", " - GR_FONT_ATLAS_RECIP_HEIGHT ")*%s;", uv.vsOut(), - dfTexEffect.inTextureCoords()->fName); #ifdef SK_GAMMA_APPLY_TO_A8 // adjust based on gamma const char* distanceAdjustUniName = NULL; @@ -78,9 +68,36 @@ public: this->setupPosition(pb, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix()); // emit transforms + const SkMatrix& localMatrix = dfTexEffect.localMatrix(); this->emitTransforms(args.fPB, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName, - dfTexEffect.localMatrix(), args.fTransformsIn, args.fTransformsOut); + localMatrix, args.fTransformsIn, args.fTransformsOut); + + // add varyings + GrGLVertToFrag recipScale(kFloat_GrSLType); + GrGLVertToFrag st(kVec2f_GrSLType); + bool isSimilarity = SkToBool(dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag); + const char* viewMatrixName = this->uViewM(); + // view matrix name is NULL if identity matrix + bool useInverseScale = !localMatrix.isIdentity() && viewMatrixName; + if (isSimilarity && useInverseScale) { + args.fPB->addVarying("RecipScale", &recipScale, kHigh_GrSLPrecision); + vsBuilder->codeAppendf("vec2 tx = vec2(%s[0][0], %s[1][0]);", + viewMatrixName, viewMatrixName); + vsBuilder->codeAppend("float tx2 = dot(tx, tx);"); + vsBuilder->codeAppendf("%s = inversesqrt(tx2);", recipScale.vsOut()); + } else { + args.fPB->addVarying("IntTextureCoords", &st, kHigh_GrSLPrecision); + vsBuilder->codeAppendf("%s = %s;", st.vsOut(), dfTexEffect.inTextureCoords()->fName); + } + GrGLVertToFrag uv(kVec2f_GrSLType); + args.fPB->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision); + // this is only used with text, so our texture bounds always match the glyph atlas + vsBuilder->codeAppendf("%s = vec2(" GR_FONT_ATLAS_A8_RECIP_WIDTH ", " + GR_FONT_ATLAS_RECIP_HEIGHT ")*%s;", uv.vsOut(), + dfTexEffect.inTextureCoords()->fName); + + // Use highp to work around aliasing issues fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision, pb->ctxInfo().standard())); @@ -100,16 +117,23 @@ public: fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision, pb->ctxInfo().standard())); - fsBuilder->codeAppendf("vec2 st = %s;", st.fsIn()); fsBuilder->codeAppend("float afwidth;"); - if (dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag) { + if (isSimilarity) { // For uniform scale, we adjust for the effect of the transformation on the distance + // either by using the inverse scale in the view matrix, or (if there is no view matrix) // 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. + // with the latter to ensure we're mapping 1:1 from texel space to pixel space. // this gives us a smooth step across approximately one fragment - fsBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*dFdx(st.x));"); + if (useInverseScale) { + fsBuilder->codeAppendf("afwidth = abs(" SK_DistanceFieldAAFactor "*%s);", + recipScale.fsIn()); + } else { + fsBuilder->codeAppendf("afwidth = abs(" SK_DistanceFieldAAFactor "*dFdx(%s.x));", + st.fsIn()); + } } else { + fsBuilder->codeAppendf("vec2 st = %s;", st.fsIn()); // 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 // (which is the inverse transform for this fragment) and take the length of the result. @@ -170,6 +194,7 @@ public: key |= local.fInputColorType << 16; key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x1 << 24: 0x0; key |= ComputePosKey(gp.viewMatrix()) << 25; + key |= (!gp.viewMatrix().isIdentity() && !gp.localMatrix().isIdentity()) ? 0x1 << 27 : 0x0; b->add32(key); } @@ -188,13 +213,14 @@ private: GrDistanceFieldTextureEffect::GrDistanceFieldTextureEffect(GrColor color, const SkMatrix& viewMatrix, + const SkMatrix& localMatrix, GrTexture* texture, const GrTextureParams& params, #ifdef SK_GAMMA_APPLY_TO_A8 float distanceAdjust, #endif uint32_t flags, bool opaqueVertexColors) - : INHERITED(color, viewMatrix, SkMatrix::I(), opaqueVertexColors) + : INHERITED(color, viewMatrix, localMatrix, opaqueVertexColors) , fTextureAccess(texture, params) #ifdef SK_GAMMA_APPLY_TO_A8 , fDistanceAdjust(distanceAdjust) @@ -281,6 +307,7 @@ GrGeometryProcessor* GrDistanceFieldTextureEffect::TestCreate(SkRandom* random, return GrDistanceFieldTextureEffect::Create(GrRandomColor(random), GrProcessorUnitTest::TestMatrix(random), + GrProcessorUnitTest::TestMatrix(random), textures[texIdx], params, #ifdef SK_GAMMA_APPLY_TO_A8 random->nextF(), @@ -564,17 +591,6 @@ public: // emit attributes vsBuilder->emitAttributes(dfTexEffect); - GrGLVertToFrag st(kVec2f_GrSLType); - args.fPB->addVarying("IntTextureCoords", &st, kHigh_GrSLPrecision); - vsBuilder->codeAppendf("%s = %s;", st.vsOut(), dfTexEffect.inTextureCoords()->fName); - - GrGLVertToFrag uv(kVec2f_GrSLType); - args.fPB->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision); - // this is only used with text, so our texture bounds always match the glyph atlas - vsBuilder->codeAppendf("%s = vec2(" GR_FONT_ATLAS_A8_RECIP_WIDTH ", " - GR_FONT_ATLAS_RECIP_HEIGHT ")*%s;", uv.vsOut(), - dfTexEffect.inTextureCoords()->fName); - // setup pass through color this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, NULL, &fColorUniform); @@ -583,9 +599,36 @@ public: this->setupPosition(pb, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix()); // emit transforms + const SkMatrix& localMatrix = dfTexEffect.localMatrix(); this->emitTransforms(args.fPB, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName, - dfTexEffect.localMatrix(), args.fTransformsIn, args.fTransformsOut); + localMatrix, args.fTransformsIn, args.fTransformsOut); + + // set up varyings + bool isUniformScale = SkToBool(dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask); + GrGLVertToFrag recipScale(kFloat_GrSLType); + GrGLVertToFrag st(kVec2f_GrSLType); + const char* viewMatrixName = this->uViewM(); + // view matrix name is NULL if identity matrix + bool useInverseScale = !localMatrix.isIdentity() && viewMatrixName; + if (isUniformScale && useInverseScale) { + args.fPB->addVarying("RecipScale", &recipScale, kHigh_GrSLPrecision); + vsBuilder->codeAppendf("vec2 tx = vec2(%s[0][0], %s[1][0]);", + viewMatrixName, viewMatrixName); + vsBuilder->codeAppend("float tx2 = dot(tx, tx);"); + vsBuilder->codeAppendf("%s = inversesqrt(tx2);", recipScale.vsOut()); + } else { + args.fPB->addVarying("IntTextureCoords", &st, kHigh_GrSLPrecision); + vsBuilder->codeAppendf("%s = %s;", st.vsOut(), dfTexEffect.inTextureCoords()->fName); + } + GrGLVertToFrag uv(kVec2f_GrSLType); + args.fPB->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision); + // this is only used with text, so our texture bounds always match the glyph atlas + vsBuilder->codeAppendf("%s = vec2(" GR_FONT_ATLAS_A8_RECIP_WIDTH ", " + GR_FONT_ATLAS_RECIP_HEIGHT ")*%s;", uv.vsOut(), + dfTexEffect.inTextureCoords()->fName); + + // add frag shader code GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); SkAssertResult(fsBuilder->enableFeature( @@ -598,21 +641,24 @@ public: fsBuilder->codeAppendf("vec2 uv = %s;\n", uv.fsIn()); fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision, pb->ctxInfo().standard())); - fsBuilder->codeAppendf("vec2 st = %s;\n", st.fsIn()); - bool isUniformScale = !!(dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask); - if (dfTexEffect.getFlags() & kBGR_DistanceFieldEffectFlag) { fsBuilder->codeAppend("float delta = -" GR_FONT_ATLAS_LCD_DELTA ";\n"); } else { fsBuilder->codeAppend("float delta = " GR_FONT_ATLAS_LCD_DELTA ";\n"); } if (isUniformScale) { - fsBuilder->codeAppend("\tfloat dx = dFdx(st.x);\n"); - fsBuilder->codeAppend("\tvec2 offset = vec2(dx*delta, 0.0);\n"); + if (useInverseScale) { + fsBuilder->codeAppendf("float dx = %s;", recipScale.fsIn()); + } else { + fsBuilder->codeAppendf("float dx = dFdx(%s.x);", st.fsIn()); + } + fsBuilder->codeAppend("vec2 offset = vec2(dx*delta, 0.0);"); } else { - fsBuilder->codeAppend("\tvec2 Jdx = dFdx(st);\n"); - fsBuilder->codeAppend("\tvec2 Jdy = dFdy(st);\n"); - fsBuilder->codeAppend("\tvec2 offset = delta*Jdx;\n"); + fsBuilder->codeAppendf("vec2 st = %s;\n", st.fsIn()); + + fsBuilder->codeAppend("vec2 Jdx = dFdx(st);"); + fsBuilder->codeAppend("vec2 Jdy = dFdy(st);"); + fsBuilder->codeAppend("vec2 offset = delta*Jdx;"); } // green is distance to uv center @@ -721,6 +767,7 @@ public: key |= local.fInputColorType << 16; key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x1 << 24: 0x0; key |= ComputePosKey(gp.viewMatrix()) << 25; + key |= (!gp.viewMatrix().isIdentity() && !gp.localMatrix().isIdentity()) ? 0x1 << 27 : 0x0; b->add32(key); } @@ -737,10 +784,11 @@ private: GrDistanceFieldLCDTextureEffect::GrDistanceFieldLCDTextureEffect( GrColor color, const SkMatrix& viewMatrix, + const SkMatrix& localMatrix, GrTexture* texture, const GrTextureParams& params, DistanceAdjust distanceAdjust, uint32_t flags) - : INHERITED(color, viewMatrix, SkMatrix::I()) + : INHERITED(color, viewMatrix, localMatrix) , fTextureAccess(texture, params) , fDistanceAdjust(distanceAdjust) , fFlags(flags & kLCD_DistanceFieldEffectMask){ @@ -821,6 +869,7 @@ GrGeometryProcessor* GrDistanceFieldLCDTextureEffect::TestCreate(SkRandom* rando flags |= random->nextBool() ? kBGR_DistanceFieldEffectFlag : 0; return GrDistanceFieldLCDTextureEffect::Create(GrRandomColor(random), GrProcessorUnitTest::TestMatrix(random), + GrProcessorUnitTest::TestMatrix(random), textures[texIdx], params, wa, flags); diff --git a/src/gpu/effects/GrDistanceFieldTextureEffect.h b/src/gpu/effects/GrDistanceFieldTextureEffect.h index 6be7f9eef3..58d1b77a59 100644 --- a/src/gpu/effects/GrDistanceFieldTextureEffect.h +++ b/src/gpu/effects/GrDistanceFieldTextureEffect.h @@ -47,18 +47,20 @@ enum GrDistanceFieldEffectFlags { class GrDistanceFieldTextureEffect : public GrGeometryProcessor { public: #ifdef SK_GAMMA_APPLY_TO_A8 - static GrGeometryProcessor* Create(GrColor color, const SkMatrix& viewMatrix, GrTexture* tex, - const GrTextureParams& params, + static GrGeometryProcessor* Create(GrColor color, const SkMatrix& viewMatrix, + const SkMatrix& localMatrix, + GrTexture* tex, const GrTextureParams& params, float lum, uint32_t flags, bool opaqueVertexColors) { - return SkNEW_ARGS(GrDistanceFieldTextureEffect, (color, viewMatrix, tex, params, lum, - flags, opaqueVertexColors)); + return SkNEW_ARGS(GrDistanceFieldTextureEffect, (color, viewMatrix, localMatrix, tex, + params, lum, flags, opaqueVertexColors)); } #else - static GrGeometryProcessor* Create(GrColor color, const SkMatrix& viewMatrix, GrTexture* tex, - const GrTextureParams& params, + static GrGeometryProcessor* Create(GrColor color, const SkMatrix& viewMatrix, + const SkMatrix& localMatrix, + GrTexture* tex, const GrTextureParams& params, uint32_t flags, bool opaqueVertexColors) { - return SkNEW_ARGS(GrDistanceFieldTextureEffect, (color, viewMatrix, tex, params, flags, - opaqueVertexColors)); + return SkNEW_ARGS(GrDistanceFieldTextureEffect, (color, viewMatrix, localMatrix, tex, + params, flags, opaqueVertexColors)); } #endif @@ -88,8 +90,8 @@ public: const GrBatchTracker&) const override; private: - GrDistanceFieldTextureEffect(GrColor, const SkMatrix& viewMatrix, GrTexture* texture, - const GrTextureParams& params, + GrDistanceFieldTextureEffect(GrColor, const SkMatrix& viewMatrix, const SkMatrix& localMatrix, + GrTexture* texture, const GrTextureParams& params, #ifdef SK_GAMMA_APPLY_TO_A8 float distanceAdjust, #endif @@ -194,11 +196,12 @@ public: } }; - static GrGeometryProcessor* Create(GrColor color, const SkMatrix& viewMatrix, GrTexture* tex, - const GrTextureParams& params, + static GrGeometryProcessor* Create(GrColor color, const SkMatrix& viewMatrix, + const SkMatrix& localMatrix, + GrTexture* tex, const GrTextureParams& params, DistanceAdjust distanceAdjust, uint32_t flags) { return SkNEW_ARGS(GrDistanceFieldLCDTextureEffect, - (color, viewMatrix, tex, params, distanceAdjust, flags)); + (color, viewMatrix, localMatrix, tex, params, distanceAdjust, flags)); } virtual ~GrDistanceFieldLCDTextureEffect() {} @@ -224,8 +227,9 @@ public: const GrBatchTracker&) const override; private: - GrDistanceFieldLCDTextureEffect(GrColor, const SkMatrix& viewMatrix, GrTexture* texture, - const GrTextureParams& params, + GrDistanceFieldLCDTextureEffect(GrColor, const SkMatrix& viewMatrix, + const SkMatrix& localMatrix, + GrTexture* texture, const GrTextureParams& params, DistanceAdjust wa, uint32_t flags); bool onIsEqual(const GrGeometryProcessor& other) const override; |