1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/gpu/effects/GrDistanceFieldTextureEffect.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,155 @@ 1.4 +/* 1.5 + * Copyright 2013 Google Inc. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#include "GrDistanceFieldTextureEffect.h" 1.12 +#include "gl/GrGLEffect.h" 1.13 +#include "gl/GrGLSL.h" 1.14 +#include "gl/GrGLTexture.h" 1.15 +#include "gl/GrGLVertexEffect.h" 1.16 +#include "GrTBackendEffectFactory.h" 1.17 +#include "GrTexture.h" 1.18 + 1.19 +// The distance field is constructed as unsigned char values, so that the zero value is at 128, 1.20 +// and the range is [-4, 4 - 1/255). Hence our multiplier is 8 - 1/32 and zero threshold is 128/255. 1.21 +#define MULTIPLIER "7.96875" 1.22 +#define THRESHOLD "0.50196078431" 1.23 + 1.24 +class GrGLDistanceFieldTextureEffect : public GrGLVertexEffect { 1.25 +public: 1.26 + GrGLDistanceFieldTextureEffect(const GrBackendEffectFactory& factory, 1.27 + const GrDrawEffect& drawEffect) 1.28 + : INHERITED (factory) 1.29 + , fTextureSize(SkSize::Make(-1.f,-1.f)) {} 1.30 + 1.31 + virtual void emitCode(GrGLFullShaderBuilder* builder, 1.32 + const GrDrawEffect& drawEffect, 1.33 + EffectKey key, 1.34 + const char* outputColor, 1.35 + const char* inputColor, 1.36 + const TransformedCoordsArray&, 1.37 + const TextureSamplerArray& samplers) SK_OVERRIDE { 1.38 + SkASSERT(1 == drawEffect.castEffect<GrDistanceFieldTextureEffect>().numVertexAttribs()); 1.39 + 1.40 + SkAssertResult(builder->enableFeature(GrGLShaderBuilder::kStandardDerivatives_GLSLFeature)); 1.41 + 1.42 + SkString fsCoordName; 1.43 + const char* vsCoordName; 1.44 + const char* fsCoordNamePtr; 1.45 + builder->addVarying(kVec2f_GrSLType, "textureCoords", &vsCoordName, &fsCoordNamePtr); 1.46 + fsCoordName = fsCoordNamePtr; 1.47 + 1.48 + const char* attrName0 = 1.49 + builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0])->c_str(); 1.50 + builder->vsCodeAppendf("\t%s = %s;\n", vsCoordName, attrName0); 1.51 + 1.52 + const char* textureSizeUniName = NULL; 1.53 + fTextureSizeUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, 1.54 + kVec2f_GrSLType, "TextureSize", 1.55 + &textureSizeUniName); 1.56 + 1.57 + builder->fsCodeAppend("\tvec4 texColor = "); 1.58 + builder->fsAppendTextureLookup(samplers[0], 1.59 + fsCoordName.c_str(), 1.60 + kVec2f_GrSLType); 1.61 + builder->fsCodeAppend(";\n"); 1.62 + builder->fsCodeAppend("\tfloat distance = " MULTIPLIER "*(texColor.r - " THRESHOLD ");\n"); 1.63 + 1.64 + // we adjust for the effect of the transformation on the distance by using 1.65 + // the length of the gradient of the texture coordinates. We use st coordinates 1.66 + // to ensure we're mapping 1:1 from texel space to pixel space. 1.67 + builder->fsCodeAppendf("\tvec2 st = %s*%s;\n", fsCoordName.c_str(), textureSizeUniName); 1.68 + builder->fsCodeAppend("\tvec2 Jdx = dFdx(st);\n"); 1.69 + builder->fsCodeAppend("\tvec2 Jdy = dFdy(st);\n"); 1.70 + builder->fsCodeAppend("\tvec2 st_grad = normalize(st);\n"); 1.71 + builder->fsCodeAppend("\tvec2 grad = vec2(st_grad.x*Jdx.x + st_grad.y*Jdy.x,\n"); 1.72 + builder->fsCodeAppend("\t st_grad.x*Jdx.y + st_grad.y*Jdy.y);\n"); 1.73 + 1.74 + // this gives us a smooth step across approximately one fragment 1.75 + // (assuming a radius of the diagonal of the fragment, hence a factor of sqrt(2)/2) 1.76 + builder->fsCodeAppend("\tfloat afwidth = 0.7071*length(grad);\n"); 1.77 + builder->fsCodeAppend("\tfloat val = smoothstep(-afwidth, afwidth, distance);\n"); 1.78 + 1.79 + builder->fsCodeAppendf("\t%s = %s;\n", outputColor, 1.80 + (GrGLSLExpr4(inputColor) * GrGLSLExpr1("val")).c_str()); 1.81 + } 1.82 + 1.83 + virtual void setData(const GrGLUniformManager& uman, 1.84 + const GrDrawEffect& drawEffect) SK_OVERRIDE { 1.85 + SkASSERT(fTextureSizeUni.isValid()); 1.86 + const GrDistanceFieldTextureEffect& distanceFieldEffect = 1.87 + drawEffect.castEffect<GrDistanceFieldTextureEffect>(); 1.88 + if (distanceFieldEffect.getSize().width() != fTextureSize.width() || 1.89 + distanceFieldEffect.getSize().height() != fTextureSize.height()) { 1.90 + fTextureSize = distanceFieldEffect.getSize(); 1.91 + uman.set2f(fTextureSizeUni, 1.92 + distanceFieldEffect.getSize().width(), 1.93 + distanceFieldEffect.getSize().height()); 1.94 + } 1.95 + } 1.96 + 1.97 +private: 1.98 + GrGLUniformManager::UniformHandle fTextureSizeUni; 1.99 + SkSize fTextureSize; 1.100 + 1.101 + typedef GrGLVertexEffect INHERITED; 1.102 +}; 1.103 + 1.104 +/////////////////////////////////////////////////////////////////////////////// 1.105 + 1.106 +GrDistanceFieldTextureEffect::GrDistanceFieldTextureEffect(GrTexture* texture, 1.107 + const GrTextureParams& params, 1.108 + const SkISize& size) 1.109 + : fTextureAccess(texture, params) 1.110 + , fSize(SkSize::Make(SkIntToScalar(size.width()), SkIntToScalar(size.height()))) { 1.111 + this->addTextureAccess(&fTextureAccess); 1.112 + this->addVertexAttrib(kVec2f_GrSLType); 1.113 +} 1.114 + 1.115 +bool GrDistanceFieldTextureEffect::onIsEqual(const GrEffect& other) const { 1.116 + const GrDistanceFieldTextureEffect& cte = CastEffect<GrDistanceFieldTextureEffect>(other); 1.117 + return fTextureAccess == cte.fTextureAccess; 1.118 +} 1.119 + 1.120 +void GrDistanceFieldTextureEffect::getConstantColorComponents(GrColor* color, 1.121 + uint32_t* validFlags) const { 1.122 + if ((*validFlags & kA_GrColorComponentFlag) && 0xFF == GrColorUnpackA(*color) && 1.123 + GrPixelConfigIsOpaque(this->texture(0)->config())) { 1.124 + *validFlags = kA_GrColorComponentFlag; 1.125 + } else { 1.126 + *validFlags = 0; 1.127 + } 1.128 +} 1.129 + 1.130 +const GrBackendEffectFactory& GrDistanceFieldTextureEffect::getFactory() const { 1.131 + return GrTBackendEffectFactory<GrDistanceFieldTextureEffect>::getInstance(); 1.132 +} 1.133 + 1.134 +/////////////////////////////////////////////////////////////////////////////// 1.135 + 1.136 +GR_DEFINE_EFFECT_TEST(GrDistanceFieldTextureEffect); 1.137 + 1.138 +GrEffectRef* GrDistanceFieldTextureEffect::TestCreate(SkRandom* random, 1.139 + GrContext*, 1.140 + const GrDrawTargetCaps&, 1.141 + GrTexture* textures[]) { 1.142 + int texIdx = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx : 1.143 + GrEffectUnitTest::kAlphaTextureIdx; 1.144 + static const SkShader::TileMode kTileModes[] = { 1.145 + SkShader::kClamp_TileMode, 1.146 + SkShader::kRepeat_TileMode, 1.147 + SkShader::kMirror_TileMode, 1.148 + }; 1.149 + SkShader::TileMode tileModes[] = { 1.150 + kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))], 1.151 + kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))], 1.152 + }; 1.153 + GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode : 1.154 + GrTextureParams::kNone_FilterMode); 1.155 + SkISize size = SkISize::Make(1024, 2048); 1.156 + 1.157 + return GrDistanceFieldTextureEffect::Create(textures[texIdx], params, size); 1.158 +}