blob: 3fd39c560ae8a04f0d6103d1ea5ec302d90d70ef [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@google.comac10a2d2010-12-22 21:39:39 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2010 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
reed@google.comac10a2d2010-12-22 21:39:39 +00007 */
8
9
epoger@google.comec3ed6a2011-07-28 14:26:00 +000010
reed@google.comac10a2d2010-12-22 21:39:39 +000011#ifndef GrSamplerState_DEFINED
12#define GrSamplerState_DEFINED
13
tomhudson@google.com07eecdc2012-04-20 18:35:38 +000014#include "GrCustomStage.h"
bsalomon@google.comc6cf7232011-02-17 16:43:10 +000015#include "GrMatrix.h"
tomhudson@google.com07eecdc2012-04-20 18:35:38 +000016#include "GrTypes.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000017
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +000018#define MAX_KERNEL_WIDTH 25
19
reed@google.comac10a2d2010-12-22 21:39:39 +000020class GrSamplerState {
21public:
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000022 enum Filter {
23 /**
24 * Read the closest src texel to the sample position
25 */
26 kNearest_Filter,
27 /**
28 * Blend between closest 4 src texels to sample position (tent filter)
29 */
30 kBilinear_Filter,
31 /**
32 * Average of 4 bilinear filterings spaced +/- 1 texel from sample
33 * position in x and y. Intended for averaging 16 texels in a downsample
34 * pass. (rasterizing such that texture samples fall exactly halfway
bsalomon@google.com1f221a72011-08-23 20:54:07 +000035 * between texels in x and y spaced 4 texels apart.) Only supported
36 * on shader backends.
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000037 */
38 k4x4Downsample_Filter,
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +000039 /**
40 * Apply a separable convolution kernel.
41 */
bsalomon@google.comaa814fe2011-12-12 18:45:07 +000042 kConvolution_Filter,
senorblanco@chromium.org05054f12012-03-02 21:05:45 +000043 /**
44 * Apply a dilate filter (max over a 1D radius).
45 */
46 kDilate_Filter,
47 /**
48 * Apply an erode filter (min over a 1D radius).
49 */
50 kErode_Filter,
bsalomon@google.comaa814fe2011-12-12 18:45:07 +000051
52 kDefault_Filter = kNearest_Filter
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000053 };
54
bsalomon@google.comc6cf7232011-02-17 16:43:10 +000055 /**
56 * The intepretation of the texture matrix depends on the sample mode. The
57 * texture matrix is applied both when the texture coordinates are explicit
58 * and when vertex positions are used as texture coordinates. In the latter
59 * case the texture matrix is applied to the pre-view-matrix position
60 * values.
61 *
62 * kNormal_SampleMode
63 * The post-matrix texture coordinates are in normalize space with (0,0) at
64 * the top-left and (1,1) at the bottom right.
65 * kRadial_SampleMode
66 * The matrix specifies the radial gradient parameters.
67 * (0,0) in the post-matrix space is center of the radial gradient.
68 * kRadial2_SampleMode
69 * Matrix transforms to space where first circle is centered at the
70 * origin. The second circle will be centered (x, 0) where x may be
71 * 0 and is provided by setRadial2Params. The post-matrix space is
72 * normalized such that 1 is the second radius - first radius.
73 * kSweepSampleMode
74 * The angle from the origin of texture coordinates in post-matrix space
75 * determines the gradient value.
76 */
reed@google.comac10a2d2010-12-22 21:39:39 +000077 enum SampleMode {
78 kNormal_SampleMode, //!< sample color directly
reed@google.comac10a2d2010-12-22 21:39:39 +000079 kRadial_SampleMode, //!< treat as radial gradient
80 kRadial2_SampleMode, //!< treat as 2-point radial gradient
81 kSweep_SampleMode, //!< treat as sweep gradient
bsalomon@google.comaa814fe2011-12-12 18:45:07 +000082
83 kDefault_SampleMode = kNormal_SampleMode
reed@google.comac10a2d2010-12-22 21:39:39 +000084 };
85
86 /**
87 * Describes how a texture is sampled when coordinates are outside the
88 * texture border
89 */
90 enum WrapMode {
91 kClamp_WrapMode,
92 kRepeat_WrapMode,
bsalomon@google.comaa814fe2011-12-12 18:45:07 +000093 kMirror_WrapMode,
94
95 kDefault_WrapMode = kClamp_WrapMode
reed@google.comac10a2d2010-12-22 21:39:39 +000096 };
97
98 /**
senorblanco@chromium.org05054f12012-03-02 21:05:45 +000099 * For the filters which perform more than one texture sample (convolution,
100 * erode, dilate), this determines the direction in which the texture
101 * coordinates will be incremented.
102 */
103 enum FilterDirection {
104 kX_FilterDirection,
105 kY_FilterDirection,
106
107 kDefault_FilterDirection = kX_FilterDirection,
108 };
109 /**
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000110 * Default sampler state is set to clamp, use normal sampling mode, be
111 * unfiltered, and use identity matrix.
reed@google.comac10a2d2010-12-22 21:39:39 +0000112 */
bsalomon@google.com6aab8e32011-06-21 20:32:12 +0000113 GrSamplerState()
tomhudson@google.comb88bbd22012-05-01 12:48:07 +0000114 : fRadial2CenterX1()
bsalomon@google.com6aab8e32011-06-21 20:32:12 +0000115 , fRadial2Radius0()
tomhudson@google.comb88bbd22012-05-01 12:48:07 +0000116 , fRadial2PosRoot()
117 , fCustomStage (NULL) {
bsalomon@google.com97912912011-12-06 16:30:36 +0000118 this->reset();
reed@google.comac10a2d2010-12-22 21:39:39 +0000119 }
120
tomhudson@google.com07eecdc2012-04-20 18:35:38 +0000121 ~GrSamplerState() {
122 GrSafeUnref(fCustomStage);
123 }
124
tomhudson@google.com02b1ea22012-04-30 20:19:07 +0000125 bool operator ==(const GrSamplerState& s) const {
tomhudson@google.comb88bbd22012-05-01 12:48:07 +0000126 /* We must be bit-identical as far as the CustomStage;
127 there may be multiple CustomStages that will produce
128 the same shader code and so are equivalent.
129 Can't take the address of fWrapX because it's :8 */
130 int bitwiseRegion = (intptr_t) &fCustomStage - (intptr_t) this;
131 GrAssert(sizeof(GrSamplerState) ==
132 bitwiseRegion + sizeof(fCustomStage));
133 return !memcmp(this, &s, bitwiseRegion) &&
134 ((fCustomStage == s.fCustomStage) ||
135 (fCustomStage && s.fCustomStage &&
136 (fCustomStage->getGLFactory() ==
137 s.fCustomStage->getGLFactory()) &&
138 fCustomStage->isEquivalent(s.fCustomStage)));
tomhudson@google.com02b1ea22012-04-30 20:19:07 +0000139 }
140 bool operator !=(const GrSamplerState& s) const { return !(*this == s); }
141
142 GrSamplerState& operator =(const GrSamplerState s) {
143 memcpy(this, &s, sizeof(GrSamplerState));
144 return *this;
145 }
146
reed@google.comac10a2d2010-12-22 21:39:39 +0000147 WrapMode getWrapX() const { return fWrapX; }
148 WrapMode getWrapY() const { return fWrapY; }
senorblanco@chromium.org05054f12012-03-02 21:05:45 +0000149 FilterDirection getFilterDirection() const { return fFilterDirection; }
reed@google.comac10a2d2010-12-22 21:39:39 +0000150 SampleMode getSampleMode() const { return fSampleMode; }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000151 const GrMatrix& getMatrix() const { return fMatrix; }
junov@google.com6acc9b32011-05-16 18:32:07 +0000152 const GrRect& getTextureDomain() const { return fTextureDomain; }
senorblanco@chromium.org64cc5792011-05-19 19:58:58 +0000153 bool hasTextureDomain() const {return SkIntToScalar(0) != fTextureDomain.right();}
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000154 Filter getFilter() const { return fFilter; }
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000155 int getKernelWidth() const { return fKernelWidth; }
156 const float* getKernel() const { return fKernel; }
bsalomon@google.com0a97be22011-11-08 19:20:57 +0000157 bool swapsRAndB() const { return fSwapRAndB; }
reed@google.comac10a2d2010-12-22 21:39:39 +0000158
159 bool isGradient() const {
160 return kRadial_SampleMode == fSampleMode ||
161 kRadial2_SampleMode == fSampleMode ||
162 kSweep_SampleMode == fSampleMode;
163 }
164
165 void setWrapX(WrapMode mode) { fWrapX = mode; }
166 void setWrapY(WrapMode mode) { fWrapY = mode; }
167 void setSampleMode(SampleMode mode) { fSampleMode = mode; }
senorblanco@chromium.org05054f12012-03-02 21:05:45 +0000168 void setFilterDirection(FilterDirection mode) { fFilterDirection = mode; }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000169
170 /**
bsalomon@google.comaa814fe2011-12-12 18:45:07 +0000171 * Access the sampler's matrix. See SampleMode for explanation of
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000172 * relationship between the matrix and sample mode.
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000173 */
bsalomon@google.comaa814fe2011-12-12 18:45:07 +0000174 GrMatrix* matrix() { return &fMatrix; }
175
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000176 /**
junov@google.com6acc9b32011-05-16 18:32:07 +0000177 * Sets the sampler's texture coordinate domain to a
178 * custom rectangle, rather than the default (0,1).
179 * This option is currently only supported with kClamp_WrapMode
180 */
181 void setTextureDomain(const GrRect& textureDomain) { fTextureDomain = textureDomain; }
182
183 /**
bsalomon@google.com0a97be22011-11-08 19:20:57 +0000184 * Swaps the R and B components when reading from the texture. Has no effect
185 * if the texture is alpha only.
186 */
187 void setRAndBSwap(bool swap) { fSwapRAndB = swap; }
188
189 /**
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000190 * Multiplies the current sampler matrix a matrix
191 *
192 * After this call M' = M*m where M is the old matrix, m is the parameter
193 * to this function, and M' is the new matrix. (We consider points to
194 * be column vectors so tex cood vector t is transformed by matrix X as
195 * t' = X*t.)
196 *
197 * @param matrix the matrix used to modify the matrix.
198 */
199 void preConcatMatrix(const GrMatrix& matrix) { fMatrix.preConcat(matrix); }
200
201 /**
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000202 * Sets filtering type.
203 * @param filter type of filtering to apply
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000204 */
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000205 void setFilter(Filter filter) { fFilter = filter; }
reed@google.comac10a2d2010-12-22 21:39:39 +0000206
bsalomon@google.com97912912011-12-06 16:30:36 +0000207 void reset(WrapMode wrapXAndY,
208 Filter filter,
senorblanco@chromium.org05054f12012-03-02 21:05:45 +0000209 FilterDirection direction,
bsalomon@google.com97912912011-12-06 16:30:36 +0000210 const GrMatrix& matrix) {
211 fWrapX = wrapXAndY;
212 fWrapY = wrapXAndY;
bsalomon@google.comaa814fe2011-12-12 18:45:07 +0000213 fSampleMode = kDefault_SampleMode;
bsalomon@google.com97912912011-12-06 16:30:36 +0000214 fFilter = filter;
senorblanco@chromium.org05054f12012-03-02 21:05:45 +0000215 fFilterDirection = direction;
bsalomon@google.com97912912011-12-06 16:30:36 +0000216 fMatrix = matrix;
217 fTextureDomain.setEmpty();
218 fSwapRAndB = false;
tomhudson@google.com07eecdc2012-04-20 18:35:38 +0000219 GrSafeSetNull(fCustomStage);
bsalomon@google.com97912912011-12-06 16:30:36 +0000220 }
senorblanco@chromium.org05054f12012-03-02 21:05:45 +0000221 void reset(WrapMode wrapXAndY, Filter filter, const GrMatrix& matrix) {
222 this->reset(wrapXAndY, filter, kDefault_FilterDirection, matrix);
223 }
bsalomon@google.comaa814fe2011-12-12 18:45:07 +0000224 void reset(WrapMode wrapXAndY,
225 Filter filter) {
senorblanco@chromium.org05054f12012-03-02 21:05:45 +0000226 this->reset(wrapXAndY, filter, kDefault_FilterDirection, GrMatrix::I());
bsalomon@google.comaa814fe2011-12-12 18:45:07 +0000227 }
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000228 void reset(const GrMatrix& matrix) {
senorblanco@chromium.org05054f12012-03-02 21:05:45 +0000229 this->reset(kDefault_WrapMode, kDefault_Filter, kDefault_FilterDirection, matrix);
bsalomon@google.comaa814fe2011-12-12 18:45:07 +0000230 }
231 void reset() {
senorblanco@chromium.org05054f12012-03-02 21:05:45 +0000232 this->reset(kDefault_WrapMode, kDefault_Filter, kDefault_FilterDirection, GrMatrix::I());
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000233 }
bsalomon@google.com97912912011-12-06 16:30:36 +0000234
reed@google.comac10a2d2010-12-22 21:39:39 +0000235 GrScalar getRadial2CenterX1() const { return fRadial2CenterX1; }
236 GrScalar getRadial2Radius0() const { return fRadial2Radius0; }
bsalomon@google.come7160bf2011-11-10 15:28:16 +0000237 bool isRadial2PosRoot() const { return SkToBool(fRadial2PosRoot); }
bsalomon@google.com22c5dea2011-07-07 14:38:03 +0000238 // do the radial gradient params lead to a linear (rather than quadratic)
239 // equation.
240 bool radial2IsDegenerate() const { return GR_Scalar1 == fRadial2CenterX1; }
reed@google.comac10a2d2010-12-22 21:39:39 +0000241
242 /**
bsalomon@google.com5782d712011-01-21 21:03:59 +0000243 * Sets the parameters for kRadial2_SampleMode. The texture
244 * matrix must be set so that the first point is at (0,0) and the second
reed@google.comac10a2d2010-12-22 21:39:39 +0000245 * point lies on the x-axis. The second radius minus the first is 1 unit.
246 * The additional parameters to define the gradient are specified by this
247 * function.
248 */
249 void setRadial2Params(GrScalar centerX1, GrScalar radius0, bool posRoot) {
250 fRadial2CenterX1 = centerX1;
251 fRadial2Radius0 = radius0;
252 fRadial2PosRoot = posRoot;
253 }
254
senorblanco@chromium.org05054f12012-03-02 21:05:45 +0000255 void setConvolutionParams(int kernelWidth, const float* kernel) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000256 GrAssert(kernelWidth >= 0 && kernelWidth <= MAX_KERNEL_WIDTH);
257 fKernelWidth = kernelWidth;
258 if (NULL != kernel) {
259 memcpy(fKernel, kernel, kernelWidth * sizeof(float));
260 }
senorblanco@chromium.org05054f12012-03-02 21:05:45 +0000261 }
262
263 void setMorphologyRadius(int radius) {
264 GrAssert(radius >= 0 && radius <= MAX_KERNEL_WIDTH);
265 fKernelWidth = radius;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000266 }
267
tomhudson@google.com07eecdc2012-04-20 18:35:38 +0000268 void setCustomStage(GrCustomStage* stage) {
269 GrSafeAssign(fCustomStage, stage);
270 }
271 GrCustomStage* getCustomStage() const { return fCustomStage; }
272
reed@google.comac10a2d2010-12-22 21:39:39 +0000273private:
senorblanco@chromium.org05054f12012-03-02 21:05:45 +0000274 WrapMode fWrapX : 8;
275 WrapMode fWrapY : 8;
276 FilterDirection fFilterDirection : 8;
277 SampleMode fSampleMode : 8;
278 Filter fFilter : 8;
279 GrMatrix fMatrix;
280 bool fSwapRAndB;
281 GrRect fTextureDomain;
reed@google.comac10a2d2010-12-22 21:39:39 +0000282
283 // these are undefined unless fSampleMode == kRadial2_SampleMode
senorblanco@chromium.org05054f12012-03-02 21:05:45 +0000284 GrScalar fRadial2CenterX1;
285 GrScalar fRadial2Radius0;
286 SkBool8 fRadial2PosRoot;
reed@google.comac10a2d2010-12-22 21:39:39 +0000287
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000288 // These are undefined unless fFilter == kConvolution_Filter
senorblanco@chromium.org05054f12012-03-02 21:05:45 +0000289 uint8_t fKernelWidth;
290 float fKernel[MAX_KERNEL_WIDTH];
tomhudson@google.com02b1ea22012-04-30 20:19:07 +0000291
292 /// BUG! Ganesh only works correctly so long as fCustomStage is
293 /// NULL; we need to have a complex ID system here so that we can
294 /// have an equality-like comparison to determine whether two
295 /// fCustomStages are equal.
296 GrCustomStage* fCustomStage;
reed@google.comac10a2d2010-12-22 21:39:39 +0000297};
298
299#endif
300