From 6c89c34614573797ce63e429229b6f7848df0bb7 Mon Sep 17 00:00:00 2001 From: "commit-bot@chromium.org" Date: Fri, 14 Feb 2014 21:48:29 +0000 Subject: Improved distance field sampling There are two different fixes here. First, it computes the distance value properly within the shader. Second, it handles anti-aliasing properly by doing a correction based on the gradient of the texture coordinates. R=bsalomon@google.com, reed@google.com Author: jvanverth@google.com Review URL: https://codereview.chromium.org/149853002 git-svn-id: http://skia.googlecode.com/svn/trunk@13461 2bbb7eff-a529-9590-31e7-b0007b416f81 --- src/gpu/effects/GrDistanceFieldTextureEffect.cpp | 72 ++++++++++++++++++------ src/gpu/effects/GrDistanceFieldTextureEffect.h | 11 ++-- 2 files changed, 62 insertions(+), 21 deletions(-) (limited to 'src/gpu/effects') diff --git a/src/gpu/effects/GrDistanceFieldTextureEffect.cpp b/src/gpu/effects/GrDistanceFieldTextureEffect.cpp index 8c38f9bebf..88a36fdc8d 100755 --- a/src/gpu/effects/GrDistanceFieldTextureEffect.cpp +++ b/src/gpu/effects/GrDistanceFieldTextureEffect.cpp @@ -13,14 +13,17 @@ #include "GrTBackendEffectFactory.h" #include "GrTexture.h" -// The distance field is constructed as unsigned char values, so that the zero value is at 128. -// Hence our zero threshold is 128/255. +// The distance field is constructed as unsigned char values, so that the zero value is at 128, +// and the range is [-4, 4 - 1/255). Hence our multiplier is 8 - 1/32 and zero threshold is 128/255. +#define MULTIPLIER "7.96875" #define THRESHOLD "0.50196078431" class GrGLDistanceFieldTextureEffect : public GrGLVertexEffect { public: - GrGLDistanceFieldTextureEffect(const GrBackendEffectFactory& factory, const GrDrawEffect& drawEffect) - : INHERITED (factory) {} + GrGLDistanceFieldTextureEffect(const GrBackendEffectFactory& factory, + const GrDrawEffect& drawEffect) + : INHERITED (factory) + , fTextureSize(SkSize::Make(-1.f,-1.f)) {} virtual void emitCode(GrGLFullShaderBuilder* builder, const GrDrawEffect& drawEffect, @@ -31,43 +34,77 @@ public: const TextureSamplerArray& samplers) SK_OVERRIDE { SkASSERT(1 == drawEffect.castEffect().numVertexAttribs()); + SkAssertResult(builder->enableFeature(GrGLShaderBuilder::kStandardDerivatives_GLSLFeature)); + SkString fsCoordName; - const char* vsVaryingName; - const char* fsVaryingNamePtr; - builder->addVarying(kVec2f_GrSLType, "textureCoords", &vsVaryingName, &fsVaryingNamePtr); - fsCoordName = fsVaryingNamePtr; + const char* vsCoordName; + const char* fsCoordNamePtr; + builder->addVarying(kVec2f_GrSLType, "textureCoords", &vsCoordName, &fsCoordNamePtr); + fsCoordName = fsCoordNamePtr; - const char* attrName = + const char* attrName0 = builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0])->c_str(); - builder->vsCodeAppendf("\t%s = %s;\n", vsVaryingName, attrName); + builder->vsCodeAppendf("\t%s = %s;\n", vsCoordName, attrName0); + + const char* textureSizeUniName = NULL; + fTextureSizeUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, + kVec2f_GrSLType, "TextureSize", + &textureSizeUniName); builder->fsCodeAppend("\tvec4 texColor = "); builder->fsAppendTextureLookup(samplers[0], fsCoordName.c_str(), kVec2f_GrSLType); builder->fsCodeAppend(";\n"); - builder->fsCodeAppend("\tfloat distance = texColor.r;\n"); + builder->fsCodeAppend("\tfloat distance = "MULTIPLIER"*(texColor.r - "THRESHOLD");\n"); + + // 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. + builder->fsCodeAppendf("\tvec2 st = %s*%s;\n", fsCoordName.c_str(), textureSizeUniName); + builder->fsCodeAppend("\tvec2 Jdx = dFdx(st);\n"); + builder->fsCodeAppend("\tvec2 Jdy = dFdy(st);\n"); + builder->fsCodeAppend("\tvec2 st_grad = normalize(st);\n"); + builder->fsCodeAppend("\tvec2 grad = vec2(st_grad.x*Jdx.x + st_grad.y*Jdy.x,\n"); + builder->fsCodeAppend("\t st_grad.x*Jdx.y + st_grad.y*Jdy.y);\n"); + // this gives us a smooth step across approximately one fragment // (assuming a radius of the diagonal of the fragment, hence a factor of sqrt(2)/2) - builder->fsCodeAppend("\tfloat afwidth = 0.7071*length(vec2(dFdx(distance), dFdy(distance)));\n"); - builder->fsCodeAppend("\tfloat val = smoothstep("THRESHOLD"-afwidth, "THRESHOLD"+afwidth, distance);\n"); + builder->fsCodeAppend("\tfloat afwidth = 0.7071*length(grad);\n"); + builder->fsCodeAppend("\tfloat val = smoothstep(-afwidth, afwidth, distance);\n"); builder->fsCodeAppendf("\t%s = %s;\n", outputColor, (GrGLSLExpr4(inputColor) * GrGLSLExpr1("val")).c_str()); } virtual void setData(const GrGLUniformManager& uman, - const GrDrawEffect& drawEffect) SK_OVERRIDE {} + const GrDrawEffect& drawEffect) SK_OVERRIDE { + SkASSERT(fTextureSizeUni.isValid()); + const GrDistanceFieldTextureEffect& distanceFieldEffect = + drawEffect.castEffect(); + if (distanceFieldEffect.getSize().width() != fTextureSize.width() || + distanceFieldEffect.getSize().height() != fTextureSize.height()) { + fTextureSize = distanceFieldEffect.getSize(); + uman.set2f(fTextureSizeUni, + distanceFieldEffect.getSize().width(), + distanceFieldEffect.getSize().height()); + } + } private: + GrGLUniformManager::UniformHandle fTextureSizeUni; + SkSize fTextureSize; + typedef GrGLVertexEffect INHERITED; }; /////////////////////////////////////////////////////////////////////////////// GrDistanceFieldTextureEffect::GrDistanceFieldTextureEffect(GrTexture* texture, - const GrTextureParams& params) - : fTextureAccess(texture, params) { + const GrTextureParams& params, + const SkISize& size) + : fTextureAccess(texture, params) + , fSize(SkSize::Make(SkIntToScalar(size.width()), SkIntToScalar(size.height()))) { this->addTextureAccess(&fTextureAccess); this->addVertexAttrib(kVec2f_GrSLType); } @@ -112,6 +149,7 @@ GrEffectRef* GrDistanceFieldTextureEffect::TestCreate(SkRandom* random, }; GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode : GrTextureParams::kNone_FilterMode); + SkISize size = SkISize::Make(1024, 2048); - return GrDistanceFieldTextureEffect::Create(textures[texIdx], params); + return GrDistanceFieldTextureEffect::Create(textures[texIdx], params, size); } diff --git a/src/gpu/effects/GrDistanceFieldTextureEffect.h b/src/gpu/effects/GrDistanceFieldTextureEffect.h index fc37ddb99a..e754bb200b 100755 --- a/src/gpu/effects/GrDistanceFieldTextureEffect.h +++ b/src/gpu/effects/GrDistanceFieldTextureEffect.h @@ -21,27 +21,30 @@ class GrGLDistanceFieldTextureEffect; */ class GrDistanceFieldTextureEffect : public GrVertexEffect { public: - static GrEffectRef* Create(GrTexture* tex, const GrTextureParams& p) { - AutoEffectUnref effect(SkNEW_ARGS(GrDistanceFieldTextureEffect, (tex, p))); + static GrEffectRef* Create(GrTexture* tex, const GrTextureParams& p, const SkISize& s) { + AutoEffectUnref effect(SkNEW_ARGS(GrDistanceFieldTextureEffect, (tex, p, s))); return CreateEffectRef(effect); } virtual ~GrDistanceFieldTextureEffect() {} - static const char* Name() { return "Texture"; } + static const char* Name() { return "DistanceFieldTexture"; } virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE; + const SkSize& getSize() const { return fSize; } typedef GrGLDistanceFieldTextureEffect GLEffect; virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; private: - GrDistanceFieldTextureEffect(GrTexture* texture, const GrTextureParams& params); + GrDistanceFieldTextureEffect(GrTexture* texture, const GrTextureParams& params, + const SkISize& textureSize); virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE; GrTextureAccess fTextureAccess; + SkSize fSize; GR_DECLARE_EFFECT_TEST; -- cgit v1.2.3