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