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 * 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 = (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 FtRef, uint16_t BkRef, 122 GrUserStencilTest FtTest, GrUserStencilTest BkTest, 123 uint16_t FtTestMask, uint16_t BkTestMask, 124 GrUserStencilOp FtPassOp, GrUserStencilOp BkPassOp, 125 GrUserStencilOp FtFailOp, GrUserStencilOp BkFailOp, 126 uint16_t FtWriteMask, uint16_t BkWriteMask> struct InitSeparate {}; 127 128 template<uint16_t Ref, GrUserStencilTest Test, uint16_t TestMask, 129 GrUserStencilOp PassOp, GrUserStencilOp FailOp, uint16_t WriteMask> StaticInitGrUserStencilSettings130 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 FtRef, uint16_t BkRef, 135 GrUserStencilTest FtTest, GrUserStencilTest BkTest, 136 uint16_t FtTestMask, uint16_t BkTestMask, 137 GrUserStencilOp FtPassOp, GrUserStencilOp BkPassOp, 138 GrUserStencilOp FtFailOp, GrUserStencilOp BkFailOp, 139 uint16_t FtWriteMask, uint16_t BkWriteMask> 140 constexpr static InitSeparate<FtRef, BkRef, FtTest, BkTest, FtTestMask, BkTestMask, 141 FtPassOp, BkPassOp, FtFailOp, BkFailOp, FtWriteMask, StaticInitSeparateGrUserStencilSettings142 BkWriteMask> StaticInitSeparate() { 143 return InitSeparate<FtRef, BkRef, FtTest, BkTest, FtTestMask, BkTestMask, 144 FtPassOp, BkPassOp, FtFailOp, BkFailOp, FtWriteMask, BkWriteMask>(); 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> > GrUserStencilSettingsGrUserStencilSettings152 constexpr explicit GrUserStencilSettings( 153 const Init<Ref, Test, TestMask, PassOp, FailOp, WriteMask>&) 154 : fFrontFlags{(uint16_t)(Attrs::Flags(false) | kSingleSided_StencilFlag), 155 (uint16_t)(Attrs::Flags(true) | kSingleSided_StencilFlag)} 156 , fFront{Ref, Test, Attrs::EffectiveTestMask(TestMask), PassOp, FailOp, 157 Attrs::EffectiveWriteMask(WriteMask)} 158 , fBackFlags{(uint16_t)(Attrs::Flags(false) | kSingleSided_StencilFlag), 159 (uint16_t)(Attrs::Flags(true) | kSingleSided_StencilFlag)} 160 , fBack{Ref, Test, Attrs::EffectiveTestMask(TestMask), PassOp, FailOp, 161 Attrs::EffectiveWriteMask(WriteMask)} { 162 } 163 164 template<uint16_t FtRef, uint16_t BkRef, 165 GrUserStencilTest FtTest, GrUserStencilTest BkTest, 166 uint16_t FtTestMask, uint16_t BkTestMask, 167 GrUserStencilOp FtPassOp, GrUserStencilOp BkPassOp, 168 GrUserStencilOp FtFailOp, GrUserStencilOp BkFailOp, 169 uint16_t FtWriteMask, uint16_t BkWriteMask, 170 typename FtAttrs = Attrs<FtTest, FtPassOp, FtFailOp>, 171 typename BkAttrs = Attrs<BkTest, BkPassOp, BkFailOp> > GrUserStencilSettingsGrUserStencilSettings172 constexpr explicit GrUserStencilSettings( 173 const InitSeparate<FtRef, BkRef, FtTest, BkTest, FtTestMask, BkTestMask, 174 FtPassOp, BkPassOp, FtFailOp, BkFailOp, FtWriteMask, BkWriteMask>&) 175 : fFrontFlags{FtAttrs::Flags(false), FtAttrs::Flags(true)} 176 , fFront{FtRef, FtTest, FtAttrs::EffectiveTestMask(FtTestMask), FtPassOp, FtFailOp, 177 FtAttrs::EffectiveWriteMask(FtWriteMask)} 178 , fBackFlags{BkAttrs::Flags(false), BkAttrs::Flags(true)} 179 , fBack{BkRef, BkTest, BkAttrs::EffectiveTestMask(BkTestMask), BkPassOp, BkFailOp, 180 BkAttrs::EffectiveWriteMask(BkWriteMask)} {} 181 182 // This struct can only be constructed with static initializers. 183 GrUserStencilSettings() = delete; 184 GrUserStencilSettings(const GrUserStencilSettings&) = delete; 185 flagsGrUserStencilSettings186 uint16_t flags(bool hasStencilClip) const { 187 return fFrontFlags[hasStencilClip] & fBackFlags[hasStencilClip]; 188 } isDisabledGrUserStencilSettings189 bool isDisabled(bool hasStencilClip) const { 190 return this->flags(hasStencilClip) & kDisabled_StencilFlag; 191 } testAlwaysPassesGrUserStencilSettings192 bool testAlwaysPasses(bool hasStencilClip) const { 193 return this->flags(hasStencilClip) & kTestAlwaysPasses_StencilFlag; 194 } isTwoSidedGrUserStencilSettings195 bool isTwoSided(bool hasStencilClip) const { 196 return !(this->flags(hasStencilClip) & kSingleSided_StencilFlag); 197 } usesWrapOpGrUserStencilSettings198 bool usesWrapOp(bool hasStencilClip) const { 199 return !(this->flags(hasStencilClip) & kNoWrapOps_StencilFlag); 200 } 201 202 const uint16_t fFrontFlags[2]; // frontFlagsForDraw = fFrontFlags[hasStencilClip]. 203 const Face fFront; 204 const uint16_t fBackFlags[2]; // backFlagsForDraw = fBackFlags[hasStencilClip]. 205 const Face fBack; 206 207 static const GrUserStencilSettings& kUnused; 208 isUnusedGrUserStencilSettings209 bool isUnused() const { return this == &kUnused; } 210 }; 211 212 template<GrUserStencilTest Test, GrUserStencilOp PassOp, GrUserStencilOp FailOp> 213 struct GrUserStencilSettings::Attrs { 214 // Ensure an op that only modifies user bits isn't paired with one that modifies clip bits. 215 GR_STATIC_ASSERT(GrUserStencilOp::kKeep == PassOp || GrUserStencilOp::kKeep == FailOp || 216 (PassOp <= kLastUserOnlyStencilOp) == (FailOp <= kLastUserOnlyStencilOp)); 217 // Ensure an op that only modifies clip bits isn't paired with one that modifies clip and user. 218 GR_STATIC_ASSERT(GrUserStencilOp::kKeep == PassOp || GrUserStencilOp::kKeep == FailOp || 219 (PassOp <= kLastClipOnlyStencilOp) == (FailOp <= kLastClipOnlyStencilOp)); 220 TestAlwaysPassesAttrs221 constexpr static bool TestAlwaysPasses(bool hasStencilClip) { 222 return (!hasStencilClip && GrUserStencilTest::kAlwaysIfInClip == Test) || 223 GrUserStencilTest::kAlways == Test; 224 } DoesNotModifyStencilAttrs225 constexpr static bool DoesNotModifyStencil(bool hasStencilClip) { 226 return (GrUserStencilTest::kNever == Test || GrUserStencilOp::kKeep == PassOp) && 227 (TestAlwaysPasses(hasStencilClip) || GrUserStencilOp::kKeep == FailOp); 228 } IsDisabledAttrs229 constexpr static bool IsDisabled(bool hasStencilClip) { 230 return TestAlwaysPasses(hasStencilClip) && DoesNotModifyStencil(hasStencilClip); 231 } UsesWrapOpsAttrs232 constexpr static bool UsesWrapOps() { 233 return GrUserStencilOp::kIncWrap == PassOp || GrUserStencilOp::kDecWrap == PassOp || 234 GrUserStencilOp::kIncWrap == FailOp || GrUserStencilOp::kDecWrap == FailOp; 235 } TestIgnoresRefAttrs236 constexpr static bool TestIgnoresRef() { 237 return (GrUserStencilTest::kAlwaysIfInClip == Test || GrUserStencilTest::kAlways == Test || 238 GrUserStencilTest::kNever == Test); 239 } FlagsAttrs240 constexpr static uint16_t Flags(bool hasStencilClip) { 241 return (IsDisabled(hasStencilClip) ? kDisabled_StencilFlag : 0) | 242 (TestAlwaysPasses(hasStencilClip) ? kTestAlwaysPasses_StencilFlag : 0) | 243 (DoesNotModifyStencil(hasStencilClip) ? kNoModifyStencil_StencilFlag : 0) | 244 (UsesWrapOps() ? 0 : kNoWrapOps_StencilFlag); 245 } EffectiveTestMaskAttrs246 constexpr static uint16_t EffectiveTestMask(uint16_t testMask) { 247 return TestIgnoresRef() ? 0 : testMask; 248 } EffectiveWriteMaskAttrs249 constexpr static uint16_t EffectiveWriteMask(uint16_t writeMask) { 250 // We don't modify the mask differently when hasStencilClip=false because either the entire 251 // face gets disabled in that case (e.g. Test=kAlwaysIfInClip, PassOp=kKeep), or else the 252 // effective mask stays the same either way. 253 return DoesNotModifyStencil(true) ? 0 : writeMask; 254 } 255 }; 256 257 #endif 258