1 /* 2 * Copyright 2012 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef GrTextureDomainEffect_DEFINED 9 #define GrTextureDomainEffect_DEFINED 10 11 #include "GrSingleTextureEffect.h" 12 #include "gl/GrGLProcessor.h" 13 14 class GrGLProgramBuilder; 15 class GrGLShaderBuilder; 16 class GrInvariantOutput; 17 struct SkRect; 18 19 /** 20 * Limits a texture's lookup coordinates to a domain. Samples outside the domain are either clamped 21 * the edge of the domain or result in a vec4 of zeros (decal mode). The domain is clipped to 22 * normalized texture coords ([0,1]x[0,1] square). Bilinear filtering can cause texels outside the 23 * domain to affect the read value unless the caller considers this when calculating the domain. 24 */ 25 class GrTextureDomain { 26 public: 27 enum Mode { 28 // Ignore the texture domain rectangle. 29 kIgnore_Mode, 30 // Clamp texture coords to the domain rectangle. 31 kClamp_Mode, 32 // Treat the area outside the domain rectangle as fully transparent. 33 kDecal_Mode, 34 // Wrap texture coordinates. NOTE: filtering may not work as expected because Bilerp will 35 // read texels outside of the domain. We could perform additional texture reads and filter 36 // in the shader, but are not currently doing this for performance reasons 37 kRepeat_Mode, 38 39 kLastMode = kRepeat_Mode 40 }; 41 static const int kModeCount = kLastMode + 1; 42 IgnoredDomain()43 static const GrTextureDomain& IgnoredDomain() { 44 static const SkRect gDummyRect = {0, 0, 0, 0}; 45 static const GrTextureDomain gDomain(gDummyRect, kIgnore_Mode); 46 return gDomain; 47 } 48 49 /** 50 * @param index Pass a value >= 0 if using multiple texture domains in the same effect. 51 * It is used to keep inserted variables from causing name collisions. 52 */ 53 GrTextureDomain(const SkRect& domain, Mode, int index = -1); 54 domain()55 const SkRect& domain() const { return fDomain; } mode()56 Mode mode() const { return fMode; } 57 58 /* Computes a domain that bounds all the texels in texelRect. Note that with bilerp enabled 59 texels neighboring the domain may be read. */ MakeTexelDomain(const GrTexture * texture,const SkIRect & texelRect)60 static const SkRect MakeTexelDomain(const GrTexture* texture, const SkIRect& texelRect) { 61 SkScalar wInv = SK_Scalar1 / texture->width(); 62 SkScalar hInv = SK_Scalar1 / texture->height(); 63 SkRect result = { 64 texelRect.fLeft * wInv, 65 texelRect.fTop * hInv, 66 texelRect.fRight * wInv, 67 texelRect.fBottom * hInv 68 }; 69 return result; 70 } 71 MakeTexelDomainForMode(const GrTexture * texture,const SkIRect & texelRect,Mode mode)72 static const SkRect MakeTexelDomainForMode(const GrTexture* texture, const SkIRect& texelRect, Mode mode) { 73 // For Clamp mode, inset by half a texel. 74 SkScalar wInv = SK_Scalar1 / texture->width(); 75 SkScalar hInv = SK_Scalar1 / texture->height(); 76 SkScalar inset = (mode == kClamp_Mode && !texelRect.isEmpty()) ? SK_ScalarHalf : 0; 77 return SkRect::MakeLTRB( 78 (texelRect.fLeft + inset) * wInv, 79 (texelRect.fTop + inset) * hInv, 80 (texelRect.fRight - inset) * wInv, 81 (texelRect.fBottom - inset) * hInv 82 ); 83 } 84 85 bool operator== (const GrTextureDomain& that) const { 86 return fMode == that.fMode && (kIgnore_Mode == fMode || fDomain == that.fDomain); 87 } 88 89 /** 90 * A GrGLProcessor subclass that corresponds to a GrProcessor subclass that uses GrTextureDomain 91 * should include this helper. It generates the texture domain GLSL, produces the part of the 92 * effect key that reflects the texture domain code, and performs the uniform uploads necessary 93 * for texture domains. 94 */ 95 class GLDomain { 96 public: GLDomain()97 GLDomain() { 98 fPrevDomain[0] = SK_FloatNaN; 99 SkDEBUGCODE(fMode = (Mode) -1;) 100 } 101 102 /** 103 * Call this from GrGLProcessor::emitCode() to sample the texture W.R.T. the domain and 104 * mode. 105 * 106 * @param outcolor name of vec4 variable to hold the sampled color. 107 * @param inCoords name of vec2 variable containing the coords to be used with the domain. 108 * It is assumed that this is a variable and not an expression. 109 * @param inModulateColor if non-NULL the sampled color will be modulated with this 110 * expression before being written to outColor. 111 */ 112 void sampleTexture(GrGLShaderBuilder* builder, 113 const GrTextureDomain& textureDomain, 114 const char* outColor, 115 const SkString& inCoords, 116 const GrGLProcessor::TextureSampler sampler, 117 const char* inModulateColor = NULL); 118 119 /** 120 * Call this from GrGLProcessor::setData() to upload uniforms necessary for the texture 121 * domain. The rectangle is automatically adjusted to account for the texture's origin. 122 */ 123 void setData(const GrGLProgramDataManager& pdman, const GrTextureDomain& textureDomain, 124 GrSurfaceOrigin textureOrigin); 125 126 enum { 127 kDomainKeyBits = 2, // See DomainKey(). 128 }; 129 130 /** 131 * GrGLProcessor::GenKey() must call this and include the returned value in it's computed 132 * key. The returned will be limited to the lower kDomainKeyBits bits. 133 */ DomainKey(const GrTextureDomain & domain)134 static uint32_t DomainKey(const GrTextureDomain& domain) { 135 GR_STATIC_ASSERT(kModeCount <= 4); 136 return domain.mode(); 137 } 138 139 private: 140 SkDEBUGCODE(Mode fMode;) 141 GrGLProgramDataManager::UniformHandle fDomainUni; 142 SkString fDomainName; 143 GrGLfloat fPrevDomain[4]; 144 }; 145 146 protected: 147 Mode fMode; 148 SkRect fDomain; 149 int fIndex; 150 151 typedef GrSingleTextureEffect INHERITED; 152 }; 153 154 /** 155 * A basic texture effect that uses GrTextureDomain. 156 */ 157 class GrTextureDomainEffect : public GrSingleTextureEffect { 158 159 public: 160 static GrFragmentProcessor* Create(GrTexture*, 161 const SkMatrix&, 162 const SkRect& domain, 163 GrTextureDomain::Mode, 164 GrTextureParams::FilterMode filterMode, 165 GrCoordSet = kLocal_GrCoordSet); 166 167 virtual ~GrTextureDomainEffect(); 168 name()169 const char* name() const override { return "TextureDomain"; } 170 171 void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override; 172 173 GrGLFragmentProcessor* createGLInstance() const override; 174 textureDomain()175 const GrTextureDomain& textureDomain() const { return fTextureDomain; } 176 177 protected: 178 GrTextureDomain fTextureDomain; 179 180 private: 181 GrTextureDomainEffect(GrTexture*, 182 const SkMatrix&, 183 const SkRect& domain, 184 GrTextureDomain::Mode, 185 GrTextureParams::FilterMode, 186 GrCoordSet); 187 188 bool onIsEqual(const GrFragmentProcessor&) const override; 189 190 void onComputeInvariantOutput(GrInvariantOutput* inout) const override; 191 192 GR_DECLARE_FRAGMENT_PROCESSOR_TEST; 193 194 typedef GrSingleTextureEffect INHERITED; 195 }; 196 197 #endif 198