blob: ab83441f41e28692aca17183ceae27528fb89699 [file] [log] [blame]
joshualitt44701df2015-02-23 14:44:57 -08001/*
2 * Copyright 2010 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 GrClip_DEFINED
9#define GrClip_DEFINED
10
cdalton846c0512016-05-13 10:25:00 -070011#include "GrFragmentProcessor.h"
12#include "GrTypesPriv.h"
joshualitt44701df2015-02-23 14:44:57 -080013#include "SkClipStack.h"
joshualitt44701df2015-02-23 14:44:57 -080014
robertphillips976f5f02016-06-03 10:59:20 -070015class GrDrawContext;
joshualitt44701df2015-02-23 14:44:57 -080016
17/**
cdalton846c0512016-05-13 10:25:00 -070018 * Produced by GrClip. It provides a set of modifications to the drawing state that are used to
19 * create the final GrPipeline for a GrBatch.
joshualitt44701df2015-02-23 14:44:57 -080020 */
robertphillips5f2fa472016-05-19 11:36:25 -070021class GrAppliedClip : public SkNoncopyable {
joshualitt44701df2015-02-23 14:44:57 -080022public:
bsalomon6cc90062016-07-08 11:31:22 -070023 GrAppliedClip() : fHasStencilClip(false), fDeviceBounds(SkRect::MakeLargest()) {}
bungeman06ca8ec2016-06-09 08:01:03 -070024 GrFragmentProcessor* getClipCoverageFragmentProcessor() const {
robertphillips5f2fa472016-05-19 11:36:25 -070025 return fClipCoverageFP.get();
26 }
cdalton846c0512016-05-13 10:25:00 -070027 const GrScissorState& scissorState() const { return fScissorState; }
28 bool hasStencilClip() const { return fHasStencilClip; }
joshualitt44701df2015-02-23 14:44:57 -080029
bsalomon6cc90062016-07-08 11:31:22 -070030 void makeStencil(bool hasStencil, const SkRect& deviceBounds) {
robertphillips5f2fa472016-05-19 11:36:25 -070031 fClipCoverageFP = nullptr;
32 fScissorState.setDisabled();
33 fHasStencilClip = hasStencil;
bsalomon6cc90062016-07-08 11:31:22 -070034 fDeviceBounds = deviceBounds;
robertphillips5f2fa472016-05-19 11:36:25 -070035 }
joshualitt44701df2015-02-23 14:44:57 -080036
bsalomon6cc90062016-07-08 11:31:22 -070037 /**
38 * The device bounds of the clip defaults to the scissor rect, but a tighter bounds (based
39 * on the known effect of the stencil values) can be provided.
40 */
41 void makeScissoredStencil(const SkIRect& scissor, const SkRect* deviceBounds = nullptr) {
robertphillips5f2fa472016-05-19 11:36:25 -070042 fClipCoverageFP = nullptr;
43 fScissorState.set(scissor);
bsalomon6cc90062016-07-08 11:31:22 -070044 fHasStencilClip = true;
45 if (deviceBounds) {
46 fDeviceBounds = *deviceBounds;
47 SkASSERT(scissor.contains(*deviceBounds))
48 } else {
49 fDeviceBounds = SkRect::Make(scissor);
50 }
robertphillips5f2fa472016-05-19 11:36:25 -070051 }
52
bsalomon6cc90062016-07-08 11:31:22 -070053 void makeFPBased(sk_sp<GrFragmentProcessor> fp, const SkRect& deviceBounds) {
robertphillips5f2fa472016-05-19 11:36:25 -070054 fClipCoverageFP = fp;
55 fScissorState.setDisabled();
56 fHasStencilClip = false;
bsalomon6cc90062016-07-08 11:31:22 -070057 fDeviceBounds = deviceBounds;
robertphillips5f2fa472016-05-19 11:36:25 -070058 }
59
bsalomonbd2bbe42016-07-08 07:36:42 -070060 void makeScissored(SkIRect& scissor) {
61 fClipCoverageFP.reset();
62 fScissorState.set(scissor);
63 fHasStencilClip = false;
bsalomon6cc90062016-07-08 11:31:22 -070064 fDeviceBounds = SkRect::Make(scissor);
bsalomonbd2bbe42016-07-08 07:36:42 -070065 }
66
bsalomon6cc90062016-07-08 11:31:22 -070067 /**
68 * The device bounds of the clip defaults to the scissor rect, but a tighter bounds (based
69 * on the known effect of the fragment processor) can be provided.
70 */
71 void makeScissoredFPBased(sk_sp<GrFragmentProcessor> fp, const SkIRect& scissor,
72 const SkRect* deviceBounds = nullptr) {
robertphillips5f2fa472016-05-19 11:36:25 -070073 fClipCoverageFP = fp;
74 fScissorState.set(scissor);
75 fHasStencilClip = false;
bsalomon6cc90062016-07-08 11:31:22 -070076 if (deviceBounds) {
77 fDeviceBounds = *deviceBounds;
78 SkASSERT(scissor.contains(*deviceBounds))
79 } else {
80 fDeviceBounds = SkRect::Make(scissor);
81 }
robertphillips5f2fa472016-05-19 11:36:25 -070082 }
83
bsalomon6cc90062016-07-08 11:31:22 -070084 /**
85 * Returns the device bounds of the applied clip. Ideally this considers the combined effect of
86 * all clipping techniques in play (scissor, stencil, and/or coverage fp).
87 */
88 const SkRect& deviceBounds() const { return fDeviceBounds; }
89
robertphillips5f2fa472016-05-19 11:36:25 -070090private:
bungeman06ca8ec2016-06-09 08:01:03 -070091 sk_sp<GrFragmentProcessor> fClipCoverageFP;
92 GrScissorState fScissorState;
93 bool fHasStencilClip;
bsalomon6cc90062016-07-08 11:31:22 -070094 SkRect fDeviceBounds;
cdalton846c0512016-05-13 10:25:00 -070095 typedef SkNoncopyable INHERITED;
96};
97
98/**
99 * GrClip is an abstract base class for applying a clip. It constructs a clip mask if necessary, and
100 * fills out a GrAppliedClip instructing the caller on how to set up the draw state.
101 */
102class GrClip {
103public:
104 virtual bool quickContains(const SkRect&) const = 0;
105 virtual void getConservativeBounds(int width, int height, SkIRect* devResult,
106 bool* isIntersectionOfRects = nullptr) const = 0;
robertphillips59cf61a2016-07-13 09:18:21 -0700107 virtual bool apply(GrContext*,
108 GrDrawContext*,
109 const SkRect* devBounds,
110 bool useHWAA,
111 bool hasUserStencilSettings,
112 GrAppliedClip* out) const = 0;
cdalton846c0512016-05-13 10:25:00 -0700113
114 virtual ~GrClip() {}
csmartdalton97f6cd52016-07-13 13:37:08 -0700115
116protected:
117 /**
118 * Returns true if a clip can safely disable its scissor test for a particular draw.
119 */
120 static bool CanIgnoreScissor(const SkIRect& scissorRect, const SkRect& drawBounds) {
121 // This is the maximum distance that a draw may extend beyond a clip's scissor and still
122 // count as inside. We use a sloppy compare because the draw may have chosen its bounds in a
123 // different coord system. The rationale for 1e-3 is that in the coverage case (and barring
124 // unexpected rounding), as long as coverage stays below 0.5 * 1/256 we ought to be OK.
125 constexpr SkScalar fuzz = 1e-3f;
126 SkASSERT(!scissorRect.isEmpty());
127 SkASSERT(!drawBounds.isEmpty());
128 return scissorRect.fLeft <= drawBounds.fLeft + fuzz &&
129 scissorRect.fTop <= drawBounds.fTop + fuzz &&
130 scissorRect.fRight >= drawBounds.fRight - fuzz &&
131 scissorRect.fBottom >= drawBounds.fBottom - fuzz;
132 }
133
134 friend class GrClipMaskManager;
cdalton846c0512016-05-13 10:25:00 -0700135};
136
137/**
138 * Specialized implementation for no clip.
139 */
140class GrNoClip final : public GrClip {
141private:
142 bool quickContains(const SkRect&) const final { return true; }
143 void getConservativeBounds(int width, int height, SkIRect* devResult,
144 bool* isIntersectionOfRects) const final;
robertphillips59cf61a2016-07-13 09:18:21 -0700145 bool apply(GrContext*,
146 GrDrawContext*,
147 const SkRect* /* devBounds */,
148 bool /* useHWAA */,
149 bool /* hasUserStencilSettings */,
150 GrAppliedClip* /* out */) const final { return true; }
cdalton846c0512016-05-13 10:25:00 -0700151};
152
153/**
154 * GrFixedClip is a clip that can be represented by fixed-function hardware. It never modifies the
155 * stencil buffer itself, but can be configured to use whatever clip is already there.
156 */
157class GrFixedClip final : public GrClip {
158public:
bsalomon6cc90062016-07-08 11:31:22 -0700159 GrFixedClip() : fDeviceBounds(SkRect::MakeLargest()), fHasStencilClip(false) {}
160 GrFixedClip(const SkIRect& scissorRect)
161 : fScissorState(scissorRect)
162 , fDeviceBounds(SkRect::Make(scissorRect))
163 , fHasStencilClip(false) {}
cdalton846c0512016-05-13 10:25:00 -0700164
165 void reset() {
166 fScissorState.setDisabled();
bsalomon6cc90062016-07-08 11:31:22 -0700167 fDeviceBounds.setLargest();
cdalton846c0512016-05-13 10:25:00 -0700168 fHasStencilClip = false;
169 }
170
171 void reset(const SkIRect& scissorRect) {
172 fScissorState.set(scissorRect);
bsalomon6cc90062016-07-08 11:31:22 -0700173 fDeviceBounds = SkRect::Make(scissorRect);
cdalton846c0512016-05-13 10:25:00 -0700174 fHasStencilClip = false;
175 }
176
bsalomon6cc90062016-07-08 11:31:22 -0700177 /**
178 * Enables stenciling. The stencil bounds is the device space bounds where the stencil test
179 * may pass.
180 */
181 void enableStencilClip(const SkRect& stencilBounds) {
182 fHasStencilClip = true;
183 fDeviceBounds = stencilBounds;
184 if (fScissorState.enabled()) {
185 const SkIRect& s = fScissorState.rect();
186 fDeviceBounds.fLeft = SkTMax(fDeviceBounds.fLeft, SkIntToScalar(s.fLeft));
187 fDeviceBounds.fTop = SkTMax(fDeviceBounds.fTop, SkIntToScalar(s.fTop));
188 fDeviceBounds.fRight = SkTMin(fDeviceBounds.fRight, SkIntToScalar(s.fRight));
189 fDeviceBounds.fBottom = SkTMin(fDeviceBounds.fBottom, SkIntToScalar(s.fBottom));
190 }
191 }
192
193 void disableStencilClip() {
194 fHasStencilClip = false;
195 if (fScissorState.enabled()) {
196 fDeviceBounds = SkRect::Make(fScissorState.rect());
197 } else {
198 fDeviceBounds.setLargest();
199 }
200 }
cdalton846c0512016-05-13 10:25:00 -0700201
202 const GrScissorState& scissorState() const { return fScissorState; }
203 bool hasStencilClip() const { return fHasStencilClip; }
204
205 bool quickContains(const SkRect&) const final;
206 void getConservativeBounds(int width, int height, SkIRect* devResult,
207 bool* isIntersectionOfRects) const final;
208
209private:
robertphillips59cf61a2016-07-13 09:18:21 -0700210 bool apply(GrContext*,
211 GrDrawContext*,
212 const SkRect* devBounds,
213 bool useHWAA,
214 bool hasUserStencilSettings,
215 GrAppliedClip* out) const final;
cdalton846c0512016-05-13 10:25:00 -0700216
217 GrScissorState fScissorState;
bsalomon6cc90062016-07-08 11:31:22 -0700218 SkRect fDeviceBounds;
cdalton846c0512016-05-13 10:25:00 -0700219 bool fHasStencilClip;
220};
221
222/**
223 * GrClipStackClip can apply a generic SkClipStack to the draw state. It may generate clip masks or
224 * write to the stencil buffer during apply().
225 */
226class GrClipStackClip final : public GrClip {
227public:
228 GrClipStackClip(const SkClipStack* stack = nullptr, const SkIPoint* origin = nullptr) {
229 this->reset(stack, origin);
230 }
231
232 void reset(const SkClipStack* stack = nullptr, const SkIPoint* origin = nullptr) {
233 fOrigin = origin ? *origin : SkIPoint::Make(0, 0);
234 fStack.reset(SkSafeRef(stack));
235 }
236
237 const SkIPoint& origin() const { return fOrigin; }
238 const SkClipStack* clipStack() const { return fStack; }
239
240 bool quickContains(const SkRect&) const final;
241 void getConservativeBounds(int width, int height, SkIRect* devResult,
242 bool* isIntersectionOfRects) const final;
robertphillips59cf61a2016-07-13 09:18:21 -0700243 bool apply(GrContext*,
244 GrDrawContext*,
245 const SkRect* devBounds,
246 bool useHWAA,
247 bool hasUserStencilSettings,
248 GrAppliedClip* out) const final;
cdalton846c0512016-05-13 10:25:00 -0700249
250private:
251 SkIPoint fOrigin;
252 SkAutoTUnref<const SkClipStack> fStack;
joshualitt44701df2015-02-23 14:44:57 -0800253};
254
255#endif