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 #ifndef GrReducedClip_DEFINED
9 #define GrReducedClip_DEFINED
10 
11 #include "src/core/SkClipStack.h"
12 #include "src/core/SkTLList.h"
13 #include "src/gpu/GrFragmentProcessor.h"
14 #include "src/gpu/GrWindowRectangles.h"
15 
16 class GrCoverageCountingPathRenderer;
17 class GrRecordingContext;
18 class GrRenderTargetContext;
19 
20 /**
21  * This class takes a clip stack and produces a reduced set of elements that are equivalent to
22  * applying that full stack within a specified query rectangle.
23  */
24 class GrReducedClip {
25 public:
26     using Element = SkClipStack::Element;
27     using ElementList = SkTLList<SkClipStack::Element, 16>;
28 
29     GrReducedClip(const SkClipStack&, const SkRect& queryBounds, const GrCaps* caps,
30                   int maxWindowRectangles = 0, int maxAnalyticElements = 0,
31                   int maxCCPRClipPaths = 0);
32 
33     enum class InitialState : bool {
34         kAllIn,
35         kAllOut
36     };
37 
initialState()38     InitialState initialState() const { return fInitialState; }
39 
40     /**
41      * If hasScissor() is true, the clip mask is not valid outside this rect and the caller must
42      * enforce this scissor during draw.
43      */
scissor()44     const SkIRect& scissor() const { SkASSERT(fHasScissor); return fScissor; }
left()45     int left() const { return this->scissor().left(); }
top()46     int top() const { return this->scissor().top(); }
width()47     int width() const { return this->scissor().width(); }
height()48     int height() const { return this->scissor().height(); }
49 
50     /**
51      * Indicates whether scissor() is defined. It will always be defined if the maskElements() are
52      * nonempty.
53      */
hasScissor()54     bool hasScissor() const { return fHasScissor; }
55 
56     /**
57      * Indicates if there is a clip shader, representing the merge of all shader elements of the
58      * original stack.
59      */
hasShader()60     bool hasShader() const { return SkToBool(fShader); }
shader()61     sk_sp<SkShader> shader() const { SkASSERT(fShader); return fShader; }
62 
63     /**
64      * If nonempty, the clip mask is not valid inside these windows and the caller must clip them
65      * out using the window rectangles GPU extension.
66      */
windowRectangles()67     const GrWindowRectangles& windowRectangles() const { return fWindowRects; }
68 
69     /**
70      * An ordered list of clip elements that could not be skipped or implemented by other means. If
71      * nonempty, the caller must create an alpha and/or stencil mask for these elements and apply it
72      * during draw.
73      */
maskElements()74     const ElementList& maskElements() const { return fMaskElements; }
75 
76     /**
77      * If maskElements() are nonempty, uniquely identifies the region of the clip mask that falls
78      * inside of scissor().
79      *
80      * NOTE: since clip elements might fall outside the query bounds, different regions of the same
81      * clip stack might have more or less restrictive IDs.
82      *
83      * FIXME: this prevents us from reusing a sub-rect of a perfectly good mask when that rect has
84      * been assigned a less restrictive ID.
85      */
maskGenID()86     uint32_t maskGenID() const { SkASSERT(!fMaskElements.isEmpty()); return fMaskGenID; }
87 
88     /**
89      * Indicates whether antialiasing is required to process any of the mask elements.
90      */
maskRequiresAA()91     bool maskRequiresAA() const { SkASSERT(!fMaskElements.isEmpty()); return fMaskRequiresAA; }
92 
93     bool drawAlphaClipMask(GrRenderTargetContext*) const;
94     bool drawStencilClipMask(GrRecordingContext*, GrRenderTargetContext*) const;
95 
96     int numAnalyticElements() const;
97 
98     /**
99      * Called once the client knows the ID of the opsTask that the clip FPs will operate in. This
100      * method finishes any outstanding work that was waiting for the opsTask ID, then detaches and
101      * returns this class's list of FPs that complete the clip.
102      *
103      * NOTE: this must be called AFTER producing the clip mask (if any) because draw calls on
104      * the render target context, surface allocations, and even switching render targets (pre MDB)
105      * may cause flushes or otherwise change which opsTask the actual draw is going into.
106      */
107     std::unique_ptr<GrFragmentProcessor> finishAndDetachAnalyticElements(
108             GrRecordingContext*, const SkMatrixProvider& matrixProvider,
109             GrCoverageCountingPathRenderer*, uint32_t opsTaskID);
110 
111 private:
112     void walkStack(const SkClipStack&, const SkRect& queryBounds);
113 
114     enum class ClipResult {
115         kNotClipped,
116         kClipped,
117         kMadeEmpty
118     };
119 
120     // Intersects the clip with the element's interior, regardless of inverse fill type.
121     // NOTE: do not call for elements followed by ops that can grow the clip.
122     ClipResult clipInsideElement(const Element*);
123 
124     // Intersects the clip with the element's exterior, regardless of inverse fill type.
125     // NOTE: do not call for elements followed by ops that can grow the clip.
126     ClipResult clipOutsideElement(const Element*);
127 
128     void addWindowRectangle(const SkRect& elementInteriorRect, bool elementIsAA);
129 
130     enum class Invert : bool {
131         kNo = false,
132         kYes = true
133     };
134 
135     static GrClipEdgeType GetClipEdgeType(Invert, GrAA);
136     ClipResult addAnalyticRect(const SkRect& deviceSpaceRect, Invert, GrAA);
137     ClipResult addAnalyticRRect(const SkRRect& deviceSpaceRRect, Invert, GrAA);
138     ClipResult addAnalyticPath(const SkPath& deviceSpacePath, Invert, GrAA);
139 
140     void makeEmpty();
141 
142     const GrCaps* fCaps;
143     const int fMaxWindowRectangles;
144     const int fMaxAnalyticElements;
145     const int fMaxCCPRClipPaths;
146 
147     InitialState fInitialState;
148     SkIRect fScissor;
149     bool fHasScissor = false;
150     SkRect fAAClipRect;
151     uint32_t fAAClipRectGenID = SK_InvalidGenID;  // the GenID that the mask will have if the AA
152                                                   // clip-rect is included
153     GrWindowRectangles fWindowRects;
154     ElementList fMaskElements;
155     uint32_t fMaskGenID = SK_InvalidGenID;
156     bool fMaskRequiresAA = false;
157     std::unique_ptr<GrFragmentProcessor> fAnalyticFP;
158     int fNumAnalyticElements = 0;
159     SkSTArray<4, SkPath> fCCPRClipPaths; // Converted to FPs once we have an opsTask ID for CCPR.
160     // Will be the combination of all kShader elements or null if there's no clip shader.
161     // Does not count against the analytic FP limit.
162     sk_sp<SkShader> fShader;
163 };
164 
165 #endif
166