/*
 * 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/ganesh/effects/GrModulateAtlasCoverageEffect.h"

#include "include/core/SkAlphaType.h"
#include "include/core/SkSamplingOptions.h"
#include "include/core/SkString.h"
#include "include/private/SkSLSampleUsage.h"
#include "include/private/gpu/ganesh/GrTypesPriv.h"
#include "src/core/SkSLTypeShared.h"
#include "src/gpu/KeyBuilder.h"
#include "src/gpu/ganesh/GrSamplerState.h"
#include "src/gpu/ganesh/GrSurfaceProxyView.h"
#include "src/gpu/ganesh/effects/GrTextureEffect.h"
#include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
#include "src/gpu/ganesh/glsl/GrGLSLProgramDataManager.h"
#include "src/gpu/ganesh/glsl/GrGLSLUniformHandler.h"

#include <utility>

class SkMatrix;
struct GrShaderCaps;

GrModulateAtlasCoverageEffect::GrModulateAtlasCoverageEffect(
        Flags flags,
        std::unique_ptr<GrFragmentProcessor> inputFP,
        GrSurfaceProxyView atlasView,
        const SkMatrix& devToAtlasMatrix,
        const SkIRect& devIBounds)
        : GrFragmentProcessor(kTessellate_GrModulateAtlasCoverageEffect_ClassID,
                              kCompatibleWithCoverageAsAlpha_OptimizationFlag)
        , fFlags(flags)
        , fBounds((fFlags & Flags::kCheckBounds) ? devIBounds : SkIRect{0,0,0,0}) {
    this->registerChild(std::move(inputFP));
    this->registerChild(GrTextureEffect::Make(std::move(atlasView), kUnknown_SkAlphaType,
                                              devToAtlasMatrix, GrSamplerState::Filter::kNearest),
                        SkSL::SampleUsage::Explicit());
}

GrModulateAtlasCoverageEffect::GrModulateAtlasCoverageEffect(
        const GrModulateAtlasCoverageEffect& that)
        : GrFragmentProcessor(that)
        , fFlags(that.fFlags)
        , fBounds(that.fBounds) {}

void GrModulateAtlasCoverageEffect::onAddToKey(const GrShaderCaps&,
                                               skgpu::KeyBuilder* b) const {
    b->add32(fFlags & Flags::kCheckBounds);
}

std::unique_ptr<GrFragmentProcessor::ProgramImpl>
GrModulateAtlasCoverageEffect::onMakeProgramImpl() const {
    class Impl : public ProgramImpl {
        void emitCode(EmitArgs& args) override {
            auto fp = args.fFp.cast<GrModulateAtlasCoverageEffect>();
            auto f = args.fFragBuilder;
            auto uniHandler = args.fUniformHandler;
            SkString inputColor = this->invokeChild(0, args);
            f->codeAppend("half coverage = 0;");
            if (fp.fFlags & Flags::kCheckBounds) {
                const char* boundsName;
                fBoundsUniform = uniHandler->addUniform(&fp, kFragment_GrShaderFlag,
                                                        SkSLType::kFloat4, "bounds", &boundsName);
                // Are we inside the path's valid atlas bounds?
                f->codeAppendf("if (all(greaterThan(sk_FragCoord.xy, %s.xy)) && "
                                   "all(lessThan(sk_FragCoord.xy, %s.zw))) ",
                               boundsName, boundsName);
            }
            f->codeAppendf("{");
            SkString atlasCoverage = this->invokeChild(1, args, "sk_FragCoord.xy");
            f->codeAppendf("coverage = %s.a;", atlasCoverage.c_str());
            f->codeAppendf("}");
            const char* coverageMaybeInvertName;
            fCoverageMaybeInvertUniform = uniHandler->addUniform(&fp, kFragment_GrShaderFlag,
                                                                 SkSLType::kHalf2, "coverageInvert",
                                                                 &coverageMaybeInvertName);
            // Invert coverage, if needed.
            f->codeAppendf("coverage = coverage * %s.x + %s.y;",
                           coverageMaybeInvertName, coverageMaybeInvertName);
            f->codeAppendf("return %s * coverage;", inputColor.c_str());
        }

    private:
        void onSetData(const GrGLSLProgramDataManager& pdman,
                       const GrFragmentProcessor& processor) override {
            auto fp = processor.cast<GrModulateAtlasCoverageEffect>();
            if (fp.fFlags & Flags::kCheckBounds) {
                pdman.set4fv(fBoundsUniform, 1, SkRect::Make(fp.fBounds).asScalars());
            }
            if (fp.fFlags & Flags::kInvertCoverage) {
                pdman.set2f(fCoverageMaybeInvertUniform, -1, 1);  // -1*coverage + 1 = 1 - coverage.
            } else {
                pdman.set2f(fCoverageMaybeInvertUniform, 1, 0);  // 1*coverage + 0 = coverage.
            }
        }
        UniformHandle fBoundsUniform;
        UniformHandle fCoverageMaybeInvertUniform;
    };

    return std::make_unique<Impl>();
}
