/*
 * Copyright 2020 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/ops/AtlasInstancedHelper.h"

#include "src/gpu/BufferWriter.h"
#include "src/gpu/KeyBuilder.h"
#include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
#include "src/gpu/ganesh/glsl/GrGLSLVarying.h"
#include "src/gpu/ganesh/glsl/GrGLSLVertexGeoBuilder.h"

using namespace skia_private;

namespace skgpu::ganesh {

void AtlasInstancedHelper::getKeyBits(KeyBuilder* b) const {
    b->addBits(kNumShaderFlags, (int)fShaderFlags, "atlasFlags");
}

void AtlasInstancedHelper::appendInstanceAttribs(
        TArray<GrGeometryProcessor::Attribute>* instanceAttribs) const {
    instanceAttribs->emplace_back("locations", kFloat4_GrVertexAttribType, SkSLType::kFloat4);
    if (fShaderFlags & ShaderFlags::kCheckBounds) {
        instanceAttribs->emplace_back("sizeInAtlas", kFloat2_GrVertexAttribType, SkSLType::kFloat2);
    }
}

void AtlasInstancedHelper::writeInstanceData(VertexWriter* instanceWriter,
                                             const Instance* i) const {
    SkASSERT(i->fLocationInAtlas.x() >= 0);
    SkASSERT(i->fLocationInAtlas.y() >= 0);
    *instanceWriter <<
            // A negative x coordinate in the atlas indicates that the path is transposed.
            // Also add 1 since we can't negate zero.
            ((float)(i->fTransposedInAtlas ? -i->fLocationInAtlas.x() - 1
                     : i->fLocationInAtlas.x() + 1)) <<
            (float)i->fLocationInAtlas.y() <<
            (float)i->fPathDevIBounds.left() <<
            (float)i->fPathDevIBounds.top() <<
            VertexWriter::If(fShaderFlags & ShaderFlags::kCheckBounds,
                             SkSize::Make(i->fPathDevIBounds.size()));
}

void AtlasInstancedHelper::injectShaderCode(
        const GrGeometryProcessor::ProgramImpl::EmitArgs& args,
        const GrShaderVar& devCoord,
        GrGLSLUniformHandler::UniformHandle* atlasAdjustUniformHandle) const {
    GrGLSLVarying atlasCoord(SkSLType::kFloat2);
    args.fVaryingHandler->addVarying("atlasCoord", &atlasCoord);

    const char* atlasAdjustName;
    *atlasAdjustUniformHandle = args.fUniformHandler->addUniform(
            nullptr, kVertex_GrShaderFlag, SkSLType::kFloat2, "atlas_adjust", &atlasAdjustName);

    args.fVertBuilder->codeAppendf(
    // A negative x coordinate in the atlas indicates that the path is transposed.
    // We also added 1 since we can't negate zero.
    "float2 atlasTopLeft = float2(abs(locations.x) - 1, locations.y);"
    "float2 devTopLeft = locations.zw;"
    "bool transposed = locations.x < 0;"
    "float2 atlasCoord = %s - devTopLeft;"
    "if (transposed) {"
        "atlasCoord = atlasCoord.yx;"
    "}"
    "atlasCoord += atlasTopLeft;"
    "%s = atlasCoord * %s;", devCoord.c_str(), atlasCoord.vsOut(), atlasAdjustName);

    if (fShaderFlags & ShaderFlags::kCheckBounds) {
        GrGLSLVarying atlasBounds(SkSLType::kFloat4);
        args.fVaryingHandler->addVarying("atlasbounds", &atlasBounds,
                                         GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
        args.fVertBuilder->codeAppendf(R"(
        float4 atlasBounds = atlasTopLeft.xyxy + (transposed ? sizeInAtlas.00yx
                                                             : sizeInAtlas.00xy);
        %s = atlasBounds * %s.xyxy;)", atlasBounds.vsOut(), atlasAdjustName);

        args.fFragBuilder->codeAppendf(
        "half atlasCoverage = 0;"
        "float2 atlasCoord = %s;"
        "float4 atlasBounds = %s;"
        "if (all(greaterThan(atlasCoord, atlasBounds.xy)) &&"
            "all(lessThan(atlasCoord, atlasBounds.zw))) {"
            "atlasCoverage = ", atlasCoord.fsIn(), atlasBounds.fsIn());
        args.fFragBuilder->appendTextureLookup(args.fTexSamplers[0], "atlasCoord");
        args.fFragBuilder->codeAppendf(R"(.a;
        })");
    } else {
        args.fFragBuilder->codeAppendf("half atlasCoverage = ");
        args.fFragBuilder->appendTextureLookup(args.fTexSamplers[0], atlasCoord.fsIn());
        args.fFragBuilder->codeAppendf(".a;");
    }

    if (fShaderFlags & ShaderFlags::kInvertCoverage) {
        args.fFragBuilder->codeAppendf("%s *= (1 - atlasCoverage);", args.fOutputCoverage);
    } else {
        args.fFragBuilder->codeAppendf("%s *= atlasCoverage;", args.fOutputCoverage);
    }
}

void AtlasInstancedHelper::setUniformData(
        const GrGLSLProgramDataManager& pdman,
        const GrGLSLUniformHandler::UniformHandle& atlasAdjustUniformHandle) const {
    SkASSERT(fAtlasProxy->isInstantiated());
    SkISize dimensions = fAtlasProxy->backingStoreDimensions();
    pdman.set2f(atlasAdjustUniformHandle, 1.f / dimensions.width(), 1.f / dimensions.height());
}

}  // namespace skgpu::ganesh
