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 "GrTypes.h" 13 14 /** 15 * Gr uses the stencil buffer to implement complex clipping inside the 16 * GrOpList class. The GrOpList 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. GrOpList will ignore ref, mask, and writemask bits 19 * provided by clients that fall outside the user range. 20 * 21 * When code outside the GrOpList 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 { 36 kDisabled_StencilFlag = 0x1, 37 kNoModifyStencil_StencilFlag = 0x2, 38 kNoWrapOps_StencilFlag = 0x4, 39 kSingleSided_StencilFlag = 0x8, 40 41 kLast_StencilFlag = kSingleSided_StencilFlag, 42 kAll_StencilFlags = kLast_StencilFlag | (kLast_StencilFlag - 1) 43 }; 44 45 template<typename TTest, typename TOp> struct GrTStencilFaceSettings { 46 uint16_t fRef; // Reference value for stencil test and ops. 47 TTest fTest; // Stencil test function, where fRef is on the left side. 48 uint16_t fTestMask; // Bitwise "and" to perform on fRef and stencil values before testing. 49 // (e.g. (fRef & fTestMask) < (stencil & fTestMask)) 50 TOp fPassOp; // Op to perform when the test passes. 51 TOp fFailOp; // Op to perform when the test fails. 52 uint16_t fWriteMask; // Indicates which bits in the stencil buffer should be updated. 53 // (e.g. stencil = (newValue & fWriteMask) | (stencil & ~fWriteMask)) 54 }; 55 56 enum class GrUserStencilTest : uint16_t { 57 // Tests that respect the clip bit. If a stencil clip is not in effect, the "IfInClip" is 58 // ignored and these only act on user bits. 59 kAlwaysIfInClip, 60 kEqualIfInClip, 61 kLessIfInClip, 62 kLEqualIfInClip, 63 64 // Tests that ignore the clip bit. The client is responsible to ensure no color write occurs 65 // outside the clip if it is in use. 66 kAlways, 67 kNever, 68 kGreater, 69 kGEqual, 70 kLess, 71 kLEqual, 72 kEqual, 73 kNotEqual 74 }; 75 constexpr static GrUserStencilTest kLastClippedStencilTest = GrUserStencilTest::kLEqualIfInClip; 76 constexpr static int kGrUserStencilTestCount = 1 + (int)GrUserStencilTest::kNotEqual; 77 78 enum class GrUserStencilOp : uint8_t { 79 kKeep, 80 81 // Ops that only modify user bits. These must not be paired with ops that modify the clip bit. 82 kZero, 83 kReplace, // Replace stencil value with fRef (only the bits enabled in fWriteMask). 84 kInvert, 85 kIncWrap, 86 kDecWrap, 87 // These two should only be used if wrap ops are not supported, or if the math is guaranteed 88 // to not overflow. The user bits may or may not clamp, depending on the state of non-user bits. 89 kIncMaybeClamp, 90 kDecMaybeClamp, 91 92 // Ops that only modify the clip bit. These must not be paired with ops that modify user bits. 93 kZeroClipBit, 94 kSetClipBit, 95 kInvertClipBit, 96 97 // Ops that modify both clip and user bits. These can only be paired with kKeep or each other. 98 kSetClipAndReplaceUserBits, 99 kZeroClipAndUserBits 100 }; 101 constexpr static GrUserStencilOp kLastUserOnlyStencilOp = GrUserStencilOp::kDecMaybeClamp; 102 constexpr static GrUserStencilOp kLastClipOnlyStencilOp = GrUserStencilOp::kInvertClipBit; 103 constexpr static int kGrUserStencilOpCount = 1 + (int)GrUserStencilOp::kZeroClipAndUserBits; 104 105 /** 106 * This struct is a compile-time constant representation of user stencil settings. It describes in 107 * abstract terms how a draw will use the stencil buffer. It gets ODR-used at runtime to define a 108 * draw's stencil settings, and is later translated into concrete settings when the pipeline is 109 * finalized. 110 */ 111 struct GrUserStencilSettings { 112 typedef GrTStencilFaceSettings<GrUserStencilTest, GrUserStencilOp> Face; 113 114 template<GrUserStencilTest, GrUserStencilOp PassOp, GrUserStencilOp FailOp> struct Attrs; 115 116 // Unfortunately, this is the only way to pass template arguments to a constructor. 117 template<uint16_t Ref, GrUserStencilTest Test, uint16_t TestMask, 118 GrUserStencilOp PassOp, GrUserStencilOp FailOp, uint16_t WriteMask> struct Init {}; 119 120 template<uint16_t FtRef, uint16_t BkRef, 121 GrUserStencilTest FtTest, GrUserStencilTest BkTest, 122 uint16_t FtTestMask, uint16_t BkTestMask, 123 GrUserStencilOp FtPassOp, GrUserStencilOp BkPassOp, 124 GrUserStencilOp FtFailOp, GrUserStencilOp BkFailOp, 125 uint16_t FtWriteMask, uint16_t BkWriteMask> struct InitSeparate {}; 126 127 template<uint16_t Ref, GrUserStencilTest Test, uint16_t TestMask, 128 GrUserStencilOp PassOp, GrUserStencilOp FailOp, uint16_t WriteMask> 129 constexpr static Init<Ref, Test, TestMask, PassOp, FailOp, WriteMask> StaticInit() { 130 return Init<Ref, Test, TestMask, PassOp, FailOp, WriteMask>(); 131 } 132 133 template<uint16_t FtRef, uint16_t BkRef, 134 GrUserStencilTest FtTest, GrUserStencilTest BkTest, 135 uint16_t FtTestMask, uint16_t BkTestMask, 136 GrUserStencilOp FtPassOp, GrUserStencilOp BkPassOp, 137 GrUserStencilOp FtFailOp, GrUserStencilOp BkFailOp, 138 uint16_t FtWriteMask, uint16_t BkWriteMask> 139 constexpr static InitSeparate<FtRef, BkRef, FtTest, BkTest, FtTestMask, BkTestMask, 140 FtPassOp, BkPassOp, FtFailOp, BkFailOp, FtWriteMask, 141 BkWriteMask> StaticInitSeparate() { 142 return InitSeparate<FtRef, BkRef, FtTest, BkTest, FtTestMask, BkTestMask, 143 FtPassOp, BkPassOp, FtFailOp, BkFailOp, FtWriteMask, BkWriteMask>(); 144 } 145 146 // We construct with template arguments in order to enforce that the struct be compile-time 147 // constant and to make use of static asserts. 148 template<uint16_t Ref, GrUserStencilTest Test, uint16_t TestMask, 149 GrUserStencilOp PassOp, GrUserStencilOp FailOp, uint16_t WriteMask, 150 typename Attrs = Attrs<Test, PassOp, FailOp> > 151 constexpr explicit GrUserStencilSettings( 152 const Init<Ref, Test, TestMask, PassOp, FailOp, WriteMask>&) 153 : fFrontFlags{(uint16_t)(Attrs::Flags(false) | kSingleSided_StencilFlag), 154 (uint16_t)(Attrs::Flags(true) | kSingleSided_StencilFlag)} 155 , fFront{Ref, Test, Attrs::EffectiveTestMask(TestMask), PassOp, FailOp, 156 Attrs::EffectiveWriteMask(WriteMask)} 157 , fBackFlags{(uint16_t)(Attrs::Flags(false) | kSingleSided_StencilFlag), 158 (uint16_t)(Attrs::Flags(true) | kSingleSided_StencilFlag)} 159 , fBack{Ref, Test, Attrs::EffectiveTestMask(TestMask), PassOp, FailOp, 160 Attrs::EffectiveWriteMask(WriteMask)} { 161 } 162 163 template<uint16_t FtRef, uint16_t BkRef, 164 GrUserStencilTest FtTest, GrUserStencilTest BkTest, 165 uint16_t FtTestMask, uint16_t BkTestMask, 166 GrUserStencilOp FtPassOp, GrUserStencilOp BkPassOp, 167 GrUserStencilOp FtFailOp, GrUserStencilOp BkFailOp, 168 uint16_t FtWriteMask, uint16_t BkWriteMask, 169 typename FtAttrs = Attrs<FtTest, FtPassOp, FtFailOp>, 170 typename BkAttrs = Attrs<BkTest, BkPassOp, BkFailOp> > 171 constexpr explicit GrUserStencilSettings( 172 const InitSeparate<FtRef, BkRef, FtTest, BkTest, FtTestMask, BkTestMask, 173 FtPassOp, BkPassOp, FtFailOp, BkFailOp, FtWriteMask, BkWriteMask>&) 174 : fFrontFlags{FtAttrs::Flags(false), FtAttrs::Flags(true)} 175 , fFront{FtRef, FtTest, FtAttrs::EffectiveTestMask(FtTestMask), FtPassOp, FtFailOp, 176 FtAttrs::EffectiveWriteMask(FtWriteMask)} 177 , fBackFlags{BkAttrs::Flags(false), BkAttrs::Flags(true)} 178 , fBack{BkRef, BkTest, BkAttrs::EffectiveTestMask(BkTestMask), BkPassOp, BkFailOp, 179 BkAttrs::EffectiveWriteMask(BkWriteMask)} {} 180 181 // This struct can only be constructed with static initializers. 182 GrUserStencilSettings() = delete; 183 GrUserStencilSettings(const GrUserStencilSettings&) = delete; 184 185 uint16_t flags(bool hasStencilClip) const { 186 return fFrontFlags[hasStencilClip] & fBackFlags[hasStencilClip]; 187 } 188 bool isDisabled(bool hasStencilClip) const { 189 return this->flags(hasStencilClip) & kDisabled_StencilFlag; 190 } 191 bool isTwoSided(bool hasStencilClip) const { 192 return !(this->flags(hasStencilClip) & kSingleSided_StencilFlag); 193 } 194 bool usesWrapOp(bool hasStencilClip) const { 195 return !(this->flags(hasStencilClip) & kNoWrapOps_StencilFlag); 196 } 197 198 const uint16_t fFrontFlags[2]; // frontFlagsForDraw = fFrontFlags[hasStencilClip]. 199 const Face fFront; 200 const uint16_t fBackFlags[2]; // backFlagsForDraw = fBackFlags[hasStencilClip]. 201 const Face fBack; 202 203 static const GrUserStencilSettings& kUnused; 204 205 bool isUnused() const { return this == &kUnused; } 206 }; 207 208 template<GrUserStencilTest Test, GrUserStencilOp PassOp, GrUserStencilOp FailOp> 209 struct GrUserStencilSettings::Attrs { 210 // Ensure an op that only modifies user bits isn't paired with one that modifies clip bits. 211 GR_STATIC_ASSERT(GrUserStencilOp::kKeep == PassOp || GrUserStencilOp::kKeep == FailOp || 212 (PassOp <= kLastUserOnlyStencilOp) == (FailOp <= kLastUserOnlyStencilOp)); 213 // Ensure an op that only modifies clip bits isn't paired with one that modifies clip and user. 214 GR_STATIC_ASSERT(GrUserStencilOp::kKeep == PassOp || GrUserStencilOp::kKeep == FailOp || 215 (PassOp <= kLastClipOnlyStencilOp) == (FailOp <= kLastClipOnlyStencilOp)); 216 217 constexpr static bool TestAlwaysPasses(bool hasStencilClip) { 218 return (!hasStencilClip && GrUserStencilTest::kAlwaysIfInClip == Test) || 219 GrUserStencilTest::kAlways == Test; 220 } 221 constexpr static bool DoesNotModifyStencil(bool hasStencilClip) { 222 return (GrUserStencilTest::kNever == Test || GrUserStencilOp::kKeep == PassOp) && 223 (TestAlwaysPasses(hasStencilClip) || GrUserStencilOp::kKeep == FailOp); 224 } 225 constexpr static bool IsDisabled(bool hasStencilClip) { 226 return TestAlwaysPasses(hasStencilClip) && DoesNotModifyStencil(hasStencilClip); 227 } 228 constexpr static bool UsesWrapOps() { 229 return GrUserStencilOp::kIncWrap == PassOp || GrUserStencilOp::kDecWrap == PassOp || 230 GrUserStencilOp::kIncWrap == FailOp || GrUserStencilOp::kDecWrap == FailOp; 231 } 232 constexpr static bool TestIgnoresRef() { 233 return (GrUserStencilTest::kAlwaysIfInClip == Test || GrUserStencilTest::kAlways == Test || 234 GrUserStencilTest::kNever == Test); 235 } 236 constexpr static uint16_t Flags(bool hasStencilClip) { 237 return (IsDisabled(hasStencilClip) ? kDisabled_StencilFlag : 0) | 238 (DoesNotModifyStencil(hasStencilClip) ? kNoModifyStencil_StencilFlag : 0) | 239 (UsesWrapOps() ? 0 : kNoWrapOps_StencilFlag); 240 } 241 constexpr static uint16_t EffectiveTestMask(uint16_t testMask) { 242 return TestIgnoresRef() ? 0 : testMask; 243 } 244 constexpr static uint16_t EffectiveWriteMask(uint16_t writeMask) { 245 // We don't modify the mask differently when hasStencilClip=false because either the entire 246 // face gets disabled in that case (e.g. Test=kAlwaysIfInClip, PassOp=kKeep), or else the 247 // effective mask stays the same either way. 248 return DoesNotModifyStencil(true) ? 0 : writeMask; 249 } 250 }; 251 252 #endif 253