////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2017-2020, 2024 Qualcomm Technologies, Inc.
// All Rights Reserved.
// Confidential and Proprietary - Qualcomm Technologies, Inc.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @file  chitintlessinterface.h
///
/// @brief Qualcomm Technologies, Inc. Tintless Algorithm Interface
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef CHITINTLESSINTERFACE_H
#define CHITINTLESSINTERFACE_H

#include <string.h>
#include "camxcdktypes.h"

#include "chiispstatsdefs.h"

#ifdef __cplusplus

extern "C"
{
#endif // __cplusplus

/// @brief Data structures that are exposed to OEM must be packed to have the expected layout.
#pragma pack(push, CDK_PACK_SIZE)

/// @brief Number of Tintless threshold entries
#define TINTLESS_THRESHOLD_ENTRIES 16
#define MAX_STATS_NUM              3072 ///< Maximum nuber of stats entries 64 x 48, but tintless algo support only 32 x 24
#define ROLLOFF_SIZE               221  ///< 17 x 13 entries per mesh table

// This is used by the new ALSC algo for output.
#define ALSC_MESH_PT_H             17
#define ALSC_MESH_PT_V             13
#define ALSC_BUFFER_LIST_SIZE      16

// @brief Constants for TMC fusion
#define TMC_EXP_COUNT               3
#define TMC_BHIST_LENGTH            1024

static const CHAR* pTintlessLibName  = "libcamxtintlessalgo";
static const CHAR* pTintlessFuncName = "CreateTintless";
static const CHAR* pAlscFuncName     = "CreateALSC";
static const CHAR* pTMCFuncName      = "CreateTMC";

/// @brief Represents stats configuration parameters passed to ITintlessAlgorithm::Configure()
struct StatsConfigParams
{
    UINT32            camifWidth;                     ///< Input image width
    UINT32            camifHeight;                    ///< Input image Height
    UINT32            statsRegionWidth;               ///< Region width of stats
    UINT32            statsRegionHeight;              ///< Region height of stats
    UINT32            statsNumberOfHorizontalRegions; ///< Total number of horizontal regions
    UINT32            statsNumberOfVerticalRegions;   ///< Total number of vertical regions
    UINT32            postBayer;                      ///< HRDBE/TintlessBG postBayer = 0/ AWBBG postBayer = 1
    UINT32            saturationLimit[ChannelIndexCount];                ///< Saturation limit for stats
    UINT32            statsBitDepth;                  ///< Bit depth of stats
};

/// @brief Represents LSC configuration parameters
struct LSCConfigParams
{
    UINT32 LSCTableWidth;              ///< Mesh rolloff table width
    UINT32 LSCTableHeight;             ///< Mesh rolloff table height
    UINT32 LSCSubgridWidth;            ///< Mesh rolloff subgrid width
    UINT32 LSCSubgridHeight;           ///< Mesh rolloff subgrid height
    UINT32 numberOfLSCSubgrids;        ///< Number of mesh rolloff sub grids
    UINT32 LSCSubgridHorizontalOffset; ///< Sub grid horizontal offset
    UINT32 LSCSubgridVerticalOffset;   ///< Sub grid vertical offset
};

/// @brief Represents Tintless configuration parameters
struct TintlessConfigParams
{
    UINT8 tintlessCorrectionStrength;                    ///< Tintless Algorithm Correction strength
    UINT8 tintlessThreshold[TINTLESS_THRESHOLD_ENTRIES]; ///< Tintless Threshold
    UINT8 tintAcuuracy;                                  ///< Tint correction accuracy
    UINT8 updateDelay;                                   ///< Tintless update Delay
    FLOAT tracePercentage;                               ///< Tintless trace percentage
    FLOAT centerWeight;                                  ///< Tintless correction center weight
    FLOAT cornerWeight;                                  ///< Tintless correction corner weight
    UINT8 applyTemporalFiltering;                        ///< 1 - apply Temporal Filtering 0 - dont apply
};

/// @brief Tintless Mesh rolloff Table
struct TintlessRolloffTable
{
    UINT16 TintlessRoloffTableSize; ///< Tintless Rolloff table size
    FLOAT* RGain;                   ///< R Channel gains for Tintless table
    FLOAT* GRGain;                  ///< Gr Channel gains for Tintless table
    FLOAT* GBGain;                  ///< Gb Channel gains for Tintless table
    FLOAT* BGain;                   ///< B Channel gains for Tintless table
};

/// @brief Tintless Config
struct TintlessConfig
{
    LSCConfigParams      rolloffConfig;
    StatsConfigParams    statsConfig;
    TintlessConfigParams tintlessParamConfig;
};

struct ALSCHelperParam {        //parameters to be tuned
    BOOL    ALSC_enable;
    UINT32  threshold_highlight;
    UINT32  threshold_lowlight;
    UINT32  c_r;
    UINT32  c_g;
    UINT32  c_b;
    UINT32  c_max;
    UINT32  adaptive_gain_low;
    UINT32  adaptive_gain_high;
    UINT32  lowlight_gain_strength;
    UINT32  highlight_gain_strength;
    UINT32* ALSCbufferList[ALSC_BUFFER_LIST_SIZE];
};

struct ALSCHelperOutput {       //output stats
    float nGrid_gain[ALSC_MESH_PT_V * ALSC_MESH_PT_H];   //keep floating point
    float nGrid_mean[ALSC_MESH_PT_V * ALSC_MESH_PT_H];
};

struct AWBStatsSizeInput {   //AWB stats size info
    UINT16 nBG_Grid_H;
    UINT16 nBG_Grid_V;
};

/// @brief The exposure indice used in TMC algorithm for histogram fusion
enum ExposureModes
{
    LONG_EXP = 0,   // LONG EXPOSURE    0
    MID_EXP,        // MID EXPOSURE     1
    SHORT_EXP       // SHORT EXPOSURE   2
};

typedef unsigned int Word32u;
struct StatsBGBEUnpackedData_HDR {
    Word32u     length;
    Word32u     *r_sum;
    Word32u     *b_sum;
    Word32u     *g_or_gr_sum;
    Word32u     *y_or_gb_sum;

    Word32u     *r_cnt;
    Word32u     *b_cnt;
    Word32u     *g_or_gr_cnt;
    Word32u     *y_or_gb_cnt;

    Word32u     *sat_r_sum;
    Word32u     *sat_b_sum;
    Word32u     *sat_g_or_gr_sum;
    Word32u     *sat_y_or_gb_sum;

    Word32u     *sat_r_cnt;
    Word32u     *sat_b_cnt;
    Word32u     *sat_g_or_gr_cnt;
    Word32u     *sat_y_or_gb_cnt;
    void uninitialize() {
        auto safe_free = [](Word32u *&ptr) {
            if (ptr) {
                delete[] ptr;
                ptr = nullptr;
            }
        };
        safe_free(r_sum);
        safe_free(b_sum);
        safe_free(g_or_gr_sum);
        safe_free(y_or_gb_sum);

        safe_free(r_cnt);
        safe_free(b_cnt);
        safe_free(g_or_gr_cnt);
        safe_free(y_or_gb_cnt);

        safe_free(sat_r_sum);
        safe_free(sat_b_sum);
        safe_free(sat_g_or_gr_sum);
        safe_free(sat_y_or_gb_sum);

        safe_free(sat_r_cnt);
        safe_free(sat_b_cnt);
        safe_free(sat_g_or_gr_cnt);
        safe_free(sat_y_or_gb_cnt);
    }
    int initialize(Word32u len) {
        int ret = 0;

        length = len;
        r_sum = new Word32u[len];
        b_sum = new Word32u[len];
        g_or_gr_sum = new Word32u[len];
        y_or_gb_sum = new Word32u[len];

        r_cnt = new Word32u[len];
        b_cnt = new Word32u[len];
        g_or_gr_cnt = new Word32u[len];
        y_or_gb_cnt = new Word32u[len];

        sat_r_sum = new Word32u[len];
        sat_b_sum = new Word32u[len];
        sat_g_or_gr_sum = new Word32u[len];
        sat_y_or_gb_sum = new Word32u[len];

        sat_r_cnt = new Word32u[len];
        sat_b_cnt = new Word32u[len];
        sat_g_or_gr_cnt = new Word32u[len];
        sat_y_or_gb_cnt = new Word32u[len];

        ret = ((NULL == r_sum) ||
                (NULL == b_sum) ||
                (NULL == g_or_gr_sum) ||
                (NULL == y_or_gb_sum) ||
                (NULL == r_cnt) ||
                (NULL == b_cnt) ||
                (NULL == g_or_gr_cnt) ||
                (NULL == y_or_gb_cnt) ||
                (NULL == sat_r_sum) ||
                (NULL == sat_b_sum) ||
                (NULL == sat_g_or_gr_sum) ||
                (NULL == sat_y_or_gb_sum) ||
                (NULL == sat_r_cnt) ||
                (NULL == sat_b_cnt) ||
                (NULL == sat_g_or_gr_cnt) ||
                (NULL == sat_y_or_gb_cnt))  ? -1 : 0;

        if (0 == ret)
        {
            memset(r_sum, 0, sizeof(Word32u)*len);
            memset(b_sum, 0, sizeof(Word32u)*len);
            memset(g_or_gr_sum, 0, sizeof(Word32u)*len);
            memset(y_or_gb_sum, 0, sizeof(Word32u)*len);

            memset(r_cnt, 0, sizeof(Word32u)*len);
            memset(b_cnt, 0, sizeof(Word32u)*len);
            memset(g_or_gr_cnt, 0, sizeof(Word32u)*len);
            memset(y_or_gb_cnt, 0, sizeof(Word32u)*len);

            memset(sat_r_sum, 0, sizeof(Word32u)*len);
            memset(sat_b_sum, 0, sizeof(Word32u)*len);
            memset(sat_g_or_gr_sum, 0, sizeof(Word32u)*len);
            memset(sat_y_or_gb_sum, 0, sizeof(Word32u)*len);

            memset(sat_r_cnt, 0, sizeof(Word32u)*len);
            memset(sat_b_cnt, 0, sizeof(Word32u)*len);
            memset(sat_g_or_gr_cnt, 0, sizeof(Word32u)*len);
            memset(sat_y_or_gb_cnt, 0, sizeof(Word32u)*len);
        }
        return ret;
    }
    StatsBGBEUnpackedData_HDR() {
        length = 0;
        r_sum = nullptr;
        b_sum = nullptr;
        g_or_gr_sum = nullptr;
        y_or_gb_sum = nullptr;

        r_cnt = nullptr;
        b_cnt = nullptr;
        g_or_gr_cnt = nullptr;
        y_or_gb_cnt = nullptr;

        sat_r_sum = nullptr;
        sat_b_sum = nullptr;
        sat_g_or_gr_sum = nullptr;
        sat_y_or_gb_sum = nullptr;

        sat_r_cnt = nullptr;
        sat_b_cnt = nullptr;
        sat_g_or_gr_cnt = nullptr;
        sat_y_or_gb_cnt = nullptr;
    }
    StatsBGBEUnpackedData_HDR& operator =(StatsBGBEUnpackedData_HDR& obj)
    {

        Word32u len = obj.length;
        int ret = initialize(len);
        if (0 == ret)
        {
        memcpy(r_sum, obj.r_sum, sizeof(Word32u)*len);
        memcpy(b_sum, obj.b_sum, sizeof(Word32u)*len);
        memcpy(g_or_gr_sum, obj.g_or_gr_sum, sizeof(Word32u)*len);
        memcpy(y_or_gb_sum, obj.y_or_gb_sum, sizeof(Word32u)*len);

        memcpy(r_cnt, obj.r_cnt, sizeof(Word32u)*len);
        memcpy(b_cnt, obj.b_cnt, sizeof(Word32u)*len);
        memcpy(g_or_gr_cnt, obj.g_or_gr_cnt, sizeof(Word32u)*len);
        memcpy(y_or_gb_cnt, obj.y_or_gb_cnt, sizeof(Word32u)*len);

        memcpy(sat_r_sum, obj.sat_r_sum, sizeof(Word32u)*len);
        memcpy(sat_b_sum, obj.sat_b_sum, sizeof(Word32u)*len);
        memcpy(sat_g_or_gr_sum, obj.sat_g_or_gr_sum, sizeof(Word32u)*len);
        memcpy(sat_y_or_gb_sum, obj.sat_y_or_gb_sum, sizeof(Word32u)*len);

        memcpy(sat_r_cnt, obj.sat_r_cnt, sizeof(Word32u)*len);
        memcpy(sat_b_cnt, obj.sat_b_cnt, sizeof(Word32u)*len);
        memcpy(sat_g_or_gr_cnt, obj.sat_g_or_gr_cnt, sizeof(Word32u)*len);
        memcpy(sat_y_or_gb_cnt, obj.sat_y_or_gb_cnt, sizeof(Word32u)*len);
        }
        return *this;
    }

    ~StatsBGBEUnpackedData_HDR() {
        uninitialize();
    }
};

/// @brief The parameters for TMC algorithm fusing histograms (parameters to be tuned).
struct TMCHelperParam {
    FLOAT   mid2short_ratio;                                ///< The ratio of mid and short exposures
    FLOAT   long2mid_ratio;                                 ///< The ratio of long and mid exposures
    FLOAT   long2short_ratio;                               ///< The ratio of long and short exposures
    UINT32  hist_tmc13[TMC_EXP_COUNT][TMC_BHIST_LENGTH];    ///< The histograms to be fused into one histogram
    UINT32  out_hist_fuse[TMC_BHIST_LENGTH];                ///< The result of fused histogram to be stored
    INT     exp_count;                                      ///< The number of exposure to be fused (2 or 3 exposures)

    FLOAT   stats_fusion_long_range;                        ///< The range for long histogram stats fusion
    FLOAT   stats_fusion_medium_range;                      ///< The range for medium histogram stats fusion
    FLOAT   stats_fusion_short_range;                       ///< The range for short histogram stats fusion

    FLOAT   stats_fusion_long_str;                          ///< The strengh for long histogram stats fusion
    FLOAT   stats_fusion_medium_str;                        ///< The strengh for medium histogram stats fusion

    FLOAT   BGMidStatsSatRatio;                             ///< Sat ratio from AWB BG stats
    FLOAT   BGMidStatsDarkRatio;                            ///< Dark ratio from AWB BS stats

    StatsBGBEUnpackedData_HDR * pAWBBGMidStats;             ///< BG stats unpacked data
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Interface for Tintless algorithm.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef struct
{

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// TintlessAlgorithmProcess
    ///
    /// @brief  Process the Input Table and generate the Output table
    ///
    /// @param  pChiTintlessAlgo  Pointer to the CHI tintless interface
    /// @param  pTintlessConfig   Pointer to Tintless Algo Config.
    /// @param  pTintlessStats    Pointer to the Tintless Stats data
    /// @param  PInputTable       Pointer to the Input Rolloff Table
    /// @param  POutputTable      Pointer to the Output Rolloff Table
    ///
    /// @return CDKResultSuccess upon success.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CDKResult(*TintlessAlgorithmProcess)(
        VOID*                              pChiTintlessAlgo,
        const TintlessConfig*              pTintlessConfig,
        const ParsedTintlessBGStatsOutput* pTintlessStats,
        TintlessRolloffTable*              pInputTable,
        TintlessRolloffTable*              pOutputTable);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// TintlessDestroy
    ///
    /// @brief  This method destroys the derived instance of the interface
    ///
    /// @param  pChiTintlessAlgo  Pointer to the CHI tintless interface
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID(*TintlessDestroy)(VOID* pChiTintlessAlgo);

    VOID* pTintlessAlgoResource; ///< Tintless Algorithm Resource
} CHITintlessAlgorithm;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// CreateTintless
///
/// @brief  This function pointer to method of creating a handle of CHITintlessAlgorithm.
///
/// @param  ppCHITintlessAlgorithm  Pointer to pointer of the created CHITintlessAlgorithm instance
///
/// @return CDKResultSuccess upon success.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef CDKResult(*CREATETINTLESS)(
    CHITintlessAlgorithm** ppCHITintlessAlgorithm);



////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Interface for ALSC algorithm.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef struct
{
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ALSCAlgorithmProcess
    ///
    /// @brief  Process the Input Table and generate the Output table
    ///
    /// @param  pChiALSCAlgo    Pointer to the CHI ALSC interface
    /// @param  pStatsAWB       Pointer to Parsed AWB stats
    /// @param  pAlscParam      Pointer to ALSC configuration
    /// @param  awbSize         AWB stats size input
    /// @param  pAlscOutput     Pointer to the ALSC Output
    ///
    /// @return CDKResultSuccess upon success.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CDKResult(*ALSCAlgorithmProcess)(
        VOID*                     pChiALSCAlgo,
        ParsedAWBBGStatsOutput*   pStatsAWB,
        ALSCHelperParam*          pAlscParam,
        AWBStatsSizeInput         awbSize,
        ALSCHelperOutput*         pAlscOutput
        );

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ALSCDestroy
    ///
    /// @brief  This method destroys the derived instance of the interface
    ///
    /// @param  pChiALSCAlgo  Pointer to the CHI ALSC interface
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID(*ALSCDestroy)(VOID* pChiALSCAlgo);

    VOID* pALSCAlgoResource; ///< ALSC Algorithm Resource
} CHIALSCAlgorithm;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// CreateALSC
///
/// @brief  This function pointer to method of creating a handle of CHIALSCAlgorithm.
///
/// @param  ppCHIALSCAlgorithm  Pointer to pointer of the created CHIALSCAlgorithm instance
///
/// @return CDKResultSuccess upon success.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef CDKResult(*CREATEALSC)(
    CHIALSCAlgorithm** ppCHIALSCAlgorithm);


CamxResult ALSCHelper(
    ParsedAWBBGStatsOutput* pStatsAWB,
    const ALSCHelperParam*  pAlscParam,
    const AWBStatsSizeInput awbSize,
    ALSCHelperOutput*       pAlscOutput);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Interface for TMC algorithm.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef struct
{
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// TMCAlgorithmProcess
    ///
    /// @brief  Process the Input Table and generate the Output table
    ///
    /// @param  pChiTMCAlgo  Pointer to the CHI TMC interface
    /// @param  tmcHelperparam    Pointer to the TMC Stats data
    ///
    /// @return CDKResultSuccess upon success.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CDKResult(*TMCAlgorithmProcess)(
        VOID*               pChiTMCAlgo,
        TMCHelperParam*     pTMCParam);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// TMCDestroy
    ///
    /// @brief  This method destroys the derived instance of the interface
    ///
    /// @param  pChiTMCAlgo  Pointer to the CHI TMC interface
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID(*TMCDestroy)(VOID* pChiTMCAlgo);

    VOID* pTMCAlgoResource; ///< TMC Algorithm Resource
} CHITMCAlgorithm;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// CreateTMC
///
/// @brief  This function pointer to method of creating a handle of CHITMCAlgorithm.
///
/// @param  ppCHIALSCAlgorithm  Pointer to pointer of the created CHITMCAlgorithm instance
///
/// @return CDKResultSuccess upon success.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef CDKResult(*CREATETMC)(
    CHITMCAlgorithm** ppCHITMCAlgorithm);

CamxResult TMCHelper(
    TMCHelperParam *tmcParam);


#pragma pack(pop)

#ifdef __cplusplus
}
#endif // __cplusplus

#endif // CHITINTLESSINTERFACE_H
