/*
 * 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 "include/core/SkTypes.h"
#include "include/private/SkSLLayout.h"
#include "include/private/SkSLModifiers.h"
#include "include/private/SkSLProgramElement.h"
#include "include/private/SkSLStatement.h"
#include "include/private/SkTHash.h"
#include "src/sksl/SkSLBuiltinMap.h"
#include "src/sksl/SkSLBuiltinTypes.h"
#include "src/sksl/SkSLCompiler.h"
#include "src/sksl/SkSLContext.h"
#include "src/sksl/SkSLProgramSettings.h"
#include "src/sksl/SkSLUtil.h"
#include "src/sksl/analysis/SkSLProgramUsage.h"
#include "src/sksl/analysis/SkSLProgramVisitor.h"
#include "src/sksl/ir/SkSLFunctionDeclaration.h"
#include "src/sksl/ir/SkSLFunctionDefinition.h"
#include "src/sksl/ir/SkSLInterfaceBlock.h"
#include "src/sksl/ir/SkSLProgram.h"
#include "src/sksl/ir/SkSLType.h"
#include "src/sksl/ir/SkSLVarDeclarations.h"
#include "src/sksl/ir/SkSLVariable.h"
#include "src/sksl/transform/SkSLTransform.h"

#include <algorithm>
#include <memory>
#include <string>
#include <string_view>
#include <vector>

namespace SkSL {
namespace Transform {
namespace {

class BuiltinVariableScanner : public ProgramVisitor {
public:
    BuiltinVariableScanner(const Context& context) : fContext(context) {}

    void addDeclaringElement(const std::string& name) {
        // If this is the *first* time we've seen this builtin, findAndInclude will return the
        // corresponding ProgramElement.
        BuiltinMap& builtins = *fContext.fBuiltins;
        if (const ProgramElement* decl = builtins.findAndInclude(name)) {
            SkASSERT(decl->is<GlobalVarDeclaration>() || decl->is<InterfaceBlock>());
            fNewElements.push_back(decl);
        }
    }

    bool visitProgramElement(const ProgramElement& pe) override {
        if (pe.is<FunctionDefinition>()) {
            const FunctionDefinition& funcDef = pe.as<FunctionDefinition>();
            // We synthesize writes to sk_FragColor if main() returns a color, even if it's
            // otherwise unreferenced. Check main's return type to see if it's half4.
            if (funcDef.declaration().isMain()) {
                if (funcDef.declaration().returnType().matches(*fContext.fTypes.fHalf4)) {
                    // main() returns a half4, so make sure we don't dead-strip sk_FragColor.
                    this->addDeclaringElement(Compiler::FRAGCOLOR_NAME);
                }
                // Once we find main(), we can stop scanning.
                return true;
            }
        }
        return false;
    }

    static std::string_view GlobalVarBuiltinName(const ProgramElement& elem) {
        return elem.as<GlobalVarDeclaration>().declaration()->as<VarDeclaration>().var().name();
    }

    static std::string_view InterfaceBlockName(const ProgramElement& elem) {
        return elem.as<InterfaceBlock>().instanceName();
    }

    void sortNewElements() {
        std::sort(fNewElements.begin(),
                  fNewElements.end(),
                  [](const ProgramElement* a, const ProgramElement* b) {
                      if (a->kind() != b->kind()) {
                          return a->kind() < b->kind();
                      }
                      switch (a->kind()) {
                          case ProgramElement::Kind::kGlobalVar:
                              SkASSERT(GlobalVarBuiltinName(*a) != GlobalVarBuiltinName(*b));
                              return GlobalVarBuiltinName(*a) < GlobalVarBuiltinName(*b);

                          case ProgramElement::Kind::kInterfaceBlock:
                              SkASSERT(InterfaceBlockName(*a) != InterfaceBlockName(*b));
                              return InterfaceBlockName(*a) < InterfaceBlockName(*b);

                          default:
                              SkUNREACHABLE;
                      }
                  });
    }

    const Context& fContext;
    std::vector<const ProgramElement*> fNewElements;
};

}  // namespace

void FindAndDeclareBuiltinVariables(Program& program) {
    const Context& context = *program.fContext;
    BuiltinVariableScanner scanner(context);

    // Find main() in the program and check its return type.
    for (auto& e : program.fOwnedElements) {
        scanner.visitProgramElement(*e);
    }

    if (ProgramConfig::IsFragment(program.fConfig->fKind)) {
        // Vulkan requires certain builtin variables be present, even if they're unused. At one
        // time, validation errors would result if sk_Clockwise was missing. Now, it's just (Adreno)
        // driver bugs that drop or corrupt draws if they're missing.
        scanner.addDeclaringElement("sk_Clockwise");
    }

    // Scan all the variables used by the program and declare any built-ins.
    for (const auto& [var, counts] : program.fUsage->fVariableCounts) {
        if (var->isBuiltin()) {
            scanner.addDeclaringElement(std::string(var->name()));

            // Set the FlipRT program input if we find sk_FragCoord or sk_Clockwise.
            switch (var->modifiers().fLayout.fBuiltin) {
                case SK_FRAGCOORD_BUILTIN:
                    if (context.fCaps.fCanUseFragCoord) {
                        program.fInputs.fUseFlipRTUniform =
                                !context.fConfig->fSettings.fForceNoRTFlip;
                    }
                    break;

                case SK_CLOCKWISE_BUILTIN:
                    program.fInputs.fUseFlipRTUniform = !context.fConfig->fSettings.fForceNoRTFlip;
                    break;
            }
        }
    }

    // Sort the referenced builtin functions into a consistent order; otherwise our output will
    // become non-deterministic. The exact order isn't particularly important.
    scanner.sortNewElements();

    // Add all the newly-declared elements to the program, and update ProgramUsage to match.
    program.fSharedElements.insert(program.fSharedElements.begin(),
                                   scanner.fNewElements.begin(),
                                   scanner.fNewElements.end());

    for (const ProgramElement* element : scanner.fNewElements) {
        program.fUsage->add(*element);
    }
}

}  // namespace Transform
}  // namespace SkSL
