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