/*
* Copyright (c) 2020, Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
//!
//! \file     codechal_encode_sfc_base.h
//! \brief    Defines the encode interface for CSC via SFC.
//! \details  Downsampling in this case is supported by the SFC fixed function HW unit.
//!

#ifndef __CODECHAL_ENCODE_SFC_BASE_H__
#define __CODECHAL_ENCODE_SFC_BASE_H__

#include "codechal.h"
#include "codechal_hw.h"

#define CODECHAL_SFC_ALIGNMENT_16        16
#define CODECHAL_SFC_ALIGNMENT_8         8

#define CODECHAL_SFC_VEBOX_STATISTICS_SIZE                        (32 * 4)
#define CODECHAL_SFC_VEBOX_LACE_HISTOGRAM_256_BIN_PER_BLOCK       (256 * 2)
#define CODECHAL_SFC_VEBOX_ACE_HISTOGRAM_SIZE_PER_FRAME_PER_SLICE (256 * 4)
#define CODECHAL_SFC_NUM_FRAME_PREVIOUS_CURRENT                    2

#define CODECHAL_SFC_VEBOX_RGB_HISTOGRAM_SIZE_PER_SLICE           (256 * 4)
#define CODECHAL_SFC_NUM_RGB_CHANNEL                               3
#define CODECHAL_SFC_AVS_LINEBUFFER_SIZE_PER_VERTICAL_PIXEL       (5 * MHW_SFC_CACHELINE_SIZE)

typedef struct _CODECHAL_ENCODE_RECTANGLE
{
    uint32_t              X;
    uint32_t              Y;
    uint32_t              Width;
    uint32_t              Height;
} CODECHAL_ENCODE_RECTANGLE, *PCODECHAL_ENCODE_RECTANGLE;

//!
//! \struct    CODECHAL_ENCODE_SFC_PARAMS
//! \brief     Parameters needed for the processing of the encode render target
//!
struct CODECHAL_ENCODE_SFC_PARAMS
{
    CODECHAL_ENCODE_SFC_PARAMS()
    {
        MOS_ZeroMemory(this, sizeof(*this));
    }

    // Input
    PMOS_SURFACE                 pInputSurface;
    CODECHAL_ENCODE_RECTANGLE    rcInputSurfaceRegion;
    uint32_t                     uiChromaSitingType;

    // Output
    PMOS_SURFACE                 pOutputSurface;
    CODECHAL_ENCODE_RECTANGLE    rcOutputSurfaceRegion;
};

class CodecHalEncodeSfcBase
{
public:
    //!
    //! \brief    Constructor
    //!
    CodecHalEncodeSfcBase() {};

    //!
    //! \brief    Destructor
    //!
    virtual ~CodecHalEncodeSfcBase();

    void SetInputColorSpace(MHW_CSPACE colorSpace)
    {
        m_inputSurfaceColorSpace = colorSpace;
    }
    void SetOutputColorSpace(MHW_CSPACE colorSpace)
    {
        m_outputSurfaceColorSpace = colorSpace;
    }
    //!
    //! \brief    Initialize
    //!
    //! \param    [in] hwInterface
    //!           Codechal hardware interface
    //! \param    [in] osInterface
    //!           Pointer to MOS interface
    //!
    //! \return   MOS_STATUS
    //!           Return MOS_STATUS_SUCCESS if call success, else fail reason
    //!
    MOS_STATUS Initialize(
        CodechalHwInterface                *hwInterface,
        PMOS_INTERFACE                      osInterface);

    //!
    //! \brief    Allocate resources
    //!
    //! \return   MOS_STATUS
    //!           Return MOS_STATUS_SUCCESS if call success, else fail reason
    //!
    MOS_STATUS AllocateResources();

    //!
    //! \brief    Free resources
    //!
    //! \return   MOS_STATUS
    //!           Return MOS_STATUS_SUCCESS if call success, else fail reason
    //!
    MOS_STATUS FreeResources();

    //!
    //! \brief    Set parameters
    //! \details    call every frame.  get the input/output surface and  color space...
    //!
    //! \param    [in] params
    //!           Pointer to codechal encode sfc parameters
    //!
    //! \return   MOS_STATUS
    //!           Return MOS_STATUS_SUCCESS if call success, else fail reason
    //!
    MOS_STATUS SetParams(
        CODECHAL_ENCODE_SFC_PARAMS*         params);

    //!
    //! \brief    Render start
    //!
    //! \param    [in] encoder
    //!           Pointer to codechal encoder state
    //!
    //! \return   MOS_STATUS
    //!           Return MOS_STATUS_SUCCESS if call success, else fail reason
    //!
    MOS_STATUS RenderStart(
        CodechalEncoderState*           encoder);

    //!
    //! \brief    Add sfc commands
    //!
    //! \param    [in] sfcInterface
    //!           Pointer to MHW sfc interface
    //! \param    [in] cmdBuffer
    //!           Pointer to MOS command buffer
    //!
    //! \return   MOS_STATUS
    //!           Return MOS_STATUS_SUCCESS if call success, else fail reason
    //!
    virtual MOS_STATUS AddSfcCommands(
        PMHW_SFC_INTERFACE              sfcInterface,
        PMOS_COMMAND_BUFFER             cmdBuffer);

    //!
    //! \brief    Set sfc state parameters
    //!
    //! \param    [in] sfcInterface
    //!           Pointer to MHW sfc interface
    //! \param    [in] params
    //!           Pointer to MHW sfc state parameters
    //! \param    [in] outSurfaceParams
    //!           Pointer to MHW sfc out surface parameters
    //!
    //! \return   MOS_STATUS
    //!           Return MOS_STATUS_SUCCESS if call success, else fail reason
    //!
    MOS_STATUS SetSfcStateParams(
        PMHW_SFC_INTERFACE             sfcInterface,
        PMHW_SFC_STATE_PARAMS          params,
        PMHW_SFC_OUT_SURFACE_PARAMS    outSurfaceParams);

    //!
    //! \brief    Set sfc avs state parameters
    //!
    //! \param    [in] sfcInterface
    //!           Pointer to MHW sfc interface
    //!
    //! \return   MOS_STATUS
    //!           Return MOS_STATUS_SUCCESS if call success, else fail reason
    //!
    MOS_STATUS SetSfcAvsStateParams(
        PMHW_SFC_INTERFACE             sfcInterface);

    //!
    //! \brief    Set sfc ief state parameters
    //!
    //! \param    [in] params
    //!           Pointer to MHW sfc ief state parameters
    //!
    //! \return   MOS_STATUS
    //!           Return MOS_STATUS_SUCCESS if call success, else fail reason
    //!
    MOS_STATUS SetSfcIefStateParams(
        PMHW_SFC_IEF_STATE_PARAMS         params);

    //!
    //! \brief    Set vebox state parameters
    //!
    //! \param    [in] params
    //!           Pointer to vebox state command params
    //!
    //! \return   MOS_STATUS
    //!           Return MOS_STATUS_SUCCESS if call success, else fail reason
    //!
    MOS_STATUS SetVeboxStateParams(
        PMHW_VEBOX_STATE_CMD_PARAMS         params);

    //!
    //! \brief    Set vebox surface state params
    //!
    //! \param    [in] params
    //!           Pointer to MHW vebox surface state command parameters
    //!
    //! \return   MOS_STATUS
    //!           Return MOS_STATUS_SUCCESS if call success, else fail reason
    //!
    MOS_STATUS SetVeboxSurfaceStateParams(
        PMHW_VEBOX_SURFACE_STATE_CMD_PARAMS         params);

    //!
    //! \brief    Set vebox di iecp parameters
    //!
    //! \param    [in] params
    //!           Pointer to MHW vebox di iecp command parameters
    //!
    //! \return   MOS_STATUS
    //!           Return MOS_STATUS_SUCCESS if call success, else fail reason
    //!
    virtual MOS_STATUS SetVeboxDiIecpParams(
        PMHW_VEBOX_DI_IECP_CMD_PARAMS         params);

    //!
    //! \brief    Vebox set iecp parameters
    //! \details  input -> RGB (from app)
    //!           output -> NV12 (raw surface?)
    //!
    //! \param    [in] mhwVeboxIecpParams
    //!           Pointer t MHW vebox iecp paramters
    //!
    //! \return   MOS_STATUS
    //!           Return MOS_STATUS_SUCCESS if call success, else fail reason
    //!
    MOS_STATUS VeboxSetIecpParams(
        PMHW_VEBOX_IECP_PARAMS         mhwVeboxIecpParams);

#if (_DEBUG || _RELEASE_INTERNAL)
    MOS_STATUS DumpBuffers(CodechalDebugInterface* debugInterface);
#endif
private:
    //!
    //! \brief    Check if is Cspac
    //!
    //! \param    [in] srcCspace
    //!           MHW cspace
    //! \param    [in] dstCspace
    //!           MHW cspace
    //!
    //! \return   bool
    //!           true if call success, else false
    //!
    bool IsCspace(MHW_CSPACE srcCspace, MHW_CSPACE dstCspace);

    //!
    //! \brief    Get RGB range and offset
    //!
    //! \param    [in] srcCspace
    //!           MHW cspace
    //! \param    [in] rgbOffset
    //!           RGB offset
    //! \param    [in] rgbExcursion
    //!           RGB excursion
    //!
    //! \return   bool
    //!           true if call success, else false
    //!
    bool GetRgbRangeAndOffset(
        MHW_CSPACE          srcCspace,
        float               *rgbOffset,
        float               *rgbExcursion);

    //!
    //! \brief    Get YUV range and offset
    //!
    //! \param    [in] srcCspace
    //!           MHW cspace
    //! \param    [in] lumaOffset
    //!           Luma offset
    //! \param    [in] lumaExcursion
    //!           Luma excursion
    //! \param    [in] chromaZero
    //!           Chroma zero
    //! \param    [in] chromaExcursion
    //!           Chroma excursion
    //!
    //! \return   bool
    //!           true if call success, else false
    //!
    bool GetYuvRangeAndOffset(
        MHW_CSPACE          srcCspace,
        float               *lumaOffset,
        float               *lumaExcursion,
        float               *chromaZero,
        float               *chromaExcursion);

    //!
    //! \brief    Calculate YUV To RGB matrix
    //! \details  Given the YUV->RGB transfer matrix, get the final matrix after
    //!             applying offsets and excursions.
    //!
    //! [R']     [R_o]                                 [R_e/Y_e    0       0   ]  [Y'  - Y_o]
    //! [G']  =  [R_o] + [YUVtoRGBCoeff (3x3 matrix)]. [   0    R_e/C_e    0   ]. [Cb' - C_z]
    //! [B']     [R_o]                                 [   0       0    R_e/C_e]. [Cr' - C_z]
    //!
    //! [R']  = [C0  C1   C2] [Y' ]   [C3]      {Out pMatrix}
    //! [G']  = [C4  C5   C6].[Cb'] + [C7]
    //! [B']  = [C8  C9  C10] [Cr'] + [C11]
    //!
    //! \param    [in] srcCspace
    //!           YUV Color space 
    //! \param    [in] dstCspace
    //!           RGB Color space
    //! \param    [in] transferMatrix
    //!           Transfer matrix (3x3)
    //! \param    [out] outMatrix
    //!           Conversion matrix (3x4)
    //! \return   true if success else false
    //!
    bool CalcYuvToRgbMatrix(
        MHW_CSPACE      srcCspace,
        MHW_CSPACE      dstCspace,
        float           *transferMatrix,
        float           *outMatrix);

    //!
    //! \brief    Calculate RGB To YUV matrix
    //!
    //! \param    [in] srcCspace
    //!           RGB Color space 
    //! \param    [in] dstCspace
    //!           YUV Color space
    //! \param    [in] transferMatrix
    //!           Transfer matrix (3x3)
    //! \param    [out] outMatrix
    //!           Conversion matrix (3x4)
    //! \return   bool
    //!           true if call success, else false
    bool CalcRgbToYuvMatrix(
        MHW_CSPACE      srcCspace,
        MHW_CSPACE      dstCspace,
        float           *transferMatrix,
        float           *outMatrix);

    //!
    //! \brief    Get csc matrix
    //!
    //! \param    [in] srcCspace
    //!           Source Color space
    //! \param    [in] dstCspace
    //!           Destination Color space
    //! \param    [out] cscMatrix
    //!           CSC matrix to use
    //!
    void GetCSCMatrix(
        MHW_CSPACE          srcCspace,
        MHW_CSPACE          dstCspace,
        float               *cscMatrix);

    //!
    //! \brief    Get csc matrix
    //!
    //! \param    [in] srcCspace
    //!           Source Cspace
    //! \param    [in] dstCspace
    //!           Destination Cspace
    //! \param    [out] cscCoeff
    //!           Coefficients matrix
    //! \param    [out] cscInOffset
    //!           Input Offset matrix
    //! \param    [out] cscOutOffset
    //!           Output Offset matrix
    //!
    void GetCscMatrix(
        MHW_CSPACE             srcCspace,
        MHW_CSPACE             dstCspace,
        float                  *cscCoeff,
        float                  *cscInOffset,
        float                  *cscOutOffset);

protected:
    virtual int32_t GetAvsLineBufferSize() const;

    virtual int32_t GetSfcVeboxStatisticsSize() const = 0;
    virtual int32_t GetStatisticsOutputBufferSize() const;

    // ACE/LACE/RGB Histogram buffer
    virtual int32_t GetVeboxRgbHistogramSize() const;
    virtual int32_t GetVeboxRgbAceHistogramSizeReserved() const = 0;
    virtual int32_t GetVeboxMaxSlicesNum() const = 0;
    virtual int32_t GetResLaceOrAceOrRgbHistogramBufferSize() const;

    CodechalHwInterface            *m_hwInterface = nullptr;  //!< Pointer to CodechalHwInterface
    PMOS_INTERFACE                  m_osInterface = nullptr;  //!< Pointer to MOS_INTERFACE

    PMOS_SURFACE    m_inputSurface = nullptr;
    MHW_CSPACE      m_inputSurfaceColorSpace = MHW_CSpace_Any;
    PMOS_SURFACE    m_veboxOutputSurface = nullptr;
    PMOS_SURFACE    m_sfcOutputSurface = nullptr;
    MHW_CSPACE      m_outputSurfaceColorSpace = MHW_CSpace_Any;

    MOS_RESOURCE    m_resAvsLineBuffer = { 0, };
    MOS_RESOURCE    m_resLaceOrAceOrRgbHistogram = { 0, };
    MOS_RESOURCE    m_resStatisticsOutput = { 0, };

    bool            m_scaling = false;
    bool            m_colorFill = false;
    bool            m_IEF = false;
    bool            m_CSC = false;

    float           m_scaleX = 0.0f;
    float           m_scaleY = 0.0f;

    uint16_t        m_iefFactor = 0;
    uint32_t        m_rotationMode = 0;
    uint32_t        m_chromaSiting = 0;
    uint32_t        m_inputFrameWidth = 0;
    uint32_t        m_inputFrameHeight = 0;

    CODECHAL_ENCODE_RECTANGLE       m_inputSurfaceRegion = { 0, };
    CODECHAL_ENCODE_RECTANGLE       m_outputSurfaceRegion = { 0, };

    // CSC in VEBOX params
    bool                            m_veboxCsc = false;
    MHW_CSPACE                      m_cscOutputCspace = MHW_CSpace_Any;    //!< Cspace of Output Frame
    MHW_CSPACE                      m_cscInputCspace = MHW_CSpace_Any;     //!< Cspace of Input frame
    float                           m_cscCoeff[9] = { 0.0f, };
    float                           m_cscInOffset[3] = { 0.0f, };
    float                           m_cscOutOffset[3] = { 0.0f, };

    MHW_AVS_PARAMS                  m_avsParams = { Format_Any, };
    MHW_SFC_AVS_LUMA_TABLE          m_lumaTable = { 0, };
    MHW_SFC_AVS_CHROMA_TABLE        m_chromaTable = { 0, };
    MHW_SFC_AVS_STATE               m_avsState = { 0, };
};
#endif  // __CODECHAL_ENCODE_SFC_BASE_H__
