blob: a1c8c09b2dc549aecb42c4c8c98e869e0376801e [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
19const GrStencilSettings GrStencilSettings::gDisabled = {};
20GR_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]) {
252 if (canBeDirect) {
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;
376}