| /* | 
 |  * Copyright 2016 Google Inc. | 
 |  * | 
 |  * Use of this source code is governed by a BSD-style license that can be | 
 |  * found in the LICENSE file. | 
 |  */ | 
 |  | 
 |  | 
 | #ifndef GrUserStencilSettings_DEFINED | 
 | #define GrUserStencilSettings_DEFINED | 
 |  | 
 | #include "include/gpu/GrTypes.h" | 
 |  | 
 | /** | 
 |  * Gr uses the stencil buffer to implement complex clipping inside the | 
 |  * GrOpsTask class. The GrOpsTask makes a subset of the stencil buffer | 
 |  * bits available for other uses by external code (user bits). Client code can | 
 |  * modify these bits. GrOpsTask will ignore ref, mask, and writemask bits | 
 |  * provided by clients that fall outside the user range. | 
 |  * | 
 |  * When code outside the GrOpsTask class uses the stencil buffer the contract | 
 |  * is as follows: | 
 |  * | 
 |  * > 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 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 user bits that were modifed (both inside and outside the | 
 |  *   clip). | 
 |  */ | 
 |  | 
 | enum GrStencilFlags : int { | 
 |     kDisabled_StencilFlag         = (1 << 0), | 
 |     kTestAlwaysPasses_StencilFlag = (1 << 1), | 
 |     kNoModifyStencil_StencilFlag  = (1 << 2), | 
 |     kNoWrapOps_StencilFlag        = (1 << 3), | 
 |     kSingleSided_StencilFlag      = (1 << 4), | 
 |  | 
 |     kLast_StencilFlag = kSingleSided_StencilFlag, | 
 |     kAll_StencilFlags = kLast_StencilFlag | (kLast_StencilFlag - 1) | 
 | }; | 
 |  | 
 | 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)) | 
 | }; | 
 |  | 
 | enum class GrUserStencilTest : uint16_t { | 
 |     // Tests that respect the clip bit. If a stencil clip is not in effect, the "IfInClip" is | 
 |     // ignored and these only act on user bits. | 
 |     kAlwaysIfInClip, | 
 |     kEqualIfInClip, | 
 |     kLessIfInClip, | 
 |     kLEqualIfInClip, | 
 |  | 
 |     // Tests that ignore the clip bit. The client is responsible to ensure no color write occurs | 
 |     // outside the clip if it is in use. | 
 |     kAlways, | 
 |     kNever, | 
 |     kGreater, | 
 |     kGEqual, | 
 |     kLess, | 
 |     kLEqual, | 
 |     kEqual, | 
 |     kNotEqual | 
 | }; | 
 | constexpr static GrUserStencilTest kLastClippedStencilTest = GrUserStencilTest::kLEqualIfInClip; | 
 | constexpr static 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 | 
 | }; | 
 | constexpr static GrUserStencilOp kLastUserOnlyStencilOp = GrUserStencilOp::kDecMaybeClamp; | 
 | constexpr static GrUserStencilOp kLastClipOnlyStencilOp = GrUserStencilOp::kInvertClipBit; | 
 | constexpr static int kGrUserStencilOpCount = 1 + (int)GrUserStencilOp::kZeroClipAndUserBits; | 
 |  | 
 | /** | 
 |  * 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. | 
 |  */ | 
 | 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 CWRef,            uint16_t CCWRef, | 
 |              GrUserStencilTest CWTest,  GrUserStencilTest CCWTest, | 
 |              uint16_t CWTestMask,       uint16_t CCWTestMask, | 
 |              GrUserStencilOp CWPassOp,  GrUserStencilOp CCWPassOp, | 
 |              GrUserStencilOp CWFailOp,  GrUserStencilOp CCWFailOp, | 
 |              uint16_t CWWriteMask,      uint16_t CCWWriteMask> 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>(); | 
 |     } | 
 |  | 
 |     template<uint16_t CWRef,            uint16_t CCWRef, | 
 |              GrUserStencilTest CWTest,  GrUserStencilTest CCWTest, | 
 |              uint16_t CWTestMask,       uint16_t CCWTestMask, | 
 |              GrUserStencilOp CWPassOp,  GrUserStencilOp CCWPassOp, | 
 |              GrUserStencilOp CWFailOp,  GrUserStencilOp CCWFailOp, | 
 |              uint16_t CWWriteMask,      uint16_t CCWWriteMask> | 
 |     constexpr static InitSeparate<CWRef, CCWRef, CWTest, CCWTest, CWTestMask, CCWTestMask, | 
 |                                   CWPassOp, CCWPassOp, CWFailOp, CCWFailOp, CWWriteMask, | 
 |                                   CCWWriteMask> StaticInitSeparate() { | 
 |         return InitSeparate<CWRef, CCWRef, CWTest, CCWTest, CWTestMask, CCWTestMask, | 
 |                             CWPassOp, CCWPassOp, CWFailOp, CCWFailOp, CWWriteMask, CCWWriteMask>(); | 
 |     } | 
 |  | 
 |     // 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>&) | 
 |         : fCWFlags{(uint16_t)(Attrs::Flags(false) | kSingleSided_StencilFlag), | 
 |                       (uint16_t)(Attrs::Flags(true) | kSingleSided_StencilFlag)} | 
 |         , fCWFace{Ref, Test, Attrs::EffectiveTestMask(TestMask), PassOp, FailOp, | 
 |                  Attrs::EffectiveWriteMask(WriteMask)} | 
 |         , fCCWFlags{(uint16_t)(Attrs::Flags(false) | kSingleSided_StencilFlag), | 
 |                      (uint16_t)(Attrs::Flags(true) | kSingleSided_StencilFlag)} | 
 |         , fCCWFace{Ref, Test, Attrs::EffectiveTestMask(TestMask), PassOp, FailOp, | 
 |                 Attrs::EffectiveWriteMask(WriteMask)} { | 
 |     } | 
 |  | 
 |     template<uint16_t CWRef,            uint16_t CCWRef, | 
 |              GrUserStencilTest CWTest,  GrUserStencilTest CCWTest, | 
 |              uint16_t CWTestMask,       uint16_t CCWTestMask, | 
 |              GrUserStencilOp CWPassOp,  GrUserStencilOp CCWPassOp, | 
 |              GrUserStencilOp CWFailOp,  GrUserStencilOp CCWFailOp, | 
 |              uint16_t CWWriteMask,      uint16_t CCWWriteMask, | 
 |              typename CWAttrs = Attrs<CWTest, CWPassOp, CWFailOp>, | 
 |              typename CCWAttrs = Attrs<CCWTest, CCWPassOp, CCWFailOp> > | 
 |     constexpr explicit GrUserStencilSettings( | 
 |             const InitSeparate<CWRef, CCWRef, CWTest, CCWTest, CWTestMask, CCWTestMask, | 
 |                                CWPassOp, CCWPassOp, CWFailOp, CCWFailOp, CWWriteMask, | 
 |                                CCWWriteMask>&) | 
 |         : fCWFlags{CWAttrs::Flags(false), CWAttrs::Flags(true)} | 
 |         , fCWFace{CWRef, CWTest, CWAttrs::EffectiveTestMask(CWTestMask), CWPassOp, CWFailOp, | 
 |                  CWAttrs::EffectiveWriteMask(CWWriteMask)} | 
 |         , fCCWFlags{CCWAttrs::Flags(false), CCWAttrs::Flags(true)} | 
 |         , fCCWFace{CCWRef, CCWTest, CCWAttrs::EffectiveTestMask(CCWTestMask), CCWPassOp, CCWFailOp, | 
 |                 CCWAttrs::EffectiveWriteMask(CCWWriteMask)} {} | 
 |  | 
 |     // This struct can only be constructed with static initializers. | 
 |     GrUserStencilSettings() = delete; | 
 |     GrUserStencilSettings(const GrUserStencilSettings&) = delete; | 
 |  | 
 |     uint16_t flags(bool hasStencilClip) const { | 
 |         return fCWFlags[hasStencilClip] & fCCWFlags[hasStencilClip]; | 
 |     } | 
 |     bool isDisabled(bool hasStencilClip) const { | 
 |         return this->flags(hasStencilClip) & kDisabled_StencilFlag; | 
 |     } | 
 |     bool testAlwaysPasses(bool hasStencilClip) const { | 
 |         return this->flags(hasStencilClip) & kTestAlwaysPasses_StencilFlag; | 
 |     } | 
 |     bool isTwoSided(bool hasStencilClip) const { | 
 |         return !(this->flags(hasStencilClip) & kSingleSided_StencilFlag); | 
 |     } | 
 |     bool usesWrapOp(bool hasStencilClip) const { | 
 |         return !(this->flags(hasStencilClip) & kNoWrapOps_StencilFlag); | 
 |     } | 
 |  | 
 |     const uint16_t   fCWFlags[2]; // cwFlagsForDraw = fCWFlags[hasStencilClip]. | 
 |     const Face       fCWFace; | 
 |     const uint16_t   fCCWFlags[2]; // ccwFlagsForDraw = fCCWFlags[hasStencilClip]. | 
 |     const Face       fCCWFace; | 
 |  | 
 |     static const GrUserStencilSettings& kUnused; | 
 |  | 
 |     bool isUnused() const { return this == &kUnused; } | 
 | }; | 
 |  | 
 | 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. | 
 |     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. | 
 |     static_assert(GrUserStencilOp::kKeep == PassOp || GrUserStencilOp::kKeep == FailOp || | 
 |                   (PassOp <= kLastClipOnlyStencilOp) == (FailOp <= kLastClipOnlyStencilOp)); | 
 |  | 
 |     constexpr static bool TestAlwaysPasses(bool hasStencilClip) { | 
 |         return (!hasStencilClip && GrUserStencilTest::kAlwaysIfInClip == Test) || | 
 |                 GrUserStencilTest::kAlways == Test; | 
 |     } | 
 |     constexpr static bool DoesNotModifyStencil(bool hasStencilClip) { | 
 |         return (GrUserStencilTest::kNever == Test || GrUserStencilOp::kKeep == PassOp) && | 
 |                 (TestAlwaysPasses(hasStencilClip) || GrUserStencilOp::kKeep == FailOp); | 
 |     } | 
 |     constexpr static bool IsDisabled(bool hasStencilClip) { | 
 |         return TestAlwaysPasses(hasStencilClip) && DoesNotModifyStencil(hasStencilClip); | 
 |     } | 
 |     constexpr static bool UsesWrapOps() { | 
 |         return GrUserStencilOp::kIncWrap == PassOp || GrUserStencilOp::kDecWrap == PassOp || | 
 |                GrUserStencilOp::kIncWrap == FailOp || GrUserStencilOp::kDecWrap == FailOp; | 
 |     } | 
 |     constexpr static bool TestIgnoresRef() { | 
 |         return (GrUserStencilTest::kAlwaysIfInClip == Test || GrUserStencilTest::kAlways == Test || | 
 |                 GrUserStencilTest::kNever == Test); | 
 |     } | 
 |     constexpr static uint16_t Flags(bool hasStencilClip) { | 
 |         return (IsDisabled(hasStencilClip) ? kDisabled_StencilFlag : 0) | | 
 |                (TestAlwaysPasses(hasStencilClip) ? kTestAlwaysPasses_StencilFlag : 0) | | 
 |                (DoesNotModifyStencil(hasStencilClip) ? kNoModifyStencil_StencilFlag : 0) | | 
 |                (UsesWrapOps() ? 0 : kNoWrapOps_StencilFlag); | 
 |     } | 
 |     constexpr static uint16_t EffectiveTestMask(uint16_t testMask) { | 
 |         return TestIgnoresRef() ? 0 : testMask; | 
 |     } | 
 |     constexpr static 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 else the | 
 |         // effective mask stays the same either way. | 
 |         return DoesNotModifyStencil(true) ? 0 : writeMask; | 
 |     } | 
 | }; | 
 |  | 
 | #endif |