1
2 /*
3 * 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.
7 */
8
9
10 #include "GrStencil.h"
11
12 ////////////////////////////////////////////////////////////////////////////////
13 // Stencil Rules for Merging user stencil space into clip
14
15 // We can't include the clip bit in the ref or mask values because the division
16 // between user and clip bits in the stencil depends on the number of stencil
17 // bits in the runtime. Comments below indicate what the code should do to
18 // incorporate the clip bit into these settings.
19
20 ///////
21 // Replace
22
23 // set the ref to be the clip bit, but mask it out for the test
24 GR_STATIC_CONST_SAME_STENCIL(gUserToClipReplace,
25 kReplace_StencilOp,
26 kZero_StencilOp,
27 kLess_StencilFunc,
28 0xffff, // unset clip bit
29 0x0000, // set clip bit
30 0xffff);
31
32 GR_STATIC_CONST_SAME_STENCIL(gInvUserToClipReplace,
33 kReplace_StencilOp,
34 kZero_StencilOp,
35 kEqual_StencilFunc,
36 0xffff, // unset clip bit
37 0x0000, // set clip bit
38 0xffff);
39
40 ///////
41 // Intersect
42 GR_STATIC_CONST_SAME_STENCIL(gUserToClipIsect,
43 kReplace_StencilOp,
44 kZero_StencilOp,
45 kLess_StencilFunc,
46 0xffff,
47 0x0000, // set clip bit
48 0xffff);
49
50 GR_STATIC_CONST_SAME_STENCIL(gInvUserToClipIsect,
51 kReplace_StencilOp,
52 kZero_StencilOp,
53 kEqual_StencilFunc,
54 0xffff,
55 0x0000, // set clip bit
56 0xffff);
57
58 ///////
59 // Difference
60 GR_STATIC_CONST_SAME_STENCIL(gUserToClipDiff,
61 kReplace_StencilOp,
62 kZero_StencilOp,
63 kEqual_StencilFunc,
64 0xffff,
65 0x0000, // set clip bit
66 0xffff);
67
68 GR_STATIC_CONST_SAME_STENCIL(gInvUserToClipDiff,
69 kReplace_StencilOp,
70 kZero_StencilOp,
71 kLess_StencilFunc,
72 0xffff,
73 0x0000, // set clip bit
74 0xffff);
75
76 ///////
77 // Union
78
79 // first pass makes all the passing cases >= just clip bit set.
80 GR_STATIC_CONST_SAME_STENCIL(gUserToClipUnionPass0,
81 kReplace_StencilOp,
82 kKeep_StencilOp,
83 kLEqual_StencilFunc,
84 0xffff,
85 0x0001, // set clip bit
86 0xffff);
87
88 // second pass allows anything greater than just clip bit set to pass
89 GR_STATIC_CONST_SAME_STENCIL(gUserToClipUnionPass1,
90 kReplace_StencilOp,
91 kZero_StencilOp,
92 kLEqual_StencilFunc,
93 0xffff,
94 0x0000, // set clip bit
95 0xffff);
96
97 // first pass finds zeros in the user bits and if found sets
98 // the clip bit to 1
99 GR_STATIC_CONST_SAME_STENCIL(gInvUserToClipUnionPass0,
100 kReplace_StencilOp,
101 kKeep_StencilOp,
102 kEqual_StencilFunc,
103 0xffff,
104 0x0000, // set clip bit
105 0x0000 // set clip bit
106 );
107
108 // second pass zeros the user bits
109 GR_STATIC_CONST_SAME_STENCIL(gInvUserToClipUnionPass1,
110 kZero_StencilOp,
111 kZero_StencilOp,
112 kLess_StencilFunc,
113 0xffff,
114 0x0000,
115 0xffff // unset clip bit
116 );
117
118 ///////
119 // Xor
120 GR_STATIC_CONST_SAME_STENCIL(gUserToClipXorPass0,
121 kInvert_StencilOp,
122 kKeep_StencilOp,
123 kEqual_StencilFunc,
124 0xffff, // unset clip bit
125 0x0000,
126 0xffff);
127
128 GR_STATIC_CONST_SAME_STENCIL(gUserToClipXorPass1,
129 kReplace_StencilOp,
130 kZero_StencilOp,
131 kGreater_StencilFunc,
132 0xffff,
133 0x0000, // set clip bit
134 0xffff);
135
136 GR_STATIC_CONST_SAME_STENCIL(gInvUserToClipXorPass0,
137 kInvert_StencilOp,
138 kKeep_StencilOp,
139 kEqual_StencilFunc,
140 0xffff, // unset clip bit
141 0x0000,
142 0xffff);
143
144 GR_STATIC_CONST_SAME_STENCIL(gInvUserToClipXorPass1,
145 kReplace_StencilOp,
146 kZero_StencilOp,
147 kLess_StencilFunc,
148 0xffff,
149 0x0000, // set clip bit
150 0xffff);
151
152 ///////
153 // Reverse Diff
154 GR_STATIC_CONST_SAME_STENCIL(gUserToClipRDiffPass0,
155 kInvert_StencilOp,
156 kZero_StencilOp,
157 kLess_StencilFunc,
158 0xffff, // unset clip bit
159 0x0000, // set clip bit
160 0xffff);
161
162 GR_STATIC_CONST_SAME_STENCIL(gUserToClipRDiffPass1,
163 kReplace_StencilOp,
164 kZero_StencilOp,
165 kEqual_StencilFunc,
166 0x0000, // set clip bit
167 0x0000, // set clip bit
168 0xffff);
169
170 GR_STATIC_CONST_SAME_STENCIL(gInvUserToClipRDiff,
171 kInvert_StencilOp,
172 kZero_StencilOp,
173 kEqual_StencilFunc,
174 0xffff,
175 0x0000,
176 0x0000 // set clip bit
177 );
178 ///////
179 // Direct to Stencil
180
181 // We can render a clip element directly without first writing to the client
182 // portion of the clip when the fill is not inverse and the set operation will
183 // only modify the in/out status of samples covered by the clip element.
184
185 // this one only works if used right after stencil clip was cleared.
186 // Our GrClip doesn't allow midstream replace ops.
187 GR_STATIC_CONST_SAME_STENCIL(gReplaceClip,
188 kReplace_StencilOp,
189 kReplace_StencilOp,
190 kAlways_StencilFunc,
191 0xffff,
192 0x0000, // set clip bit
193 0x0000 // set clipBit
194 );
195
196 GR_STATIC_CONST_SAME_STENCIL(gUnionClip,
197 kReplace_StencilOp,
198 kReplace_StencilOp,
199 kAlways_StencilFunc,
200 0xffff,
201 0x0000, // set clip bit
202 0x0000 // set clip bit
203 );
204
205 GR_STATIC_CONST_SAME_STENCIL(gXorClip,
206 kInvert_StencilOp,
207 kInvert_StencilOp,
208 kAlways_StencilFunc,
209 0xffff,
210 0x0000,
211 0x0000 // set clip bit
212 );
213
214 GR_STATIC_CONST_SAME_STENCIL(gDiffClip,
215 kZero_StencilOp,
216 kZero_StencilOp,
217 kAlways_StencilFunc,
218 0xffff,
219 0x0000,
220 0x0000 // set clip bit
221 );
222
GetClipPasses(GrSetOp op,bool canBeDirect,unsigned int stencilClipMask,bool invertedFill,int * numPasses,GrStencilSettings settings[kMaxStencilClipPasses])223 bool GrStencilSettings::GetClipPasses(GrSetOp op,
224 bool canBeDirect,
225 unsigned int stencilClipMask,
226 bool invertedFill,
227 int* numPasses,
228 GrStencilSettings settings[kMaxStencilClipPasses]) {
229 if (canBeDirect && !invertedFill) {
230 *numPasses = 0;
231 switch (op) {
232 case kReplace_SetOp:
233 *numPasses = 1;
234 settings[0] = gReplaceClip;
235 break;
236 case kUnion_SetOp:
237 *numPasses = 1;
238 settings[0] = gUnionClip;
239 break;
240 case kXor_SetOp:
241 *numPasses = 1;
242 settings[0] = gXorClip;
243 break;
244 case kDifference_SetOp:
245 *numPasses = 1;
246 settings[0] = gDiffClip;
247 break;
248 default: // suppress warning
249 break;
250 }
251 if (1 == *numPasses) {
252 settings[0].fFrontFuncRef |= stencilClipMask;
253 settings[0].fFrontWriteMask |= stencilClipMask;
254 settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
255 settings[0].fBackWriteMask = settings[0].fFrontWriteMask;
256 return true;
257 }
258 }
259 switch (op) {
260 // if we make the path renderer go to stencil we always give it a
261 // non-inverted fill and we use the stencil rules on the client->clipbit
262 // pass to select either the zeros or nonzeros.
263 case kReplace_SetOp:
264 *numPasses= 1;
265 settings[0] = invertedFill ? gInvUserToClipReplace : gUserToClipReplace;
266 settings[0].fFrontFuncMask &= ~stencilClipMask;
267 settings[0].fFrontFuncRef |= stencilClipMask;
268 settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
269 settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
270 break;
271 case kIntersect_SetOp:
272 *numPasses = 1;
273 settings[0] = invertedFill ? gInvUserToClipIsect : gUserToClipIsect;
274 settings[0].fFrontFuncRef = stencilClipMask;
275 settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
276 break;
277 case kUnion_SetOp:
278 *numPasses = 2;
279 if (invertedFill) {
280 settings[0] = gInvUserToClipUnionPass0;
281 settings[0].fFrontFuncMask &= ~stencilClipMask;
282 settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
283 settings[0].fFrontFuncRef |= stencilClipMask;
284 settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
285 settings[0].fFrontWriteMask |= stencilClipMask;
286 settings[0].fBackWriteMask = settings[0].fFrontWriteMask;
287
288 settings[1] = gInvUserToClipUnionPass1;
289 settings[1].fFrontWriteMask &= ~stencilClipMask;
290 settings[1].fBackWriteMask &= settings[1].fFrontWriteMask;
291
292 } else {
293 settings[0] = gUserToClipUnionPass0;
294 settings[0].fFrontFuncMask &= ~stencilClipMask;
295 settings[0].fFrontFuncRef |= stencilClipMask;
296 settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
297 settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
298
299 settings[1] = gUserToClipUnionPass1;
300 settings[1].fFrontFuncRef |= stencilClipMask;
301 settings[1].fBackFuncRef = settings[1].fFrontFuncRef;
302 }
303 break;
304 case kXor_SetOp:
305 *numPasses = 2;
306 if (invertedFill) {
307 settings[0] = gInvUserToClipXorPass0;
308 settings[0].fFrontFuncMask &= ~stencilClipMask;
309 settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
310
311 settings[1] = gInvUserToClipXorPass1;
312 settings[1].fFrontFuncRef |= stencilClipMask;
313 settings[1].fBackFuncRef = settings[1].fFrontFuncRef;
314 } else {
315 settings[0] = gUserToClipXorPass0;
316 settings[0].fFrontFuncMask &= ~stencilClipMask;
317 settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
318
319 settings[1] = gUserToClipXorPass1;
320 settings[1].fFrontFuncRef |= stencilClipMask;
321 settings[1].fBackFuncRef = settings[1].fFrontFuncRef;
322 }
323 break;
324 case kDifference_SetOp:
325 *numPasses = 1;
326 settings[0] = invertedFill ? gInvUserToClipDiff : gUserToClipDiff;
327 settings[0].fFrontFuncRef |= stencilClipMask;
328 settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
329 break;
330 case kReverseDifference_SetOp:
331 if (invertedFill) {
332 *numPasses = 1;
333 settings[0] = gInvUserToClipRDiff;
334 settings[0].fFrontWriteMask |= stencilClipMask;
335 settings[0].fBackWriteMask = settings[0].fFrontWriteMask;
336 } else {
337 *numPasses = 2;
338 settings[0] = gUserToClipRDiffPass0;
339 settings[0].fFrontFuncMask &= ~stencilClipMask;
340 settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
341 settings[0].fFrontFuncRef |= stencilClipMask;
342 settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
343
344 settings[1] = gUserToClipRDiffPass1;
345 settings[1].fFrontFuncMask |= stencilClipMask;
346 settings[1].fFrontFuncRef |= stencilClipMask;
347 settings[1].fBackFuncMask = settings[1].fFrontFuncMask;
348 settings[1].fBackFuncRef = settings[1].fFrontFuncRef;
349 }
350 break;
351 default:
352 GrCrash("Unknown set op");
353 }
354 return false;
355 }
356