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 GrStencilSettings_DEFINED
10#define GrStencilSettings_DEFINED
11
12#include "GrUserStencilSettings.h"
13#include "SkRegion.h"
14
15class GrProcessorKeyBuilder;
16
17enum class GrStencilTest : uint16_t {
18    kAlways,
19    kNever,
20    kGreater,
21    kGEqual,
22    kLess,
23    kLEqual,
24    kEqual,
25    kNotEqual
26};
27static constexpr int kGrStencilTestCount = 1 + (int)GrStencilTest::kNotEqual;
28
29enum class GrStencilOp : uint8_t {
30    kKeep,
31    kZero,
32    kReplace, // Replace stencil value with fRef (only the bits enabled in fWriteMask).
33    kInvert,
34    kIncWrap,
35    kDecWrap,
36    // NOTE: clamping occurs before the write mask. So if the MSB is zero and masked out, stencil
37    // values will still wrap when using clamping ops.
38    kIncClamp,
39    kDecClamp
40};
41static constexpr int kGrStencilOpCount = 1 + (int)GrStencilOp::kDecClamp;
42
43/**
44 * This class defines concrete stencil settings that map directly to the underlying hardware. It
45 * is deduced from user stencil settings, stencil clip status, and the number of bits in the
46 * target stencil buffer.
47 */
48class GrStencilSettings {
49public:
50    GrStencilSettings() { this->setDisabled(); }
51    GrStencilSettings(const GrUserStencilSettings& user, bool hasStencilClip, int numStencilBits) {
52        this->reset(user, hasStencilClip, numStencilBits);
53    }
54    GrStencilSettings(const GrStencilSettings& that) { this->reset(that); }
55    GrStencilSettings& operator=(const GrStencilSettings& that) { this->reset(that); return *this; }
56
57    void invalidate() { fFlags |= kInvalid_PrivateFlag; }
58    void setDisabled() { fFlags = kAll_StencilFlags; }
59    void reset(const GrUserStencilSettings&, bool hasStencilClip, int numStencilBits);
60    void reset(const GrStencilSettings&);
61
62    bool isValid() const { return !(fFlags & kInvalid_PrivateFlag); }
63    bool isDisabled() const { SkASSERT(this->isValid()); return fFlags & kDisabled_StencilFlag; }
64    bool doesWrite() const { SkASSERT(this->isValid());
65                             return !(fFlags & kNoModifyStencil_StencilFlag); }
66    bool isTwoSided() const { SkASSERT(this->isValid());
67                              return !(fFlags & kSingleSided_StencilFlag); }
68    bool usesWrapOp() const { SkASSERT(this->isValid());
69                              return !(fFlags & kNoWrapOps_StencilFlag); }
70
71    void genKey(GrProcessorKeyBuilder* b) const;
72
73    bool operator!=(const GrStencilSettings& that) const { return !(*this == that); }
74    bool operator==(const GrStencilSettings&) const;
75
76    struct Face : public GrTStencilFaceSettings<GrStencilTest, GrStencilOp> {
77        void reset(const GrUserStencilSettings::Face&, bool useStencilClip, int numStencilBits);
78        void setDisabled();
79    };
80
81    const Face& front() const { SkASSERT(!this->isDisabled()); return fFront; }
82    const Face& back() const { SkASSERT(this->isTwoSided()); return fBack; }
83
84    /**
85     * Given a thing to draw into the stencil clip, a fill type, and a set op
86     * this function determines:
87     *      1. Whether the thing can be draw directly to the stencil clip or
88     *      needs to be drawn to the client portion of the stencil first.
89     *      2. How many passes are needed.
90     *      3. What those passes are.
91     *
92     * @param op                the set op to combine this element with the existing clip
93     * @param canBeDirect       can the caller draw this element directly (without using stencil)?
94     * @param invertedFill      is this path inverted
95     * @param drawDirectToClip  out: true if caller should draw the element directly, false if it
96     *                          should draw it into the user stencil bits first.
97     *
98     * @return a null-terminated array of settings for stencil passes.
99     *
100     *         If drawDirectToClip is false, the caller must first draw the element into the user
101     *         stencil bits, and then cover the clip area with multiple passes using the returned
102     *         stencil settings.
103     *
104     *         If drawDirectToClip is true, the returned array will only have one pass and the
105     *         caller should use those stencil settings while drawing the element directly.
106     */
107    static GrUserStencilSettings const* const* GetClipPasses(SkRegion::Op op,
108                                                             bool canBeDirect,
109                                                             bool invertedFill,
110                                                             bool* drawDirectToClip);
111
112    /** Gets the user stencil settings to directly set the clip bit. */
113    static const GrUserStencilSettings* SetClipBitSettings(bool setToInside);
114
115private:
116    // Internal flag for backends to optionally mark their tracked stencil state as invalid.
117    enum { kInvalid_PrivateFlag = (kLast_StencilFlag << 1) };
118
119    uint32_t   fFlags;
120    Face       fFront;
121    Face       fBack;
122};
123
124#endif
125