| 1 | /* | 
|---|
| 2 | * Copyright 2016 Google Inc. | 
|---|
| 3 | * | 
|---|
| 4 | * Use of this source code is governed by a BSD-style license that can be | 
|---|
| 5 | * found in the LICENSE file. | 
|---|
| 6 | */ | 
|---|
| 7 |  | 
|---|
| 8 |  | 
|---|
| 9 | #ifndef GrUserStencilSettings_DEFINED | 
|---|
| 10 | #define GrUserStencilSettings_DEFINED | 
|---|
| 11 |  | 
|---|
| 12 | #include "include/gpu/GrTypes.h" | 
|---|
| 13 |  | 
|---|
| 14 | /** | 
|---|
| 15 | * Gr uses the stencil buffer to implement complex clipping inside the | 
|---|
| 16 | * GrOpsTask class. The GrOpsTask makes a subset of the stencil buffer | 
|---|
| 17 | * bits available for other uses by external code (user bits). Client code can | 
|---|
| 18 | * modify these bits. GrOpsTask will ignore ref, mask, and writemask bits | 
|---|
| 19 | * provided by clients that fall outside the user range. | 
|---|
| 20 | * | 
|---|
| 21 | * When code outside the GrOpsTask class uses the stencil buffer the contract | 
|---|
| 22 | * is as follows: | 
|---|
| 23 | * | 
|---|
| 24 | * > Normal stencil funcs allow the client to pass / fail regardless of the | 
|---|
| 25 | *   reserved clip bits. | 
|---|
| 26 | * > Additional functions allow a test against the clip along with a limited | 
|---|
| 27 | *   set of tests against the user bits. | 
|---|
| 28 | * > Client can assume all user bits are zero initially. | 
|---|
| 29 | * > Client must ensure that after all its passes are finished it has only | 
|---|
| 30 | *   written to the color buffer in the region inside the clip. Furthermore, it | 
|---|
| 31 | *   must zero all user bits that were modifed (both inside and outside the | 
|---|
| 32 | *   clip). | 
|---|
| 33 | */ | 
|---|
| 34 |  | 
|---|
| 35 | enum GrStencilFlags : int { | 
|---|
| 36 | kDisabled_StencilFlag         = (1 << 0), | 
|---|
| 37 | kTestAlwaysPasses_StencilFlag = (1 << 1), | 
|---|
| 38 | kNoModifyStencil_StencilFlag  = (1 << 2), | 
|---|
| 39 | kNoWrapOps_StencilFlag        = (1 << 3), | 
|---|
| 40 | kSingleSided_StencilFlag      = (1 << 4), | 
|---|
| 41 |  | 
|---|
| 42 | kLast_StencilFlag = kSingleSided_StencilFlag, | 
|---|
| 43 | kAll_StencilFlags = kLast_StencilFlag | (kLast_StencilFlag - 1) | 
|---|
| 44 | }; | 
|---|
| 45 |  | 
|---|
| 46 | template<typename TTest, typename TOp> struct GrTStencilFaceSettings { | 
|---|
| 47 | uint16_t   fRef;        // Reference value for stencil test and ops. | 
|---|
| 48 | TTest      fTest;       // Stencil test function, where fRef is on the left side. | 
|---|
| 49 | uint16_t   fTestMask;   // Bitwise "and" to perform on fRef and stencil values before testing. | 
|---|
| 50 | // (e.g. (fRef & fTestMask) < (stencil & fTestMask)) | 
|---|
| 51 | TOp        fPassOp;     // Op to perform when the test passes. | 
|---|
| 52 | TOp        fFailOp;     // Op to perform when the test fails. | 
|---|
| 53 | uint16_t   fWriteMask;  // Indicates which bits in the stencil buffer should be updated. | 
|---|
| 54 | // (e.g. stencil = (newValue & fWriteMask) | (stencil & ~fWriteMask)) | 
|---|
| 55 | }; | 
|---|
| 56 |  | 
|---|
| 57 | enum class GrUserStencilTest : uint16_t { | 
|---|
| 58 | // Tests that respect the clip bit. If a stencil clip is not in effect, the "IfInClip" is | 
|---|
| 59 | // ignored and these only act on user bits. | 
|---|
| 60 | kAlwaysIfInClip, | 
|---|
| 61 | kEqualIfInClip, | 
|---|
| 62 | kLessIfInClip, | 
|---|
| 63 | kLEqualIfInClip, | 
|---|
| 64 |  | 
|---|
| 65 | // Tests that ignore the clip bit. The client is responsible to ensure no color write occurs | 
|---|
| 66 | // outside the clip if it is in use. | 
|---|
| 67 | kAlways, | 
|---|
| 68 | kNever, | 
|---|
| 69 | kGreater, | 
|---|
| 70 | kGEqual, | 
|---|
| 71 | kLess, | 
|---|
| 72 | kLEqual, | 
|---|
| 73 | kEqual, | 
|---|
| 74 | kNotEqual | 
|---|
| 75 | }; | 
|---|
| 76 | constexpr static GrUserStencilTest kLastClippedStencilTest = GrUserStencilTest::kLEqualIfInClip; | 
|---|
| 77 | constexpr static int kGrUserStencilTestCount = 1 + (int)GrUserStencilTest::kNotEqual; | 
|---|
| 78 |  | 
|---|
| 79 | enum class GrUserStencilOp : uint8_t { | 
|---|
| 80 | kKeep, | 
|---|
| 81 |  | 
|---|
| 82 | // Ops that only modify user bits. These must not be paired with ops that modify the clip bit. | 
|---|
| 83 | kZero, | 
|---|
| 84 | kReplace, // Replace stencil value with fRef (only the bits enabled in fWriteMask). | 
|---|
| 85 | kInvert, | 
|---|
| 86 | kIncWrap, | 
|---|
| 87 | kDecWrap, | 
|---|
| 88 | // These two should only be used if wrap ops are not supported, or if the math is guaranteed | 
|---|
| 89 | // to not overflow. The user bits may or may not clamp, depending on the state of non-user bits. | 
|---|
| 90 | kIncMaybeClamp, | 
|---|
| 91 | kDecMaybeClamp, | 
|---|
| 92 |  | 
|---|
| 93 | // Ops that only modify the clip bit. These must not be paired with ops that modify user bits. | 
|---|
| 94 | kZeroClipBit, | 
|---|
| 95 | kSetClipBit, | 
|---|
| 96 | kInvertClipBit, | 
|---|
| 97 |  | 
|---|
| 98 | // Ops that modify both clip and user bits. These can only be paired with kKeep or each other. | 
|---|
| 99 | kSetClipAndReplaceUserBits, | 
|---|
| 100 | kZeroClipAndUserBits | 
|---|
| 101 | }; | 
|---|
| 102 | constexpr static GrUserStencilOp kLastUserOnlyStencilOp = GrUserStencilOp::kDecMaybeClamp; | 
|---|
| 103 | constexpr static GrUserStencilOp kLastClipOnlyStencilOp = GrUserStencilOp::kInvertClipBit; | 
|---|
| 104 | constexpr static int kGrUserStencilOpCount = 1 + (int)GrUserStencilOp::kZeroClipAndUserBits; | 
|---|
| 105 |  | 
|---|
| 106 | /** | 
|---|
| 107 | * This struct is a compile-time constant representation of user stencil settings. It describes in | 
|---|
| 108 | * abstract terms how a draw will use the stencil buffer. It gets ODR-used at runtime to define a | 
|---|
| 109 | * draw's stencil settings, and is later translated into concrete settings when the pipeline is | 
|---|
| 110 | * finalized. | 
|---|
| 111 | */ | 
|---|
| 112 | struct GrUserStencilSettings { | 
|---|
| 113 | typedef GrTStencilFaceSettings<GrUserStencilTest, GrUserStencilOp> Face; | 
|---|
| 114 |  | 
|---|
| 115 | template<GrUserStencilTest, GrUserStencilOp PassOp, GrUserStencilOp FailOp> struct Attrs; | 
|---|
| 116 |  | 
|---|
| 117 | // Unfortunately, this is the only way to pass template arguments to a constructor. | 
|---|
| 118 | template<uint16_t Ref, GrUserStencilTest Test, uint16_t TestMask, | 
|---|
| 119 | GrUserStencilOp PassOp, GrUserStencilOp FailOp, uint16_t WriteMask> struct Init {}; | 
|---|
| 120 |  | 
|---|
| 121 | template<uint16_t CWRef,            uint16_t CCWRef, | 
|---|
| 122 | GrUserStencilTest CWTest,  GrUserStencilTest CCWTest, | 
|---|
| 123 | uint16_t CWTestMask,       uint16_t CCWTestMask, | 
|---|
| 124 | GrUserStencilOp CWPassOp,  GrUserStencilOp CCWPassOp, | 
|---|
| 125 | GrUserStencilOp CWFailOp,  GrUserStencilOp CCWFailOp, | 
|---|
| 126 | uint16_t CWWriteMask,      uint16_t CCWWriteMask> struct InitSeparate {}; | 
|---|
| 127 |  | 
|---|
| 128 | template<uint16_t Ref, GrUserStencilTest Test, uint16_t TestMask, | 
|---|
| 129 | GrUserStencilOp PassOp, GrUserStencilOp FailOp, uint16_t WriteMask> | 
|---|
| 130 | constexpr static Init<Ref, Test, TestMask, PassOp, FailOp, WriteMask> StaticInit() { | 
|---|
| 131 | return Init<Ref, Test, TestMask, PassOp, FailOp, WriteMask>(); | 
|---|
| 132 | } | 
|---|
| 133 |  | 
|---|
| 134 | template<uint16_t CWRef,            uint16_t CCWRef, | 
|---|
| 135 | GrUserStencilTest CWTest,  GrUserStencilTest CCWTest, | 
|---|
| 136 | uint16_t CWTestMask,       uint16_t CCWTestMask, | 
|---|
| 137 | GrUserStencilOp CWPassOp,  GrUserStencilOp CCWPassOp, | 
|---|
| 138 | GrUserStencilOp CWFailOp,  GrUserStencilOp CCWFailOp, | 
|---|
| 139 | uint16_t CWWriteMask,      uint16_t CCWWriteMask> | 
|---|
| 140 | constexpr static InitSeparate<CWRef, CCWRef, CWTest, CCWTest, CWTestMask, CCWTestMask, | 
|---|
| 141 | CWPassOp, CCWPassOp, CWFailOp, CCWFailOp, CWWriteMask, | 
|---|
| 142 | CCWWriteMask> StaticInitSeparate() { | 
|---|
| 143 | return InitSeparate<CWRef, CCWRef, CWTest, CCWTest, CWTestMask, CCWTestMask, | 
|---|
| 144 | CWPassOp, CCWPassOp, CWFailOp, CCWFailOp, CWWriteMask, CCWWriteMask>(); | 
|---|
| 145 | } | 
|---|
| 146 |  | 
|---|
| 147 | // We construct with template arguments in order to enforce that the struct be compile-time | 
|---|
| 148 | // constant and to make use of static asserts. | 
|---|
| 149 | template<uint16_t Ref, GrUserStencilTest Test, uint16_t TestMask, | 
|---|
| 150 | GrUserStencilOp PassOp, GrUserStencilOp FailOp, uint16_t WriteMask, | 
|---|
| 151 | typename Attrs = Attrs<Test, PassOp, FailOp> > | 
|---|
| 152 | constexpr explicit GrUserStencilSettings( | 
|---|
| 153 | const Init<Ref, Test, TestMask, PassOp, FailOp, WriteMask>&) | 
|---|
| 154 | : fCWFlags{(uint16_t)(Attrs::Flags(false) | kSingleSided_StencilFlag), | 
|---|
| 155 | (uint16_t)(Attrs::Flags(true) | kSingleSided_StencilFlag)} | 
|---|
| 156 | , fCWFace{Ref, Test, Attrs::EffectiveTestMask(TestMask), PassOp, FailOp, | 
|---|
| 157 | Attrs::EffectiveWriteMask(WriteMask)} | 
|---|
| 158 | , fCCWFlags{(uint16_t)(Attrs::Flags(false) | kSingleSided_StencilFlag), | 
|---|
| 159 | (uint16_t)(Attrs::Flags(true) | kSingleSided_StencilFlag)} | 
|---|
| 160 | , fCCWFace{Ref, Test, Attrs::EffectiveTestMask(TestMask), PassOp, FailOp, | 
|---|
| 161 | Attrs::EffectiveWriteMask(WriteMask)} { | 
|---|
| 162 | } | 
|---|
| 163 |  | 
|---|
| 164 | template<uint16_t CWRef,            uint16_t CCWRef, | 
|---|
| 165 | GrUserStencilTest CWTest,  GrUserStencilTest CCWTest, | 
|---|
| 166 | uint16_t CWTestMask,       uint16_t CCWTestMask, | 
|---|
| 167 | GrUserStencilOp CWPassOp,  GrUserStencilOp CCWPassOp, | 
|---|
| 168 | GrUserStencilOp CWFailOp,  GrUserStencilOp CCWFailOp, | 
|---|
| 169 | uint16_t CWWriteMask,      uint16_t CCWWriteMask, | 
|---|
| 170 | typename CWAttrs = Attrs<CWTest, CWPassOp, CWFailOp>, | 
|---|
| 171 | typename CCWAttrs = Attrs<CCWTest, CCWPassOp, CCWFailOp> > | 
|---|
| 172 | constexpr explicit GrUserStencilSettings( | 
|---|
| 173 | const InitSeparate<CWRef, CCWRef, CWTest, CCWTest, CWTestMask, CCWTestMask, | 
|---|
| 174 | CWPassOp, CCWPassOp, CWFailOp, CCWFailOp, CWWriteMask, | 
|---|
| 175 | CCWWriteMask>&) | 
|---|
| 176 | : fCWFlags{CWAttrs::Flags(false), CWAttrs::Flags(true)} | 
|---|
| 177 | , fCWFace{CWRef, CWTest, CWAttrs::EffectiveTestMask(CWTestMask), CWPassOp, CWFailOp, | 
|---|
| 178 | CWAttrs::EffectiveWriteMask(CWWriteMask)} | 
|---|
| 179 | , fCCWFlags{CCWAttrs::Flags(false), CCWAttrs::Flags(true)} | 
|---|
| 180 | , fCCWFace{CCWRef, CCWTest, CCWAttrs::EffectiveTestMask(CCWTestMask), CCWPassOp, CCWFailOp, | 
|---|
| 181 | CCWAttrs::EffectiveWriteMask(CCWWriteMask)} {} | 
|---|
| 182 |  | 
|---|
| 183 | // This struct can only be constructed with static initializers. | 
|---|
| 184 | GrUserStencilSettings() = delete; | 
|---|
| 185 | GrUserStencilSettings(const GrUserStencilSettings&) = delete; | 
|---|
| 186 |  | 
|---|
| 187 | uint16_t flags(bool hasStencilClip) const { | 
|---|
| 188 | return fCWFlags[hasStencilClip] & fCCWFlags[hasStencilClip]; | 
|---|
| 189 | } | 
|---|
| 190 | bool isDisabled(bool hasStencilClip) const { | 
|---|
| 191 | return this->flags(hasStencilClip) & kDisabled_StencilFlag; | 
|---|
| 192 | } | 
|---|
| 193 | bool testAlwaysPasses(bool hasStencilClip) const { | 
|---|
| 194 | return this->flags(hasStencilClip) & kTestAlwaysPasses_StencilFlag; | 
|---|
| 195 | } | 
|---|
| 196 | bool isTwoSided(bool hasStencilClip) const { | 
|---|
| 197 | return !(this->flags(hasStencilClip) & kSingleSided_StencilFlag); | 
|---|
| 198 | } | 
|---|
| 199 | bool usesWrapOp(bool hasStencilClip) const { | 
|---|
| 200 | return !(this->flags(hasStencilClip) & kNoWrapOps_StencilFlag); | 
|---|
| 201 | } | 
|---|
| 202 |  | 
|---|
| 203 | const uint16_t   fCWFlags[2]; // cwFlagsForDraw = fCWFlags[hasStencilClip]. | 
|---|
| 204 | const Face       fCWFace; | 
|---|
| 205 | const uint16_t   fCCWFlags[2]; // ccwFlagsForDraw = fCCWFlags[hasStencilClip]. | 
|---|
| 206 | const Face       fCCWFace; | 
|---|
| 207 |  | 
|---|
| 208 | static const GrUserStencilSettings& kUnused; | 
|---|
| 209 |  | 
|---|
| 210 | bool isUnused() const { return this == &kUnused; } | 
|---|
| 211 | }; | 
|---|
| 212 |  | 
|---|
| 213 | template<GrUserStencilTest Test, GrUserStencilOp PassOp, GrUserStencilOp FailOp> | 
|---|
| 214 | struct GrUserStencilSettings::Attrs { | 
|---|
| 215 | // Ensure an op that only modifies user bits isn't paired with one that modifies clip bits. | 
|---|
| 216 | static_assert(GrUserStencilOp::kKeep == PassOp || GrUserStencilOp::kKeep == FailOp || | 
|---|
| 217 | (PassOp <= kLastUserOnlyStencilOp) == (FailOp <= kLastUserOnlyStencilOp)); | 
|---|
| 218 | // Ensure an op that only modifies clip bits isn't paired with one that modifies clip and user. | 
|---|
| 219 | static_assert(GrUserStencilOp::kKeep == PassOp || GrUserStencilOp::kKeep == FailOp || | 
|---|
| 220 | (PassOp <= kLastClipOnlyStencilOp) == (FailOp <= kLastClipOnlyStencilOp)); | 
|---|
| 221 |  | 
|---|
| 222 | constexpr static bool TestAlwaysPasses(bool hasStencilClip) { | 
|---|
| 223 | return (!hasStencilClip && GrUserStencilTest::kAlwaysIfInClip == Test) || | 
|---|
| 224 | GrUserStencilTest::kAlways == Test; | 
|---|
| 225 | } | 
|---|
| 226 | constexpr static bool DoesNotModifyStencil(bool hasStencilClip) { | 
|---|
| 227 | return (GrUserStencilTest::kNever == Test || GrUserStencilOp::kKeep == PassOp) && | 
|---|
| 228 | (TestAlwaysPasses(hasStencilClip) || GrUserStencilOp::kKeep == FailOp); | 
|---|
| 229 | } | 
|---|
| 230 | constexpr static bool IsDisabled(bool hasStencilClip) { | 
|---|
| 231 | return TestAlwaysPasses(hasStencilClip) && DoesNotModifyStencil(hasStencilClip); | 
|---|
| 232 | } | 
|---|
| 233 | constexpr static bool UsesWrapOps() { | 
|---|
| 234 | return GrUserStencilOp::kIncWrap == PassOp || GrUserStencilOp::kDecWrap == PassOp || | 
|---|
| 235 | GrUserStencilOp::kIncWrap == FailOp || GrUserStencilOp::kDecWrap == FailOp; | 
|---|
| 236 | } | 
|---|
| 237 | constexpr static bool TestIgnoresRef() { | 
|---|
| 238 | return (GrUserStencilTest::kAlwaysIfInClip == Test || GrUserStencilTest::kAlways == Test || | 
|---|
| 239 | GrUserStencilTest::kNever == Test); | 
|---|
| 240 | } | 
|---|
| 241 | constexpr static uint16_t Flags(bool hasStencilClip) { | 
|---|
| 242 | return (IsDisabled(hasStencilClip) ? kDisabled_StencilFlag : 0) | | 
|---|
| 243 | (TestAlwaysPasses(hasStencilClip) ? kTestAlwaysPasses_StencilFlag : 0) | | 
|---|
| 244 | (DoesNotModifyStencil(hasStencilClip) ? kNoModifyStencil_StencilFlag : 0) | | 
|---|
| 245 | (UsesWrapOps() ? 0 : kNoWrapOps_StencilFlag); | 
|---|
| 246 | } | 
|---|
| 247 | constexpr static uint16_t EffectiveTestMask(uint16_t testMask) { | 
|---|
| 248 | return TestIgnoresRef() ? 0 : testMask; | 
|---|
| 249 | } | 
|---|
| 250 | constexpr static uint16_t EffectiveWriteMask(uint16_t writeMask) { | 
|---|
| 251 | // We don't modify the mask differently when hasStencilClip=false because either the entire | 
|---|
| 252 | // face gets disabled in that case (e.g. Test=kAlwaysIfInClip, PassOp=kKeep), or else the | 
|---|
| 253 | // effective mask stays the same either way. | 
|---|
| 254 | return DoesNotModifyStencil(true) ? 0 : writeMask; | 
|---|
| 255 | } | 
|---|
| 256 | }; | 
|---|
| 257 |  | 
|---|
| 258 | #endif | 
|---|
| 259 |  | 
|---|