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