• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "GrCoordTransform.h"
12 #include "GrFragmentProcessor.h"
13 #include "glsl/GrGLSLFragmentProcessor.h"
14 #include "glsl/GrGLSLProgramDataManager.h"
15 
16 class GrGLProgramBuilder;
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 half4 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 
58     GrTextureDomain(const GrTextureDomain&) = default;
59 
domain()60     const SkRect& domain() const { return fDomain; }
mode()61     Mode mode() const { return fMode; }
62 
63     /* Computes a domain that bounds all the texels in texelRect. Note that with bilerp enabled
64        texels neighboring the domain may be read. */
MakeTexelDomain(const SkIRect & texelRect)65     static const SkRect MakeTexelDomain(const SkIRect& texelRect) {
66         return SkRect::Make(texelRect);
67     }
68 
MakeTexelDomainForMode(const SkIRect & texelRect,Mode mode)69     static const SkRect MakeTexelDomainForMode(const SkIRect& texelRect, Mode mode) {
70         // For Clamp mode, inset by half a texel.
71         SkScalar inset = (mode == kClamp_Mode && !texelRect.isEmpty()) ? SK_ScalarHalf : 0;
72         return SkRect::MakeLTRB(texelRect.fLeft + inset, texelRect.fTop + inset,
73                                 texelRect.fRight - inset, texelRect.fBottom - inset);
74     }
75 
76     bool operator==(const GrTextureDomain& that) const {
77         return fMode == that.fMode && (kIgnore_Mode == fMode || fDomain == that.fDomain);
78     }
79 
80     /**
81      * A GrGLSLFragmentProcessor subclass that corresponds to a GrProcessor subclass that uses
82      * GrTextureDomain should include this helper. It generates the texture domain GLSL, produces
83      * the part of the effect key that reflects the texture domain code, and performs the uniform
84      * uploads necessary for texture domains.
85      */
86     class GLDomain {
87     public:
GLDomain()88         GLDomain() {
89             for (int i = 0; i < kPrevDomainCount; i++) {
90                 fPrevDomain[i] = SK_FloatNaN;
91             }
92         }
93 
94         /**
95          * Call this from GrGLSLFragmentProcessor::emitCode() to sample the texture W.R.T. the
96          * domain and mode.
97          *
98          * @param outcolor  name of half4 variable to hold the sampled color.
99          * @param inCoords  name of float2 variable containing the coords to be used with the domain.
100          *                  It is assumed that this is a variable and not an expression.
101          * @param inModulateColor   if non-nullptr the sampled color will be modulated with this
102          *                          expression before being written to outColor.
103          */
104         void sampleTexture(GrGLSLShaderBuilder* builder,
105                            GrGLSLUniformHandler* uniformHandler,
106                            const GrShaderCaps* shaderCaps,
107                            const GrTextureDomain& textureDomain,
108                            const char* outColor,
109                            const SkString& inCoords,
110                            GrGLSLFragmentProcessor::SamplerHandle sampler,
111                            const char* inModulateColor = 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&, const GrTextureDomain&, GrSurfaceProxy*);
119 
120         enum {
121             kDomainKeyBits = 2, // See DomainKey().
122         };
123 
124         /**
125          * GrGLSLFragmentProcessor::GenKey() must call this and include the returned value in it's
126          * computed key. The returned will be limited to the lower kDomainKeyBits bits.
127          */
DomainKey(const GrTextureDomain & domain)128         static uint32_t DomainKey(const GrTextureDomain& domain) {
129             GR_STATIC_ASSERT(kModeCount <= (1 << kDomainKeyBits));
130             return domain.mode();
131         }
132 
133     private:
134         static const int kPrevDomainCount = 4;
135         SkDEBUGCODE(Mode                        fMode;)
136         SkDEBUGCODE(bool                        fHasMode = false;)
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 GrFragmentProcessor {
152 public:
153     static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy>,
154                                                      const SkMatrix&,
155                                                      const SkRect& domain,
156                                                      GrTextureDomain::Mode,
157                                                      GrSamplerState::Filter filterMode);
158 
name()159     const char* name() const override { return "TextureDomain"; }
160 
clone()161     std::unique_ptr<GrFragmentProcessor> clone() const override {
162         return std::unique_ptr<GrFragmentProcessor>(new GrTextureDomainEffect(*this));
163     }
164 
dumpInfo()165     SkString dumpInfo() const override {
166         SkString str;
167         str.appendf("Domain: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]",
168                     fTextureDomain.domain().fLeft, fTextureDomain.domain().fTop,
169                     fTextureDomain.domain().fRight, fTextureDomain.domain().fBottom);
170         str.append(INHERITED::dumpInfo());
171         return str;
172     }
173 
174 private:
175     GrCoordTransform fCoordTransform;
176     GrTextureDomain fTextureDomain;
177     TextureSampler fTextureSampler;
178 
179     GrTextureDomainEffect(sk_sp<GrTextureProxy>,
180                           const SkMatrix&,
181                           const SkRect& domain,
182                           GrTextureDomain::Mode,
183                           GrSamplerState::Filter);
184 
185     explicit GrTextureDomainEffect(const GrTextureDomainEffect&);
186 
187     static OptimizationFlags OptFlags(GrPixelConfig config, GrTextureDomain::Mode mode);
188 
189     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
190 
191     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
192 
193     bool onIsEqual(const GrFragmentProcessor&) const override;
194 
195     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
196 
197     typedef GrFragmentProcessor INHERITED;
198 };
199 
200 class GrDeviceSpaceTextureDecalFragmentProcessor : public GrFragmentProcessor {
201 public:
202     static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy>,
203                                                      const SkIRect& subset,
204                                                      const SkIPoint& deviceSpaceOffset);
205 
name()206     const char* name() const override { return "GrDeviceSpaceTextureDecalFragmentProcessor"; }
207 
dumpInfo()208     SkString dumpInfo() const override {
209         SkString str;
210         str.appendf("Domain: [L: %.2f, T: %.2f, R: %.2f, B: %.2f] Offset: [%d %d]",
211                     fTextureDomain.domain().fLeft, fTextureDomain.domain().fTop,
212                     fTextureDomain.domain().fRight, fTextureDomain.domain().fBottom,
213                     fDeviceSpaceOffset.fX, fDeviceSpaceOffset.fY);
214         str.append(INHERITED::dumpInfo());
215         return str;
216     }
217 
218     std::unique_ptr<GrFragmentProcessor> clone() const override;
219 
220 private:
221     TextureSampler fTextureSampler;
222     GrTextureDomain fTextureDomain;
223     SkIPoint fDeviceSpaceOffset;
224 
225     GrDeviceSpaceTextureDecalFragmentProcessor(sk_sp<GrTextureProxy>,
226                                                const SkIRect&, const SkIPoint&);
227     GrDeviceSpaceTextureDecalFragmentProcessor(const GrDeviceSpaceTextureDecalFragmentProcessor&);
228 
229     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
230 
231     // Since we always use decal mode, there is no need for key data.
onGetGLSLProcessorKey(const GrShaderCaps &,GrProcessorKeyBuilder *)232     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
233 
234     bool onIsEqual(const GrFragmentProcessor& fp) const override;
235 
236     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
237 
238     typedef GrFragmentProcessor INHERITED;
239 };
240 #endif
241