2 * Copyright 2012 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #ifndef GrTextureDomainEffect_DEFINED
9 #define GrTextureDomainEffect_DEFINED
11 #include "GrSingleTextureEffect.h"
12 #include "glsl/GrGLSLFragmentProcessor.h"
13 #include "glsl/GrGLSLProgramDataManager.h"
15 class GrGLProgramBuilder;
16 class GrGLSLShaderBuilder;
17 class GrInvariantOutput;
19 class GrGLSLUniformHandler;
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.
28 class GrTextureDomain {
31 // Ignore the texture domain rectangle.
33 // Clamp texture coords to the domain rectangle.
35 // Treat the area outside the domain rectangle as fully transparent.
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
42 kLastMode = kRepeat_Mode
44 static const int kModeCount = kLastMode + 1;
46 static const GrTextureDomain& IgnoredDomain() {
47 static const SkRect gDummyRect = {0, 0, 0, 0};
48 static const GrTextureDomain gDomain(gDummyRect, kIgnore_Mode);
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.
56 GrTextureDomain(const SkRect& domain, Mode, int index = -1);
58 const SkRect& domain() const { return fDomain; }
59 Mode mode() const { return fMode; }
61 /* Computes a domain that bounds all the texels in texelRect. Note that with bilerp enabled
62 texels neighboring the domain may be read. */
63 static const SkRect MakeTexelDomain(const GrTexture* texture, const SkIRect& texelRect) {
64 SkScalar wInv = SK_Scalar1 / texture->width();
65 SkScalar hInv = SK_Scalar1 / texture->height();
67 texelRect.fLeft * wInv,
68 texelRect.fTop * hInv,
69 texelRect.fRight * wInv,
70 texelRect.fBottom * hInv
75 static const SkRect MakeTexelDomainForMode(const GrTexture* texture, const SkIRect& texelRect, Mode mode) {
76 // For Clamp mode, inset by half a texel.
77 SkScalar wInv = SK_Scalar1 / texture->width();
78 SkScalar hInv = SK_Scalar1 / texture->height();
79 SkScalar inset = (mode == kClamp_Mode && !texelRect.isEmpty()) ? SK_ScalarHalf : 0;
80 return SkRect::MakeLTRB(
81 (texelRect.fLeft + inset) * wInv,
82 (texelRect.fTop + inset) * hInv,
83 (texelRect.fRight - inset) * wInv,
84 (texelRect.fBottom - inset) * hInv
88 bool operator== (const GrTextureDomain& that) const {
89 return fMode == that.fMode && (kIgnore_Mode == fMode || fDomain == that.fDomain);
93 * A GrGLSLFragmentProcessor subclass that corresponds to a GrProcessor subclass that uses
94 * GrTextureDomain should include this helper. It generates the texture domain GLSL, produces
95 * the part of the effect key that reflects the texture domain code, and performs the uniform
96 * uploads necessary for texture domains.
101 for (int i = 0; i < kPrevDomainCount; i++) {
102 fPrevDomain[i] = SK_FloatNaN;
104 SkDEBUGCODE(fMode = (Mode) -1;)
108 * Call this from GrGLSLFragmentProcessor::emitCode() to sample the texture W.R.T. the
111 * @param outcolor name of vec4 variable to hold the sampled color.
112 * @param inCoords name of vec2 variable containing the coords to be used with the domain.
113 * It is assumed that this is a variable and not an expression.
114 * @param inModulateColor if non-nullptr the sampled color will be modulated with this
115 * expression before being written to outColor.
117 void sampleTexture(GrGLSLShaderBuilder* builder,
118 GrGLSLUniformHandler* uniformHandler,
119 const GrGLSLCaps* glslCaps,
120 const GrTextureDomain& textureDomain,
121 const char* outColor,
122 const SkString& inCoords,
123 GrGLSLFragmentProcessor::SamplerHandle sampler,
124 const char* inModulateColor = nullptr);
127 * Call this from GrGLSLFragmentProcessor::setData() to upload uniforms necessary for the
128 * texture domain. The rectangle is automatically adjusted to account for the texture's
131 void setData(const GrGLSLProgramDataManager& pdman, const GrTextureDomain& textureDomain,
132 GrSurfaceOrigin textureOrigin);
135 kDomainKeyBits = 2, // See DomainKey().
139 * GrGLSLFragmentProcessor::GenKey() must call this and include the returned value in it's
140 * computed key. The returned will be limited to the lower kDomainKeyBits bits.
142 static uint32_t DomainKey(const GrTextureDomain& domain) {
143 GR_STATIC_ASSERT(kModeCount <= 4);
144 return domain.mode();
148 static const int kPrevDomainCount = 4;
149 SkDEBUGCODE(Mode fMode;)
150 GrGLSLProgramDataManager::UniformHandle fDomainUni;
151 SkString fDomainName;
152 float fPrevDomain[kPrevDomainCount];
160 typedef GrSingleTextureEffect INHERITED;
164 * A basic texture effect that uses GrTextureDomain.
166 class GrTextureDomainEffect : public GrSingleTextureEffect {
169 static sk_sp<GrFragmentProcessor> Make(GrTexture*,
170 sk_sp<GrColorSpaceXform>,
172 const SkRect& domain,
173 GrTextureDomain::Mode,
174 GrTextureParams::FilterMode filterMode,
175 GrCoordSet = kLocal_GrCoordSet);
177 virtual ~GrTextureDomainEffect();
179 const char* name() const override { return "TextureDomain"; }
181 SkString dumpInfo() const override {
183 str.appendf("Domain: [L: %.2f, T: %.2f, R: %.2f, B: %.2f] ",
184 fTextureDomain.domain().fLeft, fTextureDomain.domain().fTop,
185 fTextureDomain.domain().fRight, fTextureDomain.domain().fBottom);
186 str.append(INHERITED::dumpInfo());
190 const GrTextureDomain& textureDomain() const { return fTextureDomain; }
193 GrTextureDomain fTextureDomain;
196 GrTextureDomainEffect(GrTexture*,
197 sk_sp<GrColorSpaceXform>,
199 const SkRect& domain,
200 GrTextureDomain::Mode,
201 GrTextureParams::FilterMode,
204 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
206 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
208 bool onIsEqual(const GrFragmentProcessor&) const override;
210 void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
212 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
214 typedef GrSingleTextureEffect INHERITED;