OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2011 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 | |
9 #ifndef GrStencil_DEFINED | |
10 #define GrStencil_DEFINED | |
11 | |
12 #include "GrTypes.h" | |
13 #include "SkRegion.h" | |
14 | |
15 class GrProcessorKeyBuilder; | |
16 | |
17 /** | |
18 * Gr uses the stencil buffer to implement complex clipping inside the | |
19 * GrDrawTarget class. The GrDrawTarget makes a subset of the stencil buffer | |
20 * bits available for other uses by external code (clients). Client code can | |
21 * modify these bits. GrDrawTarget will ignore ref, mask, and writemask bits | |
22 * provided by clients that overlap the bits used to implement clipping. | |
23 * | |
24 * When code outside the GrDrawTarget class uses the stencil buffer the contract | |
25 * is as follows: | |
26 * | |
27 * > Normal stencil funcs allow the client to pass / fail regardless of the | |
28 * reserved clip bits. | |
29 * > Additional functions allow a test against the clip along with a limited | |
30 * set of tests against the client bits. | |
31 * > Client can assume all client bits are zero initially. | |
32 * > Client must ensure that after all its passes are finished it has only | |
33 * written to the color buffer in the region inside the clip. Furthermore, it | |
34 * must zero all client bits that were modifed (both inside and outside the | |
35 * clip). | |
36 */ | |
37 | |
38 /** | |
39 * Determines which pixels pass / fail the stencil test. | |
40 * Stencil test passes if (ref & mask) FUNC (stencil & mask) is true | |
41 */ | |
42 enum GrStencilFunc { | |
43 kAlways_StencilFunc = 0, | |
44 kNever_StencilFunc, | |
45 kGreater_StencilFunc, | |
46 kGEqual_StencilFunc, | |
47 kLess_StencilFunc, | |
48 kLEqual_StencilFunc, | |
49 kEqual_StencilFunc, | |
50 kNotEqual_StencilFunc, | |
51 | |
52 // Gr stores the current clip in the | |
53 // stencil buffer in the high bits that | |
54 // are not directly accessible modifiable | |
55 // via the GrDrawTarget interface. The below | |
56 // stencil funcs test against the current | |
57 // clip in addition to the GrDrawTarget | |
58 // client's stencil bits. | |
59 | |
60 // pass if inside the clip | |
61 kAlwaysIfInClip_StencilFunc, | |
62 kEqualIfInClip_StencilFunc, | |
63 kLessIfInClip_StencilFunc, | |
64 kLEqualIfInClip_StencilFunc, | |
65 kNonZeroIfInClip_StencilFunc, // this one forces the ref to be 0 | |
66 | |
67 kLast_StencilFunc = kNonZeroIfInClip_StencilFunc | |
68 }; | |
69 | |
70 static const int kStencilFuncCnt = kLast_StencilFunc + 1; | |
71 static const int kClipStencilFuncCnt = | |
72 kNonZeroIfInClip_StencilFunc - kAlwaysIfInClip_StencilFunc + 1; | |
73 static const int kBasicStencilFuncCnt = kStencilFuncCnt - kClipStencilFuncCnt; | |
74 | |
75 /** | |
76 * Operations to perform based on whether stencil test passed failed. | |
77 */ | |
78 enum GrStencilOp { | |
79 kKeep_StencilOp = 0, // preserve existing stencil value | |
80 kReplace_StencilOp, // replace with reference value from stencl test | |
81 kIncWrap_StencilOp, // increment and wrap at max | |
82 kIncClamp_StencilOp, // increment and clamp at max | |
83 kDecWrap_StencilOp, // decrement and wrap at 0 | |
84 kDecClamp_StencilOp, // decrement and clamp at 0 | |
85 kZero_StencilOp, // zero stencil bits | |
86 kInvert_StencilOp, // invert stencil bits | |
87 kLast_StencilOp = kInvert_StencilOp | |
88 }; | |
89 static const int kStencilOpCnt = kLast_StencilOp + 1; | |
90 | |
91 /** | |
92 * Class representing stencil state. | |
93 */ | |
94 class GrStencilSettings { | |
95 public: | |
96 enum Face { | |
97 kFront_Face = 0, | |
98 kBack_Face = 1, | |
99 }; | |
100 | |
101 constexpr GrStencilSettings(GrStencilOp passOp, | |
102 GrStencilOp failOp, | |
103 GrStencilFunc func, | |
104 unsigned short funcMask, | |
105 unsigned short funcRef, | |
106 unsigned short writeMask) | |
107 : fPassOps{(uint8_t)passOp, (uint8_t)passOp} | |
108 , fFailOps{(uint8_t)failOp, (uint8_t)failOp} | |
109 , fFuncs{(uint8_t)func, (uint8_t)func} | |
110 , fPad0(0) | |
111 , fPad1(0) | |
112 , fFuncMasks{funcMask, funcMask} | |
113 , fFuncRefs{funcRef, funcRef} | |
114 , fWriteMasks{writeMask, writeMask} | |
115 , fFlags(ComputeFlags(passOp, passOp, | |
116 failOp, failOp, | |
117 func, func, | |
118 writeMask, writeMask)) { | |
119 } | |
120 | |
121 constexpr GrStencilSettings(GrStencilOp frontPassOp, GrStencilOp backPassOp
, | |
122 GrStencilOp frontFailOp, GrStencilOp backFailOp
, | |
123 GrStencilFunc frontFunc, GrStencilFunc backFunc
, | |
124 uint16_t frontFuncMask, uint16_t backFuncMask, | |
125 uint16_t frontFuncRef, uint16_t backFuncRef, | |
126 uint16_t frontWriteMask, uint16_t backWriteMask
) | |
127 : fPassOps{(uint8_t)frontPassOp, (uint8_t)backPassOp} | |
128 , fFailOps{(uint8_t)frontFailOp, (uint8_t)backFailOp} | |
129 , fFuncs{(uint8_t)frontFunc, (uint8_t)backFunc} | |
130 , fPad0(0) | |
131 , fPad1(0) | |
132 , fFuncMasks{frontFuncMask, backFuncMask} | |
133 , fFuncRefs{frontFuncRef, backFuncRef} | |
134 , fWriteMasks{frontWriteMask, backWriteMask} | |
135 , fFlags(ComputeFlags(frontPassOp, backPassOp, | |
136 frontFailOp, backFailOp, | |
137 frontFunc, backFunc, | |
138 frontWriteMask, backWriteMask)) { | |
139 } | |
140 | |
141 GrStencilSettings() { | |
142 fPad0 = fPad1 = 0; | |
143 this->setDisabled(); | |
144 } | |
145 | |
146 GrStencilOp passOp(Face f) const { return static_cast<GrStencilOp>(fPassOps[
f]); } | |
147 GrStencilOp failOp(Face f) const { return static_cast<GrStencilOp>(fFailOps[
f]); } | |
148 GrStencilFunc func(Face f) const { return static_cast<GrStencilFunc>(fFuncs[
f]); } | |
149 uint16_t funcMask(Face f) const { return fFuncMasks[f]; } | |
150 uint16_t funcRef(Face f) const { return fFuncRefs[f]; } | |
151 uint16_t writeMask(Face f) const { return fWriteMasks[f]; } | |
152 | |
153 void setPassOp(Face f, GrStencilOp op) { fPassOps[f] = op; fFlags = 0;} | |
154 void setFailOp(Face f, GrStencilOp op) { fFailOps[f] = op; fFlags = 0;} | |
155 void setFunc(Face f, GrStencilFunc func) { fFuncs[f] = func; fFlags = 0;} | |
156 void setFuncMask(Face f, unsigned short mask) { fFuncMasks[f] = mask; } | |
157 void setFuncRef(Face f, unsigned short ref) { fFuncRefs[f] = ref; } | |
158 void setWriteMask(Face f, unsigned short writeMask) { fWriteMasks[f] = write
Mask; } | |
159 | |
160 void copyFrontSettingsToBack() { | |
161 fPassOps[kBack_Face] = fPassOps[kFront_Face]; | |
162 fFailOps[kBack_Face] = fFailOps[kFront_Face]; | |
163 fFuncs[kBack_Face] = fFuncs[kFront_Face]; | |
164 fFuncMasks[kBack_Face] = fFuncMasks[kFront_Face]; | |
165 fFuncRefs[kBack_Face] = fFuncRefs[kFront_Face]; | |
166 fWriteMasks[kBack_Face] = fWriteMasks[kFront_Face]; | |
167 fFlags = 0; | |
168 } | |
169 | |
170 void setDisabled() { | |
171 memset(this, 0, sizeof(*this)); | |
172 GR_STATIC_ASSERT(0 == kKeep_StencilOp); | |
173 GR_STATIC_ASSERT(0 == kAlways_StencilFunc); | |
174 fFlags = kIsDisabled_StencilFlag | kDoesNotWrite_StencilFlag; | |
175 } | |
176 | |
177 bool isTwoSided() const { | |
178 return fPassOps[kFront_Face] != fPassOps[kBack_Face] || | |
179 fFailOps[kFront_Face] != fFailOps[kBack_Face] || | |
180 fFuncs[kFront_Face] != fFuncs[kBack_Face] || | |
181 fFuncMasks[kFront_Face] != fFuncMasks[kBack_Face] || | |
182 fFuncRefs[kFront_Face] != fFuncRefs[kBack_Face] || | |
183 fWriteMasks[kFront_Face] != fWriteMasks[kBack_Face]; | |
184 } | |
185 | |
186 bool usesWrapOp() const { | |
187 return kIncWrap_StencilOp == fPassOps[kFront_Face] || | |
188 kDecWrap_StencilOp == fPassOps[kFront_Face] || | |
189 kIncWrap_StencilOp == fPassOps[kBack_Face] || | |
190 kDecWrap_StencilOp == fPassOps[kBack_Face] || | |
191 kIncWrap_StencilOp == fFailOps[kFront_Face] || | |
192 kDecWrap_StencilOp == fFailOps[kFront_Face] || | |
193 kIncWrap_StencilOp == fFailOps[kBack_Face] || | |
194 kDecWrap_StencilOp == fFailOps[kBack_Face]; | |
195 } | |
196 | |
197 bool isDisabled() const { | |
198 if (fFlags & kIsDisabled_StencilFlag) { | |
199 return true; | |
200 } | |
201 if (fFlags & kNotDisabled_StencilFlag) { | |
202 return false; | |
203 } | |
204 bool disabled = this->computeIsDisabled(); | |
205 fFlags |= disabled ? kIsDisabled_StencilFlag : kNotDisabled_StencilFlag; | |
206 return disabled; | |
207 } | |
208 | |
209 bool doesWrite() const { | |
210 if (fFlags & kDoesWrite_StencilFlag) { | |
211 return true; | |
212 } | |
213 if (fFlags & kDoesNotWrite_StencilFlag) { | |
214 return false; | |
215 } | |
216 bool writes = this->computeDoesWrite(); | |
217 fFlags |= writes ? kDoesWrite_StencilFlag : kDoesNotWrite_StencilFlag; | |
218 return writes; | |
219 } | |
220 | |
221 void invalidate() { | |
222 // write an illegal value to the first member | |
223 fPassOps[0] = kStencilOpCnt; | |
224 fFlags = 0; | |
225 } | |
226 | |
227 bool isValid() const { return fPassOps[0] < kStencilOpCnt; } | |
228 | |
229 void genKey(GrProcessorKeyBuilder* b) const; | |
230 | |
231 bool operator==(const GrStencilSettings& s) const { | |
232 static const size_t gCompareSize = sizeof(GrStencilSettings) - | |
233 sizeof(fFlags); | |
234 SkASSERT((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; | |
249 } | |
250 | |
251 private: | |
252 friend class GrClipMaskManager; | |
253 | |
254 enum { | |
255 kMaxStencilClipPasses = 2 // maximum number of passes to add a clip | |
256 // element to the stencil buffer. | |
257 }; | |
258 | |
259 /** | |
260 * Given a thing to draw into the stencil clip, a fill type, and a set op | |
261 * this function determines: | |
262 * 1. Whether the thing can be draw directly to the stencil clip or | |
263 * needs to be drawn to the client portion of the stencil first. | |
264 * 2. How many passes are needed. | |
265 * 3. What those passes are. | |
266 * 4. The fill rule that should actually be used to render (will | |
267 * always be non-inverted). | |
268 * | |
269 * @param op the set op to combine this element with the | |
270 * existing clip | |
271 * @param stencilClipMask mask with just the stencil bit used for clipping | |
272 * enabled. | |
273 * @param invertedFill is this path inverted | |
274 * @param numPasses out: the number of passes needed to add the | |
275 * element to the clip. | |
276 * @param settings out: the stencil settings to use for each pass | |
277 * | |
278 * @return true if the clip element's geometry can be drawn directly to the | |
279 * stencil clip bit. Will only be true if canBeDirect is true. | |
280 * numPasses will be 1 if return value is true. | |
281 */ | |
282 static bool GetClipPasses(SkRegion::Op op, | |
283 bool canBeDirect, | |
284 unsigned int stencilClipMask, | |
285 bool invertedFill, | |
286 int* numPasses, | |
287 GrStencilSettings settings[kMaxStencilClipPasses])
; | |
288 | |
289 constexpr static bool IsDisabled(GrStencilOp frontPassOp, GrStencilOp backP
assOp, | |
290 GrStencilOp frontFailOp, GrStencilOp backF
ailOp, | |
291 GrStencilFunc frontFunc, GrStencilFunc bac
kFunc) { | |
292 return (((frontPassOp == kKeep_StencilOp && frontFailOp == kKeep_Stencil
Op)) && | |
293 ((backPassOp == kKeep_StencilOp && backFailOp == kKeep_Stencil
Op)) && | |
294 frontFunc == kAlways_StencilFunc && | |
295 backFunc == kAlways_StencilFunc); | |
296 } | |
297 | |
298 constexpr static bool DoesWrite(GrStencilOp frontPassOp, GrStencilOp backPa
ssOp, | |
299 GrStencilOp frontFailOp, GrStencilOp backFa
ilOp, | |
300 GrStencilFunc frontFunc, GrStencilFunc back
Func, | |
301 uint16_t frontWriteMask, uint16_t backWrite
Mask) { | |
302 return (0 != (frontWriteMask | backWriteMask)) && | |
303 // Can we write due to a front face passing the stencil test? | |
304 ((frontFunc != kNever_StencilFunc && frontPassOp != kKeep_Stenci
lOp) || | |
305 // Can we write due to a back face passing the stencil test? | |
306 (backFunc != kNever_StencilFunc && backPassOp != kKeep_Stenci
lOp) || | |
307 // Can we write due to a front face failing the stencil test? | |
308 (frontFunc != kAlways_StencilFunc && frontFailOp != kKeep_Stenci
lOp) || | |
309 // Can we write due to a back face failing the stencil test? | |
310 (backFunc != kAlways_StencilFunc && backFailOp != kKeep_Stenci
lOp)); | |
311 } | |
312 | |
313 constexpr static uint32_t ComputeFlags(GrStencilOp frontPassOp, GrStencilOp
backPassOp, | |
314 GrStencilOp frontFailOp, GrStencilOp
backFailOp, | |
315 GrStencilFunc frontFunc, GrStencilFu
nc backFunc, | |
316 uint16_t frontWriteMask, uint16_t ba
ckWriteMask) { | |
317 return (IsDisabled(frontPassOp, backPassOp, frontFailOp, backFailOp, | |
318 frontFunc, backFunc) | |
319 ? kIsDisabled_StencilFlag | |
320 : kNotDisabled_StencilFlag) | | |
321 (DoesWrite(frontPassOp, backPassOp, frontFailOp, backFailOp, | |
322 frontFunc, backFunc, frontWriteMask, backWriteMask) | |
323 ? kDoesWrite_StencilFlag | |
324 : kDoesNotWrite_StencilFlag); | |
325 } | |
326 | |
327 bool computeIsDisabled() const { | |
328 return IsDisabled((GrStencilOp) fPassOps[kFront_Face], (GrStencilOp) fPa
ssOps[kBack_Face], | |
329 (GrStencilOp) fFailOps[kFront_Face], (GrStencilOp) fFa
ilOps[kBack_Face], | |
330 (GrStencilFunc) fFuncs[kFront_Face], (GrStencilFunc) f
Funcs[kBack_Face]); | |
331 } | |
332 bool computeDoesWrite() const { | |
333 return DoesWrite((GrStencilOp)fPassOps[kFront_Face], (GrStencilOp)fPassO
ps[kBack_Face], | |
334 (GrStencilOp)fFailOps[kFront_Face], (GrStencilOp)fFailO
ps[kBack_Face], | |
335 (GrStencilFunc)fFuncs[kFront_Face], (GrStencilFunc)fFun
cs[kBack_Face], | |
336 fWriteMasks[kFront_Face], fWriteMasks[kBack_F
ace]); | |
337 } | |
338 | |
339 enum GrStencilFlags { | |
340 kIsDisabled_StencilFlag = 0x1, | |
341 kNotDisabled_StencilFlag = 0x2, | |
342 kDoesWrite_StencilFlag = 0x4, | |
343 kDoesNotWrite_StencilFlag = 0x8, | |
344 }; | |
345 | |
346 uint8_t fPassOps[2]; // op to perform when faces pass (GrStencilOp) | |
347 uint8_t fFailOps[2]; // op to perform when faces fail (GrStencilOp) | |
348 uint8_t fFuncs[2]; // test function for faces (GrStencilFunc) | |
349 uint8_t fPad0; | |
350 uint8_t fPad1; | |
351 uint16_t fFuncMasks[2]; // mask for face tests | |
352 uint16_t fFuncRefs[2]; // reference values for face tests | |
353 uint16_t fWriteMasks[2]; // stencil write masks | |
354 mutable uint32_t fFlags; | |
355 | |
356 }; | |
357 | |
358 // We rely on this being packed and aligned (memcmp'ed and memcpy'ed) | |
359 GR_STATIC_ASSERT(sizeof(GrStencilSettings) % 4 == 0); | |
360 GR_STATIC_ASSERT(sizeof(GrStencilSettings) == | |
361 4*sizeof(uint8_t) + // ops | |
362 2*sizeof(uint8_t) + // funcs | |
363 2*sizeof(uint8_t) + // pads | |
364 2*sizeof(uint16_t) + // func masks | |
365 2*sizeof(uint16_t) + // ref values | |
366 2*sizeof(uint16_t) + // write masks | |
367 sizeof(uint32_t)); // flags | |
368 | |
369 #endif | |
OLD | NEW |