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