blob: 83a19b776ea03ef21e920159aca7aa792d564481 [file] [log] [blame]
cdalton93a379b2016-05-11 13:58:08 -07001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "include/gpu/GrTypes.h"
cdalton93a379b2016-05-11 13:58:08 -070013
14/**
15 * Gr uses the stencil buffer to implement complex clipping inside the
Greg Danielf41b2bd2019-08-22 16:19:24 -040016 * GrOpsTask class. The GrOpsTask makes a subset of the stencil buffer
cdalton93a379b2016-05-11 13:58:08 -070017 * bits available for other uses by external code (user bits). Client code can
Greg Danielf41b2bd2019-08-22 16:19:24 -040018 * modify these bits. GrOpsTask will ignore ref, mask, and writemask bits
cdalton93a379b2016-05-11 13:58:08 -070019 * provided by clients that fall outside the user range.
20 *
Greg Danielf41b2bd2019-08-22 16:19:24 -040021 * When code outside the GrOpsTask class uses the stencil buffer the contract
cdalton93a379b2016-05-11 13:58:08 -070022 * 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
35enum GrStencilFlags {
Chris Daltonb8fff0d2019-03-05 10:11:58 -070036 kDisabled_StencilFlag = (1 << 0),
37 kTestAlwaysPasses_StencilFlag = (1 << 1),
38 kNoModifyStencil_StencilFlag = (1 << 2),
39 kNoWrapOps_StencilFlag = (1 << 3),
40 kSingleSided_StencilFlag = (1 << 4),
cdalton93a379b2016-05-11 13:58:08 -070041
42 kLast_StencilFlag = kSingleSided_StencilFlag,
43 kAll_StencilFlags = kLast_StencilFlag | (kLast_StencilFlag - 1)
44};
45
46template<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
57enum 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};
76constexpr static GrUserStencilTest kLastClippedStencilTest = GrUserStencilTest::kLEqualIfInClip;
77constexpr static int kGrUserStencilTestCount = 1 + (int)GrUserStencilTest::kNotEqual;
78
79enum 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};
102constexpr static GrUserStencilOp kLastUserOnlyStencilOp = GrUserStencilOp::kDecMaybeClamp;
103constexpr static GrUserStencilOp kLastClipOnlyStencilOp = GrUserStencilOp::kInvertClipBit;
104constexpr 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 */
112struct 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 FtRef, uint16_t BkRef,
122 GrUserStencilTest FtTest, GrUserStencilTest BkTest,
123 uint16_t FtTestMask, uint16_t BkTestMask,
124 GrUserStencilOp FtPassOp, GrUserStencilOp BkPassOp,
125 GrUserStencilOp FtFailOp, GrUserStencilOp BkFailOp,
126 uint16_t FtWriteMask, uint16_t BkWriteMask> 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 FtRef, uint16_t BkRef,
135 GrUserStencilTest FtTest, GrUserStencilTest BkTest,
136 uint16_t FtTestMask, uint16_t BkTestMask,
137 GrUserStencilOp FtPassOp, GrUserStencilOp BkPassOp,
138 GrUserStencilOp FtFailOp, GrUserStencilOp BkFailOp,
139 uint16_t FtWriteMask, uint16_t BkWriteMask>
140 constexpr static InitSeparate<FtRef, BkRef, FtTest, BkTest, FtTestMask, BkTestMask,
141 FtPassOp, BkPassOp, FtFailOp, BkFailOp, FtWriteMask,
142 BkWriteMask> StaticInitSeparate() {
143 return InitSeparate<FtRef, BkRef, FtTest, BkTest, FtTestMask, BkTestMask,
144 FtPassOp, BkPassOp, FtFailOp, BkFailOp, FtWriteMask, BkWriteMask>();
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 : fFrontFlags{(uint16_t)(Attrs::Flags(false) | kSingleSided_StencilFlag),
155 (uint16_t)(Attrs::Flags(true) | kSingleSided_StencilFlag)}
156 , fFront{Ref, Test, Attrs::EffectiveTestMask(TestMask), PassOp, FailOp,
157 Attrs::EffectiveWriteMask(WriteMask)}
158 , fBackFlags{(uint16_t)(Attrs::Flags(false) | kSingleSided_StencilFlag),
159 (uint16_t)(Attrs::Flags(true) | kSingleSided_StencilFlag)}
160 , fBack{Ref, Test, Attrs::EffectiveTestMask(TestMask), PassOp, FailOp,
161 Attrs::EffectiveWriteMask(WriteMask)} {
162 }
163
164 template<uint16_t FtRef, uint16_t BkRef,
165 GrUserStencilTest FtTest, GrUserStencilTest BkTest,
166 uint16_t FtTestMask, uint16_t BkTestMask,
167 GrUserStencilOp FtPassOp, GrUserStencilOp BkPassOp,
168 GrUserStencilOp FtFailOp, GrUserStencilOp BkFailOp,
169 uint16_t FtWriteMask, uint16_t BkWriteMask,
170 typename FtAttrs = Attrs<FtTest, FtPassOp, FtFailOp>,
171 typename BkAttrs = Attrs<BkTest, BkPassOp, BkFailOp> >
172 constexpr explicit GrUserStencilSettings(
173 const InitSeparate<FtRef, BkRef, FtTest, BkTest, FtTestMask, BkTestMask,
174 FtPassOp, BkPassOp, FtFailOp, BkFailOp, FtWriteMask, BkWriteMask>&)
175 : fFrontFlags{FtAttrs::Flags(false), FtAttrs::Flags(true)}
176 , fFront{FtRef, FtTest, FtAttrs::EffectiveTestMask(FtTestMask), FtPassOp, FtFailOp,
177 FtAttrs::EffectiveWriteMask(FtWriteMask)}
178 , fBackFlags{BkAttrs::Flags(false), BkAttrs::Flags(true)}
179 , fBack{BkRef, BkTest, BkAttrs::EffectiveTestMask(BkTestMask), BkPassOp, BkFailOp,
180 BkAttrs::EffectiveWriteMask(BkWriteMask)} {}
181
182 // This struct can only be constructed with static initializers.
183 GrUserStencilSettings() = delete;
184 GrUserStencilSettings(const GrUserStencilSettings&) = delete;
185
csmartdaltonc633abb2016-11-01 08:55:55 -0700186 uint16_t flags(bool hasStencilClip) const {
187 return fFrontFlags[hasStencilClip] & fBackFlags[hasStencilClip];
188 }
189 bool isDisabled(bool hasStencilClip) const {
190 return this->flags(hasStencilClip) & kDisabled_StencilFlag;
191 }
Chris Daltonb8fff0d2019-03-05 10:11:58 -0700192 bool testAlwaysPasses(bool hasStencilClip) const {
193 return this->flags(hasStencilClip) & kTestAlwaysPasses_StencilFlag;
194 }
csmartdaltonc633abb2016-11-01 08:55:55 -0700195 bool isTwoSided(bool hasStencilClip) const {
196 return !(this->flags(hasStencilClip) & kSingleSided_StencilFlag);
197 }
198 bool usesWrapOp(bool hasStencilClip) const {
199 return !(this->flags(hasStencilClip) & kNoWrapOps_StencilFlag);
200 }
201
cdalton93a379b2016-05-11 13:58:08 -0700202 const uint16_t fFrontFlags[2]; // frontFlagsForDraw = fFrontFlags[hasStencilClip].
203 const Face fFront;
204 const uint16_t fBackFlags[2]; // backFlagsForDraw = fBackFlags[hasStencilClip].
205 const Face fBack;
206
207 static const GrUserStencilSettings& kUnused;
robertphillips976f5f02016-06-03 10:59:20 -0700208
209 bool isUnused() const { return this == &kUnused; }
cdalton93a379b2016-05-11 13:58:08 -0700210};
211
212template<GrUserStencilTest Test, GrUserStencilOp PassOp, GrUserStencilOp FailOp>
213struct GrUserStencilSettings::Attrs {
214 // Ensure an op that only modifies user bits isn't paired with one that modifies clip bits.
215 GR_STATIC_ASSERT(GrUserStencilOp::kKeep == PassOp || GrUserStencilOp::kKeep == FailOp ||
216 (PassOp <= kLastUserOnlyStencilOp) == (FailOp <= kLastUserOnlyStencilOp));
217 // Ensure an op that only modifies clip bits isn't paired with one that modifies clip and user.
218 GR_STATIC_ASSERT(GrUserStencilOp::kKeep == PassOp || GrUserStencilOp::kKeep == FailOp ||
219 (PassOp <= kLastClipOnlyStencilOp) == (FailOp <= kLastClipOnlyStencilOp));
220
221 constexpr static bool TestAlwaysPasses(bool hasStencilClip) {
222 return (!hasStencilClip && GrUserStencilTest::kAlwaysIfInClip == Test) ||
223 GrUserStencilTest::kAlways == Test;
224 }
225 constexpr static bool DoesNotModifyStencil(bool hasStencilClip) {
226 return (GrUserStencilTest::kNever == Test || GrUserStencilOp::kKeep == PassOp) &&
227 (TestAlwaysPasses(hasStencilClip) || GrUserStencilOp::kKeep == FailOp);
228 }
229 constexpr static bool IsDisabled(bool hasStencilClip) {
230 return TestAlwaysPasses(hasStencilClip) && DoesNotModifyStencil(hasStencilClip);
231 }
232 constexpr static bool UsesWrapOps() {
233 return GrUserStencilOp::kIncWrap == PassOp || GrUserStencilOp::kDecWrap == PassOp ||
234 GrUserStencilOp::kIncWrap == FailOp || GrUserStencilOp::kDecWrap == FailOp;
235 }
236 constexpr static bool TestIgnoresRef() {
237 return (GrUserStencilTest::kAlwaysIfInClip == Test || GrUserStencilTest::kAlways == Test ||
238 GrUserStencilTest::kNever == Test);
239 }
240 constexpr static uint16_t Flags(bool hasStencilClip) {
241 return (IsDisabled(hasStencilClip) ? kDisabled_StencilFlag : 0) |
Chris Daltonb8fff0d2019-03-05 10:11:58 -0700242 (TestAlwaysPasses(hasStencilClip) ? kTestAlwaysPasses_StencilFlag : 0) |
cdalton93a379b2016-05-11 13:58:08 -0700243 (DoesNotModifyStencil(hasStencilClip) ? kNoModifyStencil_StencilFlag : 0) |
244 (UsesWrapOps() ? 0 : kNoWrapOps_StencilFlag);
245 }
246 constexpr static uint16_t EffectiveTestMask(uint16_t testMask) {
247 return TestIgnoresRef() ? 0 : testMask;
248 }
249 constexpr static uint16_t EffectiveWriteMask(uint16_t writeMask) {
250 // We don't modify the mask differently when hasStencilClip=false because either the entire
251 // face gets disabled in that case (e.g. Test=kAlwaysIfInClip, PassOp=kKeep), or else the
252 // effective mask stays the same either way.
253 return DoesNotModifyStencil(true) ? 0 : writeMask;
254 }
255};
256
257#endif