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> 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 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, StaticInitSeparateGrUserStencilSettings142 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> > GrUserStencilSettingsGrUserStencilSettings152 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> > GrUserStencilSettingsGrUserStencilSettings172 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 flagsGrUserStencilSettings187 uint16_t flags(bool hasStencilClip) const { 188 return fCWFlags[hasStencilClip] & fCCWFlags[hasStencilClip]; 189 } isDisabledGrUserStencilSettings190 bool isDisabled(bool hasStencilClip) const { 191 return this->flags(hasStencilClip) & kDisabled_StencilFlag; 192 } testAlwaysPassesGrUserStencilSettings193 bool testAlwaysPasses(bool hasStencilClip) const { 194 return this->flags(hasStencilClip) & kTestAlwaysPasses_StencilFlag; 195 } isTwoSidedGrUserStencilSettings196 bool isTwoSided(bool hasStencilClip) const { 197 return !(this->flags(hasStencilClip) & kSingleSided_StencilFlag); 198 } usesWrapOpGrUserStencilSettings199 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 isUnusedGrUserStencilSettings210 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 TestAlwaysPassesAttrs222 constexpr static bool TestAlwaysPasses(bool hasStencilClip) { 223 return (!hasStencilClip && GrUserStencilTest::kAlwaysIfInClip == Test) || 224 GrUserStencilTest::kAlways == Test; 225 } DoesNotModifyStencilAttrs226 constexpr static bool DoesNotModifyStencil(bool hasStencilClip) { 227 return (GrUserStencilTest::kNever == Test || GrUserStencilOp::kKeep == PassOp) && 228 (TestAlwaysPasses(hasStencilClip) || GrUserStencilOp::kKeep == FailOp); 229 } IsDisabledAttrs230 constexpr static bool IsDisabled(bool hasStencilClip) { 231 return TestAlwaysPasses(hasStencilClip) && DoesNotModifyStencil(hasStencilClip); 232 } UsesWrapOpsAttrs233 constexpr static bool UsesWrapOps() { 234 return GrUserStencilOp::kIncWrap == PassOp || GrUserStencilOp::kDecWrap == PassOp || 235 GrUserStencilOp::kIncWrap == FailOp || GrUserStencilOp::kDecWrap == FailOp; 236 } TestIgnoresRefAttrs237 constexpr static bool TestIgnoresRef() { 238 return (GrUserStencilTest::kAlwaysIfInClip == Test || GrUserStencilTest::kAlways == Test || 239 GrUserStencilTest::kNever == Test); 240 } FlagsAttrs241 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 } EffectiveTestMaskAttrs247 constexpr static uint16_t EffectiveTestMask(uint16_t testMask) { 248 return TestIgnoresRef() ? 0 : testMask; 249 } EffectiveWriteMaskAttrs250 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