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

/**************************************************************************************************
 *** This file was autogenerated from GrRectBlurEffect.fp; do not modify.
 **************************************************************************************************/
#include "GrRectBlurEffect.h"

#include "include/gpu/GrTexture.h"
#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
#include "src/sksl/SkSLCPP.h"
#include "src/sksl/SkSLUtil.h"
class GrGLSLRectBlurEffect : public GrGLSLFragmentProcessor {
public:
    GrGLSLRectBlurEffect() {}
    void emitCode(EmitArgs& args) override {
        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
        const GrRectBlurEffect& _outer = args.fFp.cast<GrRectBlurEffect>();
        (void)_outer;
        auto rect = _outer.rect;
        (void)rect;
        auto sigma = _outer.sigma;
        (void)sigma;
        highp = ((abs(rect.left()) > 16000.0 || abs(rect.top()) > 16000.0) ||
                 abs(rect.right()) > 16000.0) ||
                abs(rect.bottom()) > 16000.0;
        if (highp) {
            rectFVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kFloat4_GrSLType,
                                                        "rectF");
        }
        if (!highp) {
            rectHVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4_GrSLType,
                                                        "rectH");
        }
        sigmaVar =
                args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType, "sigma");
        fragBuilder->codeAppendf(
                "/* key */ bool highp = %s;\nhalf x;\n@if (highp) {\n    x = "
                "min(half(sk_FragCoord.x - %s.x), half(%s.z - sk_FragCoord.x));\n} else {\n    x = "
                "min(half(sk_FragCoord.x - float(%s.x)), half(float(%s.z) - "
                "sk_FragCoord.x));\n}\nhalf y;\n@if (highp) {\n    y = min(half(sk_FragCoord.y - "
                "%s.y), half(%s.w - sk_FragCoord.y));\n} else {\n    y = min(half(sk_FragCoord.y - "
                "float(%s.y)), half(float(%s.w) - sk_FragCoord.y));\n}\nhalf r = 1.0 / (2.0 * "
                "%s);\nx *= r;\ny *= r;\nx = clamp(x, -1.5, 1.5);\ny = clamp(y, -1.5, 1.5",
                (highp ? "true" : "false"),
                rectFVar.isValid() ? args.fUniformHandler->getUniformCStr(rectFVar) : "float4(0)",
                rectFVar.isValid() ? args.fUniformHandler->getUniformCStr(rectFVar) : "float4(0)",
                rectHVar.isValid() ? args.fUniformHandler->getUniformCStr(rectHVar) : "half4(0)",
                rectHVar.isValid() ? args.fUniformHandler->getUniformCStr(rectHVar) : "half4(0)",
                rectFVar.isValid() ? args.fUniformHandler->getUniformCStr(rectFVar) : "float4(0)",
                rectFVar.isValid() ? args.fUniformHandler->getUniformCStr(rectFVar) : "float4(0)",
                rectHVar.isValid() ? args.fUniformHandler->getUniformCStr(rectHVar) : "half4(0)",
                rectHVar.isValid() ? args.fUniformHandler->getUniformCStr(rectHVar) : "half4(0)",
                args.fUniformHandler->getUniformCStr(sigmaVar));
        fragBuilder->codeAppendf(
                ");\nhalf x2 = x * x;\nhalf x3 = x2 * x;\nhalf x5 = x2 * x3;\n\n\n\n\nhalf "
                "xCoverage = ((0.73482197523117065 * x + -0.31337600946426392 * x3) + "
                "0.060916900634765625 * x5) + 0.5;\nhalf y2 = y * y;\nhalf y3 = y2 * y;\nhalf y5 = "
                "y2 * y3;\nhalf yCoverage = ((0.73482197523117065 * y + -0.31337600946426392 * y3) "
                "+ 0.060916900634765625 * y5) + 0.5;\n%s = (%s * xCoverage) * yCoverage;\n",
                args.fOutputColor, args.fInputColor);
    }

private:
    void onSetData(const GrGLSLProgramDataManager& pdman,
                   const GrFragmentProcessor& _proc) override {
        const GrRectBlurEffect& _outer = _proc.cast<GrRectBlurEffect>();
        { pdman.set1f(sigmaVar, (_outer.sigma)); }
        auto rect = _outer.rect;
        (void)rect;
        UniformHandle& rectF = rectFVar;
        (void)rectF;
        UniformHandle& rectH = rectHVar;
        (void)rectH;
        UniformHandle& sigma = sigmaVar;
        (void)sigma;

        float r[]{rect.fLeft, rect.fTop, rect.fRight, rect.fBottom};
        pdman.set4fv(highp ? rectF : rectH, 1, r);
    }
    bool highp = false;
    UniformHandle rectFVar;
    UniformHandle rectHVar;
    UniformHandle sigmaVar;
};
GrGLSLFragmentProcessor* GrRectBlurEffect::onCreateGLSLInstance() const {
    return new GrGLSLRectBlurEffect();
}
void GrRectBlurEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
                                             GrProcessorKeyBuilder* b) const {
    bool highp = ((abs(rect.left()) > 16000.0 || abs(rect.top()) > 16000.0) ||
                  abs(rect.right()) > 16000.0) ||
                 abs(rect.bottom()) > 16000.0;
    b->add32((int32_t)highp);
}
bool GrRectBlurEffect::onIsEqual(const GrFragmentProcessor& other) const {
    const GrRectBlurEffect& that = other.cast<GrRectBlurEffect>();
    (void)that;
    if (rect != that.rect) return false;
    if (sigma != that.sigma) return false;
    return true;
}
GrRectBlurEffect::GrRectBlurEffect(const GrRectBlurEffect& src)
        : INHERITED(kGrRectBlurEffect_ClassID, src.optimizationFlags())
        , rect(src.rect)
        , sigma(src.sigma) {}
std::unique_ptr<GrFragmentProcessor> GrRectBlurEffect::clone() const {
    return std::unique_ptr<GrFragmentProcessor>(new GrRectBlurEffect(*this));
}
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRectBlurEffect);
#if GR_TEST_UTILS
std::unique_ptr<GrFragmentProcessor> GrRectBlurEffect::TestCreate(GrProcessorTestData* data) {
    float sigma = data->fRandom->nextRangeF(3, 8);
    float width = data->fRandom->nextRangeF(200, 300);
    float height = data->fRandom->nextRangeF(200, 300);
    return GrRectBlurEffect::Make(data->proxyProvider(), *data->caps()->shaderCaps(),
                                  SkRect::MakeWH(width, height), sigma);
}
#endif
