blob: fed4205653471e9f17f28562aeb1785de7edb4bf [file] [log] [blame]
robertphillips@google.com1e945b72012-04-16 18:03:03 +00001
2/*
3 * Copyright 2012 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#ifndef GrClipMaskManager_DEFINED
10#define GrClipMaskManager_DEFINED
11
robertphillips@google.comf105b102012-05-14 12:18:26 +000012#include "GrContext.h"
bsalomon@google.com411dad02012-06-05 20:24:20 +000013#include "GrNoncopyable.h"
14#include "GrRect.h"
15#include "GrStencil.h"
16#include "GrTexture.h"
17
robertphillips@google.com641f8b12012-07-31 19:15:58 +000018#include "SkClipStack.h"
bsalomon@google.com411dad02012-06-05 20:24:20 +000019#include "SkDeque.h"
20#include "SkPath.h"
21#include "SkRefCnt.h"
robertphillips@google.com1e945b72012-04-16 18:03:03 +000022
23class GrGpu;
robertphillips@google.com1e945b72012-04-16 18:03:03 +000024class GrPathRenderer;
25class GrPathRendererChain;
26class SkPath;
robertphillips@google.comf294b772012-04-27 14:29:26 +000027class GrTexture;
28class GrDrawState;
robertphillips@google.com1e945b72012-04-16 18:03:03 +000029
30/**
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000031 * The stencil buffer stores the last clip path - providing a single entry
32 * "cache". This class provides similar functionality for AA clip paths
33 */
34class GrClipMaskCache : public GrNoncopyable {
35public:
robertphillips@google.comf8d904a2012-07-31 12:18:16 +000036 GrClipMaskCache();
robertphillips@google.com6d62df42012-05-07 18:07:36 +000037
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000038 ~GrClipMaskCache() {
39
40 while (!fStack.empty()) {
41 GrClipStackFrame* temp = (GrClipStackFrame*) fStack.back();
42 temp->~GrClipStackFrame();
43 fStack.pop_back();
44 }
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000045 }
46
robertphillips@google.com641f8b12012-07-31 19:15:58 +000047 bool canReuse(const SkClipStack& clip, int width, int height) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000048
49 if (fStack.empty()) {
50 GrAssert(false);
51 return false;
52 }
53
54 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
55
robertphillips@google.comf105b102012-05-14 12:18:26 +000056 if (back->fLastMask.texture() &&
57 back->fLastMask.texture()->width() >= width &&
58 back->fLastMask.texture()->height() >= height &&
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000059 clip == back->fLastClip) {
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000060 return true;
61 }
62
63 return false;
64 }
65
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000066 void reset() {
67 if (fStack.empty()) {
robertphillips@google.com87baf892012-05-23 12:02:21 +000068// GrAssert(false);
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000069 return;
70 }
71
72 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
73
74 back->reset();
75 }
76
77 /**
78 * After a "push" the clip state is entirely open. Currently, the
79 * entire clip stack will be re-rendered into a new clip mask.
80 * TODO: can we take advantage of the nested nature of the clips to
81 * reduce the mask creation cost?
82 */
robertphillips@google.comf8d904a2012-07-31 12:18:16 +000083 void push();
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000084
85 void pop() {
robertphillips@google.com87baf892012-05-23 12:02:21 +000086 //GrAssert(!fStack.empty());
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000087
88 if (!fStack.empty()) {
89 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
90
91 back->~GrClipStackFrame();
92 fStack.pop_back();
93 }
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000094 }
95
robertphillips@google.com641f8b12012-07-31 19:15:58 +000096 void getLastClip(SkClipStack* clip) const {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000097
98 if (fStack.empty()) {
99 GrAssert(false);
robertphillips@google.com641f8b12012-07-31 19:15:58 +0000100 clip->reset();
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000101 return;
102 }
103
104 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
105
106 *clip = back->fLastClip;
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000107 }
108
109 GrTexture* getLastMask() {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000110
111 if (fStack.empty()) {
112 GrAssert(false);
113 return NULL;
114 }
115
116 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
117
robertphillips@google.comf105b102012-05-14 12:18:26 +0000118 return back->fLastMask.texture();
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000119 }
120
121 const GrTexture* getLastMask() const {
122
123 if (fStack.empty()) {
124 GrAssert(false);
125 return NULL;
126 }
127
128 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
129
robertphillips@google.comf105b102012-05-14 12:18:26 +0000130 return back->fLastMask.texture();
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000131 }
132
robertphillips@google.com641f8b12012-07-31 19:15:58 +0000133 void acquireMask(const SkClipStack& clip,
robertphillips@google.comf105b102012-05-14 12:18:26 +0000134 const GrTextureDesc& desc,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000135 const GrIRect& bound) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000136
137 if (fStack.empty()) {
138 GrAssert(false);
robertphillips@google.comf105b102012-05-14 12:18:26 +0000139 return;
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000140 }
141
142 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
143
robertphillips@google.comf105b102012-05-14 12:18:26 +0000144 back->acquireMask(fContext, clip, desc, bound);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000145 }
146
147 int getLastMaskWidth() const {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000148
149 if (fStack.empty()) {
150 GrAssert(false);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000151 return -1;
152 }
153
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000154 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
155
robertphillips@google.comf105b102012-05-14 12:18:26 +0000156 if (NULL == back->fLastMask.texture()) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000157 return -1;
158 }
159
robertphillips@google.comf105b102012-05-14 12:18:26 +0000160 return back->fLastMask.texture()->width();
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000161 }
162
163 int getLastMaskHeight() const {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000164
165 if (fStack.empty()) {
166 GrAssert(false);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000167 return -1;
168 }
169
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000170 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
171
robertphillips@google.comf105b102012-05-14 12:18:26 +0000172 if (NULL == back->fLastMask.texture()) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000173 return -1;
174 }
175
robertphillips@google.comf105b102012-05-14 12:18:26 +0000176 return back->fLastMask.texture()->height();
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000177 }
178
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000179 void getLastBound(GrIRect* bound) const {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000180
181 if (fStack.empty()) {
182 GrAssert(false);
183 bound->setEmpty();
184 return;
185 }
186
187 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
188
189 *bound = back->fLastBound;
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000190 }
191
robertphillips@google.comf105b102012-05-14 12:18:26 +0000192 void setContext(GrContext* context) {
193 fContext = context;
194 }
195
196 GrContext* getContext() {
197 return fContext;
198 }
199
200 void releaseResources() {
201
202 SkDeque::F2BIter iter(fStack);
203 for (GrClipStackFrame* frame = (GrClipStackFrame*) iter.next();
204 frame != NULL;
205 frame = (GrClipStackFrame*) iter.next()) {
206 frame->reset();
207 }
208 }
209
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000210protected:
211private:
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000212 struct GrClipStackFrame {
213
214 GrClipStackFrame() {
215 reset();
216 }
217
robertphillips@google.comf105b102012-05-14 12:18:26 +0000218 void acquireMask(GrContext* context,
robertphillips@google.com641f8b12012-07-31 19:15:58 +0000219 const SkClipStack& clip,
robertphillips@google.comf105b102012-05-14 12:18:26 +0000220 const GrTextureDesc& desc,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000221 const GrIRect& bound) {
robertphillips@google.comf105b102012-05-14 12:18:26 +0000222
223 fLastClip = clip;
224
225 fLastMask.set(context, desc);
226
227 fLastBound = bound;
228 }
229
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000230 void reset () {
robertphillips@google.com641f8b12012-07-31 19:15:58 +0000231 fLastClip.reset();
robertphillips@google.comf105b102012-05-14 12:18:26 +0000232
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000233 GrTextureDesc desc;
robertphillips@google.comf105b102012-05-14 12:18:26 +0000234
235 fLastMask.set(NULL, desc);
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000236 fLastBound.setEmpty();
237 }
238
robertphillips@google.com641f8b12012-07-31 19:15:58 +0000239 SkClipStack fLastClip;
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000240 // The mask's width & height values are used in setupDrawStateAAClip to
241 // correctly scale the uvs for geometry drawn with this mask
robertphillips@google.comf105b102012-05-14 12:18:26 +0000242 GrAutoScratchTexture fLastMask;
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000243 // fLastBound stores the bounding box of the clip mask in canvas
244 // space. The left and top fields are used to offset the uvs for
245 // geometry drawn with this mask (in setupDrawStateAAClip)
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000246 GrIRect fLastBound;
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000247 };
248
robertphillips@google.comf105b102012-05-14 12:18:26 +0000249 GrContext* fContext;
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000250 SkDeque fStack;
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000251
252 typedef GrNoncopyable INHERITED;
253};
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000254
255/**
256 * The clip mask creator handles the generation of the clip mask. If anti
257 * aliasing is requested it will (in the future) generate a single channel
258 * (8bit) mask. If no anti aliasing is requested it will generate a 1-bit
259 * mask in the stencil buffer. In the non anti-aliasing case, if the clip
260 * mask can be represented as a rectangle then scissoring is used. In all
261 * cases scissoring is used to bound the range of the clip mask.
262 */
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000263class GrClipMaskManager : public GrNoncopyable {
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000264public:
robertphillips@google.com46a86002012-08-08 10:42:44 +0000265 GR_DECLARE_RESOURCE_CACHE_DOMAIN(GetAlphaMaskDomain)
266
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000267 GrClipMaskManager(GrGpu* gpu)
268 : fGpu(gpu)
bsalomon@google.comc8f7f472012-06-18 13:44:51 +0000269 , fCurrClipMaskType(kNone_ClipMaskType) {
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000270 }
271
bsalomon@google.coma3201942012-06-21 19:58:20 +0000272 /**
273 * Creates a clip mask if necessary as a stencil buffer or alpha texture
274 * and sets the GrGpu's scissor and stencil state. If the return is false
275 * then the draw can be skipped.
276 */
robertphillips@google.combeb1af72012-07-26 18:52:16 +0000277 bool setupClipping(const GrClipData* clipDataIn);
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000278
robertphillips@google.comf105b102012-05-14 12:18:26 +0000279 void releaseResources();
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000280
bsalomon@google.comc8f7f472012-06-18 13:44:51 +0000281 bool isClipInStencil() const {
282 return kStencil_ClipMaskType == fCurrClipMaskType;
283 }
284 bool isClipInAlpha() const {
285 return kAlpha_ClipMaskType == fCurrClipMaskType;
286 }
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000287
bsalomon@google.comc8f7f472012-06-18 13:44:51 +0000288 void invalidateStencilMask() {
289 if (kStencil_ClipMaskType == fCurrClipMaskType) {
290 fCurrClipMaskType = kNone_ClipMaskType;
291 }
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000292 }
293
robertphillips@google.comf105b102012-05-14 12:18:26 +0000294 void setContext(GrContext* context) {
295 fAACache.setContext(context);
296 }
297
robertphillips@google.com2c756812012-05-22 20:28:23 +0000298 GrContext* getContext() {
299 return fAACache.getContext();
300 }
301
bsalomon@google.coma3201942012-06-21 19:58:20 +0000302private:
bsalomon@google.com411dad02012-06-05 20:24:20 +0000303 /**
304 * Informs the helper function adjustStencilParams() about how the stencil
305 * buffer clip is being used.
306 */
307 enum StencilClipMode {
308 // Draw to the clip bit of the stencil buffer
309 kModifyClip_StencilClipMode,
310 // Clip against the existing representation of the clip in the high bit
311 // of the stencil buffer.
312 kRespectClip_StencilClipMode,
313 // Neither writing to nor clipping against the clip bit.
314 kIgnoreClip_StencilClipMode,
315 };
316
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000317 GrGpu* fGpu;
bsalomon@google.comc8f7f472012-06-18 13:44:51 +0000318
319 /**
320 * We may represent the clip as a mask in the stencil buffer or as an alpha
321 * texture. It may be neither because the scissor rect suffices or we
322 * haven't yet examined the clip.
323 */
324 enum ClipMaskType {
325 kNone_ClipMaskType,
326 kStencil_ClipMaskType,
327 kAlpha_ClipMaskType,
328 } fCurrClipMaskType;
329
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000330 GrClipMaskCache fAACache; // cache for the AA path
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000331
robertphillips@google.combeb1af72012-07-26 18:52:16 +0000332 bool createStencilClipMask(const GrClipData& clipDataIn,
robertphillips@google.com7b112892012-07-31 15:18:21 +0000333 const GrIRect& devClipBounds);
robertphillips@google.combeb1af72012-07-26 18:52:16 +0000334 bool createAlphaClipMask(const GrClipData& clipDataIn,
robertphillips@google.coma72eef32012-05-01 17:22:59 +0000335 GrTexture** result,
robertphillips@google.com7b112892012-07-31 15:18:21 +0000336 GrIRect *devResultBounds);
robertphillips@google.combeb1af72012-07-26 18:52:16 +0000337 bool createSoftwareClipMask(const GrClipData& clipDataIn,
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000338 GrTexture** result,
robertphillips@google.com7b112892012-07-31 15:18:21 +0000339 GrIRect *devResultBounds);
robertphillips@google.combeb1af72012-07-26 18:52:16 +0000340 bool clipMaskPreamble(const GrClipData& clipDataIn,
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000341 GrTexture** result,
robertphillips@google.com7b112892012-07-31 15:18:21 +0000342 GrIRect *devResultBounds);
robertphillips@google.comf294b772012-04-27 14:29:26 +0000343
robertphillips@google.com641f8b12012-07-31 19:15:58 +0000344 bool useSWOnlyPath(const SkClipStack& clipIn);
robertphillips@google.comfa662942012-05-17 12:20:22 +0000345
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000346 bool drawClipShape(GrTexture* target,
robertphillips@google.com641f8b12012-07-31 19:15:58 +0000347 const SkClipStack::Iter::Clip* clip,
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000348 const GrIRect& resultBounds);
robertphillips@google.comf294b772012-04-27 14:29:26 +0000349
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000350 void drawTexture(GrTexture* target,
robertphillips@google.comf294b772012-04-27 14:29:26 +0000351 GrTexture* texture);
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000352
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000353 void getTemp(const GrIRect& bounds, GrAutoScratchTexture* temp);
robertphillips@google.comf105b102012-05-14 12:18:26 +0000354
robertphillips@google.com641f8b12012-07-31 19:15:58 +0000355 void setupCache(const SkClipStack& clip,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000356 const GrIRect& bounds);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000357
bsalomon@google.coma3201942012-06-21 19:58:20 +0000358 /**
359 * Called prior to return control back the GrGpu in setupClipping. It
360 * updates the GrGpu with stencil settings that account stencil-based
361 * clipping.
362 */
363 void setGpuStencil();
364
365 /**
366 * Adjusts the stencil settings to account for interaction with stencil
367 * clipping.
368 */
369 void adjustStencilParams(GrStencilSettings* settings,
370 StencilClipMode mode,
371 int stencilBitCnt);
372
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000373 typedef GrNoncopyable INHERITED;
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000374};
375
376#endif // GrClipMaskManager_DEFINED