blob: 2f4d8c7aa7292a84718c51cfe5d90d4c4c9bd5d6 [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/**
31 * Scissoring needs special handling during stencil clip mask creation
32 * since the creation process re-entrantly invokes setupClipAndFlushState.
33 * During this process the call stack is used to keep
34 * track of (and apply to the GPU) the current scissor settings.
35 */
36struct ScissoringSettings {
37 bool fEnableScissoring;
38 GrIRect fScissorRect;
39
40 void setupScissoring(GrGpu* gpu);
41};
42
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000043/**
44 * The stencil buffer stores the last clip path - providing a single entry
45 * "cache". This class provides similar functionality for AA clip paths
46 */
47class GrClipMaskCache : public GrNoncopyable {
48public:
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000049 GrClipMaskCache()
robertphillips@google.comf105b102012-05-14 12:18:26 +000050 : fContext(NULL)
51 , fStack(sizeof(GrClipStackFrame)) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000052 // We need an initial frame to capture the clip state prior to
53 // any pushes
54 new (fStack.push_back()) GrClipStackFrame();
robertphillips@google.com6d62df42012-05-07 18:07:36 +000055 }
56
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000057 ~GrClipMaskCache() {
58
59 while (!fStack.empty()) {
60 GrClipStackFrame* temp = (GrClipStackFrame*) fStack.back();
61 temp->~GrClipStackFrame();
62 fStack.pop_back();
63 }
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000064 }
65
66 bool canReuse(const GrClip& clip, int width, int height) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000067
68 if (fStack.empty()) {
69 GrAssert(false);
70 return false;
71 }
72
73 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
74
robertphillips@google.comf105b102012-05-14 12:18:26 +000075 if (back->fLastMask.texture() &&
76 back->fLastMask.texture()->width() >= width &&
77 back->fLastMask.texture()->height() >= height &&
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000078 clip == back->fLastClip) {
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000079 return true;
80 }
81
82 return false;
83 }
84
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000085 void reset() {
86 if (fStack.empty()) {
robertphillips@google.com87baf892012-05-23 12:02:21 +000087// GrAssert(false);
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000088 return;
89 }
90
91 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
92
93 back->reset();
94 }
95
96 /**
97 * After a "push" the clip state is entirely open. Currently, the
98 * entire clip stack will be re-rendered into a new clip mask.
99 * TODO: can we take advantage of the nested nature of the clips to
100 * reduce the mask creation cost?
101 */
102 void push() {
103 new (fStack.push_back()) GrClipStackFrame();
104 }
105
106 void pop() {
robertphillips@google.com87baf892012-05-23 12:02:21 +0000107 //GrAssert(!fStack.empty());
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000108
109 if (!fStack.empty()) {
110 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
111
112 back->~GrClipStackFrame();
113 fStack.pop_back();
114 }
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000115 }
116
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000117 void getLastClip(GrClip* clip) const {
118
119 if (fStack.empty()) {
120 GrAssert(false);
121 clip->setEmpty();
122 return;
123 }
124
125 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
126
127 *clip = back->fLastClip;
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000128 }
129
130 GrTexture* getLastMask() {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000131
132 if (fStack.empty()) {
133 GrAssert(false);
134 return NULL;
135 }
136
137 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
138
robertphillips@google.comf105b102012-05-14 12:18:26 +0000139 return back->fLastMask.texture();
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000140 }
141
142 const GrTexture* getLastMask() const {
143
144 if (fStack.empty()) {
145 GrAssert(false);
146 return NULL;
147 }
148
149 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
150
robertphillips@google.comf105b102012-05-14 12:18:26 +0000151 return back->fLastMask.texture();
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000152 }
153
robertphillips@google.comf105b102012-05-14 12:18:26 +0000154 void acquireMask(const GrClip& clip,
155 const GrTextureDesc& desc,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000156 const GrIRect& bound) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000157
158 if (fStack.empty()) {
159 GrAssert(false);
robertphillips@google.comf105b102012-05-14 12:18:26 +0000160 return;
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000161 }
162
163 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
164
robertphillips@google.comf105b102012-05-14 12:18:26 +0000165 back->acquireMask(fContext, clip, desc, bound);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000166 }
167
168 int getLastMaskWidth() const {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000169
170 if (fStack.empty()) {
171 GrAssert(false);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000172 return -1;
173 }
174
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000175 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
176
robertphillips@google.comf105b102012-05-14 12:18:26 +0000177 if (NULL == back->fLastMask.texture()) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000178 return -1;
179 }
180
robertphillips@google.comf105b102012-05-14 12:18:26 +0000181 return back->fLastMask.texture()->width();
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000182 }
183
184 int getLastMaskHeight() const {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000185
186 if (fStack.empty()) {
187 GrAssert(false);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000188 return -1;
189 }
190
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000191 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
192
robertphillips@google.comf105b102012-05-14 12:18:26 +0000193 if (NULL == back->fLastMask.texture()) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000194 return -1;
195 }
196
robertphillips@google.comf105b102012-05-14 12:18:26 +0000197 return back->fLastMask.texture()->height();
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000198 }
199
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000200 void getLastBound(GrIRect* bound) const {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000201
202 if (fStack.empty()) {
203 GrAssert(false);
204 bound->setEmpty();
205 return;
206 }
207
208 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
209
210 *bound = back->fLastBound;
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000211 }
212
robertphillips@google.comf105b102012-05-14 12:18:26 +0000213 void setContext(GrContext* context) {
214 fContext = context;
215 }
216
217 GrContext* getContext() {
218 return fContext;
219 }
220
221 void releaseResources() {
222
223 SkDeque::F2BIter iter(fStack);
224 for (GrClipStackFrame* frame = (GrClipStackFrame*) iter.next();
225 frame != NULL;
226 frame = (GrClipStackFrame*) iter.next()) {
227 frame->reset();
228 }
229 }
230
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000231protected:
232private:
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000233 struct GrClipStackFrame {
234
235 GrClipStackFrame() {
236 reset();
237 }
238
robertphillips@google.comf105b102012-05-14 12:18:26 +0000239 void acquireMask(GrContext* context,
240 const GrClip& clip,
241 const GrTextureDesc& desc,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000242 const GrIRect& bound) {
robertphillips@google.comf105b102012-05-14 12:18:26 +0000243
244 fLastClip = clip;
245
246 fLastMask.set(context, desc);
247
248 fLastBound = bound;
249 }
250
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000251 void reset () {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000252 fLastClip.setEmpty();
robertphillips@google.comf105b102012-05-14 12:18:26 +0000253
254 const GrTextureDesc desc = { kNone_GrTextureFlags, 0, 0,
255 kUnknown_GrPixelConfig, 0 };
256
257 fLastMask.set(NULL, desc);
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000258 fLastBound.setEmpty();
259 }
260
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000261 GrClip fLastClip;
262 // The mask's width & height values are used in setupDrawStateAAClip to
263 // correctly scale the uvs for geometry drawn with this mask
robertphillips@google.comf105b102012-05-14 12:18:26 +0000264 GrAutoScratchTexture fLastMask;
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000265 // fLastBound stores the bounding box of the clip mask in canvas
266 // space. The left and top fields are used to offset the uvs for
267 // geometry drawn with this mask (in setupDrawStateAAClip)
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000268 GrIRect fLastBound;
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000269 };
270
robertphillips@google.comf105b102012-05-14 12:18:26 +0000271 GrContext* fContext;
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000272 SkDeque fStack;
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000273
274 typedef GrNoncopyable INHERITED;
275};
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000276
277/**
278 * The clip mask creator handles the generation of the clip mask. If anti
279 * aliasing is requested it will (in the future) generate a single channel
280 * (8bit) mask. If no anti aliasing is requested it will generate a 1-bit
281 * mask in the stencil buffer. In the non anti-aliasing case, if the clip
282 * mask can be represented as a rectangle then scissoring is used. In all
283 * cases scissoring is used to bound the range of the clip mask.
284 */
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000285class GrClipMaskManager : public GrNoncopyable {
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000286public:
287 GrClipMaskManager()
288 : fClipMaskInStencil(false)
robertphillips@google.com2c756812012-05-22 20:28:23 +0000289 , fClipMaskInAlpha(false) {
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000290 }
291
292 bool createClipMask(GrGpu* gpu,
293 const GrClip& clip,
294 ScissoringSettings* scissorSettings);
295
robertphillips@google.comf105b102012-05-14 12:18:26 +0000296 void releaseResources();
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000297
298 bool isClipInStencil() const { return fClipMaskInStencil; }
robertphillips@google.comf294b772012-04-27 14:29:26 +0000299 bool isClipInAlpha() const { return fClipMaskInAlpha; }
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000300
301 void resetMask() {
302 fClipMaskInStencil = false;
303 }
304
robertphillips@google.com49d9fd52012-05-23 11:44:08 +0000305 void postClipPush() {
306 // TODO: make sure that, if the clip stack is unaltered, the
307 // prior clip mask is reused (i.e., a push w/ no change to the
308 // clip stack)
309 fAACache.push();
310 }
311
312 void preClipPop() {
313 fAACache.pop();
314 }
315
robertphillips@google.comf105b102012-05-14 12:18:26 +0000316 void setContext(GrContext* context) {
317 fAACache.setContext(context);
318 }
319
robertphillips@google.com2c756812012-05-22 20:28:23 +0000320 GrContext* getContext() {
321 return fAACache.getContext();
322 }
323
bsalomon@google.com411dad02012-06-05 20:24:20 +0000324 /**
325 * Informs the helper function adjustStencilParams() about how the stencil
326 * buffer clip is being used.
327 */
328 enum StencilClipMode {
329 // Draw to the clip bit of the stencil buffer
330 kModifyClip_StencilClipMode,
331 // Clip against the existing representation of the clip in the high bit
332 // of the stencil buffer.
333 kRespectClip_StencilClipMode,
334 // Neither writing to nor clipping against the clip bit.
335 kIgnoreClip_StencilClipMode,
336 };
337
338 /**
339 * The stencil func, mask, and reference value are specified by GrGpu's
340 * caller but the actual values passed to the API may have to be adjusted
341 * due to the stencil buffer simultaneously being used for clipping. This
342 * function should be called even when clipping is disabled in order to
343 * prevent the clip from being accidentally overwritten.
344 */
345 GrStencilFunc adjustStencilParams(GrStencilFunc,
346 StencilClipMode mode,
347 unsigned int stencilBitCnt,
348 unsigned int* ref,
349 unsigned int* mask,
350 unsigned int* writeMask);
351
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000352private:
353 bool fClipMaskInStencil; // is the clip mask in the stencil buffer?
robertphillips@google.comf294b772012-04-27 14:29:26 +0000354 bool fClipMaskInAlpha; // is the clip mask in an alpha texture?
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000355 GrClipMaskCache fAACache; // cache for the AA path
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000356
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000357 bool createStencilClipMask(GrGpu* gpu,
358 const GrClip& clip,
359 const GrRect& bounds,
360 ScissoringSettings* scissorSettings);
robertphillips@google.coma72eef32012-05-01 17:22:59 +0000361 bool createAlphaClipMask(GrGpu* gpu,
362 const GrClip& clipIn,
363 GrTexture** result,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000364 GrIRect *resultBounds);
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000365 bool createSoftwareClipMask(GrGpu* gpu,
366 const GrClip& clipIn,
367 GrTexture** result,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000368 GrIRect *resultBounds);
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000369 bool clipMaskPreamble(GrGpu* gpu,
370 const GrClip& clipIn,
371 GrTexture** result,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000372 GrIRect *resultBounds);
robertphillips@google.comf294b772012-04-27 14:29:26 +0000373
robertphillips@google.comfa662942012-05-17 12:20:22 +0000374 bool useSWOnlyPath(GrGpu* gpu, const GrClip& clipIn);
375
robertphillips@google.comf294b772012-04-27 14:29:26 +0000376 bool drawClipShape(GrGpu* gpu,
377 GrTexture* target,
378 const GrClip& clipIn,
379 int index);
380
381 void drawTexture(GrGpu* gpu,
382 GrTexture* target,
robertphillips@google.comf294b772012-04-27 14:29:26 +0000383 GrTexture* texture);
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000384
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000385 void getTemp(const GrIRect& bounds, GrAutoScratchTexture* temp);
robertphillips@google.comf105b102012-05-14 12:18:26 +0000386
387 void setupCache(const GrClip& clip,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000388 const GrIRect& bounds);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000389
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000390 typedef GrNoncopyable INHERITED;
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000391};
392
393#endif // GrClipMaskManager_DEFINED