/*
 * Copyright 2021 Google LLC.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef GrStrokeTessellator_DEFINED
#define GrStrokeTessellator_DEFINED

#include "src/gpu/GrVx.h"
#include "src/gpu/tessellate/shaders/GrStrokeTessellationShader.h"

// Prepares GPU data for, and then draws a stroke's tessellated geometry.
class GrStrokeTessellator {
public:
    using ShaderFlags = GrStrokeTessellationShader::ShaderFlags;

    struct PathStrokeList {
        PathStrokeList(const SkPath& path, const SkStrokeRec& stroke, const SkPMColor4f& color)
                : fPath(path), fStroke(stroke), fColor(color) {}
        SkPath fPath;
        SkStrokeRec fStroke;
        SkPMColor4f fColor;
        PathStrokeList* fNext = nullptr;
    };

    GrStrokeTessellator(const GrShaderCaps& shaderCaps, GrStrokeTessellationShader::Mode shaderMode,
                        ShaderFlags shaderFlags, int8_t maxParametricSegments_log2,
                        const SkMatrix& viewMatrix, PathStrokeList* pathStrokeList,
                        std::array<float, 2> matrixMinMaxScales, const SkRect& strokeCullBounds)
            : fShader(shaderCaps, shaderMode, shaderFlags, viewMatrix, pathStrokeList->fStroke,
                      pathStrokeList->fColor, maxParametricSegments_log2)
            , fPathStrokeList(pathStrokeList)
            , fMatrixMinMaxScales(matrixMinMaxScales)
            , fStrokeCullBounds(strokeCullBounds) {
    }

    const GrTessellationShader* shader() const { return &fShader; }

    // Called before draw(). Prepares GPU buffers containing the geometry to tessellate.
    virtual void prepare(GrMeshDrawTarget*, int totalCombinedVerbCnt) = 0;

    // Issues draw calls for the tessellated stroke. The caller is responsible for creating and
    // binding a pipeline that uses this class's shader() before calling draw().
    virtual void draw(GrOpFlushState*) const = 0;

    virtual ~GrStrokeTessellator() {}

protected:
    GrStrokeTessellationShader fShader;
    PathStrokeList* fPathStrokeList;
    const std::array<float,2> fMatrixMinMaxScales;
    const SkRect fStrokeCullBounds;  // See SkStrokeRec::inflationRadius.
};

// These tolerances decide the number of parametric and radial segments the tessellator will
// linearize strokes into. These decisions are made in (pre-viewMatrix) local path space.
struct GrStrokeTolerances {
    // Decides the number of parametric segments the tessellator adds for each curve. (Uniform
    // steps in parametric space.) The tessellator will add enough parametric segments so that,
    // once transformed into device space, they never deviate by more than
    // 1/GrTessellationPathRenderer::kLinearizationPrecision pixels from the true curve.
    constexpr static float CalcParametricPrecision(float matrixMaxScale) {
        return matrixMaxScale * GrTessellationShader::kLinearizationPrecision;
    }
    // Decides the number of radial segments the tessellator adds for each curve. (Uniform steps
    // in tangent angle.) The tessellator will add this number of radial segments for each
    // radian of rotation in local path space.
    static float CalcNumRadialSegmentsPerRadian(float parametricPrecision,
                                                float strokeWidth) {
        return .5f / acosf(std::max(1 - 2 / (parametricPrecision * strokeWidth), -1.f));
    }
    template<int N> static grvx::vec<N> ApproxNumRadialSegmentsPerRadian(
            float parametricPrecision, grvx::vec<N> strokeWidths) {
        grvx::vec<N> cosTheta = skvx::max(1 - 2 / (parametricPrecision * strokeWidths), -1);
        // Subtract GRVX_APPROX_ACOS_MAX_ERROR so we never account for too few segments.
        return .5f / (grvx::approx_acos(cosTheta) - GRVX_APPROX_ACOS_MAX_ERROR);
    }
    // Returns the equivalent stroke width in (pre-viewMatrix) local path space that the
    // tessellator will use when rendering this stroke. This only differs from the actual stroke
    // width for hairlines.
    static float GetLocalStrokeWidth(const float matrixMinMaxScales[2], float strokeWidth) {
        SkASSERT(strokeWidth >= 0);
        float localStrokeWidth = strokeWidth;
        if (localStrokeWidth == 0) {  // Is the stroke a hairline?
            float matrixMinScale = matrixMinMaxScales[0];
            float matrixMaxScale = matrixMinMaxScales[1];
            // If the stroke is hairline then the tessellator will operate in post-transform
            // space instead. But for the sake of CPU methods that need to conservatively
            // approximate the number of segments to emit, we use
            // localStrokeWidth ~= 1/matrixMinScale.
            float approxScale = matrixMinScale;
            // If the matrix has strong skew, don't let the scale shoot off to infinity. (This
            // does not affect the tessellator; only the CPU methods that approximate the number
            // of segments to emit.)
            approxScale = std::max(matrixMinScale, matrixMaxScale * .25f);
            localStrokeWidth = 1/approxScale;
            if (localStrokeWidth == 0) {
                // We just can't accidentally return zero from this method because zero means
                // "hairline". Otherwise return whatever we calculated above.
                localStrokeWidth = SK_ScalarNearlyZero;
            }
        }
        return localStrokeWidth;
    }
    static GrStrokeTolerances Make(const float matrixMinMaxScales[2], float strokeWidth) {
        return MakeNonHairline(matrixMinMaxScales[1],
                               GetLocalStrokeWidth(matrixMinMaxScales, strokeWidth));
    }
    static GrStrokeTolerances MakeNonHairline(float matrixMaxScale, float strokeWidth) {
        SkASSERT(strokeWidth > 0);
        float parametricPrecision = CalcParametricPrecision(matrixMaxScale);
        return {parametricPrecision,
                CalcNumRadialSegmentsPerRadian(parametricPrecision, strokeWidth)};
    }
    float fParametricPrecision;
    float fNumRadialSegmentsPerRadian;
};

// Calculates and buffers up future values for "numRadialSegmentsPerRadian" using SIMD.
class alignas(sizeof(float) * 4) GrStrokeToleranceBuffer {
public:
    using PathStrokeList = GrStrokeTessellator::PathStrokeList;

    GrStrokeToleranceBuffer(float parametricPrecision)
            : fParametricPrecision(parametricPrecision) {
    }

    float fetchRadialSegmentsPerRadian(PathStrokeList* head) {
        // GrStrokeTessellateOp::onCombineIfPossible does not allow hairlines to become dynamic. If
        // this changes, we will need to call GrStrokeTolerances::GetLocalStrokeWidth() for each
        // stroke.
        SkASSERT(!head->fStroke.isHairlineStyle());
        if (fBufferIdx == 4) {
            // We ran out of values. Peek ahead and buffer up 4 more.
            PathStrokeList* peekAhead = head;
            int i = 0;
            do {
                fStrokeWidths[i++] = peekAhead->fStroke.getWidth();
            } while ((peekAhead = peekAhead->fNext) && i < 4);
            auto tol = GrStrokeTolerances::ApproxNumRadialSegmentsPerRadian(fParametricPrecision,
                                                                            fStrokeWidths);
            tol.store(fNumRadialSegmentsPerRadian);
            fBufferIdx = 0;
        }
        SkASSERT(0 <= fBufferIdx && fBufferIdx < 4);
        SkASSERT(fStrokeWidths[fBufferIdx] == head->fStroke.getWidth());
        return fNumRadialSegmentsPerRadian[fBufferIdx++];
    }

private:
    grvx::float4 fStrokeWidths{};  // Must be first for alignment purposes.
    float fNumRadialSegmentsPerRadian[4];
    const float fParametricPrecision;
    int fBufferIdx = 4;  // Initialize the buffer as "empty";
};

#endif
