Flutter Engine
The Flutter Engine
GrTextureEffect.h
Go to the documentation of this file.
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
13#include "include/core/SkRect.h"
22
23#include <cstdint>
24#include <memory>
25
27class GrTexture;
28enum SkAlphaType : int;
29namespace skgpu { class KeyBuilder; }
30struct GrShaderCaps;
31
33public:
34 inline static constexpr float kDefaultBorder[4] = {0};
35
36 // An extra inset amount to apply to subset clamp boundaries to ensure clamped coordinates will
37 // access texel (i-1) to i instead of i to (i+1), even if the weights should mean the clamped
38 // color is still equal to texel i's value.
39#if defined(SK_USE_SAFE_INSET_FOR_TEXTURE_SAMPLING)
40 inline static constexpr float kInsetEpsilon = 0.0001f;
41#else
42 // A value of 0 means that coordinates for linear filtering will be clamped to exactly 1/2px
43 // inset from the defined data boundary (for approx-fit textures that don't fill to the HW
44 // boundaries). For bottom/right edges this can then access the row or column outside of the
45 // defined data. The filtering weight should be 0, which should be safe for non-floating-point
46 // color types, and not have any impact on the clamped sample. In practice, devices with lower
47 // precision texture coordinates may not actually evaluate with a weight of 0, and it is
48 // caught by Swiftshader+MSAN.
49 inline static constexpr float kInsetEpsilon = 0.f;
50#endif
51
52 inline static constexpr float kLinearInset = 0.5f + kInsetEpsilon;
53
54 /** Make from a filter. The sampler will be configured with clamp mode. */
55 static std::unique_ptr<GrFragmentProcessor> Make(
58 const SkMatrix& = SkMatrix::I(),
61
62 /**
63 * Make from a full GrSamplerState. Caps are required to determine support for kClampToBorder.
64 * This will be emulated in the shader if there is no hardware support.
65 */
66 static std::unique_ptr<GrFragmentProcessor> Make(GrSurfaceProxyView, SkAlphaType,
68 const GrCaps& caps,
69 const float border[4] = kDefaultBorder);
70
71 /**
72 * Makes a texture effect that samples a subset of a texture. The wrap modes of the
73 * GrSampleState are applied to the subset in the shader rather than using HW samplers.
74 * The 'subset' parameter specifies the texels in the base level. The shader code will
75 * avoid allowing linear filtering to read outside the texel window. However, if MIP
76 * filtering is used and a shader invocation reads from a level other than the base
77 * then it may read texel values that were computed from in part from base level texels
78 * outside the window. More specifically, we treat the MIP map case exactly like the
79 * linear case in terms of how the final texture coords are computed. If
80 * alwaysUseShaderTileMode is true then MakeSubset won't attempt to use HW wrap modes if the
81 * subset contains the entire texture.
82 */
83 static std::unique_ptr<GrFragmentProcessor> MakeSubset(GrSurfaceProxyView,
85 const SkMatrix&,
87 const SkRect& subset,
88 const GrCaps& caps,
89 const float border[4] = kDefaultBorder,
90 bool alwaysUseShaderTileMode = false);
91
92 /**
93 * The same as above but also takes a 'domain' that specifies any known limit on the post-
94 * matrix texture coords that will be used to sample the texture. Specifying this requires
95 * knowledge of how this effect will be nested into a paint, the local coords used with the
96 * draw, etc. It is only used to attempt to optimize away the shader subset calculations.
97 */
98 static std::unique_ptr<GrFragmentProcessor> MakeSubset(GrSurfaceProxyView,
100 const SkMatrix&,
102 const SkRect& subset,
103 const SkRect& domain,
104 const GrCaps& caps,
105 const float border[4] = kDefaultBorder);
106
107 /**
108 * Like MakeSubset() but always uses kLinear filtering. MakeSubset() uses the subset rect
109 * dimensions to determine the period of the wrap mode (for repeat and mirror). Once it computes
110 * the wrapped texture coordinate inside subset rect it further clamps it to a 0.5 inset rect of
111 * subset. When subset is an integer rectangle this clamping avoids the hw linear filtering from
112 * reading texels just outside the subset rect. This factory allows a custom inset clamping
113 * distance rather than 0.5, allowing those neighboring texels to influence the linear filtering
114 * sample result. If there is a known restriction on the post-matrix texture coords it can be
115 * specified using domain.
116 */
117 static std::unique_ptr<GrFragmentProcessor> MakeCustomLinearFilterInset(
120 const SkMatrix&,
123 const SkRect& subset,
124 const SkRect* domain,
126 const GrCaps& caps,
127 const float border[4] = kDefaultBorder);
128
129 std::unique_ptr<GrFragmentProcessor> clone() const override;
130
131 const char* name() const override { return "TextureEffect"; }
132
133 GrSamplerState samplerState() const { return fSamplerState; }
134
135 GrTexture* texture() const { return fView.asTextureProxy()->peekTexture(); }
136
137 const GrSurfaceProxyView& view() const { return fView; }
138
139 // Gets a matrix that is concat'ed by wrapping GrMatrixEffect that handles y-flip and coord
140 // normalization if required. This matrix is not always known when we make the GrTextureEffect
141 // because of fully-lazy proxies. Hence, this method exists to allow this concat to happen
142 // after proxy instantiation with coordination from GrMatrixEffect.
144
145 class Impl : public ProgramImpl {
146 public:
147 void emitCode(EmitArgs&) override;
148
150 fSamplerHandle = handle;
151 }
152
153 private:
154 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
155
156 UniformHandle fSubsetUni;
157 UniformHandle fClampUni;
158 UniformHandle fIDimsUni;
159 UniformHandle fBorderUni;
161 };
162
163private:
164 struct Sampling;
165
166 /**
167 * Possible implementation of wrap mode in shader code. Some modes are specialized by
168 * filter.
169 */
170 enum class ShaderMode : uint16_t {
171 kNone, // Using HW mode
172 kClamp, // Shader based clamp, no filter specialization
173 kRepeat_Nearest_None, // Simple repeat for nearest sampling, no mipmapping
174 kRepeat_Linear_None, // Filter the subset boundary for kRepeat mode, no mip mapping
175 kRepeat_Linear_Mipmap, // Logic for linear filtering and LOD selection with kRepeat mode.
176 kRepeat_Nearest_Mipmap, // Logic for nearest filtering and LOD selection with kRepeat mode.
177 kMirrorRepeat, // Mirror repeat (doesn't depend on filter))
178 kClampToBorder_Nearest, // Logic for hard transition to border color when not filtering.
179 kClampToBorder_Filter, // Logic for fading to border color when filtering.
180 };
181 static ShaderMode GetShaderMode(GrSamplerState::WrapMode,
184 static bool ShaderModeIsClampToBorder(ShaderMode);
185 // To keep things a little simpler, when we have filtering logic in the shader we
186 // operate on unnormalized texture coordinates. We will add a uniform that stores
187 // {1/w, 1/h} in a float2 and normalizes after the mode is handled if the texture
188 // is not rectangle.
189 static bool ShaderModeRequiresUnormCoord(ShaderMode);
190
191 GrSurfaceProxyView fView;
192 GrSamplerState fSamplerState;
193 float fBorder[4];
194 SkRect fSubset;
195 SkRect fClamp;
196 ShaderMode fShaderModes[2];
197
198 inline GrTextureEffect(GrSurfaceProxyView, SkAlphaType, const Sampling&);
199
200 explicit GrTextureEffect(const GrTextureEffect& src);
201
202 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override;
203
204 void onAddToKey(const GrShaderCaps&, skgpu::KeyBuilder*) const override;
205
206 bool onIsEqual(const GrFragmentProcessor&) const override;
207
208 bool matrixEffectShouldNormalize() const;
209
210 bool hasClampToBorderShaderMode() const {
211 return ShaderModeIsClampToBorder(fShaderModes[0]) ||
212 ShaderModeIsClampToBorder(fShaderModes[1]);
213 }
214
216
218};
219#endif
#define GR_DECLARE_FRAGMENT_PROCESSOR_TEST
SkAlphaType
Definition: SkAlphaType.h:26
#define INHERITED(method,...)
Definition: SkRecorder.cpp:128
SkFilterMode
SkMipmapMode
Definition: GrCaps.h:57
GrGLSLUniformHandler::UniformHandle UniformHandle
GrFragmentProcessor(ClassID classID, OptimizationFlags optimizationFlags)
GrGLSLUniformHandler::SamplerHandle SamplerHandle
GrTextureProxy * asTextureProxy() const
GrTexture * peekTexture() const
void emitCode(EmitArgs &) override
void setSamplerHandle(GrGLSLShaderBuilder::SamplerHandle handle)
static constexpr float kInsetEpsilon
static std::unique_ptr< GrFragmentProcessor > MakeCustomLinearFilterInset(GrSurfaceProxyView, SkAlphaType, const SkMatrix &, GrSamplerState::WrapMode wx, GrSamplerState::WrapMode wy, const SkRect &subset, const SkRect *domain, SkVector inset, const GrCaps &caps, const float border[4]=kDefaultBorder)
const char * name() const override
const GrSurfaceProxyView & view() const
static std::unique_ptr< GrFragmentProcessor > MakeSubset(GrSurfaceProxyView, SkAlphaType, const SkMatrix &, GrSamplerState, const SkRect &subset, const GrCaps &caps, const float border[4]=kDefaultBorder, bool alwaysUseShaderTileMode=false)
SkMatrix coordAdjustmentMatrix() const
static constexpr float kLinearInset
static constexpr float kDefaultBorder[4]
GrTexture * texture() const
std::unique_ptr< GrFragmentProcessor > clone() const override
GrSamplerState samplerState() const
static std::unique_ptr< GrFragmentProcessor > Make(GrSurfaceProxyView, SkAlphaType, const SkMatrix &=SkMatrix::I(), GrSamplerState::Filter=GrSamplerState::Filter::kNearest, GrSamplerState::MipmapMode mipmapMode=GrSamplerState::MipmapMode::kNone)
static const SkMatrix & I()
Definition: SkMatrix.cpp:1544
Definition: GpuTools.h:21
static SkRect inset(const SkRect &r)