GrStencil.cpp revision 1cab2921ab279367f8206cdadc9259d12e603548
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
24GR_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
32GR_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
42GR_STATIC_CONST_SAME_STENCIL(gUserToClipIsect,
43    kReplace_StencilOp,
44    kZero_StencilOp,
45    kLess_StencilFunc,
46    0xffff,
47    0x0000,           // set clip bit
48    0xffff);
49
50GR_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
60GR_STATIC_CONST_SAME_STENCIL(gUserToClipDiff,
61    kReplace_StencilOp,
62    kZero_StencilOp,
63    kEqual_StencilFunc,
64    0xffff,
65    0x0000,           // set clip bit
66    0xffff);
67
68GR_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.
80GR_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
89GR_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
99GR_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
109GR_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
120GR_STATIC_CONST_SAME_STENCIL(gUserToClipXorPass0,
121    kInvert_StencilOp,
122    kKeep_StencilOp,
123    kEqual_StencilFunc,
124    0xffff,           // unset clip bit
125    0x0000,
126    0xffff);
127
128GR_STATIC_CONST_SAME_STENCIL(gUserToClipXorPass1,
129    kReplace_StencilOp,
130    kZero_StencilOp,
131    kGreater_StencilFunc,
132    0xffff,
133    0x0000,          // set clip bit
134    0xffff);
135
136GR_STATIC_CONST_SAME_STENCIL(gInvUserToClipXorPass0,
137    kInvert_StencilOp,
138    kKeep_StencilOp,
139    kEqual_StencilFunc,
140    0xffff,           // unset clip bit
141    0x0000,
142    0xffff);
143
144GR_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
154GR_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
162GR_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
170GR_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.
187GR_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
196GR_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
205GR_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
214GR_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
223bool 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