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;
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);
}
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
#include "GrPathRenderer.h"
GrPathRenderer::GrPathRenderer()
- : fCurveTolerance (GR_Scalar1)
- , fPath(NULL)
+ : fPath(NULL)
, fTarget(NULL) {
}
* 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
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.
*/
virtual void pathWasSet() {}
virtual void pathWillClear() {}
- GrScalar fCurveTolerance;
const SkPath* fPath;
GrDrawTarget* fTarget;
GrPathFill fFill;
#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) {
#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
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;
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;
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);
SkPath curves;
SkPath hulls;
SkPath ctrlPts;
+
for (int i = 0; i < 100; ++i) {
SkScalar pts[] = {
rand.nextUScalar1(), rand.nextUScalar1(),
SkScalar SkMatrix::getMaxStretch() const {
TypeMask mask = this->getType();
- if (mask & kPerspective_Mask) {
- return -SK_Scalar1;
- }
-
SkScalar stretch;
if (this->isIdentity()) {
// 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;
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