xref: /aosp_15_r20/external/skia/src/gpu/ganesh/GrUserStencilSettings.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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/ganesh/GrTypes.h"  // IWYU pragma: keep
13 
14 #include <cstdint>
15 
16 /**
17  * Gr uses the stencil buffer to implement complex clipping inside the
18  * OpsTask class. The OpsTask makes a subset of the stencil buffer
19  * bits available for other uses by external code (user bits). Client code can
20  * modify these bits. OpsTask will ignore ref, mask, and writemask bits
21  * provided by clients that fall outside the user range.
22  *
23  * When code outside the OpsTask class uses the stencil buffer the contract
24  * is as follows:
25  *
26  * > Normal stencil funcs allow the client to pass / fail regardless of the
27  *   reserved clip bits.
28  * > Additional functions allow a test against the clip along with a limited
29  *   set of tests against the user bits.
30  * > Client can assume all user bits are zero initially.
31  * > Client must ensure that after all its passes are finished it has only
32  *   written to the color buffer in the region inside the clip. Furthermore, it
33  *   must zero all user bits that were modifed (both inside and outside the
34  *   clip).
35  */
36 
37 enum GrStencilFlags : int {
38     kDisabled_StencilFlag         = (1 << 0),
39     kTestAlwaysPasses_StencilFlag = (1 << 1),
40     kNoModifyStencil_StencilFlag  = (1 << 2),
41     kNoWrapOps_StencilFlag        = (1 << 3),
42     kSingleSided_StencilFlag      = (1 << 4),
43 
44     kLast_StencilFlag = kSingleSided_StencilFlag,
45     kAll_StencilFlags = kLast_StencilFlag | (kLast_StencilFlag - 1)
46 };
47 
48 template<typename TTest, typename TOp> struct GrTStencilFaceSettings {
49     uint16_t   fRef;        // Reference value for stencil test and ops.
50     TTest      fTest;       // Stencil test function, where fRef is on the left side.
51     uint16_t   fTestMask;   // Bitwise "and" to perform on fRef and stencil values before testing.
52                             // (e.g. (fRef & fTestMask) < (stencil & fTestMask))
53     TOp        fPassOp;     // Op to perform when the test passes.
54     TOp        fFailOp;     // Op to perform when the test fails.
55     uint16_t   fWriteMask;  // Indicates which bits in the stencil buffer should be updated.
56                             // (e.g. stencil = (newValue & fWriteMask) | (stencil & ~fWriteMask))
57 };
58 
59 enum class GrUserStencilTest : uint16_t {
60     // Tests that respect the clip bit. If a stencil clip is not in effect, the "IfInClip" is
61     // ignored and these only act on user bits.
62     kAlwaysIfInClip,
63     kEqualIfInClip,
64     kLessIfInClip,
65     kLEqualIfInClip,
66 
67     // Tests that ignore the clip bit. The client is responsible to ensure no color write occurs
68     // outside the clip if it is in use.
69     kAlways,
70     kNever,
71     kGreater,
72     kGEqual,
73     kLess,
74     kLEqual,
75     kEqual,
76     kNotEqual
77 };
78 constexpr static GrUserStencilTest kLastClippedStencilTest = GrUserStencilTest::kLEqualIfInClip;
79 constexpr static int kGrUserStencilTestCount = 1 + (int)GrUserStencilTest::kNotEqual;
80 
81 enum class GrUserStencilOp : uint8_t {
82     kKeep,
83 
84     // Ops that only modify user bits. These must not be paired with ops that modify the clip bit.
85     kZero,
86     kReplace, // Replace stencil value with fRef (only the bits enabled in fWriteMask).
87     kInvert,
88     kIncWrap,
89     kDecWrap,
90     // These two should only be used if wrap ops are not supported, or if the math is guaranteed
91     // to not overflow. The user bits may or may not clamp, depending on the state of non-user bits.
92     kIncMaybeClamp,
93     kDecMaybeClamp,
94 
95     // Ops that only modify the clip bit. These must not be paired with ops that modify user bits.
96     kZeroClipBit,
97     kSetClipBit,
98     kInvertClipBit,
99 
100     // Ops that modify both clip and user bits. These can only be paired with kKeep or each other.
101     kSetClipAndReplaceUserBits,
102     kZeroClipAndUserBits
103 };
104 constexpr static GrUserStencilOp kLastUserOnlyStencilOp = GrUserStencilOp::kDecMaybeClamp;
105 constexpr static GrUserStencilOp kLastClipOnlyStencilOp = GrUserStencilOp::kInvertClipBit;
106 constexpr static int kGrUserStencilOpCount = 1 + (int)GrUserStencilOp::kZeroClipAndUserBits;
107 
108 /**
109  * This struct is a compile-time constant representation of user stencil settings. It describes in
110  * abstract terms how a draw will use the stencil buffer. It gets ODR-used at runtime to define a
111  * draw's stencil settings, and is later translated into concrete settings when the pipeline is
112  * finalized.
113  */
114 struct GrUserStencilSettings {
115     typedef GrTStencilFaceSettings<GrUserStencilTest, GrUserStencilOp> Face;
116 
117     template<GrUserStencilTest, GrUserStencilOp PassOp, GrUserStencilOp FailOp> struct Attrs;
118 
119     // Unfortunately, this is the only way to pass template arguments to a constructor.
120     template<uint16_t Ref, GrUserStencilTest Test, uint16_t TestMask,
121              GrUserStencilOp PassOp, GrUserStencilOp FailOp, uint16_t WriteMask> struct Init {};
122 
123     template<uint16_t CWRef,            uint16_t CCWRef,
124              GrUserStencilTest CWTest,  GrUserStencilTest CCWTest,
125              uint16_t CWTestMask,       uint16_t CCWTestMask,
126              GrUserStencilOp CWPassOp,  GrUserStencilOp CCWPassOp,
127              GrUserStencilOp CWFailOp,  GrUserStencilOp CCWFailOp,
128              uint16_t CWWriteMask,      uint16_t CCWWriteMask> struct InitSeparate {};
129 
130     template<uint16_t Ref, GrUserStencilTest Test, uint16_t TestMask,
131              GrUserStencilOp PassOp, GrUserStencilOp FailOp, uint16_t WriteMask>
StaticInitGrUserStencilSettings132     constexpr static Init<Ref, Test, TestMask, PassOp, FailOp, WriteMask> StaticInit() {
133         return Init<Ref, Test, TestMask, PassOp, FailOp, WriteMask>();
134     }
135 
136     template<uint16_t CWRef,            uint16_t CCWRef,
137              GrUserStencilTest CWTest,  GrUserStencilTest CCWTest,
138              uint16_t CWTestMask,       uint16_t CCWTestMask,
139              GrUserStencilOp CWPassOp,  GrUserStencilOp CCWPassOp,
140              GrUserStencilOp CWFailOp,  GrUserStencilOp CCWFailOp,
141              uint16_t CWWriteMask,      uint16_t CCWWriteMask>
142     constexpr static InitSeparate<CWRef, CCWRef, CWTest, CCWTest, CWTestMask, CCWTestMask,
143                                   CWPassOp, CCWPassOp, CWFailOp, CCWFailOp, CWWriteMask,
StaticInitSeparateGrUserStencilSettings144                                   CCWWriteMask> StaticInitSeparate() {
145         return InitSeparate<CWRef, CCWRef, CWTest, CCWTest, CWTestMask, CCWTestMask,
146                             CWPassOp, CCWPassOp, CWFailOp, CCWFailOp, CWWriteMask, CCWWriteMask>();
147     }
148 
149     // We construct with template arguments in order to enforce that the struct be compile-time
150     // constant and to make use of static asserts.
151     template<uint16_t Ref, GrUserStencilTest Test, uint16_t TestMask,
152              GrUserStencilOp PassOp, GrUserStencilOp FailOp, uint16_t WriteMask,
153              typename Attrs = Attrs<Test, PassOp, FailOp> >
GrUserStencilSettingsGrUserStencilSettings154     constexpr explicit GrUserStencilSettings(
155             const Init<Ref, Test, TestMask, PassOp, FailOp, WriteMask>&)
156         : fCWFlags{(uint16_t)(Attrs::Flags(false) | kSingleSided_StencilFlag),
157                       (uint16_t)(Attrs::Flags(true) | kSingleSided_StencilFlag)}
158         , fCWFace{Ref, Test, Attrs::EffectiveTestMask(TestMask), PassOp, FailOp,
159                  Attrs::EffectiveWriteMask(WriteMask)}
160         , fCCWFlags{(uint16_t)(Attrs::Flags(false) | kSingleSided_StencilFlag),
161                      (uint16_t)(Attrs::Flags(true) | kSingleSided_StencilFlag)}
162         , fCCWFace{Ref, Test, Attrs::EffectiveTestMask(TestMask), PassOp, FailOp,
163                 Attrs::EffectiveWriteMask(WriteMask)} {
164     }
165 
166     template<uint16_t CWRef,            uint16_t CCWRef,
167              GrUserStencilTest CWTest,  GrUserStencilTest CCWTest,
168              uint16_t CWTestMask,       uint16_t CCWTestMask,
169              GrUserStencilOp CWPassOp,  GrUserStencilOp CCWPassOp,
170              GrUserStencilOp CWFailOp,  GrUserStencilOp CCWFailOp,
171              uint16_t CWWriteMask,      uint16_t CCWWriteMask,
172              typename CWAttrs = Attrs<CWTest, CWPassOp, CWFailOp>,
173              typename CCWAttrs = Attrs<CCWTest, CCWPassOp, CCWFailOp> >
GrUserStencilSettingsGrUserStencilSettings174     constexpr explicit GrUserStencilSettings(
175             const InitSeparate<CWRef, CCWRef, CWTest, CCWTest, CWTestMask, CCWTestMask,
176                                CWPassOp, CCWPassOp, CWFailOp, CCWFailOp, CWWriteMask,
177                                CCWWriteMask>&)
178         : fCWFlags{CWAttrs::Flags(false), CWAttrs::Flags(true)}
179         , fCWFace{CWRef, CWTest, CWAttrs::EffectiveTestMask(CWTestMask), CWPassOp, CWFailOp,
180                  CWAttrs::EffectiveWriteMask(CWWriteMask)}
181         , fCCWFlags{CCWAttrs::Flags(false), CCWAttrs::Flags(true)}
182         , fCCWFace{CCWRef, CCWTest, CCWAttrs::EffectiveTestMask(CCWTestMask), CCWPassOp, CCWFailOp,
183                 CCWAttrs::EffectiveWriteMask(CCWWriteMask)} {}
184 
185     // This struct can only be constructed with static initializers.
186     GrUserStencilSettings() = delete;
187     GrUserStencilSettings(const GrUserStencilSettings&) = delete;
188 
flagsGrUserStencilSettings189     uint16_t flags(bool hasStencilClip) const {
190         return fCWFlags[hasStencilClip] & fCCWFlags[hasStencilClip];
191     }
isDisabledGrUserStencilSettings192     bool isDisabled(bool hasStencilClip) const {
193         return this->flags(hasStencilClip) & kDisabled_StencilFlag;
194     }
testAlwaysPassesGrUserStencilSettings195     bool testAlwaysPasses(bool hasStencilClip) const {
196         return this->flags(hasStencilClip) & kTestAlwaysPasses_StencilFlag;
197     }
isTwoSidedGrUserStencilSettings198     bool isTwoSided(bool hasStencilClip) const {
199         return !(this->flags(hasStencilClip) & kSingleSided_StencilFlag);
200     }
usesWrapOpGrUserStencilSettings201     bool usesWrapOp(bool hasStencilClip) const {
202         return !(this->flags(hasStencilClip) & kNoWrapOps_StencilFlag);
203     }
204 
205     const uint16_t   fCWFlags[2]; // cwFlagsForDraw = fCWFlags[hasStencilClip].
206     const Face       fCWFace;
207     const uint16_t   fCCWFlags[2]; // ccwFlagsForDraw = fCCWFlags[hasStencilClip].
208     const Face       fCCWFace;
209 
210     static const GrUserStencilSettings& kUnused;
211 
isUnusedGrUserStencilSettings212     bool isUnused() const { return this == &kUnused; }
213 };
214 
215 template<GrUserStencilTest Test, GrUserStencilOp PassOp, GrUserStencilOp FailOp>
216 struct GrUserStencilSettings::Attrs {
217     // Ensure an op that only modifies user bits isn't paired with one that modifies clip bits.
218     static_assert(GrUserStencilOp::kKeep == PassOp || GrUserStencilOp::kKeep == FailOp ||
219                   (PassOp <= kLastUserOnlyStencilOp) == (FailOp <= kLastUserOnlyStencilOp));
220     // Ensure an op that only modifies clip bits isn't paired with one that modifies clip and user.
221     static_assert(GrUserStencilOp::kKeep == PassOp || GrUserStencilOp::kKeep == FailOp ||
222                   (PassOp <= kLastClipOnlyStencilOp) == (FailOp <= kLastClipOnlyStencilOp));
223 
TestAlwaysPassesAttrs224     constexpr static bool TestAlwaysPasses(bool hasStencilClip) {
225         return (!hasStencilClip && GrUserStencilTest::kAlwaysIfInClip == Test) ||
226                 GrUserStencilTest::kAlways == Test;
227     }
DoesNotModifyStencilAttrs228     constexpr static bool DoesNotModifyStencil(bool hasStencilClip) {
229         return (GrUserStencilTest::kNever == Test || GrUserStencilOp::kKeep == PassOp) &&
230                 (TestAlwaysPasses(hasStencilClip) || GrUserStencilOp::kKeep == FailOp);
231     }
IsDisabledAttrs232     constexpr static bool IsDisabled(bool hasStencilClip) {
233         return TestAlwaysPasses(hasStencilClip) && DoesNotModifyStencil(hasStencilClip);
234     }
UsesWrapOpsAttrs235     constexpr static bool UsesWrapOps() {
236         return GrUserStencilOp::kIncWrap == PassOp || GrUserStencilOp::kDecWrap == PassOp ||
237                GrUserStencilOp::kIncWrap == FailOp || GrUserStencilOp::kDecWrap == FailOp;
238     }
TestIgnoresRefAttrs239     constexpr static bool TestIgnoresRef() {
240         return (GrUserStencilTest::kAlwaysIfInClip == Test || GrUserStencilTest::kAlways == Test ||
241                 GrUserStencilTest::kNever == Test);
242     }
FlagsAttrs243     constexpr static uint16_t Flags(bool hasStencilClip) {
244         return (IsDisabled(hasStencilClip) ? kDisabled_StencilFlag : 0) |
245                (TestAlwaysPasses(hasStencilClip) ? kTestAlwaysPasses_StencilFlag : 0) |
246                (DoesNotModifyStencil(hasStencilClip) ? kNoModifyStencil_StencilFlag : 0) |
247                (UsesWrapOps() ? 0 : kNoWrapOps_StencilFlag);
248     }
EffectiveTestMaskAttrs249     constexpr static uint16_t EffectiveTestMask(uint16_t testMask) {
250         return TestIgnoresRef() ? 0 : testMask;
251     }
EffectiveWriteMaskAttrs252     constexpr static uint16_t EffectiveWriteMask(uint16_t writeMask) {
253         // We don't modify the mask differently when hasStencilClip=false because either the entire
254         // face gets disabled in that case (e.g. Test=kAlwaysIfInClip, PassOp=kKeep), or else the
255         // effective mask stays the same either way.
256         return DoesNotModifyStencil(true) ? 0 : writeMask;
257     }
258 };
259 
260 #endif
261