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> |
130 | 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, |
142 | 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> > |
152 | 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> > |
172 | 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 | |
187 | uint16_t flags(bool hasStencilClip) const { |
188 | return fCWFlags[hasStencilClip] & fCCWFlags[hasStencilClip]; |
189 | } |
190 | bool isDisabled(bool hasStencilClip) const { |
191 | return this->flags(hasStencilClip) & kDisabled_StencilFlag; |
192 | } |
193 | bool testAlwaysPasses(bool hasStencilClip) const { |
194 | return this->flags(hasStencilClip) & kTestAlwaysPasses_StencilFlag; |
195 | } |
196 | bool isTwoSided(bool hasStencilClip) const { |
197 | return !(this->flags(hasStencilClip) & kSingleSided_StencilFlag); |
198 | } |
199 | 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 | |
210 | 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 | |
222 | constexpr static bool TestAlwaysPasses(bool hasStencilClip) { |
223 | return (!hasStencilClip && GrUserStencilTest::kAlwaysIfInClip == Test) || |
224 | GrUserStencilTest::kAlways == Test; |
225 | } |
226 | constexpr static bool DoesNotModifyStencil(bool hasStencilClip) { |
227 | return (GrUserStencilTest::kNever == Test || GrUserStencilOp::kKeep == PassOp) && |
228 | (TestAlwaysPasses(hasStencilClip) || GrUserStencilOp::kKeep == FailOp); |
229 | } |
230 | constexpr static bool IsDisabled(bool hasStencilClip) { |
231 | return TestAlwaysPasses(hasStencilClip) && DoesNotModifyStencil(hasStencilClip); |
232 | } |
233 | constexpr static bool UsesWrapOps() { |
234 | return GrUserStencilOp::kIncWrap == PassOp || GrUserStencilOp::kDecWrap == PassOp || |
235 | GrUserStencilOp::kIncWrap == FailOp || GrUserStencilOp::kDecWrap == FailOp; |
236 | } |
237 | constexpr static bool TestIgnoresRef() { |
238 | return (GrUserStencilTest::kAlwaysIfInClip == Test || GrUserStencilTest::kAlways == Test || |
239 | GrUserStencilTest::kNever == Test); |
240 | } |
241 | 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 | } |
247 | constexpr static uint16_t EffectiveTestMask(uint16_t testMask) { |
248 | return TestIgnoresRef() ? 0 : testMask; |
249 | } |
250 | 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 | |