blob: 4b21b974508562cef6cc34ba0b3015963e052ba5 [file] [log] [blame]
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +00001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "src/gpu/GrCoordTransform.h"
12#include "src/gpu/GrFragmentProcessor.h"
13#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
14#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +000015
joshualitt30ba4362014-08-21 20:18:45 -070016class GrGLProgramBuilder;
egdaniel2d721d32015-11-11 13:06:05 -080017class GrGLSLShaderBuilder;
Brian Salomon1127c0b2019-06-13 20:22:10 +000018class GrInvariantOutput;
egdaniel7ea439b2015-12-03 09:20:44 -080019class GrGLSLUniformHandler;
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +000020struct SkRect;
21
22/**
23 * Limits a texture's lookup coordinates to a domain. Samples outside the domain are either clamped
Ethan Nicholasf7b88202017-09-18 14:10:39 -040024 * the edge of the domain or result in a half4 of zeros (decal mode). The domain is clipped to
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +000025 * 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 */
28class GrTextureDomain {
29public:
30 enum Mode {
joshualitt5ae5fc52014-07-29 12:59:27 -070031 // 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,
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +000041
joshualitt5ae5fc52014-07-29 12:59:27 -070042 kLastMode = kRepeat_Mode
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +000043 };
44 static const int kModeCount = kLastMode + 1;
45
commit-bot@chromium.org7d7f3142013-12-16 15:18:11 +000046 static const GrTextureDomain& IgnoredDomain() {
Robert Phillips40fd7c92017-01-30 08:06:27 -050047 static const GrTextureDomain gDomain((GrTextureProxy*)nullptr,
Michael Ludwigbe315a22018-12-17 09:50:51 -050048 SkRect::MakeEmpty(), kIgnore_Mode, kIgnore_Mode);
commit-bot@chromium.org7d7f3142013-12-16 15:18:11 +000049 return gDomain;
50 }
51
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +000052 /**
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 */
Michael Ludwigbe315a22018-12-17 09:50:51 -050056 GrTextureDomain(GrTextureProxy*, const SkRect& domain, Mode modeX, Mode modeY, int index = -1);
Robert Phillips40fd7c92017-01-30 08:06:27 -050057
Brian Salomonffc2ec42017-07-25 14:59:03 -040058 GrTextureDomain(const GrTextureDomain&) = default;
59
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +000060 const SkRect& domain() const { return fDomain; }
Michael Ludwigbe315a22018-12-17 09:50:51 -050061 Mode modeX() const { return fModeX; }
62 Mode modeY() const { return fModeY; }
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +000063
Michael Ludwigbe315a22018-12-17 09:50:51 -050064 /*
65 * Computes a domain that bounds all the texels in texelRect, possibly insetting by half a pixel
66 * depending on the mode. The mode is used for both axes.
67 */
68 static const SkRect MakeTexelDomain(const SkIRect& texelRect, Mode mode) {
69 return MakeTexelDomain(texelRect, mode, mode);
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +000070 }
71
Michael Ludwigbe315a22018-12-17 09:50:51 -050072 static const SkRect MakeTexelDomain(const SkIRect& texelRect, Mode modeX, Mode modeY) {
73 // For Clamp and decal modes, inset by half a texel
74 SkScalar insetX = ((modeX == kClamp_Mode || modeX == kDecal_Mode) && texelRect.width() > 0)
75 ? SK_ScalarHalf : 0;
76 SkScalar insetY = ((modeY == kClamp_Mode || modeY == kDecal_Mode) && texelRect.height() > 0)
77 ? SK_ScalarHalf : 0;
78 return SkRect::MakeLTRB(texelRect.fLeft + insetX, texelRect.fTop + insetY,
79 texelRect.fRight - insetX, texelRect.fBottom - insetY);
senorblancod0d37ca2015-04-02 04:54:56 -070080 }
81
Michael Ludwig257a03d2018-12-13 14:07:07 -050082 // Convenience to determine if any axis of a texture uses an explicit decal mode or the hardware
83 // clamp to border decal mode.
84 static bool IsDecalSampled(GrSamplerState::WrapMode wrapX, GrSamplerState::WrapMode wrapY,
85 Mode modeX, Mode modeY) {
86 return wrapX == GrSamplerState::WrapMode::kClampToBorder ||
87 wrapY == GrSamplerState::WrapMode::kClampToBorder ||
88 modeX == kDecal_Mode ||
89 modeY == kDecal_Mode;
90 }
91
92 static bool IsDecalSampled(const GrSamplerState::WrapMode wraps[2], Mode modeX, Mode modeY) {
93 return IsDecalSampled(wraps[0], wraps[1], modeX, modeY);
94 }
95
96 static bool IsDecalSampled(const GrSamplerState& sampler, Mode modeX, Mode modeY) {
97 return IsDecalSampled(sampler.wrapModeX(), sampler.wrapModeY(), modeX, modeY);
98 }
99
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400100 bool operator==(const GrTextureDomain& that) const {
Michael Ludwigbe315a22018-12-17 09:50:51 -0500101 return fModeX == that.fModeX && fModeY == that.fModeY &&
102 (kIgnore_Mode == fModeX || (fDomain.fLeft == that.fDomain.fLeft &&
103 fDomain.fRight == that.fDomain.fRight)) &&
104 (kIgnore_Mode == fModeY || (fDomain.fTop == that.fDomain.fTop &&
105 fDomain.fBottom == that.fDomain.fBottom));
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000106 }
107
108 /**
egdaniel64c47282015-11-13 06:54:19 -0800109 * A GrGLSLFragmentProcessor subclass that corresponds to a GrProcessor subclass that uses
egdaniel7dc4bd02015-10-29 07:57:01 -0700110 * GrTextureDomain should include this helper. It generates the texture domain GLSL, produces
111 * the part of the effect key that reflects the texture domain code, and performs the uniform
112 * uploads necessary for texture domains.
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000113 */
114 class GLDomain {
115 public:
116 GLDomain() {
joshualittb5fb5af2015-08-25 12:10:54 -0700117 for (int i = 0; i < kPrevDomainCount; i++) {
118 fPrevDomain[i] = SK_FloatNaN;
119 }
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000120 }
121
122 /**
egdaniel64c47282015-11-13 06:54:19 -0800123 * Call this from GrGLSLFragmentProcessor::emitCode() to sample the texture W.R.T. the
124 * domain and mode.
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000125 *
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400126 * @param outcolor name of half4 variable to hold the sampled color.
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400127 * @param inCoords name of float2 variable containing the coords to be used with the domain.
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000128 * It is assumed that this is a variable and not an expression.
halcanary96fcdcc2015-08-27 07:41:13 -0700129 * @param inModulateColor if non-nullptr the sampled color will be modulated with this
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000130 * expression before being written to outColor.
131 */
egdaniel2d721d32015-11-11 13:06:05 -0800132 void sampleTexture(GrGLSLShaderBuilder* builder,
egdaniel7ea439b2015-12-03 09:20:44 -0800133 GrGLSLUniformHandler* uniformHandler,
Brian Salomon1edc5b92016-11-29 13:43:46 -0500134 const GrShaderCaps* shaderCaps,
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000135 const GrTextureDomain& textureDomain,
136 const char* outColor,
137 const SkString& inCoords,
egdaniel09aa1fc2016-04-20 07:09:46 -0700138 GrGLSLFragmentProcessor::SamplerHandle sampler,
Brian Osman2240be92017-10-18 13:15:13 -0400139 const char* inModulateColor = nullptr);
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000140
141 /**
egdaniel64c47282015-11-13 06:54:19 -0800142 * Call this from GrGLSLFragmentProcessor::setData() to upload uniforms necessary for the
egdaniel7dc4bd02015-10-29 07:57:01 -0700143 * texture domain. The rectangle is automatically adjusted to account for the texture's
144 * origin.
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000145 */
Michael Ludwigbe315a22018-12-17 09:50:51 -0500146 void setData(const GrGLSLProgramDataManager&, const GrTextureDomain&, GrTextureProxy*,
147 const GrSamplerState& sampler);
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000148
149 enum {
Michael Ludwigbe315a22018-12-17 09:50:51 -0500150 kModeBits = 2, // See DomainKey().
151 kDomainKeyBits = 4
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000152 };
153
154 /**
egdaniel64c47282015-11-13 06:54:19 -0800155 * GrGLSLFragmentProcessor::GenKey() must call this and include the returned value in it's
egdaniel7dc4bd02015-10-29 07:57:01 -0700156 * computed key. The returned will be limited to the lower kDomainKeyBits bits.
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000157 */
bsalomon63e99f72014-07-21 08:03:14 -0700158 static uint32_t DomainKey(const GrTextureDomain& domain) {
Michael Ludwigbe315a22018-12-17 09:50:51 -0500159 GR_STATIC_ASSERT(kModeCount <= (1 << kModeBits));
160 return domain.modeX() | (domain.modeY() << kModeBits);
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000161 }
162
163 private:
joshualittb5fb5af2015-08-25 12:10:54 -0700164 static const int kPrevDomainCount = 4;
Michael Ludwigbe315a22018-12-17 09:50:51 -0500165 SkDEBUGCODE(Mode fModeX;)
166 SkDEBUGCODE(Mode fModeY;)
Hans Wennborgc63ec5c2017-12-08 18:56:23 -0800167 SkDEBUGCODE(bool fHasMode = false;)
egdaniel018fb622015-10-28 07:26:40 -0700168 GrGLSLProgramDataManager::UniformHandle fDomainUni;
169 SkString fDomainName;
Michael Ludwigbe315a22018-12-17 09:50:51 -0500170
171 // Only initialized if the domain has at least one decal axis
172 GrGLSLProgramDataManager::UniformHandle fDecalUni;
173 SkString fDecalName;
174
egdaniel018fb622015-10-28 07:26:40 -0700175 float fPrevDomain[kPrevDomainCount];
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000176 };
177
178protected:
Michael Ludwigbe315a22018-12-17 09:50:51 -0500179 Mode fModeX;
180 Mode fModeY;
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000181 SkRect fDomain;
182 int fIndex;
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000183};
184
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000185/**
186 * A basic texture effect that uses GrTextureDomain.
187 */
Brian Salomon6cd51b52017-07-26 19:07:15 -0400188class GrTextureDomainEffect : public GrFragmentProcessor {
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000189public:
Brian Salomonaff329b2017-08-11 09:40:37 -0400190 static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy>,
Brian Salomonaff329b2017-08-11 09:40:37 -0400191 const SkMatrix&,
192 const SkRect& domain,
Michael Ludwigbe315a22018-12-17 09:50:51 -0500193 GrTextureDomain::Mode mode,
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400194 GrSamplerState::Filter filterMode);
Robert Phillips40fd7c92017-01-30 08:06:27 -0500195
Michael Ludwigbe315a22018-12-17 09:50:51 -0500196 static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy>,
197 const SkMatrix&,
198 const SkRect& domain,
199 GrTextureDomain::Mode modeX,
200 GrTextureDomain::Mode modeY,
201 const GrSamplerState& sampler);
202
mtklein36352bf2015-03-25 18:17:31 -0700203 const char* name() const override { return "TextureDomain"; }
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000204
Brian Salomonaff329b2017-08-11 09:40:37 -0400205 std::unique_ptr<GrFragmentProcessor> clone() const override {
206 return std::unique_ptr<GrFragmentProcessor>(new GrTextureDomainEffect(*this));
Brian Salomon3f6f9652017-07-28 07:34:05 -0400207 }
208
Brian Osman9a390ac2018-11-12 09:47:48 -0500209#ifdef SK_DEBUG
robertphillipse004bfc2015-11-16 09:06:59 -0800210 SkString dumpInfo() const override {
211 SkString str;
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400212 str.appendf("Domain: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]",
robertphillipse004bfc2015-11-16 09:06:59 -0800213 fTextureDomain.domain().fLeft, fTextureDomain.domain().fTop,
214 fTextureDomain.domain().fRight, fTextureDomain.domain().fBottom);
215 str.append(INHERITED::dumpInfo());
216 return str;
217 }
Brian Osman9a390ac2018-11-12 09:47:48 -0500218#endif
robertphillipse004bfc2015-11-16 09:06:59 -0800219
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400220private:
Brian Salomon6cd51b52017-07-26 19:07:15 -0400221 GrCoordTransform fCoordTransform;
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000222 GrTextureDomain fTextureDomain;
Brian Salomon6cd51b52017-07-26 19:07:15 -0400223 TextureSampler fTextureSampler;
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000224
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400225 GrTextureDomainEffect(sk_sp<GrTextureProxy>,
Robert Phillips40fd7c92017-01-30 08:06:27 -0500226 const SkMatrix&,
227 const SkRect& domain,
Michael Ludwigbe315a22018-12-17 09:50:51 -0500228 GrTextureDomain::Mode modeX,
229 GrTextureDomain::Mode modeY,
230 const GrSamplerState&);
Robert Phillips40fd7c92017-01-30 08:06:27 -0500231
Brian Salomon3f6f9652017-07-28 07:34:05 -0400232 explicit GrTextureDomainEffect(const GrTextureDomainEffect&);
233
egdaniel57d3b032015-11-13 11:57:27 -0800234 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700235
Brian Salomon94efbf52016-11-29 13:43:05 -0500236 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700237
mtklein36352bf2015-03-25 18:17:31 -0700238 bool onIsEqual(const GrFragmentProcessor&) const override;
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000239
Brian Salomonf7dcd762018-07-30 14:48:15 -0400240 const TextureSampler& onTextureSampler(int) const override { return fTextureSampler; }
241
Brian Salomon0c26a9d2017-07-06 10:09:38 -0400242 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000243
Brian Salomon6cd51b52017-07-26 19:07:15 -0400244 typedef GrFragmentProcessor INHERITED;
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000245};
246
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400247class GrDeviceSpaceTextureDecalFragmentProcessor : public GrFragmentProcessor {
248public:
Brian Salomonaff329b2017-08-11 09:40:37 -0400249 static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy>,
250 const SkIRect& subset,
251 const SkIPoint& deviceSpaceOffset);
Robert Phillips40fd7c92017-01-30 08:06:27 -0500252
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400253 const char* name() const override { return "GrDeviceSpaceTextureDecalFragmentProcessor"; }
254
Brian Osman9a390ac2018-11-12 09:47:48 -0500255#ifdef SK_DEBUG
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400256 SkString dumpInfo() const override {
257 SkString str;
258 str.appendf("Domain: [L: %.2f, T: %.2f, R: %.2f, B: %.2f] Offset: [%d %d]",
259 fTextureDomain.domain().fLeft, fTextureDomain.domain().fTop,
260 fTextureDomain.domain().fRight, fTextureDomain.domain().fBottom,
261 fDeviceSpaceOffset.fX, fDeviceSpaceOffset.fY);
262 str.append(INHERITED::dumpInfo());
263 return str;
264 }
Brian Osman9a390ac2018-11-12 09:47:48 -0500265#endif
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400266
Brian Salomonaff329b2017-08-11 09:40:37 -0400267 std::unique_ptr<GrFragmentProcessor> clone() const override;
Brian Salomon1a2a7ab2017-07-26 13:11:51 -0400268
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400269private:
Brian Salomon0bbecb22016-11-17 11:38:22 -0500270 TextureSampler fTextureSampler;
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400271 GrTextureDomain fTextureDomain;
272 SkIPoint fDeviceSpaceOffset;
273
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400274 GrDeviceSpaceTextureDecalFragmentProcessor(sk_sp<GrTextureProxy>,
Robert Phillips40fd7c92017-01-30 08:06:27 -0500275 const SkIRect&, const SkIPoint&);
Brian Salomon1a2a7ab2017-07-26 13:11:51 -0400276 GrDeviceSpaceTextureDecalFragmentProcessor(const GrDeviceSpaceTextureDecalFragmentProcessor&);
Robert Phillips40fd7c92017-01-30 08:06:27 -0500277
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400278 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
279
280 // Since we always use decal mode, there is no need for key data.
Brian Salomon94efbf52016-11-29 13:43:05 -0500281 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400282
283 bool onIsEqual(const GrFragmentProcessor& fp) const override;
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400284
Brian Salomonf7dcd762018-07-30 14:48:15 -0400285 const TextureSampler& onTextureSampler(int) const override { return fTextureSampler; }
286
Brian Salomon0c26a9d2017-07-06 10:09:38 -0400287 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400288
289 typedef GrFragmentProcessor INHERITED;
290};
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000291#endif