• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  * 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         = (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 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>
StaticInitGrUserStencilSettings130     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,
StaticInitSeparateGrUserStencilSettings142                                   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> >
GrUserStencilSettingsGrUserStencilSettings152     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> >
GrUserStencilSettingsGrUserStencilSettings172     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 
flagsGrUserStencilSettings186     uint16_t flags(bool hasStencilClip) const {
187         return fFrontFlags[hasStencilClip] & fBackFlags[hasStencilClip];
188     }
isDisabledGrUserStencilSettings189     bool isDisabled(bool hasStencilClip) const {
190         return this->flags(hasStencilClip) & kDisabled_StencilFlag;
191     }
testAlwaysPassesGrUserStencilSettings192     bool testAlwaysPasses(bool hasStencilClip) const {
193         return this->flags(hasStencilClip) & kTestAlwaysPasses_StencilFlag;
194     }
isTwoSidedGrUserStencilSettings195     bool isTwoSided(bool hasStencilClip) const {
196         return !(this->flags(hasStencilClip) & kSingleSided_StencilFlag);
197     }
usesWrapOpGrUserStencilSettings198     bool usesWrapOp(bool hasStencilClip) const {
199         return !(this->flags(hasStencilClip) & kNoWrapOps_StencilFlag);
200     }
201 
202     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;
208 
isUnusedGrUserStencilSettings209     bool isUnused() const { return this == &kUnused; }
210 };
211 
212 template<GrUserStencilTest Test, GrUserStencilOp PassOp, GrUserStencilOp FailOp>
213 struct 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 
TestAlwaysPassesAttrs221     constexpr static bool TestAlwaysPasses(bool hasStencilClip) {
222         return (!hasStencilClip && GrUserStencilTest::kAlwaysIfInClip == Test) ||
223                 GrUserStencilTest::kAlways == Test;
224     }
DoesNotModifyStencilAttrs225     constexpr static bool DoesNotModifyStencil(bool hasStencilClip) {
226         return (GrUserStencilTest::kNever == Test || GrUserStencilOp::kKeep == PassOp) &&
227                 (TestAlwaysPasses(hasStencilClip) || GrUserStencilOp::kKeep == FailOp);
228     }
IsDisabledAttrs229     constexpr static bool IsDisabled(bool hasStencilClip) {
230         return TestAlwaysPasses(hasStencilClip) && DoesNotModifyStencil(hasStencilClip);
231     }
UsesWrapOpsAttrs232     constexpr static bool UsesWrapOps() {
233         return GrUserStencilOp::kIncWrap == PassOp || GrUserStencilOp::kDecWrap == PassOp ||
234                GrUserStencilOp::kIncWrap == FailOp || GrUserStencilOp::kDecWrap == FailOp;
235     }
TestIgnoresRefAttrs236     constexpr static bool TestIgnoresRef() {
237         return (GrUserStencilTest::kAlwaysIfInClip == Test || GrUserStencilTest::kAlways == Test ||
238                 GrUserStencilTest::kNever == Test);
239     }
FlagsAttrs240     constexpr static uint16_t Flags(bool hasStencilClip) {
241         return (IsDisabled(hasStencilClip) ? kDisabled_StencilFlag : 0) |
242                (TestAlwaysPasses(hasStencilClip) ? kTestAlwaysPasses_StencilFlag : 0) |
243                (DoesNotModifyStencil(hasStencilClip) ? kNoModifyStencil_StencilFlag : 0) |
244                (UsesWrapOps() ? 0 : kNoWrapOps_StencilFlag);
245     }
EffectiveTestMaskAttrs246     constexpr static uint16_t EffectiveTestMask(uint16_t testMask) {
247         return TestIgnoresRef() ? 0 : testMask;
248     }
EffectiveWriteMaskAttrs249     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
258