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 "include/core/SkRegion.h"
13#include "src/gpu/GrUserStencilSettings.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& singleSidedFace() const {
82 SkASSERT(!this->isDisabled());
83 SkASSERT(!this->isTwoSided());
84 return fCWFace;
85 }
86 // Returns the stencil settings for triangles that wind clockwise in "post-origin" space.
87 // (i.e., the space that results after a potential y-axis flip on device space for bottom-left
88 // origins.)
89 const Face& postOriginCWFace(GrSurfaceOrigin origin) const {
90 SkASSERT(this->isTwoSided());
91 return (kTopLeft_GrSurfaceOrigin == origin) ? fCWFace : fCCWFace;
92 }
93 // Returns the stencil settings for triangles that wind counter-clockwise in "post-origin"
94 // space. (i.e., the space that results after a potential y-axis flip on device space for
95 // bottom-left origins.)
96 const Face& postOriginCCWFace(GrSurfaceOrigin origin) const {
97 SkASSERT(this->isTwoSided());
98 return (kTopLeft_GrSurfaceOrigin == origin) ? fCCWFace : fCWFace;
99 }
100
101 /**
102 * Given a thing to draw into the stencil clip, a fill type, and a set op
103 * this function determines:
104 * 1. Whether the thing can be draw directly to the stencil clip or
105 * needs to be drawn to the client portion of the stencil first.
106 * 2. How many passes are needed.
107 * 3. What those passes are.
108 *
109 * @param op the set op to combine this element with the existing clip
110 * @param canBeDirect can the caller draw this element directly (without using stencil)?
111 * @param invertedFill is this path inverted
112 * @param drawDirectToClip out: true if caller should draw the element directly, false if it
113 * should draw it into the user stencil bits first.
114 *
115 * @return a null-terminated array of settings for stencil passes.
116 *
117 * If drawDirectToClip is false, the caller must first draw the element into the user
118 * stencil bits, and then cover the clip area with multiple passes using the returned
119 * stencil settings.
120 *
121 * If drawDirectToClip is true, the returned array will only have one pass and the
122 * caller should use those stencil settings while drawing the element directly.
123 */
124 static GrUserStencilSettings const* const* GetClipPasses(SkRegion::Op op,
125 bool canBeDirect,
126 bool invertedFill,
127 bool* drawDirectToClip);
128
129 /** Gets the user stencil settings to directly set the clip bit. */
130 static const GrUserStencilSettings* SetClipBitSettings(bool setToInside);
131
132private:
133 // Internal flag for backends to optionally mark their tracked stencil state as invalid.
134 // NOTE: This value is outside the declared range of GrStencilFlags, but since that type is
135 // explicitly backed by 'int', it can still represent this constant. clang 11 complains about
136 // mixing enum types in bit operations, so this works around that.
137 static constexpr GrStencilFlags kInvalid_PrivateFlag =
138 static_cast<GrStencilFlags>(kLast_StencilFlag << 1);
139
140 uint32_t fFlags;
141 Face fCWFace;
142 Face fCCWFace;
143};
144
145#endif
146