blob: 65205679d55bd84b508a59bf2dc44e2866197827 [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
12#include "GrRect.h"
bsalomon@google.com8d033a12012-04-27 15:52:53 +000013#include "SkPath.h"
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000014#include "GrNoncopyable.h"
15#include "GrClip.h"
16#include "SkRefCnt.h"
robertphillips@google.com6d62df42012-05-07 18:07:36 +000017#include "GrTexture.h"
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000018#include "SkDeque.h"
robertphillips@google.com1e945b72012-04-16 18:03:03 +000019
20class GrGpu;
robertphillips@google.com1e945b72012-04-16 18:03:03 +000021class GrPathRenderer;
22class GrPathRendererChain;
23class SkPath;
robertphillips@google.comf294b772012-04-27 14:29:26 +000024class GrTexture;
25class GrDrawState;
robertphillips@google.com1e945b72012-04-16 18:03:03 +000026
27/**
28 * Scissoring needs special handling during stencil clip mask creation
29 * since the creation process re-entrantly invokes setupClipAndFlushState.
30 * During this process the call stack is used to keep
31 * track of (and apply to the GPU) the current scissor settings.
32 */
33struct ScissoringSettings {
34 bool fEnableScissoring;
35 GrIRect fScissorRect;
36
37 void setupScissoring(GrGpu* gpu);
38};
39
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000040/**
41 * The stencil buffer stores the last clip path - providing a single entry
42 * "cache". This class provides similar functionality for AA clip paths
43 */
44class GrClipMaskCache : public GrNoncopyable {
45public:
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000046 GrClipMaskCache()
47 : fStack(sizeof(GrClipStackFrame)) {
48 // We need an initial frame to capture the clip state prior to
49 // any pushes
50 new (fStack.push_back()) GrClipStackFrame();
robertphillips@google.com6d62df42012-05-07 18:07:36 +000051 }
52
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000053 ~GrClipMaskCache() {
54
55 while (!fStack.empty()) {
56 GrClipStackFrame* temp = (GrClipStackFrame*) fStack.back();
57 temp->~GrClipStackFrame();
58 fStack.pop_back();
59 }
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000060 }
61
62 bool canReuse(const GrClip& clip, int width, int height) {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000063
64 if (fStack.empty()) {
65 GrAssert(false);
66 return false;
67 }
68
69 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
70
71 if (back->fLastWidth >= width &&
72 back->fLastHeight >= height &&
73 clip == back->fLastClip) {
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000074 return true;
75 }
76
77 return false;
78 }
79
80 void set(const GrClip& clip, int width, int height,
81 GrTexture* mask, const GrRect& bound) {
82
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000083 if (fStack.empty()) {
84 GrAssert(false);
85 return;
86 }
87
88 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
89
90 back->fLastWidth = width;
91 back->fLastHeight = height;
92 back->fLastClip = clip;
robertphillips@google.comfd6daf52012-05-02 19:32:32 +000093 SkSafeRef(mask);
robertphillips@google.combeeb97c2012-05-09 21:15:28 +000094 back->fLastMask.reset(mask);
95 back->fLastBound = bound;
96 }
97
98 void reset() {
99 if (fStack.empty()) {
100 GrAssert(false);
101 return;
102 }
103
104 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
105
106 back->reset();
107 }
108
109 /**
110 * After a "push" the clip state is entirely open. Currently, the
111 * entire clip stack will be re-rendered into a new clip mask.
112 * TODO: can we take advantage of the nested nature of the clips to
113 * reduce the mask creation cost?
114 */
115 void push() {
116 new (fStack.push_back()) GrClipStackFrame();
117 }
118
119 void pop() {
120 GrAssert(!fStack.empty());
121
122 if (!fStack.empty()) {
123 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
124
125 back->~GrClipStackFrame();
126 fStack.pop_back();
127 }
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000128 }
129
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000130 int getLastWidth() const {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000131
132 if (fStack.empty()) {
133 GrAssert(false);
134 return -1;
135 }
136
137 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
138
139 return back->fLastWidth;
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000140 }
141
142 int getLastHeight() const {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000143
144 if (fStack.empty()) {
145 GrAssert(false);
146 return -1;
147 }
148
149 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
150
151 return back->fLastHeight;
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000152 }
153
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000154 void getLastClip(GrClip* clip) const {
155
156 if (fStack.empty()) {
157 GrAssert(false);
158 clip->setEmpty();
159 return;
160 }
161
162 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
163
164 *clip = back->fLastClip;
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000165 }
166
167 GrTexture* getLastMask() {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000168
169 if (fStack.empty()) {
170 GrAssert(false);
171 return NULL;
172 }
173
174 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
175
176 return back->fLastMask.get();
177 }
178
179 const GrTexture* getLastMask() const {
180
181 if (fStack.empty()) {
182 GrAssert(false);
183 return NULL;
184 }
185
186 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
187
188 return back->fLastMask.get();
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000189 }
190
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000191 GrTexture* detachLastMask() {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000192
193 if (fStack.empty()) {
194 GrAssert(false);
195 return NULL;
196 }
197
198 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
199
200 return back->fLastMask.detach();
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000201 }
202
203 int getLastMaskWidth() const {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000204
205 if (fStack.empty()) {
206 GrAssert(false);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000207 return -1;
208 }
209
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000210 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
211
212 if (NULL == back->fLastMask.get()) {
213 return -1;
214 }
215
216 return back->fLastMask.get()->width();
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000217 }
218
219 int getLastMaskHeight() const {
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000220
221 if (fStack.empty()) {
222 GrAssert(false);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000223 return -1;
224 }
225
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000226 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
227
228 if (NULL == back->fLastMask.get()) {
229 return -1;
230 }
231
232 return back->fLastMask.get()->height();
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000233 }
234
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000235 void getLastBound(GrRect* bound) const {
236
237 if (fStack.empty()) {
238 GrAssert(false);
239 bound->setEmpty();
240 return;
241 }
242
243 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
244
245 *bound = back->fLastBound;
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000246 }
247
248protected:
249private:
robertphillips@google.combeeb97c2012-05-09 21:15:28 +0000250 struct GrClipStackFrame {
251
252 GrClipStackFrame() {
253 reset();
254 }
255
256 void reset () {
257 fLastWidth = -1;
258 fLastHeight = -1;
259 fLastClip.setEmpty();
260 fLastMask.reset(NULL);
261 fLastBound.setEmpty();
262 }
263
264 // fLastWidth & fLastHeight store the render target size used when
265 // creating the mask. They factor into the reuse decision (in canReuse)
266 // TODO: We should probably use the mask's width & height rather than
267 // the render target's width & height for reuse decisions
268 int fLastWidth;
269 int fLastHeight;
270 GrClip fLastClip;
271 // The mask's width & height values are used in setupDrawStateAAClip to
272 // correctly scale the uvs for geometry drawn with this mask
273 SkAutoTUnref<GrTexture> fLastMask;
274 // fLastBound stores the bounding box of the clip mask in canvas
275 // space. The left and top fields are used to offset the uvs for
276 // geometry drawn with this mask (in setupDrawStateAAClip)
277 GrRect fLastBound;
278 };
279
280 SkDeque fStack;
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000281
282 typedef GrNoncopyable INHERITED;
283};
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000284
285/**
286 * The clip mask creator handles the generation of the clip mask. If anti
287 * aliasing is requested it will (in the future) generate a single channel
288 * (8bit) mask. If no anti aliasing is requested it will generate a 1-bit
289 * mask in the stencil buffer. In the non anti-aliasing case, if the clip
290 * mask can be represented as a rectangle then scissoring is used. In all
291 * cases scissoring is used to bound the range of the clip mask.
292 */
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000293class GrClipMaskManager : public GrNoncopyable {
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000294public:
295 GrClipMaskManager()
296 : fClipMaskInStencil(false)
robertphillips@google.comf294b772012-04-27 14:29:26 +0000297 , fClipMaskInAlpha(false)
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000298 , fPathRendererChain(NULL) {
299 }
300
301 bool createClipMask(GrGpu* gpu,
302 const GrClip& clip,
303 ScissoringSettings* scissorSettings);
304
305 void freeResources();
306
307 bool isClipInStencil() const { return fClipMaskInStencil; }
robertphillips@google.comf294b772012-04-27 14:29:26 +0000308 bool isClipInAlpha() const { return fClipMaskInAlpha; }
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000309
310 void resetMask() {
311 fClipMaskInStencil = false;
312 }
313
314protected:
315private:
316 bool fClipMaskInStencil; // is the clip mask in the stencil buffer?
robertphillips@google.comf294b772012-04-27 14:29:26 +0000317 bool fClipMaskInAlpha; // is the clip mask in an alpha texture?
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000318 GrClipMaskCache fAACache; // cache for the AA path
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000319
320 // must be instantiated after GrGpu object has been given its owning
321 // GrContext ptr. (GrGpu is constructed first then handed off to GrContext).
322 GrPathRendererChain* fPathRendererChain;
323
324 bool createStencilClipMask(GrGpu* gpu,
325 const GrClip& clip,
326 const GrRect& bounds,
327 ScissoringSettings* scissorSettings);
robertphillips@google.coma72eef32012-05-01 17:22:59 +0000328 bool createAlphaClipMask(GrGpu* gpu,
329 const GrClip& clipIn,
330 GrTexture** result,
331 GrRect *resultBounds);
robertphillips@google.comf294b772012-04-27 14:29:26 +0000332
333 bool drawPath(GrGpu* gpu,
bsalomon@google.com8d033a12012-04-27 15:52:53 +0000334 const SkPath& path,
robertphillips@google.comf294b772012-04-27 14:29:26 +0000335 GrPathFill fill,
336 bool doAA);
337
338 bool drawClipShape(GrGpu* gpu,
339 GrTexture* target,
340 const GrClip& clipIn,
341 int index);
342
343 void drawTexture(GrGpu* gpu,
344 GrTexture* target,
345 const GrRect& rect,
346 GrTexture* texture);
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000347
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000348 void getAccum(GrGpu* gpu,
349 const GrTextureDesc& desc,
350 GrTexture** accum);
351
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000352 // determines the path renderer used to draw a clip path element.
353 GrPathRenderer* getClipPathRenderer(GrGpu* gpu,
354 const SkPath& path,
robertphillips@google.comf294b772012-04-27 14:29:26 +0000355 GrPathFill fill,
356 bool antiAlias);
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000357
robertphillips@google.comfd6daf52012-05-02 19:32:32 +0000358 typedef GrNoncopyable INHERITED;
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000359};
360
361#endif // GrClipMaskManager_DEFINED