• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 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 GrTextureEffect_DEFINED
9 #define GrTextureEffect_DEFINED
10 
11 #include "include/core/SkImageInfo.h"
12 #include "include/core/SkMatrix.h"
13 #include "src/gpu/ganesh/GrFragmentProcessor.h"
14 #include "src/gpu/ganesh/GrProcessorUnitTest.h"
15 #include "src/gpu/ganesh/GrSamplerState.h"
16 #include "src/gpu/ganesh/GrSurfaceProxyView.h"
17 #include "src/gpu/ganesh/GrTextureProxy.h"
18 #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
19 
20 class GrTextureEffect : public GrFragmentProcessor {
21 public:
22     inline static constexpr float kDefaultBorder[4] = {0};
23 
24     /** Make from a filter. The sampler will be configured with clamp mode. */
25     static std::unique_ptr<GrFragmentProcessor> Make(
26             GrSurfaceProxyView,
27             SkAlphaType,
28             const SkMatrix& = SkMatrix::I(),
29             GrSamplerState::Filter = GrSamplerState::Filter::kNearest,
30             GrSamplerState::MipmapMode mipmapMode = GrSamplerState::MipmapMode::kNone);
31 
32     /**
33      * Make from a full GrSamplerState. Caps are required to determine support for kClampToBorder.
34      * This will be emulated in the shader if there is no hardware support.
35      */
36     static std::unique_ptr<GrFragmentProcessor> Make(GrSurfaceProxyView, SkAlphaType,
37                                                      const SkMatrix&, GrSamplerState,
38                                                      const GrCaps& caps,
39                                                      const float border[4] = kDefaultBorder);
40 
41     /**
42      * Makes a texture effect that samples a subset of a texture. The wrap modes of the
43      * GrSampleState are applied to the subset in the shader rather than using HW samplers.
44      * The 'subset' parameter specifies the texels in the base level. The shader code will
45      * avoid allowing linear filtering to read outside the texel window. However, if MIP
46      * filtering is used and a shader invocation reads from a level other than the base
47      * then it may read texel values that were computed from in part from base level texels
48      * outside the window. More specifically, we treat the MIP map case exactly like the
49      * linear case in terms of how the final texture coords are computed. If
50      * alwaysUseShaderTileMode is true then MakeSubset won't attempt to use HW wrap modes if the
51      * subset contains the entire texture.
52      */
53     static std::unique_ptr<GrFragmentProcessor> MakeSubset(GrSurfaceProxyView,
54                                                            SkAlphaType,
55                                                            const SkMatrix&,
56                                                            GrSamplerState,
57                                                            const SkRect& subset,
58                                                            const GrCaps& caps,
59                                                            const float border[4] = kDefaultBorder,
60                                                            bool alwaysUseShaderTileMode = false);
61 
62     /**
63      * The same as above but also takes a 'domain' that specifies any known limit on the post-
64      * matrix texture coords that will be used to sample the texture. Specifying this requires
65      * knowledge of how this effect will be nested into a paint, the local coords used with the
66      * draw, etc. It is only used to attempt to optimize away the shader subset calculations.
67      */
68     static std::unique_ptr<GrFragmentProcessor> MakeSubset(GrSurfaceProxyView,
69                                                            SkAlphaType,
70                                                            const SkMatrix&,
71                                                            GrSamplerState,
72                                                            const SkRect& subset,
73                                                            const SkRect& domain,
74                                                            const GrCaps& caps,
75                                                            const float border[4] = kDefaultBorder);
76 
77     /**
78      * Like MakeSubset() but always uses kLinear filtering. MakeSubset() uses the subset rect
79      * dimensions to determine the period of the wrap mode (for repeat and mirror). Once it computes
80      * the wrapped texture coordinate inside subset rect it further clamps it to a 0.5 inset rect of
81      * subset. When subset is an integer rectangle this clamping avoids the hw linear filtering from
82      * reading texels just outside the subset rect. This factory allows a custom inset clamping
83      * distance rather than 0.5, allowing those neighboring texels to influence the linear filtering
84      * sample result. If there is a known restriction on the post-matrix texture coords it can be
85      * specified using domain.
86      */
87     static std::unique_ptr<GrFragmentProcessor> MakeCustomLinearFilterInset(
88             GrSurfaceProxyView,
89             SkAlphaType,
90             const SkMatrix&,
91             GrSamplerState::WrapMode wx,
92             GrSamplerState::WrapMode wy,
93             const SkRect& subset,
94             const SkRect* domain,
95             SkVector inset,
96             const GrCaps& caps,
97             const float border[4] = kDefaultBorder);
98 
99     std::unique_ptr<GrFragmentProcessor> clone() const override;
100 
name()101     const char* name() const override { return "TextureEffect"; }
102 
samplerState()103     GrSamplerState samplerState() const { return fSamplerState; }
104 
texture()105     GrTexture* texture() const { return fView.asTextureProxy()->peekTexture(); }
106 
view()107     const GrSurfaceProxyView& view() const { return fView; }
108 
109     // Gets a matrix that is concat'ed by wrapping GrMatrixEffect that handles y-flip and coord
110     // normalization if required. This matrix is not always known when we make the GrTextureEffect
111     // because of fully-lazy proxies. Hence, this method  exists to allow this concat to happen
112     // after proxy instantiation with coordination from GrMatrixEffect.
113     SkMatrix coordAdjustmentMatrix() const;
114 
115     class Impl : public ProgramImpl {
116     public:
117         void emitCode(EmitArgs&) override;
118 
setSamplerHandle(GrGLSLShaderBuilder::SamplerHandle handle)119         void setSamplerHandle(GrGLSLShaderBuilder::SamplerHandle handle) {
120             fSamplerHandle = handle;
121         }
122 
123     private:
124         void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
125 
126         UniformHandle fSubsetUni;
127         UniformHandle fClampUni;
128         UniformHandle fIDimsUni;
129         UniformHandle fBorderUni;
130         GrGLSLShaderBuilder::SamplerHandle fSamplerHandle;
131     };
132 
133 private:
134     struct Sampling;
135 
136     /**
137      * Possible implementation of wrap mode in shader code. Some modes are specialized by
138      * filter.
139      */
140     enum class ShaderMode : uint16_t {
141         kNone,                   // Using HW mode
142         kClamp,                  // Shader based clamp, no filter specialization
143         kRepeat_Nearest_None,    // Simple repeat for nearest sampling, no mipmapping
144         kRepeat_Linear_None,     // Filter the subset boundary for kRepeat mode, no mip mapping
145         kRepeat_Linear_Mipmap,   // Logic for linear filtering and LOD selection with kRepeat mode.
146         kRepeat_Nearest_Mipmap,  // Logic for nearest filtering and LOD selection with kRepeat mode.
147         kMirrorRepeat,           // Mirror repeat (doesn't depend on filter))
148         kClampToBorder_Nearest,  // Logic for hard transition to border color when not filtering.
149         kClampToBorder_Filter,   // Logic for fading to border color when filtering.
150     };
151     static ShaderMode GetShaderMode(GrSamplerState::WrapMode,
152                                     GrSamplerState::Filter,
153                                     GrSamplerState::MipmapMode);
154     static bool ShaderModeIsClampToBorder(ShaderMode);
155     // To keep things a little simpler, when we have filtering logic in the shader we
156     // operate on unnormalized texture coordinates. We will add a uniform that stores
157     // {1/w, 1/h} in a float2 and normalizes after the mode is handled if the texture
158     // is not rectangle.
159     static bool ShaderModeRequiresUnormCoord(ShaderMode);
160 
161     GrSurfaceProxyView fView;
162     GrSamplerState fSamplerState;
163     float fBorder[4];
164     SkRect fSubset;
165     SkRect fClamp;
166     ShaderMode fShaderModes[2];
167 
168     inline GrTextureEffect(GrSurfaceProxyView, SkAlphaType, const Sampling&);
169 
170     explicit GrTextureEffect(const GrTextureEffect& src);
171 
172     std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override;
173 
174     void onAddToKey(const GrShaderCaps&, skgpu::KeyBuilder*) const override;
175 
176     bool onIsEqual(const GrFragmentProcessor&) const override;
177 
178     bool matrixEffectShouldNormalize() const;
179 
hasClampToBorderShaderMode()180     bool hasClampToBorderShaderMode() const {
181         return ShaderModeIsClampToBorder(fShaderModes[0]) ||
182                ShaderModeIsClampToBorder(fShaderModes[1]);
183     }
184 
185     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
186 
187     using INHERITED = GrFragmentProcessor;
188 };
189 #endif
190