| 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));
|
| }
|
|
|