diff options
author | bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2011-03-04 20:29:08 +0000 |
---|---|---|
committer | bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2011-03-04 20:29:08 +0000 |
commit | 5aaa69e4339e229adfb05e96084a8ec0a590238b (patch) | |
tree | 0a4c274694b62f8e908d73adaa0d28215fd9fe7b /gpu | |
parent | f7c2c4544f866ae65cd9a4eee4da563f6d653d20 (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.h | 4 | ||||
-rw-r--r-- | gpu/include/GrDrawTarget.h | 10 | ||||
-rw-r--r-- | gpu/include/GrPath.h | 39 | ||||
-rw-r--r-- | gpu/include/GrPathIter.h | 74 | ||||
-rw-r--r-- | gpu/include/GrPoint.h | 49 | ||||
-rw-r--r-- | gpu/include/GrRect.h | 14 | ||||
-rw-r--r-- | gpu/include/GrStencil.h | 5 | ||||
-rw-r--r-- | gpu/include/GrTypes.h | 111 | ||||
-rw-r--r-- | gpu/src/GrGpu.cpp | 32 | ||||
-rw-r--r-- | gpu/src/GrGpuGL.cpp | 14 | ||||
-rw-r--r-- | gpu/src/GrGpuGLShaders2.cpp | 5 | ||||
-rw-r--r-- | gpu/src/GrPath.cpp | 375 | ||||
-rw-r--r-- | gpu/src/GrPathRenderer.cpp | 62 | ||||
-rw-r--r-- | gpu/src/GrPathRenderer.h | 41 | ||||
-rw-r--r-- | gpu/src/GrRedBlackTree.h | 16 | ||||
-rw-r--r-- | gpu/src/GrStencil.cpp | 98 | ||||
-rw-r--r-- | gpu/src/gr_unittests.cpp | 5 |
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(); } |