From: bsalomon@google.com Date: Wed, 7 Sep 2011 18:42:30 +0000 (+0000) Subject: Improve gpu path subdiv with perspective, remove tolerance scale, fix comment X-Git-Tag: submit/tizen/20180928.044319~17703 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=181e9bd9484ece4132e0cc5cfcff602134e5489d;p=platform%2Fupstream%2FlibSkiaSharp.git Improve gpu path subdiv with perspective, remove tolerance scale, fix comment Review URL: http://codereview.appspot.com/4993041/ git-svn-id: http://skia.googlecode.com/svn/trunk@2239 2bbb7eff-a529-9590-31e7-b0007b416f81 --- diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp index 639e25d685..b857dda8f7 100644 --- a/gpu/src/GrContext.cpp +++ b/gpu/src/GrContext.cpp @@ -692,11 +692,6 @@ bool GrContext::prepareForOffscreenAA(GrDrawTarget* target, GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE); desc.fAALevel = kNone_GrAALevel; } - // Avoid overtesselating paths in AA buffers; may unduly reduce quality - // of simple circles? - if (pr) { - //pr->scaleCurveTolerance(GrIntToScalar(record->fScale)); - } desc.fWidth *= record->fScale; desc.fHeight *= record->fScale; @@ -881,10 +876,6 @@ void GrContext::doOffscreenAAPass2(GrDrawTarget* target, void GrContext::cleanupOffscreenAA(GrDrawTarget* target, GrPathRenderer* pr, OffscreenRecord* record) { - if (pr) { - // Counterpart of scale() in prepareForOffscreenAA() - //pr->scaleCurveTolerance(SkScalarInvert(SkIntToScalar(record->fScale))); - } target->restoreDrawState(record->fSavedState); } diff --git a/gpu/src/GrDefaultPathRenderer.cpp b/gpu/src/GrDefaultPathRenderer.cpp index b70b8631d5..3323c91725 100644 --- a/gpu/src/GrDefaultPathRenderer.cpp +++ b/gpu/src/GrDefaultPathRenderer.cpp @@ -374,18 +374,9 @@ void GrDefaultPathRenderer::onDrawPath(GrDrawTarget::StageBitfield stages, bool stencilOnly) { GrMatrix viewM = fTarget->getViewMatrix(); - // In order to tesselate the path we get a bound on how much the matrix can - // stretch when mapping to screen coordinates. - GrScalar stretch = viewM.getMaxStretch(); - bool useStretch = stretch > 0; - GrScalar tol = fCurveTolerance; - - if (!useStretch) { - // TODO: deal with perspective in some better way. - tol /= 10; - } else { - tol = GrScalarDiv(tol, stretch); - } + GrScalar tol = GR_Scalar1; + tol = GrPathUtils::scaleToleranceToSrc(tol, viewM); + // FIXME: It's really dumb that we recreate the verts for a new vertex // layout. We only do that because the GrDrawTarget API doesn't allow // us to change the vertex layout after reserveVertexSpace(). We won't diff --git a/gpu/src/GrPathRenderer.cpp b/gpu/src/GrPathRenderer.cpp index 06a00e44b7..929941a47e 100644 --- a/gpu/src/GrPathRenderer.cpp +++ b/gpu/src/GrPathRenderer.cpp @@ -9,8 +9,7 @@ #include "GrPathRenderer.h" GrPathRenderer::GrPathRenderer() - : fCurveTolerance (GR_Scalar1) - , fPath(NULL) + : fPath(NULL) , fTarget(NULL) { } diff --git a/gpu/src/GrPathRenderer.h b/gpu/src/GrPathRenderer.h index 4694de5252..815da47de1 100644 --- a/gpu/src/GrPathRenderer.h +++ b/gpu/src/GrPathRenderer.h @@ -36,8 +36,8 @@ public: * This is called to install custom path renderers in every GrContext at * create time. The default implementation in GrCreatePathRenderer_none.cpp * does not add any additional renderers. Link against another - * implementation to install your own. The most recently added is the - * most preferred path renderer. + * implementation to install your own. The first added is the most preferred + * path renderer, second is second most preferred, etc. * * @param context the context that will use the path renderer * @param flags flags indicating how path renderers will be used @@ -169,16 +169,6 @@ public: GrCrash("Unexpected call to drawPathToStencil."); } - /** - * Multiply curve tolerance by the given value, increasing or decreasing - * the maximum error permitted in tesselating curves with short straight - * line segments. - */ - void scaleCurveTolerance(GrScalar multiplier) { - GrAssert(multiplier > 0); - fCurveTolerance = SkScalarMul(fCurveTolerance, multiplier); - } - /** * Helper that sets a path and automatically remove it in destructor. */ @@ -224,7 +214,6 @@ protected: virtual void pathWasSet() {} virtual void pathWillClear() {} - GrScalar fCurveTolerance; const SkPath* fPath; GrDrawTarget* fTarget; GrPathFill fFill; diff --git a/gpu/src/GrPathUtils.cpp b/gpu/src/GrPathUtils.cpp index 429b2945d3..b7dc4b643e 100644 --- a/gpu/src/GrPathUtils.cpp +++ b/gpu/src/GrPathUtils.cpp @@ -8,10 +8,27 @@ #include "GrPathUtils.h" + #include "GrPoint.h" +GrScalar GrPathUtils::scaleToleranceToSrc(GrScalar devTol, + const GrMatrix& viewM) { + // In order to tesselate the path we get a bound on how much the matrix can + // stretch when mapping to screen coordinates. + GrScalar stretch = viewM.getMaxStretch(); + GrScalar srcTol = devTol; + + if (stretch < 0) { + // TODO: deal with perspective in some better way. + srcTol /= 5; + stretch = -stretch; + } + srcTol = GrScalarDiv(srcTol, stretch); + return srcTol; +} + static const int MAX_POINTS_PER_CURVE = 1 << 10; -const GrScalar GrPathUtils::gMinCurveTol (GrFloatToScalar(0.0001f)); +static const GrScalar gMinCurveTol = GrFloatToScalar(0.0001f); uint32_t GrPathUtils::quadraticPointCount(const GrPoint points[], GrScalar tol) { diff --git a/gpu/src/GrPathUtils.h b/gpu/src/GrPathUtils.h index cde560139e..8d77982a70 100644 --- a/gpu/src/GrPathUtils.h +++ b/gpu/src/GrPathUtils.h @@ -10,41 +10,42 @@ #ifndef GrPathUtils_DEFINED #define GrPathUtils_DEFINED -#include "GrNoncopyable.h" -#include "GrPoint.h" +#include "GrMatrix.h" #include "GrPath.h" +class GrPoint; + /** * Utilities for evaluating paths. */ -class GrPathUtils : public GrNoncopyable { -public: +namespace GrPathUtils { + GrScalar scaleToleranceToSrc(GrScalar devTol, + const GrMatrix& viewM); + /// Since we divide by tol if we're computing exact worst-case bounds, /// very small tolerances will be increased to gMinCurveTol. - static int worstCasePointCount(const GrPath&, - int* subpaths, - GrScalar tol); + int worstCasePointCount(const GrPath&, + int* subpaths, + GrScalar tol); /// Since we divide by tol if we're computing exact worst-case bounds, /// very small tolerances will be increased to gMinCurveTol. - static uint32_t quadraticPointCount(const GrPoint points[], GrScalar tol); - static uint32_t generateQuadraticPoints(const GrPoint& p0, - const GrPoint& p1, - const GrPoint& p2, - GrScalar tolSqd, - GrPoint** points, - uint32_t pointsLeft); + uint32_t quadraticPointCount(const GrPoint points[], GrScalar tol); + uint32_t generateQuadraticPoints(const GrPoint& p0, + const GrPoint& p1, + const GrPoint& p2, + GrScalar tolSqd, + GrPoint** points, + uint32_t pointsLeft); /// Since we divide by tol if we're computing exact worst-case bounds, /// very small tolerances will be increased to gMinCurveTol. - static uint32_t cubicPointCount(const GrPoint points[], GrScalar tol); - static uint32_t generateCubicPoints(const GrPoint& p0, - const GrPoint& p1, - const GrPoint& p2, - const GrPoint& p3, - GrScalar tolSqd, - GrPoint** points, - uint32_t pointsLeft); - -private: - static const GrScalar gMinCurveTol; + uint32_t cubicPointCount(const GrPoint points[], GrScalar tol); + uint32_t generateCubicPoints(const GrPoint& p0, + const GrPoint& p1, + const GrPoint& p2, + const GrPoint& p3, + GrScalar tolSqd, + GrPoint** points, + uint32_t pointsLeft); + }; #endif diff --git a/gpu/src/GrTesselatedPathRenderer.cpp b/gpu/src/GrTesselatedPathRenderer.cpp index 15e3cc0230..dd281ed0b4 100644 --- a/gpu/src/GrTesselatedPathRenderer.cpp +++ b/gpu/src/GrTesselatedPathRenderer.cpp @@ -351,18 +351,9 @@ void GrTesselatedPathRenderer::drawPath(GrDrawTarget::StageBitfield stages) { GrAssert(GrDrawTarget::kBoth_DrawFace == fTarget->getDrawFace()); GrMatrix viewM = fTarget->getViewMatrix(); - // In order to tesselate the path we get a bound on how much the matrix can - // stretch when mapping to screen coordinates. - GrScalar stretch = viewM.getMaxStretch(); - bool useStretch = stretch > 0; - GrScalar tol = fCurveTolerance; - - if (!useStretch) { - // TODO: deal with perspective in some better way. - tol /= 10; - } else { - tol = GrScalarDiv(tol, stretch); - } + + GrScalar tol = GR_Scalar1; + tol = GrPathUtils::scaleToleranceToSrc(tol, viewM); GrScalar tolSqd = GrMul(tol, tol); int subpathCnt; diff --git a/include/core/SkMatrix.h b/include/core/SkMatrix.h index 7c2109c629..333749c442 100644 --- a/include/core/SkMatrix.h +++ b/include/core/SkMatrix.h @@ -501,10 +501,12 @@ public: void toDumpString(SkString*) const; /** - * Calculates the maximum stretching factor of the matrix. Only defined if - * the matrix does not have perspective. + * Calculates the maximum stretching factor of the matrix. If the matrix has + * perspective the max stretch at the origin (in the pre-matrix space) is + * computed and returned as a negative. * - * @return maximum strecthing factor or negative if matrix has perspective. + * @return maximum strecthing factor or negative max stretching factor at + * the origin if matrix has perspective. */ SkScalar getMaxStretch() const; diff --git a/samplecode/SampleHairCurves.cpp b/samplecode/SampleHairCurves.cpp index 152cbeb09c..a3ea5e103d 100644 --- a/samplecode/SampleHairCurves.cpp +++ b/samplecode/SampleHairCurves.cpp @@ -28,6 +28,11 @@ protected: virtual void onDrawContent(SkCanvas* canvas) { + SkMatrix m; + m.reset(); + m.setPerspX(0.00020); + canvas->concat(m); + SkPaint paint; paint.setAntiAlias(true); paint.setStyle(SkPaint::kStroke_Style); @@ -38,6 +43,7 @@ protected: SkPath curves; SkPath hulls; SkPath ctrlPts; + for (int i = 0; i < 100; ++i) { SkScalar pts[] = { rand.nextUScalar1(), rand.nextUScalar1(), diff --git a/src/core/SkMatrix.cpp b/src/core/SkMatrix.cpp index a525f11a01..6fc6e5de30 100644 --- a/src/core/SkMatrix.cpp +++ b/src/core/SkMatrix.cpp @@ -1674,10 +1674,6 @@ bool SkMatrix::setPolyToPoly(const SkPoint src[], const SkPoint dst[], SkScalar SkMatrix::getMaxStretch() const { TypeMask mask = this->getType(); - if (mask & kPerspective_Mask) { - return -SK_Scalar1; - } - SkScalar stretch; if (this->isIdentity()) { @@ -1702,7 +1698,8 @@ SkScalar SkMatrix::getMaxStretch() const { // and roots are guaraunteed to be pos and real). SkScalar largerRoot; SkScalar bSqd = SkScalarMul(b,b); - if (bSqd <= SkFloatToScalar(1e-10)) { // will be true if upper left 2x2 is orthogonal, which is common, so save some math + // if upper left 2x2 is orthogonal save some math + if (bSqd <= SK_ScalarNearlyZero) { largerRoot = SkMaxScalar(a, c); } else { SkScalar aminusc = a - c; @@ -1710,8 +1707,17 @@ SkScalar SkMatrix::getMaxStretch() const { SkScalar x = SkScalarSqrt(SkScalarMul(aminusc, aminusc) + 4 * bSqd) / 2; largerRoot = apluscdiv2 + x; } - stretch = SkScalarSqrt(largerRoot); + if (mask & kPerspective_Mask) { + stretch = -stretch; + if (fMat[kMPersp2] != kMatrix22Elem) { +#if defined(SK_SCALAR_IS_FLOAT) + stretch /= fMat[kMPersp2]; +#else + stretch = SkFractDiv(stretch, fMat[kMPersp2]); +#endif + } + } } #if defined(SK_DEBUG) && 0 // test a bunch of vectors. None should be scaled by more than stretch