/*
* Copyright (c) 2015-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     mhw_sfc_g12_X.cpp
//! \brief    Constructs sfc commands on Gen12-based platforms
//! \details  Each client facing function both creates a HW command and adds
//!           that command to a command or batch buffer.
//!

#include "mhw_sfc_g12_X.h"

MOS_STATUS MhwSfcInterfaceG12::AddSfcLock(
    PMOS_COMMAND_BUFFER            pCmdBuffer,
    PMHW_SFC_LOCK_PARAMS           pSfcLockParams)
{
    MHW_CHK_NULL_RETURN(pCmdBuffer);
    MHW_CHK_NULL_RETURN(pSfcLockParams);

    mhw_sfc_g12_X::SFC_LOCK_CMD cmd, *cmdPtr;
    cmdPtr = (mhw_sfc_g12_X::SFC_LOCK_CMD *)pCmdBuffer->pCmdPtr;

    MHW_CHK_STATUS_RETURN(MhwSfcInterfaceGeneric::AddSfcLock(pCmdBuffer, pSfcLockParams));

    if (pSfcLockParams->sfcPipeMode == MhwSfcInterfaceG12::SFC_PIPE_MODE_HCP)
    {
        MHW_CHK_NULL_RETURN(cmdPtr);
        cmdPtr->DW0.MediaCommandOpcode = cmd.MEDIA_COMMAND_OPCODE_MEDIAHEVCSFCMODE;
    }

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS MhwSfcInterfaceG12::AddSfcState(
    PMOS_COMMAND_BUFFER            pCmdBuffer,
    PMHW_SFC_STATE_PARAMS          pSfcStateParams,
    PMHW_SFC_OUT_SURFACE_PARAMS    pOutSurface)
{
    PMOS_INTERFACE              pOsInterface;
    bool                        bHalfPitchForChroma;
    bool                        bInterleaveChroma;
    uint16_t                    wUXOffset;
    uint16_t                    wUYOffset;
    uint16_t                    wVXOffset;
    uint16_t                    wVYOffset;
    MHW_RESOURCE_PARAMS         ResourceParams;
    MEDIA_WA_TABLE              *pWaTable = nullptr;

    PMHW_SFC_STATE_PARAMS_G12       pSfcStateParamsG12 = static_cast<PMHW_SFC_STATE_PARAMS_G12>(pSfcStateParams);
    mhw_sfc_g12_X::SFC_STATE_CMD    cmd;

    MHW_CHK_NULL_RETURN(pCmdBuffer);
    MHW_CHK_NULL_RETURN(pSfcStateParams);
    MHW_CHK_NULL_RETURN(pOutSurface);

    pOsInterface    = m_osInterface;
    MHW_CHK_NULL_RETURN(pOsInterface);
    pWaTable        = pOsInterface->pfnGetWaTable(pOsInterface);
    MHW_CHK_NULL_RETURN(pWaTable);

    bHalfPitchForChroma = false;
    bInterleaveChroma   = false;
    wUXOffset           = 0;
    wUYOffset           = 0;
    wVXOffset           = 0;
    wVYOffset           = 0;

    // Check input/output size
    MHW_ASSERT(pSfcStateParamsG12->dwInputFrameWidth   >= m_minWidth);
    MHW_ASSERT(pSfcStateParamsG12->dwInputFrameHeight  >= m_minHeight);
    MHW_ASSERT(pSfcStateParamsG12->dwOutputFrameWidth  <= m_maxWidth);
    MHW_ASSERT(pSfcStateParamsG12->dwOutputFrameHeight <= m_maxHeight);

    // Set DW0
    if (pSfcStateParamsG12->sfcPipeMode == MhwSfcInterfaceG12::SFC_PIPE_MODE_HCP)
    {
        cmd.DW0.MediaCommandOpcode = cmd.MEDIA_COMMAND_OPCODE_MEDIAHCPSFCMODE;
    }
    else
    {
        cmd.DW0.MediaCommandOpcode = cmd.MEDIA_COMMAND_OPCODE_MEDIAMFXVEBOXSFCMODE;
    }

    // Set DW1
    cmd.DW1.SfcPipeMode                  = pSfcStateParamsG12->sfcPipeMode;
    cmd.DW1.SfcInputChromaSubSampling    = pSfcStateParamsG12->dwInputChromaSubSampling;
    cmd.DW1.VdVeInputOrderingMode        = pSfcStateParamsG12->dwVDVEInputOrderingMode;
    cmd.DW1.SfcEngineMode                = pSfcStateParamsG12->engineMode;
    cmd.DW1.SfcInputStreamBitDepth       = pSfcStateParamsG12->inputBitDepth;

    // Set DW2
    cmd.DW2.InputFrameResolutionWidth    = pSfcStateParamsG12->dwInputFrameWidth - 1;
    cmd.DW2.InputFrameResolutionHeight   = pSfcStateParamsG12->dwInputFrameHeight - 1;

    // Set DW3
    cmd.DW3.OutputChromaDownsamplingCoSitingPositionVerticalDirection      = pSfcStateParamsG12->dwChromaDownSamplingVerticalCoef;
    cmd.DW3.OutputChromaDownsamplingCoSitingPositionHorizontalDirection    = pSfcStateParamsG12->dwChromaDownSamplingHorizontalCoef;
    cmd.DW3.InputColorSpace0Yuv1Rgb                                        = pSfcStateParamsG12->bInputColorSpace;

    switch(pSfcStateParamsG12->OutputFrameFormat)
    {
        case Format_AYUV:
            cmd.DW3.OutputSurfaceFormatType = cmd.OUTPUT_SURFACE_FORMAT_TYPE_AYUV;
            break;
        case Format_X8R8G8B8:
        case Format_A8R8G8B8:
        case Format_X8B8G8R8:
        case Format_A8B8G8R8:
            cmd.DW3.OutputSurfaceFormatType = cmd.OUTPUT_SURFACE_FORMAT_TYPE_A8B8G8R8;
            break;
        case Format_R10G10B10A2:
        case Format_B10G10R10A2:
            cmd.DW3.OutputSurfaceFormatType = cmd.OUTPUT_SURFACE_FORMAT_TYPE_A2R10G10B10;
            break;
        case Format_R5G6B5:
            cmd.DW3.OutputSurfaceFormatType = cmd.OUTPUT_SURFACE_FORMAT_TYPE_R5G6B5;
            break;
        case Format_NV12:
            cmd.DW3.OutputSurfaceFormatType = cmd.OUTPUT_SURFACE_FORMAT_TYPE_NV12;
            bInterleaveChroma   = true;
            wUYOffset           = (uint16_t)pOutSurface->dwUYoffset;
            break;
        case Format_YUY2:
            cmd.DW3.OutputSurfaceFormatType = cmd.OUTPUT_SURFACE_FORMAT_TYPE_YUYV;
            break;
        case Format_UYVY:
            cmd.DW3.OutputSurfaceFormatType = cmd.OUTPUT_SURFACE_FORMAT_TYPE_UYVY;
            break;
        case Format_P010:
            cmd.DW3.OutputSurfaceFormatType = cmd.OUTPUT_SURFACE_FORMAT_TYPE_P016;
            cmd.DW4.Bitdepth                = 0;
            wUYOffset                       = (uint16_t)pOutSurface->dwUYoffset;
            break;
        case Format_P016:
            cmd.DW3.OutputSurfaceFormatType = cmd.OUTPUT_SURFACE_FORMAT_TYPE_P016;
            cmd.DW4.Bitdepth                = 1;
            wUYOffset                       = (uint16_t)pOutSurface->dwUYoffset;
            break;
        case Format_Y210:
            cmd.DW3.OutputSurfaceFormatType = cmd.OUTPUT_SURFACE_FORMAT_TYPE_Y216;
            cmd.DW4.Bitdepth                = 0;
            wUYOffset                       = (uint16_t)pOutSurface->dwUYoffset;
            break;
        case Format_Y216:
            cmd.DW3.OutputSurfaceFormatType = cmd.OUTPUT_SURFACE_FORMAT_TYPE_Y216;
            cmd.DW4.Bitdepth                = 1;
            wUYOffset                       = (uint16_t)pOutSurface->dwUYoffset;
            break;
        case Format_Y410:
            cmd.DW3.OutputSurfaceFormatType = cmd.OUTPUT_SURFACE_FORMAT_TYPE_Y416;
            cmd.DW4.Bitdepth                = 0;
            wUYOffset                       = (uint16_t)pOutSurface->dwUYoffset;
            break;
        case Format_Y416:
            cmd.DW3.OutputSurfaceFormatType = cmd.OUTPUT_SURFACE_FORMAT_TYPE_Y416;
            cmd.DW4.Bitdepth                = 1;
            wUYOffset                       = (uint16_t)pOutSurface->dwUYoffset;
            break;
        default:
            MHW_ASSERTMESSAGE("Unknown Output Format.");
            return MOS_STATUS_UNKNOWN;

    }

    // RGBASwapEnable is true when the OutputSurfaceFormatType is set as A8B8G8R8 for X8R8G8B8 and A8R8G8B8 output,
    // and the OutputSurfaceFormatType is set as A2R10G10B10 for R10G10B10A2 output.
    cmd.DW3.RgbaChannelSwapEnable = pSfcStateParamsG12->bRGBASwapEnable;

    // Set DW4
    cmd.DW4.IefEnable                    = pSfcStateParamsG12->bIEFEnable;
    cmd.DW4.SkinToneTunedIefEnable       = pSfcStateParamsG12->bSkinToneTunedIEFEnable;
    cmd.DW4.AvsFilterMode                = pSfcStateParamsG12->dwAVSFilterMode;
    if (pSfcStateParamsG12->b8tapChromafiltering)
    {
        cmd.DW4.AdaptiveFilterForAllChannels = true;
    }
    else
    {
        cmd.DW4.AdaptiveFilterForAllChannels = false;
    }

    cmd.DW4.AvsScalingEnable                     = ((pSfcStateParamsG12->fAVSXScalingRatio == 1.0F) &&
                                                             (pSfcStateParamsG12->fAVSYScalingRatio == 1.0F)) ? false : true;
    cmd.DW4.BypassYAdaptiveFiltering             = pSfcStateParamsG12->bBypassYAdaptiveFilter;
    cmd.DW4.BypassXAdaptiveFiltering             = pSfcStateParamsG12->bBypassXAdaptiveFilter;
    cmd.DW4.ChromaUpsamplingEnable               = pSfcStateParamsG12->bAVSChromaUpsamplingEnable;
    cmd.DW4.RotationMode                         = pSfcStateParamsG12->RotationMode;
    cmd.DW4.ColorFillEnable                      = pSfcStateParamsG12->bColorFillEnable;
    cmd.DW4.CscEnable                            = pSfcStateParamsG12->bCSCEnable;
    cmd.DW4.Enable8TapForChromaChannelsFiltering = pSfcStateParamsG12->b8tapChromafiltering;
    cmd.DW4.TileType                             = pSfcStateParamsG12->tileType;
    cmd.DW4.RgbAdaptive                          = pSfcStateParamsG12->bRGBAdaptive;

    if (pSfcStateParams->bMirrorEnable)
    {
        cmd.DW4.Value |= (uint32_t)(1 << 14) & 0x00004000;                                          // Mirror Mode
        cmd.DW4.Value |= (uint32_t)(pSfcStateParams->dwMirrorType << 13) & 0x00002000;              // Mirror Type
    }

    // Set DW5, DW6, DW7, DW8, DW9
    cmd.DW5.SourceRegionWidth            = pSfcStateParamsG12->dwSourceRegionWidth - 1;
    cmd.DW5.SourceRegionHeight           = pSfcStateParamsG12->dwSourceRegionHeight - 1;
    cmd.DW6.SourceRegionHorizontalOffset = pSfcStateParamsG12->dwSourceRegionHorizontalOffset;
    cmd.DW6.SourceRegionVerticalOffset   = pSfcStateParamsG12->dwSourceRegionVerticalOffset;
    cmd.DW7.OutputFrameWidth             = pSfcStateParamsG12->dwOutputFrameWidth + pOutSurface->dwSurfaceXOffset - 1;
    cmd.DW7.OutputFrameHeight            = pSfcStateParamsG12->dwOutputFrameHeight + pOutSurface->dwSurfaceYOffset - 1;
    cmd.DW8.ScaledRegionSizeWidth        = pSfcStateParamsG12->dwScaledRegionWidth - 1;
    cmd.DW8.ScaledRegionSizeHeight       = pSfcStateParamsG12->dwScaledRegionHeight - 1;
    cmd.DW9.ScaledRegionHorizontalOffset = pSfcStateParamsG12->dwScaledRegionHorizontalOffset + pOutSurface->dwSurfaceXOffset;
    cmd.DW9.ScaledRegionVerticalOffset   = pSfcStateParamsG12->dwScaledRegionVerticalOffset + pOutSurface->dwSurfaceYOffset;

    // Set DW10
    cmd.DW10.GrayBarPixelUG              = MOS_CLAMP_MIN_MAX(MOS_F_ROUND(pSfcStateParamsG12->fColorFillUGPixel * 1024.0F), 0, 1023); // U10
    cmd.DW10.GrayBarPixelYR              = MOS_CLAMP_MIN_MAX(MOS_F_ROUND(pSfcStateParamsG12->fColorFillYRPixel * 1024.0F), 0, 1023); // U10

    // Set DW11
    cmd.DW11.GrayBarPixelA               = MOS_CLAMP_MIN_MAX(MOS_F_ROUND(pSfcStateParamsG12->fColorFillAPixel * 1024.0F), 0, 1023); // U10
    cmd.DW11.GrayBarPixelVB              = MOS_CLAMP_MIN_MAX(MOS_F_ROUND(pSfcStateParamsG12->fColorFillVBPixel * 1024.0F), 0, 1023); // U10

    // Set DW13
    cmd.DW13.AlphaDefaultValue           = MOS_CLAMP_MIN_MAX(MOS_F_ROUND(pSfcStateParamsG12->fAlphaPixel * 1024.0F), 0, 1023); // U10

    // Set DW14
    cmd.DW14.ScalingFactorHeight         = MOS_UF_ROUND((double)pSfcStateParamsG12->dwSourceRegionHeight / (double)pSfcStateParamsG12->dwScaledRegionHeight * 524288.0F); // U4.19

    // Set DW15
    cmd.DW15.ScalingFactorWidth          = MOS_UF_ROUND((double)pSfcStateParamsG12->dwSourceRegionWidth / (double)pSfcStateParamsG12->dwScaledRegionWidth * 524288.0F); // U4.19

    // Set DW19
    if (pSfcStateParamsG12->MMCMode == MOS_MMC_RC || pSfcStateParamsG12->MMCMode == MOS_MMC_MC)
    {
        cmd.DW19.OutputFrameSurfaceBaseAddressMemoryCompressionEnable = pSfcStateParamsG12->bMMCEnable;
    }
    cmd.DW19.OutputFrameSurfaceBaseAddressIndexToMemoryObjectControlStateMocsTables = m_outputSurfCtrl.Gen12.Index;

    cmd.DW19.OutputFrameSurfaceBaseAddressMemoryCompressionMode = (pSfcStateParamsG12->MMCMode == MOS_MMC_RC) ? 1 : 0;

    switch (pSfcStateParamsG12->tileType)
    {
    case MOS_TILE_YF:
        cmd.DW19.OutputSurfaceTiledMode = TRMODE_TILEYF;
        break;
    case MOS_TILE_YS:
        cmd.DW19.OutputSurfaceTiledMode = TRMODE_TILEYS;
        break;
    default:
        cmd.DW19.OutputSurfaceTiledMode = TRMODE_NONE;
        break;
    }

    // Set DW29
    cmd.DW29.OutputSurfaceTileWalk       = (pOutSurface->TileType == MOS_TILE_Y) ?
                                                      true : false;
    cmd.DW29.OutputSurfaceTiled          = (pOutSurface->TileType != MOS_TILE_LINEAR) ?
                                                      true : false;
    cmd.DW29.OutputSurfaceHalfPitchForChroma
                                                   = bHalfPitchForChroma;
    cmd.DW29.OutputSurfacePitch          = pOutSurface->dwPitch - 1;
    cmd.DW29.OutputSurfaceInterleaveChromaEnable
                                                   = bInterleaveChroma;
    cmd.DW29.OutputSurfaceFormat         = cmd.DW3.OutputSurfaceFormatType;

    // Set DW30, DW31
    cmd.DW30.OutputSurfaceYOffsetForU    = wUYOffset;
    cmd.DW30.OutputSurfaceXOffsetForU    = wUXOffset;
    cmd.DW31.OutputSurfaceYOffsetForV    = wVYOffset;
    cmd.DW31.OutputSurfaceXOffsetForV    = wVXOffset;

    // DW34, DW35
    cmd.DW34.SourceStartX         = pSfcStateParamsG12->srcStartX;
    cmd.DW34.SourceEndX           = pSfcStateParamsG12->srcEndX;
    cmd.DW35.DestinationStartX    = pSfcStateParamsG12->dstStartX;
    cmd.DW35.DestinationEndX      = pSfcStateParamsG12->dstEndX;

    // Set DW36, DW37
    //Change SFC outputcentering scaling X/Yphaseshift value and limition limitione with 19bit following Fuslim setting.
    if (m_outputCenteringEnable)
    {
        cmd.DW36.Xphaseshift = MOS_CLAMP_MIN_MAX(MOS_F_ROUND((((double)cmd.DW15.ScalingFactorWidth / 524288.0F - 1.0) / 2.0) * 524288.0F), -(1 << (4 + 19)), ((1 << (4 + 19)) - 1));
        cmd.DW37.Yphaseshift = MOS_CLAMP_MIN_MAX(MOS_F_ROUND((((double)cmd.DW14.ScalingFactorHeight / 524288.0F - 1.0) / 2.0) * 524288.0F), -(1 << (4 + 19)), ((1 << (4 + 19)) - 1));
    }

    if (pSfcStateParamsG12->pOsResOutputSurface)
    {
        MOS_ZeroMemory(&ResourceParams, sizeof(ResourceParams));
        InitMocsParams(ResourceParams, &cmd.DW19.Value, 1, 6);
        ResourceParams.presResource                = pSfcStateParamsG12->pOsResOutputSurface;
        ResourceParams.pdwCmd                      = &(cmd.DW17.Value);
        ResourceParams.dwLocationInCmd             = 17;
        ResourceParams.HwCommandType               = MOS_SFC_STATE;
        ResourceParams.bIsWritable                 = true;
        ResourceParams.dwOffset                    = pSfcStateParamsG12->dwOutputSurfaceOffset;

        MHW_CHK_STATUS_RETURN(pfnAddResourceToCmd(
          pOsInterface,
          pCmdBuffer,
          &ResourceParams));
        if (m_outputSurfCtrl.Gen12.Index != 0)
        {
            cmd.DW19.OutputFrameSurfaceBaseAddressIndexToMemoryObjectControlStateMocsTables = m_outputSurfCtrl.Gen12.Index;
        }
    }

    if (pSfcStateParamsG12->pOsResAVSLineBuffer)
    {
        MOS_ZeroMemory(&ResourceParams, sizeof(ResourceParams));
        InitMocsParams(ResourceParams, &cmd.DW22.Value, 1, 6);
        ResourceParams.presResource                = pSfcStateParamsG12->pOsResAVSLineBuffer;
        ResourceParams.pdwCmd                      = &(cmd.DW20.Value);
        ResourceParams.dwLocationInCmd             = 20;
        ResourceParams.HwCommandType               = MOS_SFC_STATE;
        ResourceParams.bIsWritable                 = true;
        MHW_CHK_STATUS_RETURN(pfnAddResourceToCmd(
          pOsInterface,
          pCmdBuffer,
          &ResourceParams));
        if (m_avsLineBufferCtrl.Gen12.Index != 0)
        {
            cmd.DW22.AvsLineBufferBaseAddressIndexToMemoryObjectControlStateMocsTables = m_avsLineBufferCtrl.Gen12.Index;
        }
    }

    if (pSfcStateParamsG12->pOsResIEFLineBuffer)
    {
        MOS_ZeroMemory(&ResourceParams, sizeof(ResourceParams));
        InitMocsParams(ResourceParams, &cmd.DW25.Value, 1, 6);
        ResourceParams.presResource                = pSfcStateParamsG12->pOsResIEFLineBuffer;
        ResourceParams.pdwCmd                      = &(cmd.DW23.Value);
        ResourceParams.dwLocationInCmd             = 23;
        ResourceParams.HwCommandType               = MOS_SFC_STATE;
        ResourceParams.bIsWritable                 = true;

        MHW_CHK_STATUS_RETURN(pfnAddResourceToCmd(
          pOsInterface,
          pCmdBuffer,
          &ResourceParams));
        if (m_iefLineBufferCtrl.Gen12.Index != 0)
        {
            cmd.DW25.IefLineBufferBaseAddressIndexToMemoryObjectControlStateMocsTables = m_iefLineBufferCtrl.Gen12.Index;
        }
    }

    if (pSfcStateParamsG12->resSfdLineBuffer && !Mos_ResourceIsNull(pSfcStateParamsG12->resSfdLineBuffer))
    {
        MOS_ZeroMemory(&ResourceParams, sizeof(ResourceParams));
        InitMocsParams(ResourceParams, &cmd.DW28.Value, 1, 6);
        ResourceParams.presResource = pSfcStateParamsG12->resSfdLineBuffer;
        ResourceParams.pdwCmd = &(cmd.DW26.Value);
        ResourceParams.dwLocationInCmd = 26;
        ResourceParams.HwCommandType = MOS_SFC_STATE;
        ResourceParams.bIsWritable = true;

        MHW_CHK_STATUS_RETURN(pfnAddResourceToCmd(
            pOsInterface,
            pCmdBuffer,
            &ResourceParams));
        if (m_sfdLineBufferCtrl.Gen12.Index != 0)
        {
            cmd.DW28.SfdLineBufferBaseAddressIndexToMemoryObjectControlStateMocsTables = m_sfdLineBufferCtrl.Gen12.Index;
        }
    }

    if (pSfcStateParamsG12->resAvsLineTileBuffer && !Mos_ResourceIsNull(pSfcStateParamsG12->resAvsLineTileBuffer))
    {
        MOS_ZeroMemory(&ResourceParams, sizeof(ResourceParams));
        InitMocsParams(ResourceParams, &cmd.DW40.Value, 1, 6);
        ResourceParams.presResource = pSfcStateParamsG12->resAvsLineTileBuffer;
        ResourceParams.pdwCmd = &(cmd.DW38.Value);
        ResourceParams.dwLocationInCmd = 38;
        ResourceParams.HwCommandType = MOS_SFC_STATE;
        ResourceParams.bIsWritable = true;

        MHW_CHK_STATUS_RETURN(pfnAddResourceToCmd(
            pOsInterface,
            pCmdBuffer,
            &ResourceParams));

        if (m_avsLineTileBufferCtrl.Gen12.Index != 0)
        {
            cmd.DW40.AvsLineTileBufferBaseAddressIndexToMemoryObjectControlStateMocsTables = m_avsLineTileBufferCtrl.Gen12.Index;
        }
    }

    if (pSfcStateParamsG12->resIefLineTileBuffer && !Mos_ResourceIsNull(pSfcStateParamsG12->resIefLineTileBuffer))
    {
        MOS_ZeroMemory(&ResourceParams, sizeof(ResourceParams));
        InitMocsParams(ResourceParams, &cmd.DW43.Value, 1, 6);
        ResourceParams.presResource = pSfcStateParamsG12->resIefLineTileBuffer;
        ResourceParams.pdwCmd = &(cmd.DW41.Value);
        ResourceParams.dwLocationInCmd = 41;
        ResourceParams.HwCommandType = MOS_SFC_STATE;
        ResourceParams.bIsWritable = true;

        MHW_CHK_STATUS_RETURN(pfnAddResourceToCmd(
            pOsInterface,
            pCmdBuffer,
            &ResourceParams));

        if (m_iefLineTileBufferCtrl.Gen12.Index != 0)
        {
            cmd.DW43.IefLineTileBufferBaseAddressIndexToMemoryObjectControlStateMocsTables = m_iefLineTileBufferCtrl.Gen12.Index;
        }
    }

    if (pSfcStateParamsG12->resSfdLineTileBuffer && !Mos_ResourceIsNull(pSfcStateParamsG12->resSfdLineTileBuffer))
    {
        MOS_ZeroMemory(&ResourceParams, sizeof(ResourceParams));
        InitMocsParams(ResourceParams, &cmd.DW46.Value, 1, 6);
        ResourceParams.presResource = pSfcStateParamsG12->resSfdLineTileBuffer;
        ResourceParams.pdwCmd = &(cmd.DW44.Value);
        ResourceParams.dwLocationInCmd = 44;
        ResourceParams.HwCommandType = MOS_SFC_STATE;
        ResourceParams.bIsWritable = true;

        MHW_CHK_STATUS_RETURN(pfnAddResourceToCmd(
            pOsInterface,
            pCmdBuffer,
            &ResourceParams));

        if (m_sfdLineTileBufferCtrl.Gen12.Index != 0)
        {
            cmd.DW46.SfdLineTileBufferBaseAddressIndexToMemoryObjectControlStateMocsTables = m_sfdLineTileBufferCtrl.Gen12.Index;
        }
    }

    if (pSfcStateParamsG12->histogramSurface && !Mos_ResourceIsNull(&pSfcStateParamsG12->histogramSurface->OsResource))
    {
        cmd.DW4.HistogramStreamout                 = 1;
        cmd.DW49.Value                             = 0;

        MOS_ZeroMemory(&ResourceParams, sizeof(ResourceParams));
        ResourceParams.presResource                = &pSfcStateParamsG12->histogramSurface->OsResource;
        ResourceParams.dwOffset                    = pSfcStateParamsG12->histogramSurface->dwOffset;
        ResourceParams.pdwCmd                      = &(cmd.DW47.Value);
        ResourceParams.dwLocationInCmd             = 47;
        ResourceParams.HwCommandType               = MOS_SFC_STATE;
        ResourceParams.bIsWritable                 = true;
        InitMocsParams(ResourceParams, &cmd.DW49.Value, 1, 6);

        MHW_CHK_STATUS_RETURN(pfnAddResourceToCmd(
            pOsInterface,
            pCmdBuffer,
            &ResourceParams));
        
        if (m_histogramBufferCtrl.Gen12.Index != 0)
        {
            cmd.DW49.HistogramBaseAddressMOCSIndex = m_histogramBufferCtrl.Gen12.Index;
        }
    }

    MHW_CHK_STATUS_RETURN(Mos_AddCommand(pCmdBuffer, &cmd, cmd.byteSize));

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS MhwSfcInterfaceG12::AddSfcAvsState(
    PMOS_COMMAND_BUFFER             pCmdBuffer,
    PMHW_SFC_AVS_STATE              pSfcAvsState)
{
    MHW_CHK_NULL_RETURN(pCmdBuffer);
    MHW_CHK_NULL_RETURN(pSfcAvsState);
    mhw_sfc_g12_X::SFC_AVS_STATE_CMD cmd, *cmdPtr;
    cmdPtr = (mhw_sfc_g12_X::SFC_AVS_STATE_CMD *)pCmdBuffer->pCmdPtr;

    MHW_CHK_STATUS_RETURN(MhwSfcInterfaceGeneric::AddSfcAvsState(pCmdBuffer, pSfcAvsState));

    MHW_CHK_NULL_RETURN(cmdPtr);
    if (pSfcAvsState->sfcPipeMode == MhwSfcInterfaceG12::SFC_PIPE_MODE_HCP)
    {
        cmdPtr->DW0.MediaCommandOpcode = cmd.MEDIA_COMMAND_OPCODE_MEDIAHEVCSFCMODE;
    }
    else
    {
        cmdPtr->DW0.MediaCommandOpcode = cmd.MEDIA_COMMAND_OPCODE_MEDIAMFXVEBOXSFCMODE;
    }

    cmdPtr->DW3.InputHorizontalSitingValueSpecifiesTheHorizontalSitingOfTheInput = pSfcAvsState->dwInputHorizontalSiting;
    cmdPtr->DW3.InputVerticalSitingSpecifiesTheVerticalSitingOfTheInput          = pSfcAvsState->dwInputVerticalSitting;

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS MhwSfcInterfaceG12::AddSfcFrameStart(
    PMOS_COMMAND_BUFFER            pCmdBuffer,
    uint8_t                        sfcPipeMode)
{
    MHW_CHK_NULL_RETURN(pCmdBuffer);
    mhw_sfc_g12_X::SFC_FRAME_START_CMD cmd, *cmdPtr;
    cmdPtr = (mhw_sfc_g12_X::SFC_FRAME_START_CMD *)pCmdBuffer->pCmdPtr;

    MHW_CHK_STATUS_RETURN(MhwSfcInterfaceGeneric::AddSfcFrameStart(pCmdBuffer, sfcPipeMode));
    MHW_CHK_NULL_RETURN(cmdPtr);
    if (sfcPipeMode == MhwSfcInterfaceG12::SFC_PIPE_MODE_HCP)
    {
        cmdPtr->DW0.MediaCommandOpcode = cmd.MEDIA_COMMAND_OPCODE_MEDIAHEVCSFCMODE;
    }
    return MOS_STATUS_SUCCESS;
}

MOS_STATUS MhwSfcInterfaceG12::AddSfcIefState(
    PMOS_COMMAND_BUFFER            pCmdBuffer,
    PMHW_SFC_IEF_STATE_PARAMS      pSfcIefStateParams)
{
    MHW_CHK_NULL_RETURN(pCmdBuffer);
    MHW_CHK_NULL_RETURN(pSfcIefStateParams);

    mhw_sfc_g12_X::SFC_IEF_STATE_CMD cmd, *cmdPtr;
    cmdPtr = (mhw_sfc_g12_X::SFC_IEF_STATE_CMD *)pCmdBuffer->pCmdPtr;

    MHW_CHK_STATUS_RETURN(MhwSfcInterfaceGeneric::AddSfcIefState(pCmdBuffer, pSfcIefStateParams));

    if (pSfcIefStateParams->sfcPipeMode == MhwSfcInterfaceG12::SFC_PIPE_MODE_HCP)
    {
        MHW_CHK_NULL_RETURN(cmdPtr);
        cmdPtr->DW0.MediaCommandOpcode = cmd.MEDIA_COMMAND_OPCODE_MEDIAHEVCSFCMODE;
    }

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS MhwSfcInterfaceG12::AddSfcAvsChromaTable(
    PMOS_COMMAND_BUFFER             pCmdBuffer,
    PMHW_SFC_AVS_CHROMA_TABLE       pChromaTable)
{
    MHW_CHK_NULL_RETURN(pCmdBuffer);
    MHW_CHK_NULL_RETURN(pChromaTable);

    mhw_sfc_g12_X::SFC_AVS_CHROMA_Coeff_Table_CMD cmd, *cmdPtr;
    cmdPtr = (mhw_sfc_g12_X::SFC_AVS_CHROMA_Coeff_Table_CMD *)pCmdBuffer->pCmdPtr;
    MHW_CHK_STATUS_RETURN(MhwSfcInterfaceGeneric::AddSfcAvsChromaTable(pCmdBuffer, pChromaTable));

    if (pChromaTable->sfcPipeMode == MhwSfcInterfaceG12::SFC_PIPE_MODE_HCP) // HCP-to-SFC
    {
        MHW_CHK_NULL_RETURN(cmdPtr);
        cmdPtr->DW0.MediaCommandOpcode = cmd.MEDIA_COMMAND_OPCODE_MEDIAHEVCSFCMODE;
    }

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS MhwSfcInterfaceG12::AddSfcAvsLumaTable(
    PMOS_COMMAND_BUFFER             pCmdBuffer,
    PMHW_SFC_AVS_LUMA_TABLE         pLumaTable)
{
    MHW_CHK_NULL_RETURN(pCmdBuffer);
    MHW_CHK_NULL_RETURN(pLumaTable);

    mhw_sfc_g12_X::SFC_AVS_LUMA_Coeff_Table_CMD cmd, *cmdPtr;
    cmdPtr = (mhw_sfc_g12_X::SFC_AVS_LUMA_Coeff_Table_CMD *)pCmdBuffer->pCmdPtr;
    MHW_CHK_STATUS_RETURN(MhwSfcInterfaceGeneric::AddSfcAvsLumaTable(pCmdBuffer, pLumaTable));

    if (pLumaTable->sfcPipeMode == MhwSfcInterfaceG12::SFC_PIPE_MODE_HCP) // HCP-to-SFC
    {
        MHW_CHK_NULL_RETURN(cmdPtr);
        cmdPtr->DW0.MediaCommandOpcode = cmd.MEDIA_COMMAND_OPCODE_MEDIAHEVCSFCMODE;
    }

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS MhwSfcInterfaceG12 :: SetSfcSamplerTable(
    PMHW_SFC_AVS_LUMA_TABLE         pLumaTable,
    PMHW_SFC_AVS_CHROMA_TABLE       pChromaTable,
    PMHW_AVS_PARAMS                 pAvsParams,
    MOS_FORMAT                      SrcFormat,
    float                           fScaleX,
    float                           fScaleY,
    uint32_t                        dwChromaSiting,
    bool                            bUse8x8Filter,
    float                           fHPStrength,
    float                           fLanczosT)
{
    int32_t     *piYCoefsX,  *piYCoefsY;
    int32_t     *piUVCoefsX, *piUVCoefsY;
    MHW_PLANE   Plane;

    MHW_CHK_NULL_RETURN(pLumaTable);
    MHW_CHK_NULL_RETURN(pChromaTable);
    MHW_CHK_NULL_RETURN(pAvsParams);

    fHPStrength = 0.0F;
    piYCoefsX   = pAvsParams->piYCoefsX;
    piYCoefsY   = pAvsParams->piYCoefsY;
    piUVCoefsX  = pAvsParams->piUVCoefsX;
    piUVCoefsY  = pAvsParams->piUVCoefsY;

    // Skip calculation if no changes to AVS parameters
    if (SrcFormat == pAvsParams->Format  &&
        fScaleX   == pAvsParams->fScaleX &&
        fScaleY   == pAvsParams->fScaleY)
    {
        return MOS_STATUS_SUCCESS;
    }

    // AVS Coefficients don't change for Scaling Factors > 1.0x
    // Hence recalculation is avoided
    if (fScaleX > 1.0F && pAvsParams->fScaleX > 1.0F)
    {
        pAvsParams->fScaleX = fScaleX;
    }

    // AVS Coefficients don't change for Scaling Factors > 1.0x
    // Hence recalculation is avoided
    if (fScaleY > 1.0F && pAvsParams->fScaleY > 1.0F)
    {
        pAvsParams->fScaleY = fScaleY;
    }

    // Recalculate Horizontal scaling table
    if (SrcFormat != pAvsParams->Format || fScaleX != pAvsParams->fScaleX || pAvsParams->bUse8x8Filter != bUse8x8Filter)
    {
        MOS_ZeroMemory(
            piYCoefsX,
            8 * 32 * sizeof(int32_t));

        MOS_ZeroMemory(
            piUVCoefsX,
            4 * 32 * sizeof(int32_t));

        Plane = (IS_RGB32_FORMAT(SrcFormat) && !bUse8x8Filter) ? MHW_U_PLANE : MHW_Y_PLANE;

        pAvsParams->fScaleX = fScaleX;

        if (m_scalingMode == MHW_SCALING_NEAREST)
        {
            MHW_CHK_STATUS_RETURN(Mhw_SetNearestModeTable(
                piYCoefsX,
                Plane,
                true));
            MHW_CHK_STATUS_RETURN(Mhw_SetNearestModeTable(
                piUVCoefsX,
                MHW_U_PLANE,
                true));
        }
        else
        {
            // For 1x scaling in horizontal direction and not force polyphase coefs, use special coefficients for filtering
            if ((fScaleX == 1.0F && !pAvsParams->bForcePolyPhaseCoefs))
            {
                MHW_CHK_STATUS_RETURN(Mhw_SetNearestModeTable(
                    piYCoefsX,
                    Plane,
                    true));

                // The 8-tap adaptive is enabled for all channel if RGB format input, then UV/RB use the same coefficient as Y/G
                // So, coefficient for UV/RB channels caculation can be passed
                if ((!(IS_RGB32_FORMAT(SrcFormat) && bUse8x8Filter)))
                {
                    MHW_CHK_STATUS_RETURN(Mhw_SetNearestModeTable(
                        piUVCoefsX,
                        MHW_U_PLANE,
                        true));
                }
            }
            else
            {
                // Clamp the Scaling Factor if > 1.0x
                fScaleX = MOS_MIN(1.0F, fScaleX);

                MHW_CHK_STATUS_RETURN(Mhw_CalcPolyphaseTablesY(
                    piYCoefsX,
                    fScaleX,
                    Plane,
                    SrcFormat,
                    fHPStrength,
                    bUse8x8Filter,
                    NUM_HW_POLYPHASE_TABLES,
                    0));
            }

            // The 8-tap adaptive is enabled for all channel if RGB format input, then UV/RB use the same coefficient as Y/G
            // So, coefficient for UV/RB channels caculation can be passed
            if (!(IS_RGB32_FORMAT(SrcFormat) && bUse8x8Filter))
            {
                // If Chroma Siting info is present
                if (dwChromaSiting & MHW_CHROMA_SITING_HORZ_LEFT)
                {
                    // No Chroma Siting
                    MHW_CHK_STATUS_RETURN(Mhw_CalcPolyphaseTablesUV(
                        piUVCoefsX,
                        2.0F,
                        fScaleX));
                }
                else
                {
                    // Chroma siting offset will be add in the HW cmd
                    MHW_CHK_STATUS_RETURN(Mhw_CalcPolyphaseTablesUV(
                        piUVCoefsX,
                        3.0F,
                        fScaleX));
                }
            }
        }
    }

    // Recalculate Vertical scaling table
    if (SrcFormat != pAvsParams->Format || fScaleY != pAvsParams->fScaleY || pAvsParams->bUse8x8Filter != bUse8x8Filter)
    {
        memset((void *)piYCoefsY, 0, 8 * 32 * sizeof(int32_t));

        memset((void *)piUVCoefsY, 0, 4 * 32 * sizeof(int32_t));

        Plane = (IS_RGB32_FORMAT(SrcFormat) && !bUse8x8Filter) ? MHW_U_PLANE : MHW_Y_PLANE;

        pAvsParams->fScaleY = fScaleY;

        if (m_scalingMode == MHW_SCALING_NEAREST)
        {
            MHW_CHK_STATUS_RETURN(Mhw_SetNearestModeTable(
                piYCoefsY,
                Plane,
                true));
            MHW_CHK_STATUS_RETURN(Mhw_SetNearestModeTable(
                piUVCoefsY,
                MHW_U_PLANE,
                true));
        }
        else
        {
            // For 1x scaling in vertical direction and not force polyphase coefs, use special coefficients for filtering
            if ((fScaleY == 1.0F && !pAvsParams->bForcePolyPhaseCoefs))
            {
                MHW_CHK_STATUS_RETURN(Mhw_SetNearestModeTable(
                    piYCoefsY,
                    Plane,
                    true));

                // The 8-tap adaptive is enabled for all channel if RGB format input, then UV/RB use the same coefficient as Y/G
                // So, coefficient for UV/RB channels caculation can be passed
                if ((!(IS_RGB32_FORMAT(SrcFormat) && bUse8x8Filter)))
                {
                    MHW_CHK_STATUS_RETURN(Mhw_SetNearestModeTable(
                        piUVCoefsY,
                        MHW_U_PLANE,
                        true));
                }
            }
            else
            {
                // Clamp the Scaling Factor if > 1.0x
                fScaleY = MOS_MIN(1.0F, fScaleY);

                MHW_CHK_STATUS_RETURN(Mhw_CalcPolyphaseTablesY(
                    piYCoefsY,
                    fScaleY,
                    Plane,
                    SrcFormat,
                    fHPStrength,
                    bUse8x8Filter,
                    NUM_HW_POLYPHASE_TABLES, 0));
            }

            // The 8-tap adaptive is enabled for all channel if RGB format input, then UV/RB use the same coefficient as Y/G
            // So, coefficient for UV/RB channels caculation can be passed
            if (!(IS_RGB32_FORMAT(SrcFormat) && bUse8x8Filter))
            {
                // If Chroma Siting info is present
                if (dwChromaSiting & MHW_CHROMA_SITING_VERT_TOP)
                {
                    // No Chroma Siting
                    MHW_CHK_STATUS_RETURN(Mhw_CalcPolyphaseTablesUV(
                        piUVCoefsY,
                        2.0F,
                        fScaleY));
                }
                else
                {
                    // Chroma siting offset will be add in the HW cmd
                    MHW_CHK_STATUS_RETURN(Mhw_CalcPolyphaseTablesUV(
                        piUVCoefsY,
                        3.0F,
                        fScaleY));
                }
            }
        }
    }

    // Save format used to calculate AVS parameters
    pAvsParams->Format = SrcFormat;
    // Need to recaculate if use8x8Filter changed
    pAvsParams->bUse8x8Filter = bUse8x8Filter;

    MhwSfcInterface::SetSfcAVSLumaTable(
        SrcFormat,
        pLumaTable->LumaTable,
        piYCoefsX,
        piYCoefsY,
        bUse8x8Filter);

    MhwSfcInterface::SetSfcAVSChromaTable(
        pChromaTable->ChromaTable,
        piUVCoefsX,
        piUVCoefsY);

    return MOS_STATUS_SUCCESS;
}

MhwSfcInterfaceG12::MhwSfcInterfaceG12(PMOS_INTERFACE pOsInterface) : MhwSfcInterfaceGeneric(pOsInterface)
{
    if (m_osInterface == nullptr)
    {
        MHW_ASSERTMESSAGE("Invalid Input Parameter: m_osInterface is nullptr");
        return;
    }

    // Get Memory control object directly from MOS.
    // If any override is needed, something like pfnOverrideMemoryObjectCtrl() / pfnComposeSurfaceCacheabilityControl()
    // will need to be implemented.
    m_outputSurfCtrl.Value = m_osInterface->pfnCachePolicyGetMemoryObject(
        MOS_MHW_RESOURCE_USAGE_Sfc_CurrentOutputSurface,
        m_osInterface->pfnGetGmmClientContext(m_osInterface)).DwordValue;

    m_avsLineBufferCtrl.Value = m_osInterface->pfnCachePolicyGetMemoryObject(
        MOS_MHW_RESOURCE_USAGE_Sfc_AvsLineBufferSurface,
        m_osInterface->pfnGetGmmClientContext(m_osInterface)).DwordValue;
    m_iefLineBufferCtrl.Value = m_osInterface->pfnCachePolicyGetMemoryObject(
        MOS_MHW_RESOURCE_USAGE_Sfc_IefLineBufferSurface,
        m_osInterface->pfnGetGmmClientContext(m_osInterface)).DwordValue;
    m_sfdLineBufferCtrl.Value = m_osInterface->pfnCachePolicyGetMemoryObject(
        MOS_CODEC_RESOURCE_USAGE_SURFACE_UNCACHED,
        m_osInterface->pfnGetGmmClientContext(m_osInterface)).DwordValue;
    m_avsLineTileBufferCtrl.Value = m_osInterface->pfnCachePolicyGetMemoryObject(
        MOS_CODEC_RESOURCE_USAGE_SURFACE_UNCACHED,
        m_osInterface->pfnGetGmmClientContext(m_osInterface)).DwordValue;
    m_iefLineTileBufferCtrl.Value = m_osInterface->pfnCachePolicyGetMemoryObject(
        MOS_CODEC_RESOURCE_USAGE_SURFACE_UNCACHED,
        m_osInterface->pfnGetGmmClientContext(m_osInterface)).DwordValue;
    m_sfdLineTileBufferCtrl.Value = m_osInterface->pfnCachePolicyGetMemoryObject(
        MOS_CODEC_RESOURCE_USAGE_SURFACE_UNCACHED,
        m_osInterface->pfnGetGmmClientContext(m_osInterface)).DwordValue;
    m_histogramBufferCtrl.Value = m_osInterface->pfnCachePolicyGetMemoryObject(
        MOS_CODEC_RESOURCE_USAGE_SURFACE_UNCACHED,
        m_osInterface->pfnGetGmmClientContext(m_osInterface)).DwordValue;

    m_maxWidth  = MHW_SFC_MAX_WIDTH_G12;
    m_maxHeight = MHW_SFC_MAX_HEIGHT_G12;
}

void MhwSfcInterfaceG12::IsOutPutCenterEnable(bool inputEnable)
{
    m_outputCenteringEnable = inputEnable;
}
