blob: b177d6fda38d3018d0f7c91cb87064fad2df6954 [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() {}
115};
116
117/**
118 * Specialized implementation for no clip.
119 */
120class GrNoClip final : public GrClip {
121private:
122 bool quickContains(const SkRect&) const final { return true; }
123 void getConservativeBounds(int width, int height, SkIRect* devResult,
124 bool* isIntersectionOfRects) const final;
robertphillips59cf61a2016-07-13 09:18:21 -0700125 bool apply(GrContext*,
126 GrDrawContext*,
127 const SkRect* /* devBounds */,
128 bool /* useHWAA */,
129 bool /* hasUserStencilSettings */,
130 GrAppliedClip* /* out */) const final { return true; }
cdalton846c0512016-05-13 10:25:00 -0700131};
132
133/**
134 * GrFixedClip is a clip that can be represented by fixed-function hardware. It never modifies the
135 * stencil buffer itself, but can be configured to use whatever clip is already there.
136 */
137class GrFixedClip final : public GrClip {
138public:
bsalomon6cc90062016-07-08 11:31:22 -0700139 GrFixedClip() : fDeviceBounds(SkRect::MakeLargest()), fHasStencilClip(false) {}
140 GrFixedClip(const SkIRect& scissorRect)
141 : fScissorState(scissorRect)
142 , fDeviceBounds(SkRect::Make(scissorRect))
143 , fHasStencilClip(false) {}
cdalton846c0512016-05-13 10:25:00 -0700144
145 void reset() {
146 fScissorState.setDisabled();
bsalomon6cc90062016-07-08 11:31:22 -0700147 fDeviceBounds.setLargest();
cdalton846c0512016-05-13 10:25:00 -0700148 fHasStencilClip = false;
149 }
150
151 void reset(const SkIRect& scissorRect) {
152 fScissorState.set(scissorRect);
bsalomon6cc90062016-07-08 11:31:22 -0700153 fDeviceBounds = SkRect::Make(scissorRect);
cdalton846c0512016-05-13 10:25:00 -0700154 fHasStencilClip = false;
155 }
156
bsalomon6cc90062016-07-08 11:31:22 -0700157 /**
158 * Enables stenciling. The stencil bounds is the device space bounds where the stencil test
159 * may pass.
160 */
161 void enableStencilClip(const SkRect& stencilBounds) {
162 fHasStencilClip = true;
163 fDeviceBounds = stencilBounds;
164 if (fScissorState.enabled()) {
165 const SkIRect& s = fScissorState.rect();
166 fDeviceBounds.fLeft = SkTMax(fDeviceBounds.fLeft, SkIntToScalar(s.fLeft));
167 fDeviceBounds.fTop = SkTMax(fDeviceBounds.fTop, SkIntToScalar(s.fTop));
168 fDeviceBounds.fRight = SkTMin(fDeviceBounds.fRight, SkIntToScalar(s.fRight));
169 fDeviceBounds.fBottom = SkTMin(fDeviceBounds.fBottom, SkIntToScalar(s.fBottom));
170 }
171 }
172
173 void disableStencilClip() {
174 fHasStencilClip = false;
175 if (fScissorState.enabled()) {
176 fDeviceBounds = SkRect::Make(fScissorState.rect());
177 } else {
178 fDeviceBounds.setLargest();
179 }
180 }
cdalton846c0512016-05-13 10:25:00 -0700181
182 const GrScissorState& scissorState() const { return fScissorState; }
183 bool hasStencilClip() const { return fHasStencilClip; }
184
185 bool quickContains(const SkRect&) const final;
186 void getConservativeBounds(int width, int height, SkIRect* devResult,
187 bool* isIntersectionOfRects) const final;
188
189private:
robertphillips59cf61a2016-07-13 09:18:21 -0700190 bool apply(GrContext*,
191 GrDrawContext*,
192 const SkRect* devBounds,
193 bool useHWAA,
194 bool hasUserStencilSettings,
195 GrAppliedClip* out) const final;
cdalton846c0512016-05-13 10:25:00 -0700196
197 GrScissorState fScissorState;
bsalomon6cc90062016-07-08 11:31:22 -0700198 SkRect fDeviceBounds;
cdalton846c0512016-05-13 10:25:00 -0700199 bool fHasStencilClip;
200};
201
202/**
203 * GrClipStackClip can apply a generic SkClipStack to the draw state. It may generate clip masks or
204 * write to the stencil buffer during apply().
205 */
206class GrClipStackClip final : public GrClip {
207public:
208 GrClipStackClip(const SkClipStack* stack = nullptr, const SkIPoint* origin = nullptr) {
209 this->reset(stack, origin);
210 }
211
212 void reset(const SkClipStack* stack = nullptr, const SkIPoint* origin = nullptr) {
213 fOrigin = origin ? *origin : SkIPoint::Make(0, 0);
214 fStack.reset(SkSafeRef(stack));
215 }
216
217 const SkIPoint& origin() const { return fOrigin; }
218 const SkClipStack* clipStack() const { return fStack; }
219
220 bool quickContains(const SkRect&) const final;
221 void getConservativeBounds(int width, int height, SkIRect* devResult,
222 bool* isIntersectionOfRects) const final;
robertphillips59cf61a2016-07-13 09:18:21 -0700223 bool apply(GrContext*,
224 GrDrawContext*,
225 const SkRect* devBounds,
226 bool useHWAA,
227 bool hasUserStencilSettings,
228 GrAppliedClip* out) const final;
cdalton846c0512016-05-13 10:25:00 -0700229
230private:
231 SkIPoint fOrigin;
232 SkAutoTUnref<const SkClipStack> fStack;
joshualitt44701df2015-02-23 14:44:57 -0800233};
234
235#endif