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

#include "src/gpu/tessellate/GrPathCurveTessellator.h"

#include "src/gpu/geometry/GrPathUtils.h"
#include "src/gpu/geometry/GrWangsFormula.h"
#include "src/gpu/tessellate/GrCullTest.h"
#include "src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h"
#include "src/gpu/tessellate/shaders/GrPathTessellationShader.h"

namespace {

constexpr static float kPrecision = GrTessellationPathRenderer::kLinearizationPrecision;

// Writes out curve patches, chopping as necessary so none require more segments than are
// supported by the hardware.
class CurveWriter {
public:
    CurveWriter(const SkRect& cullBounds, const SkMatrix& viewMatrix,
                const GrShaderCaps& shaderCaps)
            : fCullTest(cullBounds, viewMatrix)
            , fVectorXform(viewMatrix) {
        // GrCurveTessellateShader tessellates T=0..(1/2) on the first side of the triangle and
        // T=(1/2)..1 on the second side. This means we get double the max tessellation segments
        // for the range T=0..1.
        float maxSegments = shaderCaps.maxTessellationSegments() * 2;
        fMaxSegments_pow2 = maxSegments * maxSegments;
        fMaxSegments_pow4 = fMaxSegments_pow2 * fMaxSegments_pow2;
    }

    SK_ALWAYS_INLINE void writeQuadratic(GrVertexChunkBuilder* chunker, const SkPoint p[3]) {
        if (GrWangsFormula::quadratic_pow4(kPrecision, p, fVectorXform) > fMaxSegments_pow4) {
            this->chopAndWriteQuadratic(chunker, p);
            return;
        }
        if (GrVertexWriter vertexWriter = chunker->appendVertex()) {
            GrPathUtils::writeQuadAsCubic(p, &vertexWriter);
        }
    }

    SK_ALWAYS_INLINE void writeConic(GrVertexChunkBuilder* chunker, const SkPoint p[3], float w) {
        if (GrWangsFormula::conic_pow2(kPrecision, p, w, fVectorXform) > fMaxSegments_pow2) {
            this->chopAndWriteConic(chunker, {p, w});
            return;
        }
        if (GrVertexWriter vertexWriter = chunker->appendVertex()) {
            GrTessellationShader::WriteConicPatch(p, w, &vertexWriter);
        }
    }

    SK_ALWAYS_INLINE void writeCubic(GrVertexChunkBuilder* chunker, const SkPoint p[4]) {
        if (GrWangsFormula::cubic_pow4(kPrecision, p, fVectorXform) > fMaxSegments_pow4) {
            this->chopAndWriteCubic(chunker, p);
            return;
        }
        if (GrVertexWriter vertexWriter = chunker->appendVertex()) {
            vertexWriter.writeArray(p, 4);
        }
    }

private:
    void chopAndWriteQuadratic(GrVertexChunkBuilder* chunker, const SkPoint p[3]) {
        SkPoint chops[5];
        SkChopQuadAtHalf(p, chops);
        for (int i = 0; i < 2; ++i) {
            const SkPoint* q = chops + i*2;
            if (fCullTest.areVisible3(q)) {
                this->writeQuadratic(chunker, q);
            }
        }
        // Connect the two halves.
        this->writeTriangle(chunker, chops[0], chops[2], chops[4]);
    }

    void chopAndWriteConic(GrVertexChunkBuilder* chunker, const SkConic& conic) {
        SkConic chops[2];
        if (!conic.chopAt(.5, chops)) {
            return;
        }<commit_msg>Don't emit tessellated curves that only need one segment<commit_after>/*
 * Copyright 2021 Google LLC.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "src/gpu/tessellate/GrPathCurveTessellator.h"

#include "src/gpu/geometry/GrPathUtils.h"
#include "src/gpu/geometry/GrWangsFormula.h"
#include "src/gpu/tessellate/GrCullTest.h"
#include "src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h"
#include "src/gpu/tessellate/shaders/GrPathTessellationShader.h"

namespace {

constexpr static float kPrecision = GrTessellationPathRenderer::kLinearizationPrecision;

// Writes out curve patches, chopping as necessary so none require more segments than are
// supported by the hardware.
class CurveWriter {
public:
    CurveWriter(const SkRect& cullBounds, const SkMatrix& viewMatrix,
                const GrShaderCaps& shaderCaps)
            : fCullTest(cullBounds, viewMatrix)
            , fVectorXform(viewMatrix) {
        // GrCurveTessellateShader tessellates T=0..(1/2) on the first side of the triangle and
        // T=(1/2)..1 on the second side. This means we get double the max tessellation segments
        // for the range T=0..1.
        float maxSegments = shaderCaps.maxTessellationSegments() * 2;
        fMaxSegments_pow2 = maxSegments * maxSegments;
        fMaxSegments_pow4 = fMaxSegments_pow2 * fMaxSegments_pow2;
    }

    SK_ALWAYS_INLINE void writeQuadratic(GrVertexChunkBuilder* chunker, const SkPoint p[3]) {
        float numSegments_pow4 = GrWangsFormula::quadratic_pow4(kPrecision, p, fVectorXform);
        if (numSegments_pow4 > fMaxSegments_pow4) {
            this->chopAndWriteQuadratic(chunker, p);
            return;
        }
        if (numSegments_pow4 > 1) {
            if (GrVertexWriter vertexWriter = chunker->appendVertex()) {
                GrPathUtils::writeQuadAsCubic(p, &vertexWriter);
            }
        }
    }

    SK_ALWAYS_INLINE void writeConic(GrVertexChunkBuilder* chunker, const SkPoint p[3], float w) {
        float numSegments_pow2 = GrWangsFormula::conic_pow2(kPrecision, p, w, fVectorXform);
        if (numSegments_pow2 > fMaxSegments_pow2) {
            this->chopAndWriteConic(chunker, {p, w});
            return;
        }
        if (numSegments_pow2 > 1) {
            if (GrVertexWriter vertexWriter = chunker->appendVertex()) {
                GrTessellationShader::WriteConicPatch(p, w, &vertexWriter);
            }
        }
    }

    SK_ALWAYS_INLINE void writeCubic(GrVertexChunkBuilder* chunker, const SkPoint p[4]) {
        float numSegments_pow4 = GrWangsFormula::cubic_pow4(kPrecision, p, fVectorXform);
        if (numSegments_pow4 > fMaxSegments_pow4) {
            this->chopAndWriteCubic(chunker, p);
            return;
        }
        if (numSegments_pow4 > 1) {
            if (GrVertexWriter vertexWriter = chunker->appendVertex()) {
                vertexWriter.writeArray(p, 4);
            }
        }
    }

private:
    void chopAndWriteQuadratic(GrVertexChunkBuilder* chunker, const SkPoint p[3]) {
        SkPoint chops[5];
        SkChopQuadAtHalf(p, chops);
        for (int i = 0; i < 2; ++i) {
            const SkPoint* q = chops + i*2;
            if (fCullTest.areVisible3(q)) {
                this->writeQuadratic(chunker, q);
            }
        }
        // Connect the two halves.
        this->writeTriangle(chunker, chops[0], chops[2], chops[4]);
    }

    void chopAndWriteConic(GrVertexChunkBuilder* chunker, const SkConic& conic) {
        SkConic chops[2];
        if (!conic.chopAt(.5, chops)) {
            return;
        }
{'fraction_non_alphanumeric': 0.0997093023255814, 'fraction_numerical': 0.012790697674418604, 'mean_word_length': 2.7539552645935625, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 28, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1451303', 'n_tokens_mistral': 2305, 'n_tokens_neox': 2218, 'n_words': 484}