1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/gpu/effects/GrTextureDomain.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,280 @@ 1.4 +/* 1.5 + * Copyright 2012 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 "GrTextureDomain.h" 1.12 +#include "GrSimpleTextureEffect.h" 1.13 +#include "GrTBackendEffectFactory.h" 1.14 +#include "gl/GrGLEffect.h" 1.15 +#include "SkFloatingPoint.h" 1.16 + 1.17 + 1.18 +GrTextureDomain::GrTextureDomain(const SkRect& domain, Mode mode, int index) 1.19 + : fIndex(index) { 1.20 + 1.21 + static const SkRect kFullRect = {0, 0, SK_Scalar1, SK_Scalar1}; 1.22 + if (domain.contains(kFullRect)) { 1.23 + fMode = kIgnore_Mode; 1.24 + } else { 1.25 + fMode = mode; 1.26 + } 1.27 + 1.28 + if (fMode != kIgnore_Mode) { 1.29 + // We don't currently handle domains that are empty or don't intersect the texture. 1.30 + // It is OK if the domain rect is a line or point, but it should not be inverted. We do not 1.31 + // handle rects that do not intersect the [0..1]x[0..1] rect. 1.32 + SkASSERT(domain.fLeft <= domain.fRight); 1.33 + SkASSERT(domain.fTop <= domain.fBottom); 1.34 + fDomain.fLeft = SkMaxScalar(domain.fLeft, kFullRect.fLeft); 1.35 + fDomain.fRight = SkMinScalar(domain.fRight, kFullRect.fRight); 1.36 + fDomain.fTop = SkMaxScalar(domain.fTop, kFullRect.fTop); 1.37 + fDomain.fBottom = SkMinScalar(domain.fBottom, kFullRect.fBottom); 1.38 + SkASSERT(fDomain.fLeft <= fDomain.fRight); 1.39 + SkASSERT(fDomain.fTop <= fDomain.fBottom); 1.40 + } 1.41 +} 1.42 + 1.43 +////////////////////////////////////////////////////////////////////////////// 1.44 + 1.45 +void GrTextureDomain::GLDomain::sampleTexture(GrGLShaderBuilder* builder, 1.46 + const GrTextureDomain& textureDomain, 1.47 + const char* outColor, 1.48 + const SkString& inCoords, 1.49 + const GrGLEffect::TextureSampler sampler, 1.50 + const char* inModulateColor) { 1.51 + SkASSERT((Mode)-1 == fMode || textureDomain.mode() == fMode); 1.52 + SkDEBUGCODE(fMode = textureDomain.mode();) 1.53 + 1.54 + if (kIgnore_Mode == textureDomain.mode()) { 1.55 + builder->fsCodeAppendf("\t%s = ", outColor); 1.56 + builder->fsAppendTextureLookupAndModulate(inModulateColor, sampler, 1.57 + inCoords.c_str()); 1.58 + builder->fsCodeAppend(";\n"); 1.59 + return; 1.60 + } 1.61 + 1.62 + if (!fDomainUni.isValid()) { 1.63 + const char* name; 1.64 + SkString uniName("TexDom"); 1.65 + if (textureDomain.fIndex >= 0) { 1.66 + uniName.appendS32(textureDomain.fIndex); 1.67 + } 1.68 + fDomainUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, 1.69 + kVec4f_GrSLType, uniName.c_str(), &name); 1.70 + fDomainName = name; 1.71 + } 1.72 + if (kClamp_Mode == textureDomain.mode()) { 1.73 + SkString clampedCoords; 1.74 + clampedCoords.appendf("\tclamp(%s, %s.xy, %s.zw)", 1.75 + inCoords.c_str(), fDomainName.c_str(), fDomainName.c_str()); 1.76 + 1.77 + builder->fsCodeAppendf("\t%s = ", outColor); 1.78 + builder->fsAppendTextureLookupAndModulate(inModulateColor, sampler, clampedCoords.c_str()); 1.79 + builder->fsCodeAppend(";\n"); 1.80 + } else { 1.81 + SkASSERT(GrTextureDomain::kDecal_Mode == textureDomain.mode()); 1.82 + // Add a block since we're going to declare variables. 1.83 + GrGLShaderBuilder::FSBlock block(builder); 1.84 + 1.85 + const char* domain = fDomainName.c_str(); 1.86 + if (kImagination_GrGLVendor == builder->ctxInfo().vendor()) { 1.87 + // On the NexusS and GalaxyNexus, the other path (with the 'any' 1.88 + // call) causes the compilation error "Calls to any function that 1.89 + // may require a gradient calculation inside a conditional block 1.90 + // may return undefined results". This appears to be an issue with 1.91 + // the 'any' call since even the simple "result=black; if (any()) 1.92 + // result=white;" code fails to compile. 1.93 + builder->fsCodeAppend("\tvec4 outside = vec4(0.0, 0.0, 0.0, 0.0);\n"); 1.94 + builder->fsCodeAppend("\tvec4 inside = "); 1.95 + builder->fsAppendTextureLookupAndModulate(inModulateColor, sampler, inCoords.c_str()); 1.96 + builder->fsCodeAppend(";\n"); 1.97 + 1.98 + builder->fsCodeAppendf("\tfloat x = abs(2.0*(%s.x - %s.x)/(%s.z - %s.x) - 1.0);\n", 1.99 + inCoords.c_str(), domain, domain, domain); 1.100 + builder->fsCodeAppendf("\tfloat y = abs(2.0*(%s.y - %s.y)/(%s.w - %s.y) - 1.0);\n", 1.101 + inCoords.c_str(), domain, domain, domain); 1.102 + builder->fsCodeAppend("\tfloat blend = step(1.0, max(x, y));\n"); 1.103 + builder->fsCodeAppendf("\t%s = mix(inside, outside, blend);\n", outColor); 1.104 + } else { 1.105 + builder->fsCodeAppend("\tbvec4 outside;\n"); 1.106 + builder->fsCodeAppendf("\toutside.xy = lessThan(%s, %s.xy);\n", inCoords.c_str(), 1.107 + domain); 1.108 + builder->fsCodeAppendf("\toutside.zw = greaterThan(%s, %s.zw);\n", inCoords.c_str(), 1.109 + domain); 1.110 + builder->fsCodeAppendf("\t%s = any(outside) ? vec4(0.0, 0.0, 0.0, 0.0) : ", outColor); 1.111 + builder->fsAppendTextureLookupAndModulate(inModulateColor, sampler, inCoords.c_str()); 1.112 + builder->fsCodeAppend(";\n"); 1.113 + } 1.114 + } 1.115 +} 1.116 + 1.117 +void GrTextureDomain::GLDomain::setData(const GrGLUniformManager& uman, 1.118 + const GrTextureDomain& textureDomain, 1.119 + GrSurfaceOrigin textureOrigin) { 1.120 + SkASSERT(textureDomain.mode() == fMode); 1.121 + if (kIgnore_Mode != textureDomain.mode()) { 1.122 + GrGLfloat values[4] = { 1.123 + SkScalarToFloat(textureDomain.domain().left()), 1.124 + SkScalarToFloat(textureDomain.domain().top()), 1.125 + SkScalarToFloat(textureDomain.domain().right()), 1.126 + SkScalarToFloat(textureDomain.domain().bottom()) 1.127 + }; 1.128 + // vertical flip if necessary 1.129 + if (kBottomLeft_GrSurfaceOrigin == textureOrigin) { 1.130 + values[1] = 1.0f - values[1]; 1.131 + values[3] = 1.0f - values[3]; 1.132 + // The top and bottom were just flipped, so correct the ordering 1.133 + // of elements so that values = (l, t, r, b). 1.134 + SkTSwap(values[1], values[3]); 1.135 + } 1.136 + if (0 != memcmp(values, fPrevDomain, 4 * sizeof(GrGLfloat))) { 1.137 + uman.set4fv(fDomainUni, 1, values); 1.138 + memcpy(fPrevDomain, values, 4 * sizeof(GrGLfloat)); 1.139 + } 1.140 + } 1.141 +} 1.142 + 1.143 + 1.144 +////////////////////////////////////////////////////////////////////////////// 1.145 + 1.146 +class GrGLTextureDomainEffect : public GrGLEffect { 1.147 +public: 1.148 + GrGLTextureDomainEffect(const GrBackendEffectFactory&, const GrDrawEffect&); 1.149 + 1.150 + virtual void emitCode(GrGLShaderBuilder*, 1.151 + const GrDrawEffect&, 1.152 + EffectKey, 1.153 + const char* outputColor, 1.154 + const char* inputColor, 1.155 + const TransformedCoordsArray&, 1.156 + const TextureSamplerArray&) SK_OVERRIDE; 1.157 + 1.158 + virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE; 1.159 + 1.160 + static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&); 1.161 + 1.162 +private: 1.163 + GrTextureDomain::GLDomain fGLDomain; 1.164 + typedef GrGLEffect INHERITED; 1.165 +}; 1.166 + 1.167 +GrGLTextureDomainEffect::GrGLTextureDomainEffect(const GrBackendEffectFactory& factory, 1.168 + const GrDrawEffect&) 1.169 + : INHERITED(factory) { 1.170 +} 1.171 + 1.172 +void GrGLTextureDomainEffect::emitCode(GrGLShaderBuilder* builder, 1.173 + const GrDrawEffect& drawEffect, 1.174 + EffectKey key, 1.175 + const char* outputColor, 1.176 + const char* inputColor, 1.177 + const TransformedCoordsArray& coords, 1.178 + const TextureSamplerArray& samplers) { 1.179 + const GrTextureDomainEffect& effect = drawEffect.castEffect<GrTextureDomainEffect>(); 1.180 + const GrTextureDomain& domain = effect.textureDomain(); 1.181 + 1.182 + SkString coords2D = builder->ensureFSCoords2D(coords, 0); 1.183 + fGLDomain.sampleTexture(builder, domain, outputColor, coords2D, samplers[0], inputColor); 1.184 +} 1.185 + 1.186 +void GrGLTextureDomainEffect::setData(const GrGLUniformManager& uman, 1.187 + const GrDrawEffect& drawEffect) { 1.188 + const GrTextureDomainEffect& effect = drawEffect.castEffect<GrTextureDomainEffect>(); 1.189 + const GrTextureDomain& domain = effect.textureDomain(); 1.190 + fGLDomain.setData(uman, domain, effect.texture(0)->origin()); 1.191 +} 1.192 + 1.193 +GrGLEffect::EffectKey GrGLTextureDomainEffect::GenKey(const GrDrawEffect& drawEffect, 1.194 + const GrGLCaps&) { 1.195 + const GrTextureDomain& domain = drawEffect.castEffect<GrTextureDomainEffect>().textureDomain(); 1.196 + return GrTextureDomain::GLDomain::DomainKey(domain); 1.197 +} 1.198 + 1.199 + 1.200 +/////////////////////////////////////////////////////////////////////////////// 1.201 + 1.202 +GrEffectRef* GrTextureDomainEffect::Create(GrTexture* texture, 1.203 + const SkMatrix& matrix, 1.204 + const SkRect& domain, 1.205 + GrTextureDomain::Mode mode, 1.206 + GrTextureParams::FilterMode filterMode, 1.207 + GrCoordSet coordSet) { 1.208 + static const SkRect kFullRect = {0, 0, SK_Scalar1, SK_Scalar1}; 1.209 + if (GrTextureDomain::kIgnore_Mode == mode || 1.210 + (GrTextureDomain::kClamp_Mode == mode && domain.contains(kFullRect))) { 1.211 + return GrSimpleTextureEffect::Create(texture, matrix, filterMode); 1.212 + } else { 1.213 + 1.214 + AutoEffectUnref effect(SkNEW_ARGS(GrTextureDomainEffect, (texture, 1.215 + matrix, 1.216 + domain, 1.217 + mode, 1.218 + filterMode, 1.219 + coordSet))); 1.220 + return CreateEffectRef(effect); 1.221 + 1.222 + } 1.223 +} 1.224 + 1.225 +GrTextureDomainEffect::GrTextureDomainEffect(GrTexture* texture, 1.226 + const SkMatrix& matrix, 1.227 + const SkRect& domain, 1.228 + GrTextureDomain::Mode mode, 1.229 + GrTextureParams::FilterMode filterMode, 1.230 + GrCoordSet coordSet) 1.231 + : GrSingleTextureEffect(texture, matrix, filterMode, coordSet) 1.232 + , fTextureDomain(domain, mode) { 1.233 +} 1.234 + 1.235 +GrTextureDomainEffect::~GrTextureDomainEffect() { 1.236 + 1.237 +} 1.238 + 1.239 +const GrBackendEffectFactory& GrTextureDomainEffect::getFactory() const { 1.240 + return GrTBackendEffectFactory<GrTextureDomainEffect>::getInstance(); 1.241 +} 1.242 + 1.243 +bool GrTextureDomainEffect::onIsEqual(const GrEffect& sBase) const { 1.244 + const GrTextureDomainEffect& s = CastEffect<GrTextureDomainEffect>(sBase); 1.245 + return this->hasSameTextureParamsMatrixAndSourceCoords(s) && 1.246 + this->fTextureDomain == s.fTextureDomain; 1.247 +} 1.248 + 1.249 +void GrTextureDomainEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const { 1.250 + if (GrTextureDomain::kDecal_Mode == fTextureDomain.mode()) { // TODO: helper 1.251 + *validFlags = 0; 1.252 + } else { 1.253 + this->updateConstantColorComponentsForModulation(color, validFlags); 1.254 + } 1.255 +} 1.256 + 1.257 +/////////////////////////////////////////////////////////////////////////////// 1.258 + 1.259 +GR_DEFINE_EFFECT_TEST(GrTextureDomainEffect); 1.260 + 1.261 +GrEffectRef* GrTextureDomainEffect::TestCreate(SkRandom* random, 1.262 + GrContext*, 1.263 + const GrDrawTargetCaps&, 1.264 + GrTexture* textures[]) { 1.265 + int texIdx = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx : 1.266 + GrEffectUnitTest::kAlphaTextureIdx; 1.267 + SkRect domain; 1.268 + domain.fLeft = random->nextUScalar1(); 1.269 + domain.fRight = random->nextRangeScalar(domain.fLeft, SK_Scalar1); 1.270 + domain.fTop = random->nextUScalar1(); 1.271 + domain.fBottom = random->nextRangeScalar(domain.fTop, SK_Scalar1); 1.272 + GrTextureDomain::Mode mode = 1.273 + (GrTextureDomain::Mode) random->nextULessThan(GrTextureDomain::kModeCount); 1.274 + const SkMatrix& matrix = GrEffectUnitTest::TestMatrix(random); 1.275 + bool bilerp = random->nextBool(); 1.276 + GrCoordSet coords = random->nextBool() ? kLocal_GrCoordSet : kPosition_GrCoordSet; 1.277 + return GrTextureDomainEffect::Create(textures[texIdx], 1.278 + matrix, 1.279 + domain, 1.280 + mode, 1.281 + bilerp ? GrTextureParams::kBilerp_FilterMode : GrTextureParams::kNone_FilterMode, 1.282 + coords); 1.283 +}