aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar jvanverth <jvanverth@google.com>2015-04-06 11:38:52 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-04-06 11:38:52 -0700
commit5b143038cb47763974d2750ed78d436eb6c38bea (patch)
tree512a1937181862a2151ed2da8762bdf5e6258a70
parent9a27e639481882b59a8ef123e0b69a9a719f08b9 (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-xsrc/gpu/GrDistanceFieldTextContext.cpp39
-rwxr-xr-xsrc/gpu/effects/GrDistanceFieldTextureEffect.cpp123
-rw-r--r--src/gpu/effects/GrDistanceFieldTextureEffect.h34
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;