1 /*
2  * Copyright 2011 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 
9 #include "GrStencilSettings.h"
10 
11 #include "GrProcessor.h"
12 
13 constexpr const GrUserStencilSettings gUnused(
14     GrUserStencilSettings::StaticInit<
15         0x0000,
16         GrUserStencilTest::kAlwaysIfInClip,
17         0xffff,
18         GrUserStencilOp::kKeep,
19         GrUserStencilOp::kKeep,
20         0x0000>()
21 );
22 
23 GR_STATIC_ASSERT(kAll_StencilFlags == (gUnused.fFrontFlags[0] & gUnused.fBackFlags[0]));
24 
25 const GrUserStencilSettings& GrUserStencilSettings::kUnused = gUnused;
26 
reset(const GrUserStencilSettings & user,bool hasStencilClip,int numStencilBits)27 void GrStencilSettings::reset(const GrUserStencilSettings& user, bool hasStencilClip,
28                               int numStencilBits) {
29     uint16_t frontFlags = user.fFrontFlags[hasStencilClip];
30     if (frontFlags & kSingleSided_StencilFlag) {
31         fFlags = frontFlags;
32         if (!this->isDisabled()) {
33             fFront.reset(user.fFront, hasStencilClip, numStencilBits);
34         }
35         return;
36     }
37 
38     uint16_t backFlags = user.fBackFlags[hasStencilClip];
39     fFlags = frontFlags & backFlags;
40     if (this->isDisabled()) {
41         return;
42     }
43     if (!(frontFlags & kDisabled_StencilFlag)) {
44         fFront.reset(user.fFront, hasStencilClip, numStencilBits);
45     } else {
46         fFront.setDisabled();
47     }
48     if (!(backFlags & kDisabled_StencilFlag)) {
49         fBack.reset(user.fBack, hasStencilClip, numStencilBits);
50     } else {
51         fBack.setDisabled();
52     }
53 }
54 
reset(const GrStencilSettings & that)55 void GrStencilSettings::reset(const GrStencilSettings& that) {
56     fFlags = that.fFlags;
57     if ((kInvalid_PrivateFlag | kDisabled_StencilFlag) & fFlags) {
58         return;
59     }
60     if (!this->isTwoSided()) {
61         memcpy(&fFront, &that.fFront, sizeof(Face));
62     } else {
63         memcpy(&fFront, &that.fFront, 2 * sizeof(Face));
64         GR_STATIC_ASSERT(sizeof(Face) ==
65                          offsetof(GrStencilSettings, fBack) - offsetof(GrStencilSettings, fFront));
66     }
67 }
68 
operator ==(const GrStencilSettings & that) const69 bool GrStencilSettings::operator==(const GrStencilSettings& that) const {
70     if ((kInvalid_PrivateFlag | kDisabled_StencilFlag) & (fFlags | that.fFlags)) {
71         // At least one is invalid and/or disabled.
72         if (kInvalid_PrivateFlag & (fFlags | that.fFlags)) {
73             return false; // We never allow invalid stencils to be equal.
74         }
75         // They're only equal if both are disabled.
76         return kDisabled_StencilFlag & (fFlags & that.fFlags);
77     }
78     if (kSingleSided_StencilFlag & (fFlags & that.fFlags)) {
79         return 0 == memcmp(&fFront, &that.fFront, sizeof(Face)); // Both are single sided.
80     } else {
81         return 0 == memcmp(&fFront, &that.fFront, 2 * sizeof(Face));
82         GR_STATIC_ASSERT(sizeof(Face) ==
83                          offsetof(GrStencilSettings, fBack) - offsetof(GrStencilSettings, fFront));
84     }
85     // memcmp relies on GrStencilSettings::Face being tightly packed.
86     GR_STATIC_ASSERT(0 == offsetof(Face, fRef));
87     GR_STATIC_ASSERT(2 == sizeof(Face::fRef));
88     GR_STATIC_ASSERT(2 == offsetof(Face, fTest));
89     GR_STATIC_ASSERT(2 == sizeof(Face::fTest));
90     GR_STATIC_ASSERT(4 == offsetof(Face, fTestMask));
91     GR_STATIC_ASSERT(2 == sizeof(Face::fTestMask));
92     GR_STATIC_ASSERT(6 == offsetof(Face, fPassOp));
93     GR_STATIC_ASSERT(1 == sizeof(Face::fPassOp));
94     GR_STATIC_ASSERT(7 == offsetof(Face, fFailOp));
95     GR_STATIC_ASSERT(1 == sizeof(Face::fFailOp));
96     GR_STATIC_ASSERT(8 == offsetof(Face, fWriteMask));
97     GR_STATIC_ASSERT(2 == sizeof(Face::fWriteMask));
98     GR_STATIC_ASSERT(10 == sizeof(Face));
99 }
100 
101 static constexpr GrStencilTest gUserStencilTestToRaw[kGrUserStencilTestCount] = {
102     // Tests that respect the clip.
103     GrStencilTest::kAlways,  // kAlwaysIfInClip (This is only for when there is not a stencil clip).
104     GrStencilTest::kEqual,   // kEqualIfInClip.
105     GrStencilTest::kLess,    // kLessIfInClip.
106     GrStencilTest::kLEqual,  // kLEqualIfInClip.
107 
108     // Tests that ignore the clip.
109     GrStencilTest::kAlways,
110     GrStencilTest::kNever,
111     GrStencilTest::kGreater,
112     GrStencilTest::kGEqual,
113     GrStencilTest::kLess,
114     GrStencilTest::kLEqual,
115     GrStencilTest::kEqual,
116     GrStencilTest::kNotEqual
117 };
118 
119 GR_STATIC_ASSERT(0 == (int)GrUserStencilTest::kAlwaysIfInClip);
120 GR_STATIC_ASSERT(1 == (int)GrUserStencilTest::kEqualIfInClip);
121 GR_STATIC_ASSERT(2 == (int)GrUserStencilTest::kLessIfInClip);
122 GR_STATIC_ASSERT(3 == (int)GrUserStencilTest::kLEqualIfInClip);
123 GR_STATIC_ASSERT(4 == (int)GrUserStencilTest::kAlways);
124 GR_STATIC_ASSERT(5 == (int)GrUserStencilTest::kNever);
125 GR_STATIC_ASSERT(6 == (int)GrUserStencilTest::kGreater);
126 GR_STATIC_ASSERT(7 == (int)GrUserStencilTest::kGEqual);
127 GR_STATIC_ASSERT(8 == (int)GrUserStencilTest::kLess);
128 GR_STATIC_ASSERT(9 == (int)GrUserStencilTest::kLEqual);
129 GR_STATIC_ASSERT(10 == (int)GrUserStencilTest::kEqual);
130 GR_STATIC_ASSERT(11 == (int)GrUserStencilTest::kNotEqual);
131 
132 static constexpr GrStencilOp gUserStencilOpToRaw[kGrUserStencilOpCount] = {
133     GrStencilOp::kKeep,
134 
135     // Ops that only modify user bits.
136     GrStencilOp::kZero,
137     GrStencilOp::kReplace,
138     GrStencilOp::kInvert,
139     GrStencilOp::kIncWrap,
140     GrStencilOp::kDecWrap,
141     GrStencilOp::kIncClamp,  // kIncMaybeClamp.
142     GrStencilOp::kDecClamp,  // kDecMaybeClamp.
143 
144     // Ops that only modify the clip bit.
145     GrStencilOp::kZero,      // kZeroClipBit.
146     GrStencilOp::kReplace,   // kSetClipBit.
147     GrStencilOp::kInvert,    // kInvertClipBit.
148 
149     // Ops that modify clip and user bits.
150     GrStencilOp::kReplace,   // kSetClipAndReplaceUserBits.
151     GrStencilOp::kZero       // kZeroClipAndUserBits.
152 };
153 
154 GR_STATIC_ASSERT(0 == (int)GrUserStencilOp::kKeep);
155 GR_STATIC_ASSERT(1 == (int)GrUserStencilOp::kZero);
156 GR_STATIC_ASSERT(2 == (int)GrUserStencilOp::kReplace);
157 GR_STATIC_ASSERT(3 == (int)GrUserStencilOp::kInvert);
158 GR_STATIC_ASSERT(4 == (int)GrUserStencilOp::kIncWrap);
159 GR_STATIC_ASSERT(5 == (int)GrUserStencilOp::kDecWrap);
160 GR_STATIC_ASSERT(6 == (int)GrUserStencilOp::kIncMaybeClamp);
161 GR_STATIC_ASSERT(7 == (int)GrUserStencilOp::kDecMaybeClamp);
162 GR_STATIC_ASSERT(8 == (int)GrUserStencilOp::kZeroClipBit);
163 GR_STATIC_ASSERT(9 == (int)GrUserStencilOp::kSetClipBit);
164 GR_STATIC_ASSERT(10 == (int)GrUserStencilOp::kInvertClipBit);
165 GR_STATIC_ASSERT(11 == (int)GrUserStencilOp::kSetClipAndReplaceUserBits);
166 GR_STATIC_ASSERT(12 == (int)GrUserStencilOp::kZeroClipAndUserBits);
167 
reset(const GrUserStencilSettings::Face & user,bool hasStencilClip,int numStencilBits)168 void GrStencilSettings::Face::reset(const GrUserStencilSettings::Face& user, bool hasStencilClip,
169                                     int numStencilBits) {
170     SkASSERT(user.fTest < (GrUserStencilTest)kGrUserStencilTestCount);
171     SkASSERT(user.fPassOp < (GrUserStencilOp)kGrUserStencilOpCount);
172     SkASSERT(user.fFailOp < (GrUserStencilOp)kGrUserStencilOpCount);
173     SkASSERT(numStencilBits > 0 && numStencilBits <= 16);
174     int clipBit = 1 << (numStencilBits - 1);
175     int userMask = clipBit - 1;
176 
177     GrUserStencilOp maxOp = SkTMax(user.fPassOp, user.fFailOp);
178     SkDEBUGCODE(GrUserStencilOp otherOp = SkTMin(user.fPassOp, user.fFailOp);)
179     if (maxOp <= kLastUserOnlyStencilOp) {
180         // Ops that only modify user bits.
181         fWriteMask = user.fWriteMask & userMask;
182         SkASSERT(otherOp <= kLastUserOnlyStencilOp);
183     } else if (maxOp <= kLastClipOnlyStencilOp) {
184         // Ops that only modify the clip bit.
185         fWriteMask = clipBit;
186         SkASSERT(GrUserStencilOp::kKeep == otherOp ||
187                  (otherOp > kLastUserOnlyStencilOp && otherOp <= kLastClipOnlyStencilOp));
188     } else {
189         // Ops that modify both clip and user bits.
190         fWriteMask = clipBit | (user.fWriteMask & userMask);
191         SkASSERT(GrUserStencilOp::kKeep == otherOp || otherOp > kLastClipOnlyStencilOp);
192     }
193 
194     fFailOp = gUserStencilOpToRaw[(int)user.fFailOp];
195     fPassOp = gUserStencilOpToRaw[(int)user.fPassOp];
196 
197     if (!hasStencilClip || user.fTest > kLastClippedStencilTest) {
198         // Ignore the clip.
199         fTestMask = user.fTestMask & userMask;
200         fTest = gUserStencilTestToRaw[(int)user.fTest];
201     } else if (GrUserStencilTest::kAlwaysIfInClip != user.fTest) {
202         // Respect the clip.
203         fTestMask = clipBit | (user.fTestMask & userMask);
204         fTest = gUserStencilTestToRaw[(int)user.fTest];
205     } else {
206         // Test only for clip.
207         fTestMask = clipBit;
208         fTest = GrStencilTest::kEqual;
209     }
210 
211     fRef = (clipBit | user.fRef) & (fTestMask | fWriteMask);
212 }
213 
setDisabled()214 void GrStencilSettings::Face::setDisabled() {
215     memset(this, 0, sizeof(*this));
216     GR_STATIC_ASSERT(0 == (int)GrStencilTest::kAlways);
217     GR_STATIC_ASSERT(0 == (int)GrStencilOp::kKeep);
218 }
219 
220 ////////////////////////////////////////////////////////////////////////////////
221 // Stencil Rules for Merging user stencil space into clip
222 //
223 
224 ///////
225 // Replace
226 static constexpr GrUserStencilSettings gUserToClipReplace(
227     GrUserStencilSettings::StaticInit<
228         0x0000,
229         GrUserStencilTest::kNotEqual,
230         0xffff,
231         GrUserStencilOp::kSetClipAndReplaceUserBits,
232         GrUserStencilOp::kZeroClipAndUserBits,
233         0xffff>()
234 );
235 
236 static constexpr GrUserStencilSettings gInvUserToClipReplace(
237     GrUserStencilSettings::StaticInit<
238         0x0000,
239         GrUserStencilTest::kEqual,
240         0xffff,
241         GrUserStencilOp::kSetClipAndReplaceUserBits,
242         GrUserStencilOp::kZeroClipAndUserBits,
243         0xffff>()
244 );
245 
246 ///////
247 // Intersect
248 static constexpr GrUserStencilSettings gUserToClipIsect(
249     GrUserStencilSettings::StaticInit<
250         0x0000,
251         GrUserStencilTest::kLessIfInClip, // "0 < userBits" is equivalent to "0 != userBits".
252         0xffff,
253         GrUserStencilOp::kSetClipAndReplaceUserBits,
254         GrUserStencilOp::kZeroClipAndUserBits,
255         0xffff>()
256 );
257 
258 ///////
259 // Difference
260 static constexpr GrUserStencilSettings gUserToClipDiff(
261     GrUserStencilSettings::StaticInit<
262         0x0000,
263         GrUserStencilTest::kEqualIfInClip,
264         0xffff,
265         GrUserStencilOp::kSetClipAndReplaceUserBits,
266         GrUserStencilOp::kZeroClipAndUserBits,
267         0xffff>()
268 );
269 
270 ///////
271 // Union
272 static constexpr GrUserStencilSettings gUserToClipUnion(
273     GrUserStencilSettings::StaticInit<
274         0x0000,
275         GrUserStencilTest::kNotEqual,
276         0xffff,
277         GrUserStencilOp::kSetClipAndReplaceUserBits,
278         GrUserStencilOp::kKeep,
279         0xffff>()
280 );
281 
282 static constexpr GrUserStencilSettings gInvUserToClipUnionPass0( // Does not zero user bits.
283     GrUserStencilSettings::StaticInit<
284         0x0000,
285         GrUserStencilTest::kEqual,
286         0xffff,
287         GrUserStencilOp::kSetClipBit,
288         GrUserStencilOp::kKeep,
289         0x0000>()
290 );
291 
292 ///////
293 // Xor
294 static constexpr GrUserStencilSettings gUserToClipXorPass0( // Does not zero user bits.
295     GrUserStencilSettings::StaticInit<
296         0x0000,
297         GrUserStencilTest::kNotEqual,
298         0xffff,
299         GrUserStencilOp::kInvertClipBit,
300         GrUserStencilOp::kKeep,
301         0x0000>()
302 );
303 
304 static constexpr GrUserStencilSettings gInvUserToClipXorPass0( // Does not zero user bits.
305     GrUserStencilSettings::StaticInit<
306         0x0000,
307         GrUserStencilTest::kEqual,
308         0xffff,
309         GrUserStencilOp::kInvertClipBit,
310         GrUserStencilOp::kKeep,
311         0x0000>()
312 );
313 
314 ///////
315 // Reverse Diff
316 static constexpr GrUserStencilSettings gUserToClipRDiffPass0( // Does not zero user bits.
317     GrUserStencilSettings::StaticInit<
318         0x0000,
319         GrUserStencilTest::kNotEqual,
320         0xffff,
321         GrUserStencilOp::kInvertClipBit,
322         GrUserStencilOp::kZeroClipBit,
323         0x0000>()
324 );
325 
326 static constexpr GrUserStencilSettings gInvUserToClipRDiffPass0( // Does not zero user bits.
327     GrUserStencilSettings::StaticInit<
328         0x0000,
329         GrUserStencilTest::kEqual,
330         0xffff,
331         GrUserStencilOp::kInvertClipBit,
332         GrUserStencilOp::kZeroClipBit,
333         0x0000>()
334 );
335 
336 ///////
337 // Second pass to clear user bits (only needed sometimes)
338 static constexpr GrUserStencilSettings gZeroUserBits(
339     GrUserStencilSettings::StaticInit<
340         0x0000,
341         GrUserStencilTest::kNotEqual,
342         0xffff,
343         GrUserStencilOp::kZero,
344         GrUserStencilOp::kKeep,
345         0xffff>()
346 );
347 
348 static constexpr const GrUserStencilSettings* gUserToClipTable[2][1 + SkRegion::kLastOp][3] = {
349     {  /* Normal fill. */
350         {&gUserToClipDiff,           nullptr,         nullptr},  // kDifference_Op.
351         {&gUserToClipIsect,          nullptr,         nullptr},  // kIntersect_Op.
352         {&gUserToClipUnion,          nullptr,         nullptr},  // kUnion_Op.
353         {&gUserToClipXorPass0,       &gZeroUserBits,  nullptr},  // kXOR_Op.
354         {&gUserToClipRDiffPass0,     &gZeroUserBits,  nullptr},  // kReverseDifference_Op.
355         {&gUserToClipReplace,        nullptr,         nullptr}   // kReplace_Op.
356 
357     }, /* Inverse fill. */ {
358         {&gUserToClipIsect,          nullptr,         nullptr},  // ~diff (aka isect).
359         {&gUserToClipDiff,           nullptr,         nullptr},  // ~isect (aka diff).
360         {&gInvUserToClipUnionPass0,  &gZeroUserBits,  nullptr},  // ~union.
361         {&gInvUserToClipXorPass0,    &gZeroUserBits,  nullptr},  // ~xor.
362         {&gInvUserToClipRDiffPass0,  &gZeroUserBits,  nullptr},  // ~reverse diff.
363         {&gInvUserToClipReplace,     nullptr,         nullptr}   // ~replace.
364     }
365 };
366 
367 GR_STATIC_ASSERT(0 == SkRegion::kDifference_Op);
368 GR_STATIC_ASSERT(1 == SkRegion::kIntersect_Op);
369 GR_STATIC_ASSERT(2 == SkRegion::kUnion_Op);
370 GR_STATIC_ASSERT(3 == SkRegion::kXOR_Op);
371 GR_STATIC_ASSERT(4 == SkRegion::kReverseDifference_Op);
372 GR_STATIC_ASSERT(5 == SkRegion::kReplace_Op);
373 
374 ///////
375 // Direct to Stencil
376 
377 // We can render a clip element directly without first writing to the client
378 // portion of the clip when the fill is not inverse and the set operation will
379 // only modify the in/out status of samples covered by the clip element.
380 
381 // this one only works if used right after stencil clip was cleared.
382 // Our clip mask creation code doesn't allow midstream replace ops.
383 static constexpr GrUserStencilSettings gReplaceClip(
384     GrUserStencilSettings::StaticInit<
385         0x0000,
386         GrUserStencilTest::kAlways,
387         0xffff,
388         GrUserStencilOp::kSetClipBit,
389         GrUserStencilOp::kSetClipBit,
390         0x0000>()
391 );
392 
393 static constexpr GrUserStencilSettings gUnionClip(
394     GrUserStencilSettings::StaticInit<
395         0x0000,
396         GrUserStencilTest::kAlwaysIfInClip,
397         0xffff,
398         GrUserStencilOp::kKeep,
399         GrUserStencilOp::kSetClipBit,
400         0x0000>()
401 );
402 
403 static constexpr GrUserStencilSettings gXorClip(
404     GrUserStencilSettings::StaticInit<
405         0x0000,
406         GrUserStencilTest::kAlways,
407         0xffff,
408         GrUserStencilOp::kInvertClipBit,
409         GrUserStencilOp::kInvertClipBit,
410         0x0000>()
411 );
412 
413 static constexpr GrUserStencilSettings gDiffClip(
414     GrUserStencilSettings::StaticInit<
415         0x0000,
416         GrUserStencilTest::kAlwaysIfInClip,
417         0xffff,
418         GrUserStencilOp::kZeroClipBit,
419         GrUserStencilOp::kKeep,
420         0x0000>()
421 );
422 
423 static constexpr const GrUserStencilSettings* gDirectDrawTable[1 + SkRegion::kLastOp][2] = {
424     {&gDiffClip,     nullptr},  // kDifference_Op.
425     {nullptr,        nullptr},  // kIntersect_Op.
426     {&gUnionClip,    nullptr},  // kUnion_Op.
427     {&gXorClip,      nullptr},  // kXOR_Op.
428     {nullptr,        nullptr},  // kReverseDifference_Op.
429     {&gReplaceClip,  nullptr}   // kReplace_Op.
430 };
431 
432 GR_STATIC_ASSERT(0 == SkRegion::kDifference_Op);
433 GR_STATIC_ASSERT(1 == SkRegion::kIntersect_Op);
434 GR_STATIC_ASSERT(2 == SkRegion::kUnion_Op);
435 GR_STATIC_ASSERT(3 == SkRegion::kXOR_Op);
436 GR_STATIC_ASSERT(4 == SkRegion::kReverseDifference_Op);
437 GR_STATIC_ASSERT(5 == SkRegion::kReplace_Op);
438 
GetClipPasses(SkRegion::Op op,bool canBeDirect,bool invertedFill,bool * drawDirectToClip)439 GrUserStencilSettings const* const* GrStencilSettings::GetClipPasses(SkRegion::Op op,
440                                                                      bool canBeDirect,
441                                                                      bool invertedFill,
442                                                                      bool* drawDirectToClip) {
443     SkASSERT((unsigned)op <= SkRegion::kLastOp);
444     if (canBeDirect && !invertedFill) { // TODO: inverse fill + intersect op can be direct.
445         GrUserStencilSettings const* const* directPass = gDirectDrawTable[op];
446         if (directPass[0]) {
447             *drawDirectToClip = true;
448             return directPass;
449         }
450     }
451     *drawDirectToClip = false;
452     return gUserToClipTable[invertedFill][op];
453 }
454 
genKey(GrProcessorKeyBuilder * b) const455 void GrStencilSettings::genKey(GrProcessorKeyBuilder* b) const {
456     b->add32(fFlags);
457     if (this->isDisabled()) {
458         return;
459     }
460     if (!this->isTwoSided()) {
461         constexpr int kCount16 = sizeof(Face) / sizeof(uint16_t);
462         GR_STATIC_ASSERT(0 == sizeof(Face) % sizeof(uint16_t));
463         uint16_t* key = reinterpret_cast<uint16_t*>(b->add32n((kCount16 + 1) / 2));
464         memcpy(key, &fFront, sizeof(Face));
465         key[kCount16] = 0;
466         GR_STATIC_ASSERT(1 == kCount16 % 2);
467     } else {
468         constexpr int kCount32 = (2 * sizeof(Face)) / sizeof(uint32_t);
469         GR_STATIC_ASSERT(0 == (2 * sizeof(Face)) % sizeof(uint32_t));
470         uint32_t* key = b->add32n(kCount32);
471         memcpy(key, &fFront, 2 * sizeof(Face));
472         GR_STATIC_ASSERT(sizeof(Face) ==
473                          offsetof(GrStencilSettings, fBack) - offsetof(GrStencilSettings, fFront));
474     }
475     // We rely on GrStencilSettings::Face being tightly packed for the key to be reliable.
476     GR_STATIC_ASSERT(0 == offsetof(Face, fRef));
477     GR_STATIC_ASSERT(2 == sizeof(Face::fRef));
478     GR_STATIC_ASSERT(2 == offsetof(Face, fTest));
479     GR_STATIC_ASSERT(2 == sizeof(Face::fTest));
480     GR_STATIC_ASSERT(4 == offsetof(Face, fTestMask));
481     GR_STATIC_ASSERT(2 == sizeof(Face::fTestMask));
482     GR_STATIC_ASSERT(6 == offsetof(Face, fPassOp));
483     GR_STATIC_ASSERT(1 == sizeof(Face::fPassOp));
484     GR_STATIC_ASSERT(7 == offsetof(Face, fFailOp));
485     GR_STATIC_ASSERT(1 == sizeof(Face::fFailOp));
486     GR_STATIC_ASSERT(8 == offsetof(Face, fWriteMask));
487     GR_STATIC_ASSERT(2 == sizeof(Face::fWriteMask));
488     GR_STATIC_ASSERT(10 == sizeof(Face));
489 }
490