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 * OpsTask class. The OpsTask 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. OpsTask will ignore ref, mask, and writemask bits
19 * provided by clients that fall outside the user range.
20 *
21 * When code outside the OpsTask 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
35enum GrStencilFlags : int {
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
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 CWRef,            uint16_t CCWRef,
122             GrUserStencilTest CWTest,  GrUserStencilTest CCWTest,
123             uint16_t CWTestMask,       uint16_t CCWTestMask,
124             GrUserStencilOp CWPassOp,  GrUserStencilOp CCWPassOp,
125             GrUserStencilOp CWFailOp,  GrUserStencilOp CCWFailOp,
126             uint16_t CWWriteMask,      uint16_t CCWWriteMask> 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 CWRef,            uint16_t CCWRef,
135             GrUserStencilTest CWTest,  GrUserStencilTest CCWTest,
136             uint16_t CWTestMask,       uint16_t CCWTestMask,
137             GrUserStencilOp CWPassOp,  GrUserStencilOp CCWPassOp,
138             GrUserStencilOp CWFailOp,  GrUserStencilOp CCWFailOp,
139             uint16_t CWWriteMask,      uint16_t CCWWriteMask>
140    constexpr static InitSeparate<CWRef, CCWRef, CWTest, CCWTest, CWTestMask, CCWTestMask,
141                                  CWPassOp, CCWPassOp, CWFailOp, CCWFailOp, CWWriteMask,
142                                  CCWWriteMask> StaticInitSeparate() {
143        return InitSeparate<CWRef, CCWRef, CWTest, CCWTest, CWTestMask, CCWTestMask,
144                            CWPassOp, CCWPassOp, CWFailOp, CCWFailOp, CWWriteMask, CCWWriteMask>();
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        : fCWFlags{(uint16_t)(Attrs::Flags(false) | kSingleSided_StencilFlag),
155                      (uint16_t)(Attrs::Flags(true) | kSingleSided_StencilFlag)}
156        , fCWFace{Ref, Test, Attrs::EffectiveTestMask(TestMask), PassOp, FailOp,
157                 Attrs::EffectiveWriteMask(WriteMask)}
158        , fCCWFlags{(uint16_t)(Attrs::Flags(false) | kSingleSided_StencilFlag),
159                     (uint16_t)(Attrs::Flags(true) | kSingleSided_StencilFlag)}
160        , fCCWFace{Ref, Test, Attrs::EffectiveTestMask(TestMask), PassOp, FailOp,
161                Attrs::EffectiveWriteMask(WriteMask)} {
162    }
163
164    template<uint16_t CWRef,            uint16_t CCWRef,
165             GrUserStencilTest CWTest,  GrUserStencilTest CCWTest,
166             uint16_t CWTestMask,       uint16_t CCWTestMask,
167             GrUserStencilOp CWPassOp,  GrUserStencilOp CCWPassOp,
168             GrUserStencilOp CWFailOp,  GrUserStencilOp CCWFailOp,
169             uint16_t CWWriteMask,      uint16_t CCWWriteMask,
170             typename CWAttrs = Attrs<CWTest, CWPassOp, CWFailOp>,
171             typename CCWAttrs = Attrs<CCWTest, CCWPassOp, CCWFailOp> >
172    constexpr explicit GrUserStencilSettings(
173            const InitSeparate<CWRef, CCWRef, CWTest, CCWTest, CWTestMask, CCWTestMask,
174                               CWPassOp, CCWPassOp, CWFailOp, CCWFailOp, CWWriteMask,
175                               CCWWriteMask>&)
176        : fCWFlags{CWAttrs::Flags(false), CWAttrs::Flags(true)}
177        , fCWFace{CWRef, CWTest, CWAttrs::EffectiveTestMask(CWTestMask), CWPassOp, CWFailOp,
178                 CWAttrs::EffectiveWriteMask(CWWriteMask)}
179        , fCCWFlags{CCWAttrs::Flags(false), CCWAttrs::Flags(true)}
180        , fCCWFace{CCWRef, CCWTest, CCWAttrs::EffectiveTestMask(CCWTestMask), CCWPassOp, CCWFailOp,
181                CCWAttrs::EffectiveWriteMask(CCWWriteMask)} {}
182
183    // This struct can only be constructed with static initializers.
184    GrUserStencilSettings() = delete;
185    GrUserStencilSettings(const GrUserStencilSettings&) = delete;
186
187    uint16_t flags(bool hasStencilClip) const {
188        return fCWFlags[hasStencilClip] & fCCWFlags[hasStencilClip];
189    }
190    bool isDisabled(bool hasStencilClip) const {
191        return this->flags(hasStencilClip) & kDisabled_StencilFlag;
192    }
193    bool testAlwaysPasses(bool hasStencilClip) const {
194        return this->flags(hasStencilClip) & kTestAlwaysPasses_StencilFlag;
195    }
196    bool isTwoSided(bool hasStencilClip) const {
197        return !(this->flags(hasStencilClip) & kSingleSided_StencilFlag);
198    }
199    bool usesWrapOp(bool hasStencilClip) const {
200        return !(this->flags(hasStencilClip) & kNoWrapOps_StencilFlag);
201    }
202
203    const uint16_t   fCWFlags[2]; // cwFlagsForDraw = fCWFlags[hasStencilClip].
204    const Face       fCWFace;
205    const uint16_t   fCCWFlags[2]; // ccwFlagsForDraw = fCCWFlags[hasStencilClip].
206    const Face       fCCWFace;
207
208    static const GrUserStencilSettings& kUnused;
209
210    bool isUnused() const { return this == &kUnused; }
211};
212
213template<GrUserStencilTest Test, GrUserStencilOp PassOp, GrUserStencilOp FailOp>
214struct GrUserStencilSettings::Attrs {
215    // Ensure an op that only modifies user bits isn't paired with one that modifies clip bits.
216    static_assert(GrUserStencilOp::kKeep == PassOp || GrUserStencilOp::kKeep == FailOp ||
217                  (PassOp <= kLastUserOnlyStencilOp) == (FailOp <= kLastUserOnlyStencilOp));
218    // Ensure an op that only modifies clip bits isn't paired with one that modifies clip and user.
219    static_assert(GrUserStencilOp::kKeep == PassOp || GrUserStencilOp::kKeep == FailOp ||
220                  (PassOp <= kLastClipOnlyStencilOp) == (FailOp <= kLastClipOnlyStencilOp));
221
222    constexpr static bool TestAlwaysPasses(bool hasStencilClip) {
223        return (!hasStencilClip && GrUserStencilTest::kAlwaysIfInClip == Test) ||
224                GrUserStencilTest::kAlways == Test;
225    }
226    constexpr static bool DoesNotModifyStencil(bool hasStencilClip) {
227        return (GrUserStencilTest::kNever == Test || GrUserStencilOp::kKeep == PassOp) &&
228                (TestAlwaysPasses(hasStencilClip) || GrUserStencilOp::kKeep == FailOp);
229    }
230    constexpr static bool IsDisabled(bool hasStencilClip) {
231        return TestAlwaysPasses(hasStencilClip) && DoesNotModifyStencil(hasStencilClip);
232    }
233    constexpr static bool UsesWrapOps() {
234        return GrUserStencilOp::kIncWrap == PassOp || GrUserStencilOp::kDecWrap == PassOp ||
235               GrUserStencilOp::kIncWrap == FailOp || GrUserStencilOp::kDecWrap == FailOp;
236    }
237    constexpr static bool TestIgnoresRef() {
238        return (GrUserStencilTest::kAlwaysIfInClip == Test || GrUserStencilTest::kAlways == Test ||
239                GrUserStencilTest::kNever == Test);
240    }
241    constexpr static uint16_t Flags(bool hasStencilClip) {
242        return (IsDisabled(hasStencilClip) ? kDisabled_StencilFlag : 0) |
243               (TestAlwaysPasses(hasStencilClip) ? kTestAlwaysPasses_StencilFlag : 0) |
244               (DoesNotModifyStencil(hasStencilClip) ? kNoModifyStencil_StencilFlag : 0) |
245               (UsesWrapOps() ? 0 : kNoWrapOps_StencilFlag);
246    }
247    constexpr static uint16_t EffectiveTestMask(uint16_t testMask) {
248        return TestIgnoresRef() ? 0 : testMask;
249    }
250    constexpr static uint16_t EffectiveWriteMask(uint16_t writeMask) {
251        // We don't modify the mask differently when hasStencilClip=false because either the entire
252        // face gets disabled in that case (e.g. Test=kAlwaysIfInClip, PassOp=kKeep), or else the
253        // effective mask stays the same either way.
254        return DoesNotModifyStencil(true) ? 0 : writeMask;
255    }
256};
257
258#endif
259