Modifications to GrPatherRenderer(Chain) interfaces to support clip mask manager.
R=robertphillips@google.com
Review URL: https://codereview.appspot.com/6904069
git-svn-id: http://skia.googlecode.com/svn/trunk@6741 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi
index 3a6b1f2..7d3c0f2 100644
--- a/gyp/gpu.gypi
+++ b/gyp/gpu.gypi
@@ -25,6 +25,7 @@
'<(skia_include_path)/gpu/GrKey.h',
'<(skia_include_path)/gpu/GrNoncopyable.h',
'<(skia_include_path)/gpu/GrPaint.h',
+ '<(skia_include_path)/gpu/GrPathRendererChain.h',
'<(skia_include_path)/gpu/GrPoint.h',
'<(skia_include_path)/gpu/GrRect.h',
'<(skia_include_path)/gpu/GrRefCnt.h',
@@ -85,7 +86,6 @@
'<(skia_src_path)/gpu/GrPath.cpp',
'<(skia_src_path)/gpu/GrPath.h',
'<(skia_src_path)/gpu/GrPathRendererChain.cpp',
- '<(skia_src_path)/gpu/GrPathRendererChain.h',
'<(skia_src_path)/gpu/GrPathRenderer.cpp',
'<(skia_src_path)/gpu/GrPathRenderer.h',
'<(skia_src_path)/gpu/GrPathUtils.cpp',
diff --git a/include/core/SkTLazy.h b/include/core/SkTLazy.h
index cd1e8f2..315bd95 100644
--- a/include/core/SkTLazy.h
+++ b/include/core/SkTLazy.h
@@ -116,10 +116,21 @@
public:
SkTCopyOnFirstWrite(const T& initial) : fObj(&initial) {}
+ // Constructor for delayed initialization.
+ SkTCopyOnFirstWrite() : fObj(NULL) {}
+
+ // Should only be called once, and only if the default constructor was used.
+ void init(const T& initial) {
+ SkASSERT(NULL == fObj);
+ SkASSERT(!fLazy.isValid());
+ fObj = &initial;
+ }
+
/**
* Returns a writable T*. The first time this is called the initial object is cloned.
*/
T* writable() {
+ SkASSERT(NULL != fObj);
if (!fLazy.isValid()) {
fLazy.set(*fObj);
fObj = fLazy.get();
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index 9bd6f7d..d6a91eb 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -15,6 +15,7 @@
#include "GrClipData.h"
#include "SkMatrix.h"
#include "GrPaint.h"
+#include "GrPathRendererChain.h"
// not strictly needed but requires WK change in LayerTextureUpdaterCanvas to
// remove.
#include "GrRenderTarget.h"
@@ -32,7 +33,6 @@
class GrIndexBufferAllocPool;
class GrInOrderDrawBuffer;
class GrPathRenderer;
-class GrPathRendererChain;
class GrResourceEntry;
class GrResourceCache;
class GrStencilBuffer;
@@ -851,11 +851,13 @@
void addStencilBuffer(GrStencilBuffer* sb);
GrStencilBuffer* findStencilBuffer(int width, int height, int sampleCnt);
- GrPathRenderer* getPathRenderer(const SkPath& path,
- const SkStroke& stroke,
- const GrDrawTarget* target,
- bool antiAlias,
- bool allowSW);
+ GrPathRenderer* getPathRenderer(
+ const SkPath& path,
+ const SkStroke& stroke,
+ const GrDrawTarget* target,
+ bool allowSW,
+ GrPathRendererChain::DrawType drawType = GrPathRendererChain::kColor_DrawType,
+ GrPathRendererChain::StencilSupport* stencilSupport = NULL);
#if GR_CACHE_STATS
void printCacheStats() const;
diff --git a/include/gpu/GrPathRendererChain.h b/include/gpu/GrPathRendererChain.h
new file mode 100644
index 0000000..8b74ba3
--- /dev/null
+++ b/include/gpu/GrPathRendererChain.h
@@ -0,0 +1,83 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef GrPathRendererChain_DEFINED
+#define GrPathRendererChain_DEFINED
+
+#include "GrRefCnt.h"
+#include "SkTArray.h"
+
+class GrContext;
+class GrDrawTarget;
+class GrPathRenderer;
+class SkPath;
+class SkStroke;
+
+/**
+ * Keeps track of an ordered list of path renderers. When a path needs to be
+ * drawn this list is scanned to find the most preferred renderer. To add your
+ * path renderer to the list implement the GrPathRenderer::AddPathRenderers
+ * function.
+ */
+class GrPathRendererChain : public SkRefCnt {
+public:
+ // See comments in GrPathRenderer.h
+ enum StencilSupport {
+ kNoSupport_StencilSupport,
+ kStencilOnly_StencilSupport,
+ kNoRestriction_StencilSupport,
+ };
+
+ SK_DECLARE_INST_COUNT(GrPathRendererChain)
+
+ GrPathRendererChain(GrContext* context);
+
+ ~GrPathRendererChain();
+
+ // takes a ref and unrefs in destructor
+ GrPathRenderer* addPathRenderer(GrPathRenderer* pr);
+
+ /** Documents how the caller plans to use a GrPathRenderer to draw a path. It affects the PR
+ returned by getPathRenderer */
+ enum DrawType {
+ kColor_DrawType, // draw to the color buffer, no AA
+ kColorAntiAlias_DrawType, // draw to color buffer, with partial coverage AA
+ kStencilOnly_DrawType, // draw just to the stencil buffer
+ kStencilAndColor_DrawType, // draw the stencil and color buffer, no AA
+ kStencilAndColorAntiAlias_DrawType // draw the stencil and color buffer, with partial
+ // coverage AA.
+ };
+ /** Returns a GrPathRenderer compatible with the request if one is available. If the caller
+ is drawing the path to the stencil buffer then stencilSupport can be used to determine
+ whether the path can be rendered with arbitrary stencil rules or not. See comments on
+ StencilSupport in GrPathRenderer.h. */
+ GrPathRenderer* getPathRenderer(const SkPath& path,
+ const SkStroke& stroke,
+ const GrDrawTarget* target,
+ DrawType drawType,
+ StencilSupport* stencilSupport);
+
+private:
+
+ GrPathRendererChain();
+
+ void init();
+
+ enum {
+ kPreAllocCount = 8,
+ };
+ bool fInit;
+ GrContext* fOwner;
+ SkSTArray<kPreAllocCount, GrPathRenderer*, true> fChain;
+
+ typedef SkRefCnt INHERITED;
+};
+
+
+#endif
diff --git a/src/gpu/GrAddPathRenderers_default.cpp b/src/gpu/GrAddPathRenderers_default.cpp
index 24f1017..9be6768 100644
--- a/src/gpu/GrAddPathRenderers_default.cpp
+++ b/src/gpu/GrAddPathRenderers_default.cpp
@@ -12,17 +12,12 @@
#include "GrAAConvexPathRenderer.h"
#include "GrSoftwarePathRenderer.h"
-void GrPathRenderer::AddPathRenderers(GrContext* ctx,
- GrPathRendererChain::UsageFlags flags,
- GrPathRendererChain* chain) {
+void GrPathRenderer::AddPathRenderers(GrContext* ctx, GrPathRendererChain* chain) {
if (GrPathRenderer* pr = GrStencilAndCoverPathRenderer::Create(ctx)) {
chain->addPathRenderer(pr)->unref();
}
- if (!(GrPathRendererChain::kNonAAOnly_UsageFlag & flags)) {
-
- if (GrPathRenderer* pr = GrAAHairLinePathRenderer::Create(ctx)) {
- chain->addPathRenderer(pr)->unref();
- }
- chain->addPathRenderer(SkNEW(GrAAConvexPathRenderer))->unref();
+ if (GrPathRenderer* pr = GrAAHairLinePathRenderer::Create(ctx)) {
+ chain->addPathRenderer(pr)->unref();
}
+ chain->addPathRenderer(SkNEW(GrAAConvexPathRenderer))->unref();
}
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp
index c400486..11b301d 100644
--- a/src/gpu/GrClipMaskManager.cpp
+++ b/src/gpu/GrClipMaskManager.cpp
@@ -70,7 +70,11 @@
path.writable()->toggleInverseFillType();
}
// last (false) parameter disallows use of the SW path renderer
- return NULL == context->getPathRenderer(*path, stroke, gpu, doAA, false);
+ GrPathRendererChain::DrawType type = doAA ?
+ GrPathRendererChain::kColorAntiAlias_DrawType :
+ GrPathRendererChain::kColor_DrawType;
+
+ return NULL == context->getPathRenderer(*path, stroke, gpu, false, type);
}
}
@@ -313,10 +317,14 @@
}
SkStroke stroke;
stroke.setDoFill(true);
+ GrPathRendererChain::DrawType type = element->isAA() ?
+ GrPathRendererChain::kColorAntiAlias_DrawType :
+ GrPathRendererChain::kColor_DrawType;
GrPathRenderer* pr = this->getContext()->getPathRenderer(*path,
stroke,
fGpu,
- element->isAA(), false);
+ false,
+ type);
if (NULL == pr) {
return false;
}
@@ -580,10 +588,9 @@
drawState->setState(GrDrawState::kHWAntialias_StateBit, element->isAA());
}
- // 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?
- bool canRenderDirectToStencil = false;
+ // This will be used to determine whether the clip shape can be rendered into the
+ // stencil with arbitrary stencil settings.
+ GrPathRenderer::StencilSupport stencilSupport;
SkStroke stroke;
stroke.setDoFill(true);
@@ -591,29 +598,37 @@
SkRegion::Op op = element->getOp();
GrPathRenderer* pr = NULL;
- SkPath clipPath;
+ SkTCopyOnFirstWrite<SkPath> clipPath;
if (Element::kRect_Type == element->getType()) {
- canRenderDirectToStencil = true;
+ stencilSupport = GrPathRenderer::kNoRestriction_StencilSupport;
fill = SkPath::kEvenOdd_FillType;
fillInverted = false;
} else {
GrAssert(Element::kPath_Type == element->getType());
- clipPath = element->getPath();
- fill = clipPath.getFillType();
- fillInverted = clipPath.isInverseFillType();
- fill = SkPath::NonInverseFill(fill);
- clipPath.setFillType(fill);
- pr = this->getContext()->getPathRenderer(clipPath, stroke, fGpu, false, true);
+ clipPath.init(element->getPath());
+ fill = clipPath->getFillType();
+ fillInverted = clipPath->isInverseFillType();
+ if (fillInverted) {
+ clipPath.writable()->toggleInverseFillType();
+ fill = clipPath->getFillType();
+ }
+ pr = this->getContext()->getPathRenderer(*clipPath,
+ stroke,
+ fGpu,
+ false,
+ GrPathRendererChain::kStencilOnly_DrawType,
+ &stencilSupport);
if (NULL == pr) {
fGpu->setClip(oldClipData);
return false;
}
- canRenderDirectToStencil = !pr->requiresStencilPass(clipPath, stroke, fGpu);
}
int passes;
GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
+ bool canRenderDirectToStencil =
+ GrPathRenderer::kNoRestriction_StencilSupport == stencilSupport;
bool canDrawDirectToClip; // Given the renderer, the element,
// fill rule, and set operation can
// we render the element directly to
@@ -642,9 +657,9 @@
GrAssert(Element::kPath_Type == element->getType());
if (canRenderDirectToStencil) {
*drawState->stencil() = gDrawToStencil;
- pr->drawPath(clipPath, stroke, fGpu, false);
+ pr->drawPath(*clipPath, stroke, fGpu, false);
} else {
- pr->drawPathToStencil(clipPath, stroke, fGpu);
+ pr->stencilPath(*clipPath, stroke, fGpu);
}
}
}
@@ -661,7 +676,7 @@
} else {
GrAssert(Element::kPath_Type == element->getType());
SET_RANDOM_COLOR
- pr->drawPath(clipPath, stroke, fGpu, false);
+ pr->drawPath(*clipPath, stroke, fGpu, false);
}
} else {
SET_RANDOM_COLOR
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index d96a16e..c39ee75 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -1112,7 +1112,10 @@
prAA = false;
}
- GrPathRenderer* pr = this->getPathRenderer(path, stroke, target, prAA, true);
+ GrPathRendererChain::DrawType type = prAA ? GrPathRendererChain::kColorAntiAlias_DrawType :
+ GrPathRendererChain::kColor_DrawType;
+
+ GrPathRenderer* pr = this->getPathRenderer(path, stroke, target, true, type);
if (NULL == pr) {
#if GR_DEBUG
GrPrintf("Unable to find path renderer compatible with path.\n");
@@ -1620,24 +1623,24 @@
GrPathRenderer* GrContext::getPathRenderer(const SkPath& path,
const SkStroke& stroke,
const GrDrawTarget* target,
- bool antiAlias,
- bool allowSW) {
+ bool allowSW,
+ GrPathRendererChain::DrawType drawType,
+ GrPathRendererChain::StencilSupport* stencilSupport) {
+
if (NULL == fPathRendererChain) {
- fPathRendererChain =
- SkNEW_ARGS(GrPathRendererChain,
- (this, GrPathRendererChain::kNone_UsageFlag));
+ fPathRendererChain = SkNEW_ARGS(GrPathRendererChain, (this));
}
GrPathRenderer* pr = fPathRendererChain->getPathRenderer(path,
stroke,
target,
- antiAlias);
+ drawType,
+ stencilSupport);
if (NULL == pr && allowSW) {
if (NULL == fSoftwarePathRenderer) {
fSoftwarePathRenderer = SkNEW_ARGS(GrSoftwarePathRenderer, (this));
}
-
pr = fSoftwarePathRenderer;
}
diff --git a/src/gpu/GrDefaultPathRenderer.cpp b/src/gpu/GrDefaultPathRenderer.cpp
index f80b4d7..b92b77d 100644
--- a/src/gpu/GrDefaultPathRenderer.cpp
+++ b/src/gpu/GrDefaultPathRenderer.cpp
@@ -162,10 +162,15 @@
#endif
}
-bool GrDefaultPathRenderer::requiresStencilPass(const SkPath& path,
- const SkStroke& stroke,
- const GrDrawTarget* target) const {
- return !single_pass_path(path, stroke);
+GrPathRenderer::StencilSupport GrDefaultPathRenderer::onGetStencilSupport(
+ const SkPath& path,
+ const SkStroke& stroke,
+ const GrDrawTarget*) const {
+ if (single_pass_path(path, stroke)) {
+ return GrPathRenderer::kNoRestriction_StencilSupport;
+ } else {
+ return GrPathRenderer::kStencilOnly_StencilSupport;
+ }
}
static inline void append_countour_edge_indices(bool hairLine,
@@ -508,9 +513,9 @@
false);
}
-void GrDefaultPathRenderer::drawPathToStencil(const SkPath& path,
- const SkStroke& stroke,
- GrDrawTarget* target) {
+void GrDefaultPathRenderer::onStencilPath(const SkPath& path,
+ const SkStroke& stroke,
+ GrDrawTarget* target) {
GrAssert(SkPath::kInverseEvenOdd_FillType != path.getFillType());
GrAssert(SkPath::kInverseWinding_FillType != path.getFillType());
this->internalDrawPath(path, stroke, target, true);
diff --git a/src/gpu/GrDefaultPathRenderer.h b/src/gpu/GrDefaultPathRenderer.h
index e98f2d7..657537a 100644
--- a/src/gpu/GrDefaultPathRenderer.h
+++ b/src/gpu/GrDefaultPathRenderer.h
@@ -12,48 +12,46 @@
#include "SkTemplates.h"
/**
- * Subclass that renders the path using the stencil buffer to resolve fill
- * rules (e.g. winding, even-odd)
+ * Subclass that renders the path using the stencil buffer to resolve fill rules
+ * (e.g. winding, even-odd)
*/
class GR_API GrDefaultPathRenderer : public GrPathRenderer {
public:
- GrDefaultPathRenderer(bool separateStencilSupport,
- bool stencilWrapOpsSupport);
+ GrDefaultPathRenderer(bool separateStencilSupport, bool stencilWrapOpsSupport);
-
- virtual bool requiresStencilPass(const SkPath& path,
- const SkStroke& stroke,
- const GrDrawTarget* target) const SK_OVERRIDE;
-
- virtual bool canDrawPath(const SkPath& path,
- const SkStroke& stroke,
- const GrDrawTarget* target,
+ virtual bool canDrawPath(const SkPath&,
+ const SkStroke&,
+ const GrDrawTarget*,
bool antiAlias) const SK_OVERRIDE;
- virtual void drawPathToStencil(const SkPath& path,
- const SkStroke& stroke,
- GrDrawTarget* target) SK_OVERRIDE;
-
private:
- virtual bool onDrawPath(const SkPath& path,
- const SkStroke& stroke,
- GrDrawTarget* target,
+ virtual StencilSupport onGetStencilSupport(const SkPath&,
+ const SkStroke&,
+ const GrDrawTarget*) const SK_OVERRIDE;
+
+ virtual bool onDrawPath(const SkPath&,
+ const SkStroke&,
+ GrDrawTarget*,
bool antiAlias) SK_OVERRIDE;
- bool internalDrawPath(const SkPath& path,
- const SkStroke& stroke,
- GrDrawTarget* target,
+ virtual void onStencilPath(const SkPath&,
+ const SkStroke&,
+ GrDrawTarget*) SK_OVERRIDE;
+
+ bool internalDrawPath(const SkPath&,
+ const SkStroke&,
+ GrDrawTarget*,
bool stencilOnly);
- bool createGeom(const SkPath& path,
- const SkStroke& stroke,
+ bool createGeom(const SkPath&,
+ const SkStroke&,
SkScalar srcSpaceTol,
- GrDrawTarget* target,
- GrPrimitiveType* primType,
+ GrDrawTarget*,
+ GrPrimitiveType*,
int* vertexCnt,
int* indexCnt,
- GrDrawTarget::AutoReleaseGeometry* arg);
+ GrDrawTarget::AutoReleaseGeometry*);
bool fSeparateStencil;
bool fStencilWrapOps;
diff --git a/src/gpu/GrPathRenderer.h b/src/gpu/GrPathRenderer.h
index afcd3c9..9d52566 100644
--- a/src/gpu/GrPathRenderer.h
+++ b/src/gpu/GrPathRenderer.h
@@ -12,72 +12,86 @@
#include "GrDrawTarget.h"
#include "GrPathRendererChain.h"
+#include "GrStencil.h"
+#include "SkStroke.h"
#include "SkTArray.h"
class SkPath;
-class SkStroke;
struct GrPoint;
/**
* Base class for drawing paths into a GrDrawTarget.
*
- * Derived classes can use stages GrPaint::kTotalStages through
- * GrDrawState::kNumStages-1. The stages before GrPaint::kTotalStages
- * are reserved for setting up the draw (i.e., textures and filter masks).
+ * Derived classes can use stages GrPaint::kTotalStages through GrDrawState::kNumStages-1. The
+ * stages before GrPaint::kTotalStages are reserved for setting up the draw (i.e., textures and
+ * filter masks).
*/
class GR_API GrPathRenderer : public GrRefCnt {
public:
SK_DECLARE_INST_COUNT(GrPathRenderer)
/**
- * This is called to install custom path renderers in every GrContext at
- * create time. The default implementation in GrCreatePathRenderer_none.cpp
- * does not add any additional renderers. Link against another
- * implementation to install your own. The first added is the most preferred
- * path renderer, second is second most preferred, etc.
+ * This is called to install custom path renderers in every GrContext at create time. The
+ * default implementation in GrCreatePathRenderer_none.cpp does not add any additional
+ * renderers. Link against another implementation to install your own. The first added is the
+ * most preferred path renderer, second is second most preferred, etc.
*
* @param context the context that will use the path renderer
- * @param flags flags indicating how path renderers will be used
* @param prChain the chain to add path renderers to.
*/
- static void AddPathRenderers(GrContext* context,
- GrPathRendererChain::UsageFlags flags,
- GrPathRendererChain* prChain);
+ static void AddPathRenderers(GrContext* context, GrPathRendererChain* prChain);
GrPathRenderer();
/**
- * For complex clips Gr uses the stencil buffer. The path renderer must be
- * able to render paths into the stencil buffer. However, the path renderer
- * itself may require the stencil buffer to resolve the path fill rule.
- * This function queries whether the path render needs its own stencil
- * pass. If this returns false then drawPath() should not modify the
- * the target's stencil settings but use those already set on target. The
- * target is passed as a param in case the answer depends upon draw state.
+ * A caller may wish to use a path renderer to draw a path into the stencil buffer. However,
+ * the path renderer itself may require use of the stencil buffer. Also a path renderer may
+ * use a GrEffect coverage stage that sets coverage to zero to eliminate pixels that are covered
+ * by bounding geometry but outside the path. These exterior pixels would still be rendered into
+ * the stencil.
+ *
+ * A GrPathRenderer can provide three levels of support for stenciling paths:
+ * 1) kNoRestriction: This is the most general. The caller sets up the GrDrawState on the target
+ * and calls drawPath(). The path is rendered exactly as the draw state
+ * indicates including support for simultaneous color and stenciling with
+ * arbitrary stenciling rules. Pixels partially covered by AA paths are
+ * affected by the stencil settings.
+ * 2) kStencilOnly: The path renderer cannot apply arbitrary stencil rules nor shade and stencil
+ * simultaneously. The path renderer does support the stencilPath() function
+ * which performs no color writes and writes a non-zero stencil value to pixels
+ * covered by the path.
+ * 3) kNoSupport: This path renderer cannot be used to stencil the path.
+ */
+ typedef GrPathRendererChain::StencilSupport StencilSupport;
+ static const StencilSupport kNoSupport_StencilSupport =
+ GrPathRendererChain::kNoSupport_StencilSupport;
+ static const StencilSupport kStencilOnly_StencilSupport =
+ GrPathRendererChain::kStencilOnly_StencilSupport;
+ static const StencilSupport kNoRestriction_StencilSupport =
+ GrPathRendererChain::kNoRestriction_StencilSupport;
+
+ /**
+ * This function is to get the stencil support for a particular path. The path's fill must
+ * not be an inverse type.
*
* @param target target that the path will be rendered to
* @param path the path that will be drawn
* @param stroke the stroke information (width, join, cap).
- *
- * @return false if this path renderer can generate interior-only fragments
- * without changing the stencil settings on the target. If it
- * returns true the drawPathToStencil will be used when rendering
- * clips.
*/
- virtual bool requiresStencilPass(const SkPath& path,
+ StencilSupport getStencilSupport(const SkPath& path,
const SkStroke& stroke,
const GrDrawTarget* target) const {
- return false;
+ GrAssert(!path.isInverseFillType());
+ return this->onGetStencilSupport(path, stroke, target);
}
/**
- * Returns true if this path renderer is able to render the path.
- * Returning false allows the caller to fallback to another path renderer
- * This function is called when searching for a path renderer capable of
- * rendering a path.
+ * Returns true if this path renderer is able to render the path. Returning false allows the
+ * caller to fallback to another path renderer This function is called when searching for a path
+ * renderer capable of rendering a path.
*
* @param path The path to draw
* @param stroke The stroke information (width, join, cap)
@@ -91,55 +105,72 @@
const GrDrawTarget* target,
bool antiAlias) const = 0;
/**
- * Draws the path into the draw target. If requiresStencilBuffer returned
- * false then the target may be setup for stencil rendering (since the
- * path renderer didn't claim that it needs to use the stencil internally).
+ * Draws the path into the draw target. If getStencilSupport() would return kNoRestriction then
+ * the subclass must respect the stencil settings of the target's draw state.
*
* @param path the path to draw.
* @param stroke the stroke information (width, join, cap)
* @param target target that the path will be rendered to
* @param antiAlias true if anti-aliasing is required.
*/
- virtual bool drawPath(const SkPath& path,
- const SkStroke& stroke,
- GrDrawTarget* target,
- bool antiAlias) {
+ bool drawPath(const SkPath& path,
+ const SkStroke& stroke,
+ GrDrawTarget* target,
+ bool antiAlias) {
GrAssert(this->canDrawPath(path, stroke, target, antiAlias));
return this->onDrawPath(path, stroke, target, antiAlias);
}
/**
- * Draws the path to the stencil buffer. Assume the writable stencil bits
- * are already initialized to zero. Fill will always be either
- * kWinding_FillType or kEvenOdd_FillType.
- *
- * Only called if requiresStencilPass returns true for the same combo of
- * target, path, and fill. Never called with an inverse fill.
- *
- * The default implementation assumes the path filling algorithm doesn't
- * require a separate stencil pass and so crashes.
- *
- */
- virtual void drawPathToStencil(const SkPath& path,
- const SkStroke& stroke,
- GrDrawTarget* target) {
- GrCrash("Unexpected call to drawPathToStencil.");
- }
-
-protected:
- /**
- * Draws the path into the draw target.
+ * Draws the path to the stencil buffer. Assume the writable stencil bits are already
+ * initialized to zero. The pixels inside the path will have non-zero stencil values afterwards.
*
* @param path the path to draw.
* @param stroke the stroke information (width, join, cap)
* @param target target that the path will be rendered to
- * @param antiAlias whether antialiasing is enabled or not.
+ */
+ void stencilPath(const SkPath& path, const SkStroke& stroke, GrDrawTarget* target) {
+ GrAssert(kNoSupport_StencilSupport != this->getStencilSupport(path, stroke, target));
+ this->onStencilPath(path, stroke, target);
+ }
+
+protected:
+ /**
+ * Subclass overrides if it has any limitations of stenciling support.
+ */
+ virtual StencilSupport onGetStencilSupport(const SkPath&,
+ const SkStroke&,
+ const GrDrawTarget*) const {
+ return kNoRestriction_StencilSupport;
+ }
+
+ /**
+ * Subclass implementation of drawPath()
*/
virtual bool onDrawPath(const SkPath& path,
const SkStroke& stroke,
GrDrawTarget* target,
bool antiAlias) = 0;
+ /**
+ * Subclass implementation of stencilPath(). Subclass must override iff it ever returns
+ * kStencilOnly in onGetStencilSupport().
+ */
+ virtual void onStencilPath(const SkPath& path, const SkStroke& stroke, GrDrawTarget* target) {
+ GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kPreserve_ASRInit);
+ GrDrawState* drawState = target->drawState();
+ GR_STATIC_CONST_SAME_STENCIL(kIncrementStencil,
+ kReplace_StencilOp,
+ kReplace_StencilOp,
+ kAlways_StencilFunc,
+ 0xffff,
+ 0xffff,
+ 0xffff);
+ drawState->setStencil(kIncrementStencil);
+ drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
+ this->drawPath(path, stroke, target, false);
+ }
+
private:
typedef GrRefCnt INHERITED;
diff --git a/src/gpu/GrPathRendererChain.cpp b/src/gpu/GrPathRendererChain.cpp
index 8ccafcf..6cb45fa 100644
--- a/src/gpu/GrPathRendererChain.cpp
+++ b/src/gpu/GrPathRendererChain.cpp
@@ -15,10 +15,9 @@
SK_DEFINE_INST_COUNT(GrPathRendererChain)
-GrPathRendererChain::GrPathRendererChain(GrContext* context, UsageFlags flags)
+GrPathRendererChain::GrPathRendererChain(GrContext* context)
: fInit(false)
- , fOwner(context)
- , fFlags(flags) {
+ , fOwner(context) {
}
GrPathRendererChain::~GrPathRendererChain() {
@@ -36,12 +35,41 @@
GrPathRenderer* GrPathRendererChain::getPathRenderer(const SkPath& path,
const SkStroke& stroke,
const GrDrawTarget* target,
- bool antiAlias) {
+ DrawType drawType,
+ StencilSupport* stencilSupport) {
if (!fInit) {
this->init();
}
+ bool antiAlias = (kColorAntiAlias_DrawType == drawType ||
+ kStencilAndColorAntiAlias_DrawType == drawType);
+
+ GR_STATIC_ASSERT(GrPathRenderer::kNoSupport_StencilSupport <
+ GrPathRenderer::kStencilOnly_StencilSupport);
+ GR_STATIC_ASSERT(GrPathRenderer::kStencilOnly_StencilSupport <
+ GrPathRenderer::kNoRestriction_StencilSupport);
+ GrPathRenderer::StencilSupport minStencilSupport;
+ if (kStencilOnly_DrawType == drawType) {
+ minStencilSupport = GrPathRenderer::kStencilOnly_StencilSupport;
+ } else if (kStencilAndColor_DrawType == drawType ||
+ kStencilAndColorAntiAlias_DrawType == drawType) {
+ minStencilSupport = GrPathRenderer::kNoRestriction_StencilSupport;
+ } else {
+ minStencilSupport = GrPathRenderer::kNoSupport_StencilSupport;
+ }
+
+
for (int i = 0; i < fChain.count(); ++i) {
if (fChain[i]->canDrawPath(path, stroke, target, antiAlias)) {
+ if (GrPathRenderer::kNoSupport_StencilSupport != minStencilSupport) {
+ GrPathRenderer::StencilSupport support = fChain[i]->getStencilSupport(path,
+ stroke,
+ target);
+ if (support < minStencilSupport) {
+ continue;
+ } else if (NULL != stencilSupport) {
+ *stencilSupport = support;
+ }
+ }
return fChain[i];
}
}
@@ -53,7 +81,7 @@
GrGpu* gpu = fOwner->getGpu();
bool twoSided = gpu->getCaps().twoSidedStencilSupport();
bool wrapOp = gpu->getCaps().stencilWrapOpsSupport();
- GrPathRenderer::AddPathRenderers(fOwner, fFlags, this);
+ GrPathRenderer::AddPathRenderers(fOwner, this);
this->addPathRenderer(SkNEW_ARGS(GrDefaultPathRenderer,
(twoSided, wrapOp)))->unref();
fInit = true;
diff --git a/src/gpu/GrPathRendererChain.h b/src/gpu/GrPathRendererChain.h
deleted file mode 100644
index dfc696d..0000000
--- a/src/gpu/GrPathRendererChain.h
+++ /dev/null
@@ -1,69 +0,0 @@
-
-/*
- * Copyright 2011 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-
-#ifndef GrPathRendererChain_DEFINED
-#define GrPathRendererChain_DEFINED
-
-#include "GrDrawTarget.h"
-#include "GrRefCnt.h"
-#include "SkTArray.h"
-
-class GrContext;
-
-class SkPath;
-class SkStroke;
-class GrPathRenderer;
-
-/**
- * Keeps track of an ordered list of path renderers. When a path needs to be
- * drawn this list is scanned to find the most preferred renderer. To add your
- * path renderer to the list implement the GrPathRenderer::AddPathRenderers
- * function.
- */
-class GrPathRendererChain : public SkRefCnt {
-public:
- SK_DECLARE_INST_COUNT(GrPathRendererChain)
-
- enum UsageFlags {
- kNone_UsageFlag = 0,
- kNonAAOnly_UsageFlag = 1,
- };
-
- GrPathRendererChain(GrContext* context, UsageFlags flags);
-
- ~GrPathRendererChain();
-
- // takes a ref and unrefs in destructor
- GrPathRenderer* addPathRenderer(GrPathRenderer* pr);
-
- GrPathRenderer* getPathRenderer(const SkPath& path,
- const SkStroke& stroke,
- const GrDrawTarget* target,
- bool antiAlias);
-
-private:
-
- GrPathRendererChain();
-
- void init();
-
- enum {
- kPreAllocCount = 8,
- };
- bool fInit;
- GrContext* fOwner;
- UsageFlags fFlags;
- SkSTArray<kPreAllocCount, GrPathRenderer*, true> fChain;
-
- typedef SkRefCnt INHERITED;
-};
-
-GR_MAKE_BITFIELD_OPS(GrPathRendererChain::UsageFlags)
-
-#endif
diff --git a/src/gpu/GrReducedClip.cpp b/src/gpu/GrReducedClip.cpp
index 5287858..da42e8c 100644
--- a/src/gpu/GrReducedClip.cpp
+++ b/src/gpu/GrReducedClip.cpp
@@ -325,7 +325,7 @@
++numAAElements;
}
// Intersecting an inverse shape is the same as differencing the non-inverse shape.
- // Replacing with a inverse shape the same as setting initialState=kAllIn and
+ // Replacing with an inverse shape is the same as setting initialState=kAllIn and
// differencing the non-inverse shape.
bool isReplace = SkRegion::kReplace_Op == newElement->getOp();
if (newElement->isInverseFilled() &&
diff --git a/src/gpu/GrSoftwarePathRenderer.cpp b/src/gpu/GrSoftwarePathRenderer.cpp
index a521eef..36a4156 100644
--- a/src/gpu/GrSoftwarePathRenderer.cpp
+++ b/src/gpu/GrSoftwarePathRenderer.cpp
@@ -28,6 +28,13 @@
return true;
}
+GrPathRenderer::StencilSupport GrSoftwarePathRenderer::onGetStencilSupport(
+ const SkPath&,
+ const SkStroke&,
+ const GrDrawTarget*) const {
+ return GrPathRenderer::kNoSupport_StencilSupport;
+}
+
namespace {
////////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/GrSoftwarePathRenderer.h b/src/gpu/GrSoftwarePathRenderer.h
index 7c7382c..dd78d6b 100644
--- a/src/gpu/GrSoftwarePathRenderer.h
+++ b/src/gpu/GrSoftwarePathRenderer.h
@@ -24,14 +24,18 @@
: fContext(context) {
}
- virtual bool canDrawPath(const SkPath& path,
- const SkStroke& stroke,
- const GrDrawTarget* target,
+ virtual bool canDrawPath(const SkPath&,
+ const SkStroke&,
+ const GrDrawTarget*,
bool antiAlias) const SK_OVERRIDE;
protected:
- virtual bool onDrawPath(const SkPath& path,
- const SkStroke& stroke,
- GrDrawTarget* target,
+ virtual StencilSupport onGetStencilSupport(const SkPath&,
+ const SkStroke&,
+ const GrDrawTarget*) const SK_OVERRIDE;
+
+ virtual bool onDrawPath(const SkPath&,
+ const SkStroke&,
+ GrDrawTarget*,
bool antiAlias) SK_OVERRIDE;
private:
diff --git a/src/gpu/GrStencilAndCoverPathRenderer.cpp b/src/gpu/GrStencilAndCoverPathRenderer.cpp
index 28e18ed..a9bddda 100644
--- a/src/gpu/GrStencilAndCoverPathRenderer.cpp
+++ b/src/gpu/GrStencilAndCoverPathRenderer.cpp
@@ -42,15 +42,16 @@
target->getDrawState().getStencil().isDisabled();
}
-bool GrStencilAndCoverPathRenderer::requiresStencilPass(const SkPath& path,
- const SkStroke& stroke,
- const GrDrawTarget* target) const {
- return true;
+GrPathRenderer::StencilSupport GrStencilAndCoverPathRenderer::onGetStencilSupport(
+ const SkPath&,
+ const SkStroke& ,
+ const GrDrawTarget*) const {
+ return GrPathRenderer::kStencilOnly_StencilSupport;
}
-void GrStencilAndCoverPathRenderer::drawPathToStencil(const SkPath& path,
- const SkStroke& stroke,
- GrDrawTarget* target) {
+void GrStencilAndCoverPathRenderer::onStencilPath(const SkPath& path,
+ const SkStroke& stroke,
+ GrDrawTarget* target) {
GrAssert(!path.isInverseFillType());
SkAutoTUnref<GrPath> p(fGpu->createPath(path));
target->stencilPath(p, stroke, path.getFillType());
diff --git a/src/gpu/GrStencilAndCoverPathRenderer.h b/src/gpu/GrStencilAndCoverPathRenderer.h
index 9a8dd57..3b830e3 100644
--- a/src/gpu/GrStencilAndCoverPathRenderer.h
+++ b/src/gpu/GrStencilAndCoverPathRenderer.h
@@ -21,31 +21,31 @@
class GrStencilAndCoverPathRenderer : public GrPathRenderer {
public:
- static GrPathRenderer* Create(GrContext* context);
+ static GrPathRenderer* Create(GrContext*);
virtual ~GrStencilAndCoverPathRenderer();
- virtual bool canDrawPath(const SkPath& path,
- const SkStroke& stroke,
- const GrDrawTarget* target,
+ virtual bool canDrawPath(const SkPath&,
+ const SkStroke&,
+ const GrDrawTarget*,
bool antiAlias) const SK_OVERRIDE;
- virtual bool requiresStencilPass(const SkPath& path,
- const SkStroke& stroke,
- const GrDrawTarget* target) const SK_OVERRIDE;
-
- virtual void drawPathToStencil(const SkPath& path,
- const SkStroke& stroke,
- GrDrawTarget* target) SK_OVERRIDE;
-
protected:
- virtual bool onDrawPath(const SkPath& path,
- const SkStroke& stroke,
- GrDrawTarget* target,
+ virtual StencilSupport onGetStencilSupport(const SkPath&,
+ const SkStroke&,
+ const GrDrawTarget*) const SK_OVERRIDE;
+
+ virtual bool onDrawPath(const SkPath&,
+ const SkStroke&,
+ GrDrawTarget*,
bool antiAlias) SK_OVERRIDE;
+ virtual void onStencilPath(const SkPath&,
+ const SkStroke&,
+ GrDrawTarget*) SK_OVERRIDE;
+
private:
- GrStencilAndCoverPathRenderer(GrGpu* gpu);
+ GrStencilAndCoverPathRenderer(GrGpu*);
GrGpu* fGpu;
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 0283a5a..ba86383 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -284,6 +284,9 @@
GrCrash("Unknown Edge Type!");
break;
}
+ if (fDesc.fDiscardIfOutsideEdge) {
+ builder->fFSCode.appendf("\tif (edgeAlpha <= 0) {\n\t\tdiscard;\n\t}\n");
+ }
*coverageVar = "edgeAlpha";
return true;
} else {
diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h
index d385e60..3902a8c 100644
--- a/src/gpu/gl/GrGLProgram.h
+++ b/src/gpu/gl/GrGLProgram.h
@@ -108,7 +108,10 @@
kDualSrcOutputCnt
};
+ // TODO: remove these two members when edge-aa can be rewritten as a GrEffect.
GrDrawState::VertexEdgeType fVertexEdgeType;
+ // should the FS discard if the edge-aa coverage is zero (to avoid stencil manipulation)
+ bool fDiscardIfOutsideEdge;
// stripped of bits that don't affect program generation
GrVertexLayout fVertexLayout;
diff --git a/src/gpu/gl/GrGpuGL_program.cpp b/src/gpu/gl/GrGpuGL_program.cpp
index 73f60ca..5850fc4 100644
--- a/src/gpu/gl/GrGpuGL_program.cpp
+++ b/src/gpu/gl/GrGpuGL_program.cpp
@@ -553,9 +553,11 @@
if (!skipCoverage && (desc->fVertexLayout &GrDrawTarget::kEdge_VertexLayoutBit)) {
desc->fVertexEdgeType = drawState.getVertexEdgeType();
+ desc->fDiscardIfOutsideEdge = drawState.getStencil().doesWrite();
} else {
- // use canonical value when not set to avoid cache misses
+ // Use canonical values when edge-aa is not enabled to avoid program cache misses.
desc->fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
+ desc->fDiscardIfOutsideEdge = false;
}
for (int s = 0; s < GrDrawState::kNumStages; ++s) {
diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp
index 1aaefbf..46d0820 100644
--- a/tests/GLProgramsTest.cpp
+++ b/tests/GLProgramsTest.cpp
@@ -92,8 +92,10 @@
pdesc.fVertexLayout |= GrDrawTarget::kEdge_VertexLayoutBit;
if (this->getCaps().shaderDerivativeSupport()) {
pdesc.fVertexEdgeType = (GrDrawState::VertexEdgeType) random_int(&random, GrDrawState::kVertexEdgeTypeCnt);
+ pdesc.fDiscardIfOutsideEdge = random.nextBool();
} else {
pdesc.fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
+ pdesc.fDiscardIfOutsideEdge = false;
}
} else {
}