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

Unified Diff: src/gpu/GrStencil.h

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.h
diff --git a/src/gpu/GrStencil.h b/src/gpu/GrStencil.h
index 075eb1ef1d2af44e092ae5b48a987fd92d3993f2..d65e2a8c59b76333338ffff5d59db2d4be6ca0de 100644
--- a/src/gpu/GrStencil.h
+++ b/src/gpu/GrStencil.h
@@ -17,9 +17,9 @@ class GrProcessorKeyBuilder;
/**
* Gr uses the stencil buffer to implement complex clipping inside the
* GrDrawTarget class. The GrDrawTarget makes a subset of the stencil buffer
- * bits available for other uses by external code (clients). Client code can
+ * bits available for other uses by external code (user bits). Client code can
* modify these bits. GrDrawTarget will ignore ref, mask, and writemask bits
- * provided by clients that overlap the bits used to implement clipping.
+ * provided by clients that fall outside the user range.
*
* When code outside the GrDrawTarget class uses the stencil buffer the contract
* is as follows:
@@ -27,235 +27,286 @@ class GrProcessorKeyBuilder;
* > Normal stencil funcs allow the client to pass / fail regardless of the
* reserved clip bits.
* > Additional functions allow a test against the clip along with a limited
- * set of tests against the client bits.
- * > Client can assume all client bits are zero initially.
+ * set of tests against the user bits.
+ * > Client can assume all user bits are zero initially.
* > Client must ensure that after all its passes are finished it has only
* written to the color buffer in the region inside the clip. Furthermore, it
- * must zero all client bits that were modifed (both inside and outside the
+ * must zero all user bits that were modifed (both inside and outside the
* clip).
*/
-/**
- * Determines which pixels pass / fail the stencil test.
- * Stencil test passes if (ref & mask) FUNC (stencil & mask) is true
- */
-enum GrStencilFunc {
- kAlways_StencilFunc = 0,
- kNever_StencilFunc,
- kGreater_StencilFunc,
- kGEqual_StencilFunc,
- kLess_StencilFunc,
- kLEqual_StencilFunc,
- kEqual_StencilFunc,
- kNotEqual_StencilFunc,
-
- // Gr stores the current clip in the
- // stencil buffer in the high bits that
- // are not directly accessible modifiable
- // via the GrDrawTarget interface. The below
- // stencil funcs test against the current
- // clip in addition to the GrDrawTarget
- // client's stencil bits.
-
- // pass if inside the clip
- kAlwaysIfInClip_StencilFunc,
- kEqualIfInClip_StencilFunc,
- kLessIfInClip_StencilFunc,
- kLEqualIfInClip_StencilFunc,
- kNonZeroIfInClip_StencilFunc, // this one forces the ref to be 0
-
- kLast_StencilFunc = kNonZeroIfInClip_StencilFunc
+enum GrStencilFlags {
+ kDisabled_StencilFlag = 0x1,
+ kNoModifyStencil_StencilFlag = 0x2,
+ kNoWrapOps_StencilFlag = 0x4,
+ kSingleSided_StencilFlag = 0x8,
+
+ kLast_StencilFlag = kSingleSided_StencilFlag,
+ kAll_StencilFlags = kLast_StencilFlag | (kLast_StencilFlag - 1)
};
-static const int kStencilFuncCnt = kLast_StencilFunc + 1;
-static const int kClipStencilFuncCnt =
- kNonZeroIfInClip_StencilFunc - kAlwaysIfInClip_StencilFunc + 1;
-static const int kBasicStencilFuncCnt = kStencilFuncCnt - kClipStencilFuncCnt;
+template<typename TTest, typename TOp> struct GrTStencilFaceSettings {
+ uint16_t fRef; // Reference value for stencil test and ops.
+ TTest fTest; // Stencil test function, where fRef is on the left side.
+ uint16_t fTestMask; // Bitwise "and" to perform on fRef and stencil values before testing.
+ // (e.g. (fRef & fTestMask) < (stencil & fTestMask))
+ TOp fPassOp; // Op to perform when the test passes.
+ TOp fFailOp; // Op to perform when the test fails.
+ uint16_t fWriteMask; // Indicates which bits in the stencil buffer should be updated.
+ // (e.g. stencil = (newValue & fWriteMask) | (stencil & ~fWriteMask))
+};
-/**
- * Operations to perform based on whether stencil test passed failed.
- */
-enum GrStencilOp {
- kKeep_StencilOp = 0, // preserve existing stencil value
- kReplace_StencilOp, // replace with reference value from stencl test
- kIncWrap_StencilOp, // increment and wrap at max
- kIncClamp_StencilOp, // increment and clamp at max
- kDecWrap_StencilOp, // decrement and wrap at 0
- kDecClamp_StencilOp, // decrement and clamp at 0
- kZero_StencilOp, // zero stencil bits
- kInvert_StencilOp, // invert stencil bits
- kLast_StencilOp = kInvert_StencilOp
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+enum class GrUserStencilTest : uint16_t {
+ // Tests that respect the clip bit (if in use).
bsalomon 2016/05/10 14:06:21 Maybe say that these tests "always fail when the c
Chris Dalton 2016/05/10 16:39:30 How's the reworded comment?
bsalomon 2016/05/10 20:10:58 better, thanks.
+ kAlwaysIfInClip,
+ kEqualIfInClip,
+ kLessIfInClip,
+ kLEqualIfInClip,
+
+ // Tests that ignore the clip bit. The client is responsible to ensure no color writes occur
+ // outside the clip when it is in use.
+ kAlways,
+ kNever,
+ kGreater,
+ kGEqual,
+ kLess,
+ kLEqual,
+ kEqual,
+ kNotEqual
+};
+static constexpr GrUserStencilTest kLastClippedStencilTest = GrUserStencilTest::kLEqualIfInClip;
+static constexpr int kGrUserStencilTestCount = 1 + (int)GrUserStencilTest::kNotEqual;
+
+enum class GrUserStencilOp : uint8_t {
+ kKeep,
+
+ // Ops that only modify user bits. These must not be paired with ops that modify the clip bit.
+ kZero,
+ kReplace, // Replace stencil value with fRef (only the bits enabled in fWriteMask).
+ kInvert,
+ kIncWrap,
+ kDecWrap,
+ // These two should only be used if wrap ops are not supported, or if the math is guaranteed
+ // to not overflow. The user bits may or may not clamp, depending on the state of non-user bits.
+ kIncMaybeClamp,
+ kDecMaybeClamp,
+
+ // Ops that only modify the clip bit. These must not be paired with ops that modify user bits.
+ kZeroClipBit,
+ kSetClipBit,
+ kInvertClipBit,
+
+ // Ops that modify both clip and user bits. These can only be paired with kKeep or each other.
+ kSetClipAndReplaceUserBits,
+ kZeroClipAndUserBits
};
-static const int kStencilOpCnt = kLast_StencilOp + 1;
+static constexpr GrUserStencilOp kLastUserOnlyStencilOp = GrUserStencilOp::kDecMaybeClamp;
+static constexpr GrUserStencilOp kLastClipOnlyStencilOp = GrUserStencilOp::kInvertClipBit;
+static constexpr int kGrUserStencilOpCount = 1 + (int)GrUserStencilOp::kZeroClipAndUserBits;
/**
- * Class representing stencil state.
+ * This struct is a compile-time constant representation of user stencil settings. It describes in
+ * abstract terms how a draw will use the stencil buffer. It gets ODR-used at runtime to define a
+ * draw's stencil settings, and is later translated into concrete settings when the pipeline is
+ * finalized.
*/
-class GrStencilSettings {
-public:
- enum Face {
- kFront_Face = 0,
- kBack_Face = 1,
- };
-
- constexpr GrStencilSettings(GrStencilOp passOp,
- GrStencilOp failOp,
- GrStencilFunc func,
- unsigned short funcMask,
- unsigned short funcRef,
- unsigned short writeMask)
- : fPassOps{(uint8_t)passOp, (uint8_t)passOp}
- , fFailOps{(uint8_t)failOp, (uint8_t)failOp}
- , fFuncs{(uint8_t)func, (uint8_t)func}
- , fPad0(0)
- , fPad1(0)
- , fFuncMasks{funcMask, funcMask}
- , fFuncRefs{funcRef, funcRef}
- , fWriteMasks{writeMask, writeMask}
- , fFlags(ComputeFlags(passOp, passOp,
- failOp, failOp,
- func, func,
- writeMask, writeMask)) {
+struct GrUserStencilSettings {
+ typedef GrTStencilFaceSettings<GrUserStencilTest, GrUserStencilOp> Face;
+
+ template<GrUserStencilTest, GrUserStencilOp PassOp, GrUserStencilOp FailOp> struct Attrs;
+
+ // Unfortunately, this is the only way to pass template arguments to a constructor.
+ template<uint16_t Ref, GrUserStencilTest Test, uint16_t TestMask,
+ GrUserStencilOp PassOp, GrUserStencilOp FailOp, uint16_t WriteMask> struct Init {};
+
+ template<uint16_t FtRef, uint16_t BkRef,
+ GrUserStencilTest FtTest, GrUserStencilTest BkTest,
+ uint16_t FtTestMask, uint16_t BkTestMask,
+ GrUserStencilOp FtPassOp, GrUserStencilOp BkPassOp,
+ GrUserStencilOp FtFailOp, GrUserStencilOp BkFailOp,
+ uint16_t FtWriteMask, uint16_t BkWriteMask> struct InitSeparate {};
+
+ template<uint16_t Ref, GrUserStencilTest Test, uint16_t TestMask,
+ GrUserStencilOp PassOp, GrUserStencilOp FailOp, uint16_t WriteMask>
+ constexpr static Init<Ref, Test, TestMask, PassOp, FailOp, WriteMask> StaticInit() {
+ return Init<Ref, Test, TestMask, PassOp, FailOp, WriteMask>();
}
- constexpr GrStencilSettings(GrStencilOp frontPassOp, GrStencilOp backPassOp,
- GrStencilOp frontFailOp, GrStencilOp backFailOp,
- GrStencilFunc frontFunc, GrStencilFunc backFunc,
- uint16_t frontFuncMask, uint16_t backFuncMask,
- uint16_t frontFuncRef, uint16_t backFuncRef,
- uint16_t frontWriteMask, uint16_t backWriteMask)
- : fPassOps{(uint8_t)frontPassOp, (uint8_t)backPassOp}
- , fFailOps{(uint8_t)frontFailOp, (uint8_t)backFailOp}
- , fFuncs{(uint8_t)frontFunc, (uint8_t)backFunc}
- , fPad0(0)
- , fPad1(0)
- , fFuncMasks{frontFuncMask, backFuncMask}
- , fFuncRefs{frontFuncRef, backFuncRef}
- , fWriteMasks{frontWriteMask, backWriteMask}
- , fFlags(ComputeFlags(frontPassOp, backPassOp,
- frontFailOp, backFailOp,
- frontFunc, backFunc,
- frontWriteMask, backWriteMask)) {
+ template<uint16_t FtRef, uint16_t BkRef,
+ GrUserStencilTest FtTest, GrUserStencilTest BkTest,
+ uint16_t FtTestMask, uint16_t BkTestMask,
+ GrUserStencilOp FtPassOp, GrUserStencilOp BkPassOp,
+ GrUserStencilOp FtFailOp, GrUserStencilOp BkFailOp,
+ uint16_t FtWriteMask, uint16_t BkWriteMask>
+ constexpr static InitSeparate<FtRef, BkRef, FtTest, BkTest, FtTestMask, BkTestMask,
+ FtPassOp, BkPassOp, FtFailOp, BkFailOp, FtWriteMask,
+ BkWriteMask> StaticInitSeparate() {
+ return InitSeparate<FtRef, BkRef, FtTest, BkTest, FtTestMask, BkTestMask,
+ FtPassOp, BkPassOp, FtFailOp, BkFailOp, FtWriteMask, BkWriteMask>();
}
- GrStencilSettings() {
- fPad0 = fPad1 = 0;
- this->setDisabled();
+ // We construct with template arguments in order to enforce that the struct be compile-time
+ // constant and to make use of static asserts.
+ template<uint16_t Ref, GrUserStencilTest Test, uint16_t TestMask,
+ GrUserStencilOp PassOp, GrUserStencilOp FailOp, uint16_t WriteMask,
+ typename Attrs = Attrs<Test, PassOp, FailOp> >
+ constexpr explicit GrUserStencilSettings(
+ const Init<Ref, Test, TestMask, PassOp, FailOp, WriteMask>&)
+ : fFrontFlags{Attrs::Flags(false) | kSingleSided_StencilFlag,
+ Attrs::Flags(true) | kSingleSided_StencilFlag}
+ , fFront{Ref, Test, Attrs::EffectiveTestMask(TestMask), PassOp, FailOp,
+ Attrs::EffectiveWriteMask(WriteMask)}
+ , fBackFlags{Attrs::Flags(false) | kSingleSided_StencilFlag,
+ Attrs::Flags(true) | kSingleSided_StencilFlag}
+ , fBack{Ref, Test, Attrs::EffectiveTestMask(TestMask), PassOp, FailOp,
+ Attrs::EffectiveWriteMask(WriteMask)} {
}
- GrStencilOp passOp(Face f) const { return static_cast<GrStencilOp>(fPassOps[f]); }
- GrStencilOp failOp(Face f) const { return static_cast<GrStencilOp>(fFailOps[f]); }
- GrStencilFunc func(Face f) const { return static_cast<GrStencilFunc>(fFuncs[f]); }
- uint16_t funcMask(Face f) const { return fFuncMasks[f]; }
- uint16_t funcRef(Face f) const { return fFuncRefs[f]; }
- uint16_t writeMask(Face f) const { return fWriteMasks[f]; }
-
- void setPassOp(Face f, GrStencilOp op) { fPassOps[f] = op; fFlags = 0;}
- void setFailOp(Face f, GrStencilOp op) { fFailOps[f] = op; fFlags = 0;}
- void setFunc(Face f, GrStencilFunc func) { fFuncs[f] = func; fFlags = 0;}
- void setFuncMask(Face f, unsigned short mask) { fFuncMasks[f] = mask; }
- void setFuncRef(Face f, unsigned short ref) { fFuncRefs[f] = ref; }
- void setWriteMask(Face f, unsigned short writeMask) { fWriteMasks[f] = writeMask; }
-
- void copyFrontSettingsToBack() {
- fPassOps[kBack_Face] = fPassOps[kFront_Face];
- fFailOps[kBack_Face] = fFailOps[kFront_Face];
- fFuncs[kBack_Face] = fFuncs[kFront_Face];
- fFuncMasks[kBack_Face] = fFuncMasks[kFront_Face];
- fFuncRefs[kBack_Face] = fFuncRefs[kFront_Face];
- fWriteMasks[kBack_Face] = fWriteMasks[kFront_Face];
- fFlags = 0;
- }
+ template<uint16_t FtRef, uint16_t BkRef,
+ GrUserStencilTest FtTest, GrUserStencilTest BkTest,
+ uint16_t FtTestMask, uint16_t BkTestMask,
+ GrUserStencilOp FtPassOp, GrUserStencilOp BkPassOp,
+ GrUserStencilOp FtFailOp, GrUserStencilOp BkFailOp,
+ uint16_t FtWriteMask, uint16_t BkWriteMask,
+ typename FtAttrs = Attrs<FtTest, FtPassOp, FtFailOp>,
+ typename BkAttrs = Attrs<BkTest, BkPassOp, BkFailOp> >
+ constexpr explicit GrUserStencilSettings(
+ const InitSeparate<FtRef, BkRef, FtTest, BkTest, FtTestMask, BkTestMask,
+ FtPassOp, BkPassOp, FtFailOp, BkFailOp, FtWriteMask, BkWriteMask>&)
+ : fFrontFlags{FtAttrs::Flags(false), FtAttrs::Flags(true)}
+ , fFront{FtRef, FtTest, FtAttrs::EffectiveTestMask(FtTestMask), FtPassOp, FtFailOp,
+ FtAttrs::EffectiveWriteMask(FtWriteMask)}
+ , fBackFlags{BkAttrs::Flags(false), BkAttrs::Flags(true)}
+ , fBack{BkRef, BkTest, BkAttrs::EffectiveTestMask(BkTestMask), BkPassOp, BkFailOp,
+ BkAttrs::EffectiveWriteMask(BkWriteMask)} {}
+
+ // This struct can only be constructed with static initializers.
+ GrUserStencilSettings() = delete;
+ GrUserStencilSettings(const GrUserStencilSettings&) = delete;
+
+ const uint16_t fFrontFlags[2]; // frontFlagsForDraw = fFrontFlags[hasStencilClip].
+ const Face fFront;
+ const uint16_t fBackFlags[2]; // backFlagsForDraw = fBackFlags[hasStencilClip].
+ const Face fBack;
+
+ static const GrUserStencilSettings& kUnused;
+};
- void setDisabled() {
- memset(this, 0, sizeof(*this));
- GR_STATIC_ASSERT(0 == kKeep_StencilOp);
- GR_STATIC_ASSERT(0 == kAlways_StencilFunc);
- fFlags = kIsDisabled_StencilFlag | kDoesNotWrite_StencilFlag;
+template<GrUserStencilTest Test, GrUserStencilOp PassOp, GrUserStencilOp FailOp>
+struct GrUserStencilSettings::Attrs {
+ // Ensure an op that only modifies user bits isn't paired with one that modifies clip bits.
+ GR_STATIC_ASSERT(GrUserStencilOp::kKeep == PassOp || GrUserStencilOp::kKeep == FailOp ||
+ (PassOp <= kLastUserOnlyStencilOp) == (FailOp <= kLastUserOnlyStencilOp));
+ // Ensure an op that only modifies clip bits isn't paired with one that modifies clip and user.
+ GR_STATIC_ASSERT(GrUserStencilOp::kKeep == PassOp || GrUserStencilOp::kKeep == FailOp ||
+ (PassOp <= kLastClipOnlyStencilOp) == (FailOp <= kLastClipOnlyStencilOp));
+
+ static constexpr bool TestAlwaysPasses(bool hasStencilClip) {
+ return (!hasStencilClip && GrUserStencilTest::kAlwaysIfInClip == Test) ||
+ GrUserStencilTest::kAlways == Test;
}
-
- bool isTwoSided() const {
- return fPassOps[kFront_Face] != fPassOps[kBack_Face] ||
- fFailOps[kFront_Face] != fFailOps[kBack_Face] ||
- fFuncs[kFront_Face] != fFuncs[kBack_Face] ||
- fFuncMasks[kFront_Face] != fFuncMasks[kBack_Face] ||
- fFuncRefs[kFront_Face] != fFuncRefs[kBack_Face] ||
- fWriteMasks[kFront_Face] != fWriteMasks[kBack_Face];
+ static constexpr bool DoesNotModifyStencil(bool hasStencilClip) {
+ return (GrUserStencilTest::kNever == Test || GrUserStencilOp::kKeep == PassOp) &&
+ (TestAlwaysPasses(hasStencilClip) || GrUserStencilOp::kKeep == FailOp);
}
-
- bool usesWrapOp() const {
- return kIncWrap_StencilOp == fPassOps[kFront_Face] ||
- kDecWrap_StencilOp == fPassOps[kFront_Face] ||
- kIncWrap_StencilOp == fPassOps[kBack_Face] ||
- kDecWrap_StencilOp == fPassOps[kBack_Face] ||
- kIncWrap_StencilOp == fFailOps[kFront_Face] ||
- kDecWrap_StencilOp == fFailOps[kFront_Face] ||
- kIncWrap_StencilOp == fFailOps[kBack_Face] ||
- kDecWrap_StencilOp == fFailOps[kBack_Face];
+ static constexpr bool IsDisabled(bool hasStencilClip) {
+ return TestAlwaysPasses(hasStencilClip) && DoesNotModifyStencil(hasStencilClip);
}
-
- bool isDisabled() const {
- if (fFlags & kIsDisabled_StencilFlag) {
- return true;
- }
- if (fFlags & kNotDisabled_StencilFlag) {
- return false;
- }
- bool disabled = this->computeIsDisabled();
- fFlags |= disabled ? kIsDisabled_StencilFlag : kNotDisabled_StencilFlag;
- return disabled;
+ static constexpr bool UsesWrapOps() {
+ return GrUserStencilOp::kIncWrap == PassOp || GrUserStencilOp::kDecWrap == PassOp ||
+ GrUserStencilOp::kIncWrap == FailOp || GrUserStencilOp::kDecWrap == FailOp;
}
-
- bool doesWrite() const {
- if (fFlags & kDoesWrite_StencilFlag) {
- return true;
- }
- if (fFlags & kDoesNotWrite_StencilFlag) {
- return false;
- }
- bool writes = this->computeDoesWrite();
- fFlags |= writes ? kDoesWrite_StencilFlag : kDoesNotWrite_StencilFlag;
- return writes;
+ static constexpr bool TestIgnoresRef() {
+ return (GrUserStencilTest::kAlwaysIfInClip == Test || GrUserStencilTest::kAlways == Test ||
+ GrUserStencilTest::kNever == Test);
}
-
- void invalidate() {
- // write an illegal value to the first member
- fPassOps[0] = kStencilOpCnt;
- fFlags = 0;
+ static constexpr uint16_t Flags(bool hasStencilClip) {
+ return (IsDisabled(hasStencilClip) ? kDisabled_StencilFlag : 0) |
+ (DoesNotModifyStencil(hasStencilClip) ? kNoModifyStencil_StencilFlag : 0) |
+ (UsesWrapOps() ? 0 : kNoWrapOps_StencilFlag);
}
-
- bool isValid() const { return fPassOps[0] < kStencilOpCnt; }
-
- void genKey(GrProcessorKeyBuilder* b) const;
-
- bool operator==(const GrStencilSettings& s) const {
- static const size_t gCompareSize = sizeof(GrStencilSettings) -
- sizeof(fFlags);
- SkASSERT((const char*)&fFlags + sizeof(fFlags) ==
- (const char*)this + sizeof(GrStencilSettings));
- if (this->isDisabled() & s.isDisabled()) { // using & not &&
- return true;
- }
- return 0 == memcmp(this, &s, gCompareSize);
+ static constexpr uint16_t EffectiveTestMask(uint16_t testMask) {
+ return TestIgnoresRef() ? 0 : testMask;
}
-
- bool operator!=(const GrStencilSettings& s) const {
- return !(*this == s);
+ static constexpr uint16_t EffectiveWriteMask(uint16_t writeMask) {
+ // We don't modify the mask differently when hasStencilClip=false because either the entire
+ // face gets disabled in that case (e.g. Test=kAlwaysIfInClip, PassOp=kKeep), or the
+ // effective mask stays the same either way.
+ return DoesNotModifyStencil(true) ? 0 : writeMask;
}
+};
- GrStencilSettings& operator=(const GrStencilSettings& s) {
- memcpy(this, &s, sizeof(GrStencilSettings));
- return *this;
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+enum class GrStencilTest : uint16_t {
bsalomon 2016/05/10 14:06:21 I'm wondering if this could be in another file tha
Chris Dalton 2016/05/10 16:39:30 Done. Good idea.
+ kAlways,
+ kNever,
+ kGreater,
+ kGEqual,
+ kLess,
+ kLEqual,
+ kEqual,
+ kNotEqual
+};
+static constexpr int kGrStencilTestCount = 1 + (int)GrStencilTest::kNotEqual;
+
+enum class GrStencilOp : uint8_t {
+ kKeep,
+ kZero,
+ kReplace, // Replace stencil value with fRef (only the bits enabled in fWriteMask).
+ kInvert,
+ kIncWrap,
+ kDecWrap,
+ // NOTE: clamping occurs before the write mask. So if the MSB is zero and masked out, stencil
+ // values will still wrap when using clamping ops.
+ kIncClamp,
+ kDecClamp
+};
+static constexpr int kGrStencilOpCount = 1 + (int)GrStencilOp::kDecClamp;
+
+/**
+ * This class defines concrete stencil settings that map directly to the underlying hardware. It
+ * is deduced from user stencil settings, stencil clip status, and the number of bits in the
+ * target stencil buffer.
+ */
+class GrStencilSettings {
+public:
+ GrStencilSettings() { this->setDisabled(); }
+ GrStencilSettings(const GrUserStencilSettings& user, bool hasStencilClip, int numStencilBits) {
+ this->reset(user, hasStencilClip, numStencilBits);
}
+ GrStencilSettings(const GrStencilSettings& that) { this->reset(that); }
+ GrStencilSettings& operator=(const GrStencilSettings& that) { this->reset(that); return *this; }
+
+ void invalidate() { fFlags |= kInvalid_PrivateFlag; }
+ void setDisabled() { fFlags = kAll_StencilFlags; }
+ void reset(const GrUserStencilSettings&, bool hasStencilClip, int numStencilBits);
+ void reset(const GrStencilSettings&);
+
+ bool isValid() const { return !(fFlags & kInvalid_PrivateFlag); }
+ bool isDisabled() const { SkASSERT(this->isValid()); return fFlags & kDisabled_StencilFlag; }
+ bool doesWrite() const { SkASSERT(this->isValid());
+ return !(fFlags & kNoModifyStencil_StencilFlag); }
+ bool isTwoSided() const { SkASSERT(this->isValid());
+ return !(fFlags & kSingleSided_StencilFlag); }
+ bool usesWrapOp() const { SkASSERT(this->isValid());
+ return !(fFlags & kNoWrapOps_StencilFlag); }
-private:
- friend class GrClipMaskManager;
+ void genKey(GrProcessorKeyBuilder* b) const;
+
+ bool operator!=(const GrStencilSettings& that) const { return !(*this == that); }
+ bool operator==(const GrStencilSettings&) const;
- enum {
- kMaxStencilClipPasses = 2 // maximum number of passes to add a clip
- // element to the stencil buffer.
+ struct Face : public GrTStencilFaceSettings<GrStencilTest, GrStencilOp> {
+ void reset(const GrUserStencilSettings::Face&, bool useStencilClip, int numStencilBits);
+ void setDisabled();
};
+ const Face& front() const { SkASSERT(!this->isDisabled()); return fFront; }
+ const Face& back() const { SkASSERT(this->isTwoSided()); return fBack; }
+
/**
* Given a thing to draw into the stencil clip, a fill type, and a set op
* this function determines:
@@ -263,107 +314,34 @@ private:
* needs to be drawn to the client portion of the stencil first.
* 2. How many passes are needed.
* 3. What those passes are.
- * 4. The fill rule that should actually be used to render (will
- * always be non-inverted).
*
- * @param op the set op to combine this element with the
- * existing clip
- * @param stencilClipMask mask with just the stencil bit used for clipping
- * enabled.
+ * @param op the set op to combine this element with the existing clip
+ * @param canBeDirect can the caller draw this element directly (without using stencil)?
* @param invertedFill is this path inverted
- * @param numPasses out: the number of passes needed to add the
- * element to the clip.
- * @param settings out: the stencil settings to use for each pass
+ * @param drawDirectToClip out: true if caller should draw the element directly, false if it
+ * should draw it into the user stencil bits first.
+ *
+ * @return a null-terminated array of settings for stencil passes.
+ *
+ * If drawDirectToClip is false, the caller must first draw the element into the user
+ * stencil bits, and then cover the clip area with multiple passes using the returned
+ * stencil settings.
*
- * @return true if the clip element's geometry can be drawn directly to the
- * stencil clip bit. Will only be true if canBeDirect is true.
- * numPasses will be 1 if return value is true.
+ * If drawDirectToClip is true, the returned array will only have one pass and the
+ * caller should use those stencil settings while drawing the element directly.
*/
- static bool GetClipPasses(SkRegion::Op op,
- bool canBeDirect,
- unsigned int stencilClipMask,
- bool invertedFill,
- int* numPasses,
- GrStencilSettings settings[kMaxStencilClipPasses]);
-
- constexpr static bool IsDisabled(GrStencilOp frontPassOp, GrStencilOp backPassOp,
- GrStencilOp frontFailOp, GrStencilOp backFailOp,
- GrStencilFunc frontFunc, GrStencilFunc backFunc) {
- return (((frontPassOp == kKeep_StencilOp && frontFailOp == kKeep_StencilOp)) &&
- ((backPassOp == kKeep_StencilOp && backFailOp == kKeep_StencilOp)) &&
- frontFunc == kAlways_StencilFunc &&
- backFunc == kAlways_StencilFunc);
- }
-
- constexpr static bool DoesWrite(GrStencilOp frontPassOp, GrStencilOp backPassOp,
- GrStencilOp frontFailOp, GrStencilOp backFailOp,
- GrStencilFunc frontFunc, GrStencilFunc backFunc,
- uint16_t frontWriteMask, uint16_t backWriteMask) {
- return (0 != (frontWriteMask | backWriteMask)) &&
- // Can we write due to a front face passing the stencil test?
- ((frontFunc != kNever_StencilFunc && frontPassOp != kKeep_StencilOp) ||
- // Can we write due to a back face passing the stencil test?
- (backFunc != kNever_StencilFunc && backPassOp != kKeep_StencilOp) ||
- // Can we write due to a front face failing the stencil test?
- (frontFunc != kAlways_StencilFunc && frontFailOp != kKeep_StencilOp) ||
- // Can we write due to a back face failing the stencil test?
- (backFunc != kAlways_StencilFunc && backFailOp != kKeep_StencilOp));
- }
-
- constexpr static uint32_t ComputeFlags(GrStencilOp frontPassOp, GrStencilOp backPassOp,
- GrStencilOp frontFailOp, GrStencilOp backFailOp,
- GrStencilFunc frontFunc, GrStencilFunc backFunc,
- uint16_t frontWriteMask, uint16_t backWriteMask) {
- return (IsDisabled(frontPassOp, backPassOp, frontFailOp, backFailOp,
- frontFunc, backFunc)
- ? kIsDisabled_StencilFlag
- : kNotDisabled_StencilFlag) |
- (DoesWrite(frontPassOp, backPassOp, frontFailOp, backFailOp,
- frontFunc, backFunc, frontWriteMask, backWriteMask)
- ? kDoesWrite_StencilFlag
- : kDoesNotWrite_StencilFlag);
- }
-
- bool computeIsDisabled() const {
- return IsDisabled((GrStencilOp) fPassOps[kFront_Face], (GrStencilOp) fPassOps[kBack_Face],
- (GrStencilOp) fFailOps[kFront_Face], (GrStencilOp) fFailOps[kBack_Face],
- (GrStencilFunc) fFuncs[kFront_Face], (GrStencilFunc) fFuncs[kBack_Face]);
- }
- bool computeDoesWrite() const {
- return DoesWrite((GrStencilOp)fPassOps[kFront_Face], (GrStencilOp)fPassOps[kBack_Face],
- (GrStencilOp)fFailOps[kFront_Face], (GrStencilOp)fFailOps[kBack_Face],
- (GrStencilFunc)fFuncs[kFront_Face], (GrStencilFunc)fFuncs[kBack_Face],
- fWriteMasks[kFront_Face], fWriteMasks[kBack_Face]);
- }
-
- enum GrStencilFlags {
- kIsDisabled_StencilFlag = 0x1,
- kNotDisabled_StencilFlag = 0x2,
- kDoesWrite_StencilFlag = 0x4,
- kDoesNotWrite_StencilFlag = 0x8,
- };
+ static GrUserStencilSettings const* const* GetClipPasses(SkRegion::Op op,
+ bool canBeDirect,
+ bool invertedFill,
+ bool* drawDirectToClip);
- uint8_t fPassOps[2]; // op to perform when faces pass (GrStencilOp)
- uint8_t fFailOps[2]; // op to perform when faces fail (GrStencilOp)
- uint8_t fFuncs[2]; // test function for faces (GrStencilFunc)
- uint8_t fPad0;
- uint8_t fPad1;
- uint16_t fFuncMasks[2]; // mask for face tests
- uint16_t fFuncRefs[2]; // reference values for face tests
- uint16_t fWriteMasks[2]; // stencil write masks
- mutable uint32_t fFlags;
+private:
+ // Internal flag for backends to optionally mark their tracked stencil state as invalid.
+ enum { kInvalid_PrivateFlag = (kLast_StencilFlag << 1) };
+ uint32_t fFlags;
+ Face fFront;
+ Face fBack;
};
-// We rely on this being packed and aligned (memcmp'ed and memcpy'ed)
-GR_STATIC_ASSERT(sizeof(GrStencilSettings) % 4 == 0);
-GR_STATIC_ASSERT(sizeof(GrStencilSettings) ==
- 4*sizeof(uint8_t) + // ops
- 2*sizeof(uint8_t) + // funcs
- 2*sizeof(uint8_t) + // pads
- 2*sizeof(uint16_t) + // func masks
- 2*sizeof(uint16_t) + // ref values
- 2*sizeof(uint16_t) + // write masks
- sizeof(uint32_t)); // flags
-
#endif

Powered by Google App Engine
This is Rietveld 408576698