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