|  | /* | 
|  | * 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 |