aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-07-01 14:57:55 +0000
committerGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-07-01 14:57:55 +0000
commitee435122d7dcb9cd4be4524004b0de282c42848b (patch)
tree7e74d0c1edfe7df8a59aee965b36272d950b99c2
parentdb2a09f2408728871ed9e26eb1197cad6585a15d (diff)
Tesselate path once for tiled offscreen AA
Review URL: http://codereview.appspot.com/4661062/ git-svn-id: http://skia.googlecode.com/svn/trunk@1777 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r--gpu/include/GrContext.h2
-rw-r--r--gpu/include/GrPathRenderer.h201
-rw-r--r--gpu/include/GrScalar.h3
-rw-r--r--gpu/include/GrTesselatedPathRenderer.h14
-rw-r--r--gpu/src/GrContext.cpp23
-rw-r--r--gpu/src/GrGpu.cpp32
-rw-r--r--gpu/src/GrPathRenderer.cpp329
-rw-r--r--gpu/src/GrTesselatedPathRenderer.cpp96
8 files changed, 397 insertions, 303 deletions
diff --git a/gpu/include/GrContext.h b/gpu/include/GrContext.h
index 05282670a5..a8810f984c 100644
--- a/gpu/include/GrContext.h
+++ b/gpu/include/GrContext.h
@@ -580,7 +580,7 @@ private:
void drawClipIntoStencil();
- GrPathRenderer* getPathRenderer(const GrDrawTarget*, const GrPath&, GrPathFill);
+ GrPathRenderer* getPathRenderer(const GrPath&, GrPathFill);
struct OffscreenRecord;
diff --git a/gpu/include/GrPathRenderer.h b/gpu/include/GrPathRenderer.h
index d77aad66b2..6bc91b58a3 100644
--- a/gpu/include/GrPathRenderer.h
+++ b/gpu/include/GrPathRenderer.h
@@ -18,57 +18,46 @@
#define GrPathRenderer_DEFINED
#include "GrDrawTarget.h"
+#include "SkTemplates.h"
class SkPath;
struct GrPoint;
/**
* Base class for drawing paths into a GrDrawTarget.
+ * Paths may be drawn multiple times as when tiling for supersampling. The
+ * calls on GrPathRenderer to draw a path will look like this:
+ *
+ * pr->setPath(target, path, fill, translate); // sets the path to draw
+ * pr->drawPath(...); // draw the path
+ * pr->drawPath(...);
+ * ...
+ * pr->clearPath(); // finished with the path
*/
class GR_API GrPathRenderer : public GrRefCnt {
public:
GrPathRenderer(void);
-
/**
* Returns true if this path renderer is able to render the path.
* Returning false allows the caller to fallback to another path renderer.
*
- * @param target The target to draw into
* @param path The path to draw
* @param fill The fill rule to use
*
* @return true if the path can be drawn by this object, false otherwise.
*/
- virtual bool canDrawPath(const GrDrawTarget* target, const SkPath& path,
- GrPathFill fill) const = 0;
-
- /**
- * Draws a path into the draw target. The target will already have its draw
- * state configured for the draw.
- * @param target the target to draw into.
- * @param stages indicates which stages the are already
- * in use. All enabled stages expect positions
- * as texture coordinates. The path renderer
- * use the remaining stages for its path
- * filling algorithm.
- * @param path the path to draw.
- * @param fill the fill rule to apply.
- * @param translate optional additional translation to apply to
- * the path. NULL means (0,0).
- */
- virtual void drawPath(GrDrawTarget* target,
- GrDrawTarget::StageBitfield stages,
- const SkPath& path,
- GrPathFill fill,
- const GrPoint* translate) = 0;
+ virtual bool canDrawPath(const SkPath& path, GrPathFill fill) const = 0;
/**
* 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
+ * 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'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.
+ * The view matrix and render target set on the draw target may change
+ * before setPath/drawPath is called and so shouldn't be considered.
*
* @param target target that the path will be rendered to
* @param path the path that will be drawn
@@ -85,7 +74,59 @@ public:
GrPathFill fill) const { return false; }
/**
- * Draws a path to the stencil buffer. Assume the writable stencil bits
+ * @return true if the path renderer can perform anti-aliasing (aside from
+ * having FSAA enabled for a render target). Target is provided to
+ * communicate the draw state (blend mode, stage settings, etc).
+ */
+ virtual bool supportsAA(GrDrawTarget* target,
+ const SkPath& path,
+ GrPathFill fill) { return false; }
+
+ /**
+ * Sets the path to render and target to render into. All calls to drawPath
+ * and drawPathToStencil must occur between setPath and clearPath. The
+ * path cannot be modified externally between setPath and clearPath. The
+ * path may be drawn several times (e.g. tiled supersampler). The target's
+ * state may change between setPath and drawPath* calls. However, if the
+ * path renderer specified vertices/indices during setPath or drawPath*
+ * they will still be set at subsequent drawPath* calls until the next
+ * clearPath. The target's draw state may change between drawPath* calls
+ * so if the subclass does any caching of tesselation, etc. then it must
+ * validate that target parameters that guided the decisions still hold.
+ *
+ * @param target the target to draw into.
+ * @param path the path to draw.
+ * @param fill the fill rule to apply.
+ * @param translate optional additional translation to apply to
+ * the path. NULL means (0,0).
+ */
+ void setPath(GrDrawTarget* target,
+ const SkPath* path,
+ GrPathFill fill,
+ const GrPoint* translate);
+
+ /**
+ * Notifies path renderer that path set in setPath is no longer in use.
+ */
+ void clearPath();
+
+ /**
+ * 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).
+ *
+ * Only called between setPath / clearPath.
+ *
+ * @param stages bitfield that indicates which stages are
+ * in use. All enabled stages expect positions
+ * as texture coordinates. The path renderer
+ * use the remaining stages for its path
+ * filling algorithm.
+ */
+ virtual void drawPath(GrDrawTarget::StageBitfield stages) = 0;
+
+ /**
+ * Draws the path to the stencil buffer. Assume the writable stencil bits
* are already initialized to zero. Fill will always be either
* kWinding_PathFill or kEvenOdd_PathFill.
*
@@ -95,27 +136,11 @@ public:
* The default implementation assumes the path filling algorithm doesn't
* require a separate stencil pass and so crashes.
*
- *
- * @param target the target to draw into.
- * @param path the path to draw.
- * @param fill the fill rule to apply.
- * @param translate optional additional translation to apply to
- * the path. NULL means (0,0).
+ * Only called between setPath / clearPath.
*/
- virtual void drawPathToStencil(GrDrawTarget* target,
- const SkPath& path,
- GrPathFill fill,
- const GrPoint* translate) {
+ virtual void drawPathToStencil() {
GrCrash("Unexpected call to drawPathToStencil.");
}
-
- /**
- * @return true if the path renderer can perform anti-aliasing (aside from
- * having FSAA enabled for a render target)
- */
- virtual bool supportsAA(GrDrawTarget* target,
- const SkPath& path,
- GrPathFill fill) { return false; }
/**
* This is called to install a custom path renderer in every GrContext at
@@ -134,8 +159,56 @@ public:
fCurveTolerance = SkScalarMul(fCurveTolerance, multiplier);
}
+ /**
+ * Helper that sets a path and automatically remove it in destructor.
+ */
+ class AutoClearPath {
+ public:
+ AutoClearPath() {
+ fPathRenderer = NULL;
+ }
+ AutoClearPath(GrPathRenderer* pr,
+ GrDrawTarget* target,
+ const SkPath* path,
+ GrPathFill fill,
+ const GrPoint* translate) {
+ GrAssert(NULL != pr);
+ pr->setPath(target, path, fill, translate);
+ fPathRenderer = pr;
+ }
+ void set(GrPathRenderer* pr,
+ GrDrawTarget* target,
+ const SkPath* path,
+ GrPathFill fill,
+ const GrPoint* translate) {
+ if (NULL != fPathRenderer) {
+ fPathRenderer->clearPath();
+ }
+ GrAssert(NULL != pr);
+ pr->setPath(target, path, fill, translate);
+ fPathRenderer = pr;
+ }
+ ~AutoClearPath() {
+ if (NULL != fPathRenderer) {
+ fPathRenderer->clearPath();
+ }
+ }
+ private:
+ GrPathRenderer* fPathRenderer;
+ };
+
protected:
+
+ // subclass can override these to be notified just after a path is set
+ // and just before the path is cleared.
+ virtual void pathWasSet() {}
+ virtual void pathWillClear() {}
+
GrScalar fCurveTolerance;
+ const SkPath* fPath;
+ GrDrawTarget* fTarget;
+ GrPathFill fFill;
+ GrPoint fTranslate;
private:
@@ -151,35 +224,37 @@ public:
GrDefaultPathRenderer(bool separateStencilSupport,
bool stencilWrapOpsSupport);
- virtual bool canDrawPath(const GrDrawTarget* target,
- const SkPath& path,
+ virtual bool canDrawPath(const SkPath& path,
GrPathFill fill) const { return true; }
- virtual void drawPath(GrDrawTarget* target,
- GrDrawTarget::StageBitfield stages,
- const SkPath& path,
- GrPathFill fill,
- const GrPoint* translate);
virtual bool requiresStencilPass(const GrDrawTarget* target,
const SkPath& path,
GrPathFill fill) const;
- virtual void drawPathToStencil(GrDrawTarget* target,
- const SkPath& path,
- GrPathFill fill,
- const GrPoint* translate);
+
+ virtual void drawPath(GrDrawTarget::StageBitfield stages);
+ virtual void drawPathToStencil();
+
+protected:
+ virtual void pathWillClear();
+
private:
- void onDrawPath(GrDrawTarget* target,
- GrDrawTarget::StageBitfield stages,
- const SkPath& path,
- GrPathFill fill,
- const GrPoint* translate,
- bool stencilOnly);
+ void onDrawPath(GrDrawTarget::StageBitfield stages, bool stencilOnly);
+
+ void createGeom(GrScalar srcSpaceTolSqd,
+ GrDrawTarget::StageBitfield stages);
bool fSeparateStencil;
bool fStencilWrapOps;
+ int fSubpathCount;
+ SkAutoSTMalloc<8, uint16_t> fSubpathVertCount;
+ GrScalar fPreviousSrcTol;
+ GrDrawTarget::StageBitfield fPreviousStages;
+
+
typedef GrPathRenderer INHERITED;
};
#endif
+
diff --git a/gpu/include/GrScalar.h b/gpu/include/GrScalar.h
index 35cd61a22c..409e80b6e6 100644
--- a/gpu/include/GrScalar.h
+++ b/gpu/include/GrScalar.h
@@ -39,7 +39,8 @@
#define GrIntToScalar(a) SkIntToScalar(a)
#define GrScalarHalf(a) SkScalarHalf(a)
#define GrScalarAve(a,b) SkScalarAve(a,b)
-#define GrMul(a,b) SkScalarMul(a,b)
+#define GrMul(a,b) SkScalarMul(a,b) // deprecated, prefer GrScalarMul
+#define GrScalarMul(a,b) SkScalarMul(a,b)
#define GrScalarDiv(a,b) SkScalarDiv(a, b)
#define GrScalarToFloat(a) SkScalarToFloat(a)
#define GrFloatToScalar(a) SkScalarToFloat(a)
diff --git a/gpu/include/GrTesselatedPathRenderer.h b/gpu/include/GrTesselatedPathRenderer.h
index e37e66bdf8..dac9a17c8f 100644
--- a/gpu/include/GrTesselatedPathRenderer.h
+++ b/gpu/include/GrTesselatedPathRenderer.h
@@ -23,22 +23,14 @@ class GrTesselatedPathRenderer : public GrPathRenderer {
public:
GrTesselatedPathRenderer();
- virtual void drawPath(GrDrawTarget* target,
- GrDrawTarget::StageBitfield stages,
- const GrPath& path,
- GrPathFill fill,
- const GrPoint* translate);
- virtual bool canDrawPath(const GrDrawTarget* target,
- const GrPath& path,
+ virtual void drawPath(GrDrawTarget::StageBitfield stages);
+ virtual bool canDrawPath(const GrPath& path,
GrPathFill fill) const;
virtual bool requiresStencilPass(const GrDrawTarget* target,
const GrPath& path,
GrPathFill fill) const { return false; }
- virtual void drawPathToStencil(GrDrawTarget* target,
- const GrPath& path,
- GrPathFill fill,
- const GrPoint* translate);
+ virtual void drawPathToStencil();
virtual bool supportsAA(GrDrawTarget* target,
const GrPath& path,
GrPathFill fill);
diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp
index 4982704c6d..eee73d9554 100644
--- a/gpu/src/GrContext.cpp
+++ b/gpu/src/GrContext.cpp
@@ -715,7 +715,7 @@ void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
OffscreenRecord* record) {
SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
GrAssert(NULL != record->fEntry0);
-
+ GrDrawTarget::AutoGeometryPush agp(target);
GrIRect tileRect;
tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
@@ -1321,7 +1321,9 @@ void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
GrPathFill fill, const GrPoint* translate) {
GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
- GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
+ GrPathRenderer* pr = this->getPathRenderer(path, fill);
+ GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, translate);
+ GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
if (!pr->supportsAA(target, path, fill) &&
this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
@@ -1357,13 +1359,12 @@ void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
for (int tx = 0; tx < record.fTileCountX; ++tx) {
for (int ty = 0; ty < record.fTileCountY; ++ty) {
this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
- pr->drawPath(target, 0, path, fill, translate);
+ pr->drawPath(0);
this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
}
}
this->cleanupOffscreenAA(target, pr, &record);
if (IsFillInverted(fill) && bound != clipIBounds) {
- int stageMask = paint.getActiveStageMask();
GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
GrRect rect;
if (clipIBounds.fTop < bound.fTop) {
@@ -1389,11 +1390,8 @@ void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
}
return;
}
- }
-
- GrDrawTarget::StageBitfield enabledStages = paint.getActiveStageMask();
-
- pr->drawPath(target, enabledStages, path, fill, translate);
+ }
+ pr->drawPath(stageMask);
}
////////////////////////////////////////////////////////////////////////////////
@@ -1690,14 +1688,13 @@ const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
return fGpu->getQuadIndexBuffer();
}
-GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
- const GrPath& path,
+GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
GrPathFill fill) {
if (NULL != fCustomPathRenderer &&
- fCustomPathRenderer->canDrawPath(target, path, fill)) {
+ fCustomPathRenderer->canDrawPath(path, fill)) {
return fCustomPathRenderer;
} else {
- GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
+ GrAssert(fDefaultPathRenderer.canDrawPath(path, fill));
return &fDefaultPathRenderer;
}
}
diff --git a/gpu/src/GrGpu.cpp b/gpu/src/GrGpu.cpp
index 192d29b0d4..62c96f524a 100644
--- a/gpu/src/GrGpu.cpp
+++ b/gpu/src/GrGpu.cpp
@@ -24,9 +24,8 @@
#include "GrPathRenderer.h"
// probably makes no sense for this to be less than a page
-static const size_t VERTEX_POOL_VB_SIZE = 1 << 12;
-static const int VERTEX_POOL_VB_COUNT = 1;
-
+static const size_t VERTEX_POOL_VB_SIZE = 1 << 18;
+static const int VERTEX_POOL_VB_COUNT = 4;
////////////////////////////////////////////////////////////////////////////////
@@ -454,6 +453,7 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
// with the existing clip.
for (int c = firstElement; c < count; ++c) {
GrPathFill fill;
+ bool fillInverted;
// enabled at bottom of loop
this->disableState(kModifyStencilClip_StateBit);
@@ -465,16 +465,20 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
GrPathRenderer* pr = NULL;
const GrPath* clipPath = NULL;
+ GrPathRenderer::AutoClearPath arp;
if (kRect_ClipType == clip.getElementType(c)) {
canRenderDirectToStencil = true;
fill = kEvenOdd_PathFill;
+ fillInverted = false;
} else {
fill = clip.getPathFill(c);
+ fillInverted = IsFillInverted(fill);
+ fill = NonInvertedFill(fill);
clipPath = &clip.getPath(c);
- pr = this->getClipPathRenderer(*clipPath, NonInvertedFill(fill));
+ pr = this->getClipPathRenderer(*clipPath, fill);
canRenderDirectToStencil =
- !pr->requiresStencilPass(this, *clipPath,
- NonInvertedFill(fill));
+ !pr->requiresStencilPass(this, *clipPath, fill);
+ arp.set(pr, this, clipPath, fill, NULL);
}
GrSetOp op = firstElement == c ? kReplace_SetOp : clip.getOp(c);
@@ -489,7 +493,7 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
GrStencilSettings::GetClipPasses(op,
canRenderDirectToStencil,
clipBit,
- IsFillInverted(fill),
+ fillInverted,
&passes, stencilSettings);
// draw the element to the client stencil bits if necessary
@@ -509,12 +513,9 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
} else {
if (canRenderDirectToStencil) {
this->setStencil(gDrawToStencil);
- pr->drawPath(this, 0, *clipPath, NonInvertedFill(fill),
- NULL);
+ pr->drawPath(0);
} else {
- pr->drawPathToStencil(this, *clipPath,
- NonInvertedFill(fill),
- NULL);
+ pr->drawPathToStencil();
}
}
}
@@ -530,8 +531,7 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
this->drawSimpleRect(clip.getRect(c), NULL, 0);
} else {
SET_RANDOM_COLOR
- GrAssert(!IsFillInverted(fill));
- pr->drawPath(this, 0, *clipPath, fill, NULL);
+ pr->drawPath(0);
}
} else {
SET_RANDOM_COLOR
@@ -558,7 +558,7 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
GrPathRenderer* GrGpu::getClipPathRenderer(const GrPath& path,
GrPathFill fill) {
if (NULL != fClientPathRenderer &&
- fClientPathRenderer->canDrawPath(this, path, fill)) {
+ fClientPathRenderer->canDrawPath(path, fill)) {
return fClientPathRenderer;
} else {
if (NULL == fDefaultPathRenderer) {
@@ -566,7 +566,7 @@ GrPathRenderer* GrGpu::getClipPathRenderer(const GrPath& path,
new GrDefaultPathRenderer(this->supportsTwoSidedStencil(),
this->supportsStencilWrapOps());
}
- GrAssert(fDefaultPathRenderer->canDrawPath(this, path, fill));
+ GrAssert(fDefaultPathRenderer->canDrawPath(path, fill));
return fDefaultPathRenderer;
}
}
diff --git a/gpu/src/GrPathRenderer.cpp b/gpu/src/GrPathRenderer.cpp
index 1e3c64518b..b103880d21 100644
--- a/gpu/src/GrPathRenderer.cpp
+++ b/gpu/src/GrPathRenderer.cpp
@@ -11,15 +11,49 @@
#include SK_USER_TRACE_INCLUDE_FILE
GrPathRenderer::GrPathRenderer()
- : fCurveTolerance (GR_Scalar1) {
+ : fCurveTolerance (GR_Scalar1)
+ , fPath(NULL)
+ , fTarget(NULL) {
+}
+
+
+void GrPathRenderer::setPath(GrDrawTarget* target,
+ const SkPath* path,
+ GrPathFill fill,
+ const GrPoint* translate) {
+ GrAssert(NULL == fPath);
+ GrAssert(NULL == fTarget);
+ GrAssert(NULL != target);
+
+ fTarget = target;
+ fPath = path;
+ fFill = fill;
+ if (NULL != translate) {
+ fTranslate = *translate;
+ } else {
+ fTranslate.fX = fTranslate.fY = 0;
+ }
+ this->pathWasSet();
+}
+void GrPathRenderer::clearPath() {
+ this->pathWillClear();
+ fTarget->resetVertexSource();
+ fTarget = NULL;
+ fPath = NULL;
}
-
+
+////////////////////////////////////////////////////////////////////////////////
+
GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
bool stencilWrapOpsSupport)
: fSeparateStencil(separateStencilSupport)
- , fStencilWrapOps(stencilWrapOpsSupport) {
-
+ , fStencilWrapOps(stencilWrapOpsSupport)
+ , fSubpathCount(0)
+ , fSubpathVertCount(0)
+ , fPreviousSrcTol(-GR_Scalar1)
+ , fPreviousStages(-1) {
+ fTarget = NULL;
}
////////////////////////////////////////////////////////////////////////////////
@@ -189,21 +223,105 @@ bool GrDefaultPathRenderer::requiresStencilPass(const GrDrawTarget* target,
return !single_pass_path(*target, path, fill);
}
-void GrDefaultPathRenderer::onDrawPath(GrDrawTarget* target,
- GrDrawTarget::StageBitfield stages,
- const GrPath& path,
- GrPathFill fill,
- const GrPoint* translate,
+void GrDefaultPathRenderer::pathWillClear() {
+ fSubpathVertCount.realloc(0);
+ fTarget->resetVertexSource();
+ fPreviousSrcTol = -GR_Scalar1;
+ fPreviousStages = -1;
+}
+
+void GrDefaultPathRenderer::createGeom(GrScalar srcSpaceTol,
+ GrDrawTarget::StageBitfield stages) {
+ {
+ SK_TRACE_EVENT0("GrDefaultPathRenderer::createGeom");
+
+ fPreviousSrcTol = srcSpaceTol;
+ fPreviousStages = stages;
+
+ GrScalar srcSpaceTolSqd = GrMul(srcSpaceTol, srcSpaceTol);
+ int maxPts = GrPathUtils::worstCasePointCount(*fPath, &fSubpathCount,
+ srcSpaceTol);
+
+ GrVertexLayout layout = 0;
+ for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
+ if ((1 << s) & stages) {
+ layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
+ }
+ }
+
+ // add 4 to hold the bounding rect
+ GrPoint* base;
+ fTarget->reserveVertexSpace(layout, maxPts + 4, (void**)&base);
+
+ GrPoint* vert = base;
+ GrPoint* subpathBase = base;
+
+ fSubpathVertCount.realloc(fSubpathCount);
+
+ GrPoint pts[4];
+
+ bool first = true;
+ int subpath = 0;
+
+ SkPath::Iter iter(*fPath, false);
+
+ for (;;) {
+ GrPathCmd cmd = (GrPathCmd)iter.next(pts);
+ switch (cmd) {
+ case kMove_PathCmd:
+ if (!first) {
+ fSubpathVertCount[subpath] = vert-subpathBase;
+ subpathBase = vert;
+ ++subpath;
+ }
+ *vert = pts[0];
+ vert++;
+ break;
+ case kLine_PathCmd:
+ *vert = pts[1];
+ vert++;
+ break;
+ case kQuadratic_PathCmd: {
+ GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2],
+ srcSpaceTolSqd, &vert,
+ GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
+ break;
+ }
+ case kCubic_PathCmd: {
+ GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3],
+ srcSpaceTolSqd, &vert,
+ GrPathUtils::cubicPointCount(pts, srcSpaceTol));
+ break;
+ }
+ case kClose_PathCmd:
+ break;
+ case kEnd_PathCmd:
+ fSubpathVertCount[subpath] = vert-subpathBase;
+ ++subpath; // this could be only in debug
+ goto FINISHED;
+ }
+ first = false;
+ }
+FINISHED:
+ GrAssert(subpath == fSubpathCount);
+ GrAssert((vert - base) <= maxPts);
+
+ if (fTranslate.fX || fTranslate.fY) {
+ int count = vert - base;
+ for (int i = 0; i < count; i++) {
+ base[i].offset(fTranslate.fX, fTranslate.fY);
+ }
+ }
+ }
+}
+
+void GrDefaultPathRenderer::onDrawPath(GrDrawTarget::StageBitfield stages,
bool stencilOnly) {
+
SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath",
"points", SkStringPrintf("%i", path.countPoints()).c_str());
- GrDrawTarget::AutoStateRestore asr(target);
- bool colorWritesWereDisabled = target->isColorWriteDisabled();
- // face culling doesn't make sense here
- GrAssert(GrDrawTarget::kBoth_DrawFace == target->getDrawFace());
-
- GrMatrix viewM = target->getViewMatrix();
+ GrMatrix viewM = fTarget->getViewMatrix();
// In order to tesselate the path we get a bound on how much the matrix can
// stretch when mapping to screen coordinates.
GrScalar stretch = viewM.getMaxStretch();
@@ -216,28 +334,25 @@ void GrDefaultPathRenderer::onDrawPath(GrDrawTarget* target,
} else {
tol = GrScalarDiv(tol, stretch);
}
- GrScalar tolSqd = GrMul(tol, tol);
-
- int subpathCnt;
- int maxPts = GrPathUtils::worstCasePointCount(path, &subpathCnt, tol);
-
- GrVertexLayout layout = 0;
- for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
- if ((1 << s) & stages) {
- layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
- }
+ // FIXME: It's really dumb that we recreate the verts for a new vertex
+ // layout. We only do that because the GrDrawTarget API doesn't allow
+ // us to change the vertex layout after reserveVertexSpace(). We won't
+ // actually change the vertex data when the layout changes since all the
+ // stages reference the positions (rather than having separate tex coords)
+ // and we don't ever have per-vert colors. In practice our call sites
+ // won't change the stages in use inside a setPath / removePath pair. But
+ // it is a silly limitation of the GrDrawTarget design that should be fixed.
+ if (tol != fPreviousSrcTol ||
+ stages != fPreviousStages) {
+ this->createGeom(tol, stages);
}
- // add 4 to hold the bounding rect
- GrDrawTarget::AutoReleaseGeometry arg(target, layout, maxPts + 4, 0);
-
- GrPoint* base = (GrPoint*) arg.vertices();
- GrPoint* vert = base;
- GrPoint* subpathBase = base;
-
- SkAutoSTMalloc<8, uint16_t> subpathVertCount(subpathCnt);
+ GrAssert(NULL != fTarget);
+ GrDrawTarget::AutoStateRestore asr(fTarget);
+ bool colorWritesWereDisabled = fTarget->isColorWriteDisabled();
+ // face culling doesn't make sense here
+ GrAssert(GrDrawTarget::kBoth_DrawFace == fTarget->getDrawFace());
- // TODO: use primitve restart if available rather than multiple draws
GrPrimitiveType type;
int passCount = 0;
const GrStencilSettings* passes[3];
@@ -245,7 +360,7 @@ void GrDefaultPathRenderer::onDrawPath(GrDrawTarget* target,
bool reverse = false;
bool lastPassIsBounds;
- if (kHairLine_PathFill == fill) {
+ if (kHairLine_PathFill == fFill) {
type = kLineStrip_PrimitiveType;
passCount = 1;
if (stencilOnly) {
@@ -257,7 +372,7 @@ void GrDefaultPathRenderer::onDrawPath(GrDrawTarget* target,
drawFace[0] = GrDrawTarget::kBoth_DrawFace;
} else {
type = kTriangleFan_PrimitiveType;
- if (single_pass_path(*target, path, fill)) {
+ if (single_pass_path(*fTarget, *fPath, fFill)) {
passCount = 1;
if (stencilOnly) {
passes[0] = &gDirectToStencil;
@@ -267,7 +382,7 @@ void GrDefaultPathRenderer::onDrawPath(GrDrawTarget* target,
drawFace[0] = GrDrawTarget::kBoth_DrawFace;
lastPassIsBounds = false;
} else {
- switch (fill) {
+ switch (fFill) {
case kInverseEvenOdd_PathFill:
reverse = true;
// fallthrough
@@ -327,140 +442,62 @@ void GrDefaultPathRenderer::onDrawPath(GrDrawTarget* target,
}
break;
default:
- GrAssert(!"Unknown path fill!");
+ GrAssert(!"Unknown path fFill!");
return;
}
}
}
- GrPoint pts[4];
-
- bool first = true;
- int subpath = 0;
-
- SkPath::Iter iter(path, false);
-
- {
- SK_TRACE_EVENT0("GrDefaultPathRenderer::onDrawPath::assembleVerts");
- for (;;) {
-
- GrPathCmd cmd = (GrPathCmd)iter.next(pts);
- switch (cmd) {
- case kMove_PathCmd:
- if (!first) {
- subpathVertCount[subpath] = vert-subpathBase;
- subpathBase = vert;
- ++subpath;
- }
- *vert = pts[0];
- vert++;
- break;
- case kLine_PathCmd:
- *vert = pts[1];
- vert++;
- break;
- case kQuadratic_PathCmd: {
- GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2],
- tolSqd, &vert,
- GrPathUtils::quadraticPointCount(pts, tol));
- break;
- }
- case kCubic_PathCmd: {
- GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3],
- tolSqd, &vert,
- GrPathUtils::cubicPointCount(pts, tol));
- break;
- }
- case kClose_PathCmd:
- break;
- case kEnd_PathCmd:
- subpathVertCount[subpath] = vert-subpathBase;
- ++subpath; // this could be only in debug
- goto FINISHED;
- }
- first = false;
- }
- }
-FINISHED:
- GrAssert(subpath == subpathCnt);
- GrAssert((vert - base) <= maxPts);
-
- if (translate) {
- int count = vert - base;
- for (int i = 0; i < count; i++) {
- base[i].offset(translate->fX, translate->fY);
- }
- }
-
- // if we're stenciling we will follow with a pass that draws
- // a bounding rect to set the color. We're stenciling when
- // passCount > 1.
- const int& boundVertexStart = maxPts;
- GrPoint* boundsVerts = base + boundVertexStart;
- if (lastPassIsBounds) {
- GrRect bounds;
- if (reverse) {
- GrAssert(NULL != target->getRenderTarget());
- // draw over the whole world.
- bounds.setLTRB(0, 0,
- GrIntToScalar(target->getRenderTarget()->width()),
- GrIntToScalar(target->getRenderTarget()->height()));
- GrMatrix vmi;
- if (target->getViewInverse(&vmi)) {
- vmi.mapRect(&bounds);
- }
- } else {
- bounds.setBounds((GrPoint*)base, vert - base);
- }
- boundsVerts[0].setRectFan(bounds.fLeft, bounds.fTop, bounds.fRight,
- bounds.fBottom);
- }
-
{
SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath::renderPasses",
"verts", SkStringPrintf("%i", vert - base).c_str());
for (int p = 0; p < passCount; ++p) {
- target->setDrawFace(drawFace[p]);
+ fTarget->setDrawFace(drawFace[p]);
if (NULL != passes[p]) {
- target->setStencil(*passes[p]);
+ fTarget->setStencil(*passes[p]);
}
if (lastPassIsBounds && (p == passCount-1)) {
if (!colorWritesWereDisabled) {
- target->disableState(GrDrawTarget::kNoColorWrites_StateBit);
+ fTarget->disableState(GrDrawTarget::kNoColorWrites_StateBit);
}
- target->drawNonIndexed(kTriangleFan_PrimitiveType,
- boundVertexStart, 4);
-
+ GrRect bounds;
+ if (reverse) {
+ GrAssert(NULL != fTarget->getRenderTarget());
+ // draw over the whole world.
+ bounds.setLTRB(0, 0,
+ GrIntToScalar(fTarget->getRenderTarget()->width()),
+ GrIntToScalar(fTarget->getRenderTarget()->height()));
+ GrMatrix vmi;
+ if (fTarget->getViewInverse(&vmi)) {
+ vmi.mapRect(&bounds);
+ }
+ } else {
+ bounds = fPath->getBounds();
+ }
+ GrDrawTarget::AutoGeometryPush agp(fTarget);
+ fTarget->drawSimpleRect(bounds, NULL, stages);
} else {
if (passCount > 1) {
- target->enableState(GrDrawTarget::kNoColorWrites_StateBit);
+ fTarget->enableState(GrDrawTarget::kNoColorWrites_StateBit);
}
int baseVertex = 0;
- for (int sp = 0; sp < subpathCnt; ++sp) {
- target->drawNonIndexed(type,
- baseVertex,
- subpathVertCount[sp]);
- baseVertex += subpathVertCount[sp];
+ for (int sp = 0; sp < fSubpathCount; ++sp) {
+ fTarget->drawNonIndexed(type, baseVertex,
+ fSubpathVertCount[sp]);
+ baseVertex += fSubpathVertCount[sp];
}
}
}
}
}
-void GrDefaultPathRenderer::drawPath(GrDrawTarget* target,
- GrDrawTarget::StageBitfield stages,
- const GrPath& path,
- GrPathFill fill,
- const GrPoint* translate) {
- this->onDrawPath(target, stages, path, fill, translate, false);
+void GrDefaultPathRenderer::drawPath(GrDrawTarget::StageBitfield stages) {
+ this->onDrawPath(stages, false);
}
-void GrDefaultPathRenderer::drawPathToStencil(GrDrawTarget* target,
- const GrPath& path,
- GrPathFill fill,
- const GrPoint* translate) {
- GrAssert(kInverseEvenOdd_PathFill != fill);
- GrAssert(kInverseWinding_PathFill != fill);
- this->onDrawPath(target, 0, path, fill, translate, true);
+void GrDefaultPathRenderer::drawPathToStencil() {
+ GrAssert(kInverseEvenOdd_PathFill != fFill);
+ GrAssert(kInverseWinding_PathFill != fFill);
+ this->onDrawPath(0, true);
}
diff --git a/gpu/src/GrTesselatedPathRenderer.cpp b/gpu/src/GrTesselatedPathRenderer.cpp
index 5ddba99e38..c85040a941 100644
--- a/gpu/src/GrTesselatedPathRenderer.cpp
+++ b/gpu/src/GrTesselatedPathRenderer.cpp
@@ -33,7 +33,7 @@ typedef void (*TESSCB)();
// limit the allowable vertex range to approximately half of the representable
// IEEE exponent in order to avoid overflow when doing multiplies between
// vertex components,
-const float kMaxVertexValue = 1e18;
+const float kMaxVertexValue = 1e18f;
static inline GrDrawTarget::Edge computeEdge(const GrPoint& p,
const GrPoint& q,
@@ -352,16 +352,12 @@ static size_t computeEdgesAndIntersect(const GrMatrix& matrix,
return edges->count();
}
-void GrTesselatedPathRenderer::drawPath(GrDrawTarget* target,
- GrDrawTarget::StageBitfield stages,
- const GrPath& path,
- GrPathFill fill,
- const GrPoint* translate) {
- GrDrawTarget::AutoStateRestore asr(target);
+void GrTesselatedPathRenderer::drawPath(GrDrawTarget::StageBitfield stages) {
+ GrDrawTarget::AutoStateRestore asr(fTarget);
// face culling doesn't make sense here
- GrAssert(GrDrawTarget::kBoth_DrawFace == target->getDrawFace());
+ GrAssert(GrDrawTarget::kBoth_DrawFace == fTarget->getDrawFace());
- GrMatrix viewM = target->getViewMatrix();
+ GrMatrix viewM = fTarget->getViewMatrix();
// In order to tesselate the path we get a bound on how much the matrix can
// stretch when mapping to screen coordinates.
GrScalar stretch = viewM.getMaxStretch();
@@ -377,7 +373,7 @@ void GrTesselatedPathRenderer::drawPath(GrDrawTarget* target,
GrScalar tolSqd = GrMul(tol, tol);
int subpathCnt;
- int maxPts = GrPathUtils::worstCasePointCount(path, &subpathCnt, tol);
+ int maxPts = GrPathUtils::worstCasePointCount(*fPath, &subpathCnt, tol);
GrVertexLayout layout = 0;
for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
@@ -386,7 +382,7 @@ void GrTesselatedPathRenderer::drawPath(GrDrawTarget* target,
}
}
- bool inverted = IsFillInverted(fill);
+ bool inverted = IsFillInverted(fFill);
if (inverted) {
maxPts += 4;
subpathCnt++;
@@ -402,7 +398,7 @@ void GrTesselatedPathRenderer::drawPath(GrDrawTarget* target,
SkAutoSTMalloc<8, uint16_t> subpathVertCount(subpathCnt);
GrPoint pts[4];
- SkPath::Iter iter(path, false);
+ SkPath::Iter iter(*fPath, false);
bool first = true;
int subpath = 0;
@@ -444,20 +440,20 @@ void GrTesselatedPathRenderer::drawPath(GrDrawTarget* target,
first = false;
}
FINISHED:
- if (translate) {
+ if (0 != fTranslate.fX || 0 != fTranslate.fY) {
for (int i = 0; i < vert - base; i++) {
- base[i].offset(translate->fX, translate->fY);
+ base[i].offset(fTranslate.fX, fTranslate.fY);
}
}
if (inverted) {
GrRect bounds;
- GrAssert(NULL != target->getRenderTarget());
+ GrAssert(NULL != fTarget->getRenderTarget());
bounds.setLTRB(0, 0,
- GrIntToScalar(target->getRenderTarget()->width()),
- GrIntToScalar(target->getRenderTarget()->height()));
+ GrIntToScalar(fTarget->getRenderTarget()->width()),
+ GrIntToScalar(fTarget->getRenderTarget()->height()));
GrMatrix vmi;
- if (target->getViewInverse(&vmi)) {
+ if (fTarget->getViewInverse(&vmi)) {
vmi.mapRect(&bounds);
}
*vert++ = GrPoint::Make(bounds.fLeft, bounds.fTop);
@@ -476,22 +472,22 @@ FINISHED:
return;
}
- if (subpathCnt == 1 && !inverted && path.isConvex()) {
- if (target->isAntialiasState()) {
+ if (subpathCnt == 1 && !inverted && fPath->isConvex()) {
+ if (fTarget->isAntialiasState()) {
GrEdgeArray edges;
- GrMatrix inverse, matrix = target->getViewMatrix();
- target->getViewInverse(&inverse);
+ GrMatrix inverse, matrix = fTarget->getViewMatrix();
+ fTarget->getViewInverse(&inverse);
count = computeEdgesAndIntersect(matrix, inverse, base, count, &edges, 0.0f);
- size_t maxEdges = target->getMaxEdges();
+ size_t maxEdges = fTarget->getMaxEdges();
if (count == 0) {
return;
}
if (count <= maxEdges) {
// All edges fit; upload all edges and draw all verts as a fan
- target->setVertexSourceToArray(layout, base, count);
- target->setEdgeAAData(&edges[0], count);
- target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count);
+ fTarget->setVertexSourceToArray(layout, base, count);
+ fTarget->setEdgeAAData(&edges[0], count);
+ fTarget->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count);
} else {
// Upload "maxEdges" edges and verts at a time, and draw as
// separate fans
@@ -499,26 +495,26 @@ FINISHED:
edges[i] = edges[0];
base[i] = base[0];
int size = GR_CT_MIN(count - i, maxEdges);
- target->setVertexSourceToArray(layout, &base[i], size);
- target->setEdgeAAData(&edges[i], size);
- target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, size);
+ fTarget->setVertexSourceToArray(layout, &base[i], size);
+ fTarget->setEdgeAAData(&edges[i], size);
+ fTarget->drawNonIndexed(kTriangleFan_PrimitiveType, 0, size);
}
}
- target->setEdgeAAData(NULL, 0);
+ fTarget->setEdgeAAData(NULL, 0);
} else {
- target->setVertexSourceToArray(layout, base, count);
- target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count);
+ fTarget->setVertexSourceToArray(layout, base, count);
+ fTarget->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count);
}
return;
}
- if (target->isAntialiasState()) {
+ if (fTarget->isAntialiasState()) {
// Run the tesselator once to get the boundaries.
- GrBoundaryTess btess(count, fill_type_to_glu_winding_rule(fill));
+ GrBoundaryTess btess(count, fill_type_to_glu_winding_rule(fFill));
btess.addVertices(base, subpathVertCount, subpathCnt);
- GrMatrix inverse, matrix = target->getViewMatrix();
- if (!target->getViewInverse(&inverse)) {
+ GrMatrix inverse, matrix = fTarget->getViewMatrix();
+ if (!fTarget->getViewInverse(&inverse)) {
return;
}
@@ -553,7 +549,7 @@ FINISHED:
}
// Draw the resulting polys and upload their edge data.
- target->enableState(GrDrawTarget::kEdgeAAConcave_StateBit);
+ fTarget->enableState(GrDrawTarget::kEdgeAAConcave_StateBit);
const GrPointArray& vertices = ptess.vertices();
const GrIndexArray& indices = ptess.indices();
const GrDrawTarget::Edge* edges = ptess.edges();
@@ -586,23 +582,23 @@ FINISHED:
tri_edges[t++] = edge4;
tri_edges[t++] = edge5;
}
- target->setEdgeAAData(&tri_edges[0], t);
- target->setVertexSourceToArray(layout, &tri_verts[0], 3);
- target->drawNonIndexed(kTriangles_PrimitiveType, 0, 3);
+ fTarget->setEdgeAAData(&tri_edges[0], t);
+ fTarget->setVertexSourceToArray(layout, &tri_verts[0], 3);
+ fTarget->drawNonIndexed(kTriangles_PrimitiveType, 0, 3);
}
- target->setEdgeAAData(NULL, 0);
- target->disableState(GrDrawTarget::kEdgeAAConcave_StateBit);
+ fTarget->setEdgeAAData(NULL, 0);
+ fTarget->disableState(GrDrawTarget::kEdgeAAConcave_StateBit);
return;
}
- GrPolygonTess ptess(count, fill_type_to_glu_winding_rule(fill));
+ GrPolygonTess ptess(count, fill_type_to_glu_winding_rule(fFill));
ptess.addVertices(base, subpathVertCount, subpathCnt);
const GrPointArray& vertices = ptess.vertices();
const GrIndexArray& indices = ptess.indices();
if (indices.count() > 0) {
- target->setVertexSourceToArray(layout, vertices.begin(), vertices.count());
- target->setIndexSourceToArray(indices.begin(), indices.count());
- target->drawIndexed(kTriangles_PrimitiveType,
+ fTarget->setVertexSourceToArray(layout, vertices.begin(), vertices.count());
+ fTarget->setIndexSourceToArray(indices.begin(), indices.count());
+ fTarget->drawIndexed(kTriangles_PrimitiveType,
0,
0,
vertices.count(),
@@ -610,16 +606,12 @@ FINISHED:
}
}
-bool GrTesselatedPathRenderer::canDrawPath(const GrDrawTarget* target,
- const SkPath& path,
+bool GrTesselatedPathRenderer::canDrawPath(const SkPath& path,
GrPathFill fill) const {
return kHairLine_PathFill != fill;
}
-void GrTesselatedPathRenderer::drawPathToStencil(GrDrawTarget* target,
- const SkPath& path,
- GrPathFill fill,
- const GrPoint* translate) {
+void GrTesselatedPathRenderer::drawPathToStencil() {
GrAlwaysAssert(!"multipass stencil should not be needed");
}