1/*
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 = {
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};
27GR_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
253bool GrStencilSettings::GetClipPasses(GrSetOp op,
254                                      bool canBeDirect,
255                                      unsigned int stencilClipMask,
256                                      bool invertedFill,
257                                      int* numPasses,
258                                      GrStencilSettings settings[kMaxStencilClipPasses]) {
259    if (canBeDirect && !invertedFill) {
260        *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;
287        }
288    }
289    switch (op) {
290        // 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.
293        case kReplace_SetOp:
294            *numPasses= 1;
295            settings[0] = invertedFill ? gInvUserToClipReplace : gUserToClipReplace;
296            settings[0].fFrontFuncMask &= ~stencilClipMask;
297            settings[0].fFrontFuncRef |= stencilClipMask;
298            settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
299            settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
300            break;
301        case kIntersect_SetOp:
302            *numPasses = 1;
303            settings[0] = invertedFill ? gInvUserToClipIsect : gUserToClipIsect;
304            settings[0].fFrontFuncRef = stencilClipMask;
305            settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
306            break;
307        case kUnion_SetOp:
308            *numPasses = 2;
309            if (invertedFill) {
310                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;
334            if (invertedFill) {
335                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;
354            settings[0] = invertedFill ? gInvUserToClipDiff : gUserToClipDiff;
355            settings[0].fFrontFuncRef |= stencilClipMask;
356            settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
357            break;
358        case kReverseDifference_SetOp:
359            if (invertedFill) {
360                *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    }
382    return false;
383}
384