diff options
author | robertphillips@google.com <robertphillips@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-04-16 18:03:03 +0000 |
---|---|---|
committer | robertphillips@google.com <robertphillips@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-04-16 18:03:03 +0000 |
commit | 1e945b7e708c633d4aed937ebfce57d52ba21d83 (patch) | |
tree | 1d27847d9e7a6f32137b6a3025c5d17f58a8c2c8 | |
parent | 13eaaaa75a16fa300fa212ec910107f77530ef2c (diff) |
Minor refactoring to pull GrClipMaskManager into its own files
http://codereview.appspot.com/5978055/
git-svn-id: http://skia.googlecode.com/svn/trunk@3697 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r-- | gyp/gpu.gyp | 2 | ||||
-rw-r--r-- | src/gpu/GrClipMaskManager.cpp | 359 | ||||
-rw-r--r-- | src/gpu/GrClipMaskManager.h | 81 | ||||
-rw-r--r-- | src/gpu/GrGpu.cpp | 351 | ||||
-rw-r--r-- | src/gpu/GrGpu.h | 61 |
5 files changed, 443 insertions, 411 deletions
diff --git a/gyp/gpu.gyp b/gyp/gpu.gyp index 026f3b937f..fc2277e0b3 100644 --- a/gyp/gpu.gyp +++ b/gyp/gpu.gyp @@ -227,6 +227,8 @@ '../src/gpu/GrDrawTarget.cpp', '../src/gpu/GrDrawTarget.h', '../src/gpu/GrGeometryBuffer.h', + '../src/gpu/GrClipMaskManager.h', + '../src/gpu/GrClipMaskManager.cpp', '../src/gpu/GrGpu.cpp', '../src/gpu/GrGpu.h', '../src/gpu/GrGpuFactory.cpp', diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp new file mode 100644 index 0000000000..cdcc741706 --- /dev/null +++ b/src/gpu/GrClipMaskManager.cpp @@ -0,0 +1,359 @@ + +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrClipMaskManager.h" +#include "GrGpu.h" +#include "GrRenderTarget.h" +#include "GrStencilBuffer.h" +#include "GrPathRenderer.h" + +void ScissoringSettings::setupScissoring(GrGpu* gpu) { + if (!fEnableScissoring) { + gpu->disableScissor(); + return; + } + + gpu->enableScissoring(fScissorRect); +} + +// sort out what kind of clip mask needs to be created: A8/R8, stencil or scissor +bool GrClipMaskManager::createClipMask(GrGpu* gpu, + const GrClip& clipIn, + ScissoringSettings* scissorSettings) { + + GrAssert(scissorSettings); + + scissorSettings->fEnableScissoring = false; + fClipMaskInStencil = false; + + GrDrawState* drawState = gpu->drawState(); + if (!drawState->isClipState()) { + return true; + } + + GrRenderTarget* rt = drawState->getRenderTarget(); + + // GrDrawTarget should have filtered this for us + GrAssert(NULL != rt); + + GrRect bounds; + GrRect rtRect; + rtRect.setLTRB(0, 0, + GrIntToScalar(rt->width()), GrIntToScalar(rt->height())); + if (clipIn.hasConservativeBounds()) { + bounds = clipIn.getConservativeBounds(); + if (!bounds.intersect(rtRect)) { + bounds.setEmpty(); + } + } else { + bounds = rtRect; + } + + bounds.roundOut(&scissorSettings->fScissorRect); + if (scissorSettings->fScissorRect.isEmpty()) { + scissorSettings->fScissorRect.setLTRB(0,0,0,0); + // TODO: I think we can do an early exit here - after refactoring try: + // set fEnableScissoring to true but leave fClipMaskInStencil false + // and return - everything is going to be scissored away anyway! + } + scissorSettings->fEnableScissoring = true; + + // use the stencil clip if we can't represent the clip as a rectangle. + fClipMaskInStencil = !clipIn.isRect() && !clipIn.isEmpty() && + !bounds.isEmpty(); + + if (fClipMaskInStencil) { + return this->createStencilClipMask(gpu, clipIn, bounds, scissorSettings); + } + + return true; +} + +#define VISUALIZE_COMPLEX_CLIP 0 + +#if VISUALIZE_COMPLEX_CLIP + #include "GrRandom.h" + GrRandom gRandom; + #define SET_RANDOM_COLOR drawState->setColor(0xff000000 | gRandom.nextU()); +#else + #define SET_RANDOM_COLOR +#endif + +namespace { +// determines how many elements at the head of the clip can be skipped and +// whether the initial clear should be to the inside- or outside-the-clip value, +// and what op should be used to draw the first element that isn't skipped. +int process_initial_clip_elements(const GrClip& clip, + const GrRect& bounds, + bool* clearToInside, + GrSetOp* startOp) { + + // logically before the first element of the clip stack is + // processed the clip is entirely open. However, depending on the + // first set op we may prefer to clear to 0 for performance. We may + // also be able to skip the initial clip paths/rects. We loop until + // we cannot skip an element. + int curr; + bool done = false; + *clearToInside = true; + int count = clip.getElementCount(); + + for (curr = 0; curr < count && !done; ++curr) { + switch (clip.getOp(curr)) { + case kReplace_SetOp: + // replace ignores everything previous + *startOp = kReplace_SetOp; + *clearToInside = false; + done = true; + break; + case kIntersect_SetOp: + // if this element contains the entire bounds then we + // can skip it. + if (kRect_ClipType == clip.getElementType(curr) + && clip.getRect(curr).contains(bounds)) { + break; + } + // if everything is initially clearToInside then intersect is + // same as clear to 0 and treat as a replace. Otherwise, + // set stays empty. + if (*clearToInside) { + *startOp = kReplace_SetOp; + *clearToInside = false; + done = true; + } + break; + // we can skip a leading union. + case kUnion_SetOp: + // if everything is initially outside then union is + // same as replace. Otherwise, every pixel is still + // clearToInside + if (!*clearToInside) { + *startOp = kReplace_SetOp; + done = true; + } + break; + case kXor_SetOp: + // xor is same as difference or replace both of which + // can be 1-pass instead of 2 for xor. + if (*clearToInside) { + *startOp = kDifference_SetOp; + } else { + *startOp = kReplace_SetOp; + } + done = true; + break; + case kDifference_SetOp: + // if all pixels are clearToInside then we have to process the + // difference, otherwise it has no effect and all pixels + // remain outside. + if (*clearToInside) { + *startOp = kDifference_SetOp; + done = true; + } + break; + case kReverseDifference_SetOp: + // if all pixels are clearToInside then reverse difference + // produces empty set. Otherise it is same as replace + if (*clearToInside) { + *clearToInside = false; + } else { + *startOp = kReplace_SetOp; + done = true; + } + break; + default: + GrCrash("Unknown set op."); + } + } + return done ? curr-1 : count; +} +} + +// Create a 1-bit clip mask in the stencil buffer +bool GrClipMaskManager::createStencilClipMask(GrGpu* gpu, + const GrClip& clipIn, + const GrRect& bounds, + ScissoringSettings* scissorSettings) { + + GrAssert(fClipMaskInStencil); + + GrDrawState* drawState = gpu->drawState(); + GrAssert(drawState->isClipState()); + + GrRenderTarget* rt = drawState->getRenderTarget(); + GrAssert(NULL != rt); + + // TODO: dynamically attach a SB when needed. + GrStencilBuffer* stencilBuffer = rt->getStencilBuffer(); + if (NULL == stencilBuffer) { + return false; + } + + if (stencilBuffer->mustRenderClip(clipIn, rt->width(), rt->height())) { + + stencilBuffer->setLastClip(clipIn, rt->width(), rt->height()); + + // we set the current clip to the bounds so that our recursive + // draws are scissored to them. We use the copy of the complex clip + // we just stashed on the SB to render from. We set it back after + // we finish drawing it into the stencil. + const GrClip& clipCopy = stencilBuffer->getLastClip(); + gpu->setClip(GrClip(bounds)); + + GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit); + drawState = gpu->drawState(); + drawState->setRenderTarget(rt); + GrDrawTarget::AutoGeometryPush agp(gpu); + + gpu->disableScissor(); +#if !VISUALIZE_COMPLEX_CLIP + drawState->enableState(GrDrawState::kNoColorWrites_StateBit); +#endif + + int count = clipCopy.getElementCount(); + int clipBit = stencilBuffer->bits(); + SkASSERT((clipBit <= 16) && + "Ganesh only handles 16b or smaller stencil buffers"); + clipBit = (1 << (clipBit-1)); + + GrRect rtRect; + rtRect.setLTRB(0, 0, + GrIntToScalar(rt->width()), GrIntToScalar(rt->height())); + + bool clearToInside; + GrSetOp startOp = kReplace_SetOp; // suppress warning + int start = process_initial_clip_elements(clipCopy, + rtRect, + &clearToInside, + &startOp); + + gpu->clearStencilClip(scissorSettings->fScissorRect, clearToInside); + + // walk through each clip element and perform its set op + // with the existing clip. + for (int c = start; c < count; ++c) { + GrPathFill fill; + bool fillInverted; + // enabled at bottom of loop + drawState->disableState(GrGpu::kModifyStencilClip_StateBit); + + bool canRenderDirectToStencil; // can the clip element be drawn + // directly to the stencil buffer + // with a non-inverted fill rule + // without extra passes to + // resolve in/out status. + + GrPathRenderer* pr = NULL; + const GrPath* clipPath = NULL; + if (kRect_ClipType == clipCopy.getElementType(c)) { + canRenderDirectToStencil = true; + fill = kEvenOdd_PathFill; + fillInverted = false; + // there is no point in intersecting a screen filling + // rectangle. + if (kIntersect_SetOp == clipCopy.getOp(c) && + clipCopy.getRect(c).contains(rtRect)) { + continue; + } + } else { + fill = clipCopy.getPathFill(c); + fillInverted = GrIsFillInverted(fill); + fill = GrNonInvertedFill(fill); + clipPath = &clipCopy.getPath(c); + pr = this->getClipPathRenderer(gpu, *clipPath, fill); + if (NULL == pr) { + fClipMaskInStencil = false; + gpu->setClip(clipCopy); // restore to the original + return false; + } + canRenderDirectToStencil = + !pr->requiresStencilPass(*clipPath, fill, gpu); + } + + GrSetOp op = (c == start) ? startOp : clipCopy.getOp(c); + int passes; + GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses]; + + bool canDrawDirectToClip; // Given the renderer, the element, + // fill rule, and set operation can + // we render the element directly to + // stencil bit used for clipping. + canDrawDirectToClip = + GrStencilSettings::GetClipPasses(op, + canRenderDirectToStencil, + clipBit, + fillInverted, + &passes, stencilSettings); + + // draw the element to the client stencil bits if necessary + if (!canDrawDirectToClip) { + GR_STATIC_CONST_SAME_STENCIL(gDrawToStencil, + kIncClamp_StencilOp, + kIncClamp_StencilOp, + kAlways_StencilFunc, + 0xffff, + 0x0000, + 0xffff); + SET_RANDOM_COLOR + if (kRect_ClipType == clipCopy.getElementType(c)) { + *drawState->stencil() = gDrawToStencil; + gpu->drawSimpleRect(clipCopy.getRect(c), NULL, 0); + } else { + if (canRenderDirectToStencil) { + *drawState->stencil() = gDrawToStencil; + pr->drawPath(*clipPath, fill, NULL, gpu, 0, false); + } else { + pr->drawPathToStencil(*clipPath, fill, gpu); + } + } + } + + // now we modify the clip bit by rendering either the clip + // element directly or a bounding rect of the entire clip. + drawState->enableState(GrGpu::kModifyStencilClip_StateBit); + for (int p = 0; p < passes; ++p) { + *drawState->stencil() = stencilSettings[p]; + if (canDrawDirectToClip) { + if (kRect_ClipType == clipCopy.getElementType(c)) { + SET_RANDOM_COLOR + gpu->drawSimpleRect(clipCopy.getRect(c), NULL, 0); + } else { + SET_RANDOM_COLOR + pr->drawPath(*clipPath, fill, NULL, gpu, 0, false); + } + } else { + SET_RANDOM_COLOR + gpu->drawSimpleRect(bounds, NULL, 0); + } + } + } + // restore clip + gpu->setClip(clipCopy); + // recusive draws would have disabled this since they drew with + // the clip bounds as clip. + fClipMaskInStencil = true; + } + + return true; +} + +GrPathRenderer* GrClipMaskManager::getClipPathRenderer(GrGpu* gpu, + const GrPath& path, + GrPathFill fill) { + if (NULL == fPathRendererChain) { + fPathRendererChain = + new GrPathRendererChain(gpu->getContext(), + GrPathRendererChain::kNonAAOnly_UsageFlag); + } + return fPathRendererChain->getPathRenderer(path, fill, gpu, false); +} + +void GrClipMaskManager::freeResources() { + // in case path renderer has any GrResources, start from scratch + GrSafeSetNull(fPathRendererChain); +} diff --git a/src/gpu/GrClipMaskManager.h b/src/gpu/GrClipMaskManager.h new file mode 100644 index 0000000000..d3f0d159e9 --- /dev/null +++ b/src/gpu/GrClipMaskManager.h @@ -0,0 +1,81 @@ + +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrClipMaskManager_DEFINED +#define GrClipMaskManager_DEFINED + +#include "GrRect.h" + +class GrGpu; +class GrClip; +class GrPathRenderer; +class GrPathRendererChain; +class SkPath; + +/** + * Scissoring needs special handling during stencil clip mask creation + * since the creation process re-entrantly invokes setupClipAndFlushState. + * During this process the call stack is used to keep + * track of (and apply to the GPU) the current scissor settings. + */ +struct ScissoringSettings { + bool fEnableScissoring; + GrIRect fScissorRect; + + void setupScissoring(GrGpu* gpu); +}; + + +/** + * The clip mask creator handles the generation of the clip mask. If anti + * aliasing is requested it will (in the future) generate a single channel + * (8bit) mask. If no anti aliasing is requested it will generate a 1-bit + * mask in the stencil buffer. In the non anti-aliasing case, if the clip + * mask can be represented as a rectangle then scissoring is used. In all + * cases scissoring is used to bound the range of the clip mask. + */ +class GrClipMaskManager { +public: + GrClipMaskManager() + : fClipMaskInStencil(false) + , fPathRendererChain(NULL) { + } + + bool createClipMask(GrGpu* gpu, + const GrClip& clip, + ScissoringSettings* scissorSettings); + + void freeResources(); + + bool isClipInStencil() const { return fClipMaskInStencil; } + + void resetMask() { + fClipMaskInStencil = false; + } + +protected: +private: + bool fClipMaskInStencil; // is the clip mask in the stencil buffer? + + // must be instantiated after GrGpu object has been given its owning + // GrContext ptr. (GrGpu is constructed first then handed off to GrContext). + GrPathRendererChain* fPathRendererChain; + + bool createStencilClipMask(GrGpu* gpu, + const GrClip& clip, + const GrRect& bounds, + ScissoringSettings* scissorSettings); + + // determines the path renderer used to draw a clip path element. + GrPathRenderer* getClipPathRenderer(GrGpu* gpu, + const SkPath& path, + GrPathFill fill); + +}; + +#endif // GrClipMaskManager_DEFINED diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp index 4acb4f6f3e..a5c7284ce8 100644 --- a/src/gpu/GrGpu.cpp +++ b/src/gpu/GrGpu.cpp @@ -13,7 +13,6 @@ #include "GrClipIterator.h" #include "GrContext.h" #include "GrIndexBuffer.h" -#include "GrPathRenderer.h" #include "GrStencilBuffer.h" #include "GrVertexBuffer.h" @@ -441,329 +440,6 @@ void GrGpu::ConvertStencilFuncAndMask(GrStencilFunc func, //////////////////////////////////////////////////////////////////////////////// -#define VISUALIZE_COMPLEX_CLIP 0 - -#if VISUALIZE_COMPLEX_CLIP - #include "GrRandom.h" - GrRandom gRandom; - #define SET_RANDOM_COLOR drawState->setColor(0xff000000 | gRandom.nextU()); -#else - #define SET_RANDOM_COLOR -#endif - -namespace { -// determines how many elements at the head of the clip can be skipped and -// whether the initial clear should be to the inside- or outside-the-clip value, -// and what op should be used to draw the first element that isn't skipped. -int process_initial_clip_elements(const GrClip& clip, - const GrRect& bounds, - bool* clearToInside, - GrSetOp* startOp) { - - // logically before the first element of the clip stack is - // processed the clip is entirely open. However, depending on the - // first set op we may prefer to clear to 0 for performance. We may - // also be able to skip the initial clip paths/rects. We loop until - // we cannot skip an element. - int curr; - bool done = false; - *clearToInside = true; - int count = clip.getElementCount(); - - for (curr = 0; curr < count && !done; ++curr) { - switch (clip.getOp(curr)) { - case kReplace_SetOp: - // replace ignores everything previous - *startOp = kReplace_SetOp; - *clearToInside = false; - done = true; - break; - case kIntersect_SetOp: - // if this element contains the entire bounds then we - // can skip it. - if (kRect_ClipType == clip.getElementType(curr) - && clip.getRect(curr).contains(bounds)) { - break; - } - // if everything is initially clearToInside then intersect is - // same as clear to 0 and treat as a replace. Otherwise, - // set stays empty. - if (*clearToInside) { - *startOp = kReplace_SetOp; - *clearToInside = false; - done = true; - } - break; - // we can skip a leading union. - case kUnion_SetOp: - // if everything is initially outside then union is - // same as replace. Otherwise, every pixel is still - // clearToInside - if (!*clearToInside) { - *startOp = kReplace_SetOp; - done = true; - } - break; - case kXor_SetOp: - // xor is same as difference or replace both of which - // can be 1-pass instead of 2 for xor. - if (*clearToInside) { - *startOp = kDifference_SetOp; - } else { - *startOp = kReplace_SetOp; - } - done = true; - break; - case kDifference_SetOp: - // if all pixels are clearToInside then we have to process the - // difference, otherwise it has no effect and all pixels - // remain outside. - if (*clearToInside) { - *startOp = kDifference_SetOp; - done = true; - } - break; - case kReverseDifference_SetOp: - // if all pixels are clearToInside then reverse difference - // produces empty set. Otherise it is same as replace - if (*clearToInside) { - *clearToInside = false; - } else { - *startOp = kReplace_SetOp; - done = true; - } - break; - default: - GrCrash("Unknown set op."); - } - } - return done ? curr-1 : count; -} -} - - - -// sort out what kind of clip mask needs to be created: A8/R8, stencil or scissor -bool GrClipMaskManager::createClipMask(GrGpu* gpu, - const GrClip& clipIn, - ScissoringSettings* scissorSettings) { - - GrAssert(scissorSettings); - - scissorSettings->fEnableScissoring = false; - fClipMaskInStencil = false; - - GrDrawState* drawState = gpu->drawState(); - if (!drawState->isClipState()) { - return true; - } - - GrRenderTarget* rt = drawState->getRenderTarget(); - - // GrDrawTarget should have filtered this for us - GrAssert(NULL != rt); - - GrRect bounds; - GrRect rtRect; - rtRect.setLTRB(0, 0, - GrIntToScalar(rt->width()), GrIntToScalar(rt->height())); - if (clipIn.hasConservativeBounds()) { - bounds = clipIn.getConservativeBounds(); - if (!bounds.intersect(rtRect)) { - bounds.setEmpty(); - } - } else { - bounds = rtRect; - } - - bounds.roundOut(&scissorSettings->fScissorRect); - if (scissorSettings->fScissorRect.isEmpty()) { - scissorSettings->fScissorRect.setLTRB(0,0,0,0); - // TODO: I think we can do an early exit here - after refactoring try: - // set fEnableScissoring to true but leave fClipMaskInStencil false - // and return - everything is going to be scissored away anyway! - } - scissorSettings->fEnableScissoring = true; - - // use the stencil clip if we can't represent the clip as a rectangle. - fClipMaskInStencil = !clipIn.isRect() && !clipIn.isEmpty() && - !bounds.isEmpty(); - - if (fClipMaskInStencil) { - return this->createStencilClipMask(gpu, clipIn, bounds, scissorSettings); - } - - return true; -} - -// Create a 1-bit clip mask in the stencil buffer -bool GrClipMaskManager::createStencilClipMask(GrGpu* gpu, - const GrClip& clipIn, - const GrRect& bounds, - ScissoringSettings* scissorSettings) { - - GrAssert(fClipMaskInStencil); - - GrDrawState* drawState = gpu->drawState(); - GrAssert(drawState->isClipState()); - - GrRenderTarget* rt = drawState->getRenderTarget(); - GrAssert(NULL != rt); - - // TODO: dynamically attach a SB when needed. - GrStencilBuffer* stencilBuffer = rt->getStencilBuffer(); - if (NULL == stencilBuffer) { - return false; - } - - if (stencilBuffer->mustRenderClip(clipIn, rt->width(), rt->height())) { - - stencilBuffer->setLastClip(clipIn, rt->width(), rt->height()); - - // we set the current clip to the bounds so that our recursive - // draws are scissored to them. We use the copy of the complex clip - // we just stashed on the SB to render from. We set it back after - // we finish drawing it into the stencil. - const GrClip& clipCopy = stencilBuffer->getLastClip(); - gpu->setClip(GrClip(bounds)); - - GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit); - drawState = gpu->drawState(); - drawState->setRenderTarget(rt); - GrDrawTarget::AutoGeometryPush agp(gpu); - - gpu->disableScissor(); -#if !VISUALIZE_COMPLEX_CLIP - drawState->enableState(GrDrawState::kNoColorWrites_StateBit); -#endif - - int count = clipCopy.getElementCount(); - int clipBit = stencilBuffer->bits(); - SkASSERT((clipBit <= 16) && - "Ganesh only handles 16b or smaller stencil buffers"); - clipBit = (1 << (clipBit-1)); - - GrRect rtRect; - rtRect.setLTRB(0, 0, - GrIntToScalar(rt->width()), GrIntToScalar(rt->height())); - - bool clearToInside; - GrSetOp startOp = kReplace_SetOp; // suppress warning - int start = process_initial_clip_elements(clipCopy, - rtRect, - &clearToInside, - &startOp); - - gpu->clearStencilClip(scissorSettings->fScissorRect, clearToInside); - - // walk through each clip element and perform its set op - // with the existing clip. - for (int c = start; c < count; ++c) { - GrPathFill fill; - bool fillInverted; - // enabled at bottom of loop - drawState->disableState(GrGpu::kModifyStencilClip_StateBit); - - bool canRenderDirectToStencil; // can the clip element be drawn - // directly to the stencil buffer - // with a non-inverted fill rule - // without extra passes to - // resolve in/out status. - - GrPathRenderer* pr = NULL; - const GrPath* clipPath = NULL; - if (kRect_ClipType == clipCopy.getElementType(c)) { - canRenderDirectToStencil = true; - fill = kEvenOdd_PathFill; - fillInverted = false; - // there is no point in intersecting a screen filling - // rectangle. - if (kIntersect_SetOp == clipCopy.getOp(c) && - clipCopy.getRect(c).contains(rtRect)) { - continue; - } - } else { - fill = clipCopy.getPathFill(c); - fillInverted = GrIsFillInverted(fill); - fill = GrNonInvertedFill(fill); - clipPath = &clipCopy.getPath(c); - pr = this->getClipPathRenderer(gpu, *clipPath, fill); - if (NULL == pr) { - fClipMaskInStencil = false; - gpu->setClip(clipCopy); // restore to the original - return false; - } - canRenderDirectToStencil = - !pr->requiresStencilPass(*clipPath, fill, gpu); - } - - GrSetOp op = (c == start) ? startOp : clipCopy.getOp(c); - int passes; - GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses]; - - bool canDrawDirectToClip; // Given the renderer, the element, - // fill rule, and set operation can - // we render the element directly to - // stencil bit used for clipping. - canDrawDirectToClip = - GrStencilSettings::GetClipPasses(op, - canRenderDirectToStencil, - clipBit, - fillInverted, - &passes, stencilSettings); - - // draw the element to the client stencil bits if necessary - if (!canDrawDirectToClip) { - GR_STATIC_CONST_SAME_STENCIL(gDrawToStencil, - kIncClamp_StencilOp, - kIncClamp_StencilOp, - kAlways_StencilFunc, - 0xffff, - 0x0000, - 0xffff); - SET_RANDOM_COLOR - if (kRect_ClipType == clipCopy.getElementType(c)) { - *drawState->stencil() = gDrawToStencil; - gpu->drawSimpleRect(clipCopy.getRect(c), NULL, 0); - } else { - if (canRenderDirectToStencil) { - *drawState->stencil() = gDrawToStencil; - pr->drawPath(*clipPath, fill, NULL, gpu, 0, false); - } else { - pr->drawPathToStencil(*clipPath, fill, gpu); - } - } - } - - // now we modify the clip bit by rendering either the clip - // element directly or a bounding rect of the entire clip. - drawState->enableState(GrGpu::kModifyStencilClip_StateBit); - for (int p = 0; p < passes; ++p) { - *drawState->stencil() = stencilSettings[p]; - if (canDrawDirectToClip) { - if (kRect_ClipType == clipCopy.getElementType(c)) { - SET_RANDOM_COLOR - gpu->drawSimpleRect(clipCopy.getRect(c), NULL, 0); - } else { - SET_RANDOM_COLOR - pr->drawPath(*clipPath, fill, NULL, gpu, 0, false); - } - } else { - SET_RANDOM_COLOR - gpu->drawSimpleRect(bounds, NULL, 0); - } - } - } - // restore clip - gpu->setClip(clipCopy); - // recusive draws would have disabled this since they drew with - // the clip bounds as clip. - fClipMaskInStencil = true; - } - - return true; -} - bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) { ScissoringSettings scissoringSettings; @@ -781,18 +457,6 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) { return true; } -GrPathRenderer* GrClipMaskManager::getClipPathRenderer(GrGpu* gpu, - const GrPath& path, - GrPathFill fill) { - if (NULL == fPathRendererChain) { - fPathRendererChain = - new GrPathRendererChain(gpu->getContext(), - GrPathRendererChain::kNonAAOnly_UsageFlag); - } - return fPathRendererChain->getPathRenderer(path, fill, gpu, false); -} - - //////////////////////////////////////////////////////////////////////////////// void GrGpu::geometrySourceWillPush() { @@ -1030,18 +694,3 @@ void GrGpu::printStats() const { } -//////////////////////////////////////////////////////////////////////////////// -void ScissoringSettings::setupScissoring(GrGpu* gpu) { - if (!fEnableScissoring) { - gpu->disableScissor(); - return; - } - - gpu->enableScissoring(fScissorRect); -} - - -void GrClipMaskManager::freeResources() { - // in case path renderer has any GrResources, start from scratch - GrSafeSetNull(fPathRendererChain); -} diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h index 7bba3558a0..de14935e7f 100644 --- a/src/gpu/GrGpu.h +++ b/src/gpu/GrGpu.h @@ -14,6 +14,7 @@ #include "GrRect.h" #include "GrRefCnt.h" #include "GrTexture.h" +#include "GrClipMaskManager.h" class GrContext; class GrIndexBufferAllocPool; @@ -51,66 +52,6 @@ struct GrGpuStats { uint32_t fRenderTargetCreateCnt; }; -/** - * Scissoring needs special handling during stencil clip mask creation - * since the creation process re-entrantly invokes setupClipAndFlushState. - * During this process the call stack is used to keep - * track of (and apply to the GPU) the current scissor settings. - */ -struct ScissoringSettings { - bool fEnableScissoring; - GrIRect fScissorRect; - - void setupScissoring(GrGpu* gpu); -}; - -/** - * The clip mask creator handles the generation of the clip mask. If anti - * aliasing is requested it will (in the future) generate a single channel - * (8bit) mask. If no anti aliasing is requested it will generate a 1-bit - * mask in the stencil buffer. In the non anti-aliasing case, if the clip - * mask can be represented as a rectangle then scissoring is used. In all - * cases scissoring is used to bound the range of the clip mask. - */ -class GrClipMaskManager { -public: - GrClipMaskManager() - : fClipMaskInStencil(false) - , fPathRendererChain(NULL) { - } - - bool createClipMask(GrGpu* gpu, - const GrClip& clip, - ScissoringSettings* scissorSettings); - - void freeResources(); - - bool isClipInStencil() const { return fClipMaskInStencil; } - - void resetMask() { - fClipMaskInStencil = false; - } - -protected: -private: - bool fClipMaskInStencil; // is the clip mask in the stencil buffer? - - // must be instantiated after GrGpu object has been given its owning - // GrContext ptr. (GrGpu is constructed first then handed off to GrContext). - GrPathRendererChain* fPathRendererChain; - - bool createStencilClipMask(GrGpu* gpu, - const GrClip& clip, - const GrRect& bounds, - ScissoringSettings* scissorSettings); - - // determines the path renderer used to draw a clip path element. - GrPathRenderer* getClipPathRenderer(GrGpu* gpu, - const SkPath& path, - GrPathFill fill); - -}; - class GrGpu : public GrDrawTarget { public: |