xref: /aosp_15_r20/external/skia/src/gpu/ganesh/ClipStack.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2020 Google LLC
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 #ifndef ClipStack_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker #define ClipStack_DEFINED
10*c8dee2aaSAndroid Build Coastguard Worker 
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkShader.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTypeTraits.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkTBlockList.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ResourceKey.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrClip.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrFragmentProcessor.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/geometry/GrShape.h"
23*c8dee2aaSAndroid Build Coastguard Worker 
24*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
25*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
26*c8dee2aaSAndroid Build Coastguard Worker #include <type_traits>
27*c8dee2aaSAndroid Build Coastguard Worker 
28*c8dee2aaSAndroid Build Coastguard Worker class GrAppliedClip;
29*c8dee2aaSAndroid Build Coastguard Worker class GrDrawOp;
30*c8dee2aaSAndroid Build Coastguard Worker class GrProxyProvider;
31*c8dee2aaSAndroid Build Coastguard Worker class GrRecordingContext;
32*c8dee2aaSAndroid Build Coastguard Worker class SkPath;
33*c8dee2aaSAndroid Build Coastguard Worker class SkRRect;
34*c8dee2aaSAndroid Build Coastguard Worker enum class GrAA : bool;
35*c8dee2aaSAndroid Build Coastguard Worker enum class GrAAType : unsigned int;
36*c8dee2aaSAndroid Build Coastguard Worker enum class SkClipOp;
37*c8dee2aaSAndroid Build Coastguard Worker 
38*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu {
39*c8dee2aaSAndroid Build Coastguard Worker namespace ganesh {
40*c8dee2aaSAndroid Build Coastguard Worker class SurfaceDrawContext;
41*c8dee2aaSAndroid Build Coastguard Worker }
42*c8dee2aaSAndroid Build Coastguard Worker }  // namespace skgpu
43*c8dee2aaSAndroid Build Coastguard Worker 
44*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::ganesh {
45*c8dee2aaSAndroid Build Coastguard Worker 
46*c8dee2aaSAndroid Build Coastguard Worker class ClipStack final : public GrClip {
47*c8dee2aaSAndroid Build Coastguard Worker public:
48*c8dee2aaSAndroid Build Coastguard Worker     enum class ClipState : uint8_t {
49*c8dee2aaSAndroid Build Coastguard Worker         kEmpty, kWideOpen, kDeviceRect, kDeviceRRect, kComplex
50*c8dee2aaSAndroid Build Coastguard Worker     };
51*c8dee2aaSAndroid Build Coastguard Worker 
52*c8dee2aaSAndroid Build Coastguard Worker     // All data describing a geometric modification to the clip
53*c8dee2aaSAndroid Build Coastguard Worker     struct Element {
54*c8dee2aaSAndroid Build Coastguard Worker         GrShape  fShape;
55*c8dee2aaSAndroid Build Coastguard Worker         SkMatrix fLocalToDevice;
56*c8dee2aaSAndroid Build Coastguard Worker         SkClipOp fOp;
57*c8dee2aaSAndroid Build Coastguard Worker         GrAA     fAA;
58*c8dee2aaSAndroid Build Coastguard Worker 
59*c8dee2aaSAndroid Build Coastguard Worker         static_assert(::sk_is_trivially_relocatable<decltype(fShape)>::value);
60*c8dee2aaSAndroid Build Coastguard Worker         static_assert(::sk_is_trivially_relocatable<decltype(fLocalToDevice)>::value);
61*c8dee2aaSAndroid Build Coastguard Worker         static_assert(::sk_is_trivially_relocatable<decltype(fOp)>::value);
62*c8dee2aaSAndroid Build Coastguard Worker         static_assert(::sk_is_trivially_relocatable<decltype(fAA)>::value);
63*c8dee2aaSAndroid Build Coastguard Worker 
64*c8dee2aaSAndroid Build Coastguard Worker         using sk_is_trivially_relocatable = std::true_type;
65*c8dee2aaSAndroid Build Coastguard Worker     };
66*c8dee2aaSAndroid Build Coastguard Worker 
67*c8dee2aaSAndroid Build Coastguard Worker     // The ctm must outlive the ClipStack.
68*c8dee2aaSAndroid Build Coastguard Worker     ClipStack(const SkIRect& deviceBounds, const SkMatrix* ctm, bool forceAA);
69*c8dee2aaSAndroid Build Coastguard Worker 
70*c8dee2aaSAndroid Build Coastguard Worker     ~ClipStack() override;
71*c8dee2aaSAndroid Build Coastguard Worker 
72*c8dee2aaSAndroid Build Coastguard Worker     ClipStack(const ClipStack&) = delete;
73*c8dee2aaSAndroid Build Coastguard Worker     ClipStack& operator=(const ClipStack&) = delete;
74*c8dee2aaSAndroid Build Coastguard Worker 
clipState()75*c8dee2aaSAndroid Build Coastguard Worker     ClipState clipState() const { return this->currentSaveRecord().state(); }
76*c8dee2aaSAndroid Build Coastguard Worker 
77*c8dee2aaSAndroid Build Coastguard Worker     class ElementIter;
78*c8dee2aaSAndroid Build Coastguard Worker     // Provides for-range over active, valid clip elements from most recent to oldest.
79*c8dee2aaSAndroid Build Coastguard Worker     // The iterator provides items as "const Element&".
80*c8dee2aaSAndroid Build Coastguard Worker     inline ElementIter begin() const;
81*c8dee2aaSAndroid Build Coastguard Worker     inline ElementIter end() const;
82*c8dee2aaSAndroid Build Coastguard Worker 
83*c8dee2aaSAndroid Build Coastguard Worker     // Clip stack manipulation
84*c8dee2aaSAndroid Build Coastguard Worker     void save();
85*c8dee2aaSAndroid Build Coastguard Worker     void restore();
86*c8dee2aaSAndroid Build Coastguard Worker 
clipRect(const SkMatrix & ctm,const SkRect & rect,GrAA aa,SkClipOp op)87*c8dee2aaSAndroid Build Coastguard Worker     void clipRect(const SkMatrix& ctm, const SkRect& rect, GrAA aa, SkClipOp op) {
88*c8dee2aaSAndroid Build Coastguard Worker         this->clip({ctm, GrShape(rect), aa, op});
89*c8dee2aaSAndroid Build Coastguard Worker     }
clipRRect(const SkMatrix & ctm,const SkRRect & rrect,GrAA aa,SkClipOp op)90*c8dee2aaSAndroid Build Coastguard Worker     void clipRRect(const SkMatrix& ctm, const SkRRect& rrect, GrAA aa, SkClipOp op) {
91*c8dee2aaSAndroid Build Coastguard Worker         this->clip({ctm, GrShape(rrect), aa, op});
92*c8dee2aaSAndroid Build Coastguard Worker     }
clipPath(const SkMatrix & ctm,const SkPath & path,GrAA aa,SkClipOp op)93*c8dee2aaSAndroid Build Coastguard Worker     void clipPath(const SkMatrix& ctm, const SkPath& path, GrAA aa, SkClipOp op) {
94*c8dee2aaSAndroid Build Coastguard Worker         this->clip({ctm, GrShape(path), aa, op});
95*c8dee2aaSAndroid Build Coastguard Worker     }
96*c8dee2aaSAndroid Build Coastguard Worker     void clipShader(sk_sp<SkShader> shader);
97*c8dee2aaSAndroid Build Coastguard Worker 
98*c8dee2aaSAndroid Build Coastguard Worker     void replaceClip(const SkIRect& rect);
99*c8dee2aaSAndroid Build Coastguard Worker 
100*c8dee2aaSAndroid Build Coastguard Worker     // GrClip implementation
101*c8dee2aaSAndroid Build Coastguard Worker     GrClip::Effect apply(GrRecordingContext*,
102*c8dee2aaSAndroid Build Coastguard Worker                          skgpu::ganesh::SurfaceDrawContext*,
103*c8dee2aaSAndroid Build Coastguard Worker                          GrDrawOp*,
104*c8dee2aaSAndroid Build Coastguard Worker                          GrAAType,
105*c8dee2aaSAndroid Build Coastguard Worker                          GrAppliedClip*,
106*c8dee2aaSAndroid Build Coastguard Worker                          SkRect* bounds) const override;
107*c8dee2aaSAndroid Build Coastguard Worker     GrClip::PreClipResult preApply(const SkRect& drawBounds, GrAA aa) const override;
108*c8dee2aaSAndroid Build Coastguard Worker     SkIRect getConservativeBounds() const override;
109*c8dee2aaSAndroid Build Coastguard Worker 
110*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
testingOnly_getLastSWMaskKey()111*c8dee2aaSAndroid Build Coastguard Worker     UniqueKey testingOnly_getLastSWMaskKey() const {
112*c8dee2aaSAndroid Build Coastguard Worker         return fMasks.empty() ? UniqueKey() : fMasks.back().key();
113*c8dee2aaSAndroid Build Coastguard Worker     }
114*c8dee2aaSAndroid Build Coastguard Worker #endif
115*c8dee2aaSAndroid Build Coastguard Worker 
116*c8dee2aaSAndroid Build Coastguard Worker private:
117*c8dee2aaSAndroid Build Coastguard Worker     class SaveRecord;
118*c8dee2aaSAndroid Build Coastguard Worker     // class Mask;
119*c8dee2aaSAndroid Build Coastguard Worker 
120*c8dee2aaSAndroid Build Coastguard Worker     // Internally, a lot of clip reasoning is based on an op, outer bounds, and whether a shape
121*c8dee2aaSAndroid Build Coastguard Worker     // contains another (possibly just conservatively based on inner/outer device-space bounds).
122*c8dee2aaSAndroid Build Coastguard Worker     //
123*c8dee2aaSAndroid Build Coastguard Worker     // Element and SaveRecord store this information directly, but a draw fits the same definition
124*c8dee2aaSAndroid Build Coastguard Worker     // with an implicit intersect op and empty inner bounds. The OpDraw and RRectDraw types provide
125*c8dee2aaSAndroid Build Coastguard Worker     // the same interface as Element and SaveRecord for internal clip reasoning templates.
126*c8dee2aaSAndroid Build Coastguard Worker     class Draw;
127*c8dee2aaSAndroid Build Coastguard Worker 
128*c8dee2aaSAndroid Build Coastguard Worker     // Wraps the geometric Element data with logic for containment and bounds testing.
129*c8dee2aaSAndroid Build Coastguard Worker     class RawElement : private Element {
130*c8dee2aaSAndroid Build Coastguard Worker     public:
131*c8dee2aaSAndroid Build Coastguard Worker         using Stack = SkTBlockList<RawElement, 1>;
132*c8dee2aaSAndroid Build Coastguard Worker 
133*c8dee2aaSAndroid Build Coastguard Worker         RawElement(const SkMatrix& localToDevice, const GrShape& shape, GrAA aa, SkClipOp op);
134*c8dee2aaSAndroid Build Coastguard Worker 
135*c8dee2aaSAndroid Build Coastguard Worker         // Common clip type interface
op()136*c8dee2aaSAndroid Build Coastguard Worker         SkClipOp        op() const { return fOp; }
outerBounds()137*c8dee2aaSAndroid Build Coastguard Worker         const SkIRect&  outerBounds() const { return fOuterBounds; }
138*c8dee2aaSAndroid Build Coastguard Worker         bool            contains(const SaveRecord& s) const;
139*c8dee2aaSAndroid Build Coastguard Worker         bool            contains(const Draw& d) const;
140*c8dee2aaSAndroid Build Coastguard Worker         bool            contains(const RawElement& e) const;
141*c8dee2aaSAndroid Build Coastguard Worker 
142*c8dee2aaSAndroid Build Coastguard Worker         // Additional element-specific data
asElement()143*c8dee2aaSAndroid Build Coastguard Worker         const Element&  asElement() const { return *this; }
144*c8dee2aaSAndroid Build Coastguard Worker 
shape()145*c8dee2aaSAndroid Build Coastguard Worker         const GrShape&  shape() const { return fShape; }
localToDevice()146*c8dee2aaSAndroid Build Coastguard Worker         const SkMatrix& localToDevice() const { return fLocalToDevice; }
innerBounds()147*c8dee2aaSAndroid Build Coastguard Worker         const SkIRect&  innerBounds() const { return fInnerBounds; }
aa()148*c8dee2aaSAndroid Build Coastguard Worker         GrAA            aa() const { return fAA; }
149*c8dee2aaSAndroid Build Coastguard Worker 
150*c8dee2aaSAndroid Build Coastguard Worker         ClipState       clipType() const;
151*c8dee2aaSAndroid Build Coastguard Worker 
152*c8dee2aaSAndroid Build Coastguard Worker         // As new elements are pushed on to the stack, they may make older elements redundant.
153*c8dee2aaSAndroid Build Coastguard Worker         // The old elements are marked invalid so they are skipped during clip application, but may
154*c8dee2aaSAndroid Build Coastguard Worker         // become active again when a save record is restored.
isInvalid()155*c8dee2aaSAndroid Build Coastguard Worker         bool isInvalid() const { return fInvalidatedByIndex >= 0; }
156*c8dee2aaSAndroid Build Coastguard Worker         void markInvalid(const SaveRecord& current);
157*c8dee2aaSAndroid Build Coastguard Worker         void restoreValid(const SaveRecord& current);
158*c8dee2aaSAndroid Build Coastguard Worker 
159*c8dee2aaSAndroid Build Coastguard Worker         // 'added' represents a new op added to the element stack. Its combination with this element
160*c8dee2aaSAndroid Build Coastguard Worker         // can result in a number of possibilities:
161*c8dee2aaSAndroid Build Coastguard Worker         //  1. The entire clip is empty (signaled by both this and 'added' being invalidated).
162*c8dee2aaSAndroid Build Coastguard Worker         //  2. The 'added' op supercedes this element (this element is invalidated).
163*c8dee2aaSAndroid Build Coastguard Worker         //  3. This op supercedes the 'added' element (the added element is marked invalidated).
164*c8dee2aaSAndroid Build Coastguard Worker         //  4. Their combination can be represented by a single new op (in which case this
165*c8dee2aaSAndroid Build Coastguard Worker         //     element should be invalidated, and the combined shape stored in 'added').
166*c8dee2aaSAndroid Build Coastguard Worker         //  5. Or both elements remain needed to describe the clip (both are valid and unchanged).
167*c8dee2aaSAndroid Build Coastguard Worker         //
168*c8dee2aaSAndroid Build Coastguard Worker         // The calling element will only modify its invalidation index since it could belong
169*c8dee2aaSAndroid Build Coastguard Worker         // to part of the inactive stack (that might be restored later). All merged state/geometry
170*c8dee2aaSAndroid Build Coastguard Worker         // is handled by modifying 'added'.
171*c8dee2aaSAndroid Build Coastguard Worker         void updateForElement(RawElement* added, const SaveRecord& current);
172*c8dee2aaSAndroid Build Coastguard Worker 
173*c8dee2aaSAndroid Build Coastguard Worker         void simplify(const SkIRect& deviceBounds, bool forceAA);
174*c8dee2aaSAndroid Build Coastguard Worker 
175*c8dee2aaSAndroid Build Coastguard Worker     private:
176*c8dee2aaSAndroid Build Coastguard Worker         bool combine(const RawElement& other, const SaveRecord& current);
177*c8dee2aaSAndroid Build Coastguard Worker 
178*c8dee2aaSAndroid Build Coastguard Worker         SkMatrix fDeviceToLocal; // cached inverse of fLocalToDevice for contains() optimization
179*c8dee2aaSAndroid Build Coastguard Worker 
180*c8dee2aaSAndroid Build Coastguard Worker         // Device space bounds, rounded in or out to pixel boundaries and accounting for any
181*c8dee2aaSAndroid Build Coastguard Worker         // uncertainty around anti-aliasing and rasterization snapping.
182*c8dee2aaSAndroid Build Coastguard Worker         SkIRect  fInnerBounds;
183*c8dee2aaSAndroid Build Coastguard Worker         SkIRect  fOuterBounds;
184*c8dee2aaSAndroid Build Coastguard Worker 
185*c8dee2aaSAndroid Build Coastguard Worker         // Elements are invalidated by SaveRecords as the record is updated with new elements that
186*c8dee2aaSAndroid Build Coastguard Worker         // override old geometry. An invalidated element stores the index of the first element of
187*c8dee2aaSAndroid Build Coastguard Worker         // the save record that invalidated it. This makes it easy to undo when the save record is
188*c8dee2aaSAndroid Build Coastguard Worker         // popped from the stack, and is stable as the current save record is modified.
189*c8dee2aaSAndroid Build Coastguard Worker         int fInvalidatedByIndex;
190*c8dee2aaSAndroid Build Coastguard Worker     };
191*c8dee2aaSAndroid Build Coastguard Worker 
192*c8dee2aaSAndroid Build Coastguard Worker     // Represents an alpha mask with the rasterized coverage from elements in a draw query that
193*c8dee2aaSAndroid Build Coastguard Worker     // could not be converted to analytic coverage FPs.
194*c8dee2aaSAndroid Build Coastguard Worker     // TODO: This is only required for SW masks. Stencil masks and atlas masks don't have resources
195*c8dee2aaSAndroid Build Coastguard Worker     // owned by the ClipStack. Once SW masks are no longer needed, this can go away.
196*c8dee2aaSAndroid Build Coastguard Worker     class Mask {
197*c8dee2aaSAndroid Build Coastguard Worker     public:
198*c8dee2aaSAndroid Build Coastguard Worker         using Stack = SkTBlockList<Mask, 1>;
199*c8dee2aaSAndroid Build Coastguard Worker 
200*c8dee2aaSAndroid Build Coastguard Worker         Mask(const SaveRecord& current, const SkIRect& bounds);
201*c8dee2aaSAndroid Build Coastguard Worker 
~Mask()202*c8dee2aaSAndroid Build Coastguard Worker         ~Mask() {
203*c8dee2aaSAndroid Build Coastguard Worker             // The key should have been released by the clip stack before hand
204*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(!fKey.isValid());
205*c8dee2aaSAndroid Build Coastguard Worker         }
206*c8dee2aaSAndroid Build Coastguard Worker 
key()207*c8dee2aaSAndroid Build Coastguard Worker         const UniqueKey& key() const { return fKey; }
bounds()208*c8dee2aaSAndroid Build Coastguard Worker         const SkIRect&   bounds() const { return fBounds; }
genID()209*c8dee2aaSAndroid Build Coastguard Worker         uint32_t         genID() const { return fGenID; }
210*c8dee2aaSAndroid Build Coastguard Worker 
211*c8dee2aaSAndroid Build Coastguard Worker         bool appliesToDraw(const SaveRecord& current, const SkIRect& drawBounds) const;
212*c8dee2aaSAndroid Build Coastguard Worker         void invalidate(GrProxyProvider* proxyProvider);
213*c8dee2aaSAndroid Build Coastguard Worker 
214*c8dee2aaSAndroid Build Coastguard Worker         SkDEBUGCODE(const SaveRecord* owner() const { return fOwner; })
215*c8dee2aaSAndroid Build Coastguard Worker     private:
216*c8dee2aaSAndroid Build Coastguard Worker         UniqueKey fKey;
217*c8dee2aaSAndroid Build Coastguard Worker         // The gen ID of the save record and the query bounds uniquely define the set of elements
218*c8dee2aaSAndroid Build Coastguard Worker         // that would go into a mask. If the save record adds new elements, its gen ID would change.
219*c8dee2aaSAndroid Build Coastguard Worker         // If the draw had different bounds it would select a different set of masked elements.
220*c8dee2aaSAndroid Build Coastguard Worker         // Repeatedly querying an unmodified save record with the same bounds is idempotent.
221*c8dee2aaSAndroid Build Coastguard Worker         SkIRect     fBounds;
222*c8dee2aaSAndroid Build Coastguard Worker         uint32_t    fGenID;
223*c8dee2aaSAndroid Build Coastguard Worker 
224*c8dee2aaSAndroid Build Coastguard Worker         SkDEBUGCODE(const SaveRecord* fOwner;)
225*c8dee2aaSAndroid Build Coastguard Worker     };
226*c8dee2aaSAndroid Build Coastguard Worker 
227*c8dee2aaSAndroid Build Coastguard Worker     // Represents a saved point in the clip stack, and manages the life time of elements added to
228*c8dee2aaSAndroid Build Coastguard Worker     // stack within the record's life time. Also provides the logic for determining active elements
229*c8dee2aaSAndroid Build Coastguard Worker     // given a draw query.
230*c8dee2aaSAndroid Build Coastguard Worker     class SaveRecord {
231*c8dee2aaSAndroid Build Coastguard Worker     public:
232*c8dee2aaSAndroid Build Coastguard Worker         using Stack = SkTBlockList<SaveRecord, 2>;
233*c8dee2aaSAndroid Build Coastguard Worker 
234*c8dee2aaSAndroid Build Coastguard Worker         explicit SaveRecord(const SkIRect& deviceBounds);
235*c8dee2aaSAndroid Build Coastguard Worker 
236*c8dee2aaSAndroid Build Coastguard Worker         SaveRecord(const SaveRecord& prior, int startingMaskIndex, int startingElementIndex);
237*c8dee2aaSAndroid Build Coastguard Worker 
238*c8dee2aaSAndroid Build Coastguard Worker         // The common clip type interface
op()239*c8dee2aaSAndroid Build Coastguard Worker         SkClipOp        op() const { return fStackOp; }
outerBounds()240*c8dee2aaSAndroid Build Coastguard Worker         const SkIRect&  outerBounds() const { return fOuterBounds; }
241*c8dee2aaSAndroid Build Coastguard Worker         bool            contains(const Draw& d) const;
242*c8dee2aaSAndroid Build Coastguard Worker         bool            contains(const RawElement& e) const;
243*c8dee2aaSAndroid Build Coastguard Worker 
244*c8dee2aaSAndroid Build Coastguard Worker         // Additional save record-specific data/functionality
shader()245*c8dee2aaSAndroid Build Coastguard Worker         const SkShader* shader() const { return fShader.get(); }
innerBounds()246*c8dee2aaSAndroid Build Coastguard Worker         const SkIRect&  innerBounds() const { return fInnerBounds; }
firstActiveElementIndex()247*c8dee2aaSAndroid Build Coastguard Worker         int             firstActiveElementIndex() const { return fStartingElementIndex; }
oldestElementIndex()248*c8dee2aaSAndroid Build Coastguard Worker         int             oldestElementIndex() const { return fOldestValidIndex; }
canBeUpdated()249*c8dee2aaSAndroid Build Coastguard Worker         bool            canBeUpdated() const { return (fDeferredSaveCount == 0); }
250*c8dee2aaSAndroid Build Coastguard Worker 
251*c8dee2aaSAndroid Build Coastguard Worker         ClipState       state() const;
252*c8dee2aaSAndroid Build Coastguard Worker         uint32_t        genID() const;
253*c8dee2aaSAndroid Build Coastguard Worker 
254*c8dee2aaSAndroid Build Coastguard Worker         // Deferred save manipulation
pushSave()255*c8dee2aaSAndroid Build Coastguard Worker         void pushSave() {
256*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(fDeferredSaveCount >= 0);
257*c8dee2aaSAndroid Build Coastguard Worker             fDeferredSaveCount++;
258*c8dee2aaSAndroid Build Coastguard Worker         }
259*c8dee2aaSAndroid Build Coastguard Worker         // Returns true if the record should stay alive. False means the ClipStack must delete it
popSave()260*c8dee2aaSAndroid Build Coastguard Worker         bool popSave() {
261*c8dee2aaSAndroid Build Coastguard Worker             fDeferredSaveCount--;
262*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(fDeferredSaveCount >= -1);
263*c8dee2aaSAndroid Build Coastguard Worker             return fDeferredSaveCount >= 0;
264*c8dee2aaSAndroid Build Coastguard Worker         }
265*c8dee2aaSAndroid Build Coastguard Worker 
266*c8dee2aaSAndroid Build Coastguard Worker         // Return true if the element was added to 'elements', or otherwise affected the save record
267*c8dee2aaSAndroid Build Coastguard Worker         // (e.g. turned it empty).
268*c8dee2aaSAndroid Build Coastguard Worker         bool addElement(RawElement&& toAdd, RawElement::Stack* elements);
269*c8dee2aaSAndroid Build Coastguard Worker 
270*c8dee2aaSAndroid Build Coastguard Worker         void addShader(sk_sp<SkShader> shader);
271*c8dee2aaSAndroid Build Coastguard Worker         void reset(const SkIRect& bounds);
272*c8dee2aaSAndroid Build Coastguard Worker 
273*c8dee2aaSAndroid Build Coastguard Worker         // Remove the elements owned by this save record, which must happen before the save record
274*c8dee2aaSAndroid Build Coastguard Worker         // itself is removed from the clip stack.
275*c8dee2aaSAndroid Build Coastguard Worker         void removeElements(RawElement::Stack* elements);
276*c8dee2aaSAndroid Build Coastguard Worker 
277*c8dee2aaSAndroid Build Coastguard Worker         // Restore element validity now that this record is the new top of the stack.
278*c8dee2aaSAndroid Build Coastguard Worker         void restoreElements(RawElement::Stack* elements);
279*c8dee2aaSAndroid Build Coastguard Worker 
280*c8dee2aaSAndroid Build Coastguard Worker         void invalidateMasks(GrProxyProvider* proxyProvider, Mask::Stack* masks);
281*c8dee2aaSAndroid Build Coastguard Worker 
282*c8dee2aaSAndroid Build Coastguard Worker     private:
283*c8dee2aaSAndroid Build Coastguard Worker         // These functions modify 'elements' and element-dependent state of the record
284*c8dee2aaSAndroid Build Coastguard Worker         // (such as valid index and fState).
285*c8dee2aaSAndroid Build Coastguard Worker         bool appendElement(RawElement&& toAdd, RawElement::Stack* elements);
286*c8dee2aaSAndroid Build Coastguard Worker         void replaceWithElement(RawElement&& toAdd, RawElement::Stack* elements);
287*c8dee2aaSAndroid Build Coastguard Worker 
288*c8dee2aaSAndroid Build Coastguard Worker         // Inner bounds is always contained in outer bounds, or it is empty. All bounds will be
289*c8dee2aaSAndroid Build Coastguard Worker         // contained in the device bounds.
290*c8dee2aaSAndroid Build Coastguard Worker         SkIRect   fInnerBounds; // Inside is full coverage (stack op == intersect) or 0 cov (diff)
291*c8dee2aaSAndroid Build Coastguard Worker         SkIRect   fOuterBounds; // Outside is 0 coverage (op == intersect) or full cov (diff)
292*c8dee2aaSAndroid Build Coastguard Worker 
293*c8dee2aaSAndroid Build Coastguard Worker         // A save record can have up to one shader, multiple shaders are automatically blended
294*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkShader> fShader;
295*c8dee2aaSAndroid Build Coastguard Worker 
296*c8dee2aaSAndroid Build Coastguard Worker         const int fStartingMaskIndex; // First mask owned by this save record
297*c8dee2aaSAndroid Build Coastguard Worker         const int fStartingElementIndex;  // First element owned by this save record
298*c8dee2aaSAndroid Build Coastguard Worker         int       fOldestValidIndex; // Index of oldest element that remains valid for this record
299*c8dee2aaSAndroid Build Coastguard Worker 
300*c8dee2aaSAndroid Build Coastguard Worker         int       fDeferredSaveCount; // Number of save() calls without modifications (yet)
301*c8dee2aaSAndroid Build Coastguard Worker 
302*c8dee2aaSAndroid Build Coastguard Worker         // Will be kIntersect unless every valid element is kDifference, which is significant
303*c8dee2aaSAndroid Build Coastguard Worker         // because if kDifference then there is an implicit extra outer bounds at the device edges.
304*c8dee2aaSAndroid Build Coastguard Worker         SkClipOp  fStackOp;
305*c8dee2aaSAndroid Build Coastguard Worker         ClipState fState;
306*c8dee2aaSAndroid Build Coastguard Worker         uint32_t  fGenID;
307*c8dee2aaSAndroid Build Coastguard Worker     };
308*c8dee2aaSAndroid Build Coastguard Worker 
309*c8dee2aaSAndroid Build Coastguard Worker     // Adds the element to the clip, handling allocating a new save record on the stack if
310*c8dee2aaSAndroid Build Coastguard Worker     // there is a deferred save.
311*c8dee2aaSAndroid Build Coastguard Worker     void clip(RawElement&& element);
312*c8dee2aaSAndroid Build Coastguard Worker 
currentSaveRecord()313*c8dee2aaSAndroid Build Coastguard Worker     const SaveRecord& currentSaveRecord() const {
314*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(!fSaves.empty());
315*c8dee2aaSAndroid Build Coastguard Worker         return fSaves.back();
316*c8dee2aaSAndroid Build Coastguard Worker     }
317*c8dee2aaSAndroid Build Coastguard Worker 
318*c8dee2aaSAndroid Build Coastguard Worker     // Will return the current save record, properly updating deferred saves
319*c8dee2aaSAndroid Build Coastguard Worker     // and initializing a first record if it were empty.
320*c8dee2aaSAndroid Build Coastguard Worker     SaveRecord& writableSaveRecord(bool* wasDeferred);
321*c8dee2aaSAndroid Build Coastguard Worker 
322*c8dee2aaSAndroid Build Coastguard Worker     // Generate or find a cached SW coverage mask and return an FP that samples it.
323*c8dee2aaSAndroid Build Coastguard Worker     // 'elements' is an array of pointers to elements in the stack.
324*c8dee2aaSAndroid Build Coastguard Worker     static GrFPResult GetSWMaskFP(GrRecordingContext* context, Mask::Stack* masks,
325*c8dee2aaSAndroid Build Coastguard Worker                                   const SaveRecord& current, const SkIRect& bounds,
326*c8dee2aaSAndroid Build Coastguard Worker                                   const Element** elements, int count,
327*c8dee2aaSAndroid Build Coastguard Worker                                   std::unique_ptr<GrFragmentProcessor> clipFP);
328*c8dee2aaSAndroid Build Coastguard Worker 
329*c8dee2aaSAndroid Build Coastguard Worker     RawElement::Stack        fElements;
330*c8dee2aaSAndroid Build Coastguard Worker     SaveRecord::Stack        fSaves; // always has one wide open record at the top
331*c8dee2aaSAndroid Build Coastguard Worker 
332*c8dee2aaSAndroid Build Coastguard Worker     // The masks are recorded during apply() calls so we can cache them; they are not modifications
333*c8dee2aaSAndroid Build Coastguard Worker     // of the actual clip stack.
334*c8dee2aaSAndroid Build Coastguard Worker     // NOTE: These fields can go away once a context has a dedicated clip atlas
335*c8dee2aaSAndroid Build Coastguard Worker     mutable Mask::Stack      fMasks;
336*c8dee2aaSAndroid Build Coastguard Worker     mutable GrProxyProvider* fProxyProvider;
337*c8dee2aaSAndroid Build Coastguard Worker 
338*c8dee2aaSAndroid Build Coastguard Worker     const SkIRect            fDeviceBounds;
339*c8dee2aaSAndroid Build Coastguard Worker     const SkMatrix*          fCTM;
340*c8dee2aaSAndroid Build Coastguard Worker 
341*c8dee2aaSAndroid Build Coastguard Worker     // When there's MSAA, clip elements are applied using the stencil buffer. If a backend cannot
342*c8dee2aaSAndroid Build Coastguard Worker     // disable MSAA per draw, then all elements are effectively AA'ed. Tracking them as such makes
343*c8dee2aaSAndroid Build Coastguard Worker     // keeps the entire stack as simple as possible.
344*c8dee2aaSAndroid Build Coastguard Worker     bool                     fForceAA;
345*c8dee2aaSAndroid Build Coastguard Worker };
346*c8dee2aaSAndroid Build Coastguard Worker 
347*c8dee2aaSAndroid Build Coastguard Worker // Clip element iteration
348*c8dee2aaSAndroid Build Coastguard Worker class ClipStack::ElementIter {
349*c8dee2aaSAndroid Build Coastguard Worker public:
350*c8dee2aaSAndroid Build Coastguard Worker     bool operator!=(const ElementIter& o) const {
351*c8dee2aaSAndroid Build Coastguard Worker         return o.fItem != fItem && o.fRemaining != fRemaining;
352*c8dee2aaSAndroid Build Coastguard Worker     }
353*c8dee2aaSAndroid Build Coastguard Worker 
354*c8dee2aaSAndroid Build Coastguard Worker     const Element& operator*() const { return (*fItem).asElement(); }
355*c8dee2aaSAndroid Build Coastguard Worker 
356*c8dee2aaSAndroid Build Coastguard Worker     ElementIter& operator++() {
357*c8dee2aaSAndroid Build Coastguard Worker         // Skip over invalidated elements
358*c8dee2aaSAndroid Build Coastguard Worker         do {
359*c8dee2aaSAndroid Build Coastguard Worker             fRemaining--;
360*c8dee2aaSAndroid Build Coastguard Worker             ++fItem;
361*c8dee2aaSAndroid Build Coastguard Worker         } while(fRemaining > 0 && (*fItem).isInvalid());
362*c8dee2aaSAndroid Build Coastguard Worker 
363*c8dee2aaSAndroid Build Coastguard Worker         return *this;
364*c8dee2aaSAndroid Build Coastguard Worker     }
365*c8dee2aaSAndroid Build Coastguard Worker 
ElementIter(RawElement::Stack::CRIter::Item item,int r)366*c8dee2aaSAndroid Build Coastguard Worker     ElementIter(RawElement::Stack::CRIter::Item item, int r) : fItem(item), fRemaining(r) {}
367*c8dee2aaSAndroid Build Coastguard Worker 
368*c8dee2aaSAndroid Build Coastguard Worker     RawElement::Stack::CRIter::Item fItem;
369*c8dee2aaSAndroid Build Coastguard Worker     int fRemaining;
370*c8dee2aaSAndroid Build Coastguard Worker 
371*c8dee2aaSAndroid Build Coastguard Worker     friend class ClipStack;
372*c8dee2aaSAndroid Build Coastguard Worker };
373*c8dee2aaSAndroid Build Coastguard Worker 
begin()374*c8dee2aaSAndroid Build Coastguard Worker ClipStack::ElementIter ClipStack::begin() const {
375*c8dee2aaSAndroid Build Coastguard Worker     if (this->currentSaveRecord().state() == ClipState::kEmpty ||
376*c8dee2aaSAndroid Build Coastguard Worker         this->currentSaveRecord().state() == ClipState::kWideOpen) {
377*c8dee2aaSAndroid Build Coastguard Worker         // No visible clip elements when empty or wide open
378*c8dee2aaSAndroid Build Coastguard Worker         return this->end();
379*c8dee2aaSAndroid Build Coastguard Worker     }
380*c8dee2aaSAndroid Build Coastguard Worker     int count = fElements.count() - this->currentSaveRecord().oldestElementIndex();
381*c8dee2aaSAndroid Build Coastguard Worker     return ElementIter(fElements.ritems().begin(), count);
382*c8dee2aaSAndroid Build Coastguard Worker }
383*c8dee2aaSAndroid Build Coastguard Worker 
end()384*c8dee2aaSAndroid Build Coastguard Worker ClipStack::ElementIter ClipStack::end() const {
385*c8dee2aaSAndroid Build Coastguard Worker     return ElementIter(fElements.ritems().end(), 0);
386*c8dee2aaSAndroid Build Coastguard Worker }
387*c8dee2aaSAndroid Build Coastguard Worker 
388*c8dee2aaSAndroid Build Coastguard Worker }  // namespace skgpu::ganesh
389*c8dee2aaSAndroid Build Coastguard Worker 
390*c8dee2aaSAndroid Build Coastguard Worker #endif // ClipStack_DEFINED
391