blob: edf83fe94c50cfec44f0c35be82a1f2b39e30645 [file] [log] [blame]
bsalomon@google.comd302f142011-03-03 13:54:13 +00001/*
2 Copyright 2011 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17#include "GrStencil.h"
18
senorblanco@chromium.org64cc5792011-05-19 19:58:58 +000019const GrStencilSettings GrStencilSettings::gDisabled = {
20 kKeep_StencilOp, kKeep_StencilOp,
21 kKeep_StencilOp, kKeep_StencilOp,
22 kAlways_StencilFunc, kAlways_StencilFunc,
23 0x0, 0x0,
24 0x0, 0x0,
25 0x0, 0x0
26};
bsalomon@google.comd302f142011-03-03 13:54:13 +000027GR_STATIC_ASSERT(0 == kKeep_StencilOp);
28GR_STATIC_ASSERT(0 == kAlways_StencilFunc);
29
30////////////////////////////////////////////////////////////////////////////////
31// Stencil Rules for Merging user stencil space into clip
32
33// We can't include the clip bit in the ref or mask values because the division
34// between user and clip bits in the stencil depends on the number of stencil
35// bits in the runtime. Comments below indicate what the code should do to
36// incorporate the clip bit into these settings.
37
38///////
39// Replace
40
41// set the ref to be the clip bit, but mask it out for the test
42static const GrStencilSettings gUserToClipReplace = {
43 kReplace_StencilOp, kReplace_StencilOp,
44 kZero_StencilOp, kZero_StencilOp,
45 kLess_StencilFunc, kLess_StencilFunc,
46 0xffffffff, 0xffffffff, // unset clip bit
47 0x0, 0x0, // set clip bit
48 0xffffffff, 0xffffffff
49};
50static const GrStencilSettings gInvUserToClipReplace = {
51 kReplace_StencilOp, kReplace_StencilOp,
52 kZero_StencilOp, kZero_StencilOp,
53 kEqual_StencilFunc, kEqual_StencilFunc,
54 0xffffffff, 0xffffffff, // unset clip bit
55 0x0, 0x0, // set clip bit
56 0xffffffff, 0xffffffff
57};
58
59///////
60// Intersect
61static const GrStencilSettings gUserToClipIsect = {
62 kReplace_StencilOp, kReplace_StencilOp,
63 kZero_StencilOp, kZero_StencilOp,
64 kLess_StencilFunc, kLess_StencilFunc,
65 0xffffffff, 0xffffffff,
66 0x0, 0x0, // set clip bit
67 0xffffffff, 0xffffffff
68};
69static const GrStencilSettings gInvUserToClipIsect = {
70 kReplace_StencilOp, kReplace_StencilOp,
71 kZero_StencilOp, kZero_StencilOp,
72 kEqual_StencilFunc, kEqual_StencilFunc,
73 0xffffffff, 0xffffffff,
74 0x0, 0x0, // set clip bit
75 0xffffffff, 0xffffffff
76};
77
78///////
79// Difference
80static const GrStencilSettings gUserToClipDiff = {
81 kReplace_StencilOp, kReplace_StencilOp,
82 kZero_StencilOp, kZero_StencilOp,
83 kEqual_StencilFunc, kEqual_StencilFunc,
84 0xffffffff, 0xffffffff,
85 0x0, 0x0, // set clip bit
86 0xffffffff, 0xffffffff
87};
88static const GrStencilSettings gInvUserToClipDiff = {
89 kReplace_StencilOp, kReplace_StencilOp,
90 kZero_StencilOp, kZero_StencilOp,
91 kLess_StencilFunc, kLess_StencilFunc,
92 0xffffffff, 0xffffffff,
93 0x0, 0x0, // set clip bit
94 0xffffffff, 0xffffffff
95};
96
97///////
98// Union
99
100// first pass makes all the passing cases >= just clip bit set.
101static const GrStencilSettings gUserToClipUnionPass0 = {
102 kReplace_StencilOp, kReplace_StencilOp,
103 kKeep_StencilOp, kKeep_StencilOp,
104 kLEqual_StencilFunc, kLEqual_StencilFunc,
105 0xffffffff, 0xffffffff, // unset clip bit
106 0x00000001, 0x00000001, // set clip bit
107 0xffffffff, 0xffffffff
108};
109
110// second pass allows anything greater than just clip bit set to pass
111static const GrStencilSettings gUserToClipUnionPass1 = {
112 kReplace_StencilOp, kReplace_StencilOp,
113 kZero_StencilOp, kZero_StencilOp,
114 kLEqual_StencilFunc, kLEqual_StencilFunc,
115 0xffffffff, 0xffffffff,
116 0x00000000, 0x00000000, // set clip bit
117 0xffffffff, 0xffffffff
118};
119
120// for inverse first pass finds non-zerp user with clip bit set
121// and converts it to just clip bit set
122static const GrStencilSettings gInvUserToClipUnionPass0 = {
123 kReplace_StencilOp, kReplace_StencilOp,
124 kKeep_StencilOp, kKeep_StencilOp,
125 kLess_StencilFunc, kLess_StencilFunc,
126 0xffffffff, 0xffffffff,
127 0x00000000, 0x00000000, // set clip bit
128 0xffffffff, 0xffffffff
129};
130
131// second pass lets anything through with a nonzero user portion
132// and writes a ref value with just the clip bit set to it.
133static const GrStencilSettings gInvUserToClipUnionPass1 = {
134 kReplace_StencilOp, kReplace_StencilOp,
135 kZero_StencilOp, kZero_StencilOp,
136 kLess_StencilFunc, kLess_StencilFunc,
137 0xffffffff, 0xffffffff, // unset clip bit
138 0x00000000, 0x00000000, // set clip bit
139 0xffffffff, 0xffffffff
140};
141
142///////
143// Xor
144static const GrStencilSettings gUserToClipXorPass0 = {
145 kInvert_StencilOp, kInvert_StencilOp,
146 kKeep_StencilOp, kKeep_StencilOp,
147 kEqual_StencilFunc, kEqual_StencilFunc,
148 0xffffffff, 0xffffffff, // unset clip bit
149 0x00000000, 0x00000000,
150 0xffffffff, 0xffffffff
151};
152
153static const GrStencilSettings gUserToClipXorPass1 = {
154 kReplace_StencilOp, kReplace_StencilOp,
155 kZero_StencilOp, kZero_StencilOp,
156 kGreater_StencilFunc, kGreater_StencilFunc,
157 0xffffffff, 0xffffffff,
158 0x00000000, 0x00000000, // set clip bit
159 0xffffffff, 0xffffffff
160};
161
162static const GrStencilSettings gInvUserToClipXorPass0 = {
163 kInvert_StencilOp, kInvert_StencilOp,
164 kKeep_StencilOp, kKeep_StencilOp,
165 kEqual_StencilFunc, kEqual_StencilFunc,
166 0xffffffff, 0xffffffff, // unset clip bit
167 0x00000000, 0x00000000,
168 0xffffffff, 0xffffffff
169};
170
171static const GrStencilSettings gInvUserToClipXorPass1 = {
172 kReplace_StencilOp, kReplace_StencilOp,
173 kZero_StencilOp, kZero_StencilOp,
174 kLess_StencilFunc, kLess_StencilFunc,
175 0xffffffff, 0xffffffff,
176 0x00000000, 0x00000000, // set clip bit
177 0xffffffff, 0xffffffff
178};
179
180///////
181// Reverse Diff
182static const GrStencilSettings gUserToClipRDiffPass0 = {
183 kInvert_StencilOp, kInvert_StencilOp,
184 kZero_StencilOp, kZero_StencilOp,
185 kLess_StencilFunc, kLess_StencilFunc,
186 0xffffffff, 0xffffffff, // unset clip bit
187 0x00000000, 0x00000000, // set clip bit
188 0xffffffff, 0xffffffff
189};
190
191static const GrStencilSettings gUserToClipRDiffPass1 = {
192 kReplace_StencilOp, kReplace_StencilOp,
193 kZero_StencilOp, kZero_StencilOp,
194 kEqual_StencilFunc, kEqual_StencilFunc,
195 0x00000000, 0x00000000, // set clip bit
196 0x00000000, 0x00000000, // set clip bit
197 0xffffffff, 0xffffffff
198};
199
200static const GrStencilSettings gInvUserToClipRDiff = {
201 kInvert_StencilOp, kInvert_StencilOp,
202 kZero_StencilOp, kZero_StencilOp,
203 kEqual_StencilFunc, kEqual_StencilFunc,
204 0xffffffff, 0xffffffff,
205 0x00000000, 0x00000000,
206 0x00000000, 0x00000000 // set clip bit
207};
208///////
209// Direct to Stencil
210
211// We can render a clip element directly without first writing to the client
212// portion of the clip when the fill is not inverse and the set operation will
213// only modify the in/out status of samples covered by the clip element.
214
215// this one only works if used right after stencil clip was cleared.
216// Our GrClip doesn't allow midstream replace ops.
217static const GrStencilSettings gReplaceClip = {
218 kReplace_StencilOp, kReplace_StencilOp,
219 kReplace_StencilOp, kReplace_StencilOp,
220 kAlways_StencilFunc, kAlways_StencilFunc,
221 0xffffffff, 0xffffffff,
222 0x00000000, 0x00000000, // set clip bit
223 0x00000000, 0x00000000 // set clipBit
224};
225
226static const GrStencilSettings gUnionClip = {
227 kReplace_StencilOp, kReplace_StencilOp,
228 kReplace_StencilOp, kReplace_StencilOp,
229 kAlways_StencilFunc, kAlways_StencilFunc,
230 0xffffffff, 0xffffffff,
231 0x00000000, 0x00000000, // set clip bit
232 0x00000000, 0x00000000 // set clip bit
233};
234
235static const GrStencilSettings gXorClip = {
236 kInvert_StencilOp, kInvert_StencilOp,
237 kInvert_StencilOp, kInvert_StencilOp,
238 kAlways_StencilFunc, kAlways_StencilFunc,
239 0xffffffff, 0xffffffff,
240 0x00000000, 0x00000000,
241 0x00000000, 0x00000000 // set clip bit
242};
243
244static const GrStencilSettings gDiffClip = {
245 kZero_StencilOp, kZero_StencilOp,
246 kZero_StencilOp, kZero_StencilOp,
247 kAlways_StencilFunc, kAlways_StencilFunc,
248 0xffffffff, 0xffffffff,
249 0x00000000, 0x00000000,
250 0x00000000, 0x00000000 // set clip bit
251};
252
bsalomon@google.comd302f142011-03-03 13:54:13 +0000253bool GrStencilSettings::GetClipPasses(GrSetOp op,
254 bool canBeDirect,
255 unsigned int stencilClipMask,
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000256 bool invertedFill,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000257 int* numPasses,
258 GrStencilSettings settings[kMaxStencilClipPasses]) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000259 if (canBeDirect && !invertedFill) {
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000260 *numPasses = 0;
261 switch (op) {
262 case kReplace_SetOp:
263 *numPasses = 1;
264 settings[0] = gReplaceClip;
265 break;
266 case kUnion_SetOp:
267 *numPasses = 1;
268 settings[0] = gUnionClip;
269 break;
270 case kXor_SetOp:
271 *numPasses = 1;
272 settings[0] = gXorClip;
273 break;
274 case kDifference_SetOp:
275 *numPasses = 1;
276 settings[0] = gDiffClip;
277 break;
278 default: // suppress warning
279 break;
280 }
281 if (1 == *numPasses) {
282 settings[0].fFrontFuncRef |= stencilClipMask;
283 settings[0].fFrontWriteMask |= stencilClipMask;
284 settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
285 settings[0].fBackWriteMask = settings[0].fFrontWriteMask;
286 return true;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000287 }
288 }
289 switch (op) {
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000290 // if we make the path renderer go to stencil we always give it a
291 // non-inverted fill and we use the stencil rules on the client->clipbit
292 // pass to select either the zeros or nonzeros.
bsalomon@google.comd302f142011-03-03 13:54:13 +0000293 case kReplace_SetOp:
294 *numPasses= 1;
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000295 settings[0] = invertedFill ? gInvUserToClipReplace : gUserToClipReplace;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000296 settings[0].fFrontFuncMask &= ~stencilClipMask;
297 settings[0].fFrontFuncRef |= stencilClipMask;
298 settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
299 settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000300 break;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000301 case kIntersect_SetOp:
302 *numPasses = 1;
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000303 settings[0] = invertedFill ? gInvUserToClipIsect : gUserToClipIsect;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000304 settings[0].fFrontFuncRef = stencilClipMask;
305 settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
306 break;
307 case kUnion_SetOp:
308 *numPasses = 2;
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000309 if (invertedFill) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000310 settings[0] = gInvUserToClipUnionPass0;
311 settings[0].fFrontFuncRef |= stencilClipMask;
312 settings[0].fBackFuncRef = settings[0].fFrontFuncMask;
313
314 settings[1] = gInvUserToClipUnionPass1;
315 settings[1].fFrontFuncMask &= ~stencilClipMask;
316 settings[1].fFrontFuncRef |= stencilClipMask;
317 settings[1].fBackFuncMask = settings[1].fFrontFuncMask;
318 settings[1].fBackFuncRef = settings[1].fFrontFuncRef;
319
320 } else {
321 settings[0] = gUserToClipUnionPass0;
322 settings[0].fFrontFuncMask &= ~stencilClipMask;
323 settings[0].fFrontFuncRef |= stencilClipMask;
324 settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
325 settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
326
327 settings[1] = gUserToClipUnionPass1;
328 settings[1].fFrontFuncRef |= stencilClipMask;
329 settings[1].fBackFuncRef = settings[1].fFrontFuncRef;
330 }
331 break;
332 case kXor_SetOp:
333 *numPasses = 2;
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000334 if (invertedFill) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000335 settings[0] = gInvUserToClipXorPass0;
336 settings[0].fFrontFuncMask &= ~stencilClipMask;
337 settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
338
339 settings[1] = gInvUserToClipXorPass1;
340 settings[1].fFrontFuncRef |= stencilClipMask;
341 settings[1].fBackFuncRef = settings[1].fFrontFuncRef;
342 } else {
343 settings[0] = gUserToClipXorPass0;
344 settings[0].fFrontFuncMask &= ~stencilClipMask;
345 settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
346
347 settings[1] = gUserToClipXorPass1;
348 settings[1].fFrontFuncRef |= stencilClipMask;
349 settings[1].fBackFuncRef = settings[1].fFrontFuncRef;
350 }
351 break;
352 case kDifference_SetOp:
353 *numPasses = 1;
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000354 settings[0] = invertedFill ? gInvUserToClipDiff : gUserToClipDiff;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000355 settings[0].fFrontFuncRef |= stencilClipMask;
356 settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
357 break;
358 case kReverseDifference_SetOp:
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000359 if (invertedFill) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000360 *numPasses = 1;
361 settings[0] = gInvUserToClipRDiff;
362 settings[0].fFrontWriteMask |= stencilClipMask;
363 settings[0].fBackWriteMask = settings[0].fFrontWriteMask;
364 } else {
365 *numPasses = 2;
366 settings[0] = gUserToClipRDiffPass0;
367 settings[0].fFrontFuncMask &= ~stencilClipMask;
368 settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
369 settings[0].fFrontFuncRef |= stencilClipMask;
370 settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
371
372 settings[1] = gUserToClipRDiffPass1;
373 settings[1].fFrontFuncMask |= stencilClipMask;
374 settings[1].fFrontFuncRef |= stencilClipMask;
375 settings[1].fBackFuncMask = settings[1].fFrontFuncMask;
376 settings[1].fBackFuncRef = settings[1].fFrontFuncRef;
377 }
378 break;
379 default:
380 GrCrash("Unknown set op");
381 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000382 return false;
ctguil@chromium.orgd5683e22011-04-18 18:12:50 +0000383}