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