// Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
//
// NVIDIA CORPORATION and its licensors retain all intellectual property
// and proprietary rights in and to this software, related documentation
// and any modifications thereto.  Any use, reproduction, disclosure or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA CORPORATION is strictly prohibited.
//
#include <omni/graph/core/GpuArray.h>

#include <OgnTutorialCudaDataDatabase.h>

// This function exercises referencing simple data types on the GPU, something you normally wouldn't do as
// there is no efficiency gain in doing that versus just passing in the CPU value.
extern "C" void applyAddGPU(outputs::sum_t sum, inputs::a_t a, inputs::b_t b);

// This function exercises referencing of array data on the GPU.
// The CUDA code takes its own "float3" data types, which are castable equivalents to the generated GfVec3f.
// The GpuArray/ConstGpuArray wrappers isolate the GPU pointers from the CPU code.
extern "C" void applyDeformationGPU(outputs::points_t outputPoints,
                                    inputs::points_t inputPoints,
                                    inputs::multiplier_t multiplier,
                                    size_t numberOfPoints);

// This function exercises referencing non-standard data types on the GPU to illustrate how data of different
// types are passed to the GPU.
extern "C" void applyDataTypes(outputs::half_t halfOutput,
                               outputs::color_t colorOutput,
                               outputs::matrix_t matrixOutput,
                               inputs::half_t halfInput,
                               inputs::color_t colorInput,
                               inputs::matrix_t matrixInput);

// This node runs a couple of algorithms on the GPU, while accessing parameters from the CPU
class OgnTutorialCudaData
{
public:
    static bool compute(OgnTutorialCudaDataDatabase& db)
    {
        // ================ algorithm 1 =========================================================
        // It's an important distinction here that GPU data is always returned as raw pointers since the CPU code
        // in the node cannot directly access it. The raw pointers are passed into the GPU code for dereferencing.
        applyAddGPU(db.outputs.sum(), db.inputs.a(), db.inputs.b());

        // ================ algorithm 2 =========================================================
        size_t numberOfPoints = db.inputs.points.size();
        db.outputs.points.resize(numberOfPoints);
        const auto& multiplier = db.inputs.multiplier();
        if (numberOfPoints > 0)
        {
            applyDeformationGPU(db.outputs.points(), db.inputs.points(), db.inputs.multiplier(), numberOfPoints);
        }

        // ================ algorithm 3 =========================================================
        applyDataTypes(db.outputs.half(), db.outputs.color(), db.outputs.matrix(),
                       db.inputs.half(), db.inputs.color(), db.inputs.matrix());
        return true;
    }
};

REGISTER_OGN_NODE()
