Line data Source code
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 : * GrOpList class. The GrOpList 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. GrOpList will ignore ref, mask, and writemask bits
19 : * provided by clients that fall outside the user range.
20 : *
21 : * When code outside the GrOpList 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 values 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) | (stencil & ~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 color 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::kNotEqual;
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 modify the clip bit.
82 : kZero,
83 : kReplace, // Replace stencil value with fRef (only the bits enabled in fWriteMask).
84 : kInvert,
85 : kIncWrap,
86 : kDecWrap,
87 : // These two should only be used if wrap ops are not supported, or if the math is guaranteed
88 : // to not overflow. The user bits may or may not clamp, depending on the state 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 kKeep or each other.
98 : kSetClipAndReplaceUserBits,
99 : kZeroClipAndUserBits
100 : };
101 : constexpr static GrUserStencilOp kLastUserOnlyStencilOp = GrUserStencilOp::kDecMaybeClamp;
102 : constexpr static GrUserStencilOp kLastClipOnlyStencilOp = GrUserStencilOp::kInvertClipBit;
103 : constexpr static int kGrUserStencilOpCount = 1 + (int)GrUserStencilOp::kZeroClipAndUserBits;
104 :
105 : /**
106 : * This struct is a compile-time constant representation of user stencil settings. It describes in
107 : * abstract terms how a draw will use the stencil buffer. It gets ODR-used at runtime 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 constructor.
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 InitSeparate {};
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> StaticInit() {
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, BkTestMask,
140 : FtPassOp, BkPassOp, FtFailOp, BkFailOp, FtWriteMask,
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, BkTestMask,
173 : FtPassOp, BkPassOp, FtFailOp, BkFailOp, FtWriteMask, 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 0 : uint16_t flags(bool hasStencilClip) const {
186 0 : return fFrontFlags[hasStencilClip] & fBackFlags[hasStencilClip];
187 : }
188 0 : bool isDisabled(bool hasStencilClip) const {
189 0 : return this->flags(hasStencilClip) & kDisabled_StencilFlag;
190 : }
191 : bool isTwoSided(bool hasStencilClip) const {
192 : return !(this->flags(hasStencilClip) & kSingleSided_StencilFlag);
193 : }
194 : bool usesWrapOp(bool hasStencilClip) const {
195 : return !(this->flags(hasStencilClip) & kNoWrapOps_StencilFlag);
196 : }
197 :
198 : const uint16_t fFrontFlags[2]; // frontFlagsForDraw = fFrontFlags[hasStencilClip].
199 : const Face fFront;
200 : const uint16_t fBackFlags[2]; // backFlagsForDraw = fBackFlags[hasStencilClip].
201 : const Face fBack;
202 :
203 : static const GrUserStencilSettings& kUnused;
204 :
205 0 : bool isUnused() const { return this == &kUnused; }
206 : };
207 :
208 : template<GrUserStencilTest Test, GrUserStencilOp PassOp, GrUserStencilOp FailOp>
209 : struct GrUserStencilSettings::Attrs {
210 : // Ensure an op that only modifies user bits isn't paired with one that modifies clip bits.
211 : GR_STATIC_ASSERT(GrUserStencilOp::kKeep == PassOp || GrUserStencilOp::kKeep == FailOp ||
212 : (PassOp <= kLastUserOnlyStencilOp) == (FailOp <= kLastUserOnlyStencilOp));
213 : // Ensure an op that only modifies clip bits isn't paired with one that modifies clip and user.
214 : GR_STATIC_ASSERT(GrUserStencilOp::kKeep == PassOp || GrUserStencilOp::kKeep == FailOp ||
215 : (PassOp <= kLastClipOnlyStencilOp) == (FailOp <= kLastClipOnlyStencilOp));
216 :
217 : constexpr static bool TestAlwaysPasses(bool hasStencilClip) {
218 : return (!hasStencilClip && GrUserStencilTest::kAlwaysIfInClip == Test) ||
219 : GrUserStencilTest::kAlways == Test;
220 : }
221 : constexpr static bool DoesNotModifyStencil(bool hasStencilClip) {
222 : return (GrUserStencilTest::kNever == Test || GrUserStencilOp::kKeep == PassOp) &&
223 : (TestAlwaysPasses(hasStencilClip) || GrUserStencilOp::kKeep == FailOp);
224 : }
225 : constexpr static bool IsDisabled(bool hasStencilClip) {
226 : return TestAlwaysPasses(hasStencilClip) && DoesNotModifyStencil(hasStencilClip);
227 : }
228 : constexpr static bool UsesWrapOps() {
229 : return GrUserStencilOp::kIncWrap == PassOp || GrUserStencilOp::kDecWrap == PassOp ||
230 : GrUserStencilOp::kIncWrap == FailOp || GrUserStencilOp::kDecWrap == FailOp;
231 : }
232 : constexpr static bool TestIgnoresRef() {
233 : return (GrUserStencilTest::kAlwaysIfInClip == Test || GrUserStencilTest::kAlways == Test ||
234 : GrUserStencilTest::kNever == Test);
235 : }
236 : constexpr static uint16_t Flags(bool hasStencilClip) {
237 : return (IsDisabled(hasStencilClip) ? kDisabled_StencilFlag : 0) |
238 : (DoesNotModifyStencil(hasStencilClip) ? kNoModifyStencil_StencilFlag : 0) |
239 : (UsesWrapOps() ? 0 : kNoWrapOps_StencilFlag);
240 : }
241 : constexpr static uint16_t EffectiveTestMask(uint16_t testMask) {
242 : return TestIgnoresRef() ? 0 : testMask;
243 : }
244 : constexpr static uint16_t EffectiveWriteMask(uint16_t writeMask) {
245 : // We don't modify the mask differently when hasStencilClip=false because either the entire
246 : // face gets disabled in that case (e.g. Test=kAlwaysIfInClip, PassOp=kKeep), or else the
247 : // effective mask stays the same either way.
248 : return DoesNotModifyStencil(true) ? 0 : writeMask;
249 : }
250 : };
251 :
252 : #endif
|