blob: ae8184029f05da0d9c72a1b76640129189d1b00f [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
bsalomon@google.comd302f142011-03-03 13:54:13 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 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.
bsalomon@google.comd302f142011-03-03 13:54:13 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
bsalomon@google.comd302f142011-03-03 13:54:13 +000010#ifndef GrStencil_DEFINED
11#define GrStencil_DEFINED
12
13#include "GrTypes.h"
14/**
15 * Gr uses the stencil buffer to implement complex clipping inside the
16 * GrDrawTarget class. The GrDrawTarget makes a subset of the stencil buffer
17 * bits available for other uses by external code (clients). Client code can
18 * modify these bits. GrDrawTarget will ignore ref, mask, and writemask bits
bsalomon@google.comdea2f8d2011-08-01 15:51:05 +000019 * provided by clients that overlap the bits used to implement clipping.
bsalomon@google.comd302f142011-03-03 13:54:13 +000020 *
21 * When code outside the GrDrawTarget class uses the stencil buffer the contract
22 * is as follows:
23 *
bsalomon@google.comdea2f8d2011-08-01 15:51:05 +000024 * > Normal stencil funcs allow the client to pass / fail regardless of the
25 * reserved clip bits.
26 * > Additional functions allow a test against the clip along with a limited
27 * set of tests against the client bits.
bsalomon@google.comd302f142011-03-03 13:54:13 +000028 * > Client can assume all client bits are zero initially.
29 * > Client must ensure that after all its passes are finished it has only
30 * written to the color buffer in the region inside the clip. Furthermore, it
31 * must zero all client bits that were modifed (both inside and outside the
32 * clip).
33 */
34
35/**
36 * Determines which pixels pass / fail the stencil test.
37 * Stencil test passes if (ref & mask) FUNC (stencil & mask) is true
38 */
39enum GrStencilFunc {
40 kAlways_StencilFunc = 0,
41 kNever_StencilFunc,
42 kGreater_StencilFunc,
43 kGEqual_StencilFunc,
44 kLess_StencilFunc,
45 kLEqual_StencilFunc,
46 kEqual_StencilFunc,
47 kNotEqual_StencilFunc,
48
49 // Gr stores the current clip in the
50 // stencil buffer in the high bits that
51 // are not directly accessible modifiable
52 // via the GrDrawTarget interface. The below
53 // stencil funcs test against the current
54 // clip in addition to the GrDrawTarget
55 // client's stencil bits.
56
57 // pass if inside the clip
58 kAlwaysIfInClip_StencilFunc,
59 kEqualIfInClip_StencilFunc,
60 kLessIfInClip_StencilFunc,
61 kLEqualIfInClip_StencilFunc,
62 kNonZeroIfInClip_StencilFunc, // this one forces the ref to be 0
63
64 // counts
65 kStencilFuncCount,
66 kClipStencilFuncCount = kNonZeroIfInClip_StencilFunc -
67 kAlwaysIfInClip_StencilFunc + 1,
68 kBasicStencilFuncCount = kStencilFuncCount - kClipStencilFuncCount
69};
70
71/**
72 * Operations to perform based on whether stencil test passed failed.
73 */
74enum GrStencilOp {
75 kKeep_StencilOp = 0, // preserve existing stencil value
76 kReplace_StencilOp, // replace with reference value from stencl test
77 kIncWrap_StencilOp, // increment and wrap at max
78 kIncClamp_StencilOp, // increment and clamp at max
79 kDecWrap_StencilOp, // decrement and wrap at 0
80 kDecClamp_StencilOp, // decrement and clamp at 0
81 kZero_StencilOp, // zero stencil bits
82 kInvert_StencilOp, // invert stencil bits
83
84 kStencilOpCount
85};
86
87/**
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000088 * GrStencilState needs to be a class with accessors and setters so that it
89 * can maintain flags related to its current state. However, we also want to
90 * be able to declare pre-made stencil settings at compile time (without
91 * inserting static initializer code). So all the data members are in this
92 * struct. A macro defined after the class can be used to jam an instance of
93 * this struct that is created from an initializer list into a
94 * GrStencilSettings. (We hang our heads in shame.)
bsalomon@google.comd302f142011-03-03 13:54:13 +000095 */
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000096struct GrStencilSettingsStruct {
tomhudson@google.com62b09682011-11-09 16:39:17 +000097 GrStencilOp fFrontPassOp : 8; // op to perform when front faces pass
98 GrStencilOp fBackPassOp : 8; // op to perform when back faces pass
99 GrStencilOp fFrontFailOp : 8; // op to perform when front faces fail
100 GrStencilOp fBackFailOp : 8; // op to perform when back faces fail
101 GrStencilFunc fFrontFunc : 8; // test function for front faces
102 GrStencilFunc fBackFunc : 8; // test function for back faces
bsalomon@google.com39dab772012-01-03 19:39:31 +0000103 int fPad0 : 8;
104 int fPad1 : 8;
tomhudson@google.com62b09682011-11-09 16:39:17 +0000105 unsigned short fFrontFuncMask; // mask for front face test
106 unsigned short fBackFuncMask; // mask for back face test
107 unsigned short fFrontFuncRef; // reference value for front face test
108 unsigned short fBackFuncRef; // reference value for back face test
109 unsigned short fFrontWriteMask; // stencil write mask for front faces
110 unsigned short fBackWriteMask; // stencil write mask for back faces
bsalomon@google.com39dab772012-01-03 19:39:31 +0000111 mutable uint32_t fFlags;
bsalomon@google.com6b2445e2011-12-15 19:47:46 +0000112};
bsalomon@google.com39dab772012-01-03 19:39:31 +0000113// We rely on this being packed and aligned (memcmp'ed and memcpy'ed)
114GR_STATIC_ASSERT(sizeof(GrStencilSettingsStruct) % 4 == 0);
115GR_STATIC_ASSERT(sizeof(GrStencilSettingsStruct) ==
116 4*sizeof(uint8_t) + // ops
117 2*sizeof(uint8_t) + // funcs
118 2*sizeof(uint8_t) + // pads
119 2*sizeof(unsigned short) + // func masks
120 2*sizeof(unsigned short) + // ref values
121 2*sizeof(unsigned short) + // write masks
122 sizeof(uint32_t)); // flags
bsalomon@google.comd302f142011-03-03 13:54:13 +0000123
bsalomon@google.com6b2445e2011-12-15 19:47:46 +0000124/**
125 * Class representing stencil state.
126 */
127class GrStencilSettings : private GrStencilSettingsStruct {
128
129public:
bsalomon@google.com39dab772012-01-03 19:39:31 +0000130 GrStencilSettings() {
131 fPad0 = fPad1 = 0;
132 this->setDisabled();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000133 }
bsalomon@google.com39dab772012-01-03 19:39:31 +0000134
bsalomon@google.com6b2445e2011-12-15 19:47:46 +0000135 GrStencilOp frontPassOp() const { return fFrontPassOp; }
136 GrStencilOp backPassOp() const { return fBackPassOp; }
137 GrStencilOp frontFailOp() const { return fFrontFailOp; }
138 GrStencilOp backFailOp() const { return fBackFailOp; }
139 GrStencilFunc frontFunc() const { return fFrontFunc; }
140 GrStencilFunc backFunc() const { return fBackFunc; }
141 unsigned short frontFuncMask() const { return fFrontFuncMask; }
142 unsigned short backFuncMask() const { return fBackFuncMask; }
143 unsigned short frontFuncRef() const { return fFrontFuncRef; }
144 unsigned short backFuncRef() const { return fBackFuncRef; }
145 unsigned short frontWriteMask() const {return fFrontWriteMask; }
146 unsigned short backWriteMask() const { return fBackWriteMask; }
147
bsalomon@google.com39dab772012-01-03 19:39:31 +0000148 void setFrontPassOp(GrStencilOp op) { fFrontPassOp = op; fFlags = 0;}
149 void setBackPassOp(GrStencilOp op) { fBackPassOp = op; fFlags = 0;}
150 void setFrontFailOp(GrStencilOp op) {fFrontFailOp = op; fFlags = 0;}
151 void setBackFailOp(GrStencilOp op) { fBackFailOp = op; fFlags = 0;}
152 void setFrontFunc(GrStencilFunc func) { fFrontFunc = func; fFlags = 0;}
153 void setBackFunc(GrStencilFunc func) { fBackFunc = func; fFlags = 0;}
bsalomon@google.com6b2445e2011-12-15 19:47:46 +0000154 void setFrontFuncMask(unsigned short mask) { fFrontFuncMask = mask; }
155 void setBackFuncMask(unsigned short mask) { fBackFuncMask = mask; }
156 void setFrontFuncRef(unsigned short ref) { fFrontFuncRef = ref; }
157 void setBackFuncRef(unsigned short ref) { fBackFuncRef = ref; }
158 void setFrontWriteMask(unsigned short writeMask) { fFrontWriteMask = writeMask; }
159 void setBackWriteMask(unsigned short writeMask) { fBackWriteMask = writeMask; }
160
bsalomon@google.comd302f142011-03-03 13:54:13 +0000161 void setSame(GrStencilOp passOp,
162 GrStencilOp failOp,
163 GrStencilFunc func,
tomhudson@google.com62b09682011-11-09 16:39:17 +0000164 unsigned short funcMask,
165 unsigned short funcRef,
166 unsigned short writeMask) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000167 fFrontPassOp = passOp;
168 fBackPassOp = passOp;
169 fFrontFailOp = failOp;
170 fBackFailOp = failOp;
171 fFrontFunc = func;
172 fBackFunc = func;
173 fFrontFuncMask = funcMask;
174 fBackFuncMask = funcMask;
175 fFrontFuncRef = funcRef;
176 fBackFuncRef = funcRef;
177 fFrontWriteMask = writeMask;
178 fBackWriteMask = writeMask;
bsalomon@google.com39dab772012-01-03 19:39:31 +0000179 fFlags = 0;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000180 }
181
bsalomon@google.comd302f142011-03-03 13:54:13 +0000182 void setDisabled() {
bsalomon@google.com6b2445e2011-12-15 19:47:46 +0000183 memset(this, 0, sizeof(*this));
184 GR_STATIC_ASSERT(0 == kKeep_StencilOp);
185 GR_STATIC_ASSERT(0 == kAlways_StencilFunc);
bsalomon@google.com39dab772012-01-03 19:39:31 +0000186 fFlags = kIsDisabled_Flag | kDoesNotWrite_Flag;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000187 }
bsalomon@google.com39dab772012-01-03 19:39:31 +0000188
bsalomon@google.comd302f142011-03-03 13:54:13 +0000189 bool isDisabled() const {
bsalomon@google.com39dab772012-01-03 19:39:31 +0000190 if (fFlags & kIsDisabled_Flag) {
191 return true;
192 }
193 if (fFlags & kNotDisabled_Flag) {
194 return false;
195 }
196 bool disabled = kKeep_StencilOp == fFrontPassOp &&
197 kKeep_StencilOp == fBackPassOp &&
198 kKeep_StencilOp == fFrontFailOp &&
199 kKeep_StencilOp == fBackFailOp &&
200 kAlways_StencilFunc == fFrontFunc &&
201 kAlways_StencilFunc == fBackFunc;
202 fFlags |= disabled ? kIsDisabled_Flag : kNotDisabled_Flag;
203 return disabled;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000204 }
bsalomon@google.com39dab772012-01-03 19:39:31 +0000205
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000206 bool doesWrite() const {
bsalomon@google.com39dab772012-01-03 19:39:31 +0000207 if (fFlags & kDoesWrite_Flag) {
208 return true;
209 }
210 if (fFlags & kDoesNotWrite_Flag) {
211 return false;
212 }
213 bool writes = !((kNever_StencilFunc == fFrontFunc ||
214 kKeep_StencilOp == fFrontPassOp) &&
215 (kNever_StencilFunc == fBackFunc ||
216 kKeep_StencilOp == fBackPassOp) &&
217 (kAlways_StencilFunc == fFrontFunc ||
218 kKeep_StencilOp == fFrontFailOp) &&
219 (kAlways_StencilFunc == fBackFunc ||
220 kKeep_StencilOp == fBackFailOp));
221 fFlags |= writes ? kDoesWrite_Flag : kDoesNotWrite_Flag;
222 return writes;
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000223 }
bsalomon@google.com39dab772012-01-03 19:39:31 +0000224
bsalomon@google.comd302f142011-03-03 13:54:13 +0000225 void invalidate() {
bsalomon@google.com39dab772012-01-03 19:39:31 +0000226 // write an illegal value to the first member
tomhudson@google.com62b09682011-11-09 16:39:17 +0000227 fFrontPassOp = (GrStencilOp)(uint8_t)-1;
bsalomon@google.com39dab772012-01-03 19:39:31 +0000228 fFlags = 0;
229 }
230
231 bool operator == (const GrStencilSettings& s) const {
232 static const size_t gCompareSize = sizeof(GrStencilSettings) -
233 sizeof(fFlags);
234 GrAssert((const char*)&fFlags + sizeof(fFlags) ==
235 (const char*)this + sizeof(GrStencilSettings));
236 if (this->isDisabled() & s.isDisabled()) { // using & not &&
237 return true;
238 }
239 return 0 == memcmp(this, &s, gCompareSize);
240 }
241
242 bool operator != (const GrStencilSettings& s) const {
243 return !(*this == s);
244 }
245
246 GrStencilSettings& operator =(const GrStencilSettings& s) {
247 memcpy(this, &s, sizeof(GrStencilSettings));
248 return *this;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000249 }
250
251private:
252 friend class GrGpu;
bsalomon@google.com39dab772012-01-03 19:39:31 +0000253 enum {
254 kIsDisabled_Flag = 0x1,
255 kNotDisabled_Flag = 0x2,
256 kDoesWrite_Flag = 0x4,
257 kDoesNotWrite_Flag = 0x8,
258 };
bsalomon@google.comd302f142011-03-03 13:54:13 +0000259
260 enum {
261 kMaxStencilClipPasses = 2 // maximum number of passes to add a clip
262 // element to the stencil buffer.
263 };
264
265 /**
266 * Given a thing to draw into the stencil clip, a fill type, and a set op
267 * this function determines:
268 * 1. Whether the thing can be draw directly to the stencil clip or
269 * needs to be drawn to the client portion of the stencil first.
270 * 2. How many passes are needed.
271 * 3. What those passes are.
272 * 4. The fill rule that should actually be used to render (will
273 * always be non-inverted).
274 *
275 * @param op the set op to combine this element with the
276 * existing clip
277 * @param stencilClipMask mask with just the stencil bit used for clipping
278 * enabled.
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000279 * @param invertedFill is this path inverted
bsalomon@google.comd302f142011-03-03 13:54:13 +0000280 * @param numPasses out: the number of passes needed to add the
281 * element to the clip.
282 * @param settings out: the stencil settings to use for each pass
283 *
284 * @return true if the clip element's geometry can be drawn directly to the
285 * stencil clip bit. Will only be true if canBeDirect is true.
286 * numPasses will be 1 if return value is true.
287 */
288 static bool GetClipPasses(GrSetOp op,
289 bool canBeDirect,
290 unsigned int stencilClipMask,
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000291 bool invertedFill,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000292 int* numPasses,
293 GrStencilSettings settings[kMaxStencilClipPasses]);
294};
295
bsalomon@google.com6b2445e2011-12-15 19:47:46 +0000296GR_STATIC_ASSERT(sizeof(GrStencilSettingsStruct) == sizeof(GrStencilSettings));
297
298#define GR_STATIC_CONST_STENCIL(NAME, \
299 FRONT_PASS_OP, BACK_PASS_OP, \
300 FRONT_FAIL_OP, BACK_FAIL_OP, \
301 FRONT_FUNC, BACK_FUNC, \
302 FRONT_MASK, BACK_MASK, \
303 FRONT_REF, BACK_REF, \
304 FRONT_WRITE_MASK, BACK_WRITE_MASK) \
305 static const GrStencilSettingsStruct NAME ## _STRUCT = { \
306 (FRONT_PASS_OP), (BACK_PASS_OP), \
307 (FRONT_FAIL_OP), (BACK_FAIL_OP), \
308 (FRONT_FUNC), (BACK_FUNC), \
bsalomon@google.com39dab772012-01-03 19:39:31 +0000309 (0), (0), \
bsalomon@google.com6b2445e2011-12-15 19:47:46 +0000310 (FRONT_MASK), (BACK_MASK), \
311 (FRONT_REF), (BACK_REF), \
bsalomon@google.com39dab772012-01-03 19:39:31 +0000312 (FRONT_WRITE_MASK), (BACK_WRITE_MASK), \
313 0 \
bsalomon@google.com6b2445e2011-12-15 19:47:46 +0000314 }; \
315 static const GrStencilSettings& NAME = \
bsalomon@google.comc315aeb2011-12-15 19:51:05 +0000316 *reinterpret_cast<const GrStencilSettings*>(&(NAME ## _STRUCT))
bsalomon@google.comd302f142011-03-03 13:54:13 +0000317#endif
bsalomon@google.com6b2445e2011-12-15 19:47:46 +0000318
319#define GR_STATIC_CONST_SAME_STENCIL(NAME, \
320 PASS_OP, FAIL_OP, FUNC, MASK, REF, WRITE_MASK) \
321 GR_STATIC_CONST_STENCIL(NAME, (PASS_OP), (PASS_OP), (FAIL_OP), \
322 (FAIL_OP), (FUNC), (FUNC), (MASK), (MASK), (REF), (REF), (WRITE_MASK), \
323 (WRITE_MASK))