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 |