aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar robertphillips@google.com <robertphillips@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-04-16 18:03:03 +0000
committerGravatar robertphillips@google.com <robertphillips@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-04-16 18:03:03 +0000
commit1e945b7e708c633d4aed937ebfce57d52ba21d83 (patch)
tree1d27847d9e7a6f32137b6a3025c5d17f58a8c2c8
parent13eaaaa75a16fa300fa212ec910107f77530ef2c (diff)
Minor refactoring to pull GrClipMaskManager into its own files
-rw-r--r--gyp/gpu.gyp2
-rw-r--r--src/gpu/GrClipMaskManager.cpp359
-rw-r--r--src/gpu/GrClipMaskManager.h81
-rw-r--r--src/gpu/GrGpu.cpp351
-rw-r--r--src/gpu/GrGpu.h61
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: