aboutsummaryrefslogtreecommitdiffhomepage
path: root/gpu
diff options
context:
space:
mode:
authorGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-03-04 20:29:08 +0000
committerGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-03-04 20:29:08 +0000
commit5aaa69e4339e229adfb05e96084a8ec0a590238b (patch)
tree0a4c274694b62f8e908d73adaa0d28215fd9fe7b /gpu
parentf7c2c4544f866ae65cd9a4eee4da563f6d653d20 (diff)
Fixups for clipstack, convexity test for paths.
Review URL http://codereview.appspot.com/4250056/ git-svn-id: http://skia.googlecode.com/svn/trunk@891 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'gpu')
-rw-r--r--gpu/include/GrClipIterator.h4
-rw-r--r--gpu/include/GrDrawTarget.h10
-rw-r--r--gpu/include/GrPath.h39
-rw-r--r--gpu/include/GrPathIter.h74
-rw-r--r--gpu/include/GrPoint.h49
-rw-r--r--gpu/include/GrRect.h14
-rw-r--r--gpu/include/GrStencil.h5
-rw-r--r--gpu/include/GrTypes.h111
-rw-r--r--gpu/src/GrGpu.cpp32
-rw-r--r--gpu/src/GrGpuGL.cpp14
-rw-r--r--gpu/src/GrGpuGLShaders2.cpp5
-rw-r--r--gpu/src/GrPath.cpp375
-rw-r--r--gpu/src/GrPathRenderer.cpp62
-rw-r--r--gpu/src/GrPathRenderer.h41
-rw-r--r--gpu/src/GrRedBlackTree.h16
-rw-r--r--gpu/src/GrStencil.cpp98
-rw-r--r--gpu/src/gr_unittests.cpp5
17 files changed, 691 insertions, 263 deletions
diff --git a/gpu/include/GrClipIterator.h b/gpu/include/GrClipIterator.h
index abad619623..1fcbdd178a 100644
--- a/gpu/include/GrClipIterator.h
+++ b/gpu/include/GrClipIterator.h
@@ -68,8 +68,8 @@ public:
virtual GrSetOp getOp() const = 0;
/**
- * Call to move to the next rect in the set, previous path iter can be made
- * invalid.
+ * Call to move to the next element in the list, previous path iter can be
+ * made invalid.
*/
virtual void next() = 0;
};
diff --git a/gpu/include/GrDrawTarget.h b/gpu/include/GrDrawTarget.h
index 576bd7ae41..285665b0c8 100644
--- a/gpu/include/GrDrawTarget.h
+++ b/gpu/include/GrDrawTarget.h
@@ -106,6 +106,9 @@ public:
/**
* Sets the stencil settings to use for the next draw.
+ * Changing the clip has the side-effect of possibly zeroing
+ * out the client settable stencil bits. So multipass algorithms
+ * using stencil should not change the clip between passes.
* @param settings the stencil settings to use.
*/
void setStencil(const GrStencilSettings& settings) {
@@ -156,6 +159,8 @@ public:
* Sets the current clip to the region specified by clip. All draws will be
* clipped against this clip if kClip_StateBit is enabled.
*
+ * Setting the clip may (or may not) zero out the client's stencil bits.
+ *
* @param description of the clipping region
*/
void setClip(const GrClip& clip);
@@ -965,6 +970,8 @@ public:
vertexIndex * vertexSize);
}
+ static void VertexLayoutUnitTest();
+
protected:
// Helpers for GrDrawTarget subclasses that won't have private access to
@@ -1047,9 +1054,6 @@ protected:
AutoGeometrySrcRestore(const AutoGeometrySrcRestore&);
AutoGeometrySrcRestore& operator =(AutoGeometrySrcRestore&);
};
-
-private:
- void VertexLayoutUnitTest();
};
#endif
diff --git a/gpu/include/GrPath.h b/gpu/include/GrPath.h
index 23fc4a86b6..d70609ee6b 100644
--- a/gpu/include/GrPath.h
+++ b/gpu/include/GrPath.h
@@ -30,8 +30,8 @@ public:
explicit GrPath(GrPathIter&);
virtual ~GrPath();
- GrPathIter::ConvexHint getConvexHint() const { return fConvexHint; }
- void setConvexHint(GrPathIter::ConvexHint hint) { fConvexHint = hint; }
+ GrConvexHint getConvexHint() const { return fConvexHint; }
+ void setConvexHint(GrConvexHint hint) { fConvexHint = hint; }
void resetFromIter(GrPathIter*);
@@ -48,35 +48,44 @@ public:
class Iter : public GrPathIter {
public:
+ /**
+ * Creates an uninitialized iterator
+ */
+ Iter();
+
Iter(const GrPath& path);
// overrides from GrPathIter
- virtual Command next(GrPoint points[]);
- virtual ConvexHint convexHint() const;
- virtual Command next();
+ virtual GrPathCmd next(GrPoint points[]);
+ virtual GrConvexHint convexHint() const;
+ virtual GrPathCmd next();
virtual void rewind();
+
+ /**
+ * Sets iterator to begining of path
+ */
+ void reset(const GrPath& path);
private:
- const GrPath& fPath;
+ const GrPath* fPath;
GrPoint fLastPt;
- int fVerbIndex;
+ int fCmdIndex;
int fPtIndex;
};
+ static void ConvexUnitTest();
+
private:
- enum Verb {
- kMove, kLine, kQuad, kCubic, kClose
- };
- GrTDArray<uint8_t> fVerbs;
+ GrTDArray<GrPathCmd> fCmds;
GrTDArray<GrPoint> fPts;
- GrPathIter::ConvexHint fConvexHint;
+ GrConvexHint fConvexHint;
// this ensures we have a moveTo at the start of each contour
inline void ensureMoveTo();
- bool wasLastVerb(Verb verb) const {
- int count = fVerbs.count();
- return count > 0 && verb == fVerbs[count - 1];
+ bool wasLastVerb(GrPathCmd cmd) const {
+ int count = fCmds.count();
+ return count > 0 && cmd == fCmds[count - 1];
}
friend class Iter;
diff --git a/gpu/include/GrPathIter.h b/gpu/include/GrPathIter.h
index 140cbcba56..f310184bd7 100644
--- a/gpu/include/GrPathIter.h
+++ b/gpu/include/GrPathIter.h
@@ -29,76 +29,36 @@ struct GrPoint;
*/
class GrPathIter {
public:
- /**
- Returned by next(). Indicates the next piece of the path.
- */
- enum Command {
- kMove_Command, //!< next() returns 1 pt
- // Starts a new subpath at
- // at the returned point
- kLine_Command, //!< next() returns 2 pts
- // Adds a line segment
- kQuadratic_Command, //!< next() returns 3 pts
- // Adds a quadratic segment
- kCubic_Command, //!< next() returns 4 pts
- // Adds a cubic segment
- kClose_Command, //!< next() returns 0 pts
- kEnd_Command //!< next() returns 0 pts
- // Implictly closes the last
- // point
- };
-
- enum ConvexHint {
- kNone_ConvexHint, //<! No hint about convexity
- // of the path
- kConvex_ConvexHint, //<! Path is one convex piece
- kNonOverlappingConvexPieces_ConvexHint, //<! Multiple convex pieces,
- // pieces are known to be
- // disjoint
- kSameWindingConvexPieces_ConvexHint, //<! Multiple convex pieces,
- // may or may not intersect,
- // either all wind cw or all
- // wind ccw.
- kConcave_ConvexHint //<! Path is known to be
- // concave
- };
-
- static int NumCommandPoints(Command cmd) {
- static const int numPoints[] = {
- 1, 2, 3, 4, 0, 0
- };
- return numPoints[cmd];
- }
virtual ~GrPathIter() {};
/**
- Iterates through the path. Should not be called after
- kEnd_Command has been returned once. This version retrieves the
- points for the command.
- @param points The points relevant to returned commend. See Command
- enum for number of points valid for each command.
- @return The next command of the path.
+ * Iterates through the path. Should not be called after
+ * kEnd_Command has been returned once. This version retrieves the
+ * points for the command.
+ * @param points The points relevant to returned commend. See Command
+ * enum for number of points valid for each command.
+ * @return The next command of the path.
*/
- virtual Command next(GrPoint points[4]) = 0;
+ virtual GrPathCmd next(GrPoint points[4]) = 0;
/**
* If the host API has knowledge of the convexity of the path
- * it can be communicated by this hint. Ganesh can make these
- * determinations itself. So it is not necessary to compute
- * convexity status if it isn't already determined.
+ * it can be communicated by this hint. Gr can analyze the path
+ * as it is iterated. So it is not necessary to do additional work to
+ * compute convexity status if it isn't already determined.
*
* @return a hint about the convexity of the path.
*/
- virtual ConvexHint convexHint() const { return kNone_ConvexHint; }
+ virtual GrConvexHint convexHint() const { return kNone_ConvexHint; }
/**
- Iterates through the path. Should not be called after
- kEnd_Command has been returned once. This version does not retrieve the
- points for the command.
- @return The next command of the path.
- */
- virtual Command next() = 0;
+ * Iterates through the path. Should not be called after
+ * kEnd_Command has been returned once. This version does not retrieve the
+ * points for the command.
+ * @return The next command of the path.
+ */
+ virtual GrPathCmd next() = 0;
/**
Restarts iteration from the beginning.
diff --git a/gpu/include/GrPoint.h b/gpu/include/GrPoint.h
index bb24959c34..c07543bb30 100644
--- a/gpu/include/GrPoint.h
+++ b/gpu/include/GrPoint.h
@@ -161,7 +161,47 @@ public:
fX = b.fX - a.fX;
fY = b.fY - a.fY;
}
-
+
+ /**
+ * Make this vector be orthogonal to vec. Looking down vec the
+ * new vector will point left.
+ */
+ void setOrthogLeft(const GrVec& vec) {
+ // vec could be this
+ GrVec v = vec;
+ fX = -v.fY;
+ fY = v.fX;
+ }
+
+ /**
+ * Make this vector be orthogonal to vec. Looking down vec the
+ * new vector will point right.
+ */
+ void setOrthogRight(const GrVec& vec) {
+ // vec could be this
+ GrVec v = vec;
+ fX = v.fY;
+ fY = -v.fX;
+ }
+
+ /**
+ * set orthogonal to vec from a to b. Will be facing left relative to a,b
+ * vec
+ */
+ void setOrthogLeftToVecBetween(const GrPoint& a, const GrPoint& b) {
+ fX = a.fY - b.fY;
+ fY = b.fX - a.fX;
+ }
+
+ /**
+ * set orthogonal to vec from a to b. Will be facing right relative to a,b
+ * vec.
+ */
+ void setOrthogRightToVecBetween(const GrPoint& a, const GrPoint& b) {
+ fX = b.fY - a.fY;
+ fY = a.fX - b.fX;
+ }
+
/**
* length of the vector squared.
*/
@@ -201,6 +241,13 @@ public:
}
/**
+ * Dot product of this vec with vector from (0,0) to a pt.
+ */
+ GrScalar dotWithVecToPt(const GrPoint& pt) const {
+ return GrMul(pt.fX, fX) + GrMul(pt.fY, fY);
+ }
+
+ /**
* z-value of this cross vec.
*/
GrScalar cross(const GrVec& vec) const {
diff --git a/gpu/include/GrRect.h b/gpu/include/GrRect.h
index 96d302f53d..e0e53264fd 100644
--- a/gpu/include/GrRect.h
+++ b/gpu/include/GrRect.h
@@ -205,12 +205,26 @@ struct GrRect {
return (fLeft > fRight) || (fTop > fBottom);
}
+ /**
+ * Does this rect contain a point.
+ */
bool contains(const GrPoint& point) const {
return point.fX >= fLeft && point.fX < fRight &&
point.fY >= fTop && point.fY < fBottom;
}
/**
+ * Does this rect fully contain another rect.
+ */
+ bool contains(const GrRect& r) const {
+ return fLeft <= r.fLeft &&
+ fRight >= r.fRight &&
+ fTop <= r.fTop &&
+ fBottom >= r.fBottom;
+ }
+
+
+ /**
* Initialize a rectangle to a point.
* @param pt the point used to initialize the rectangle.
*/
diff --git a/gpu/include/GrStencil.h b/gpu/include/GrStencil.h
index be3e0f66fb..b014ee5586 100644
--- a/gpu/include/GrStencil.h
+++ b/gpu/include/GrStencil.h
@@ -190,8 +190,7 @@ private:
* existing clip
* @param stencilClipMask mask with just the stencil bit used for clipping
* enabled.
- * @param fill in: the fill rule of the element to draw.
- * out: the fill rule that should be used to draw
+ * @param invertedFill is this path inverted
* @param numPasses out: the number of passes needed to add the
* element to the clip.
* @param settings out: the stencil settings to use for each pass
@@ -203,7 +202,7 @@ private:
static bool GetClipPasses(GrSetOp op,
bool canBeDirect,
unsigned int stencilClipMask,
- GrPathFill* fill,
+ bool invertedFill,
int* numPasses,
GrStencilSettings settings[kMaxStencilClipPasses]);
};
diff --git a/gpu/include/GrTypes.h b/gpu/include/GrTypes.h
index 29e847fd09..f407e2f444 100644
--- a/gpu/include/GrTypes.h
+++ b/gpu/include/GrTypes.h
@@ -161,19 +161,6 @@ template <typename Dst, typename Src> Dst GrTCast(Src src) {
typedef uint16_t GrVertexLayout;
/**
- * Path filling rules
- */
-enum GrPathFill {
- kWinding_PathFill,
- kEvenOdd_PathFill,
- kInverseWinding_PathFill,
- kInverseEvenOdd_PathFill,
- kHairLine_PathFill,
-
- kPathFillCount
-};
-
-/**
* Geometric primitives used for drawing.
*/
enum GrPrimitiveType {
@@ -221,6 +208,104 @@ enum GrClipType {
kPath_ClipType
};
+/**
+ * Commands used to describe a path. Each command
+ * is accompanied by some number of points.
+ */
+enum GrPathCmd {
+ kMove_PathCmd, //!< Starts a new subpath at
+ // at the returned point
+ // 1 point
+ kLine_PathCmd, //!< Adds a line segment
+ // 2 points
+ kQuadratic_PathCmd, //!< Adds a quadratic segment
+ // 3 points
+ kCubic_PathCmd, //!< Adds a cubic segment
+ // 4 points
+ kClose_PathCmd, //!< Closes the current subpath
+ // by connecting a line to the
+ // starting point.
+ // 0 points
+ kEnd_PathCmd //!< Indicates the end of the last subpath
+ // when iterating
+ // 0 points.
+};
+
+/**
+ * Gets the number of points associated with a path command.
+ */
+static int inline NumPathCmdPoints(GrPathCmd cmd) {
+ static const int gNumPoints[] = {
+ 1, 2, 3, 4, 0, 0
+ };
+ return gNumPoints[cmd];
+}
+
+/**
+ * Path filling rules
+ */
+enum GrPathFill {
+ kWinding_PathFill,
+ kEvenOdd_PathFill,
+ kInverseWinding_PathFill,
+ kInverseEvenOdd_PathFill,
+ kHairLine_PathFill,
+
+ kPathFillCount
+};
+
+static inline GrPathFill NonInvertedFill(GrPathFill fill) {
+ static const GrPathFill gNonInvertedFills[] = {
+ kWinding_PathFill, // kWinding_PathFill
+ kEvenOdd_PathFill, // kEvenOdd_PathFill
+ kWinding_PathFill, // kInverseWinding_PathFill
+ kEvenOdd_PathFill, // kInverseEvenOdd_PathFill
+ kHairLine_PathFill,// kHairLine_PathFill
+ };
+ GR_STATIC_ASSERT(0 == kWinding_PathFill);
+ GR_STATIC_ASSERT(1 == kEvenOdd_PathFill);
+ GR_STATIC_ASSERT(2 == kInverseWinding_PathFill);
+ GR_STATIC_ASSERT(3 == kInverseEvenOdd_PathFill);
+ GR_STATIC_ASSERT(4 == kHairLine_PathFill);
+ GR_STATIC_ASSERT(5 == kPathFillCount);
+ return gNonInvertedFills[fill];
+}
+
+static inline bool IsFillInverted(GrPathFill fill) {
+ static const bool gIsFillInverted[] = {
+ false, // kWinding_PathFill
+ false, // kEvenOdd_PathFill
+ true, // kInverseWinding_PathFill
+ true, // kInverseEvenOdd_PathFill
+ false, // kHairLine_PathFill
+ };
+ GR_STATIC_ASSERT(0 == kWinding_PathFill);
+ GR_STATIC_ASSERT(1 == kEvenOdd_PathFill);
+ GR_STATIC_ASSERT(2 == kInverseWinding_PathFill);
+ GR_STATIC_ASSERT(3 == kInverseEvenOdd_PathFill);
+ GR_STATIC_ASSERT(4 == kHairLine_PathFill);
+ GR_STATIC_ASSERT(5 == kPathFillCount);
+ return gIsFillInverted[fill];
+}
+
+/**
+ * Hints provided about a path's convexity (or lack thereof).
+ */
+enum GrConvexHint {
+ kNone_ConvexHint, //<! No hint about convexity
+ // of the path
+ kConvex_ConvexHint, //<! Path is one convex piece
+ kNonOverlappingConvexPieces_ConvexHint, //<! Multiple convex pieces,
+ // pieces are known to be
+ // disjoint
+ kSameWindingConvexPieces_ConvexHint, //<! Multiple convex pieces,
+ // may or may not intersect,
+ // either all wind cw or all
+ // wind ccw.
+ kConcave_ConvexHint //<! Path is known to be
+ // concave
+};
+
///////////////////////////////////////////////////////////////////////////////
// this is included only to make it easy to use this debugging facility
diff --git a/gpu/src/GrGpu.cpp b/gpu/src/GrGpu.cpp
index f42e316082..4a46e9887d 100644
--- a/gpu/src/GrGpu.cpp
+++ b/gpu/src/GrGpu.cpp
@@ -74,7 +74,7 @@ GrGpu::GrGpu() : f8bitPaletteSupport(false),
fVertexPoolInUse(false),
fIndexPoolInUse(false) {
#if GR_DEBUG
-// gr_run_unittests();
+ //gr_run_unittests();
#endif
resetStats();
}
@@ -338,9 +338,20 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
int clipBit = rt.stencilBits();
clipBit = (1 << (clipBit-1));
+ // often we'll see the first two elements of the clip are
+ // the full rt size and another element intersected with it.
+ // We can skip the first full-size rect and save a big rect draw.
+ int firstElement = 0;
+ if (clip.getElementCount() > 1 &&
+ kRect_ClipType == clip.getElementType(0) &&
+ kIntersect_SetOp == clip.getOp(1)&&
+ clip.getRect(0).contains(bounds)) {
+ firstElement = 1;
+ }
+
// walk through each clip element and perform its set op
// with the existing clip.
- for (int c = 0; c < count; ++c) {
+ for (int c = firstElement; c < count; ++c) {
GrPathFill fill;
// enabled at bottom of loop
this->disableState(kModifyStencilClip_StateBit);
@@ -351,15 +362,16 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
fill = kEvenOdd_PathFill;
} else {
fill = clip.getPathFill(c);
- canDrawDirectToClip = getPathRenderer()->requiresStencilPass(clip.getPath(c));
+ GrPathRenderer* pr = this->getPathRenderer();
+ canDrawDirectToClip = pr->requiresStencilPass(this, clip.getPath(c), fill);
}
- GrSetOp op = 0 == c ? kReplace_SetOp : clip.getOp(c);
+ GrSetOp op = firstElement == c ? kReplace_SetOp : clip.getOp(c);
int passes;
GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
- canDrawDirectToClip = GrStencilSettings::GetClipPasses(op, canDrawDirectToClip,
- clipBit, &fill,
+ canDrawDirectToClip = GrStencilSettings::GetClipPasses(op, canDrawDirectToClip,
+ clipBit, IsFillInverted(fill),
&passes, stencilSettings);
// draw the element to the client stencil bits if necessary
@@ -378,7 +390,9 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
this->drawSimpleRect(clip.getRect(c), NULL, 0);
} else {
SET_RANDOM_COLOR
- getPathRenderer()->drawPathToStencil(this, clip.getPath(c), fill, NULL);
+ getPathRenderer()->drawPathToStencil(this, clip.getPath(c),
+ NonInvertedFill(fill),
+ NULL);
}
}
@@ -393,7 +407,9 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
this->drawSimpleRect(clip.getRect(c), NULL, 0);
} else {
SET_RANDOM_COLOR
- getPathRenderer()->drawPath(this, 0, clip.getPath(c), fill, NULL);
+ getPathRenderer()->drawPath(this, 0,
+ clip.getPath(c),
+ fill, NULL);
}
} else {
SET_RANDOM_COLOR
diff --git a/gpu/src/GrGpuGL.cpp b/gpu/src/GrGpuGL.cpp
index 1e9d7bfcba..3ee524b74b 100644
--- a/gpu/src/GrGpuGL.cpp
+++ b/gpu/src/GrGpuGL.cpp
@@ -432,6 +432,10 @@ void GrGpuGL::resetContextHelper() {
fHWBlendDisabled = false;
GR_GL(Enable(GL_BLEND));
+ // we don't use the zb at all
+ GR_GL(Disable(GL_DEPTH_TEST));
+ GR_GL(DepthMask(GL_FALSE));
+
GR_GL(Disable(GL_CULL_FACE));
GR_GL(FrontFace(GL_CCW));
fHWDrawState.fDrawFace = kBoth_DrawFace;
@@ -1097,10 +1101,18 @@ void GrGpuGL::eraseStencil(uint32_t value, uint32_t mask) {
void GrGpuGL::eraseStencilClip(const GrIRect& rect) {
GrAssert(NULL != fCurrDrawState.fRenderTarget);
+#if 0
GLint stencilBitCount = fCurrDrawState.fRenderTarget->stencilBits();
GrAssert(stencilBitCount > 0);
GLint clipStencilMask = (1 << (stencilBitCount - 1));
-
+#else
+ // we could just clear the clip bit but when we go through
+ // angle a partial stencil mask will cause clears to be
+ // turned into draws. Our contract on GrDrawTarget says that
+ // changing the clip between stencil passes may or may not
+ // zero the client's clip bits. So we just clear the whole thing.
+ static const GLint clipStencilMask = ~0;
+#endif
flushRenderTarget();
flushScissor(&rect);
GR_GL(StencilMask(clipStencilMask));
diff --git a/gpu/src/GrGpuGLShaders2.cpp b/gpu/src/GrGpuGLShaders2.cpp
index 14134e7b6c..77847e9fba 100644
--- a/gpu/src/GrGpuGLShaders2.cpp
+++ b/gpu/src/GrGpuGLShaders2.cpp
@@ -1257,7 +1257,10 @@ bool GrGpuGLShaders2::flushGraphicsState(GrPrimitiveType type) {
// invalidate the immediate mode color
fHWDrawState.fColor = GrColor_ILLEGAL;
} else {
- if (fHWDrawState.fColor != fCurrDrawState.fColor) {
+ if (fHWDrawState.fColor != fCurrDrawState.fColor &&
+ (!GR_AGGRESSIVE_SHADER_OPTS || 0xffffffff != fCurrDrawState.fColor)) {
+ // avoid pushing the color attrib if the shader will optimize it out
+
// OpenGL ES only supports the float varities of glVertexAttrib
float c[] = {
GrColorUnpackR(fCurrDrawState.fColor) / 255.f,
diff --git a/gpu/src/GrPath.cpp b/gpu/src/GrPath.cpp
index ca5c43baa2..fc53ac2335 100644
--- a/gpu/src/GrPath.cpp
+++ b/gpu/src/GrPath.cpp
@@ -1,6 +1,8 @@
#include "GrPath.h"
-GrPath::GrPath() {}
+GrPath::GrPath() {
+ fConvexHint = kNone_ConvexHint;
+}
GrPath::GrPath(const GrPath& src) : INHERITED() {
GrPath::Iter iter(src);
@@ -15,13 +17,13 @@ GrPath::~GrPath() {
}
bool GrPath::operator ==(const GrPath& path) const {
- if (fVerbs.count() != path.fVerbs.count() ||
+ if (fCmds.count() != path.fCmds.count() ||
fPts.count() != path.fPts.count()) {
return false;
}
- for (int v = 0; v < fVerbs.count(); ++v) {
- if (fVerbs[v] != path.fVerbs[v]) {
+ for (int v = 0; v < fCmds.count(); ++v) {
+ if (fCmds[v] != path.fCmds[v]) {
return false;
}
}
@@ -35,31 +37,31 @@ bool GrPath::operator ==(const GrPath& path) const {
}
void GrPath::ensureMoveTo() {
- if (fVerbs.isEmpty() || this->wasLastVerb(kClose)) {
- *fVerbs.append() = kMove;
+ if (fCmds.isEmpty() || this->wasLastVerb(kClose_PathCmd)) {
+ *fCmds.append() = kMove_PathCmd;
fPts.append()->set(0, 0);
}
}
void GrPath::moveTo(GrScalar x, GrScalar y) {
- if (this->wasLastVerb(kMove)) {
+ if (this->wasLastVerb(kMove_PathCmd)) {
// overwrite prev kMove value
fPts[fPts.count() - 1].set(x, y);
} else {
- *fVerbs.append() = kMove;
+ *fCmds.append() = kMove_PathCmd;
fPts.append()->set(x, y);
}
}
void GrPath::lineTo(GrScalar x, GrScalar y) {
this->ensureMoveTo();
- *fVerbs.append() = kLine;
+ *fCmds.append() = kLine_PathCmd;
fPts.append()->set(x, y);
}
void GrPath::quadTo(GrScalar x0, GrScalar y0, GrScalar x1, GrScalar y1) {
this->ensureMoveTo();
- *fVerbs.append() = kQuad;
+ *fCmds.append() = kQuadratic_PathCmd;
fPts.append()->set(x0, y0);
fPts.append()->set(x1, y1);
}
@@ -67,100 +69,371 @@ void GrPath::quadTo(GrScalar x0, GrScalar y0, GrScalar x1, GrScalar y1) {
void GrPath::cubicTo(GrScalar x0, GrScalar y0, GrScalar x1, GrScalar y1,
GrScalar x2, GrScalar y2) {
this->ensureMoveTo();
- *fVerbs.append() = kCubic;
+ *fCmds.append() = kCubic_PathCmd;
fPts.append()->set(x0, y0);
fPts.append()->set(x1, y1);
fPts.append()->set(x2, y2);
}
void GrPath::close() {
- if (!fVerbs.isEmpty() && !this->wasLastVerb(kClose)) {
+ if (!fCmds.isEmpty() && !this->wasLastVerb(kClose_PathCmd)) {
// should we allow kMove followed by kClose?
- *fVerbs.append() = kClose;
+ *fCmds.append() = kClose_PathCmd;
}
}
///////////////////////////////////////////////////////////////////////////////
+static bool check_two_vecs(const GrVec& prevVec,
+ const GrVec& currVec,
+ GrScalar turnDir,
+ int* xDir,
+ int* yDir,
+ int* flipX,
+ int* flipY) {
+ if (currVec.fX * *xDir < 0) {
+ ++*flipX;
+ if (*flipX > 2) {
+ return false;
+ }
+ *xDir = -*xDir;
+ }
+ if (currVec.fY * *yDir < 0) {
+ ++*flipY;
+ if (*flipY > 2) {
+ return false;
+ }
+ *yDir = -*yDir;
+ }
+ GrScalar d = prevVec.cross(currVec);
+ return (d * turnDir) >= 0;
+}
+
+static void init_from_two_vecs(const GrVec& firstVec,
+ const GrVec& secondVec,
+ GrScalar* turnDir,
+ int* xDir, int* yDir) {
+ *turnDir = firstVec.cross(secondVec);
+ if (firstVec.fX > 0) {
+ *xDir = 1;
+ } else if (firstVec.fX < 0) {
+ *xDir = -1;
+ } else {
+ *xDir = 0;
+ }
+ if (firstVec.fY > 0) {
+ *yDir = 1;
+ } else if (firstVec.fY < 0) {
+ *yDir = -1;
+ } else {
+ *yDir = 0;
+ }
+}
+
void GrPath::resetFromIter(GrPathIter* iter) {
fPts.reset();
- fVerbs.reset();
+ fCmds.reset();
- GrPoint pts[4];
- GrPathIter::Command cmd;
+ fConvexHint = iter->convexHint();
+
+ // first point of the subpath
+ GrPoint firstPt;
+ // first edge of the subpath
+ GrVec firstVec;
+ // vec of most recently processed edge, that wasn't degenerate
+ GrVec previousVec;
+ // most recently processed point
+ GrPoint previousPt;
+
+ // sign indicates whether we're bending left or right
+ GrScalar turnDir;
+ // number of times the direction has flipped in x or y
- while ((cmd = iter->next(pts)) != GrPathIter::kEnd_Command) {
+ // we track which direction we are moving in x/y and the
+ // number of times it changes.
+ int xDir;
+ int yDir;
+ int flipX;
+ int flipY;
+
+ // counts number of sub path pts that didn't add a degenerate edge.
+ int subPathPts = 0;
+
+ int numSubPaths = 0;
+ iter->rewind();
+ GrPathCmd cmd;
+ GrPoint pts[4];
+ bool subPathClosed;
+ do {
+ cmd = iter->next(pts);
+ // If the convexity test is ever updated to handle multiple subpaths
+ // the loop has to be adjusted to handle moving to a new subpath without
+ // closing the previous one. Currently the implicit closing vectors for a
+ // filled path would never be examined.
switch (cmd) {
- case GrPathIter::kMove_Command:
+ case kMove_PathCmd:
this->moveTo(pts[0].fX, pts[0].fY);
+ subPathPts = 0;
+ subPathClosed = false;
break;
- case GrPathIter::kLine_Command:
+ case kLine_PathCmd:
this->lineTo(pts[1].fX, pts[1].fY);
break;
- case GrPathIter::kQuadratic_Command:
+ case kQuadratic_PathCmd:
this->quadTo(pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
break;
- case GrPathIter::kCubic_Command:
+ case kCubic_PathCmd:
this->cubicTo(pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY,
pts[3].fX, pts[3].fY);
break;
- case GrPathIter::kClose_Command:
+ case kClose_PathCmd:
this->close();
+ subPathClosed = true;
break;
- case GrPathIter::kEnd_Command:
- // never get here, but include it to avoid the warning
+ case kEnd_PathCmd:
break;
}
+ int n = NumPathCmdPoints(cmd);
+ if (0 == subPathPts && n > 0) {
+ previousPt = pts[0];
+ firstPt = previousPt;
+ flipX = 0;
+ flipY = 0;
+ turnDir = 0;
+ subPathPts = 1;
+ ++numSubPaths;
+ }
+ // either we skip the first pt because it is redundant with
+ // last point of the previous subpath cmd or we just ate it
+ // in the above if.
+ int consumed = 1;
+ if (numSubPaths < 2 && kNone_ConvexHint == fConvexHint) {
+ while (consumed < n) {
+ GrAssert(pts[consumed-1] == previousPt);
+ GrVec vec;
+ vec.setBetween(previousPt, pts[consumed]);
+ if (vec.fX || vec.fY) {
+ if (subPathPts >= 2) {
+ if (0 == turnDir) {
+ firstVec = previousVec;
+ init_from_two_vecs(firstVec, vec,
+ &turnDir, &xDir, &yDir);
+ // here we aren't checking whether the x/y dirs
+ // change between the first and second edge. It
+ // gets covered when the path is closed.
+ } else {
+ if (!check_two_vecs(previousVec, vec, turnDir,
+ &xDir, &yDir,
+ &flipX, &flipY)) {
+ fConvexHint = kConcave_ConvexHint;
+ break;
+ }
+ }
+ }
+ previousVec = vec;
+ previousPt = pts[consumed];
+ ++subPathPts;
+ }
+ ++consumed;
+ }
+ if (subPathPts > 2 && (kClose_PathCmd == cmd ||
+ (!subPathClosed && kEnd_PathCmd == cmd ))) {
+ // if an additional vector is needed to close the loop check
+ // that it validates against the previous vector.
+ GrVec vec;
+ vec.setBetween(previousPt, firstPt);
+ if (vec.fX || vec.fY) {
+ if (!check_two_vecs(previousVec, vec, turnDir,
+ &xDir, &yDir, &flipX, &flipY)) {
+ fConvexHint = kConcave_ConvexHint;
+ break;
+ }
+ previousVec = vec;
+ }
+ // check that closing vector validates against the first vector.
+ if (!check_two_vecs(previousVec, firstVec, turnDir,
+ &xDir, &yDir, &flipX, &flipY)) {
+ fConvexHint = kConcave_ConvexHint;
+ break;
+ }
+ }
+ }
+ } while (cmd != kEnd_PathCmd);
+ if (kNone_ConvexHint == fConvexHint && numSubPaths < 2) {
+ fConvexHint = kConvex_ConvexHint;
+ } else {
+ bool recurse = false;
+ if (recurse) {
+ this->resetFromIter(iter);
+ }
}
- fConvexHint = iter->convexHint();
}
+void GrPath::ConvexUnitTest() {
+ GrPath testPath;
+ GrPath::Iter testIter;
+
+ GrPath pt;
+ pt.moveTo(0, 0);
+ pt.close();
+
+ testIter.reset(pt);
+ testPath.resetFromIter(&testIter);
+ GrAssert(kConvex_ConvexHint == testPath.getConvexHint());
+
+ GrPath line;
+ line.moveTo(GrIntToScalar(12), GrIntToScalar(20));
+ line.lineTo(GrIntToScalar(-12), GrIntToScalar(-20));
+ line.close();
+
+ testIter.reset(line);
+ testPath.resetFromIter(&testIter);
+ GrAssert(kConvex_ConvexHint == testPath.getConvexHint());
+
+ GrPath triLeft;
+ triLeft.moveTo(0, 0);
+ triLeft.lineTo(1, 0);
+ triLeft.lineTo(1, 1);
+ triLeft.close();
+
+ testIter.reset(triLeft);
+ testPath.resetFromIter(&testIter);
+ GrAssert(kConvex_ConvexHint == testPath.getConvexHint());
+
+ GrPath triRight;
+ triRight.moveTo(0, 0);
+ triRight.lineTo(-1, 0);
+ triRight.lineTo(1, 1);
+ triRight.close();
+
+ testIter.reset(triRight);
+ testPath.resetFromIter(&testIter);
+ GrAssert(kConvex_ConvexHint == testPath.getConvexHint());
+
+ GrPath square;
+ square.moveTo(0, 0);
+ square.lineTo(1, 0);
+ square.lineTo(1, 1);
+ square.lineTo(0, 1);
+ square.close();
+
+ testIter.reset(square);
+ testPath.resetFromIter(&testIter);
+ GrAssert(kConvex_ConvexHint == testPath.getConvexHint());
+
+ GrPath redundantSquare;
+ square.moveTo(0, 0);
+ square.lineTo(0, 0);
+ square.lineTo(0, 0);
+ square.lineTo(1, 0);
+ square.lineTo(1, 0);
+ square.lineTo(1, 0);
+ square.lineTo(1, 1);
+ square.lineTo(1, 1);
+ square.lineTo(1, 1);
+ square.lineTo(0, 1);
+ square.lineTo(0, 1);
+ square.lineTo(0, 1);
+ square.close();
+
+ testIter.reset(redundantSquare);
+ testPath.resetFromIter(&testIter);
+ GrAssert(kConvex_ConvexHint == testPath.getConvexHint());
+
+ GrPath bowTie;
+ bowTie.moveTo(0, 0);
+ bowTie.lineTo(0, 0);
+ bowTie.lineTo(0, 0);
+ bowTie.lineTo(1, 1);
+ bowTie.lineTo(1, 1);
+ bowTie.lineTo(1, 1);
+ bowTie.lineTo(1, 0);
+ bowTie.lineTo(1, 0);
+ bowTie.lineTo(1, 0);
+ bowTie.lineTo(0, 1);
+ bowTie.lineTo(0, 1);
+ bowTie.lineTo(0, 1);
+ bowTie.close();
+
+ testIter.reset(bowTie);
+ testPath.resetFromIter(&testIter);
+ GrAssert(kConcave_ConvexHint == testPath.getConvexHint());
+
+ GrPath spiral;
+ spiral.moveTo(0, 0);
+ spiral.lineTo(1, 0);
+ spiral.lineTo(1, 1);
+ spiral.lineTo(0, 1);
+ spiral.lineTo(0,.5);
+ spiral.lineTo(.5,.5);
+ spiral.lineTo(.5,.75);
+ spiral.close();
+
+ testIter.reset(spiral);
+ testPath.resetFromIter(&testIter);
+ GrAssert(kConcave_ConvexHint == testPath.getConvexHint());
+
+ GrPath dent;
+ dent.moveTo(0, 0);
+ dent.lineTo(1, 1);
+ dent.lineTo(0, 1);
+ dent.lineTo(-.5,2);
+ dent.lineTo(-2, 1);
+ dent.close();
+
+ testIter.reset(dent);
+ testPath.resetFromIter(&testIter);
+ GrAssert(kConcave_ConvexHint == testPath.getConvexHint());
+}
///////////////////////////////////////////////////////////////////////////////
-GrPath::Iter::Iter(const GrPath& path) : fPath(path) {
+GrPath::Iter::Iter() : fPath(NULL) {
+}
+
+GrPath::Iter::Iter(const GrPath& path) : fPath(&path) {
this->rewind();
}
-GrPathIter::Command GrPath::Iter::next(GrPoint points[]) {
- if (fVerbIndex == fPath.fVerbs.count()) {
- GrAssert(fPtIndex == fPath.fPts.count());
- return GrPathIter::kEnd_Command;
+GrPathCmd GrPath::Iter::next(GrPoint points[]) {
+ if (fCmdIndex == fPath->fCmds.count()) {
+ GrAssert(fPtIndex == fPath->fPts.count());
+ return kEnd_PathCmd;
} else {
- GrAssert(fVerbIndex < fPath.fVerbs.count());
+ GrAssert(fCmdIndex < fPath->fCmds.count());
}
- uint8_t cmd = fPath.fVerbs[fVerbIndex++];
- const GrPoint* srcPts = fPath.fPts.begin() + fPtIndex;
+ GrPathCmd cmd = fPath->fCmds[fCmdIndex++];
+ const GrPoint* srcPts = fPath->fPts.begin() + fPtIndex;
switch (cmd) {
- case kMove:
+ case kMove_PathCmd:
if (points) {
points[0] = srcPts[0];
}
fLastPt = srcPts[0];
- GrAssert(fPtIndex <= fPath.fPts.count() + 1);
+ GrAssert(fPtIndex <= fPath->fPts.count() + 1);
fPtIndex += 1;
break;
- case kLine:
+ case kLine_PathCmd:
if (points) {
points[0] = fLastPt;
points[1] = srcPts[0];
}
fLastPt = srcPts[0];
- GrAssert(fPtIndex <= fPath.fPts.count() + 1);
+ GrAssert(fPtIndex <= fPath->fPts.count() + 1);
fPtIndex += 1;
break;
- case kQuad:
+ case kQuadratic_PathCmd:
if (points) {
points[0] = fLastPt;
points[1] = srcPts[0];
points[2] = srcPts[1];
}
- fLastPt = srcPts[2];
- GrAssert(fPtIndex <= fPath.fPts.count() + 2);
+ fLastPt = srcPts[1];
+ GrAssert(fPtIndex <= fPath->fPts.count() + 2);
fPtIndex += 2;
break;
- case kCubic:
+ case kCubic_PathCmd:
if (points) {
points[0] = fLastPt;
points[1] = srcPts[0];
@@ -168,29 +441,33 @@ GrPathIter::Command GrPath::Iter::next(GrPoint points[]) {
points[3] = srcPts[2];
}
fLastPt = srcPts[2];
- GrAssert(fPtIndex <= fPath.fPts.count() + 3);
+ GrAssert(fPtIndex <= fPath->fPts.count() + 3);
fPtIndex += 3;
break;
- case kClose:
+ case kClose_PathCmd:
break;
default:
- GrAssert(!"unknown grpath verb");
+ GrAssert(!"unknown grpath cmd");
break;
}
- return (GrPathIter::Command)cmd;
+ return cmd;
}
-GrPathIter::ConvexHint GrPath::Iter::convexHint() const {
- return fPath.getConvexHint();
+GrConvexHint GrPath::Iter::convexHint() const {
+ return fPath->getConvexHint();
}
-GrPathIter::Command GrPath::Iter::next() {
+GrPathCmd GrPath::Iter::next() {
return this->next(NULL);
}
void GrPath::Iter::rewind() {
- fVerbIndex = fPtIndex = 0;
+ this->reset(*fPath);
}
+void GrPath::Iter::reset(const GrPath& path) {
+ fPath = &path;
+ fCmdIndex = fPtIndex = 0;
+}
diff --git a/gpu/src/GrPathRenderer.cpp b/gpu/src/GrPathRenderer.cpp
index 3e2b4b35c5..6d7aabb1e0 100644
--- a/gpu/src/GrPathRenderer.cpp
+++ b/gpu/src/GrPathRenderer.cpp
@@ -240,22 +240,22 @@ static int worst_case_point_count(GrPathIter* path,
bool first = true;
- GrPathIter::Command cmd;
+ GrPathCmd cmd;
GrPoint pts[4];
- while ((cmd = path->next(pts)) != GrPathIter::kEnd_Command) {
+ while ((cmd = path->next(pts)) != kEnd_PathCmd) {
switch (cmd) {
- case GrPathIter::kLine_Command:
+ case kLine_PathCmd:
pointCount += 1;
break;
- case GrPathIter::kQuadratic_Command:
+ case kQuadratic_PathCmd:
pointCount += quadratic_point_count(pts, tol);
break;
- case GrPathIter::kCubic_Command:
+ case kCubic_PathCmd:
pointCount += cubic_point_count(pts, tol);
break;
- case GrPathIter::kMove_Command:
+ case kMove_PathCmd:
pointCount += 1;
if (!first) {
++(*subpaths);
@@ -269,21 +269,21 @@ static int worst_case_point_count(GrPathIter* path,
return pointCount;
}
-static inline bool single_pass_path(const GrPathIter& path,
- GrPathFill fill,
- const GrDrawTarget& target) {
+static inline bool single_pass_path(const GrDrawTarget& target,
+ const GrPathIter& path,
+ GrPathFill fill) {
#if STENCIL_OFF
return true;
#else
if (kEvenOdd_PathFill == fill) {
- GrPathIter::ConvexHint hint = path.convexHint();
- return hint == GrPathIter::kConvex_ConvexHint ||
- hint == GrPathIter::kNonOverlappingConvexPieces_ConvexHint;
+ GrConvexHint hint = path.convexHint();
+ return hint == kConvex_ConvexHint ||
+ hint == kNonOverlappingConvexPieces_ConvexHint;
} else if (kWinding_PathFill == fill) {
- GrPathIter::ConvexHint hint = path.convexHint();
- return hint == GrPathIter::kConvex_ConvexHint ||
- hint == GrPathIter::kNonOverlappingConvexPieces_ConvexHint ||
- (hint == GrPathIter::kSameWindingConvexPieces_ConvexHint &&
+ GrConvexHint hint = path.convexHint();
+ return hint == kConvex_ConvexHint ||
+ hint == kNonOverlappingConvexPieces_ConvexHint ||
+ (hint == kSameWindingConvexPieces_ConvexHint &&
target.canDisableBlend() && !target.isDitherState());
}
@@ -291,6 +291,12 @@ static inline bool single_pass_path(const GrPathIter& path,
#endif
}
+bool GrDefaultPathRenderer::requiresStencilPass(const GrDrawTarget* target,
+ GrPathIter* path,
+ GrPathFill fill) const {
+ return single_pass_path(*target, *path, fill);
+}
+
void GrDefaultPathRenderer::drawPathHelper(GrDrawTarget* target,
GrDrawTarget::StageBitfield stages,
GrPathIter* path,
@@ -358,18 +364,18 @@ void GrDefaultPathRenderer::drawPathHelper(GrDrawTarget* target,
if (stencilOnly) {
passes[0] = &gDirectToStencil;
} else {
- passes[0] = &GrStencilSettings::gDisabled;
+ passes[0] = NULL;
}
lastPassIsBounds = false;
drawFace[0] = GrDrawTarget::kBoth_DrawFace;
} else {
type = kTriangleFan_PrimitiveType;
- if (single_pass_path(*path, fill, *target)) {
+ if (single_pass_path(*target, *path, fill)) {
passCount = 1;
if (stencilOnly) {
passes[0] = &gDirectToStencil;
} else {
- passes[0] = &GrStencilSettings::gDisabled;
+ passes[0] = NULL;
}
drawFace[0] = GrDrawTarget::kBoth_DrawFace;
lastPassIsBounds = false;
@@ -446,9 +452,9 @@ void GrDefaultPathRenderer::drawPathHelper(GrDrawTarget* target,
int subpath = 0;
for (;;) {
- GrPathIter::Command cmd = path->next(pts);
+ GrPathCmd cmd = path->next(pts);
switch (cmd) {
- case GrPathIter::kMove_Command:
+ case kMove_PathCmd:
if (!first) {
subpathVertCount[subpath] = vert-subpathBase;
subpathBase = vert;
@@ -457,25 +463,25 @@ void GrDefaultPathRenderer::drawPathHelper(GrDrawTarget* target,
*vert = pts[0];
vert++;
break;
- case GrPathIter::kLine_Command:
+ case kLine_PathCmd:
*vert = pts[1];
vert++;
break;
- case GrPathIter::kQuadratic_Command: {
+ case kQuadratic_PathCmd: {
generate_quadratic_points(pts[0], pts[1], pts[2],
tolSqd, &vert,
quadratic_point_count(pts, tol));
break;
}
- case GrPathIter::kCubic_Command: {
+ case kCubic_PathCmd: {
generate_cubic_points(pts[0], pts[1], pts[2], pts[3],
tolSqd, &vert,
cubic_point_count(pts, tol));
break;
}
- case GrPathIter::kClose_Command:
+ case kClose_PathCmd:
break;
- case GrPathIter::kEnd_Command:
+ case kEnd_PathCmd:
subpathVertCount[subpath] = vert-subpathBase;
++subpath; // this could be only in debug
goto FINISHED;
@@ -519,7 +525,9 @@ FINISHED:
for (int p = 0; p < passCount; ++p) {
target->setDrawFace(drawFace[p]);
- target->setStencil(*passes[p]);
+ if (NULL != passes[p]) {
+ target->setStencil(*passes[p]);
+ }
if (lastPassIsBounds && (p == passCount-1)) {
if (!colorWritesWereDisabled) {
diff --git a/gpu/src/GrPathRenderer.h b/gpu/src/GrPathRenderer.h
index 467b0a04d3..f99b92259c 100644
--- a/gpu/src/GrPathRenderer.h
+++ b/gpu/src/GrPathRenderer.h
@@ -60,29 +60,41 @@ public:
* 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 requires its own stencil
+ * 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.
+ * the target's stencil settings but use those already set on target.
+ *
+ * @param target target that the path will be rendered to
+ * @param path the path that will be drawn
+ * @param fill the fill rule that will be used
*
* @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(GrPathIter*) const { return false; }
+ virtual bool requiresStencilPass(const GrDrawTarget* target,
+ GrPathIter* path,
+ GrPathFill fill) const { return false; }
- bool requiresStencilPass(const GrPath& path) const {
+ bool requiresStencilPass(const GrDrawTarget* target,
+ const GrPath& path,
+ GrPathFill fill) const {
GrPath::Iter iter(path);
- return requiresStencilPass(&iter);
+ return requiresStencilPass(target, &iter, fill);
}
/**
- * Draws a path to the stencil buffer. Assume the writable bits are zero
- * prior and write a nonzero value in interior samples. The default
- * implementation assumes the path filling algorithm doesn't require a
- * separate stencil pass and so just calls drawPath.
+ * Draws a 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.
+ *
+ * Only called if requiresStencilPass returns true for the same combo of
+ * target, path, and fill (or inverse of the fill).
+ *
+ * The default implementation assumes the path filling algorithm doesn't
+ * require a separate stencil pass and so crashes.
*
- * Fill will never be an inverse fill rule.
*
* @param target the target to draw into.
* @param path the path to draw.
@@ -94,10 +106,7 @@ public:
GrPathIter* path,
GrPathFill fill,
const GrPoint* translate) {
- GrAssert(kInverseEvenOdd_PathFill != fill);
- GrAssert(kInverseWinding_PathFill != fill);
-
- this->drawPath(target, 0, path, fill, translate);
+ GrCrash("Unexpected call to drawPathToStencil.");
}
void drawPathToStencil(GrDrawTarget* target,
@@ -119,7 +128,9 @@ public:
GrPathIter* path,
GrPathFill fill,
const GrPoint* translate);
- virtual bool requiresStencilPass(GrPath&) const { return true; }
+ virtual bool requiresStencilPass(const GrDrawTarget* target,
+ GrPathIter* path,
+ GrPathFill fill) const;
virtual void drawPathToStencil(GrDrawTarget* target,
GrPathIter* path,
GrPathFill fill,
diff --git a/gpu/src/GrRedBlackTree.h b/gpu/src/GrRedBlackTree.h
index e6448fb94f..7ba326ff8a 100644
--- a/gpu/src/GrRedBlackTree.h
+++ b/gpu/src/GrRedBlackTree.h
@@ -355,6 +355,8 @@ typename GrRedBlackTree<T,C>::Iter GrRedBlackTree<T,C>::insert(const T& t) {
x->fChildren[kRight_Child] = NULL;
x->fItem = t;
+ Node* returnNode = x;
+
Node* gp = NULL;
Node* p = NULL;
Node* n = fRoot;
@@ -371,7 +373,6 @@ typename GrRedBlackTree<T,C>::Iter GrRedBlackTree<T,C>::insert(const T& t) {
gp = p;
p = n;
n = p->fChildren[pc];
-
}
if (last) {
fLast = x;
@@ -385,7 +386,7 @@ typename GrRedBlackTree<T,C>::Iter GrRedBlackTree<T,C>::insert(const T& t) {
x->fColor = kBlack_Color;
x->fParent = NULL;
GrAssert(1 == fCount);
- return Iter(x, this);
+ return Iter(returnNode, this);
}
p->fChildren[pc] = x;
x->fColor = kRed_Color;
@@ -404,7 +405,7 @@ typename GrRedBlackTree<T,C>::Iter GrRedBlackTree<T,C>::insert(const T& t) {
// if x's parent is black then we didn't violate any of the
// red/black properties when we added x as red.
if (kBlack_Color == p->fColor) {
- return Iter(x, this);
+ return Iter(returnNode, this);
}
// gp must be valid because if p was the root then it is black
GrAssert(NULL != gp);
@@ -428,7 +429,7 @@ typename GrRedBlackTree<T,C>::Iter GrRedBlackTree<T,C>::insert(const T& t) {
GrAssert(fRoot == x);
x->fColor = kBlack_Color;
validate();
- return Iter(x, this);
+ return Iter(returnNode, this);
}
gp = p->fParent;
pc = (p->fChildren[kLeft_Child] == x) ? kLeft_Child :
@@ -481,7 +482,7 @@ typename GrRedBlackTree<T,C>::Iter GrRedBlackTree<T,C>::insert(const T& t) {
rotateLeft(gp);
}
validate();
- return Iter(x, this);
+ return Iter(returnNode, this);
}
@@ -656,6 +657,7 @@ void GrRedBlackTree<T,C>::deleteAtNode(Node* x) {
Color xcolor = x->fColor;
p->fChildren[pc] = NULL;
delete x;
+ x = NULL;
// when x is red it can be with an implicit black leaf without
// violating any of the red-black tree properties.
if (kRed_Color == xcolor) {
@@ -716,9 +718,9 @@ void GrRedBlackTree<T,C>::deleteAtNode(Node* x) {
}
// x and s are now both black.
GrAssert(kBlack_Color == s->fColor);
- GrAssert(kBlack_Color == x->fColor);
+ GrAssert(NULL == x || kBlack_Color == x->fColor);
GrAssert(p == s->fParent);
- GrAssert(p == x->fParent);
+ GrAssert(NULL == x || p == x->fParent);
// when x is deleted its subtree will have reduced black-height.
slRed = (NULL != sl && kRed_Color == sl->fColor);
diff --git a/gpu/src/GrStencil.cpp b/gpu/src/GrStencil.cpp
index 9d68c65ebd..a1c8c09b2d 100644
--- a/gpu/src/GrStencil.cpp
+++ b/gpu/src/GrStencil.cpp
@@ -243,84 +243,63 @@ static const GrStencilSettings gDiffClip = {
0x00000000, 0x00000000 // set clip bit
};
-static const GrPathFill gNonInvertedFills[] = {
- kWinding_PathFill, // kWinding_PathFill
- kEvenOdd_PathFill, // kEvenOdd_PathFill
- kWinding_PathFill, // kInverseWinding_PathFill
- kEvenOdd_PathFill, // kInverseEvenOdd_PathFill
- kWinding_PathFill, // kHairLine_PathFill
-};
-
-static const bool gIsFillInverted[] = {
- false, // kWinding_PathFill
- false, // kEvenOdd_PathFill
- true, // kInverseWinding_PathFill
- true, // kInverseEvenOdd_PathFill
- false, // kHairLine_PathFill
-};
-GR_STATIC_ASSERT(0 == kWinding_PathFill);
-GR_STATIC_ASSERT(1 == kEvenOdd_PathFill);
-GR_STATIC_ASSERT(2 == kInverseWinding_PathFill);
-GR_STATIC_ASSERT(3 == kInverseEvenOdd_PathFill);
-GR_STATIC_ASSERT(4 == kHairLine_PathFill);
-GR_STATIC_ASSERT(5 == kPathFillCount);
-
bool GrStencilSettings::GetClipPasses(GrSetOp op,
bool canBeDirect,
unsigned int stencilClipMask,
- GrPathFill* fill,
+ bool invertedFill,
int* numPasses,
GrStencilSettings settings[kMaxStencilClipPasses]) {
if (canBeDirect) {
- if (!gIsFillInverted[*fill]) {
- *numPasses = 0;
- switch (op) {
- case kReplace_SetOp:
- *numPasses = 1;
- settings[0] = gReplaceClip;
- break;
- case kUnion_SetOp:
- *numPasses = 1;
- settings[0] = gUnionClip;
- break;
- case kXor_SetOp:
- *numPasses = 1;
- settings[0] = gXorClip;
- break;
- case kDifference_SetOp:
- *numPasses = 1;
- settings[0] = gDiffClip;
- break;
- default: // suppress warning
- break;
- }
- if (1 == *numPasses) {
- settings[0].fFrontFuncRef |= stencilClipMask;
- settings[0].fFrontWriteMask |= stencilClipMask;
- settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
- settings[0].fBackWriteMask = settings[0].fFrontWriteMask;
- return true;
- }
+ *numPasses = 0;
+ switch (op) {
+ case kReplace_SetOp:
+ *numPasses = 1;
+ settings[0] = gReplaceClip;
+ break;
+ case kUnion_SetOp:
+ *numPasses = 1;
+ settings[0] = gUnionClip;
+ break;
+ case kXor_SetOp:
+ *numPasses = 1;
+ settings[0] = gXorClip;
+ break;
+ case kDifference_SetOp:
+ *numPasses = 1;
+ settings[0] = gDiffClip;
+ break;
+ default: // suppress warning
+ break;
+ }
+ if (1 == *numPasses) {
+ settings[0].fFrontFuncRef |= stencilClipMask;
+ settings[0].fFrontWriteMask |= stencilClipMask;
+ settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
+ settings[0].fBackWriteMask = settings[0].fFrontWriteMask;
+ return true;
}
}
switch (op) {
+ // if we make the path renderer go to stencil we always give it a
+ // non-inverted fill and we use the stencil rules on the client->clipbit
+ // pass to select either the zeros or nonzeros.
case kReplace_SetOp:
*numPasses= 1;
- settings[0] = gIsFillInverted[*fill] ? gInvUserToClipReplace : gUserToClipReplace;
+ settings[0] = invertedFill ? gInvUserToClipReplace : gUserToClipReplace;
settings[0].fFrontFuncMask &= ~stencilClipMask;
settings[0].fFrontFuncRef |= stencilClipMask;
settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
-
+ break;
case kIntersect_SetOp:
*numPasses = 1;
- settings[0] = gIsFillInverted[*fill] ? gInvUserToClipIsect : gUserToClipIsect;
+ settings[0] = invertedFill ? gInvUserToClipIsect : gUserToClipIsect;
settings[0].fFrontFuncRef = stencilClipMask;
settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
break;
case kUnion_SetOp:
*numPasses = 2;
- if (gIsFillInverted[*fill]) {
+ if (invertedFill) {
settings[0] = gInvUserToClipUnionPass0;
settings[0].fFrontFuncRef |= stencilClipMask;
settings[0].fBackFuncRef = settings[0].fFrontFuncMask;
@@ -345,7 +324,7 @@ bool GrStencilSettings::GetClipPasses(GrSetOp op,
break;
case kXor_SetOp:
*numPasses = 2;
- if (gIsFillInverted[*fill]) {
+ if (invertedFill) {
settings[0] = gInvUserToClipXorPass0;
settings[0].fFrontFuncMask &= ~stencilClipMask;
settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
@@ -365,12 +344,12 @@ bool GrStencilSettings::GetClipPasses(GrSetOp op,
break;
case kDifference_SetOp:
*numPasses = 1;
- settings[0] = gIsFillInverted[*fill] ? gInvUserToClipDiff : gUserToClipDiff;
+ settings[0] = invertedFill ? gInvUserToClipDiff : gUserToClipDiff;
settings[0].fFrontFuncRef |= stencilClipMask;
settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
break;
case kReverseDifference_SetOp:
- if (gIsFillInverted[*fill]) {
+ if (invertedFill) {
*numPasses = 1;
settings[0] = gInvUserToClipRDiff;
settings[0].fFrontWriteMask |= stencilClipMask;
@@ -393,6 +372,5 @@ bool GrStencilSettings::GetClipPasses(GrSetOp op,
default:
GrCrash("Unknown set op");
}
- *fill = gNonInvertedFills[*fill];
return false;
} \ No newline at end of file
diff --git a/gpu/src/gr_unittests.cpp b/gpu/src/gr_unittests.cpp
index 9caaa1fb2b..16fd9dc95d 100644
--- a/gpu/src/gr_unittests.cpp
+++ b/gpu/src/gr_unittests.cpp
@@ -15,11 +15,12 @@
*/
-#include "GrClip.h"
+#include "GrDrawTarget.h"
#include "GrTDArray.h"
#include "GrTBSearch.h"
#include "GrMatrix.h"
#include "GrRedBlackTree.h"
+#include "GrPath.h"
static void dump(const GrTDArray<int>& array) {
#if 0
@@ -78,6 +79,8 @@ void gr_run_unittests() {
test_bsearch();
GrMatrix::UnitTest();
GrRedBlackTree<int>::UnitTest();
+ GrPath::ConvexUnitTest();
+ GrDrawTarget::VertexLayoutUnitTest();
}