blob: 96c2d2019b20b1cd622002898d668c97c5ad818f [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
Michael Ludwig170de012019-11-15 21:55:18 +00008#ifndef GrTextureDomainEffect_DEFINED
9#define GrTextureDomainEffect_DEFINED
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +000010
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:
Michael Ludwig170de012019-11-15 21:55:18 +0000116 GLDomain() {
117 for (int i = 0; i < kPrevDomainCount; i++) {
118 fPrevDomain[i] = SK_FloatNaN;
119 }
120 }
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000121
122 /**
Michael Ludwig170de012019-11-15 21:55:18 +0000123 * Call this from GrGLSLFragmentProcessor::emitCode() to sample the texture W.R.T. the
egdaniel64c47282015-11-13 06:54:19 -0800124 * 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.
Michael Ludwig170de012019-11-15 21:55:18 +0000127 * @param inCoords name of float2 variable containing the coords to be used with the domain.
128 * 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
Michael Ludwig170de012019-11-15 21:55:18 +0000143 * 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*,
Michael Ludwig170de012019-11-15 21:55:18 +0000147 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:
Michael Ludwig170de012019-11-15 21:55:18 +0000164 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
Michael Ludwig170de012019-11-15 21:55:18 +0000175 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;
Michael Ludwig170de012019-11-15 21:55:18 +0000181 SkRect fDomain;
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000182 int fIndex;
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000183};
184
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000185/**
Michael Ludwig170de012019-11-15 21:55:18 +0000186 * A basic texture effect that uses GrTextureDomain.
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000187 */
Michael Ludwig170de012019-11-15 21:55:18 +0000188class GrTextureDomainEffect : public GrFragmentProcessor {
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000189public:
Michael Ludwig170de012019-11-15 21:55:18 +0000190 static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy>,
Brian Salomon078e8fa2019-11-22 04:10:18 +0000191 GrColorType srcColorType,
Brian Salomonaff329b2017-08-11 09:40:37 -0400192 const SkMatrix&,
193 const SkRect& domain,
Michael Ludwig170de012019-11-15 21:55:18 +0000194 GrTextureDomain::Mode mode,
195 GrSamplerState::Filter filterMode);
Robert Phillips40fd7c92017-01-30 08:06:27 -0500196
Michael Ludwig170de012019-11-15 21:55:18 +0000197 static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy>,
Brian Salomon078e8fa2019-11-22 04:10:18 +0000198 GrColorType srcColorType,
Michael Ludwigbe315a22018-12-17 09:50:51 -0500199 const SkMatrix&,
200 const SkRect& domain,
201 GrTextureDomain::Mode modeX,
202 GrTextureDomain::Mode modeY,
Michael Ludwig170de012019-11-15 21:55:18 +0000203 const GrSamplerState& sampler);
Michael Ludwigbe315a22018-12-17 09:50:51 -0500204
Michael Ludwig170de012019-11-15 21:55:18 +0000205 const char* name() const override { return "TextureDomain"; }
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000206
Brian Salomonaff329b2017-08-11 09:40:37 -0400207 std::unique_ptr<GrFragmentProcessor> clone() const override {
Michael Ludwig170de012019-11-15 21:55:18 +0000208 return std::unique_ptr<GrFragmentProcessor>(new GrTextureDomainEffect(*this));
Brian Salomon3f6f9652017-07-28 07:34:05 -0400209 }
210
Brian Osman9a390ac2018-11-12 09:47:48 -0500211#ifdef SK_DEBUG
robertphillipse004bfc2015-11-16 09:06:59 -0800212 SkString dumpInfo() const override {
213 SkString str;
Michael Ludwig170de012019-11-15 21:55:18 +0000214 str.appendf("Domain: [L: %.2f, T: %.2f, R: %.2f, B: %.2f]",
215 fTextureDomain.domain().fLeft, fTextureDomain.domain().fTop,
216 fTextureDomain.domain().fRight, fTextureDomain.domain().fBottom);
robertphillipse004bfc2015-11-16 09:06:59 -0800217 str.append(INHERITED::dumpInfo());
218 return str;
219 }
Brian Osman9a390ac2018-11-12 09:47:48 -0500220#endif
robertphillipse004bfc2015-11-16 09:06:59 -0800221
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400222private:
Brian Salomon6cd51b52017-07-26 19:07:15 -0400223 GrCoordTransform fCoordTransform;
Michael Ludwig170de012019-11-15 21:55:18 +0000224 GrTextureDomain fTextureDomain;
225 TextureSampler fTextureSampler;
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000226
Michael Ludwig170de012019-11-15 21:55:18 +0000227 GrTextureDomainEffect(sk_sp<GrTextureProxy>,
Brian Salomon078e8fa2019-11-22 04:10:18 +0000228 GrColorType srcColorType,
Michael Ludwig170de012019-11-15 21:55:18 +0000229 const SkMatrix&,
230 const SkRect& domain,
231 GrTextureDomain::Mode modeX,
232 GrTextureDomain::Mode modeY,
233 const GrSamplerState&);
Robert Phillips40fd7c92017-01-30 08:06:27 -0500234
Michael Ludwig170de012019-11-15 21:55:18 +0000235 explicit GrTextureDomainEffect(const GrTextureDomainEffect&);
Brian Salomon3f6f9652017-07-28 07:34:05 -0400236
egdaniel57d3b032015-11-13 11:57:27 -0800237 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700238
Brian Salomon94efbf52016-11-29 13:43:05 -0500239 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700240
mtklein36352bf2015-03-25 18:17:31 -0700241 bool onIsEqual(const GrFragmentProcessor&) const override;
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000242
Michael Ludwig170de012019-11-15 21:55:18 +0000243 const TextureSampler& onTextureSampler(int) const override { return fTextureSampler; }
244
Brian Salomon0c26a9d2017-07-06 10:09:38 -0400245 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000246
Brian Salomon6cd51b52017-07-26 19:07:15 -0400247 typedef GrFragmentProcessor INHERITED;
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000248};
249
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400250class GrDeviceSpaceTextureDecalFragmentProcessor : public GrFragmentProcessor {
251public:
Brian Salomonaff329b2017-08-11 09:40:37 -0400252 static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy>,
253 const SkIRect& subset,
254 const SkIPoint& deviceSpaceOffset);
Robert Phillips40fd7c92017-01-30 08:06:27 -0500255
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400256 const char* name() const override { return "GrDeviceSpaceTextureDecalFragmentProcessor"; }
257
Brian Osman9a390ac2018-11-12 09:47:48 -0500258#ifdef SK_DEBUG
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400259 SkString dumpInfo() const override {
260 SkString str;
261 str.appendf("Domain: [L: %.2f, T: %.2f, R: %.2f, B: %.2f] Offset: [%d %d]",
262 fTextureDomain.domain().fLeft, fTextureDomain.domain().fTop,
263 fTextureDomain.domain().fRight, fTextureDomain.domain().fBottom,
264 fDeviceSpaceOffset.fX, fDeviceSpaceOffset.fY);
265 str.append(INHERITED::dumpInfo());
266 return str;
267 }
Brian Osman9a390ac2018-11-12 09:47:48 -0500268#endif
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400269
Brian Salomonaff329b2017-08-11 09:40:37 -0400270 std::unique_ptr<GrFragmentProcessor> clone() const override;
Brian Salomon1a2a7ab2017-07-26 13:11:51 -0400271
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400272private:
Brian Salomon0bbecb22016-11-17 11:38:22 -0500273 TextureSampler fTextureSampler;
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400274 GrTextureDomain fTextureDomain;
275 SkIPoint fDeviceSpaceOffset;
276
Robert Phillipsfbcef6e2017-06-15 12:07:18 -0400277 GrDeviceSpaceTextureDecalFragmentProcessor(sk_sp<GrTextureProxy>,
Robert Phillips40fd7c92017-01-30 08:06:27 -0500278 const SkIRect&, const SkIPoint&);
Brian Salomon1a2a7ab2017-07-26 13:11:51 -0400279 GrDeviceSpaceTextureDecalFragmentProcessor(const GrDeviceSpaceTextureDecalFragmentProcessor&);
Robert Phillips40fd7c92017-01-30 08:06:27 -0500280
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400281 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
282
283 // Since we always use decal mode, there is no need for key data.
Brian Salomon94efbf52016-11-29 13:43:05 -0500284 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400285
286 bool onIsEqual(const GrFragmentProcessor& fp) const override;
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400287
Brian Salomonf7dcd762018-07-30 14:48:15 -0400288 const TextureSampler& onTextureSampler(int) const override { return fTextureSampler; }
289
Brian Salomon0c26a9d2017-07-06 10:09:38 -0400290 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
Brian Salomon2ebd0c82016-10-03 17:15:28 -0400291
292 typedef GrFragmentProcessor INHERITED;
293};
commit-bot@chromium.org907fbd52013-12-09 17:03:02 +0000294#endif