blob: 0551b8cf2a5c83073e11f28ceb990c9149c69136 [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.comfd6daf52012-05-02 19:32:32 +000012#include "GrClip.h"
robertphillips@google.comf105b102012-05-14 12:18:26 +000013#include "GrContext.h"
bsalomon@google.com411dad02012-06-05 20:24:20 +000014#include "GrNoncopyable.h"
15#include "GrRect.h"
16#include "GrStencil.h"
17#include "GrTexture.h"
18
19#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.combeb1af72012-07-26 18:52:16 +000036 GrClipMaskCache()
robertphillips@google.comf105b102012-05-14 12:18:26 +000037 : fContext(NULL)
38 , fStack(sizeof(GrClipStackFrame)) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000039 // We need an initial frame to capture the clip state prior to
40 // any pushes
tomhudson@google.comc377baf2012-07-09 20:17:56 +000041 SkNEW_PLACEMENT(fStack.push_back(), GrClipStackFrame);
robertphillips@google.com6d62df42012-05-07 18:07:36 +000042 }
43
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000044 ~GrClipMaskCache() {
45
46 while (!fStack.empty()) {
47 GrClipStackFrame* temp = (GrClipStackFrame*) fStack.back();
48 temp->~GrClipStackFrame();
49 fStack.pop_back();
50 }
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000051 }
52
53 bool canReuse(const GrClip& clip, int width, int height) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000054
55 if (fStack.empty()) {
56 GrAssert(false);
57 return false;
58 }
59
60 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
61
robertphillips@google.comf105b102012-05-14 12:18:26 +000062 if (back->fLastMask.texture() &&
63 back->fLastMask.texture()->width() >= width &&
64 back->fLastMask.texture()->height() >= height &&
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000065 clip == back->fLastClip) {
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000066 return true;
67 }
68
69 return false;
70 }
71
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000072 void reset() {
73 if (fStack.empty()) {
robertphillips@google.com87baf892012-05-23 12:02:21 +000074// GrAssert(false);
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000075 return;
76 }
77
78 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
79
80 back->reset();
81 }
82
83 /**
84 * After a "push" the clip state is entirely open. Currently, the
85 * entire clip stack will be re-rendered into a new clip mask.
86 * TODO: can we take advantage of the nested nature of the clips to
87 * reduce the mask creation cost?
88 */
89 void push() {
tomhudson@google.comc377baf2012-07-09 20:17:56 +000090 SkNEW_PLACEMENT(fStack.push_back(), GrClipStackFrame);
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000091 }
92
93 void pop() {
robertphillips@google.com87baf892012-05-23 12:02:21 +000094 //GrAssert(!fStack.empty());
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000095
96 if (!fStack.empty()) {
97 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
98
99 back->~GrClipStackFrame();
100 fStack.pop_back();
101 }
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000102 }
103
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000104 void getLastClip(GrClip* clip) const {
105
106 if (fStack.empty()) {
107 GrAssert(false);
108 clip->setEmpty();
109 return;
110 }
111
112 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
113
114 *clip = back->fLastClip;
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000115 }
116
117 GrTexture* getLastMask() {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000118
119 if (fStack.empty()) {
120 GrAssert(false);
121 return NULL;
122 }
123
124 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
125
robertphillips@google.comf105b102012-05-14 12:18:26 +0000126 return back->fLastMask.texture();
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000127 }
128
129 const GrTexture* getLastMask() const {
130
131 if (fStack.empty()) {
132 GrAssert(false);
133 return NULL;
134 }
135
136 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
137
robertphillips@google.comf105b102012-05-14 12:18:26 +0000138 return back->fLastMask.texture();
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000139 }
140
robertphillips@google.comf105b102012-05-14 12:18:26 +0000141 void acquireMask(const GrClip& clip,
142 const GrTextureDesc& desc,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000143 const GrIRect& bound) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000144
145 if (fStack.empty()) {
146 GrAssert(false);
robertphillips@google.comf105b102012-05-14 12:18:26 +0000147 return;
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000148 }
149
150 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
151
robertphillips@google.comf105b102012-05-14 12:18:26 +0000152 back->acquireMask(fContext, clip, desc, bound);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000153 }
154
155 int getLastMaskWidth() const {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000156
157 if (fStack.empty()) {
158 GrAssert(false);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000159 return -1;
160 }
161
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000162 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
163
robertphillips@google.comf105b102012-05-14 12:18:26 +0000164 if (NULL == back->fLastMask.texture()) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000165 return -1;
166 }
167
robertphillips@google.comf105b102012-05-14 12:18:26 +0000168 return back->fLastMask.texture()->width();
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000169 }
170
171 int getLastMaskHeight() const {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000172
173 if (fStack.empty()) {
174 GrAssert(false);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000175 return -1;
176 }
177
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000178 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
179
robertphillips@google.comf105b102012-05-14 12:18:26 +0000180 if (NULL == back->fLastMask.texture()) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000181 return -1;
182 }
183
robertphillips@google.comf105b102012-05-14 12:18:26 +0000184 return back->fLastMask.texture()->height();
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000185 }
186
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000187 void getLastBound(GrIRect* bound) const {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000188
189 if (fStack.empty()) {
190 GrAssert(false);
191 bound->setEmpty();
192 return;
193 }
194
195 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
196
197 *bound = back->fLastBound;
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000198 }
199
robertphillips@google.comf105b102012-05-14 12:18:26 +0000200 void setContext(GrContext* context) {
201 fContext = context;
202 }
203
204 GrContext* getContext() {
205 return fContext;
206 }
207
208 void releaseResources() {
209
210 SkDeque::F2BIter iter(fStack);
211 for (GrClipStackFrame* frame = (GrClipStackFrame*) iter.next();
212 frame != NULL;
213 frame = (GrClipStackFrame*) iter.next()) {
214 frame->reset();
215 }
216 }
217
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000218protected:
219private:
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000220 struct GrClipStackFrame {
221
222 GrClipStackFrame() {
223 reset();
224 }
225
robertphillips@google.comf105b102012-05-14 12:18:26 +0000226 void acquireMask(GrContext* context,
227 const GrClip& clip,
228 const GrTextureDesc& desc,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000229 const GrIRect& bound) {
robertphillips@google.comf105b102012-05-14 12:18:26 +0000230
231 fLastClip = clip;
232
233 fLastMask.set(context, desc);
234
235 fLastBound = bound;
236 }
237
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000238 void reset () {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000239 fLastClip.setEmpty();
robertphillips@google.comf105b102012-05-14 12:18:26 +0000240
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000241 GrTextureDesc desc;
robertphillips@google.comf105b102012-05-14 12:18:26 +0000242
243 fLastMask.set(NULL, desc);
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000244 fLastBound.setEmpty();
245 }
246
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000247 GrClip fLastClip;
248 // The mask's width & height values are used in setupDrawStateAAClip to
249 // correctly scale the uvs for geometry drawn with this mask
robertphillips@google.comf105b102012-05-14 12:18:26 +0000250 GrAutoScratchTexture fLastMask;
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000251 // fLastBound stores the bounding box of the clip mask in canvas
252 // space. The left and top fields are used to offset the uvs for
253 // geometry drawn with this mask (in setupDrawStateAAClip)
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000254 GrIRect fLastBound;
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000255 };
256
robertphillips@google.comf105b102012-05-14 12:18:26 +0000257 GrContext* fContext;
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000258 SkDeque fStack;
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000259
260 typedef GrNoncopyable INHERITED;
261};
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000262
263/**
264 * The clip mask creator handles the generation of the clip mask. If anti
265 * aliasing is requested it will (in the future) generate a single channel
266 * (8bit) mask. If no anti aliasing is requested it will generate a 1-bit
267 * mask in the stencil buffer. In the non anti-aliasing case, if the clip
268 * mask can be represented as a rectangle then scissoring is used. In all
269 * cases scissoring is used to bound the range of the clip mask.
270 */
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000271class GrClipMaskManager : public GrNoncopyable {
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000272public:
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000273 GrClipMaskManager(GrGpu* gpu)
274 : fGpu(gpu)
bsalomon@google.comc8f7f472012-06-18 13:44:51 +0000275 , fCurrClipMaskType(kNone_ClipMaskType) {
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000276 }
277
bsalomon@google.coma3201942012-06-21 19:58:20 +0000278 /**
279 * Creates a clip mask if necessary as a stencil buffer or alpha texture
280 * and sets the GrGpu's scissor and stencil state. If the return is false
281 * then the draw can be skipped.
282 */
robertphillips@google.combeb1af72012-07-26 18:52:16 +0000283 bool setupClipping(const GrClipData* clipDataIn);
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000284
robertphillips@google.comf105b102012-05-14 12:18:26 +0000285 void releaseResources();
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000286
bsalomon@google.comc8f7f472012-06-18 13:44:51 +0000287 bool isClipInStencil() const {
288 return kStencil_ClipMaskType == fCurrClipMaskType;
289 }
290 bool isClipInAlpha() const {
291 return kAlpha_ClipMaskType == fCurrClipMaskType;
292 }
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000293
bsalomon@google.comc8f7f472012-06-18 13:44:51 +0000294 void invalidateStencilMask() {
295 if (kStencil_ClipMaskType == fCurrClipMaskType) {
296 fCurrClipMaskType = kNone_ClipMaskType;
297 }
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000298 }
299
robertphillips@google.comf105b102012-05-14 12:18:26 +0000300 void setContext(GrContext* context) {
301 fAACache.setContext(context);
302 }
303
robertphillips@google.com2c756812012-05-22 20:28:23 +0000304 GrContext* getContext() {
305 return fAACache.getContext();
306 }
307
bsalomon@google.coma3201942012-06-21 19:58:20 +0000308private:
bsalomon@google.com411dad02012-06-05 20:24:20 +0000309 /**
310 * Informs the helper function adjustStencilParams() about how the stencil
311 * buffer clip is being used.
312 */
313 enum StencilClipMode {
314 // Draw to the clip bit of the stencil buffer
315 kModifyClip_StencilClipMode,
316 // Clip against the existing representation of the clip in the high bit
317 // of the stencil buffer.
318 kRespectClip_StencilClipMode,
319 // Neither writing to nor clipping against the clip bit.
320 kIgnoreClip_StencilClipMode,
321 };
322
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000323 GrGpu* fGpu;
bsalomon@google.comc8f7f472012-06-18 13:44:51 +0000324
325 /**
326 * We may represent the clip as a mask in the stencil buffer or as an alpha
327 * texture. It may be neither because the scissor rect suffices or we
328 * haven't yet examined the clip.
329 */
330 enum ClipMaskType {
331 kNone_ClipMaskType,
332 kStencil_ClipMaskType,
333 kAlpha_ClipMaskType,
334 } fCurrClipMaskType;
335
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000336 GrClipMaskCache fAACache; // cache for the AA path
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000337
robertphillips@google.combeb1af72012-07-26 18:52:16 +0000338 bool createStencilClipMask(const GrClipData& clipDataIn,
bsalomon@google.coma3201942012-06-21 19:58:20 +0000339 const GrIRect& bounds);
robertphillips@google.combeb1af72012-07-26 18:52:16 +0000340 bool createAlphaClipMask(const GrClipData& clipDataIn,
robertphillips@google.coma72eef32012-05-01 17:22:59 +0000341 GrTexture** result,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000342 GrIRect *resultBounds);
robertphillips@google.combeb1af72012-07-26 18:52:16 +0000343 bool createSoftwareClipMask(const GrClipData& clipDataIn,
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000344 GrTexture** result,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000345 GrIRect *resultBounds);
robertphillips@google.combeb1af72012-07-26 18:52:16 +0000346 bool clipMaskPreamble(const GrClipData& clipDataIn,
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000347 GrTexture** result,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000348 GrIRect *resultBounds);
robertphillips@google.comf294b772012-04-27 14:29:26 +0000349
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000350 bool useSWOnlyPath(const GrClip& clipIn);
robertphillips@google.comfa662942012-05-17 12:20:22 +0000351
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000352 bool drawClipShape(GrTexture* target,
robertphillips@google.coma6f11c42012-07-23 17:39:44 +0000353 const GrClip::Iter::Clip* clip,
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000354 const GrIRect& resultBounds);
robertphillips@google.comf294b772012-04-27 14:29:26 +0000355
bsalomon@google.com13b85aa2012-06-15 21:09:40 +0000356 void drawTexture(GrTexture* target,
robertphillips@google.comf294b772012-04-27 14:29:26 +0000357 GrTexture* texture);
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000358
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000359 void getTemp(const GrIRect& bounds, GrAutoScratchTexture* temp);
robertphillips@google.comf105b102012-05-14 12:18:26 +0000360
361 void setupCache(const GrClip& clip,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000362 const GrIRect& bounds);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000363
bsalomon@google.coma3201942012-06-21 19:58:20 +0000364 /**
365 * Called prior to return control back the GrGpu in setupClipping. It
366 * updates the GrGpu with stencil settings that account stencil-based
367 * clipping.
368 */
369 void setGpuStencil();
370
371 /**
372 * Adjusts the stencil settings to account for interaction with stencil
373 * clipping.
374 */
375 void adjustStencilParams(GrStencilSettings* settings,
376 StencilClipMode mode,
377 int stencilBitCnt);
378
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000379 typedef GrNoncopyable INHERITED;
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000380};
381
382#endif // GrClipMaskManager_DEFINED