Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(218)

Unified Diff: src/gpu/GrStencil.cpp

Issue 1962243002: Separate user and raw stencil settings (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/gpu/GrStencil.cpp
diff --git a/src/gpu/GrStencil.cpp b/src/gpu/GrStencil.cpp
index 94559ab68eb6333ccd09692eb7e2df4acf8535ba..a8b0cc41bacb28746f5632cf56cb14b136cbfd7a 100644
--- a/src/gpu/GrStencil.cpp
+++ b/src/gpu/GrStencil.cpp
@@ -10,184 +10,367 @@
#include "GrProcessor.h"
+constexpr const GrUserStencilSettings gUnused(
+ GrUserStencilSettings::StaticInit<
+ 0x0000,
+ GrUserStencilTest::kAlwaysIfInClip,
+ 0xffff,
+ GrUserStencilOp::kKeep,
+ GrUserStencilOp::kKeep,
+ 0x0000>()
+);
+
+GR_STATIC_ASSERT(kAll_StencilFlags == (gUnused.fFrontFlags[0] & gUnused.fBackFlags[0]));
+
+const GrUserStencilSettings& GrUserStencilSettings::kUnused = gUnused;
+
+void GrStencilSettings::reset(const GrUserStencilSettings& user, bool hasStencilClip,
+ int numStencilBits) {
+ uint16_t frontFlags = user.fFrontFlags[hasStencilClip];
+ if (frontFlags & kSingleSided_StencilFlag) {
+ fFlags = frontFlags;
+ if (!this->isDisabled()) {
+ fFront.reset(user.fFront, hasStencilClip, numStencilBits);
+ }
+ return;
+ }
+
+ uint16_t backFlags = user.fBackFlags[hasStencilClip];
+ fFlags = frontFlags & backFlags;
+ if (this->isDisabled()) {
+ return;
+ }
+ if (!(frontFlags & kDisabled_StencilFlag)) {
+ fFront.reset(user.fFront, hasStencilClip, numStencilBits);
+ } else {
+ fFront.setDisabled();
+ }
+ if (!(backFlags & kDisabled_StencilFlag)) {
+ fBack.reset(user.fBack, hasStencilClip, numStencilBits);
+ } else {
+ fBack.setDisabled();
+ }
+}
+
+void GrStencilSettings::reset(const GrStencilSettings& that) {
+ fFlags = that.fFlags;
+ if ((kInvalid_PrivateFlag | kDisabled_StencilFlag) & fFlags) {
+ return;
+ }
+ if (!this->isTwoSided()) {
+ memcpy(&fFront, &that.fFront, sizeof(Face));
+ } else {
+ memcpy(&fFront, &that.fFront, 2 * sizeof(Face));
+ GR_STATIC_ASSERT(sizeof(Face) ==
+ offsetof(GrStencilSettings, fBack) - offsetof(GrStencilSettings, fFront));
+ }
+}
+
+bool GrStencilSettings::operator==(const GrStencilSettings& that) const {
+ if ((kInvalid_PrivateFlag | kDisabled_StencilFlag) & (fFlags | that.fFlags)) {
+ // At least one is invalid and/or disabled.
+ if (kInvalid_PrivateFlag & (fFlags | that.fFlags)) {
+ return false; // We never allow invalid stencils to be equal.
+ }
+ // They're only equal if both are disabled.
+ return kDisabled_StencilFlag & (fFlags & that.fFlags);
+ }
+ if (kSingleSided_StencilFlag & (fFlags & that.fFlags)) {
+ return 0 == memcmp(&fFront, &that.fFront, sizeof(Face)); // Both are single sided.
+ } else {
+ return 0 == memcmp(&fFront, &that.fFront, 2 * sizeof(Face));
+ GR_STATIC_ASSERT(sizeof(Face) ==
+ offsetof(GrStencilSettings, fBack) - offsetof(GrStencilSettings, fFront));
+ }
+ // memcmp relies on GrStencilSettings::Face being tightly packed.
+ GR_STATIC_ASSERT(0 == offsetof(Face, fRef));
+ GR_STATIC_ASSERT(2 == sizeof(Face::fRef));
+ GR_STATIC_ASSERT(2 == offsetof(Face, fTest));
+ GR_STATIC_ASSERT(2 == sizeof(Face::fTest));
+ GR_STATIC_ASSERT(4 == offsetof(Face, fTestMask));
+ GR_STATIC_ASSERT(2 == sizeof(Face::fTestMask));
+ GR_STATIC_ASSERT(6 == offsetof(Face, fPassOp));
+ GR_STATIC_ASSERT(1 == sizeof(Face::fPassOp));
+ GR_STATIC_ASSERT(7 == offsetof(Face, fFailOp));
+ GR_STATIC_ASSERT(1 == sizeof(Face::fFailOp));
+ GR_STATIC_ASSERT(8 == offsetof(Face, fWriteMask));
+ GR_STATIC_ASSERT(2 == sizeof(Face::fWriteMask));
+ GR_STATIC_ASSERT(10 == sizeof(Face));
+}
+
+static constexpr GrStencilTest gUserStencilTestToRaw[kGrUserStencilTestCount] = {
+ // Tests that respect the clip.
+ GrStencilTest::kAlways, // kAlwaysIfInClip (This is only for when there is not a stencil clip).
+ GrStencilTest::kEqual, // kEqualIfInClip.
+ GrStencilTest::kLess, // kLessIfInClip.
+ GrStencilTest::kLEqual, // kLEqualIfInClip.
+
+ // Tests that ignore the clip.
+ GrStencilTest::kAlways,
+ GrStencilTest::kNever,
+ GrStencilTest::kGreater,
+ GrStencilTest::kGEqual,
+ GrStencilTest::kLess,
+ GrStencilTest::kLEqual,
+ GrStencilTest::kEqual,
+ GrStencilTest::kNotEqual
+};
+
+GR_STATIC_ASSERT(0 == (int)GrUserStencilTest::kAlwaysIfInClip);
+GR_STATIC_ASSERT(1 == (int)GrUserStencilTest::kEqualIfInClip);
+GR_STATIC_ASSERT(2 == (int)GrUserStencilTest::kLessIfInClip);
+GR_STATIC_ASSERT(3 == (int)GrUserStencilTest::kLEqualIfInClip);
+GR_STATIC_ASSERT(4 == (int)GrUserStencilTest::kAlways);
+GR_STATIC_ASSERT(5 == (int)GrUserStencilTest::kNever);
+GR_STATIC_ASSERT(6 == (int)GrUserStencilTest::kGreater);
+GR_STATIC_ASSERT(7 == (int)GrUserStencilTest::kGEqual);
+GR_STATIC_ASSERT(8 == (int)GrUserStencilTest::kLess);
+GR_STATIC_ASSERT(9 == (int)GrUserStencilTest::kLEqual);
+GR_STATIC_ASSERT(10 == (int)GrUserStencilTest::kEqual);
+GR_STATIC_ASSERT(11 == (int)GrUserStencilTest::kNotEqual);
+
+static constexpr GrStencilOp gUserStencilOpToRaw[kGrUserStencilOpCount] = {
+ GrStencilOp::kKeep,
+
+ // Ops that only modify user bits.
+ GrStencilOp::kZero,
+ GrStencilOp::kReplace,
+ GrStencilOp::kInvert,
+ GrStencilOp::kIncWrap,
+ GrStencilOp::kDecWrap,
+ GrStencilOp::kIncClamp, // kIncMaybeClamp.
+ GrStencilOp::kDecClamp, // kDecMaybeClamp.
+
+ // Ops that only modify the clip bit.
+ GrStencilOp::kZero, // kZeroClipBit.
+ GrStencilOp::kReplace, // kSetClipBit.
+ GrStencilOp::kInvert, // kInvertClipBit.
+
+ // Ops that modify clip and user bits.
+ GrStencilOp::kReplace, // kSetClipAndReplaceUserBits.
+ GrStencilOp::kZero // kZeroClipAndUserBits.
+};
+
+GR_STATIC_ASSERT(0 == (int)GrUserStencilOp::kKeep);
+GR_STATIC_ASSERT(1 == (int)GrUserStencilOp::kZero);
+GR_STATIC_ASSERT(2 == (int)GrUserStencilOp::kReplace);
+GR_STATIC_ASSERT(3 == (int)GrUserStencilOp::kInvert);
+GR_STATIC_ASSERT(4 == (int)GrUserStencilOp::kIncWrap);
+GR_STATIC_ASSERT(5 == (int)GrUserStencilOp::kDecWrap);
+GR_STATIC_ASSERT(6 == (int)GrUserStencilOp::kIncMaybeClamp);
+GR_STATIC_ASSERT(7 == (int)GrUserStencilOp::kDecMaybeClamp);
+GR_STATIC_ASSERT(8 == (int)GrUserStencilOp::kZeroClipBit);
+GR_STATIC_ASSERT(9 == (int)GrUserStencilOp::kSetClipBit);
+GR_STATIC_ASSERT(10 == (int)GrUserStencilOp::kInvertClipBit);
+GR_STATIC_ASSERT(11 == (int)GrUserStencilOp::kSetClipAndReplaceUserBits);
+GR_STATIC_ASSERT(12 == (int)GrUserStencilOp::kZeroClipAndUserBits);
+
+void GrStencilSettings::Face::reset(const GrUserStencilSettings::Face& user, bool hasStencilClip,
+ int numStencilBits) {
+ SkASSERT(user.fTest < (GrUserStencilTest)kGrUserStencilTestCount);
+ SkASSERT(user.fPassOp < (GrUserStencilOp)kGrUserStencilOpCount);
+ SkASSERT(user.fFailOp < (GrUserStencilOp)kGrUserStencilOpCount);
+ SkASSERT(numStencilBits <= 16);
+ int clipBit = 1 << (numStencilBits - 1);
+ int userMask = clipBit - 1;
+
+ GrUserStencilOp maxOp = SkTMax(user.fPassOp, user.fFailOp);
+ SkDEBUGCODE(GrUserStencilOp otherOp = SkTMin(user.fPassOp, user.fFailOp);)
+ if (maxOp <= kLastUserOnlyStencilOp) {
+ // Ops that only modify user bits.
+ fWriteMask = user.fWriteMask & userMask;
+ SkASSERT(otherOp <= kLastUserOnlyStencilOp);
+ } else if (maxOp <= kLastClipOnlyStencilOp) {
+ // Ops that only modify the clip bit.
+ fWriteMask = clipBit;
+ SkASSERT(GrUserStencilOp::kKeep == otherOp ||
+ (otherOp > kLastUserOnlyStencilOp && otherOp <= kLastClipOnlyStencilOp));
+ } else {
+ // Ops that modify both clip and user bits.
+ fWriteMask = clipBit | (user.fWriteMask & userMask);
+ SkASSERT(GrUserStencilOp::kKeep == otherOp || otherOp > kLastClipOnlyStencilOp);
+ }
+
+ fFailOp = gUserStencilOpToRaw[(int)user.fFailOp];
+ fPassOp = gUserStencilOpToRaw[(int)user.fPassOp];
+
+ if (!hasStencilClip || user.fTest > kLastClippedStencilTest) {
+ // Ignore the clip.
+ fTestMask = user.fTestMask & userMask;
+ fTest = gUserStencilTestToRaw[(int)user.fTest];
+ } else if (GrUserStencilTest::kAlwaysIfInClip != user.fTest) {
+ // Respect the clip.
+ fTestMask = clipBit | (user.fTestMask & userMask);
+ fTest = gUserStencilTestToRaw[(int)user.fTest];
+ } else {
+ // Test only for clip.
+ fTestMask = clipBit;
+ fTest = GrStencilTest::kEqual;
+ }
+
+ fRef = (clipBit | user.fRef) & (fTestMask | fWriteMask);
+}
+
+void GrStencilSettings::Face::setDisabled() {
+ memset(this, 0, sizeof(*this));
+ GR_STATIC_ASSERT(0 == (int)GrStencilTest::kAlways);
+ GR_STATIC_ASSERT(0 == (int)GrStencilOp::kKeep);
+}
+
////////////////////////////////////////////////////////////////////////////////
// Stencil Rules for Merging user stencil space into clip
-
-// We can't include the clip bit in the ref or mask values because the division
-// between user and clip bits in the stencil depends on the number of stencil
-// bits in the runtime. Comments below indicate what the code should do to
-// incorporate the clip bit into these settings.
+//
///////
// Replace
+static constexpr GrUserStencilSettings gUserToClipReplace(
+ GrUserStencilSettings::StaticInit<
+ 0x0000,
+ GrUserStencilTest::kNotEqual,
+ 0xffff,
+ GrUserStencilOp::kSetClipAndReplaceUserBits,
+ GrUserStencilOp::kZeroClipAndUserBits,
+ 0xffff>()
+);
-// set the ref to be the clip bit, but mask it out for the test
-static constexpr GrStencilSettings gUserToClipReplace(
- kReplace_StencilOp,
- kZero_StencilOp,
- kLess_StencilFunc,
- 0xffff, // unset clip bit
- 0x0000, // set clip bit
- 0xffff);
-
-static constexpr GrStencilSettings gInvUserToClipReplace(
- kReplace_StencilOp,
- kZero_StencilOp,
- kEqual_StencilFunc,
- 0xffff, // unset clip bit
- 0x0000, // set clip bit
- 0xffff);
+static constexpr GrUserStencilSettings gInvUserToClipReplace(
+ GrUserStencilSettings::StaticInit<
+ 0x0000,
+ GrUserStencilTest::kEqual,
+ 0xffff,
+ GrUserStencilOp::kSetClipAndReplaceUserBits,
+ GrUserStencilOp::kZeroClipAndUserBits,
+ 0xffff>()
+);
///////
// Intersect
-static constexpr GrStencilSettings gUserToClipIsect(
- kReplace_StencilOp,
- kZero_StencilOp,
- kLess_StencilFunc,
- 0xffff,
- 0x0000, // set clip bit
- 0xffff);
-
-static constexpr GrStencilSettings gInvUserToClipIsect(
- kReplace_StencilOp,
- kZero_StencilOp,
- kEqual_StencilFunc,
- 0xffff,
- 0x0000, // set clip bit
- 0xffff);
+static constexpr GrUserStencilSettings gUserToClipIsect(
+ GrUserStencilSettings::StaticInit<
+ 0x0000,
+ GrUserStencilTest::kLessIfInClip, // "0 < userBits" is equivalent to "0 != userBits".
+ 0xffff,
+ GrUserStencilOp::kSetClipAndReplaceUserBits,
+ GrUserStencilOp::kZeroClipAndUserBits,
+ 0xffff>()
+);
///////
// Difference
-static constexpr GrStencilSettings gUserToClipDiff(
- kReplace_StencilOp,
- kZero_StencilOp,
- kEqual_StencilFunc,
- 0xffff,
- 0x0000, // set clip bit
- 0xffff);
-
-static constexpr GrStencilSettings gInvUserToClipDiff(
- kReplace_StencilOp,
- kZero_StencilOp,
- kLess_StencilFunc,
- 0xffff,
- 0x0000, // set clip bit
- 0xffff);
+static constexpr GrUserStencilSettings gUserToClipDiff(
+ GrUserStencilSettings::StaticInit<
+ 0x0000,
+ GrUserStencilTest::kEqualIfInClip,
+ 0xffff,
+ GrUserStencilOp::kSetClipAndReplaceUserBits,
+ GrUserStencilOp::kZeroClipAndUserBits,
+ 0xffff>()
+);
///////
// Union
-
-// first pass makes all the passing cases >= just clip bit set.
-static constexpr GrStencilSettings gUserToClipUnionPass0(
- kReplace_StencilOp,
- kKeep_StencilOp,
- kLEqual_StencilFunc,
- 0xffff,
- 0x0001, // set clip bit
- 0xffff);
-
-// second pass allows anything greater than just clip bit set to pass
-static constexpr GrStencilSettings gUserToClipUnionPass1(
- kReplace_StencilOp,
- kZero_StencilOp,
- kLEqual_StencilFunc,
- 0xffff,
- 0x0000, // set clip bit
- 0xffff);
-
-// first pass finds zeros in the user bits and if found sets
-// the clip bit to 1
-static constexpr GrStencilSettings gInvUserToClipUnionPass0(
- kReplace_StencilOp,
- kKeep_StencilOp,
- kEqual_StencilFunc,
- 0xffff,
- 0x0000, // set clip bit
- 0x0000 // set clip bit
+static constexpr GrUserStencilSettings gUserToClipUnion(
+ GrUserStencilSettings::StaticInit<
+ 0x0000,
+ GrUserStencilTest::kNotEqual,
+ 0xffff,
+ GrUserStencilOp::kSetClipAndReplaceUserBits,
+ GrUserStencilOp::kKeep,
+ 0xffff>()
);
-// second pass zeros the user bits
-static constexpr GrStencilSettings gInvUserToClipUnionPass1(
- kZero_StencilOp,
- kZero_StencilOp,
- kLess_StencilFunc,
- 0xffff,
- 0x0000,
- 0xffff // unset clip bit
+static constexpr GrUserStencilSettings gInvUserToClipUnionPass0( // Does not zero user bits.
+ GrUserStencilSettings::StaticInit<
+ 0x0000,
+ GrUserStencilTest::kEqual,
+ 0xffff,
+ GrUserStencilOp::kSetClipBit,
+ GrUserStencilOp::kKeep,
+ 0x0000>()
);
///////
// Xor
-static constexpr GrStencilSettings gUserToClipXorPass0(
- kInvert_StencilOp,
- kKeep_StencilOp,
- kEqual_StencilFunc,
- 0xffff, // unset clip bit
- 0x0000,
- 0xffff);
-
-static constexpr GrStencilSettings gUserToClipXorPass1(
- kReplace_StencilOp,
- kZero_StencilOp,
- kGreater_StencilFunc,
- 0xffff,
- 0x0000, // set clip bit
- 0xffff);
-
-static constexpr GrStencilSettings gInvUserToClipXorPass0(
- kInvert_StencilOp,
- kKeep_StencilOp,
- kEqual_StencilFunc,
- 0xffff, // unset clip bit
- 0x0000,
- 0xffff);
-
-static constexpr GrStencilSettings gInvUserToClipXorPass1(
- kReplace_StencilOp,
- kZero_StencilOp,
- kLess_StencilFunc,
- 0xffff,
- 0x0000, // set clip bit
- 0xffff);
+static constexpr GrUserStencilSettings gUserToClipXorPass0( // Does not zero user bits.
+ GrUserStencilSettings::StaticInit<
+ 0x0000,
+ GrUserStencilTest::kNotEqual,
+ 0xffff,
+ GrUserStencilOp::kInvertClipBit,
+ GrUserStencilOp::kKeep,
+ 0x0000>()
+);
+
+static constexpr GrUserStencilSettings gInvUserToClipXorPass0( // Does not zero user bits.
+ GrUserStencilSettings::StaticInit<
+ 0x0000,
+ GrUserStencilTest::kEqual,
+ 0xffff,
+ GrUserStencilOp::kInvertClipBit,
+ GrUserStencilOp::kKeep,
+ 0x0000>()
+);
///////
// Reverse Diff
-static constexpr GrStencilSettings gUserToClipRDiffPass0(
- kInvert_StencilOp,
- kZero_StencilOp,
- kLess_StencilFunc,
- 0xffff, // unset clip bit
- 0x0000, // set clip bit
- 0xffff);
-
-static constexpr GrStencilSettings gUserToClipRDiffPass1(
- kReplace_StencilOp,
- kZero_StencilOp,
- kEqual_StencilFunc,
- 0x0000, // set clip bit
- 0x0000, // set clip bit
- 0xffff);
-
-// We are looking for stencil values that are all zero. The first pass sets the
-// clip bit if the stencil is all zeros. The second pass clears the user bits.
-static constexpr GrStencilSettings gInvUserToClipRDiffPass0(
- kInvert_StencilOp,
- kZero_StencilOp,
- kEqual_StencilFunc,
- 0xffff,
- 0x0000,
- 0x0000 // set clip bit
+static constexpr GrUserStencilSettings gUserToClipRDiffPass0( // Does not zero user bits.
+ GrUserStencilSettings::StaticInit<
+ 0x0000,
+ GrUserStencilTest::kNotEqual,
+ 0xffff,
+ GrUserStencilOp::kInvertClipBit,
+ GrUserStencilOp::kZeroClipBit,
+ 0x0000>()
+);
+
+static constexpr GrUserStencilSettings gInvUserToClipRDiffPass0( // Does not zero user bits.
+ GrUserStencilSettings::StaticInit<
+ 0x0000,
+ GrUserStencilTest::kEqual,
+ 0xffff,
+ GrUserStencilOp::kInvertClipBit,
+ GrUserStencilOp::kZeroClipBit,
+ 0x0000>()
);
-static constexpr GrStencilSettings gInvUserToClipRDiffPass1(
- kZero_StencilOp,
- kZero_StencilOp,
- kAlways_StencilFunc,
- 0xffff,
- 0x0000,
- 0xffff // unset clip bit
+///////
+// Second pass to clear user bits (only needed sometimes)
+static constexpr GrUserStencilSettings gZeroUserBits(
+ GrUserStencilSettings::StaticInit<
+ 0x0000,
+ GrUserStencilTest::kNotEqual,
+ 0xffff,
+ GrUserStencilOp::kZero,
+ GrUserStencilOp::kKeep,
+ 0xffff>()
);
+static constexpr const GrUserStencilSettings* gUserToClipTable[2][1 + SkRegion::kLastOp][3] = {
+ { /* Normal fill. */
+ {&gUserToClipDiff, nullptr, nullptr}, // kDifference_Op.
+ {&gUserToClipIsect, nullptr, nullptr}, // kIntersect_Op.
+ {&gUserToClipUnion, nullptr, nullptr}, // kUnion_Op.
+ {&gUserToClipXorPass0, &gZeroUserBits, nullptr}, // kXOR_Op.
+ {&gUserToClipRDiffPass0, &gZeroUserBits, nullptr}, // kReverseDifference_Op.
+ {&gUserToClipReplace, nullptr, nullptr} // kReplace_Op.
+
+ }, /* Inverse fill. */ {
+ {&gUserToClipIsect, nullptr, nullptr}, // ~diff (aka isect).
+ {&gUserToClipDiff, nullptr, nullptr}, // ~isect (aka diff).
+ {&gInvUserToClipUnionPass0, &gZeroUserBits, nullptr}, // ~union.
+ {&gInvUserToClipXorPass0, &gZeroUserBits, nullptr}, // ~xor.
+ {&gInvUserToClipRDiffPass0, &gZeroUserBits, nullptr}, // ~reverse diff.
+ {&gInvUserToClipReplace, nullptr, nullptr} // ~replace.
+ }
+};
+
+GR_STATIC_ASSERT(0 == SkRegion::kDifference_Op);
+GR_STATIC_ASSERT(1 == SkRegion::kIntersect_Op);
+GR_STATIC_ASSERT(2 == SkRegion::kUnion_Op);
+GR_STATIC_ASSERT(3 == SkRegion::kXOR_Op);
+GR_STATIC_ASSERT(4 == SkRegion::kReverseDifference_Op);
+GR_STATIC_ASSERT(5 == SkRegion::kReplace_Op);
+
///////
// Direct to Stencil
@@ -197,207 +380,110 @@ static constexpr GrStencilSettings gInvUserToClipRDiffPass1(
// this one only works if used right after stencil clip was cleared.
// Our clip mask creation code doesn't allow midstream replace ops.
-static constexpr GrStencilSettings gReplaceClip(
- kReplace_StencilOp,
- kReplace_StencilOp,
- kAlways_StencilFunc,
- 0xffff,
- 0x0000, // set clip bit
- 0x0000 // set clipBit
+static constexpr GrUserStencilSettings gReplaceClip(
+ GrUserStencilSettings::StaticInit<
+ 0x0000,
+ GrUserStencilTest::kAlways,
+ 0xffff,
+ GrUserStencilOp::kSetClipBit,
+ GrUserStencilOp::kSetClipBit,
+ 0x0000>()
);
-static constexpr GrStencilSettings gUnionClip(
- kReplace_StencilOp,
- kReplace_StencilOp,
- kAlways_StencilFunc,
- 0xffff,
- 0x0000, // set clip bit
- 0x0000 // set clip bit
+static constexpr GrUserStencilSettings gUnionClip(
+ GrUserStencilSettings::StaticInit<
+ 0x0000,
+ GrUserStencilTest::kAlwaysIfInClip,
+ 0xffff,
+ GrUserStencilOp::kKeep,
+ GrUserStencilOp::kSetClipBit,
+ 0x0000>()
);
-static constexpr GrStencilSettings gXorClip(
- kInvert_StencilOp,
- kInvert_StencilOp,
- kAlways_StencilFunc,
- 0xffff,
- 0x0000,
- 0x0000 // set clip bit
+static constexpr GrUserStencilSettings gXorClip(
+ GrUserStencilSettings::StaticInit<
+ 0x0000,
+ GrUserStencilTest::kAlways,
+ 0xffff,
+ GrUserStencilOp::kInvertClipBit,
+ GrUserStencilOp::kInvertClipBit,
+ 0x0000>()
);
-static constexpr GrStencilSettings gDiffClip(
- kZero_StencilOp,
- kZero_StencilOp,
- kAlways_StencilFunc,
- 0xffff,
- 0x0000,
- 0x0000 // set clip bit
+static constexpr GrUserStencilSettings gDiffClip(
+ GrUserStencilSettings::StaticInit<
+ 0x0000,
+ GrUserStencilTest::kAlwaysIfInClip,
+ 0xffff,
+ GrUserStencilOp::kZeroClipBit,
+ GrUserStencilOp::kKeep,
+ 0x0000>()
);
-bool GrStencilSettings::GetClipPasses(
- SkRegion::Op op,
- bool canBeDirect,
- unsigned int stencilClipMask,
- bool invertedFill,
- int* numPasses,
- GrStencilSettings settings[kMaxStencilClipPasses]) {
- if (canBeDirect && !invertedFill) {
- *numPasses = 0;
- switch (op) {
- case SkRegion::kReplace_Op:
- *numPasses = 1;
- settings[0] = gReplaceClip;
- break;
- case SkRegion::kUnion_Op:
- *numPasses = 1;
- settings[0] = gUnionClip;
- break;
- case SkRegion::kXOR_Op:
- *numPasses = 1;
- settings[0] = gXorClip;
- break;
- case SkRegion::kDifference_Op:
- *numPasses = 1;
- settings[0] = gDiffClip;
- break;
- default: // suppress warning
- break;
- }
- if (1 == *numPasses) {
- settings[0].fFuncRefs[kFront_Face] |= stencilClipMask;
- settings[0].fWriteMasks[kFront_Face] |= stencilClipMask;
- settings[0].fFuncRefs[kBack_Face] =
- settings[0].fFuncRefs[kFront_Face];
- settings[0].fWriteMasks[kBack_Face] =
- settings[0].fWriteMasks[kFront_Face];
- return true;
+static constexpr const GrUserStencilSettings* gDirectDrawTable[1 + SkRegion::kLastOp][2] = {
+ {&gDiffClip, nullptr}, // kDifference_Op.
+ {nullptr, nullptr}, // kIntersect_Op.
+ {&gUnionClip, nullptr}, // kUnion_Op.
+ {&gXorClip, nullptr}, // kXOR_Op.
+ {nullptr, nullptr}, // kReverseDifference_Op.
+ {&gReplaceClip, nullptr} // kReplace_Op.
+};
+
+GR_STATIC_ASSERT(0 == SkRegion::kDifference_Op);
+GR_STATIC_ASSERT(1 == SkRegion::kIntersect_Op);
+GR_STATIC_ASSERT(2 == SkRegion::kUnion_Op);
+GR_STATIC_ASSERT(3 == SkRegion::kXOR_Op);
+GR_STATIC_ASSERT(4 == SkRegion::kReverseDifference_Op);
+GR_STATIC_ASSERT(5 == SkRegion::kReplace_Op);
+
+GrUserStencilSettings const* const* GrStencilSettings::GetClipPasses(SkRegion::Op op,
+ bool canBeDirect,
+ bool invertedFill,
+ bool* drawDirectToClip) {
+ SkASSERT((unsigned)op <= SkRegion::kLastOp);
+ if (canBeDirect && !invertedFill) { // TODO: inverse fill + intersect op can be direct.
+ GrUserStencilSettings const* const* directPass = gDirectDrawTable[op];
+ if (directPass[0]) {
+ *drawDirectToClip = true;
+ return directPass;
}
}
- switch (op) {
- // if we make the path renderer go to stencil we always give it a
- // non-inverted fill and we use the stencil rules on the client->clipbit
- // pass to select either the zeros or nonzeros.
- case SkRegion::kReplace_Op:
- *numPasses= 1;
- settings[0] = invertedFill ? gInvUserToClipReplace :
- gUserToClipReplace;
- settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask;
- settings[0].fFuncRefs[kFront_Face] |= stencilClipMask;
- settings[0].fFuncMasks[kBack_Face] =
- settings[0].fFuncMasks[kFront_Face];
- settings[0].fFuncRefs[kBack_Face] =
- settings[0].fFuncRefs[kFront_Face];
- break;
- case SkRegion::kIntersect_Op:
- *numPasses = 1;
- settings[0] = invertedFill ? gInvUserToClipIsect : gUserToClipIsect;
- settings[0].fFuncRefs[kFront_Face] = stencilClipMask;
- settings[0].fFuncRefs[kBack_Face] =
- settings[0].fFuncRefs[kFront_Face];
- break;
- case SkRegion::kUnion_Op:
- *numPasses = 2;
- if (invertedFill) {
- settings[0] = gInvUserToClipUnionPass0;
- settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask;
- settings[0].fFuncMasks[kBack_Face] =
- settings[0].fFuncMasks[kFront_Face];
- settings[0].fFuncRefs[kFront_Face] |= stencilClipMask;
- settings[0].fFuncRefs[kBack_Face] =
- settings[0].fFuncRefs[kFront_Face];
- settings[0].fWriteMasks[kFront_Face] |= stencilClipMask;
- settings[0].fWriteMasks[kBack_Face] =
- settings[0].fWriteMasks[kFront_Face];
-
- settings[1] = gInvUserToClipUnionPass1;
- settings[1].fWriteMasks[kFront_Face] &= ~stencilClipMask;
- settings[1].fWriteMasks[kBack_Face] &=
- settings[1].fWriteMasks[kFront_Face];
-
- } else {
- settings[0] = gUserToClipUnionPass0;
- settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask;
- settings[0].fFuncRefs[kFront_Face] |= stencilClipMask;
- settings[0].fFuncMasks[kBack_Face] =
- settings[0].fFuncMasks[kFront_Face];
- settings[0].fFuncRefs[kBack_Face] =
- settings[0].fFuncRefs[kFront_Face];
-
- settings[1] = gUserToClipUnionPass1;
- settings[1].fFuncRefs[kFront_Face] |= stencilClipMask;
- settings[1].fFuncRefs[kBack_Face] =
- settings[1].fFuncRefs[kFront_Face];
- }
- break;
- case SkRegion::kXOR_Op:
- *numPasses = 2;
- if (invertedFill) {
- settings[0] = gInvUserToClipXorPass0;
- settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask;
- settings[0].fFuncMasks[kBack_Face] =
- settings[0].fFuncMasks[kFront_Face];
-
- settings[1] = gInvUserToClipXorPass1;
- settings[1].fFuncRefs[kFront_Face] |= stencilClipMask;
- settings[1].fFuncRefs[kBack_Face] =
- settings[1].fFuncRefs[kFront_Face];
- } else {
- settings[0] = gUserToClipXorPass0;
- settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask;
- settings[0].fFuncMasks[kBack_Face] =
- settings[0].fFuncMasks[kFront_Face];
-
- settings[1] = gUserToClipXorPass1;
- settings[1].fFuncRefs[kFront_Face] |= stencilClipMask;
- settings[1].fFuncRefs[kBack_Face] =
- settings[1].fFuncRefs[kFront_Face];
- }
- break;
- case SkRegion::kDifference_Op:
- *numPasses = 1;
- settings[0] = invertedFill ? gInvUserToClipDiff : gUserToClipDiff;
- settings[0].fFuncRefs[kFront_Face] |= stencilClipMask;
- settings[0].fFuncRefs[kBack_Face] =
- settings[0].fFuncRefs[kFront_Face];
- break;
- case SkRegion::kReverseDifference_Op:
- if (invertedFill) {
- *numPasses = 2;
- settings[0] = gInvUserToClipRDiffPass0;
- settings[0].fWriteMasks[kFront_Face] |= stencilClipMask;
- settings[0].fWriteMasks[kBack_Face] =
- settings[0].fWriteMasks[kFront_Face];
- settings[1] = gInvUserToClipRDiffPass1;
- settings[1].fWriteMasks[kFront_Face] &= ~stencilClipMask;
- settings[1].fWriteMasks[kBack_Face] =
- settings[1].fWriteMasks[kFront_Face];
- } else {
- *numPasses = 2;
- settings[0] = gUserToClipRDiffPass0;
- settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask;
- settings[0].fFuncMasks[kBack_Face] =
- settings[0].fFuncMasks[kFront_Face];
- settings[0].fFuncRefs[kFront_Face] |= stencilClipMask;
- settings[0].fFuncRefs[kBack_Face] =
- settings[0].fFuncRefs[kFront_Face];
-
- settings[1] = gUserToClipRDiffPass1;
- settings[1].fFuncMasks[kFront_Face] |= stencilClipMask;
- settings[1].fFuncRefs[kFront_Face] |= stencilClipMask;
- settings[1].fFuncMasks[kBack_Face] =
- settings[1].fFuncMasks[kFront_Face];
- settings[1].fFuncRefs[kBack_Face] =
- settings[1].fFuncRefs[kFront_Face];
- }
- break;
- default:
- SkFAIL("Unknown set op");
- }
- return false;
+ *drawDirectToClip = false;
+ return gUserToClipTable[invertedFill][op];
}
void GrStencilSettings::genKey(GrProcessorKeyBuilder* b) const {
- static const int kCount = sizeof(GrStencilSettings) / sizeof(uint32_t);
- GR_STATIC_ASSERT(0 == sizeof(GrStencilSettings) % sizeof(uint32_t));
- uint32_t* key = b->add32n(kCount);
- memcpy(key, this, sizeof(GrStencilSettings));
+ b->add32(fFlags);
+ if (this->isDisabled()) {
+ return;
+ }
+ if (!this->isTwoSided()) {
+ constexpr int kCount16 = sizeof(Face) / sizeof(uint16_t);
+ GR_STATIC_ASSERT(0 == sizeof(Face) % sizeof(uint16_t));
+ uint16_t* key = reinterpret_cast<uint16_t*>(b->add32n((kCount16 + 1) / 2));
+ memcpy(key, &fFront, sizeof(Face));
+ key[kCount16] = 0;
+ GR_STATIC_ASSERT(1 == kCount16 % 2);
+ } else {
+ constexpr int kCount32 = (2 * sizeof(Face)) / sizeof(uint32_t);
+ GR_STATIC_ASSERT(0 == (2 * sizeof(Face)) % sizeof(uint32_t));
+ uint32_t* key = b->add32n(kCount32);
+ memcpy(key, &fFront, 2 * sizeof(Face));
+ GR_STATIC_ASSERT(sizeof(Face) ==
+ offsetof(GrStencilSettings, fBack) - offsetof(GrStencilSettings, fFront));
+ }
+ // We rely on GrStencilSettings::Face being tightly packed for the key to be reliable.
+ GR_STATIC_ASSERT(0 == offsetof(Face, fRef));
+ GR_STATIC_ASSERT(2 == sizeof(Face::fRef));
+ GR_STATIC_ASSERT(2 == offsetof(Face, fTest));
+ GR_STATIC_ASSERT(2 == sizeof(Face::fTest));
+ GR_STATIC_ASSERT(4 == offsetof(Face, fTestMask));
+ GR_STATIC_ASSERT(2 == sizeof(Face::fTestMask));
+ GR_STATIC_ASSERT(6 == offsetof(Face, fPassOp));
+ GR_STATIC_ASSERT(1 == sizeof(Face::fPassOp));
+ GR_STATIC_ASSERT(7 == offsetof(Face, fFailOp));
+ GR_STATIC_ASSERT(1 == sizeof(Face::fFailOp));
+ GR_STATIC_ASSERT(8 == offsetof(Face, fWriteMask));
+ GR_STATIC_ASSERT(2 == sizeof(Face::fWriteMask));
+ GR_STATIC_ASSERT(10 == sizeof(Face));
}

Powered by Google App Engine
This is Rietveld 408576698