Line data Source code
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 :
46 0 : static const GrTextureDomain& IgnoredDomain() {
47 : static const GrTextureDomain gDomain((GrTextureProxy*)nullptr,
48 0 : SkRect::MakeEmpty(), kIgnore_Mode);
49 0 : 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(GrTexture*, const SkRect& domain, Mode, int index = -1);
57 :
58 : GrTextureDomain(GrTextureProxy*, const SkRect& domain, Mode, int index = -1);
59 :
60 0 : const SkRect& domain() const { return fDomain; }
61 0 : 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. */
65 0 : static const SkRect MakeTexelDomain(const SkIRect& texelRect) {
66 0 : return SkRect::Make(texelRect);
67 : }
68 :
69 0 : static const SkRect MakeTexelDomainForMode(const SkIRect& texelRect, Mode mode) {
70 : // For Clamp mode, inset by half a texel.
71 0 : SkScalar inset = (mode == kClamp_Mode && !texelRect.isEmpty()) ? SK_ScalarHalf : 0;
72 0 : return SkRect::MakeLTRB(texelRect.fLeft + inset, texelRect.fTop + inset,
73 0 : texelRect.fRight - inset, texelRect.fBottom - inset);
74 : }
75 :
76 0 : bool operator==(const GrTextureDomain& that) const {
77 0 : 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 0 : class GLDomain {
87 : public:
88 0 : GLDomain() {
89 0 : for (int i = 0; i < kPrevDomainCount; i++) {
90 0 : fPrevDomain[i] = SK_FloatNaN;
91 : }
92 0 : SkDEBUGCODE(fMode = (Mode) -1;)
93 0 : }
94 :
95 : /**
96 : * Call this from GrGLSLFragmentProcessor::emitCode() to sample the texture W.R.T. the
97 : * domain and mode.
98 : *
99 : * @param outcolor name of vec4 variable to hold the sampled color.
100 : * @param inCoords name of vec2 variable containing the coords to be used with the domain.
101 : * It is assumed that this is a variable and not an expression.
102 : * @param inModulateColor if non-nullptr the sampled color will be modulated with this
103 : * expression before being written to outColor.
104 : */
105 : void sampleTexture(GrGLSLShaderBuilder* builder,
106 : GrGLSLUniformHandler* uniformHandler,
107 : const GrShaderCaps* shaderCaps,
108 : const GrTextureDomain& textureDomain,
109 : const char* outColor,
110 : const SkString& inCoords,
111 : GrGLSLFragmentProcessor::SamplerHandle sampler,
112 : const char* inModulateColor = nullptr,
113 : GrGLSLColorSpaceXformHelper* colorXformHelper = nullptr);
114 :
115 : /**
116 : * Call this from GrGLSLFragmentProcessor::setData() to upload uniforms necessary for the
117 : * texture domain. The rectangle is automatically adjusted to account for the texture's
118 : * origin.
119 : */
120 : void setData(const GrGLSLProgramDataManager& pdman, const GrTextureDomain& textureDomain,
121 : GrTexture* texure);
122 :
123 : enum {
124 : kDomainKeyBits = 2, // See DomainKey().
125 : };
126 :
127 : /**
128 : * GrGLSLFragmentProcessor::GenKey() must call this and include the returned value in it's
129 : * computed key. The returned will be limited to the lower kDomainKeyBits bits.
130 : */
131 0 : static uint32_t DomainKey(const GrTextureDomain& domain) {
132 : GR_STATIC_ASSERT(kModeCount <= (1 << kDomainKeyBits));
133 0 : return domain.mode();
134 : }
135 :
136 : private:
137 : static const int kPrevDomainCount = 4;
138 : SkDEBUGCODE(Mode fMode;)
139 : GrGLSLProgramDataManager::UniformHandle fDomainUni;
140 : SkString fDomainName;
141 : float fPrevDomain[kPrevDomainCount];
142 : };
143 :
144 : protected:
145 : Mode fMode;
146 : SkRect fDomain;
147 : int fIndex;
148 : };
149 :
150 : /**
151 : * A basic texture effect that uses GrTextureDomain.
152 : */
153 0 : class GrTextureDomainEffect : public GrSingleTextureEffect {
154 :
155 : public:
156 : static sk_sp<GrFragmentProcessor> Make(GrResourceProvider*,
157 : sk_sp<GrTextureProxy>,
158 : sk_sp<GrColorSpaceXform>,
159 : const SkMatrix&,
160 : const SkRect& domain,
161 : GrTextureDomain::Mode,
162 : GrSamplerParams::FilterMode filterMode);
163 :
164 0 : const char* name() const override { return "TextureDomain"; }
165 :
166 0 : SkString dumpInfo() const override {
167 0 : SkString str;
168 0 : str.appendf("Domain: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]",
169 0 : fTextureDomain.domain().fLeft, fTextureDomain.domain().fTop,
170 0 : fTextureDomain.domain().fRight, fTextureDomain.domain().fBottom);
171 0 : str.append(INHERITED::dumpInfo());
172 0 : return str;
173 : }
174 :
175 : private:
176 : GrTextureDomain fTextureDomain;
177 :
178 : GrTextureDomainEffect(GrResourceProvider*,
179 : sk_sp<GrTextureProxy>,
180 : sk_sp<GrColorSpaceXform>,
181 : const SkMatrix&,
182 : const SkRect& domain,
183 : GrTextureDomain::Mode,
184 : GrSamplerParams::FilterMode);
185 :
186 : static OptimizationFlags OptFlags(GrPixelConfig config, GrTextureDomain::Mode mode);
187 :
188 : GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
189 :
190 : void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
191 :
192 : bool onIsEqual(const GrFragmentProcessor&) const override;
193 :
194 : GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
195 :
196 : typedef GrSingleTextureEffect INHERITED;
197 : };
198 :
199 0 : class GrDeviceSpaceTextureDecalFragmentProcessor : public GrFragmentProcessor {
200 : public:
201 : static sk_sp<GrFragmentProcessor> Make(GrResourceProvider*, sk_sp<GrTextureProxy>,
202 : const SkIRect& subset,
203 : const SkIPoint& deviceSpaceOffset);
204 :
205 0 : const char* name() const override { return "GrDeviceSpaceTextureDecalFragmentProcessor"; }
206 :
207 0 : SkString dumpInfo() const override {
208 0 : SkString str;
209 0 : str.appendf("Domain: [L: %.2f, T: %.2f, R: %.2f, B: %.2f] Offset: [%d %d]",
210 0 : fTextureDomain.domain().fLeft, fTextureDomain.domain().fTop,
211 0 : fTextureDomain.domain().fRight, fTextureDomain.domain().fBottom,
212 0 : fDeviceSpaceOffset.fX, fDeviceSpaceOffset.fY);
213 0 : str.append(INHERITED::dumpInfo());
214 0 : return str;
215 : }
216 :
217 : private:
218 : TextureSampler fTextureSampler;
219 : GrTextureDomain fTextureDomain;
220 : SkIPoint fDeviceSpaceOffset;
221 :
222 : GrDeviceSpaceTextureDecalFragmentProcessor(GrResourceProvider*, sk_sp<GrTextureProxy>,
223 : const SkIRect&, const SkIPoint&);
224 :
225 : GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
226 :
227 : // Since we always use decal mode, there is no need for key data.
228 0 : void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
229 :
230 : bool onIsEqual(const GrFragmentProcessor& fp) const override;
231 :
232 : GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
233 :
234 : typedef GrFragmentProcessor INHERITED;
235 : };
236 : #endif
|