OLD | NEW |
(Empty) | |
| 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 * GrDrawTarget class. The GrDrawTarget 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. GrDrawTarget will ignore ref, mask, and writemask bits |
| 19 * provided by clients that fall outside the user range. |
| 20 * |
| 21 * When code outside the GrDrawTarget 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 valu
es 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) | (stenci
l & ~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 co
lor 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::kNotE
qual; |
| 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 mo
dify the clip bit. |
| 82 kZero, |
| 83 kReplace, // Replace stencil value with fRef (only the bits enabled in fWrit
eMask). |
| 84 kInvert, |
| 85 kIncWrap, |
| 86 kDecWrap, |
| 87 // These two should only be used if wrap ops are not supported, or if the ma
th is guaranteed |
| 88 // to not overflow. The user bits may or may not clamp, depending on the sta
te 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 kK
eep or each other. |
| 98 kSetClipAndReplaceUserBits, |
| 99 kZeroClipAndUserBits |
| 100 }; |
| 101 constexpr static GrUserStencilOp kLastUserOnlyStencilOp = GrUserStencilOp::kDecM
aybeClamp; |
| 102 constexpr static GrUserStencilOp kLastClipOnlyStencilOp = GrUserStencilOp::kInve
rtClipBit; |
| 103 constexpr static int kGrUserStencilOpCount = 1 + (int)GrUserStencilOp::kZeroClip
AndUserBits; |
| 104 |
| 105 /** |
| 106 * This struct is a compile-time constant representation of user stencil setting
s. It describes in |
| 107 * abstract terms how a draw will use the stencil buffer. It gets ODR-used at ru
ntime 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 const
ructor. |
| 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 InitSeparat
e {}; |
| 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> Static
Init() { |
| 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, BkTe
stMask, |
| 140 FtPassOp, BkPassOp, FtFailOp, BkFailOp, FtWrit
eMask, |
| 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, BkTestM
ask, |
| 173 FtPassOp, BkPassOp, FtFailOp, BkFailOp, FtWriteMa
sk, 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 const uint16_t fFrontFlags[2]; // frontFlagsForDraw = fFrontFlags[hasStenc
ilClip]. |
| 186 const Face fFront; |
| 187 const uint16_t fBackFlags[2]; // backFlagsForDraw = fBackFlags[hasStencilC
lip]. |
| 188 const Face fBack; |
| 189 |
| 190 static const GrUserStencilSettings& kUnused; |
| 191 }; |
| 192 |
| 193 template<GrUserStencilTest Test, GrUserStencilOp PassOp, GrUserStencilOp FailOp> |
| 194 struct GrUserStencilSettings::Attrs { |
| 195 // Ensure an op that only modifies user bits isn't paired with one that modi
fies clip bits. |
| 196 GR_STATIC_ASSERT(GrUserStencilOp::kKeep == PassOp || GrUserStencilOp::kKeep
== FailOp || |
| 197 (PassOp <= kLastUserOnlyStencilOp) == (FailOp <= kLastUserO
nlyStencilOp)); |
| 198 // Ensure an op that only modifies clip bits isn't paired with one that modi
fies clip and user. |
| 199 GR_STATIC_ASSERT(GrUserStencilOp::kKeep == PassOp || GrUserStencilOp::kKeep
== FailOp || |
| 200 (PassOp <= kLastClipOnlyStencilOp) == (FailOp <= kLastClipO
nlyStencilOp)); |
| 201 |
| 202 constexpr static bool TestAlwaysPasses(bool hasStencilClip) { |
| 203 return (!hasStencilClip && GrUserStencilTest::kAlwaysIfInClip == Test) |
| |
| 204 GrUserStencilTest::kAlways == Test; |
| 205 } |
| 206 constexpr static bool DoesNotModifyStencil(bool hasStencilClip) { |
| 207 return (GrUserStencilTest::kNever == Test || GrUserStencilOp::kKeep == P
assOp) && |
| 208 (TestAlwaysPasses(hasStencilClip) || GrUserStencilOp::kKeep == F
ailOp); |
| 209 } |
| 210 constexpr static bool IsDisabled(bool hasStencilClip) { |
| 211 return TestAlwaysPasses(hasStencilClip) && DoesNotModifyStencil(hasStenc
ilClip); |
| 212 } |
| 213 constexpr static bool UsesWrapOps() { |
| 214 return GrUserStencilOp::kIncWrap == PassOp || GrUserStencilOp::kDecWrap
== PassOp || |
| 215 GrUserStencilOp::kIncWrap == FailOp || GrUserStencilOp::kDecWrap
== FailOp; |
| 216 } |
| 217 constexpr static bool TestIgnoresRef() { |
| 218 return (GrUserStencilTest::kAlwaysIfInClip == Test || GrUserStencilTest:
:kAlways == Test || |
| 219 GrUserStencilTest::kNever == Test); |
| 220 } |
| 221 constexpr static uint16_t Flags(bool hasStencilClip) { |
| 222 return (IsDisabled(hasStencilClip) ? kDisabled_StencilFlag : 0) | |
| 223 (DoesNotModifyStencil(hasStencilClip) ? kNoModifyStencil_StencilF
lag : 0) | |
| 224 (UsesWrapOps() ? 0 : kNoWrapOps_StencilFlag); |
| 225 } |
| 226 constexpr static uint16_t EffectiveTestMask(uint16_t testMask) { |
| 227 return TestIgnoresRef() ? 0 : testMask; |
| 228 } |
| 229 constexpr static uint16_t EffectiveWriteMask(uint16_t writeMask) { |
| 230 // We don't modify the mask differently when hasStencilClip=false becaus
e either the entire |
| 231 // face gets disabled in that case (e.g. Test=kAlwaysIfInClip, PassOp=kK
eep), or else the |
| 232 // effective mask stays the same either way. |
| 233 return DoesNotModifyStencil(true) ? 0 : writeMask; |
| 234 } |
| 235 }; |
| 236 |
| 237 #endif |
OLD | NEW |