blob: e618bf17f094a210bccbc964f7708f0fcc8dd02f [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#include "GrClipMaskManager.h"
10#include "GrGpu.h"
11#include "GrRenderTarget.h"
12#include "GrStencilBuffer.h"
13#include "GrPathRenderer.h"
robertphillips@google.coma72eef32012-05-01 17:22:59 +000014#include "GrPaint.h"
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +000015#include "SkRasterClip.h"
robertphillips@google.comfa662942012-05-17 12:20:22 +000016#include "GrAAConvexPathRenderer.h"
17#include "GrAAHairLinePathRenderer.h"
18
19// TODO: move GrSWMaskHelper out of GrSoftwarePathRender.h & remove this include
20#include "GrSoftwarePathRenderer.h"
robertphillips@google.coma72eef32012-05-01 17:22:59 +000021
22//#define GR_AA_CLIP 1
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +000023//#define GR_SW_CLIP 1
robertphillips@google.coma72eef32012-05-01 17:22:59 +000024
robertphillips@google.comf294b772012-04-27 14:29:26 +000025////////////////////////////////////////////////////////////////////////////////
robertphillips@google.com1e945b72012-04-16 18:03:03 +000026void ScissoringSettings::setupScissoring(GrGpu* gpu) {
27 if (!fEnableScissoring) {
28 gpu->disableScissor();
29 return;
30 }
31
32 gpu->enableScissoring(fScissorRect);
33}
34
robertphillips@google.coma72eef32012-05-01 17:22:59 +000035namespace {
36// set up the draw state to enable the aa clipping mask. Besides setting up the
37// sampler matrix this also alters the vertex layout
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +000038void setup_drawstate_aaclip(GrGpu* gpu,
39 GrTexture* result,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +000040 const GrIRect &bound) {
robertphillips@google.coma72eef32012-05-01 17:22:59 +000041 GrDrawState* drawState = gpu->drawState();
42 GrAssert(drawState);
43
44 static const int maskStage = GrPaint::kTotalStages+1;
45
46 GrMatrix mat;
47 mat.setIDiv(result->width(), result->height());
robertphillips@google.com6623fcd2012-05-15 16:47:23 +000048 mat.preTranslate(SkIntToScalar(-bound.fLeft), SkIntToScalar(-bound.fTop));
robertphillips@google.coma72eef32012-05-01 17:22:59 +000049 mat.preConcat(drawState->getViewMatrix());
50
51 drawState->sampler(maskStage)->reset(GrSamplerState::kClamp_WrapMode,
52 GrSamplerState::kNearest_Filter,
53 mat);
54
55 drawState->setTexture(maskStage, result);
56
57 // The AA clipping determination happens long after the geometry has
58 // been set up to draw. Here we directly enable the AA clip mask stage
59 gpu->addToVertexLayout(
60 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(maskStage));
61}
62
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +000063}
64
robertphillips@google.comfa662942012-05-17 12:20:22 +000065/*
66 * This method traverses the clip stack to see if the GrSoftwarePathRenderer
67 * will be used on any element. If so, it returns true to indicate that the
68 * entire clip should be rendered in SW and then uploaded en masse to the gpu.
69 */
70bool GrClipMaskManager::useSWOnlyPath(GrGpu* gpu, const GrClip& clipIn) {
71 // TODO: this check is correct for the createAlphaClipMask path.
72 // The createStencilClipMask path does a lot more flip flopping of fill,
73 // etc - so this isn't quite correct in that case
74
75 // TODO: generalize this test so that when
76 // a clip gets complex enough it can just be done in SW regardless
77 // of whether it would invoke the GrSoftwarePathRenderer.
78 bool useSW = false;
79
80 for (int i = 0; i < clipIn.getElementCount(); ++i) {
81
82 if (SkRegion::kReplace_Op == clipIn.getOp(i)) {
83 // Everything before a replace op can be ignored so start
84 // afresh w.r.t. determining if any element uses the SW path
85 useSW = false;
86 }
87
88 if (!clipIn.getDoAA(i)) {
89 // non-anti-aliased rects and paths can always be drawn either
90 // directly or by the GrDefaultPathRenderer
91 continue;
92 }
93
94 if (kRect_ClipType == clipIn.getElementType(i)) {
95 // Antialiased rects are converted to paths and then drawn with
96 // kEvenOdd_PathFill.
97 if (!GrAAConvexPathRenderer::staticCanDrawPath(
98 true, // always convex
99 kEvenOdd_PathFill,
100 gpu, true)) {
101 // if the GrAAConvexPathRenderer can't render this rect (due
102 // to lack of derivative support in the shaders) then
103 // the GrSoftwarePathRenderer will be used
104 useSW = true;
105 }
106
107 continue;
108 }
109
110 // only paths need to be considered in the rest of the loop body
111
112 if (GrAAHairLinePathRenderer::staticCanDrawPath(clipIn.getPath(i),
113 clipIn.getPathFill(i),
114 gpu,
115 clipIn.getDoAA(i))) {
116 // the hair line path renderer can handle this one
117 continue;
118 }
119
120 if (GrAAConvexPathRenderer::staticCanDrawPath(
121 clipIn.getPath(i).isConvex(),
122 clipIn.getPathFill(i),
123 gpu,
124 clipIn.getDoAA(i))) {
125 // the convex path renderer can handle this one
126 continue;
127 }
128
129 // otherwise the GrSoftwarePathRenderer is going to be invoked
130 useSW = true;
131 }
132
133 return useSW;
robertphillips@google.coma72eef32012-05-01 17:22:59 +0000134}
135
robertphillips@google.comfa662942012-05-17 12:20:22 +0000136
robertphillips@google.comf294b772012-04-27 14:29:26 +0000137////////////////////////////////////////////////////////////////////////////////
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000138// sort out what kind of clip mask needs to be created: alpha, stencil,
139// scissor, or entirely software
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000140bool GrClipMaskManager::createClipMask(GrGpu* gpu,
141 const GrClip& clipIn,
142 ScissoringSettings* scissorSettings) {
143
144 GrAssert(scissorSettings);
145
146 scissorSettings->fEnableScissoring = false;
147 fClipMaskInStencil = false;
robertphillips@google.comf294b772012-04-27 14:29:26 +0000148 fClipMaskInAlpha = false;
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000149
150 GrDrawState* drawState = gpu->drawState();
151 if (!drawState->isClipState()) {
152 return true;
153 }
154
155 GrRenderTarget* rt = drawState->getRenderTarget();
156
157 // GrDrawTarget should have filtered this for us
158 GrAssert(NULL != rt);
159
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000160#if GR_SW_CLIP
robertphillips@google.comfa662942012-05-17 12:20:22 +0000161 if (useSWOnlyPath(gpu, clipIn)) {
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000162 // The clip geometry is complex enough that it will be more
163 // efficient to create it entirely in software
164 GrTexture* result = NULL;
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000165 GrIRect bound;
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000166 if (this->createSoftwareClipMask(gpu, clipIn, &result, &bound)) {
167 fClipMaskInAlpha = true;
168
169 setup_drawstate_aaclip(gpu, result, bound);
170 return true;
171 }
172 }
173#endif
174
robertphillips@google.comf294b772012-04-27 14:29:26 +0000175#if GR_AA_CLIP
176 // If MSAA is enabled use the (faster) stencil path for AA clipping
177 // otherwise the alpha clip mask is our only option
178 if (clipIn.requiresAA() && 0 == rt->numSamples()) {
179 // Since we are going to create a destination texture of the correct
180 // size for the mask (rather than being bound by the size of the
181 // render target) we aren't going to use scissoring like the stencil
182 // path does (see scissorSettings below)
robertphillips@google.coma72eef32012-05-01 17:22:59 +0000183 GrTexture* result = NULL;
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000184 GrIRect bound;
robertphillips@google.coma72eef32012-05-01 17:22:59 +0000185 if (this->createAlphaClipMask(gpu, clipIn, &result, &bound)) {
robertphillips@google.comf294b772012-04-27 14:29:26 +0000186 fClipMaskInAlpha = true;
robertphillips@google.coma72eef32012-05-01 17:22:59 +0000187
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000188 setup_drawstate_aaclip(gpu, result, bound);
robertphillips@google.comf294b772012-04-27 14:29:26 +0000189 return true;
190 }
191
192 // if alpha clip mask creation fails fall through to the stencil
193 // buffer method
194 }
195#endif // GR_AA_CLIP
196
robertphillips@google.com5acc0e32012-05-17 12:01:02 +0000197 // Either a hard (stencil buffer) clip was explicitly requested or
198 // an antialiased clip couldn't be created. In either case, free up
199 // the texture in the antialiased mask cache.
200 // TODO: this may require more investigation. Ganesh performs a lot of
201 // utility draws (e.g., clears, InOderDrawBuffer playbacks) that hit
202 // the stencil buffer path. These may be incorrectly messing up the
203 // AA cache.
204 fAACache.reset();
205
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000206 GrRect bounds;
207 GrRect rtRect;
208 rtRect.setLTRB(0, 0,
robertphillips@google.comfa662942012-05-17 12:20:22 +0000209 GrIntToScalar(rt->width()), GrIntToScalar(rt->height()));
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000210 if (clipIn.hasConservativeBounds()) {
211 bounds = clipIn.getConservativeBounds();
212 if (!bounds.intersect(rtRect)) {
213 bounds.setEmpty();
214 }
215 } else {
216 bounds = rtRect;
217 }
218
219 bounds.roundOut(&scissorSettings->fScissorRect);
220 if (scissorSettings->fScissorRect.isEmpty()) {
221 scissorSettings->fScissorRect.setLTRB(0,0,0,0);
222 // TODO: I think we can do an early exit here - after refactoring try:
223 // set fEnableScissoring to true but leave fClipMaskInStencil false
224 // and return - everything is going to be scissored away anyway!
225 }
226 scissorSettings->fEnableScissoring = true;
227
228 // use the stencil clip if we can't represent the clip as a rectangle.
229 fClipMaskInStencil = !clipIn.isRect() && !clipIn.isEmpty() &&
230 !bounds.isEmpty();
231
232 if (fClipMaskInStencil) {
233 return this->createStencilClipMask(gpu, clipIn, bounds, scissorSettings);
234 }
235
236 return true;
237}
238
239#define VISUALIZE_COMPLEX_CLIP 0
240
241#if VISUALIZE_COMPLEX_CLIP
242 #include "GrRandom.h"
243 GrRandom gRandom;
244 #define SET_RANDOM_COLOR drawState->setColor(0xff000000 | gRandom.nextU());
245#else
246 #define SET_RANDOM_COLOR
247#endif
248
249namespace {
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000250/**
251 * Does "container" contain "containee"? If either is empty then
252 * no containment is possible.
253 */
254bool contains(const SkRect& container, const SkIRect& containee) {
255 return !containee.isEmpty() && !container.isEmpty() &&
256 container.fLeft <= SkIntToScalar(containee.fLeft) &&
257 container.fTop <= SkIntToScalar(containee.fTop) &&
258 container.fRight >= SkIntToScalar(containee.fRight) &&
259 container.fBottom >= SkIntToScalar(containee.fBottom);
260}
261
262
robertphillips@google.comf294b772012-04-27 14:29:26 +0000263////////////////////////////////////////////////////////////////////////////////
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000264// determines how many elements at the head of the clip can be skipped and
265// whether the initial clear should be to the inside- or outside-the-clip value,
266// and what op should be used to draw the first element that isn't skipped.
267int process_initial_clip_elements(const GrClip& clip,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000268 const GrIRect& bounds,
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000269 bool* clearToInside,
robertphillips@google.com0f191f32012-04-25 15:23:36 +0000270 SkRegion::Op* startOp) {
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000271
272 // logically before the first element of the clip stack is
273 // processed the clip is entirely open. However, depending on the
274 // first set op we may prefer to clear to 0 for performance. We may
275 // also be able to skip the initial clip paths/rects. We loop until
276 // we cannot skip an element.
277 int curr;
278 bool done = false;
279 *clearToInside = true;
280 int count = clip.getElementCount();
281
282 for (curr = 0; curr < count && !done; ++curr) {
283 switch (clip.getOp(curr)) {
robertphillips@google.com0f191f32012-04-25 15:23:36 +0000284 case SkRegion::kReplace_Op:
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000285 // replace ignores everything previous
robertphillips@google.com0f191f32012-04-25 15:23:36 +0000286 *startOp = SkRegion::kReplace_Op;
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000287 *clearToInside = false;
288 done = true;
289 break;
robertphillips@google.com0f191f32012-04-25 15:23:36 +0000290 case SkRegion::kIntersect_Op:
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000291 // if this element contains the entire bounds then we
292 // can skip it.
293 if (kRect_ClipType == clip.getElementType(curr)
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000294 && contains(clip.getRect(curr), bounds)) {
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000295 break;
296 }
297 // if everything is initially clearToInside then intersect is
298 // same as clear to 0 and treat as a replace. Otherwise,
299 // set stays empty.
300 if (*clearToInside) {
robertphillips@google.com0f191f32012-04-25 15:23:36 +0000301 *startOp = SkRegion::kReplace_Op;
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000302 *clearToInside = false;
303 done = true;
304 }
305 break;
306 // we can skip a leading union.
robertphillips@google.com0f191f32012-04-25 15:23:36 +0000307 case SkRegion::kUnion_Op:
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000308 // if everything is initially outside then union is
309 // same as replace. Otherwise, every pixel is still
310 // clearToInside
311 if (!*clearToInside) {
robertphillips@google.com0f191f32012-04-25 15:23:36 +0000312 *startOp = SkRegion::kReplace_Op;
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000313 done = true;
314 }
315 break;
robertphillips@google.com0f191f32012-04-25 15:23:36 +0000316 case SkRegion::kXOR_Op:
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000317 // xor is same as difference or replace both of which
318 // can be 1-pass instead of 2 for xor.
319 if (*clearToInside) {
robertphillips@google.com0f191f32012-04-25 15:23:36 +0000320 *startOp = SkRegion::kDifference_Op;
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000321 } else {
robertphillips@google.com0f191f32012-04-25 15:23:36 +0000322 *startOp = SkRegion::kReplace_Op;
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000323 }
324 done = true;
325 break;
robertphillips@google.com0f191f32012-04-25 15:23:36 +0000326 case SkRegion::kDifference_Op:
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000327 // if all pixels are clearToInside then we have to process the
328 // difference, otherwise it has no effect and all pixels
329 // remain outside.
330 if (*clearToInside) {
robertphillips@google.com0f191f32012-04-25 15:23:36 +0000331 *startOp = SkRegion::kDifference_Op;
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000332 done = true;
333 }
334 break;
robertphillips@google.com0f191f32012-04-25 15:23:36 +0000335 case SkRegion::kReverseDifference_Op:
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000336 // if all pixels are clearToInside then reverse difference
337 // produces empty set. Otherise it is same as replace
338 if (*clearToInside) {
339 *clearToInside = false;
340 } else {
robertphillips@google.com0f191f32012-04-25 15:23:36 +0000341 *startOp = SkRegion::kReplace_Op;
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000342 done = true;
343 }
344 break;
345 default:
346 GrCrash("Unknown set op.");
347 }
348 }
349 return done ? curr-1 : count;
350}
robertphillips@google.comf294b772012-04-27 14:29:26 +0000351
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000352}
353
robertphillips@google.comf294b772012-04-27 14:29:26 +0000354
355namespace {
356
357////////////////////////////////////////////////////////////////////////////////
358// set up the OpenGL blend function to perform the specified
359// boolean operation for alpha clip mask creation
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000360void setup_boolean_blendcoeffs(GrDrawState* drawState, SkRegion::Op op) {
robertphillips@google.comf294b772012-04-27 14:29:26 +0000361
362 switch (op) {
363 case SkRegion::kReplace_Op:
364 drawState->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
365 break;
366 case SkRegion::kIntersect_Op:
367 drawState->setBlendFunc(kDC_BlendCoeff, kZero_BlendCoeff);
368 break;
369 case SkRegion::kUnion_Op:
370 drawState->setBlendFunc(kOne_BlendCoeff, kISC_BlendCoeff);
371 break;
372 case SkRegion::kXOR_Op:
373 drawState->setBlendFunc(kIDC_BlendCoeff, kISC_BlendCoeff);
374 break;
375 case SkRegion::kDifference_Op:
376 drawState->setBlendFunc(kZero_BlendCoeff, kISC_BlendCoeff);
377 break;
378 case SkRegion::kReverseDifference_Op:
379 drawState->setBlendFunc(kIDC_BlendCoeff, kZero_BlendCoeff);
380 break;
381 default:
382 GrAssert(false);
383 break;
384 }
385}
386
387}
388
389////////////////////////////////////////////////////////////////////////////////
390bool GrClipMaskManager::drawPath(GrGpu* gpu,
bsalomon@google.com8d033a12012-04-27 15:52:53 +0000391 const SkPath& path,
robertphillips@google.comf294b772012-04-27 14:29:26 +0000392 GrPathFill fill,
393 bool doAA) {
394
395 GrPathRenderer* pr = this->getClipPathRenderer(gpu, path, fill, doAA);
396 if (NULL == pr) {
397 return false;
398 }
399
400 pr->drawPath(path, fill, NULL, gpu, 0, doAA);
401 return true;
402}
403
404////////////////////////////////////////////////////////////////////////////////
405bool GrClipMaskManager::drawClipShape(GrGpu* gpu,
406 GrTexture* target,
407 const GrClip& clipIn,
408 int index) {
409 GrDrawState* drawState = gpu->drawState();
410 GrAssert(NULL != drawState);
411
412 drawState->setRenderTarget(target->asRenderTarget());
413
414 if (kRect_ClipType == clipIn.getElementType(index)) {
415 if (clipIn.getDoAA(index)) {
416 // convert the rect to a path for AA
417 SkPath temp;
418 temp.addRect(clipIn.getRect(index));
419
420 return this->drawPath(gpu, temp,
421 kEvenOdd_PathFill, clipIn.getDoAA(index));
422 } else {
423 gpu->drawSimpleRect(clipIn.getRect(index), NULL, 0);
424 }
425 } else {
426 return this->drawPath(gpu,
427 clipIn.getPath(index),
428 clipIn.getPathFill(index),
429 clipIn.getDoAA(index));
430 }
431 return true;
432}
433
434void GrClipMaskManager::drawTexture(GrGpu* gpu,
435 GrTexture* target,
robertphillips@google.comf294b772012-04-27 14:29:26 +0000436 GrTexture* texture) {
437 GrDrawState* drawState = gpu->drawState();
438 GrAssert(NULL != drawState);
439
440 // no AA here since it is encoded in the texture
441 drawState->setRenderTarget(target->asRenderTarget());
442
443 GrMatrix sampleM;
444 sampleM.setIDiv(texture->width(), texture->height());
445 drawState->setTexture(0, texture);
446
447 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
448 GrSamplerState::kNearest_Filter,
449 sampleM);
450
robertphillips@google.comf105b102012-05-14 12:18:26 +0000451 GrRect rect = GrRect::MakeWH(SkIntToScalar(target->width()),
452 SkIntToScalar(target->height()));
453
robertphillips@google.comf294b772012-04-27 14:29:26 +0000454 gpu->drawSimpleRect(rect, NULL, 1 << 0);
455
456 drawState->setTexture(0, NULL);
457}
458
459namespace {
460
461void clear(GrGpu* gpu,
462 GrTexture* target,
robertphillips@google.comf294b772012-04-27 14:29:26 +0000463 GrColor color) {
464 GrDrawState* drawState = gpu->drawState();
465 GrAssert(NULL != drawState);
466
467 // zap entire target to specified color
468 drawState->setRenderTarget(target->asRenderTarget());
469 gpu->clear(NULL, color);
470}
471
robertphillips@google.comf105b102012-05-14 12:18:26 +0000472}
473
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000474// get a texture to act as a temporary buffer for AA clip boolean operations
475// TODO: given the expense of createTexture we may want to just cache this too
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000476void GrClipMaskManager::getTemp(const GrIRect& bounds,
robertphillips@google.comf105b102012-05-14 12:18:26 +0000477 GrAutoScratchTexture* temp) {
478 if (NULL != temp->texture()) {
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000479 // we've already allocated the temp texture
480 return;
481 }
482
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000483 const GrTextureDesc desc = {
484 kRenderTarget_GrTextureFlagBit|kNoStencil_GrTextureFlagBit,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000485 bounds.width(),
486 bounds.height(),
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000487 kAlpha_8_GrPixelConfig,
488 0 // samples
489 };
490
robertphillips@google.comf105b102012-05-14 12:18:26 +0000491 temp->set(fAACache.getContext(), desc);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000492}
493
robertphillips@google.comf105b102012-05-14 12:18:26 +0000494
495void GrClipMaskManager::setupCache(const GrClip& clipIn,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000496 const GrIRect& bounds) {
robertphillips@google.comf105b102012-05-14 12:18:26 +0000497 // Since we are setting up the cache we know the last lookup was a miss
498 // Free up the currently cached mask so it can be reused
499 fAACache.reset();
500
501 const GrTextureDesc desc = {
502 kRenderTarget_GrTextureFlagBit|kNoStencil_GrTextureFlagBit,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000503 bounds.width(),
504 bounds.height(),
robertphillips@google.comf105b102012-05-14 12:18:26 +0000505 kAlpha_8_GrPixelConfig,
506 0 // samples
507 };
508
509 fAACache.acquireMask(clipIn, desc, bounds);
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000510}
511
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000512////////////////////////////////////////////////////////////////////////////////
513// Shared preamble between gpu and SW-only AA clip mask creation paths.
514// Handles caching, determination of clip mask bound & allocation (if needed)
515// of the result texture
516// Returns true if there is no more work to be done (i.e., we got a cache hit)
517bool GrClipMaskManager::clipMaskPreamble(GrGpu* gpu,
518 const GrClip& clipIn,
519 GrTexture** result,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000520 GrIRect *resultBounds) {
robertphillips@google.comf294b772012-04-27 14:29:26 +0000521 GrDrawState* origDrawState = gpu->drawState();
522 GrAssert(origDrawState->isClipState());
523
524 GrRenderTarget* rt = origDrawState->getRenderTarget();
525 GrAssert(NULL != rt);
526
527 GrRect rtRect;
528 rtRect.setLTRB(0, 0,
529 GrIntToScalar(rt->width()), GrIntToScalar(rt->height()));
530
531 // unlike the stencil path the alpha path is not bound to the size of the
532 // render target - determine the minimum size required for the mask
533 GrRect bounds;
534
535 if (clipIn.hasConservativeBounds()) {
536 bounds = clipIn.getConservativeBounds();
537 if (!bounds.intersect(rtRect)) {
538 // the mask will be empty in this case
539 GrAssert(false);
540 bounds.setEmpty();
541 }
542 } else {
543 // still locked to the size of the render target
544 bounds = rtRect;
545 }
546
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000547 GrIRect intBounds;
548 bounds.roundOut(&intBounds);
robertphillips@google.comf294b772012-04-27 14:29:26 +0000549
550 // need to outset a pixel since the standard bounding box computation
551 // path doesn't leave any room for antialiasing (esp. w.r.t. rects)
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000552 intBounds.outset(1, 1);
robertphillips@google.comf294b772012-04-27 14:29:26 +0000553
robertphillips@google.coma72eef32012-05-01 17:22:59 +0000554 // TODO: make sure we don't outset if bounds are still 0,0 @ min
555
robertphillips@google.com8fff3562012-05-11 12:53:50 +0000556 if (fAACache.canReuse(clipIn,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000557 intBounds.width(),
558 intBounds.height())) {
robertphillips@google.com8fff3562012-05-11 12:53:50 +0000559 *result = fAACache.getLastMask();
560 fAACache.getLastBound(resultBounds);
561 return true;
562 }
563
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000564 this->setupCache(clipIn, intBounds);
robertphillips@google.comf105b102012-05-14 12:18:26 +0000565
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000566 *resultBounds = intBounds;
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000567 return false;
568}
robertphillips@google.comf294b772012-04-27 14:29:26 +0000569
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000570////////////////////////////////////////////////////////////////////////////////
571// Create a 8-bit clip mask in alpha
572bool GrClipMaskManager::createAlphaClipMask(GrGpu* gpu,
573 const GrClip& clipIn,
574 GrTexture** result,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000575 GrIRect *resultBounds) {
robertphillips@google.comf294b772012-04-27 14:29:26 +0000576
robertphillips@google.comf105b102012-05-14 12:18:26 +0000577 if (this->clipMaskPreamble(gpu, clipIn, result, resultBounds)) {
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000578 return true;
579 }
580
robertphillips@google.comf105b102012-05-14 12:18:26 +0000581 GrTexture* accum = fAACache.getLastMask();
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000582 if (NULL == accum) {
robertphillips@google.comf294b772012-04-27 14:29:26 +0000583 fClipMaskInAlpha = false;
robertphillips@google.comf105b102012-05-14 12:18:26 +0000584 fAACache.reset();
robertphillips@google.comf294b772012-04-27 14:29:26 +0000585 return false;
586 }
587
588 GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
589 GrDrawState* drawState = gpu->drawState();
590
591 GrDrawTarget::AutoGeometryPush agp(gpu);
592
593 int count = clipIn.getElementCount();
594
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000595 if (0 != resultBounds->fTop || 0 != resultBounds->fLeft) {
robertphillips@google.comf294b772012-04-27 14:29:26 +0000596 // if we were able to trim down the size of the mask we need to
597 // offset the paths & rects that will be used to compute it
598 GrMatrix m;
599
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000600 m.setTranslate(SkIntToScalar(-resultBounds->fLeft),
601 SkIntToScalar(-resultBounds->fTop));
robertphillips@google.comf294b772012-04-27 14:29:26 +0000602
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000603 drawState->setViewMatrix(m);
robertphillips@google.comf294b772012-04-27 14:29:26 +0000604 }
605
606 bool clearToInside;
607 SkRegion::Op startOp = SkRegion::kReplace_Op; // suppress warning
608 int start = process_initial_clip_elements(clipIn,
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000609 *resultBounds,
robertphillips@google.comf294b772012-04-27 14:29:26 +0000610 &clearToInside,
611 &startOp);
612
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000613 clear(gpu, accum, clearToInside ? 0xffffffff : 0x00000000);
robertphillips@google.comf294b772012-04-27 14:29:26 +0000614
robertphillips@google.comf105b102012-05-14 12:18:26 +0000615 GrAutoScratchTexture temp;
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000616
robertphillips@google.comf294b772012-04-27 14:29:26 +0000617 // walk through each clip element and perform its set op
618 for (int c = start; c < count; ++c) {
619
620 SkRegion::Op op = (c == start) ? startOp : clipIn.getOp(c);
621
622 if (SkRegion::kReplace_Op == op) {
623 // TODO: replace is actually a lot faster then intersection
624 // for this path - refactor the stencil path so it can handle
625 // replace ops and alter GrClip to allow them through
626
627 // clear the accumulator and draw the new object directly into it
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000628 clear(gpu, accum, 0x00000000);
robertphillips@google.comf294b772012-04-27 14:29:26 +0000629
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000630 setup_boolean_blendcoeffs(drawState, op);
robertphillips@google.comf294b772012-04-27 14:29:26 +0000631 this->drawClipShape(gpu, accum, clipIn, c);
632
633 } else if (SkRegion::kReverseDifference_Op == op ||
634 SkRegion::kIntersect_Op == op) {
635 // there is no point in intersecting a screen filling rectangle.
636 if (SkRegion::kIntersect_Op == op &&
637 kRect_ClipType == clipIn.getElementType(c) &&
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000638 contains(clipIn.getRect(c), *resultBounds)) {
robertphillips@google.comf294b772012-04-27 14:29:26 +0000639 continue;
640 }
641
robertphillips@google.comf105b102012-05-14 12:18:26 +0000642 getTemp(*resultBounds, &temp);
643 if (NULL == temp.texture()) {
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000644 fClipMaskInAlpha = false;
robertphillips@google.comf105b102012-05-14 12:18:26 +0000645 fAACache.reset();
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000646 return false;
647 }
648
robertphillips@google.comf294b772012-04-27 14:29:26 +0000649 // clear the temp target & draw into it
robertphillips@google.comf105b102012-05-14 12:18:26 +0000650 clear(gpu, temp.texture(), 0x00000000);
robertphillips@google.comf294b772012-04-27 14:29:26 +0000651
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000652 setup_boolean_blendcoeffs(drawState, SkRegion::kReplace_Op);
robertphillips@google.comf105b102012-05-14 12:18:26 +0000653 this->drawClipShape(gpu, temp.texture(), clipIn, c);
robertphillips@google.comf294b772012-04-27 14:29:26 +0000654
655 // TODO: rather than adding these two translations here
656 // compute the bounding box needed to render the texture
657 // into temp
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000658 if (0 != resultBounds->fTop || 0 != resultBounds->fLeft) {
robertphillips@google.comf294b772012-04-27 14:29:26 +0000659 GrMatrix m;
660
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000661 m.setTranslate(SkIntToScalar(resultBounds->fLeft),
662 SkIntToScalar(resultBounds->fTop));
robertphillips@google.comf294b772012-04-27 14:29:26 +0000663
664 drawState->preConcatViewMatrix(m);
665 }
666
667 // Now draw into the accumulator using the real operation
668 // and the temp buffer as a texture
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000669 setup_boolean_blendcoeffs(drawState, op);
robertphillips@google.comf105b102012-05-14 12:18:26 +0000670 this->drawTexture(gpu, accum, temp.texture());
robertphillips@google.comf294b772012-04-27 14:29:26 +0000671
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000672 if (0 != resultBounds->fTop || 0 != resultBounds->fLeft) {
robertphillips@google.comf294b772012-04-27 14:29:26 +0000673 GrMatrix m;
674
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000675 m.setTranslate(SkIntToScalar(-resultBounds->fLeft),
676 SkIntToScalar(-resultBounds->fTop));
robertphillips@google.comf294b772012-04-27 14:29:26 +0000677
678 drawState->preConcatViewMatrix(m);
679 }
680
681 } else {
682 // all the remaining ops can just be directly draw into
683 // the accumulation buffer
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000684 setup_boolean_blendcoeffs(drawState, op);
robertphillips@google.comf294b772012-04-27 14:29:26 +0000685 this->drawClipShape(gpu, accum, clipIn, c);
686 }
687 }
688
robertphillips@google.coma72eef32012-05-01 17:22:59 +0000689 *result = accum;
robertphillips@google.com6d62df42012-05-07 18:07:36 +0000690
robertphillips@google.comf294b772012-04-27 14:29:26 +0000691 return true;
692}
693
694////////////////////////////////////////////////////////////////////////////////
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000695// Create a 1-bit clip mask in the stencil buffer
696bool GrClipMaskManager::createStencilClipMask(GrGpu* gpu,
697 const GrClip& clipIn,
698 const GrRect& bounds,
699 ScissoringSettings* scissorSettings) {
700
701 GrAssert(fClipMaskInStencil);
702
703 GrDrawState* drawState = gpu->drawState();
704 GrAssert(drawState->isClipState());
705
706 GrRenderTarget* rt = drawState->getRenderTarget();
707 GrAssert(NULL != rt);
708
709 // TODO: dynamically attach a SB when needed.
710 GrStencilBuffer* stencilBuffer = rt->getStencilBuffer();
711 if (NULL == stencilBuffer) {
712 return false;
713 }
714
715 if (stencilBuffer->mustRenderClip(clipIn, rt->width(), rt->height())) {
716
717 stencilBuffer->setLastClip(clipIn, rt->width(), rt->height());
718
719 // we set the current clip to the bounds so that our recursive
720 // draws are scissored to them. We use the copy of the complex clip
721 // we just stashed on the SB to render from. We set it back after
722 // we finish drawing it into the stencil.
723 const GrClip& clipCopy = stencilBuffer->getLastClip();
724 gpu->setClip(GrClip(bounds));
725
726 GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
727 drawState = gpu->drawState();
728 drawState->setRenderTarget(rt);
729 GrDrawTarget::AutoGeometryPush agp(gpu);
730
731 gpu->disableScissor();
732#if !VISUALIZE_COMPLEX_CLIP
733 drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
734#endif
735
736 int count = clipCopy.getElementCount();
737 int clipBit = stencilBuffer->bits();
738 SkASSERT((clipBit <= 16) &&
739 "Ganesh only handles 16b or smaller stencil buffers");
740 clipBit = (1 << (clipBit-1));
741
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000742 GrIRect rtRect = GrIRect::MakeWH(rt->width(), rt->height());
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000743
744 bool clearToInside;
robertphillips@google.com0f191f32012-04-25 15:23:36 +0000745 SkRegion::Op startOp = SkRegion::kReplace_Op; // suppress warning
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000746 int start = process_initial_clip_elements(clipCopy,
747 rtRect,
748 &clearToInside,
749 &startOp);
750
751 gpu->clearStencilClip(scissorSettings->fScissorRect, clearToInside);
752
753 // walk through each clip element and perform its set op
754 // with the existing clip.
755 for (int c = start; c < count; ++c) {
756 GrPathFill fill;
757 bool fillInverted;
758 // enabled at bottom of loop
759 drawState->disableState(GrGpu::kModifyStencilClip_StateBit);
760
761 bool canRenderDirectToStencil; // can the clip element be drawn
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000762 // directly to the stencil buffer
763 // with a non-inverted fill rule
764 // without extra passes to
765 // resolve in/out status.
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000766
robertphillips@google.comf294b772012-04-27 14:29:26 +0000767 SkRegion::Op op = (c == start) ? startOp : clipCopy.getOp(c);
768
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000769 GrPathRenderer* pr = NULL;
bsalomon@google.com8d033a12012-04-27 15:52:53 +0000770 const SkPath* clipPath = NULL;
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000771 if (kRect_ClipType == clipCopy.getElementType(c)) {
772 canRenderDirectToStencil = true;
773 fill = kEvenOdd_PathFill;
774 fillInverted = false;
775 // there is no point in intersecting a screen filling
776 // rectangle.
robertphillips@google.comf294b772012-04-27 14:29:26 +0000777 if (SkRegion::kIntersect_Op == op &&
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000778 contains(clipCopy.getRect(c), rtRect)) {
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000779 continue;
780 }
781 } else {
782 fill = clipCopy.getPathFill(c);
783 fillInverted = GrIsFillInverted(fill);
784 fill = GrNonInvertedFill(fill);
785 clipPath = &clipCopy.getPath(c);
robertphillips@google.comf294b772012-04-27 14:29:26 +0000786 pr = this->getClipPathRenderer(gpu, *clipPath, fill, false);
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000787 if (NULL == pr) {
788 fClipMaskInStencil = false;
789 gpu->setClip(clipCopy); // restore to the original
790 return false;
791 }
792 canRenderDirectToStencil =
793 !pr->requiresStencilPass(*clipPath, fill, gpu);
794 }
795
robertphillips@google.com1e945b72012-04-16 18:03:03 +0000796 int passes;
797 GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
798
799 bool canDrawDirectToClip; // Given the renderer, the element,
800 // fill rule, and set operation can
801 // we render the element directly to
802 // stencil bit used for clipping.
803 canDrawDirectToClip =
804 GrStencilSettings::GetClipPasses(op,
805 canRenderDirectToStencil,
806 clipBit,
807 fillInverted,
808 &passes, stencilSettings);
809
810 // draw the element to the client stencil bits if necessary
811 if (!canDrawDirectToClip) {
812 GR_STATIC_CONST_SAME_STENCIL(gDrawToStencil,
813 kIncClamp_StencilOp,
814 kIncClamp_StencilOp,
815 kAlways_StencilFunc,
816 0xffff,
817 0x0000,
818 0xffff);
819 SET_RANDOM_COLOR
820 if (kRect_ClipType == clipCopy.getElementType(c)) {
821 *drawState->stencil() = gDrawToStencil;
822 gpu->drawSimpleRect(clipCopy.getRect(c), NULL, 0);
823 } else {
824 if (canRenderDirectToStencil) {
825 *drawState->stencil() = gDrawToStencil;
826 pr->drawPath(*clipPath, fill, NULL, gpu, 0, false);
827 } else {
828 pr->drawPathToStencil(*clipPath, fill, gpu);
829 }
830 }
831 }
832
833 // now we modify the clip bit by rendering either the clip
834 // element directly or a bounding rect of the entire clip.
835 drawState->enableState(GrGpu::kModifyStencilClip_StateBit);
836 for (int p = 0; p < passes; ++p) {
837 *drawState->stencil() = stencilSettings[p];
838 if (canDrawDirectToClip) {
839 if (kRect_ClipType == clipCopy.getElementType(c)) {
840 SET_RANDOM_COLOR
841 gpu->drawSimpleRect(clipCopy.getRect(c), NULL, 0);
842 } else {
843 SET_RANDOM_COLOR
844 pr->drawPath(*clipPath, fill, NULL, gpu, 0, false);
845 }
846 } else {
847 SET_RANDOM_COLOR
848 gpu->drawSimpleRect(bounds, NULL, 0);
849 }
850 }
851 }
852 // restore clip
853 gpu->setClip(clipCopy);
854 // recusive draws would have disabled this since they drew with
855 // the clip bounds as clip.
856 fClipMaskInStencil = true;
857 }
858
859 return true;
860}
861
robertphillips@google.comfa662942012-05-17 12:20:22 +0000862namespace {
863
864GrPathFill invert_fill(GrPathFill fill) {
865 static const GrPathFill gInvertedFillTable[] = {
866 kInverseWinding_PathFill, // kWinding_PathFill
867 kInverseEvenOdd_PathFill, // kEvenOdd_PathFill
868 kWinding_PathFill, // kInverseWinding_PathFill
869 kEvenOdd_PathFill, // kInverseEvenOdd_PathFill
870 kHairLine_PathFill, // kHairLine_PathFill
871 };
872 GR_STATIC_ASSERT(0 == kWinding_PathFill);
873 GR_STATIC_ASSERT(1 == kEvenOdd_PathFill);
874 GR_STATIC_ASSERT(2 == kInverseWinding_PathFill);
875 GR_STATIC_ASSERT(3 == kInverseEvenOdd_PathFill);
876 GR_STATIC_ASSERT(4 == kHairLine_PathFill);
877 GR_STATIC_ASSERT(5 == kPathFillCount);
878 return gInvertedFillTable[fill];
879}
880
881}
882
robertphillips@google.comf294b772012-04-27 14:29:26 +0000883////////////////////////////////////////////////////////////////////////////////
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000884bool GrClipMaskManager::createSoftwareClipMask(GrGpu* gpu,
885 const GrClip& clipIn,
886 GrTexture** result,
robertphillips@google.com6623fcd2012-05-15 16:47:23 +0000887 GrIRect *resultBounds) {
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000888
robertphillips@google.comf105b102012-05-14 12:18:26 +0000889 if (this->clipMaskPreamble(gpu, clipIn, result, resultBounds)) {
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000890 return true;
891 }
892
robertphillips@google.comf105b102012-05-14 12:18:26 +0000893 GrTexture* accum = fAACache.getLastMask();
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000894 if (NULL == accum) {
895 fClipMaskInAlpha = false;
robertphillips@google.comf105b102012-05-14 12:18:26 +0000896 fAACache.reset();
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000897 return false;
898 }
899
robertphillips@google.comfa662942012-05-17 12:20:22 +0000900 GrSWMaskHelper helper(fAACache.getContext());
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000901
robertphillips@google.comfa662942012-05-17 12:20:22 +0000902 helper.init(*resultBounds, NULL, false);
903
904 int count = clipIn.getElementCount();
905
906 bool clearToInside;
907 SkRegion::Op startOp = SkRegion::kReplace_Op; // suppress warning
908 int start = process_initial_clip_elements(clipIn,
909 *resultBounds,
910 &clearToInside,
911 &startOp);
912
913 helper.clear(clearToInside ? SK_ColorWHITE : 0x00000000);
914
915 for (int i = start; i < count; ++i) {
916
917 SkRegion::Op op = (i == start) ? startOp : clipIn.getOp(i);
918
919 if (SkRegion::kIntersect_Op == op ||
920 SkRegion::kReverseDifference_Op == op) {
921 // Intersect and reverse difference require modifying pixels
922 // outside of the geometry that is being "drawn". In both cases
923 // we erase all the pixels outside of the geometry but
924 // leave the pixels inside the geometry alone. For reverse
925 // difference we invert all the pixels before clearing the ones
926 // outside the geometry.
927 if (SkRegion::kReverseDifference_Op == op) {
928 SkRect temp = SkRect::MakeLTRB(
929 SkIntToScalar(resultBounds->left()),
930 SkIntToScalar(resultBounds->top()),
931 SkIntToScalar(resultBounds->right()),
932 SkIntToScalar(resultBounds->bottom()));
933
934 // invert the entire scene
935 helper.draw(temp, SkRegion::kXOR_Op, false, SK_ColorWHITE);
936 }
937
938 if (kRect_ClipType == clipIn.getElementType(i)) {
939
940 // convert the rect to a path so we can invert the fill
941 SkPath temp;
942 temp.addRect(clipIn.getRect(i));
943
944 helper.draw(temp, SkRegion::kReplace_Op,
945 kInverseEvenOdd_PathFill, clipIn.getDoAA(i),
946 0x00000000);
947 } else {
948 GrAssert(kPath_ClipType == clipIn.getElementType(i));
949
950 helper.draw(clipIn.getPath(i),
951 SkRegion::kReplace_Op,
952 invert_fill(clipIn.getPathFill(i)),
953 clipIn.getDoAA(i),
954 0x00000000);
955 }
956
957 continue;
958 }
959
960 // The other ops (union, xor, diff) only affect pixels inside
961 // the geometry so they can just be drawn normally
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000962 if (kRect_ClipType == clipIn.getElementType(i)) {
robertphillips@google.comfa662942012-05-17 12:20:22 +0000963
964 helper.draw(clipIn.getRect(i),
965 op,
966 clipIn.getDoAA(i), SK_ColorWHITE);
967
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000968 } else {
969 GrAssert(kPath_ClipType == clipIn.getElementType(i));
970
robertphillips@google.comfa662942012-05-17 12:20:22 +0000971 helper.draw(clipIn.getPath(i),
972 op,
973 clipIn.getPathFill(i),
974 clipIn.getDoAA(i), SK_ColorWHITE);
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000975 }
976 }
977
robertphillips@google.comfa662942012-05-17 12:20:22 +0000978 // Because we are using the scratch texture cache, "accum" may be
979 // larger than expected and have some cruft in the areas we aren't using.
980 // Clear it out.
981
982 // TODO: need a simpler way to clear the texture - can we combine
983 // the clear and the writePixels (inside toTexture)
984 GrDrawState* drawState = gpu->drawState();
985 GrAssert(NULL != drawState);
986 GrRenderTarget* temp = drawState->getRenderTarget();
987 clear(gpu, accum, 0x00000000);
988 // can't leave the accum bound as a rendertarget
989 drawState->setRenderTarget(temp);
990
991 helper.toTexture(accum);
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000992
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000993 *result = accum;
robertphillips@google.com6b70a7b2012-05-11 15:32:48 +0000994
995 return true;
996}
997
998
999////////////////////////////////////////////////////////////////////////////////
robertphillips@google.com1e945b72012-04-16 18:03:03 +00001000GrPathRenderer* GrClipMaskManager::getClipPathRenderer(GrGpu* gpu,
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001001 const SkPath& path,
robertphillips@google.comf294b772012-04-27 14:29:26 +00001002 GrPathFill fill,
1003 bool antiAlias) {
robertphillips@google.com1e945b72012-04-16 18:03:03 +00001004 if (NULL == fPathRendererChain) {
1005 fPathRendererChain =
1006 new GrPathRendererChain(gpu->getContext(),
robertphillips@google.comf294b772012-04-27 14:29:26 +00001007 GrPathRendererChain::kNone_UsageFlag);
robertphillips@google.com1e945b72012-04-16 18:03:03 +00001008 }
robertphillips@google.comf294b772012-04-27 14:29:26 +00001009 return fPathRendererChain->getPathRenderer(path, fill, gpu, antiAlias);
robertphillips@google.com1e945b72012-04-16 18:03:03 +00001010}
1011
robertphillips@google.comf294b772012-04-27 14:29:26 +00001012////////////////////////////////////////////////////////////////////////////////
robertphillips@google.comf105b102012-05-14 12:18:26 +00001013void GrClipMaskManager::releaseResources() {
robertphillips@google.com1e945b72012-04-16 18:03:03 +00001014 // in case path renderer has any GrResources, start from scratch
1015 GrSafeSetNull(fPathRendererChain);
robertphillips@google.comf105b102012-05-14 12:18:26 +00001016 fAACache.releaseResources();
robertphillips@google.com1e945b72012-04-16 18:03:03 +00001017}