<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/GrPathStencilCoverOp.h"

#include "src/gpu/GrDefaultGeoProcFactory.h"
#include "src/gpu/GrEagerVertexAllocator.h"
#include "src/gpu/GrGpu.h"
#include "src/gpu/GrOpFlushState.h"
#include "src/gpu/GrRecordingContextPriv.h"
#include "src/gpu/GrResourceProvider.h"
#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
#include "src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h"
#include "src/gpu/tessellate/GrPathCurveTessellator.h"
#include "src/gpu/tessellate/GrPathWedgeTessellator.h"
#include "src/gpu/tessellate/GrTessellationPathRenderer.h"
#include "src/gpu/tessellate/shaders/GrPathTessellationShader.h"

using PathFlags = GrTessellationPathRenderer::PathFlags;

namespace {

// Fills a path's bounding box, with subpixel outset to avoid possible T-junctions with extreme
// edges of the path.
// NOTE: The emitted geometry may not be axis-aligned, depending on the view matrix.
class BoundingBoxShader : public GrPathTessellationShader {
public:
    BoundingBoxShader(const SkMatrix& viewMatrix, SkPMColor4f color, const GrShaderCaps& shaderCaps)
            : GrPathTessellationShader(kTessellate_BoundingBoxShader_ClassID,
                                       GrPrimitiveType::kTriangleStrip, 0, viewMatrix, color) {
        constexpr static Attribute kPathBoundsAttrib("pathBounds", kFloat4_GrVertexAttribType,
                                                     kFloat4_GrSLType);
        this->setInstanceAttributes(&kPathBoundsAttrib, 1);
        if (!shaderCaps.vertexIDSupport()) {
            constexpr static Attribute kUnitCoordAttrib("unitCoord", kFloat2_GrVertexAttribType,
                                                        kFloat2_GrSLType);
            this->setVertexAttributes(&kUnitCoordAttrib, 1);
        }
    }

private:
    const char* name() const final { return "tessellate_BoundingBoxShader"; }
    void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const final {}
    GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const final;
};

GrGLSLGeometryProcessor* BoundingBoxShader::createGLSLInstance(const GrShaderCaps&) const {
    class Impl : public GrPathTessellationShader::Impl {
        void emitVertexCode(const GrShaderCaps& shaderCaps, const GrPathTessellationShader&,
                            GrGLSLVertexBuilder* v, GrGPArgs* gpArgs) override {
            if (shaderCaps.vertexIDSupport()) {
                // If we don't have sk_VertexID support then "unitCoord" already came in as a vertex
                // attrib.
                v->codeAppendf(R"(
                float2 unitCoord = float2(sk_VertexID & 1, sk_VertexID >> 1);)");
            }

            v->codeAppend(R"(
            // Bloat the bounding box by 1/4px to avoid potential T-junctions at the edges.
            float2x2 M_ = inverse(AFFINE_MATRIX);
            float2 bloat = float2(abs(M_[0]) + abs(M_[1])) * .25;

            // Find the vertex position.
            float2 localcoord = mix(pathBounds.xy - bloat, pathBounds.zw + bloat, unitCoord);
            float2 vertexpos = AFFINE_MATRIX * localcoord + TRANSLATE;)");
            gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localcoord");
            gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos");
        }
    };
    return new Impl;
}

}  // namespace

void GrPathStencilCoverOp::visitProxies(const GrVisitProxyFunc& func) const {
    if (fCoverBBoxProgram) {
        fCoverBBoxProgram->pipeline().visitProxies(func);
    } else {
        fProcessors.visitProxies(func);
    }
}

GrDrawOp::FixedFunctionFlags GrPathStencilCoverOp::fixedFunctionFlags() const {
    auto flags = FixedFunctionFlags::kUsesStencil;
    if (fAAType != GrAAType::kNone) {
        flags |= FixedFunctionFlags::kUsesHWAA;
    }
    return flags;
}

GrProcessorSet::Analysis GrPathStencilCoverOp::finalize(const GrCaps& caps,
                                                        const GrAppliedClip* clip,
                                                        GrClampType clampType) {
    return fProcessors.finalize(fColor, GrProcessorAnalysisCoverage::kNone, clip, nullptr, caps,
                                clampType, &fColor);
}

void GrPathStencilCoverOp::prePreparePrograms(const GrTessellationShader::ProgramArgs& args,
                                              GrAppliedClip&& appliedClip) {
    SkASSERT(!fTessellator);
    SkASSERT(!fStencilFanProgram);
    SkASSERT(!fStencilPathProgram);
    SkASSERT(!fCoverBBoxProgram);

    const GrPipeline* stencilPipeline = GrPathTessellationShader::MakeStencilOnlyPipeline(
            args, fAAType, fPathFlags, appliedClip.hardClip());
    const GrUserStencilSettings* stencilPathSettings =
            GrPathTessellationShader::StencilPathSettings(GrFillRuleForSkPath(fPath));

    if (fPath.countVerbs() > 50 && this->bounds().height() * this->bounds().width() > 256 * 256) {
        // Large complex paths do better with a dedicated triangle shader for the inner fan.
        // This takes less PCI bus bandwidth (6 floats per triangle instead of 8) and allows us
        // to make sure it has an efficient middle-out topology.
        auto triangleGP = GrDefaultGeoProcFactory::Make(
                args.fArena,
                GrDefaultGeoProcFactory::Color(SK_PMColor4fTRANSPARENT),
                GrDefaultGeoProcFactory::Coverage::kSolid_Type,
                GrDefaultGeoProcFactory::LocalCoords::kUnused_Type,
                fViewMatrix);
        fStencilFanProgram = GrSimpleMeshDrawOpHelper::CreateProgramInfo(
                args.fArena,
                stencilPipeline,
                args.fWriteView,
                triangleGP,
                GrPrimitiveType::kTriangles,
                args.fXferBarrierFlags,
                args.fColorLoadOp,
                stencilPathSettings);
        fTessellator = GrPathCurveTessellator::Make(args.fArena, fViewMatrix,
                                                    SK_PMColor4fTRANSPARENT,
                                                    GrPathCurveTessellator::DrawInnerFan::kNo,
                                                    fPath.countVerbs(), *stencilPipeline,
                                                    *args.fCaps);
    } else {
        fTessellator = GrPathWedgeTessellator::Make(args.fArena, fViewMatrix,
                                                    SK_PMColor4fTRANSPARENT, fPath.countVerbs(),
                                                    *stencilPipeline, *args.fCaps);
    }
    fStencilPathProgram = GrTessellationShader::MakeProgram(args, fTessellator->shader(),
                                                            stencilPipeline, stencilPathSettings);

    if (!(fPathFlags & PathFlags::kStencilOnly)) {
        // Create a program that draws a bounding box over the path and fills its stencil coverage
        // into the color buffer.
        auto* bboxShader = args.fArena->make<BoundingBoxShader>(fViewMatrix, fColor,
                                                                *args.fCaps->shaderCaps());
        auto* bboxPipeline = GrTessellationShader::MakePipeline(args, fAAType,
                                                                std::move(appliedClip),
                                                                std::move(fProcessors));
        auto* bboxStencil =
                GrPathTessellationShader::TestAndResetStencilSettings(fPath.isInverseFillType());
        fCoverBBoxProgram = GrTessellationShader::MakeProgram(args, bboxShader, bboxPipeline,
                                                              bboxStencil);
    }
}

void GrPathStencilCoverOp::onPrePrepare(GrRecordingContext* context,
                                        const GrSurfaceProxyView& writeView, GrAppliedClip* clip,<commit_msg>Make BoundingBoxShader inherit from GrGeometryProcessor directly<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/GrPathStencilCoverOp.h"

#include "src/gpu/GrDefaultGeoProcFactory.h"
#include "src/gpu/GrEagerVertexAllocator.h"
#include "src/gpu/GrGpu.h"
#include "src/gpu/GrOpFlushState.h"
#include "src/gpu/GrRecordingContextPriv.h"
#include "src/gpu/GrResourceProvider.h"
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
#include "src/gpu/glsl/GrGLSLVarying.h"
#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
#include "src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h"
#include "src/gpu/tessellate/GrPathCurveTessellator.h"
#include "src/gpu/tessellate/GrPathWedgeTessellator.h"
#include "src/gpu/tessellate/GrTessellationPathRenderer.h"
#include "src/gpu/tessellate/shaders/GrPathTessellationShader.h"

using PathFlags = GrTessellationPathRenderer::PathFlags;

namespace {

// Fills a path's bounding box, with subpixel outset to avoid possible T-junctions with extreme
// edges of the path.
// NOTE: The emitted geometry may not be axis-aligned, depending on the view matrix.
class BoundingBoxShader : public GrGeometryProcessor {
public:
    BoundingBoxShader(const SkMatrix& viewMatrix, SkPMColor4f color, const GrShaderCaps& shaderCaps)
            : GrGeometryProcessor(kTessellate_BoundingBoxShader_ClassID)
            , fViewMatrix(viewMatrix)
            , fColor(color) {
        // The 1/4px outset logic does not work with perspective yet.
        SkASSERT(!fViewMatrix.hasPerspective());
        if (!shaderCaps.vertexIDSupport()) {
            constexpr static Attribute kUnitCoordAttrib("unitCoord", kFloat2_GrVertexAttribType,
                                                        kFloat2_GrSLType);
            this->setVertexAttributes(&kUnitCoordAttrib, 1);
        }
        constexpr static Attribute kPathBoundsAttrib("pathBounds", kFloat4_GrVertexAttribType,
                                                     kFloat4_GrSLType);
        this->setInstanceAttributes(&kPathBoundsAttrib, 1);
    }

private:
    const char* name() const final { return "tessellate_BoundingBoxShader"; }
    void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const final {}
    GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const final;

    const SkMatrix fViewMatrix;
    const SkPMColor4f fColor;
};

GrGLSLGeometryProcessor* BoundingBoxShader::createGLSLInstance(const GrShaderCaps&) const {
    class Impl : public GrGLSLGeometryProcessor {
        void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) final {
            args.fVaryingHandler->emitAttributes(args.fGeomProc);

            // Vertex shader.
            const char* viewMatrix;
            fViewMatrixUniform = args.fUniformHandler->addUniform(nullptr, kVertex_GrShaderFlag,
                                                                  kFloat3x3_GrSLType, "viewMatrix",
                                                                  &viewMatrix);
            if (args.fShaderCaps->vertexIDSupport()) {
                // If we don't have sk_VertexID support then "unitCoord" already came in as a vertex
                // attrib.
                args.fVertBuilder->codeAppendf(R"(
                float2 unitCoord = float2(sk_VertexID & 1, sk_VertexID >> 1);)");
            }
            args.fVertBuilder->codeAppendf(R"(
            float3x3 VIEW_MATRIX = %s;

            // Bloat the bounding box by 1/4px to be certain we will reset every stencil value.
            float2x2 M_ = inverse(float2x2(VIEW_MATRIX));
            float2 bloat = float2(abs(M_[0]) + abs(M_[1])) * .25;

            // Find the vertex position.
            float2 localcoord = mix(pathBounds.xy - bloat, pathBounds.zw + bloat, unitCoord);
            float2 vertexpos = (VIEW_MATRIX * float3(localcoord, 1)).xy;)", viewMatrix);
            gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localcoord");
            gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos");

            // Fragment shader.
            const char* color;
            fColorUniform = args.fUniformHandler->addUniform(nullptr, kFragment_GrShaderFlag,
                                                             kHalf4_GrSLType, "color", &color);
            args.fFragBuilder->codeAppendf("half4 %s = %s;", args.fOutputColor, color);
            args.fFragBuilder->codeAppendf("const half4 %s = half4(1);", args.fOutputCoverage);
        }

        void setData(const GrGLSLProgramDataManager& pdman, const GrShaderCaps&,
                     const GrGeometryProcessor& gp) override {
            const auto& bboxShader = gp.cast<BoundingBoxShader>();
            pdman.setSkMatrix(fViewMatrixUniform, bboxShader.fViewMatrix);
            const SkPMColor4f& color = bboxShader.fColor;
            pdman.set4f(fColorUniform, color.fR, color.fG, color.fB, color.fA);
        }

        GrGLSLUniformHandler::UniformHandle fViewMatrixUniform;
        GrGLSLUniformHandler::UniformHandle fColorUniform;
    };

    return new Impl;
}

}  // namespace

void GrPathStencilCoverOp::visitProxies(const GrVisitProxyFunc& func) const {
    if (fCoverBBoxProgram) {
        fCoverBBoxProgram->pipeline().visitProxies(func);
    } else {
        fProcessors.visitProxies(func);
    }
}

GrDrawOp::FixedFunctionFlags GrPathStencilCoverOp::fixedFunctionFlags() const {
    auto flags = FixedFunctionFlags::kUsesStencil;
    if (fAAType != GrAAType::kNone) {
        flags |= FixedFunctionFlags::kUsesHWAA;
    }
    return flags;
}

GrProcessorSet::Analysis GrPathStencilCoverOp::finalize(const GrCaps& caps,
                                                        const GrAppliedClip* clip,
                                                        GrClampType clampType) {
    return fProcessors.finalize(fColor, GrProcessorAnalysisCoverage::kNone, clip, nullptr, caps,
                                clampType, &fColor);
}

void GrPathStencilCoverOp::prePreparePrograms(const GrTessellationShader::ProgramArgs& args,
                                              GrAppliedClip&& appliedClip) {
    SkASSERT(!fTessellator);
    SkASSERT(!fStencilFanProgram);
    SkASSERT(!fStencilPathProgram);
    SkASSERT(!fCoverBBoxProgram);

    const GrPipeline* stencilPipeline = GrPathTessellationShader::MakeStencilOnlyPipeline(
            args, fAAType, fPathFlags, appliedClip.hardClip());
    const GrUserStencilSettings* stencilPathSettings =
            GrPathTessellationShader::StencilPathSettings(GrFillRuleForSkPath(fPath));

    if (fPath.countVerbs() > 50 && this->bounds().height() * this->bounds().width() > 256 * 256) {
        // Large complex paths do better with a dedicated triangle shader for the inner fan.
        // This takes less PCI bus bandwidth (6 floats per triangle instead of 8) and allows us
        // to make sure it has an efficient middle-out topology.
        auto triangleGP = GrDefaultGeoProcFactory::Make(
                args.fArena,
                GrDefaultGeoProcFactory::Color(SK_PMColor4fTRANSPARENT),
                GrDefaultGeoProcFactory::Coverage::kSolid_Type,
                GrDefaultGeoProcFactory::LocalCoords::kUnused_Type,
                fViewMatrix);
        fStencilFanProgram = GrSimpleMeshDrawOpHelper::CreateProgramInfo(
                args.fArena,
                stencilPipeline,
                args.fWriteView,
                triangleGP,
                GrPrimitiveType::kTriangles,
                args.fXferBarrierFlags,
                args.fColorLoadOp,
                stencilPathSettings);
        fTessellator = GrPathCurveTessellator::Make(args.fArena, fViewMatrix,
                                                    SK_PMColor4fTRANSPARENT,
                                                    GrPathCurveTessellator::DrawInnerFan::kNo,
                                                    fPath.countVerbs(), *stencilPipeline,
                                                    *args.fCaps);
    } else {
        fTessellator = GrPathWedgeTessellator::Make(args.fArena, fViewMatrix,
                                                    SK_PMColor4fTRANSPARENT, fPath.countVerbs(),
                                                    *stencilPipeline, *args.fCaps);
    }
    fStencilPathProgram = GrTessellationShader::MakeProgram(args, fTessellator->shader(),
                                                            stencilPipeline, stencilPathSettings);

    if (!(fPathFlags & PathFlags::kStencilOnly)) {
        // Create a program that draws a bounding box over the path and fills its stencil coverage
        // into the color buffer.
        auto* bboxShader = args.fArena->make<BoundingBoxShader>(fViewMatrix, fColor,
                                                                *args.fCaps->shaderCaps());
        auto* bboxPipeline = GrTessellationShader::MakePipeline(args, fAAType,
                                                                std::move(appliedClip),
                                                                std::move(fProcessors));
        auto* bboxStencil =
                GrPathTessellationShader::TestAndResetStencilSettings(fPath.isInverseFillType());
        fCoverBBoxProgram = GrSimpleMeshDrawOpHelper::CreateProgramInfo(
                args.fArena,
                bboxPipeline,
                args.fWriteView,
                bboxShader,
                GrPrimitiveType::kTriangleStrip,
                args.fXferBarrierFlags,
                args.fColorLoadOp,
                bboxStencil);
    }
}

void GrPathStencilCoverOp::onPrePrepare(GrRecordingContext* context,
                                        const GrSurfaceProxyView& writeView, GrAppliedClip* clip,
{'fraction_non_alphanumeric': 0.0845252843788715, 'fraction_numerical': 0.005800202725532154, 'mean_word_length': 2.18775803266918, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 44, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 71, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5001626', 'n_tokens_mistral': 4952, 'n_tokens_neox': 4740, 'n_words': 943}