blob: bba5aa67bf8859eb23ee0e4bb1394f08f57b10c1 [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"
robertphillips@google.com0f191f32012-04-25 15:23:36 +000014#include "SkRegion.h"
15
bsalomon@google.comd302f142011-03-03 13:54:13 +000016/**
17 * Gr uses the stencil buffer to implement complex clipping inside the
18 * GrDrawTarget class. The GrDrawTarget makes a subset of the stencil buffer
19 * bits available for other uses by external code (clients). Client code can
20 * modify these bits. GrDrawTarget will ignore ref, mask, and writemask bits
bsalomon@google.comdea2f8d2011-08-01 15:51:05 +000021 * provided by clients that overlap the bits used to implement clipping.
bsalomon@google.comd302f142011-03-03 13:54:13 +000022 *
23 * When code outside the GrDrawTarget class uses the stencil buffer the contract
24 * is as follows:
25 *
bsalomon@google.comdea2f8d2011-08-01 15:51:05 +000026 * > Normal stencil funcs allow the client to pass / fail regardless of the
27 * reserved clip bits.
28 * > Additional functions allow a test against the clip along with a limited
29 * set of tests against the client bits.
bsalomon@google.comd302f142011-03-03 13:54:13 +000030 * > Client can assume all client bits are zero initially.
31 * > Client must ensure that after all its passes are finished it has only
32 * written to the color buffer in the region inside the clip. Furthermore, it
33 * must zero all client bits that were modifed (both inside and outside the
34 * clip).
35 */
36
37/**
38 * Determines which pixels pass / fail the stencil test.
39 * Stencil test passes if (ref & mask) FUNC (stencil & mask) is true
40 */
41enum GrStencilFunc {
42 kAlways_StencilFunc = 0,
43 kNever_StencilFunc,
44 kGreater_StencilFunc,
45 kGEqual_StencilFunc,
46 kLess_StencilFunc,
47 kLEqual_StencilFunc,
48 kEqual_StencilFunc,
49 kNotEqual_StencilFunc,
50
51 // Gr stores the current clip in the
52 // stencil buffer in the high bits that
53 // are not directly accessible modifiable
54 // via the GrDrawTarget interface. The below
55 // stencil funcs test against the current
56 // clip in addition to the GrDrawTarget
57 // client's stencil bits.
58
59 // pass if inside the clip
60 kAlwaysIfInClip_StencilFunc,
61 kEqualIfInClip_StencilFunc,
62 kLessIfInClip_StencilFunc,
63 kLEqualIfInClip_StencilFunc,
64 kNonZeroIfInClip_StencilFunc, // this one forces the ref to be 0
65
66 // counts
67 kStencilFuncCount,
68 kClipStencilFuncCount = kNonZeroIfInClip_StencilFunc -
69 kAlwaysIfInClip_StencilFunc + 1,
70 kBasicStencilFuncCount = kStencilFuncCount - kClipStencilFuncCount
71};
72
73/**
74 * Operations to perform based on whether stencil test passed failed.
75 */
76enum GrStencilOp {
77 kKeep_StencilOp = 0, // preserve existing stencil value
78 kReplace_StencilOp, // replace with reference value from stencl test
79 kIncWrap_StencilOp, // increment and wrap at max
80 kIncClamp_StencilOp, // increment and clamp at max
81 kDecWrap_StencilOp, // decrement and wrap at 0
82 kDecClamp_StencilOp, // decrement and clamp at 0
83 kZero_StencilOp, // zero stencil bits
84 kInvert_StencilOp, // invert stencil bits
85
86 kStencilOpCount
87};
88
digit@google.com9b482c42012-02-16 22:03:26 +000089enum GrStencilFlags {
90 kIsDisabled_StencilFlag = 0x1,
91 kNotDisabled_StencilFlag = 0x2,
92 kDoesWrite_StencilFlag = 0x4,
93 kDoesNotWrite_StencilFlag = 0x8,
94};
95
bsalomon@google.comd302f142011-03-03 13:54:13 +000096/**
bsalomon@google.com6b2445e2011-12-15 19:47:46 +000097 * GrStencilState needs to be a class with accessors and setters so that it
98 * can maintain flags related to its current state. However, we also want to
99 * be able to declare pre-made stencil settings at compile time (without
100 * inserting static initializer code). So all the data members are in this
101 * struct. A macro defined after the class can be used to jam an instance of
102 * this struct that is created from an initializer list into a
103 * GrStencilSettings. (We hang our heads in shame.)
bsalomon@google.comd302f142011-03-03 13:54:13 +0000104 */
bsalomon@google.com6b2445e2011-12-15 19:47:46 +0000105struct GrStencilSettingsStruct {
tomhudson@google.com62b09682011-11-09 16:39:17 +0000106 GrStencilOp fFrontPassOp : 8; // op to perform when front faces pass
107 GrStencilOp fBackPassOp : 8; // op to perform when back faces pass
108 GrStencilOp fFrontFailOp : 8; // op to perform when front faces fail
109 GrStencilOp fBackFailOp : 8; // op to perform when back faces fail
110 GrStencilFunc fFrontFunc : 8; // test function for front faces
111 GrStencilFunc fBackFunc : 8; // test function for back faces
bsalomon@google.com39dab772012-01-03 19:39:31 +0000112 int fPad0 : 8;
113 int fPad1 : 8;
tomhudson@google.com62b09682011-11-09 16:39:17 +0000114 unsigned short fFrontFuncMask; // mask for front face test
115 unsigned short fBackFuncMask; // mask for back face test
116 unsigned short fFrontFuncRef; // reference value for front face test
117 unsigned short fBackFuncRef; // reference value for back face test
118 unsigned short fFrontWriteMask; // stencil write mask for front faces
119 unsigned short fBackWriteMask; // stencil write mask for back faces
bsalomon@google.com39dab772012-01-03 19:39:31 +0000120 mutable uint32_t fFlags;
bsalomon@google.com6b2445e2011-12-15 19:47:46 +0000121};
bsalomon@google.com39dab772012-01-03 19:39:31 +0000122// We rely on this being packed and aligned (memcmp'ed and memcpy'ed)
123GR_STATIC_ASSERT(sizeof(GrStencilSettingsStruct) % 4 == 0);
124GR_STATIC_ASSERT(sizeof(GrStencilSettingsStruct) ==
125 4*sizeof(uint8_t) + // ops
126 2*sizeof(uint8_t) + // funcs
127 2*sizeof(uint8_t) + // pads
128 2*sizeof(unsigned short) + // func masks
129 2*sizeof(unsigned short) + // ref values
130 2*sizeof(unsigned short) + // write masks
131 sizeof(uint32_t)); // flags
bsalomon@google.comd302f142011-03-03 13:54:13 +0000132
digit@google.com9b482c42012-02-16 22:03:26 +0000133// This macro is used to compute the GrStencilSettingsStructs flags
134// associated to disabling. It is used both to define constant structure
135// initializers and inside GrStencilSettings::isDisabled()
136//
137#define GR_STENCIL_SETTINGS_IS_DISABLED( \
138 FRONT_PASS_OP, BACK_PASS_OP, \
139 FRONT_FAIL_OP, BACK_FAIL_OP, \
140 FRONT_FUNC, BACK_FUNC) \
141 ((FRONT_PASS_OP) == kKeep_StencilOp && \
142 (BACK_PASS_OP) == kKeep_StencilOp && \
143 (FRONT_FAIL_OP) == kKeep_StencilOp && \
144 (BACK_FAIL_OP) == kKeep_StencilOp && \
145 (FRONT_FUNC) == kAlways_StencilFunc && \
146 (BACK_FUNC) == kAlways_StencilFunc)
147
148#define GR_STENCIL_SETTINGS_DOES_WRITE( \
149 FRONT_PASS_OP, BACK_PASS_OP, \
150 FRONT_FAIL_OP, BACK_FAIL_OP, \
151 FRONT_FUNC, BACK_FUNC) \
152 (!(((FRONT_FUNC) == kNever_StencilFunc || \
153 (FRONT_PASS_OP) == kKeep_StencilOp) && \
154 ((BACK_FUNC) == kNever_StencilFunc || \
155 (BACK_PASS_OP) == kKeep_StencilOp) && \
156 ((FRONT_FUNC) == kAlways_StencilFunc || \
157 (FRONT_FAIL_OP) == kKeep_StencilOp) && \
158 ((BACK_FUNC) == kAlways_StencilFunc || \
159 (BACK_FAIL_OP) == kKeep_StencilOp)))
160
161#define GR_STENCIL_SETTINGS_DEFAULT_FLAGS( \
162 FRONT_PASS_OP, BACK_PASS_OP, \
163 FRONT_FAIL_OP, BACK_FAIL_OP, \
164 FRONT_FUNC, BACK_FUNC) \
165 ((GR_STENCIL_SETTINGS_IS_DISABLED(FRONT_PASS_OP,BACK_PASS_OP, \
166 FRONT_FAIL_OP,BACK_FAIL_OP,FRONT_FUNC,BACK_FUNC) ? \
167 kIsDisabled_StencilFlag : kNotDisabled_StencilFlag) | \
168 (GR_STENCIL_SETTINGS_DOES_WRITE(FRONT_PASS_OP,BACK_PASS_OP, \
169 FRONT_FAIL_OP,BACK_FAIL_OP,FRONT_FUNC,BACK_FUNC) ? \
170 kDoesWrite_StencilFlag : kDoesNotWrite_StencilFlag))
171
bsalomon@google.com6b2445e2011-12-15 19:47:46 +0000172/**
173 * Class representing stencil state.
174 */
175class GrStencilSettings : private GrStencilSettingsStruct {
176
177public:
bsalomon@google.com39dab772012-01-03 19:39:31 +0000178 GrStencilSettings() {
179 fPad0 = fPad1 = 0;
180 this->setDisabled();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000181 }
bsalomon@google.com39dab772012-01-03 19:39:31 +0000182
bsalomon@google.com6b2445e2011-12-15 19:47:46 +0000183 GrStencilOp frontPassOp() const { return fFrontPassOp; }
184 GrStencilOp backPassOp() const { return fBackPassOp; }
185 GrStencilOp frontFailOp() const { return fFrontFailOp; }
186 GrStencilOp backFailOp() const { return fBackFailOp; }
187 GrStencilFunc frontFunc() const { return fFrontFunc; }
188 GrStencilFunc backFunc() const { return fBackFunc; }
189 unsigned short frontFuncMask() const { return fFrontFuncMask; }
190 unsigned short backFuncMask() const { return fBackFuncMask; }
191 unsigned short frontFuncRef() const { return fFrontFuncRef; }
192 unsigned short backFuncRef() const { return fBackFuncRef; }
193 unsigned short frontWriteMask() const {return fFrontWriteMask; }
194 unsigned short backWriteMask() const { return fBackWriteMask; }
195
bsalomon@google.com39dab772012-01-03 19:39:31 +0000196 void setFrontPassOp(GrStencilOp op) { fFrontPassOp = op; fFlags = 0;}
197 void setBackPassOp(GrStencilOp op) { fBackPassOp = op; fFlags = 0;}
198 void setFrontFailOp(GrStencilOp op) {fFrontFailOp = op; fFlags = 0;}
199 void setBackFailOp(GrStencilOp op) { fBackFailOp = op; fFlags = 0;}
200 void setFrontFunc(GrStencilFunc func) { fFrontFunc = func; fFlags = 0;}
201 void setBackFunc(GrStencilFunc func) { fBackFunc = func; fFlags = 0;}
bsalomon@google.com6b2445e2011-12-15 19:47:46 +0000202 void setFrontFuncMask(unsigned short mask) { fFrontFuncMask = mask; }
203 void setBackFuncMask(unsigned short mask) { fBackFuncMask = mask; }
204 void setFrontFuncRef(unsigned short ref) { fFrontFuncRef = ref; }
205 void setBackFuncRef(unsigned short ref) { fBackFuncRef = ref; }
206 void setFrontWriteMask(unsigned short writeMask) { fFrontWriteMask = writeMask; }
207 void setBackWriteMask(unsigned short writeMask) { fBackWriteMask = writeMask; }
208
bsalomon@google.comd302f142011-03-03 13:54:13 +0000209 void setSame(GrStencilOp passOp,
210 GrStencilOp failOp,
211 GrStencilFunc func,
tomhudson@google.com62b09682011-11-09 16:39:17 +0000212 unsigned short funcMask,
213 unsigned short funcRef,
214 unsigned short writeMask) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000215 fFrontPassOp = passOp;
216 fBackPassOp = passOp;
217 fFrontFailOp = failOp;
218 fBackFailOp = failOp;
219 fFrontFunc = func;
220 fBackFunc = func;
221 fFrontFuncMask = funcMask;
222 fBackFuncMask = funcMask;
223 fFrontFuncRef = funcRef;
224 fBackFuncRef = funcRef;
225 fFrontWriteMask = writeMask;
226 fBackWriteMask = writeMask;
bsalomon@google.com39dab772012-01-03 19:39:31 +0000227 fFlags = 0;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000228 }
229
bsalomon@google.comd302f142011-03-03 13:54:13 +0000230 void setDisabled() {
bsalomon@google.com6b2445e2011-12-15 19:47:46 +0000231 memset(this, 0, sizeof(*this));
232 GR_STATIC_ASSERT(0 == kKeep_StencilOp);
233 GR_STATIC_ASSERT(0 == kAlways_StencilFunc);
digit@google.com9b482c42012-02-16 22:03:26 +0000234 fFlags = kIsDisabled_StencilFlag | kDoesNotWrite_StencilFlag;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000235 }
bsalomon@google.com39dab772012-01-03 19:39:31 +0000236
bsalomon@google.comd302f142011-03-03 13:54:13 +0000237 bool isDisabled() const {
digit@google.com9b482c42012-02-16 22:03:26 +0000238 if (fFlags & kIsDisabled_StencilFlag) {
bsalomon@google.com39dab772012-01-03 19:39:31 +0000239 return true;
240 }
digit@google.com9b482c42012-02-16 22:03:26 +0000241 if (fFlags & kNotDisabled_StencilFlag) {
bsalomon@google.com39dab772012-01-03 19:39:31 +0000242 return false;
243 }
digit@google.com9b482c42012-02-16 22:03:26 +0000244 bool disabled = GR_STENCIL_SETTINGS_IS_DISABLED(
245 fFrontPassOp, fBackPassOp,
246 fFrontFailOp, fBackFailOp,
247 fFrontFunc ,fBackFunc);
248 fFlags |= disabled ? kIsDisabled_StencilFlag : kNotDisabled_StencilFlag;
bsalomon@google.com39dab772012-01-03 19:39:31 +0000249 return disabled;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000250 }
bsalomon@google.com39dab772012-01-03 19:39:31 +0000251
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000252 bool doesWrite() const {
digit@google.com9b482c42012-02-16 22:03:26 +0000253 if (fFlags & kDoesWrite_StencilFlag) {
bsalomon@google.com39dab772012-01-03 19:39:31 +0000254 return true;
255 }
digit@google.com9b482c42012-02-16 22:03:26 +0000256 if (fFlags & kDoesNotWrite_StencilFlag) {
bsalomon@google.com39dab772012-01-03 19:39:31 +0000257 return false;
258 }
digit@google.com9b482c42012-02-16 22:03:26 +0000259 bool writes = GR_STENCIL_SETTINGS_DOES_WRITE(
260 fFrontPassOp, fBackPassOp,
261 fFrontFailOp, fBackFailOp,
262 fFrontFunc, fBackFunc);
263 fFlags |= writes ? kDoesWrite_StencilFlag : kDoesNotWrite_StencilFlag;
bsalomon@google.com39dab772012-01-03 19:39:31 +0000264 return writes;
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000265 }
bsalomon@google.com39dab772012-01-03 19:39:31 +0000266
bsalomon@google.comd302f142011-03-03 13:54:13 +0000267 void invalidate() {
bsalomon@google.com39dab772012-01-03 19:39:31 +0000268 // write an illegal value to the first member
tomhudson@google.com62b09682011-11-09 16:39:17 +0000269 fFrontPassOp = (GrStencilOp)(uint8_t)-1;
bsalomon@google.com39dab772012-01-03 19:39:31 +0000270 fFlags = 0;
271 }
272
273 bool operator == (const GrStencilSettings& s) const {
274 static const size_t gCompareSize = sizeof(GrStencilSettings) -
275 sizeof(fFlags);
276 GrAssert((const char*)&fFlags + sizeof(fFlags) ==
277 (const char*)this + sizeof(GrStencilSettings));
278 if (this->isDisabled() & s.isDisabled()) { // using & not &&
279 return true;
280 }
281 return 0 == memcmp(this, &s, gCompareSize);
282 }
283
284 bool operator != (const GrStencilSettings& s) const {
285 return !(*this == s);
286 }
287
288 GrStencilSettings& operator =(const GrStencilSettings& s) {
289 memcpy(this, &s, sizeof(GrStencilSettings));
290 return *this;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000291 }
292
293private:
robertphillips@google.com730ebe52012-04-16 16:33:13 +0000294 friend class GrClipMaskManager;
295
bsalomon@google.com39dab772012-01-03 19:39:31 +0000296 enum {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000297 kMaxStencilClipPasses = 2 // maximum number of passes to add a clip
298 // element to the stencil buffer.
299 };
300
301 /**
302 * Given a thing to draw into the stencil clip, a fill type, and a set op
303 * this function determines:
304 * 1. Whether the thing can be draw directly to the stencil clip or
305 * needs to be drawn to the client portion of the stencil first.
306 * 2. How many passes are needed.
307 * 3. What those passes are.
308 * 4. The fill rule that should actually be used to render (will
309 * always be non-inverted).
310 *
311 * @param op the set op to combine this element with the
312 * existing clip
313 * @param stencilClipMask mask with just the stencil bit used for clipping
314 * enabled.
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000315 * @param invertedFill is this path inverted
bsalomon@google.comd302f142011-03-03 13:54:13 +0000316 * @param numPasses out: the number of passes needed to add the
317 * element to the clip.
318 * @param settings out: the stencil settings to use for each pass
319 *
320 * @return true if the clip element's geometry can be drawn directly to the
321 * stencil clip bit. Will only be true if canBeDirect is true.
322 * numPasses will be 1 if return value is true.
323 */
robertphillips@google.com0f191f32012-04-25 15:23:36 +0000324 static bool GetClipPasses(SkRegion::Op op,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000325 bool canBeDirect,
326 unsigned int stencilClipMask,
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000327 bool invertedFill,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000328 int* numPasses,
329 GrStencilSettings settings[kMaxStencilClipPasses]);
330};
331
bsalomon@google.com6b2445e2011-12-15 19:47:46 +0000332GR_STATIC_ASSERT(sizeof(GrStencilSettingsStruct) == sizeof(GrStencilSettings));
333
digit@google.com9b482c42012-02-16 22:03:26 +0000334#define GR_STATIC_CONST_STENCIL_STRUCT(STRUCT_NAME, \
bsalomon@google.com6b2445e2011-12-15 19:47:46 +0000335 FRONT_PASS_OP, BACK_PASS_OP, \
336 FRONT_FAIL_OP, BACK_FAIL_OP, \
337 FRONT_FUNC, BACK_FUNC, \
338 FRONT_MASK, BACK_MASK, \
339 FRONT_REF, BACK_REF, \
340 FRONT_WRITE_MASK, BACK_WRITE_MASK) \
digit@google.com9b482c42012-02-16 22:03:26 +0000341 static const GrStencilSettingsStruct STRUCT_NAME = { \
bsalomon@google.com6b2445e2011-12-15 19:47:46 +0000342 (FRONT_PASS_OP), (BACK_PASS_OP), \
343 (FRONT_FAIL_OP), (BACK_FAIL_OP), \
344 (FRONT_FUNC), (BACK_FUNC), \
bsalomon@google.com39dab772012-01-03 19:39:31 +0000345 (0), (0), \
bsalomon@google.com6b2445e2011-12-15 19:47:46 +0000346 (FRONT_MASK), (BACK_MASK), \
347 (FRONT_REF), (BACK_REF), \
bsalomon@google.com39dab772012-01-03 19:39:31 +0000348 (FRONT_WRITE_MASK), (BACK_WRITE_MASK), \
digit@google.com9b482c42012-02-16 22:03:26 +0000349 GR_STENCIL_SETTINGS_DEFAULT_FLAGS( \
350 FRONT_PASS_OP, BACK_PASS_OP, FRONT_FAIL_OP, BACK_FAIL_OP, \
351 FRONT_FUNC, BACK_FUNC) \
352 };
353
354#define GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(STRUCT_PTR) \
355 reinterpret_cast<const GrStencilSettings*>(STRUCT_PTR)
356
357#define GR_STATIC_CONST_SAME_STENCIL_STRUCT(STRUCT_NAME, \
358 PASS_OP, FAIL_OP, FUNC, MASK, REF, WRITE_MASK) \
359 GR_STATIC_CONST_STENCIL_STRUCT(STRUCT_NAME, (PASS_OP), (PASS_OP), \
360 (FAIL_OP),(FAIL_OP), (FUNC), (FUNC), (MASK), (MASK), (REF), (REF), \
361 (WRITE_MASK),(WRITE_MASK))
362
363#define GR_STATIC_CONST_STENCIL(NAME, \
364 FRONT_PASS_OP, BACK_PASS_OP, \
365 FRONT_FAIL_OP, BACK_FAIL_OP, \
366 FRONT_FUNC, BACK_FUNC, \
367 FRONT_MASK, BACK_MASK, \
368 FRONT_REF, BACK_REF, \
369 FRONT_WRITE_MASK, BACK_WRITE_MASK) \
370 GR_STATIC_CONST_STENCIL_STRUCT(NAME ## _STRUCT, \
371 (FRONT_PASS_OP),(BACK_PASS_OP),(FRONT_FAIL_OP),(BACK_FAIL_OP), \
372 (FRONT_FUNC),(BACK_FUNC),(FRONT_MASK),(BACK_MASK), \
373 (FRONT_REF),(BACK_REF),(FRONT_WRITE_MASK),(BACK_WRITE_MASK)) \
bsalomon@google.com6b2445e2011-12-15 19:47:46 +0000374 static const GrStencilSettings& NAME = \
digit@google.com9b482c42012-02-16 22:03:26 +0000375 *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&(NAME ## _STRUCT));
376
bsalomon@google.com6b2445e2011-12-15 19:47:46 +0000377
378#define GR_STATIC_CONST_SAME_STENCIL(NAME, \
379 PASS_OP, FAIL_OP, FUNC, MASK, REF, WRITE_MASK) \
380 GR_STATIC_CONST_STENCIL(NAME, (PASS_OP), (PASS_OP), (FAIL_OP), \
381 (FAIL_OP), (FUNC), (FUNC), (MASK), (MASK), (REF), (REF), (WRITE_MASK), \
382 (WRITE_MASK))
digit@google.com9b482c42012-02-16 22:03:26 +0000383
384#endif