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

Commit 856846f1 authored by ztenghui's avatar ztenghui Committed by Android Git Automerger
Browse files

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

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

#define OUTLINE_REFINE_THRESHOLD_SQUARED (0.5f * 0.5f)
#define OUTLINE_REFINE_THRESHOLD 0.5f
#define ROUND_CAP_THRESH 0.25f
#define PI 3.1415926535897932f
#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.
    bool forceClose = paintInfo.style != SkPaint::kStroke_Style;
    PathApproximationInfo approximationInfo(threshInvScaleX, threshInvScaleY,
            OUTLINE_REFINE_THRESHOLD);
    bool wasClosed = approximatePathOutlineVertices(path, forceClose,
            threshInvScaleX * threshInvScaleX, threshInvScaleY * threshInvScaleY,
            OUTLINE_REFINE_THRESHOLD_SQUARED, tempVertices);
            approximationInfo, tempVertices);

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

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

    if (!outlineVertices.size()) return;

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

bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, float thresholdSquared,
bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, float threshold,
        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) {
@@ -946,8 +947,7 @@ private:
};

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

    // 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[2].x(), pts[2].y(),
                        pts[1].x(), pts[1].y(),
                        sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
                        approximationInfo, outputVertices);
                clockwiseEnforcer.addPoint(pts[1]);
                clockwiseEnforcer.addPoint(pts[2]);
                break;
@@ -989,7 +989,7 @@ bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool fo
                        pts[1].x(), pts[1].y(),
                        pts[3].x(), pts[3].y(),
                        pts[2].x(), pts[2].y(),
                        sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
                        approximationInfo, outputVertices);
                clockwiseEnforcer.addPoint(pts[1]);
                clockwiseEnforcer.addPoint(pts[2]);
                clockwiseEnforcer.addPoint(pts[3]);
@@ -998,14 +998,14 @@ bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool fo
                ALOGV("kConic_Verb");
                SkAutoConicToQuads converter;
                const SkPoint* quads = converter.computeQuads(pts, iter.conicWeight(),
                        thresholdSquared);
                        approximationInfo.thresholdForConicQuads);
                for (int i = 0; i < converter.countQuads(); ++i) {
                    const int offset = 2 * i;
                    recursiveQuadraticBezierVertices(
                            quads[offset].x(), quads[offset].y(),
                            quads[offset+2].x(), quads[offset+2].y(),
                            quads[offset+1].x(), quads[offset+1].y(),
                            sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
                            approximationInfo, outputVertices);
                }
                clockwiseEnforcer.addPoint(pts[1]);
                clockwiseEnforcer.addPoint(pts[2]);
@@ -1031,12 +1031,23 @@ bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool fo

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

    // multiplying by sqrInvScaleY/X equivalent to multiplying in dimensional scale factors
    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
        pushToVector(outputVertices, p2x, p2y);
    } else {
@@ -1070,11 +1080,11 @@ void PathTessellator::recursiveCubicBezierVertices(
        recursiveCubicBezierVertices(
                p1x, p1y, p1c1x, p1c1y,
                mx, my, p1c1c2x, p1c1c2y,
                sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices, depth + 1);
                approximationInfo, outputVertices, depth + 1);
        recursiveCubicBezierVertices(
                mx, my, p2c1c2x, p2c1c2y,
                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 bx, float by,
        float cx, float cy,
        float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
        const PathApproximationInfo& approximationInfo,
        Vector<Vertex>& outputVertices, int depth) {
    float dx = bx - ax;
    float dy = by - ay;
    // d is the cross product of vector (B-A) and (C-B).
    float d = (cx - bx) * dy - (cy - by) * dx;

    // multiplying by sqrInvScaleY/X equivalent to multiplying in dimensional scale factors
    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
        pushToVector(outputVertices, bx, by);
    } else {
@@ -1104,9 +1114,9 @@ void PathTessellator::recursiveQuadraticBezierVertices(
        float my = (acy + bcy) * 0.5f;

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

+25 −6
Original line number Diff line number Diff line
@@ -27,6 +27,26 @@
namespace android {
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 {
public:
    /**
@@ -85,16 +105,15 @@ public:
     * Approximates a convex outline into a clockwise Vector of 2d vertices.
     *
     * @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
     */
    static bool approximatePathOutlineVertices(const SkPath &path, float thresholdSquared,
    static bool approximatePathOutlineVertices(const SkPath &path, float threshold,
            Vector<Vertex> &outputVertices);

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

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

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

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

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

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