blob: e58528114e873f2caa78f807337cdbb30d46b7e1 [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;
cdalton846c0512016-05-13 10:25:00 -070016class GrPipelineBuilder;
joshualitt44701df2015-02-23 14:44:57 -080017
18/**
cdalton846c0512016-05-13 10:25:00 -070019 * Produced by GrClip. It provides a set of modifications to the drawing state that are used to
20 * create the final GrPipeline for a GrBatch.
joshualitt44701df2015-02-23 14:44:57 -080021 */
robertphillips5f2fa472016-05-19 11:36:25 -070022class GrAppliedClip : public SkNoncopyable {
joshualitt44701df2015-02-23 14:44:57 -080023public:
bsalomon6cc90062016-07-08 11:31:22 -070024 GrAppliedClip() : fHasStencilClip(false), fDeviceBounds(SkRect::MakeLargest()) {}
bungeman06ca8ec2016-06-09 08:01:03 -070025 GrFragmentProcessor* getClipCoverageFragmentProcessor() const {
robertphillips5f2fa472016-05-19 11:36:25 -070026 return fClipCoverageFP.get();
27 }
cdalton846c0512016-05-13 10:25:00 -070028 const GrScissorState& scissorState() const { return fScissorState; }
29 bool hasStencilClip() const { return fHasStencilClip; }
joshualitt44701df2015-02-23 14:44:57 -080030
bsalomon6cc90062016-07-08 11:31:22 -070031 void makeStencil(bool hasStencil, const SkRect& deviceBounds) {
robertphillips5f2fa472016-05-19 11:36:25 -070032 fClipCoverageFP = nullptr;
33 fScissorState.setDisabled();
34 fHasStencilClip = hasStencil;
bsalomon6cc90062016-07-08 11:31:22 -070035 fDeviceBounds = deviceBounds;
robertphillips5f2fa472016-05-19 11:36:25 -070036 }
joshualitt44701df2015-02-23 14:44:57 -080037
bsalomon6cc90062016-07-08 11:31:22 -070038 /**
39 * The device bounds of the clip defaults to the scissor rect, but a tighter bounds (based
40 * on the known effect of the stencil values) can be provided.
41 */
42 void makeScissoredStencil(const SkIRect& scissor, const SkRect* deviceBounds = nullptr) {
robertphillips5f2fa472016-05-19 11:36:25 -070043 fClipCoverageFP = nullptr;
44 fScissorState.set(scissor);
bsalomon6cc90062016-07-08 11:31:22 -070045 fHasStencilClip = true;
46 if (deviceBounds) {
47 fDeviceBounds = *deviceBounds;
48 SkASSERT(scissor.contains(*deviceBounds))
49 } else {
50 fDeviceBounds = SkRect::Make(scissor);
51 }
robertphillips5f2fa472016-05-19 11:36:25 -070052 }
53
bsalomon6cc90062016-07-08 11:31:22 -070054 void makeFPBased(sk_sp<GrFragmentProcessor> fp, const SkRect& deviceBounds) {
robertphillips5f2fa472016-05-19 11:36:25 -070055 fClipCoverageFP = fp;
56 fScissorState.setDisabled();
57 fHasStencilClip = false;
bsalomon6cc90062016-07-08 11:31:22 -070058 fDeviceBounds = deviceBounds;
robertphillips5f2fa472016-05-19 11:36:25 -070059 }
60
bsalomonbd2bbe42016-07-08 07:36:42 -070061 void makeScissored(SkIRect& scissor) {
62 fClipCoverageFP.reset();
63 fScissorState.set(scissor);
64 fHasStencilClip = false;
bsalomon6cc90062016-07-08 11:31:22 -070065 fDeviceBounds = SkRect::Make(scissor);
bsalomonbd2bbe42016-07-08 07:36:42 -070066 }
67
bsalomon6cc90062016-07-08 11:31:22 -070068 /**
69 * The device bounds of the clip defaults to the scissor rect, but a tighter bounds (based
70 * on the known effect of the fragment processor) can be provided.
71 */
72 void makeScissoredFPBased(sk_sp<GrFragmentProcessor> fp, const SkIRect& scissor,
73 const SkRect* deviceBounds = nullptr) {
robertphillips5f2fa472016-05-19 11:36:25 -070074 fClipCoverageFP = fp;
75 fScissorState.set(scissor);
76 fHasStencilClip = false;
bsalomon6cc90062016-07-08 11:31:22 -070077 if (deviceBounds) {
78 fDeviceBounds = *deviceBounds;
79 SkASSERT(scissor.contains(*deviceBounds))
80 } else {
81 fDeviceBounds = SkRect::Make(scissor);
82 }
robertphillips5f2fa472016-05-19 11:36:25 -070083 }
84
bsalomon6cc90062016-07-08 11:31:22 -070085 /**
86 * Returns the device bounds of the applied clip. Ideally this considers the combined effect of
87 * all clipping techniques in play (scissor, stencil, and/or coverage fp).
88 */
89 const SkRect& deviceBounds() const { return fDeviceBounds; }
90
robertphillips5f2fa472016-05-19 11:36:25 -070091private:
bungeman06ca8ec2016-06-09 08:01:03 -070092 sk_sp<GrFragmentProcessor> fClipCoverageFP;
93 GrScissorState fScissorState;
94 bool fHasStencilClip;
bsalomon6cc90062016-07-08 11:31:22 -070095 SkRect fDeviceBounds;
cdalton846c0512016-05-13 10:25:00 -070096 typedef SkNoncopyable INHERITED;
97};
98
99/**
100 * GrClip is an abstract base class for applying a clip. It constructs a clip mask if necessary, and
101 * fills out a GrAppliedClip instructing the caller on how to set up the draw state.
102 */
103class GrClip {
104public:
105 virtual bool quickContains(const SkRect&) const = 0;
106 virtual void getConservativeBounds(int width, int height, SkIRect* devResult,
107 bool* isIntersectionOfRects = nullptr) const = 0;
robertphillips976f5f02016-06-03 10:59:20 -0700108 virtual bool apply(GrContext*, const GrPipelineBuilder&, GrDrawContext*,
109 const SkRect* devBounds, GrAppliedClip*) const = 0;
cdalton846c0512016-05-13 10:25:00 -0700110
111 virtual ~GrClip() {}
112};
113
114/**
115 * Specialized implementation for no clip.
116 */
117class GrNoClip final : public GrClip {
118private:
119 bool quickContains(const SkRect&) const final { return true; }
120 void getConservativeBounds(int width, int height, SkIRect* devResult,
121 bool* isIntersectionOfRects) const final;
robertphillips976f5f02016-06-03 10:59:20 -0700122 bool apply(GrContext*, const GrPipelineBuilder&, GrDrawContext*,
cdalton846c0512016-05-13 10:25:00 -0700123 const SkRect*, GrAppliedClip*) const final { return true; }
124};
125
126/**
127 * GrFixedClip is a clip that can be represented by fixed-function hardware. It never modifies the
128 * stencil buffer itself, but can be configured to use whatever clip is already there.
129 */
130class GrFixedClip final : public GrClip {
131public:
bsalomon6cc90062016-07-08 11:31:22 -0700132 GrFixedClip() : fDeviceBounds(SkRect::MakeLargest()), fHasStencilClip(false) {}
133 GrFixedClip(const SkIRect& scissorRect)
134 : fScissorState(scissorRect)
135 , fDeviceBounds(SkRect::Make(scissorRect))
136 , fHasStencilClip(false) {}
cdalton846c0512016-05-13 10:25:00 -0700137
138 void reset() {
139 fScissorState.setDisabled();
bsalomon6cc90062016-07-08 11:31:22 -0700140 fDeviceBounds.setLargest();
cdalton846c0512016-05-13 10:25:00 -0700141 fHasStencilClip = false;
142 }
143
144 void reset(const SkIRect& scissorRect) {
145 fScissorState.set(scissorRect);
bsalomon6cc90062016-07-08 11:31:22 -0700146 fDeviceBounds = SkRect::Make(scissorRect);
cdalton846c0512016-05-13 10:25:00 -0700147 fHasStencilClip = false;
148 }
149
bsalomon6cc90062016-07-08 11:31:22 -0700150 /**
151 * Enables stenciling. The stencil bounds is the device space bounds where the stencil test
152 * may pass.
153 */
154 void enableStencilClip(const SkRect& stencilBounds) {
155 fHasStencilClip = true;
156 fDeviceBounds = stencilBounds;
157 if (fScissorState.enabled()) {
158 const SkIRect& s = fScissorState.rect();
159 fDeviceBounds.fLeft = SkTMax(fDeviceBounds.fLeft, SkIntToScalar(s.fLeft));
160 fDeviceBounds.fTop = SkTMax(fDeviceBounds.fTop, SkIntToScalar(s.fTop));
161 fDeviceBounds.fRight = SkTMin(fDeviceBounds.fRight, SkIntToScalar(s.fRight));
162 fDeviceBounds.fBottom = SkTMin(fDeviceBounds.fBottom, SkIntToScalar(s.fBottom));
163 }
164 }
165
166 void disableStencilClip() {
167 fHasStencilClip = false;
168 if (fScissorState.enabled()) {
169 fDeviceBounds = SkRect::Make(fScissorState.rect());
170 } else {
171 fDeviceBounds.setLargest();
172 }
173 }
cdalton846c0512016-05-13 10:25:00 -0700174
175 const GrScissorState& scissorState() const { return fScissorState; }
176 bool hasStencilClip() const { return fHasStencilClip; }
177
178 bool quickContains(const SkRect&) const final;
179 void getConservativeBounds(int width, int height, SkIRect* devResult,
180 bool* isIntersectionOfRects) const final;
181
182private:
robertphillips976f5f02016-06-03 10:59:20 -0700183 bool apply(GrContext*, const GrPipelineBuilder&, GrDrawContext*,
cdalton846c0512016-05-13 10:25:00 -0700184 const SkRect* devBounds, GrAppliedClip* out) const final;
185
186 GrScissorState fScissorState;
bsalomon6cc90062016-07-08 11:31:22 -0700187 SkRect fDeviceBounds;
cdalton846c0512016-05-13 10:25:00 -0700188 bool fHasStencilClip;
189};
190
191/**
192 * GrClipStackClip can apply a generic SkClipStack to the draw state. It may generate clip masks or
193 * write to the stencil buffer during apply().
194 */
195class GrClipStackClip final : public GrClip {
196public:
197 GrClipStackClip(const SkClipStack* stack = nullptr, const SkIPoint* origin = nullptr) {
198 this->reset(stack, origin);
199 }
200
201 void reset(const SkClipStack* stack = nullptr, const SkIPoint* origin = nullptr) {
202 fOrigin = origin ? *origin : SkIPoint::Make(0, 0);
203 fStack.reset(SkSafeRef(stack));
204 }
205
206 const SkIPoint& origin() const { return fOrigin; }
207 const SkClipStack* clipStack() const { return fStack; }
208
209 bool quickContains(const SkRect&) const final;
210 void getConservativeBounds(int width, int height, SkIRect* devResult,
211 bool* isIntersectionOfRects) const final;
robertphillips976f5f02016-06-03 10:59:20 -0700212 bool apply(GrContext*, const GrPipelineBuilder&, GrDrawContext*,
cdalton846c0512016-05-13 10:25:00 -0700213 const SkRect* devBounds, GrAppliedClip*) const final;
214
215private:
216 SkIPoint fOrigin;
217 SkAutoTUnref<const SkClipStack> fStack;
joshualitt44701df2015-02-23 14:44:57 -0800218};
219
220#endif