GrTextureDomain.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  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. #ifndef GrTextureDomainEffect_DEFINED
  8. #define GrTextureDomainEffect_DEFINED
  9. #include "src/gpu/GrCoordTransform.h"
  10. #include "src/gpu/GrFragmentProcessor.h"
  11. #include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
  12. #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
  13. class GrGLProgramBuilder;
  14. class GrGLSLShaderBuilder;
  15. class GrInvariantOutput;
  16. class GrGLSLUniformHandler;
  17. struct SkRect;
  18. /**
  19. * Limits a texture's lookup coordinates to a domain. Samples outside the domain are either clamped
  20. * the edge of the domain or result in a half4 of zeros (decal mode). The domain is clipped to
  21. * normalized texture coords ([0,1]x[0,1] square). Bilinear filtering can cause texels outside the
  22. * domain to affect the read value unless the caller considers this when calculating the domain.
  23. */
  24. class GrTextureDomain {
  25. public:
  26. enum Mode {
  27. // Ignore the texture domain rectangle.
  28. kIgnore_Mode,
  29. // Clamp texture coords to the domain rectangle.
  30. kClamp_Mode,
  31. // Treat the area outside the domain rectangle as fully transparent.
  32. kDecal_Mode,
  33. // Wrap texture coordinates. NOTE: filtering may not work as expected because Bilerp will
  34. // read texels outside of the domain. We could perform additional texture reads and filter
  35. // in the shader, but are not currently doing this for performance reasons
  36. kRepeat_Mode,
  37. kLastMode = kRepeat_Mode
  38. };
  39. static const int kModeCount = kLastMode + 1;
  40. static const GrTextureDomain& IgnoredDomain() {
  41. static const GrTextureDomain gDomain((GrTextureProxy*)nullptr,
  42. SkRect::MakeEmpty(), kIgnore_Mode, kIgnore_Mode);
  43. return gDomain;
  44. }
  45. /**
  46. * @param index Pass a value >= 0 if using multiple texture domains in the same effect.
  47. * It is used to keep inserted variables from causing name collisions.
  48. */
  49. GrTextureDomain(GrTextureProxy*, const SkRect& domain, Mode modeX, Mode modeY, int index = -1);
  50. GrTextureDomain(const GrTextureDomain&) = default;
  51. const SkRect& domain() const { return fDomain; }
  52. Mode modeX() const { return fModeX; }
  53. Mode modeY() const { return fModeY; }
  54. /*
  55. * Computes a domain that bounds all the texels in texelRect, possibly insetting by half a pixel
  56. * depending on the mode. The mode is used for both axes.
  57. */
  58. static const SkRect MakeTexelDomain(const SkIRect& texelRect, Mode mode) {
  59. return MakeTexelDomain(texelRect, mode, mode);
  60. }
  61. static const SkRect MakeTexelDomain(const SkIRect& texelRect, Mode modeX, Mode modeY) {
  62. // For Clamp and decal modes, inset by half a texel
  63. SkScalar insetX = ((modeX == kClamp_Mode || modeX == kDecal_Mode) && texelRect.width() > 0)
  64. ? SK_ScalarHalf : 0;
  65. SkScalar insetY = ((modeY == kClamp_Mode || modeY == kDecal_Mode) && texelRect.height() > 0)
  66. ? SK_ScalarHalf : 0;
  67. return SkRect::MakeLTRB(texelRect.fLeft + insetX, texelRect.fTop + insetY,
  68. texelRect.fRight - insetX, texelRect.fBottom - insetY);
  69. }
  70. // Convenience to determine if any axis of a texture uses an explicit decal mode or the hardware
  71. // clamp to border decal mode.
  72. static bool IsDecalSampled(GrSamplerState::WrapMode wrapX, GrSamplerState::WrapMode wrapY,
  73. Mode modeX, Mode modeY) {
  74. return wrapX == GrSamplerState::WrapMode::kClampToBorder ||
  75. wrapY == GrSamplerState::WrapMode::kClampToBorder ||
  76. modeX == kDecal_Mode ||
  77. modeY == kDecal_Mode;
  78. }
  79. static bool IsDecalSampled(const GrSamplerState::WrapMode wraps[2], Mode modeX, Mode modeY) {
  80. return IsDecalSampled(wraps[0], wraps[1], modeX, modeY);
  81. }
  82. static bool IsDecalSampled(const GrSamplerState& sampler, Mode modeX, Mode modeY) {
  83. return IsDecalSampled(sampler.wrapModeX(), sampler.wrapModeY(), modeX, modeY);
  84. }
  85. bool operator==(const GrTextureDomain& that) const {
  86. return fModeX == that.fModeX && fModeY == that.fModeY &&
  87. (kIgnore_Mode == fModeX || (fDomain.fLeft == that.fDomain.fLeft &&
  88. fDomain.fRight == that.fDomain.fRight)) &&
  89. (kIgnore_Mode == fModeY || (fDomain.fTop == that.fDomain.fTop &&
  90. fDomain.fBottom == that.fDomain.fBottom));
  91. }
  92. /**
  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.
  97. */
  98. class GLDomain {
  99. public:
  100. GLDomain() {
  101. for (int i = 0; i < kPrevDomainCount; i++) {
  102. fPrevDomain[i] = SK_FloatNaN;
  103. }
  104. }
  105. /**
  106. * Call this from GrGLSLFragmentProcessor::emitCode() to sample the texture W.R.T. the
  107. * domain and mode.
  108. *
  109. * @param outcolor name of half4 variable to hold the sampled color.
  110. * @param inCoords name of float2 variable containing the coords to be used with the domain.
  111. * It is assumed that this is a variable and not an expression.
  112. * @param inModulateColor if non-nullptr the sampled color will be modulated with this
  113. * expression before being written to outColor.
  114. */
  115. void sampleTexture(GrGLSLShaderBuilder* builder,
  116. GrGLSLUniformHandler* uniformHandler,
  117. const GrShaderCaps* shaderCaps,
  118. const GrTextureDomain& textureDomain,
  119. const char* outColor,
  120. const SkString& inCoords,
  121. GrGLSLFragmentProcessor::SamplerHandle sampler,
  122. const char* inModulateColor = nullptr);
  123. /**
  124. * Call this from GrGLSLFragmentProcessor::setData() to upload uniforms necessary for the
  125. * texture domain. The rectangle is automatically adjusted to account for the texture's
  126. * origin.
  127. */
  128. void setData(const GrGLSLProgramDataManager&, const GrTextureDomain&, GrTextureProxy*,
  129. const GrSamplerState& sampler);
  130. enum {
  131. kModeBits = 2, // See DomainKey().
  132. kDomainKeyBits = 4
  133. };
  134. /**
  135. * GrGLSLFragmentProcessor::GenKey() must call this and include the returned value in it's
  136. * computed key. The returned will be limited to the lower kDomainKeyBits bits.
  137. */
  138. static uint32_t DomainKey(const GrTextureDomain& domain) {
  139. GR_STATIC_ASSERT(kModeCount <= (1 << kModeBits));
  140. return domain.modeX() | (domain.modeY() << kModeBits);
  141. }
  142. private:
  143. static const int kPrevDomainCount = 4;
  144. SkDEBUGCODE(Mode fModeX;)
  145. SkDEBUGCODE(Mode fModeY;)
  146. SkDEBUGCODE(bool fHasMode = false;)
  147. GrGLSLProgramDataManager::UniformHandle fDomainUni;
  148. SkString fDomainName;
  149. // Only initialized if the domain has at least one decal axis
  150. GrGLSLProgramDataManager::UniformHandle fDecalUni;
  151. SkString fDecalName;
  152. float fPrevDomain[kPrevDomainCount];
  153. };
  154. protected:
  155. Mode fModeX;
  156. Mode fModeY;
  157. SkRect fDomain;
  158. int fIndex;
  159. };
  160. /**
  161. * A basic texture effect that uses GrTextureDomain.
  162. */
  163. class GrTextureDomainEffect : public GrFragmentProcessor {
  164. public:
  165. static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy>,
  166. const SkMatrix&,
  167. const SkRect& domain,
  168. GrTextureDomain::Mode mode,
  169. GrSamplerState::Filter filterMode);
  170. static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy>,
  171. const SkMatrix&,
  172. const SkRect& domain,
  173. GrTextureDomain::Mode modeX,
  174. GrTextureDomain::Mode modeY,
  175. const GrSamplerState& sampler);
  176. const char* name() const override { return "TextureDomain"; }
  177. std::unique_ptr<GrFragmentProcessor> clone() const override {
  178. return std::unique_ptr<GrFragmentProcessor>(new GrTextureDomainEffect(*this));
  179. }
  180. #ifdef SK_DEBUG
  181. SkString dumpInfo() const override {
  182. SkString str;
  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());
  187. return str;
  188. }
  189. #endif
  190. private:
  191. GrCoordTransform fCoordTransform;
  192. GrTextureDomain fTextureDomain;
  193. TextureSampler fTextureSampler;
  194. GrTextureDomainEffect(sk_sp<GrTextureProxy>,
  195. const SkMatrix&,
  196. const SkRect& domain,
  197. GrTextureDomain::Mode modeX,
  198. GrTextureDomain::Mode modeY,
  199. const GrSamplerState&);
  200. explicit GrTextureDomainEffect(const GrTextureDomainEffect&);
  201. GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
  202. void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
  203. bool onIsEqual(const GrFragmentProcessor&) const override;
  204. const TextureSampler& onTextureSampler(int) const override { return fTextureSampler; }
  205. GR_DECLARE_FRAGMENT_PROCESSOR_TEST
  206. typedef GrFragmentProcessor INHERITED;
  207. };
  208. class GrDeviceSpaceTextureDecalFragmentProcessor : public GrFragmentProcessor {
  209. public:
  210. static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy>,
  211. const SkIRect& subset,
  212. const SkIPoint& deviceSpaceOffset);
  213. const char* name() const override { return "GrDeviceSpaceTextureDecalFragmentProcessor"; }
  214. #ifdef SK_DEBUG
  215. SkString dumpInfo() const override {
  216. SkString str;
  217. str.appendf("Domain: [L: %.2f, T: %.2f, R: %.2f, B: %.2f] Offset: [%d %d]",
  218. fTextureDomain.domain().fLeft, fTextureDomain.domain().fTop,
  219. fTextureDomain.domain().fRight, fTextureDomain.domain().fBottom,
  220. fDeviceSpaceOffset.fX, fDeviceSpaceOffset.fY);
  221. str.append(INHERITED::dumpInfo());
  222. return str;
  223. }
  224. #endif
  225. std::unique_ptr<GrFragmentProcessor> clone() const override;
  226. private:
  227. TextureSampler fTextureSampler;
  228. GrTextureDomain fTextureDomain;
  229. SkIPoint fDeviceSpaceOffset;
  230. GrDeviceSpaceTextureDecalFragmentProcessor(sk_sp<GrTextureProxy>,
  231. const SkIRect&, const SkIPoint&);
  232. GrDeviceSpaceTextureDecalFragmentProcessor(const GrDeviceSpaceTextureDecalFragmentProcessor&);
  233. GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
  234. // Since we always use decal mode, there is no need for key data.
  235. void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
  236. bool onIsEqual(const GrFragmentProcessor& fp) const override;
  237. const TextureSampler& onTextureSampler(int) const override { return fTextureSampler; }
  238. GR_DECLARE_FRAGMENT_PROCESSOR_TEST
  239. typedef GrFragmentProcessor INHERITED;
  240. };
  241. #endif