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 "glsl/GrGLSLFragmentProcessor.h" 13 #include "glsl/GrGLSLProgramDataManager.h" 14 15 class GrGLProgramBuilder; 16 class GrGLSLColorSpaceXformHelper; 17 class GrGLSLShaderBuilder; 18 class GrInvariantOutput; 19 class GrGLSLUniformHandler; 20 struct SkRect; 21 22 /** 23 * Limits a texture's lookup coordinates to a domain. Samples outside the domain are either clamped 24 * the edge of the domain or result in a vec4 of zeros (decal mode). The domain is clipped to 25 * normalized texture coords ([0,1]x[0,1] square). Bilinear filtering can cause texels outside the 26 * domain to affect the read value unless the caller considers this when calculating the domain. 27 */ 28 class GrTextureDomain { 29 public: 30 enum Mode { 31 // Ignore the texture domain rectangle. 32 kIgnore_Mode, 33 // Clamp texture coords to the domain rectangle. 34 kClamp_Mode, 35 // Treat the area outside the domain rectangle as fully transparent. 36 kDecal_Mode, 37 // Wrap texture coordinates. NOTE: filtering may not work as expected because Bilerp will 38 // read texels outside of the domain. We could perform additional texture reads and filter 39 // in the shader, but are not currently doing this for performance reasons 40 kRepeat_Mode, 41 42 kLastMode = kRepeat_Mode 43 }; 44 static const int kModeCount = kLastMode + 1; 45 IgnoredDomain()46 static const GrTextureDomain& IgnoredDomain() { 47 static const GrTextureDomain gDomain((GrTextureProxy*)nullptr, 48 SkRect::MakeEmpty(), kIgnore_Mode); 49 return gDomain; 50 } 51 52 /** 53 * @param index Pass a value >= 0 if using multiple texture domains in the same effect. 54 * It is used to keep inserted variables from causing name collisions. 55 */ 56 GrTextureDomain(GrTextureProxy*, const SkRect& domain, Mode, int index = -1); 57 domain()58 const SkRect& domain() const { return fDomain; } mode()59 Mode mode() const { return fMode; } 60 61 /* Computes a domain that bounds all the texels in texelRect. Note that with bilerp enabled 62 texels neighboring the domain may be read. */ MakeTexelDomain(const SkIRect & texelRect)63 static const SkRect MakeTexelDomain(const SkIRect& texelRect) { 64 return SkRect::Make(texelRect); 65 } 66 MakeTexelDomainForMode(const SkIRect & texelRect,Mode mode)67 static const SkRect MakeTexelDomainForMode(const SkIRect& texelRect, Mode mode) { 68 // For Clamp mode, inset by half a texel. 69 SkScalar inset = (mode == kClamp_Mode && !texelRect.isEmpty()) ? SK_ScalarHalf : 0; 70 return SkRect::MakeLTRB(texelRect.fLeft + inset, texelRect.fTop + inset, 71 texelRect.fRight - inset, texelRect.fBottom - inset); 72 } 73 74 bool operator==(const GrTextureDomain& that) const { 75 return fMode == that.fMode && (kIgnore_Mode == fMode || fDomain == that.fDomain); 76 } 77 78 /** 79 * A GrGLSLFragmentProcessor subclass that corresponds to a GrProcessor subclass that uses 80 * GrTextureDomain should include this helper. It generates the texture domain GLSL, produces 81 * the part of the effect key that reflects the texture domain code, and performs the uniform 82 * uploads necessary for texture domains. 83 */ 84 class GLDomain { 85 public: GLDomain()86 GLDomain() { 87 for (int i = 0; i < kPrevDomainCount; i++) { 88 fPrevDomain[i] = SK_FloatNaN; 89 } 90 SkDEBUGCODE(fMode = (Mode) -1;) 91 } 92 93 /** 94 * Call this from GrGLSLFragmentProcessor::emitCode() to sample the texture W.R.T. the 95 * domain and mode. 96 * 97 * @param outcolor name of vec4 variable to hold the sampled color. 98 * @param inCoords name of vec2 variable containing the coords to be used with the domain. 99 * It is assumed that this is a variable and not an expression. 100 * @param inModulateColor if non-nullptr the sampled color will be modulated with this 101 * expression before being written to outColor. 102 */ 103 void sampleTexture(GrGLSLShaderBuilder* builder, 104 GrGLSLUniformHandler* uniformHandler, 105 const GrShaderCaps* shaderCaps, 106 const GrTextureDomain& textureDomain, 107 const char* outColor, 108 const SkString& inCoords, 109 GrGLSLFragmentProcessor::SamplerHandle sampler, 110 const char* inModulateColor = nullptr, 111 GrGLSLColorSpaceXformHelper* colorXformHelper = nullptr); 112 113 /** 114 * Call this from GrGLSLFragmentProcessor::setData() to upload uniforms necessary for the 115 * texture domain. The rectangle is automatically adjusted to account for the texture's 116 * origin. 117 */ 118 void setData(const GrGLSLProgramDataManager& pdman, const GrTextureDomain& textureDomain, 119 GrTexture* texure); 120 121 enum { 122 kDomainKeyBits = 2, // See DomainKey(). 123 }; 124 125 /** 126 * GrGLSLFragmentProcessor::GenKey() must call this and include the returned value in it's 127 * computed key. The returned will be limited to the lower kDomainKeyBits bits. 128 */ DomainKey(const GrTextureDomain & domain)129 static uint32_t DomainKey(const GrTextureDomain& domain) { 130 GR_STATIC_ASSERT(kModeCount <= (1 << kDomainKeyBits)); 131 return domain.mode(); 132 } 133 134 private: 135 static const int kPrevDomainCount = 4; 136 SkDEBUGCODE(Mode fMode;) 137 GrGLSLProgramDataManager::UniformHandle fDomainUni; 138 SkString fDomainName; 139 float fPrevDomain[kPrevDomainCount]; 140 }; 141 142 protected: 143 Mode fMode; 144 SkRect fDomain; 145 int fIndex; 146 }; 147 148 /** 149 * A basic texture effect that uses GrTextureDomain. 150 */ 151 class GrTextureDomainEffect : public GrSingleTextureEffect { 152 153 public: 154 static sk_sp<GrFragmentProcessor> Make(sk_sp<GrTextureProxy>, 155 sk_sp<GrColorSpaceXform>, 156 const SkMatrix&, 157 const SkRect& domain, 158 GrTextureDomain::Mode, 159 GrSamplerParams::FilterMode filterMode); 160 name()161 const char* name() const override { return "TextureDomain"; } 162 dumpInfo()163 SkString dumpInfo() const override { 164 SkString str; 165 str.appendf("Domain: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]", 166 fTextureDomain.domain().fLeft, fTextureDomain.domain().fTop, 167 fTextureDomain.domain().fRight, fTextureDomain.domain().fBottom); 168 str.append(INHERITED::dumpInfo()); 169 return str; 170 } 171 172 private: 173 GrTextureDomain fTextureDomain; 174 175 GrTextureDomainEffect(sk_sp<GrTextureProxy>, 176 sk_sp<GrColorSpaceXform>, 177 const SkMatrix&, 178 const SkRect& domain, 179 GrTextureDomain::Mode, 180 GrSamplerParams::FilterMode); 181 182 static OptimizationFlags OptFlags(GrPixelConfig config, GrTextureDomain::Mode mode); 183 184 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; 185 186 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; 187 188 bool onIsEqual(const GrFragmentProcessor&) const override; 189 190 GR_DECLARE_FRAGMENT_PROCESSOR_TEST 191 192 typedef GrSingleTextureEffect INHERITED; 193 }; 194 195 class GrDeviceSpaceTextureDecalFragmentProcessor : public GrFragmentProcessor { 196 public: 197 static sk_sp<GrFragmentProcessor> Make(sk_sp<GrTextureProxy>, 198 const SkIRect& subset, 199 const SkIPoint& deviceSpaceOffset); 200 name()201 const char* name() const override { return "GrDeviceSpaceTextureDecalFragmentProcessor"; } 202 dumpInfo()203 SkString dumpInfo() const override { 204 SkString str; 205 str.appendf("Domain: [L: %.2f, T: %.2f, R: %.2f, B: %.2f] Offset: [%d %d]", 206 fTextureDomain.domain().fLeft, fTextureDomain.domain().fTop, 207 fTextureDomain.domain().fRight, fTextureDomain.domain().fBottom, 208 fDeviceSpaceOffset.fX, fDeviceSpaceOffset.fY); 209 str.append(INHERITED::dumpInfo()); 210 return str; 211 } 212 213 private: 214 TextureSampler fTextureSampler; 215 GrTextureDomain fTextureDomain; 216 SkIPoint fDeviceSpaceOffset; 217 218 GrDeviceSpaceTextureDecalFragmentProcessor(sk_sp<GrTextureProxy>, 219 const SkIRect&, const SkIPoint&); 220 221 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; 222 223 // Since we always use decal mode, there is no need for key data. onGetGLSLProcessorKey(const GrShaderCaps &,GrProcessorKeyBuilder *)224 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {} 225 226 bool onIsEqual(const GrFragmentProcessor& fp) const override; 227 228 GR_DECLARE_FRAGMENT_PROCESSOR_TEST 229 230 typedef GrFragmentProcessor INHERITED; 231 }; 232 #endif 233