Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 71123f87 authored by ztenghui's avatar ztenghui Committed by Android Git Automerger
Browse files

am f302eb00: am 856846f1: am e9d8480f: Merge "Tweak the threshold for conic...

am f302eb00: am 856846f1: am e9d8480f: Merge "Tweak the threshold for conic path quads computation." into mnc-dev

* commit 'f302eb00':
  Tweak the threshold for conic path quads computation.
parents b359bdf1 f302eb00
Loading
Loading
Loading
Loading
+35 −25
Original line number Original line Diff line number Diff line
@@ -56,7 +56,7 @@
namespace android {
namespace android {
namespace uirenderer {
namespace uirenderer {


#define OUTLINE_REFINE_THRESHOLD_SQUARED (0.5f * 0.5f)
#define OUTLINE_REFINE_THRESHOLD 0.5f
#define ROUND_CAP_THRESH 0.25f
#define ROUND_CAP_THRESH 0.25f
#define PI 3.1415926535897932f
#define PI 3.1415926535897932f
#define MAX_DEPTH 15
#define MAX_DEPTH 15
@@ -739,9 +739,10 @@ void PathTessellator::tessellatePath(const SkPath &path, const SkPaint* paint,


    // force close if we're filling the path, since fill path expects closed perimeter.
    // force close if we're filling the path, since fill path expects closed perimeter.
    bool forceClose = paintInfo.style != SkPaint::kStroke_Style;
    bool forceClose = paintInfo.style != SkPaint::kStroke_Style;
    PathApproximationInfo approximationInfo(threshInvScaleX, threshInvScaleY,
            OUTLINE_REFINE_THRESHOLD);
    bool wasClosed = approximatePathOutlineVertices(path, forceClose,
    bool wasClosed = approximatePathOutlineVertices(path, forceClose,
            threshInvScaleX * threshInvScaleX, threshInvScaleY * threshInvScaleY,
            approximationInfo, tempVertices);
            OUTLINE_REFINE_THRESHOLD_SQUARED, tempVertices);


    if (!tempVertices.size()) {
    if (!tempVertices.size()) {
        // path was empty, return without allocating vertex buffer
        // path was empty, return without allocating vertex buffer
@@ -819,10 +820,9 @@ void PathTessellator::tessellatePoints(const float* points, int count, const SkP


    // calculate outline
    // calculate outline
    Vector<Vertex> outlineVertices;
    Vector<Vertex> outlineVertices;
    approximatePathOutlineVertices(path, true,
    PathApproximationInfo approximationInfo(paintInfo.inverseScaleX, paintInfo.inverseScaleY,
            paintInfo.inverseScaleX * paintInfo.inverseScaleX,
            OUTLINE_REFINE_THRESHOLD);
            paintInfo.inverseScaleY * paintInfo.inverseScaleY,
    approximatePathOutlineVertices(path, true, approximationInfo, outlineVertices);
            OUTLINE_REFINE_THRESHOLD_SQUARED, outlineVertices);


    if (!outlineVertices.size()) return;
    if (!outlineVertices.size()) return;


@@ -899,9 +899,10 @@ void PathTessellator::tessellateLines(const float* points, int count, const SkPa
// Simple path line approximation
// Simple path line approximation
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////


bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, float thresholdSquared,
bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, float threshold,
        Vector<Vertex>& outputVertices) {
        Vector<Vertex>& outputVertices) {
    return approximatePathOutlineVertices(path, true, 1.0f, 1.0f, thresholdSquared, outputVertices);
    PathApproximationInfo approximationInfo(1.0f, 1.0f, threshold);
    return approximatePathOutlineVertices(path, true, approximationInfo, outputVertices);
}
}


void pushToVector(Vector<Vertex>& vertices, float x, float y) {
void pushToVector(Vector<Vertex>& vertices, float x, float y) {
@@ -946,8 +947,7 @@ private:
};
};


bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool forceClose,
bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool forceClose,
        float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
        const PathApproximationInfo& approximationInfo, Vector<Vertex>& outputVertices) {
        Vector<Vertex>& outputVertices) {
    ATRACE_CALL();
    ATRACE_CALL();


    // TODO: to support joins other than sharp miter, join vertices should be labelled in the
    // TODO: to support joins other than sharp miter, join vertices should be labelled in the
@@ -978,7 +978,7 @@ bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool fo
                        pts[0].x(), pts[0].y(),
                        pts[0].x(), pts[0].y(),
                        pts[2].x(), pts[2].y(),
                        pts[2].x(), pts[2].y(),
                        pts[1].x(), pts[1].y(),
                        pts[1].x(), pts[1].y(),
                        sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
                        approximationInfo, outputVertices);
                clockwiseEnforcer.addPoint(pts[1]);
                clockwiseEnforcer.addPoint(pts[1]);
                clockwiseEnforcer.addPoint(pts[2]);
                clockwiseEnforcer.addPoint(pts[2]);
                break;
                break;
@@ -989,7 +989,7 @@ bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool fo
                        pts[1].x(), pts[1].y(),
                        pts[1].x(), pts[1].y(),
                        pts[3].x(), pts[3].y(),
                        pts[3].x(), pts[3].y(),
                        pts[2].x(), pts[2].y(),
                        pts[2].x(), pts[2].y(),
                        sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
                        approximationInfo, outputVertices);
                clockwiseEnforcer.addPoint(pts[1]);
                clockwiseEnforcer.addPoint(pts[1]);
                clockwiseEnforcer.addPoint(pts[2]);
                clockwiseEnforcer.addPoint(pts[2]);
                clockwiseEnforcer.addPoint(pts[3]);
                clockwiseEnforcer.addPoint(pts[3]);
@@ -998,14 +998,14 @@ bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool fo
                ALOGV("kConic_Verb");
                ALOGV("kConic_Verb");
                SkAutoConicToQuads converter;
                SkAutoConicToQuads converter;
                const SkPoint* quads = converter.computeQuads(pts, iter.conicWeight(),
                const SkPoint* quads = converter.computeQuads(pts, iter.conicWeight(),
                        thresholdSquared);
                        approximationInfo.thresholdForConicQuads);
                for (int i = 0; i < converter.countQuads(); ++i) {
                for (int i = 0; i < converter.countQuads(); ++i) {
                    const int offset = 2 * i;
                    const int offset = 2 * i;
                    recursiveQuadraticBezierVertices(
                    recursiveQuadraticBezierVertices(
                            quads[offset].x(), quads[offset].y(),
                            quads[offset].x(), quads[offset].y(),
                            quads[offset+2].x(), quads[offset+2].y(),
                            quads[offset+2].x(), quads[offset+2].y(),
                            quads[offset+1].x(), quads[offset+1].y(),
                            quads[offset+1].x(), quads[offset+1].y(),
                            sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
                            approximationInfo, outputVertices);
                }
                }
                clockwiseEnforcer.addPoint(pts[1]);
                clockwiseEnforcer.addPoint(pts[1]);
                clockwiseEnforcer.addPoint(pts[2]);
                clockwiseEnforcer.addPoint(pts[2]);
@@ -1031,12 +1031,23 @@ bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool fo


///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Bezier approximation
// Bezier approximation
//
// All the inputs and outputs here are in path coordinates.
// We convert the error threshold from screen coordinates into path coordinates.
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////


// Get a threshold in path coordinates, by scaling the thresholdSquared from screen coordinates.
// TODO: Document the math behind this algorithm.
static inline float getThreshold(const PathApproximationInfo& info, float dx, float dy) {
    // multiplying by sqrInvScaleY/X equivalent to multiplying in dimensional scale factors
    float scale = (dx * dx * info.sqrInvScaleY + dy * dy * info.sqrInvScaleX);
    return info.thresholdSquared * scale;
}

void PathTessellator::recursiveCubicBezierVertices(
void PathTessellator::recursiveCubicBezierVertices(
        float p1x, float p1y, float c1x, float c1y,
        float p1x, float p1y, float c1x, float c1y,
        float p2x, float p2y, float c2x, float c2y,
        float p2x, float p2y, float c2x, float c2y,
        float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
        const PathApproximationInfo& approximationInfo,
        Vector<Vertex>& outputVertices, int depth) {
        Vector<Vertex>& outputVertices, int depth) {
    float dx = p2x - p1x;
    float dx = p2x - p1x;
    float dy = p2y - p1y;
    float dy = p2y - p1y;
@@ -1044,9 +1055,8 @@ void PathTessellator::recursiveCubicBezierVertices(
    float d2 = fabs((c2x - p2x) * dy - (c2y - p2y) * dx);
    float d2 = fabs((c2x - p2x) * dy - (c2y - p2y) * dx);
    float d = d1 + d2;
    float d = d1 + d2;


    // multiplying by sqrInvScaleY/X equivalent to multiplying in dimensional scale factors
    if (depth >= MAX_DEPTH
    if (depth >= MAX_DEPTH
            || d * d <= thresholdSquared * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
            || d * d <= getThreshold(approximationInfo, dx, dy)) {
        // below thresh, draw line by adding endpoint
        // below thresh, draw line by adding endpoint
        pushToVector(outputVertices, p2x, p2y);
        pushToVector(outputVertices, p2x, p2y);
    } else {
    } else {
@@ -1070,11 +1080,11 @@ void PathTessellator::recursiveCubicBezierVertices(
        recursiveCubicBezierVertices(
        recursiveCubicBezierVertices(
                p1x, p1y, p1c1x, p1c1y,
                p1x, p1y, p1c1x, p1c1y,
                mx, my, p1c1c2x, p1c1c2y,
                mx, my, p1c1c2x, p1c1c2y,
                sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices, depth + 1);
                approximationInfo, outputVertices, depth + 1);
        recursiveCubicBezierVertices(
        recursiveCubicBezierVertices(
                mx, my, p2c1c2x, p2c1c2y,
                mx, my, p2c1c2x, p2c1c2y,
                p2x, p2y, p2c2x, p2c2y,
                p2x, p2y, p2c2x, p2c2y,
                sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices, depth + 1);
                approximationInfo, outputVertices, depth + 1);
    }
    }
}
}


@@ -1082,15 +1092,15 @@ void PathTessellator::recursiveQuadraticBezierVertices(
        float ax, float ay,
        float ax, float ay,
        float bx, float by,
        float bx, float by,
        float cx, float cy,
        float cx, float cy,
        float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
        const PathApproximationInfo& approximationInfo,
        Vector<Vertex>& outputVertices, int depth) {
        Vector<Vertex>& outputVertices, int depth) {
    float dx = bx - ax;
    float dx = bx - ax;
    float dy = by - ay;
    float dy = by - ay;
    // d is the cross product of vector (B-A) and (C-B).
    float d = (cx - bx) * dy - (cy - by) * dx;
    float d = (cx - bx) * dy - (cy - by) * dx;


    // multiplying by sqrInvScaleY/X equivalent to multiplying in dimensional scale factors
    if (depth >= MAX_DEPTH
    if (depth >= MAX_DEPTH
            || d * d <= thresholdSquared * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
            || d * d <= getThreshold(approximationInfo, dx, dy)) {
        // below thresh, draw line by adding endpoint
        // below thresh, draw line by adding endpoint
        pushToVector(outputVertices, bx, by);
        pushToVector(outputVertices, bx, by);
    } else {
    } else {
@@ -1104,9 +1114,9 @@ void PathTessellator::recursiveQuadraticBezierVertices(
        float my = (acy + bcy) * 0.5f;
        float my = (acy + bcy) * 0.5f;


        recursiveQuadraticBezierVertices(ax, ay, mx, my, acx, acy,
        recursiveQuadraticBezierVertices(ax, ay, mx, my, acx, acy,
                sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices, depth + 1);
                approximationInfo, outputVertices, depth + 1);
        recursiveQuadraticBezierVertices(mx, my, bx, by, bcx, bcy,
        recursiveQuadraticBezierVertices(mx, my, bx, by, bcx, bcy,
                sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices, depth + 1);
                approximationInfo, outputVertices, depth + 1);
    }
    }
}
}


+25 −6
Original line number Original line Diff line number Diff line
@@ -27,6 +27,26 @@
namespace android {
namespace android {
namespace uirenderer {
namespace uirenderer {


/**
 * Structure used for threshold values in outline path tessellation.
 *
 * TODO: PaintInfo should store one of this object, and initialized all values in constructor
 * depending on its type (point, line or path).
 */
struct PathApproximationInfo {
    PathApproximationInfo(float invScaleX, float invScaleY, float pixelThreshold)
        : thresholdSquared(pixelThreshold * pixelThreshold)
        , sqrInvScaleX(invScaleX * invScaleX)
        , sqrInvScaleY(invScaleY * invScaleY)
        , thresholdForConicQuads(pixelThreshold * MathUtils::min(invScaleX, invScaleY) / 2.0f) {
    };

    const float thresholdSquared;
    const float sqrInvScaleX;
    const float sqrInvScaleY;
    const float thresholdForConicQuads;
};

class PathTessellator {
class PathTessellator {
public:
public:
    /**
    /**
@@ -85,16 +105,15 @@ public:
     * Approximates a convex outline into a clockwise Vector of 2d vertices.
     * Approximates a convex outline into a clockwise Vector of 2d vertices.
     *
     *
     * @param path The outline to be approximated
     * @param path The outline to be approximated
     * @param thresholdSquared The threshold of acceptable error (in pixels) when approximating
     * @param threshold The threshold of acceptable error (in pixels) when approximating
     * @param outputVertices An empty Vector which will be populated with the output
     * @param outputVertices An empty Vector which will be populated with the output
     */
     */
    static bool approximatePathOutlineVertices(const SkPath &path, float thresholdSquared,
    static bool approximatePathOutlineVertices(const SkPath &path, float threshold,
            Vector<Vertex> &outputVertices);
            Vector<Vertex> &outputVertices);


private:
private:
    static bool approximatePathOutlineVertices(const SkPath &path, bool forceClose,
    static bool approximatePathOutlineVertices(const SkPath &path, bool forceClose,
            float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
            const PathApproximationInfo& approximationInfo, Vector<Vertex> &outputVertices);
            Vector<Vertex> &outputVertices);


/*
/*
  endpoints a & b,
  endpoints a & b,
@@ -104,7 +123,7 @@ private:
            float ax, float ay,
            float ax, float ay,
            float bx, float by,
            float bx, float by,
            float cx, float cy,
            float cx, float cy,
            float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
            const PathApproximationInfo& approximationInfo,
            Vector<Vertex> &outputVertices, int depth = 0);
            Vector<Vertex> &outputVertices, int depth = 0);


/*
/*
@@ -116,7 +135,7 @@ private:
            float c1x, float c1y,
            float c1x, float c1y,
            float p2x, float p2y,
            float p2x, float p2y,
            float c2x, float c2y,
            float c2x, float c2y,
            float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
            const PathApproximationInfo& approximationInfo,
            Vector<Vertex> &outputVertices, int depth = 0);
            Vector<Vertex> &outputVertices, int depth = 0);
};
};


+2 −2
Original line number Original line Diff line number Diff line
@@ -226,9 +226,9 @@ static void tessellateShadows(


    // tessellate caster outline into a 2d polygon
    // tessellate caster outline into a 2d polygon
    Vector<Vertex> casterVertices2d;
    Vector<Vertex> casterVertices2d;
    const float casterRefinementThresholdSquared = 4.0f;
    const float casterRefinementThreshold = 2.0f;
    PathTessellator::approximatePathOutlineVertices(*casterPerimeter,
    PathTessellator::approximatePathOutlineVertices(*casterPerimeter,
            casterRefinementThresholdSquared, casterVertices2d);
            casterRefinementThreshold, casterVertices2d);


    // Shadow requires CCW for now. TODO: remove potential double-reverse
    // Shadow requires CCW for now. TODO: remove potential double-reverse
    reverseVertexArray(casterVertices2d.editArray(), casterVertices2d.size());
    reverseVertexArray(casterVertices2d.editArray(), casterVertices2d.size());