/*
* Copyright (c) 2017-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_decode_vp9_g12.cpp
//! \brief    Implements the decode interface extension for Gen12 VP9.
//! \details  Implements all functions required by CodecHal for Gen12 VP9 decoding.
//!

#include "codechal_decoder.h"
#include "codechal_secure_decode_interface.h"
#include "codechal_decode_vp9_g12.h"
#include "codechal_decode_sfc_vp9_g12.h"
#include "codechal_mmc_decode_vp9_g12.h"
#include "mhw_vdbox_hcp_g12_X.h"
#include "mhw_vdbox_mfx_g12_X.h"
#include "mhw_vdbox_g12_X.h"
#include "codechal_hw_g12_X.h"
#include "codechal_decode_histogram.h"
#include "mhw_mi_g12_X.h"
#include "hal_oca_interface.h"

CodechalDecodeVp9G12 ::  ~CodechalDecodeVp9G12()
{
    CODECHAL_DECODE_FUNCTION_ENTER;

    if (m_sinlgePipeVeState)
    {
        MOS_FreeMemAndSetNull(m_sinlgePipeVeState);
     }
     if (m_scalabilityState)
     {
         CodecHalDecodeScalability_Destroy_G12(m_scalabilityState);
         MOS_FreeMemAndSetNull(m_scalabilityState);
     }
     //Note: virtual engine interface destroy is done in MOS layer
  #ifdef _DECODE_PROCESSING_SUPPORTED
     if (m_sfcState)
     {
         MOS_Delete(m_sfcState);
         m_sfcState = nullptr;
     }
  #endif

     if (m_histogramSurface)
     {
         if (!Mos_ResourceIsNull(&m_histogramSurface->OsResource))
         {
             m_osInterface->pfnFreeResource(
                 m_osInterface,
                 &m_histogramSurface->OsResource);
         }
         MOS_FreeMemory(m_histogramSurface);
         m_histogramSurface = nullptr;
     }
}

CodechalDecodeVp9G12::CodechalDecodeVp9G12(
    CodechalHwInterface *   hwInterface,
    CodechalDebugInterface *debugInterface,
    PCODECHAL_STANDARD_INFO standardInfo) : CodechalDecodeVp9(hwInterface, debugInterface, standardInfo),
                                            m_frameSizeMaxAlloced(0),
                                            m_sinlgePipeVeState(nullptr),
                                            m_scalabilityState(nullptr)
{
    CODECHAL_DECODE_FUNCTION_ENTER;

    CODECHAL_DECODE_CHK_NULL_NO_STATUS_RETURN(m_osInterface);

    m_osInterface->pfnVirtualEngineSupported(m_osInterface, true, true);

#if (_DEBUG || _RELEASE_INTERNAL)
    MOS_USER_FEATURE_VALUE_DATA userFeatureData;
    MOS_ZeroMemory(&userFeatureData, sizeof(userFeatureData));
    MOS_UserFeature_ReadValue_ID(
        nullptr,
        __MEDIA_USER_FEATURE_VALUE_DECODE_HISTOGRAM_DEBUG_ID,
        &userFeatureData,
        m_osInterface->pOsContext);
    m_histogramDebug = userFeatureData.u32Data ? true : false;
#endif
}

MOS_STATUS CodechalDecodeVp9G12::SetGpuCtxCreatOption(
    CodechalSetting *codecHalSetting)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_DECODE_FUNCTION_ENTER;

    if (!MOS_VE_CTXBASEDSCHEDULING_SUPPORTED(m_osInterface))
    {
        CodechalDecode::SetGpuCtxCreatOption(codecHalSetting);
    }
    else
    {
        m_gpuCtxCreatOpt = MOS_New(MOS_GPUCTX_CREATOPTIONS_ENHANCED);
        CODECHAL_DECODE_CHK_NULL_RETURN(m_gpuCtxCreatOpt);

        if (static_cast<MhwVdboxMfxInterfaceG12 *>(m_mfxInterface)->IsScalabilitySupported())
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(CodechalDecodeScalability_ConstructParmsForGpuCtxCreation_g12(
                m_scalabilityState,
                (PMOS_GPUCTX_CREATOPTIONS_ENHANCED)m_gpuCtxCreatOpt,
                codecHalSetting));

            if (((PMOS_GPUCTX_CREATOPTIONS_ENHANCED)m_gpuCtxCreatOpt)->LRCACount == 2)
            {
                m_videoContext = MOS_VE_MULTINODESCALING_SUPPORTED(m_osInterface) ? MOS_GPU_CONTEXT_VIDEO5 : MOS_GPU_CONTEXT_VDBOX2_VIDEO;

                CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnCreateGpuContext(
                    m_osInterface,
                    m_videoContext,
                    MOS_GPU_NODE_VIDEO,
                    m_gpuCtxCreatOpt));

                MOS_GPUCTX_CREATOPTIONS createOption;
                CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnCreateGpuContext(
                    m_osInterface,
                    MOS_GPU_CONTEXT_VIDEO,
                    m_videoGpuNode,
                    &createOption));
            }
            else if (((PMOS_GPUCTX_CREATOPTIONS_ENHANCED)m_gpuCtxCreatOpt)->LRCACount == 3)
            {
                m_videoContext = MOS_VE_MULTINODESCALING_SUPPORTED(m_osInterface) ? MOS_GPU_CONTEXT_VIDEO7 : MOS_GPU_CONTEXT_VDBOX2_VIDEO2;

                CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnCreateGpuContext(
                    m_osInterface,
                    m_videoContext,
                    MOS_GPU_NODE_VIDEO,
                    m_gpuCtxCreatOpt));

                MOS_GPUCTX_CREATOPTIONS createOption;
                CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnCreateGpuContext(
                    m_osInterface,
                    MOS_GPU_CONTEXT_VIDEO,
                    m_videoGpuNode,
                    &createOption));
            }
            else
            {
                m_videoContext = MOS_GPU_CONTEXT_VIDEO;
            }
        }
        else
        {
            bool sfcInUse = (codecHalSetting->sfcInUseHinted && codecHalSetting->downsamplingHinted 
                                && (MEDIA_IS_SKU(m_skuTable, FtrSFCPipe) && !MEDIA_IS_SKU(m_skuTable, FtrDisableVDBox2SFC)));
            CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalDecodeSinglePipeVE_ConstructParmsForGpuCtxCreation(
                m_sinlgePipeVeState,
                (PMOS_GPUCTX_CREATOPTIONS_ENHANCED)m_gpuCtxCreatOpt,
                sfcInUse));

            m_videoContext = MOS_GPU_CONTEXT_VIDEO;
        }
    }

    return eStatus;
}

MOS_STATUS CodechalDecodeVp9G12 :: AllocateResourcesVariableSizes()
{
    MOS_STATUS              eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_DECODE_FUNCTION_ENTER;

#ifdef _MMC_SUPPORTED
    // To WA invalid aux data caused HW issue when MMC on
    if (m_mmc && m_mmc->IsMmcEnabled() && MEDIA_IS_WA(m_waTable, Wa_1408785368) &&
        !Mos_ResourceIsNull(&m_destSurface.OsResource) &&
        m_destSurface.OsResource.bConvertedFromDDIResource)
    {
        if (m_secureDecoder && m_secureDecoder->IsAuxDataInvalid(&m_destSurface.OsResource))
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(m_secureDecoder->InitAuxSurface(&m_destSurface.OsResource, false, true));
        }
        else
        {
            CODECHAL_DECODE_VERBOSEMESSAGE("Clear CCS by VE resolve before frame %d submission", m_frameNum);
            CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnDecompResource(m_osInterface, &m_destSurface.OsResource));
            CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnSetGpuContext(m_osInterface, m_videoContext));
        }
    }
#endif

    if (CodecHalDecodeScalabilityIsScalableMode(m_scalabilityState))
    {
        uint32_t widthInSb  = MOS_ROUNDUP_DIVIDE(m_width, CODEC_VP9_SUPER_BLOCK_WIDTH);
        uint32_t heightInSb = MOS_ROUNDUP_DIVIDE(m_height, CODEC_VP9_SUPER_BLOCK_HEIGHT);
        uint32_t frameSizeMax = MOS_MAX((m_copyDataBufferInUse ? m_copyDataBufferSize : m_dataSize), m_frameSizeMaxAlloced);
        uint8_t  maxBitDepth  = 8 + m_vp9DepthIndicator * 2;
        uint8_t  chromaFormat = m_chromaFormatinProfile;

        MHW_VDBOX_HCP_BUFFER_SIZE_PARAMS    hcpBufSizeParam;
        MOS_ZeroMemory(&hcpBufSizeParam, sizeof(hcpBufSizeParam));
        hcpBufSizeParam.ucMaxBitDepth  = maxBitDepth;
        hcpBufSizeParam.ucChromaFormat = chromaFormat;
        hcpBufSizeParam.dwPicWidth     = widthInSb;
        hcpBufSizeParam.dwPicHeight    = heightInSb;
        hcpBufSizeParam.dwMaxFrameSize = frameSizeMax;

        MHW_VDBOX_HCP_BUFFER_REALLOC_PARAMS reallocParam;
        MOS_ZeroMemory(&reallocParam, sizeof(reallocParam));
        reallocParam.ucMaxBitDepth       = maxBitDepth;
        reallocParam.ucChromaFormat      = chromaFormat;
        reallocParam.dwPicWidth          = widthInSb;
        reallocParam.dwPicWidthAlloced   = m_allocatedWidthInSb;
        reallocParam.dwPicHeight         = heightInSb;
        reallocParam.dwPicHeightAlloced  = m_allocatedHeightInSb;
        reallocParam.dwFrameSize         = frameSizeMax;
        reallocParam.dwFrameSizeAlloced  = m_frameSizeMaxAlloced;
        CODECHAL_DECODE_CHK_STATUS_RETURN(
            CodecHalDecodeScalability_AllocateResources_VariableSizes_G12(
                m_scalabilityState,
                &hcpBufSizeParam,
                &reallocParam));

        m_frameSizeMaxAlloced = frameSizeMax;
    }

    CODECHAL_DECODE_CHK_STATUS_RETURN(CodechalDecodeVp9 ::AllocateResourcesVariableSizes());

    return eStatus;
}

MOS_STATUS CodechalDecodeVp9G12::InitSfcState()
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
#ifdef _DECODE_PROCESSING_SUPPORTED
    // Check if SFC can be supported
    CODECHAL_DECODE_CHK_STATUS_RETURN(m_sfcState->CheckAndInitialize(
        (DecodeProcessingParams *)m_decodeParams.m_procParams, 
        m_vp9PicParams, 
        m_scalabilityState));
#endif
    return eStatus;
}

MOS_STATUS CodechalDecodeVp9G12::CalcDownsamplingParams(
    void                        *picParams,
    uint32_t                    *refSurfWidth,
    uint32_t                    *refSurfHeight,
    MOS_FORMAT                  *format,
    uint8_t                     *frameIdx)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_DECODE_CHK_NULL_RETURN(picParams);
    CODECHAL_DECODE_CHK_NULL_RETURN(refSurfWidth);
    CODECHAL_DECODE_CHK_NULL_RETURN(refSurfHeight);
    CODECHAL_DECODE_CHK_NULL_RETURN(format);
    CODECHAL_DECODE_CHK_NULL_RETURN(frameIdx);

    PCODEC_VP9_PIC_PARAMS vp9PicParams = (PCODEC_VP9_PIC_PARAMS)picParams;

    *refSurfWidth = 0;
    *refSurfHeight = 0;
    *format = Format_NV12;
    *frameIdx = vp9PicParams->CurrPic.FrameIdx;


    *refSurfWidth = MOS_ALIGN_CEIL(vp9PicParams->FrameWidthMinus1 + 1, CODEC_VP9_SUPER_BLOCK_WIDTH);
    *refSurfHeight = MOS_ALIGN_CEIL(vp9PicParams->FrameHeightMinus1 + 1, CODEC_VP9_SUPER_BLOCK_HEIGHT);

    if (vp9PicParams->subsampling_x == 1 && vp9PicParams->subsampling_y == 1) //HCP_CHROMA_FORMAT_YUV420
    {
        if (vp9PicParams->BitDepthMinus8 > 2)
        {
            *format = Format_P016;
        }
        else if (vp9PicParams->BitDepthMinus8 > 0)
        {
            *format = Format_P010;
        }
        else
        {
            *format = Format_NV12;
        }
    }
    else if (vp9PicParams->subsampling_x == 0 && vp9PicParams->subsampling_y == 0) //HCP_CHROMA_FORMAT_YUV444
    {
        if (vp9PicParams->BitDepthMinus8 > 2)
        {
            *format = Format_Y416;
        }
        else if (vp9PicParams->BitDepthMinus8 > 0)
        {
            *format = Format_Y410;
        }
        else
        {
            *format = Format_AYUV;
        }
    }
    else
    {
        CODECHAL_DECODE_ASSERTMESSAGE("Invalid Chroma sampling format!");
        eStatus = MOS_STATUS_INVALID_PARAMETER;
        return eStatus;
    }
    return eStatus;
}

MOS_STATUS CodechalDecodeVp9G12 :: InitializeDecodeMode ()
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_DECODE_FUNCTION_ENTER;

    if ( MOS_VE_SUPPORTED(m_osInterface) && static_cast<MhwVdboxMfxInterfaceG12*>(m_mfxInterface)->IsScalabilitySupported())
    {
        CODECHAL_DECODE_SCALABILITY_INIT_PARAMS_G12  initParams;

        MOS_ZeroMemory(&initParams, sizeof(initParams));
        initParams.u32PicWidthInPixel  = m_usFrameWidthAlignedMinBlk;
        initParams.u32PicHeightInPixel = m_usFrameHeightAlignedMinBlk;
        initParams.format              = m_decodeParams.m_destSurface->Format;
        initParams.gpuCtxInUse         = GetVideoContext();
        initParams.usingSecureDecode   = (m_secureDecoder != nullptr);
        if (m_decodeHistogram == nullptr)
        {
            initParams.usingHistogram = false;
#if (_DEBUG || _RELEASE_INTERNAL)
            if (m_histogramDebug)
            {
                initParams.usingHistogram = true;
            }
#endif
        }
        else
        {
            initParams.usingHistogram = true;
        }
        CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalDecodeScalability_InitScalableParams_G12(
            m_scalabilityState,
            &initParams,
            &m_decodePassNum));

        if (MOS_VE_CTXBASEDSCHEDULING_SUPPORTED(m_osInterface))
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(CodechalDecodeScalability_ChkGpuCtxReCreation(
                m_scalabilityState,
                (PMOS_GPUCTX_CREATOPTIONS_ENHANCED)m_gpuCtxCreatOpt));
            SetVideoContext(m_scalabilityState->VideoContext);
        }

    }

    return eStatus;
}

MOS_STATUS CodechalDecodeVp9G12::DetermineDecodePhase()
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_DECODE_FUNCTION_ENTER;

    if (static_cast<MhwVdboxMfxInterfaceG12*>(m_mfxInterface)->IsScalabilitySupported())
    {
        CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalDecodeScalability_DetermineDecodePhase_G12(
            m_scalabilityState,
            &m_hcpDecPhase));
    }
    else
    {
        CODECHAL_DECODE_CHK_STATUS_RETURN(CodechalDecodeVp9 :: DetermineDecodePhase());
    }

    return eStatus;
}

MOS_STATUS CodechalDecodeVp9G12::SetAndPopulateVEHintParams(
    PMOS_COMMAND_BUFFER       primCmdBuf)
{
    MOS_STATUS                      eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_DECODE_FUNCTION_ENTER;

    if (static_cast<MhwVdboxMfxInterfaceG12*>(m_mfxInterface)->IsScalabilitySupported())
    {
        CODECHAL_DECODE_SCALABILITY_SETHINT_PARMS scalSetParms;
        MOS_ZeroMemory(&scalSetParms, sizeof(CODECHAL_DECODE_SCALABILITY_SETHINT_PARMS));
        if (!MOS_VE_CTXBASEDSCHEDULING_SUPPORTED(m_osInterface))
        {
            scalSetParms.bNeedSyncWithPrevious       = true;
            scalSetParms.bSameEngineAsLastSubmission = false;
            scalSetParms.bSFCInUse                   = false;
        }
        CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalDecodeScalability_SetHintParams_G12(m_scalabilityState, &scalSetParms));
        CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalDecodeScalability_PopulateHintParams(m_scalabilityState, primCmdBuf));
    }
    else
    {
        if (!MOS_VE_CTXBASEDSCHEDULING_SUPPORTED(m_osInterface))
        {
            MOS_VIRTUALENGINE_SET_PARAMS  vesetParams;
            MOS_ZeroMemory(&vesetParams, sizeof(vesetParams));
            vesetParams.bNeedSyncWithPrevious       = true;
            vesetParams.bSameEngineAsLastSubmission = false;
            vesetParams.bSFCInUse                   = false;
            CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalDecodeSinglePipeVE_SetHintParams(m_sinlgePipeVeState, &vesetParams));
        }
        CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalDecodeSinglePipeVE_PopulateHintParams(m_sinlgePipeVeState, primCmdBuf, true));
    }

    return eStatus;
}

MOS_STATUS CodechalDecodeVp9G12::DetermineSendProlgwithFrmTracking(
    bool                        *sendPrologWithFrameTracking)
{
    MOS_STATUS       eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_DECODE_FUNCTION_ENTER;

    CODECHAL_DECODE_CHK_NULL_RETURN(sendPrologWithFrameTracking);

    if (CodecHalDecodeScalabilityIsScalableMode(m_scalabilityState))
    {
        if (CodecHalDecodeScalability1stPhaseofSubmission(m_scalabilityState))
        {
            *sendPrologWithFrameTracking = true;
        }
    }
    else
    {
        *sendPrologWithFrameTracking = true;
    }

    return eStatus;
}

uint32_t CodechalDecodeVp9G12::RequestedSpaceSize(uint32_t requestedSize)
{
    if (m_scalabilityState && m_scalabilityState->bScalableDecodeMode)
    {
        //primary cmd buffer only including cmd buffer header .
        return COMMAND_BUFFER_RESERVED_SPACE * 2;
    }
    else
    {
        return requestedSize;
    }
}

MOS_STATUS CodechalDecodeVp9G12::VerifyExtraSpace(
    uint32_t requestedSize,
    uint32_t additionalSizeNeeded)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_DECODE_FUNCTION_ENTER;

    if (m_scalabilityState && m_scalabilityState->bScalableDecodeMode)
    {
        eStatus = MOS_STATUS_NO_SPACE;

        // Try a maximum of 3 attempts to request the required sizes from OS
        // OS could reset the sizes if necessary, therefore, requires to re-verify
        for (auto i = 0; (i < 3) && (eStatus != MOS_STATUS_SUCCESS); i++)
        {
            // Verify secondary cmd buffer
            eStatus = (MOS_STATUS)m_osInterface->pfnVerifyCommandBufferSize(
                m_osInterface,
                requestedSize,
                MOS_VE_HAVE_SECONDARY_CMDBUFFER);

            // Resize command buffer if not enough
            if (eStatus != MOS_STATUS_SUCCESS)
            {
                CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnResizeCommandBufferAndPatchList(
                    m_osInterface,
                    requestedSize + additionalSizeNeeded,
                    0,
                    MOS_VE_HAVE_SECONDARY_CMDBUFFER));
                // Set status to NO_SPACE to enter the commaned buffer size verification on next loop.
                eStatus = MOS_STATUS_NO_SPACE;
            }
        }
    }

    return eStatus;
}

MOS_STATUS CodechalDecodeVp9G12::AllocateHistogramSurface()
{
    MOS_ALLOC_GFXRES_PARAMS allocParams;

    if (m_histogramSurface == nullptr)
    {
        m_histogramSurface = (MOS_SURFACE*)MOS_AllocAndZeroMemory(sizeof(MOS_SURFACE));
        CODECHAL_DECODE_CHK_NULL_RETURN(m_histogramSurface);

        MOS_ZeroMemory(&allocParams, sizeof(MOS_ALLOC_GFXRES_PARAMS));
        allocParams.Type = MOS_GFXRES_BUFFER;
        allocParams.TileType = MOS_TILE_LINEAR;
        allocParams.Format = Format_Buffer;
        allocParams.dwBytes = 256 * 4;
        allocParams.pBufName = "HistogramStreamOut";

        CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnAllocateResource(
            m_osInterface,
            &allocParams,
            &m_histogramSurface->OsResource));

        CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalGetResourceInfo(
            m_osInterface,
            m_histogramSurface));
    }

    if(m_decodeHistogram)
        m_decodeHistogram->SetSrcHistogramSurface(m_histogramSurface);

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalDecodeVp9G12::AddPicStateMhwCmds(
    PMOS_COMMAND_BUFFER       cmdBuffer)
{
    MOS_STATUS                              eStatus = MOS_STATUS_SUCCESS;
    MHW_MI_VD_CONTROL_STATE_PARAMS          vdCtrlParam;

    CODECHAL_DECODE_FUNCTION_ENTER;

    CODECHAL_DECODE_CHK_NULL_RETURN(cmdBuffer);

    // Send VD_CONTROL_STATE Pipe Initialization
    MOS_ZeroMemory(&vdCtrlParam, sizeof(MHW_MI_VD_CONTROL_STATE_PARAMS));
    vdCtrlParam.initialization = true;
    CODECHAL_DECODE_CHK_STATUS_RETURN(static_cast<MhwMiInterfaceG12 *>(m_miInterface)->AddMiVdControlStateCmd(cmdBuffer, &vdCtrlParam));

    CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->AddHcpPipeModeSelectCmd(
        cmdBuffer,
        m_picMhwParams.PipeModeSelectParams));

    if (CodecHalDecodeScalabilityIsScalableMode(m_scalabilityState) &&
        CodecHalDecodeScalabilityIsBEPhaseG12(m_scalabilityState))
    {
        // Send VD_CONTROL_STATE HcpPipeLock
        MOS_ZeroMemory(&vdCtrlParam, sizeof(MHW_MI_VD_CONTROL_STATE_PARAMS));
        vdCtrlParam.scalableModePipeLock = true;
        CODECHAL_DECODE_CHK_STATUS_RETURN(static_cast<MhwMiInterfaceG12 *>(m_miInterface)->AddMiVdControlStateCmd(cmdBuffer, &vdCtrlParam));
    }
#ifdef _DECODE_PROCESSING_SUPPORTED
    if (!CodecHalDecodeScalabilityIsFEPhase(m_scalabilityState))
    {
        CODECHAL_DECODE_CHK_STATUS_RETURN(m_sfcState->AddSfcCommands(cmdBuffer));
    }
#endif
#ifdef _MMC_SUPPORTED
    CODECHAL_DECODE_CHK_STATUS_RETURN(m_mmc->SetSurfaceState(m_picMhwParams.SurfaceParams[0]));
#endif
    CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->AddHcpSurfaceCmd(
        cmdBuffer,
        m_picMhwParams.SurfaceParams[0]));

    // For non-key frame, send extra surface commands for reference pictures
    if (m_vp9PicParams->PicFlags.fields.frame_type == CODEC_VP9_INTER_FRAME &&
        !m_vp9PicParams->PicFlags.fields.intra_only)
    {
#ifdef _MMC_SUPPORTED
        //Get each reference surface state and be recorded by skipMask if current surface state is mmc disabled
        uint8_t skipMask = 0xf8;
        for (uint8_t i = 1; i < 4; i++)
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(m_mmc->SetSurfaceState(m_picMhwParams.SurfaceParams[i]));
            if (m_picMhwParams.SurfaceParams[i]->mmcState == MOS_MEMCOMP_DISABLED)
            {
                skipMask |= (1 << (i - 1));
            }
        }
        CODECHAL_DECODE_NORMALMESSAGE("MMC skip mask is %d\n", skipMask);
        for (uint8_t i = 1; i < 4; i++)
        {
            //Set each ref surface state as MOS_MEMCOMP_MC to satisfy MmcEnable in AddHcpSurfaceCmd
            //Because each ref surface state should be programmed as the same
            //The actual mmc state is recorded by skipMask and set each ref surface too
            m_picMhwParams.SurfaceParams[i]->mmcState    = MOS_MEMCOMP_MC;
            m_picMhwParams.SurfaceParams[i]->mmcSkipMask = skipMask;
        }
#endif
        for (uint8_t i = 1; i < 4; i++)
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->AddHcpSurfaceCmd(
                cmdBuffer,
                m_picMhwParams.SurfaceParams[i]));
        }
    }

    CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->AddHcpPipeBufAddrCmd(
        cmdBuffer,
        m_picMhwParams.PipeBufAddrParams));

    CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->AddHcpIndObjBaseAddrCmd(
        cmdBuffer,
        m_picMhwParams.IndObjBaseAddrParams));

    if (m_cencBuf)
    {
        CODECHAL_DECODE_CHK_STATUS_RETURN(SetCencBatchBuffer(cmdBuffer));
    }
    else
    {
        for (uint8_t i = 0; i < CODEC_VP9_MAX_SEGMENTS; i++)
        {
            // Error handling for illegal programming on segmentation fields @ KEY/INTRA_ONLY frames
            PCODEC_VP9_SEG_PARAMS vp9SegData = &(m_picMhwParams.Vp9SegmentState->pVp9SegmentParams->SegData[i]);
            if (vp9SegData->SegmentFlags.fields.SegmentReferenceEnabled &&
                (!m_vp9PicParams->PicFlags.fields.frame_type || m_vp9PicParams->PicFlags.fields.intra_only))
            {
                vp9SegData->SegmentFlags.fields.SegmentReference = CODECHAL_DECODE_VP9_INTRA_FRAME;
            }

            m_picMhwParams.Vp9SegmentState->ucCurrentSegmentId = i;
            CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->AddHcpVp9SegmentStateCmd(
                cmdBuffer,
                nullptr,
                m_picMhwParams.Vp9SegmentState));

            if (m_vp9PicParams->PicFlags.fields.segmentation_enabled == 0)
            {
                break;
            }
        }

        CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->AddHcpVp9PicStateCmd(
            cmdBuffer,
            nullptr,
            m_picMhwParams.Vp9PicState));

        if (m_secureDecoder)
        {
            // Add secure decode command
            CODECHAL_DECODE_CHK_STATUS_RETURN(m_secureDecoder->AddHcpSecureState(
                cmdBuffer,
                this));
        }
    }
    return eStatus;
}

MOS_STATUS CodechalDecodeVp9G12::SetFrameStates()
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;


#ifdef _DECODE_PROCESSING_SUPPORTED
    if (m_decodeParams.m_procParams)
    {
        CODECHAL_DECODE_CHK_STATUS_RETURN(AllocateHistogramSurface());

        ((DecodeProcessingParams *)m_decodeParams.m_procParams)->m_histogramSurface = m_histogramSurface;

        if(m_decodeHistogram)
            m_decodeHistogram->SetSrcHistogramSurface(m_histogramSurface);

    }
#endif

    CodechalDecodeVp9::SetFrameStates();

    return eStatus;
}

MOS_STATUS CodechalDecodeVp9G12 :: DecodeStateLevel()
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    PERF_UTILITY_AUTO(__FUNCTION__, PERF_DECODE, PERF_LEVEL_HAL);
    CODECHAL_DECODE_FUNCTION_ENTER;

    CODECHAL_DECODE_CHK_NULL_RETURN(m_hwInterface->GetCpInterface());

    if (m_secureDecoder && m_hcpDecPhase == CodechalHcpDecodePhaseInitialized)
    {
        CODECHAL_DECODE_CHK_STATUS_RETURN(m_secureDecoder->Execute(this));
    }

    //HCP Decode Phase State Machine
    DetermineDecodePhase();

    if (CodecHalDecodeScalabilityIsScalableMode(m_scalabilityState))
    {
        //Switch GPU context when necessary
        CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalDecodeScalability_SwitchGpuContext(m_scalabilityState));
    }

    MOS_COMMAND_BUFFER primCmdBuffer;
    CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnGetCommandBuffer(m_osInterface, &primCmdBuffer, 0));

    bool sendPrologWithFrameTracking;
    CODECHAL_DECODE_CHK_STATUS_RETURN(DetermineSendProlgwithFrmTracking(&sendPrologWithFrameTracking));
    if (sendPrologWithFrameTracking)
    {
        if (!CodecHalDecodeScalabilityIsScalableMode(m_scalabilityState))
        {
            MHW_MI_FORCE_WAKEUP_PARAMS forceWakeupParams;
            MOS_ZeroMemory(&forceWakeupParams, sizeof(MHW_MI_FORCE_WAKEUP_PARAMS));
            forceWakeupParams.bMFXPowerWellControl = false;
            forceWakeupParams.bMFXPowerWellControlMask = true;
            forceWakeupParams.bHEVCPowerWellControl = true;
            forceWakeupParams.bHEVCPowerWellControlMask = true;
            CODECHAL_DECODE_CHK_STATUS_RETURN(m_miInterface->AddMiForceWakeupCmd(
                &primCmdBuffer,
                &forceWakeupParams));
        }
        //Frame tracking functionality is called at the start of primary command buffer.
        CODECHAL_DECODE_CHK_STATUS_RETURN(SendPrologWithFrameTracking(
            &primCmdBuffer, true));
    }

    PMOS_COMMAND_BUFFER cmdBufferInUse = &primCmdBuffer;
    MOS_COMMAND_BUFFER  scdryCmdBuffer;
    auto                mmioRegisters = m_hwInterface->GetMfxInterface()->GetMmioRegisters(m_vdboxIndex);

    if (CodecHalDecodeScalabilityIsScalableMode(m_scalabilityState) && MOS_VE_SUPPORTED(m_osInterface))
    {
        CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalDecodeScalability_GetCmdBufferToUse_G12(
            m_scalabilityState,
            &scdryCmdBuffer,
            &cmdBufferInUse));

        MHW_MI_FORCE_WAKEUP_PARAMS forceWakeupParams;
        MOS_ZeroMemory(&forceWakeupParams, sizeof(MHW_MI_FORCE_WAKEUP_PARAMS));
        forceWakeupParams.bMFXPowerWellControl = false;
        forceWakeupParams.bMFXPowerWellControlMask = true;
        forceWakeupParams.bHEVCPowerWellControl = true;
        forceWakeupParams.bHEVCPowerWellControlMask = true;
        CODECHAL_DECODE_CHK_STATUS_RETURN(m_miInterface->AddMiForceWakeupCmd(
            cmdBufferInUse,
            &forceWakeupParams));

        if (cmdBufferInUse == &scdryCmdBuffer)
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(SendPrologWithFrameTracking(cmdBufferInUse, false));
        }

        HalOcaInterface::On1stLevelBBStart(scdryCmdBuffer, *m_osInterface->pOsContext, m_osInterface->CurrentGpuContextHandle, *m_miInterface, *mmioRegisters);

    }
    else
    {
        HalOcaInterface::On1stLevelBBStart(primCmdBuffer, *m_osInterface->pOsContext, m_osInterface->CurrentGpuContextHandle, *m_miInterface, *mmioRegisters);
    }

    auto pipeModeSelectParams =
        static_cast<PMHW_VDBOX_PIPE_MODE_SELECT_PARAMS_G12>(m_picMhwParams.PipeModeSelectParams);
    *pipeModeSelectParams = {};
    auto pipeBufAddrParams =
        static_cast<PMHW_VDBOX_PIPE_BUF_ADDR_PARAMS_G12>(m_picMhwParams.PipeBufAddrParams);
    *pipeBufAddrParams = {};
    CODECHAL_DECODE_CHK_STATUS_RETURN(InitPicStateMhwParams());

    bool secureDecodeStartStatusFlag = true;
    if (CodecHalDecodeScalabilityIsScalableMode(m_scalabilityState))
    {
        // Put all SecureDecode/Start Status related cmd into FE VDBOX
        secureDecodeStartStatusFlag = CodecHalDecodeScalabilityIsFEPhase(m_scalabilityState);
       
        CodecHalDecodeScalablity_DecPhaseToHwWorkMode_G12(
            pipeModeSelectParams->MultiEngineMode,
            pipeModeSelectParams->PipeWorkMode);

        pipeBufAddrParams->presCABACSyntaxStreamOutBuffer =
            m_scalabilityState->presCABACStreamOutBuffer;
        pipeBufAddrParams->presIntraPredUpRightColStoreBuffer =
            &m_scalabilityState->resIntraPredUpRightColStoreBuffer;
        pipeBufAddrParams->presIntraPredLeftReconColStoreBuffer =
            &m_scalabilityState->resIntraPredLeftReconColStoreBuffer;
    }

    if (secureDecodeStartStatusFlag)
    {
        CODECHAL_DECODE_CHK_STATUS_RETURN(UpdatePicStateBuffers(cmdBufferInUse));

        if (m_statusQueryReportingEnabled)
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(StartStatusReport(
                cmdBufferInUse));
        }
        else
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(NullHW::StartPredicate(m_osInterface, m_miInterface, cmdBufferInUse));
        }
    }
    else
    {
        CODECHAL_DECODE_CHK_STATUS_RETURN(NullHW::StartPredicate(m_osInterface, m_miInterface, cmdBufferInUse));
    }

    if (CodecHalDecodeScalabilityIsScalableMode(m_scalabilityState))
    {
        CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalDecodeScalability_FEBESync_G12(
            m_scalabilityState,
            cmdBufferInUse,
            m_osInterface->phasedSubmission));
        if (m_perfFEBETimingEnabled && CodecHalDecodeScalabilityIsLastCompletePhase(m_scalabilityState))
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(m_perfProfiler->AddPerfCollectStartCmd((void *)this, m_osInterface, m_miInterface, &scdryCmdBuffer));
        }
    }

    if (CodecHalDecodeScalabilityIsBEPhaseG12(m_scalabilityState))
    {
        CODECHAL_DECODE_CHK_STATUS_RETURN(m_miInterface->AddWatchdogTimerStartCmd(cmdBufferInUse));
    }

    CODECHAL_DECODE_CHK_STATUS_RETURN(AddPicStateMhwCmds(
        cmdBufferInUse));

    if (CodecHalDecodeScalabilityIsBEPhaseG12(m_scalabilityState))
    {
        MHW_VDBOX_HCP_TILE_CODING_PARAMS_G12  hcpTileCodingParam;
        CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalDecodeScalability_CalculateHcpTileCodingParams<MHW_VDBOX_HCP_TILE_CODING_PARAMS_G12>(
            m_scalabilityState,
            m_vp9PicParams,
            &hcpTileCodingParam));
        //insert 2 dummy VD_CONTROL_STATE packets with data=0 before every HCP_TILE_CODING
        if (MEDIA_IS_WA(m_waTable, Wa_14010222001))
        {
            MHW_MI_VD_CONTROL_STATE_PARAMS vdCtrlParam;
            MOS_ZeroMemory(&vdCtrlParam, sizeof(MHW_MI_VD_CONTROL_STATE_PARAMS));
            for (int i = 0; i < 2; i++)
            {
                CODECHAL_DECODE_CHK_STATUS_RETURN(static_cast<MhwMiInterfaceG12 *>(m_miInterface)->AddMiVdControlStateCmd(cmdBufferInUse, &vdCtrlParam));
            }
        }
        CODECHAL_DECODE_CHK_STATUS_RETURN(static_cast<MhwVdboxHcpInterfaceG12*>(m_hcpInterface)->AddHcpTileCodingCmd(
            cmdBufferInUse,
            &hcpTileCodingParam));
    }

    m_osInterface->pfnReturnCommandBuffer(m_osInterface, &primCmdBuffer, 0);
    if (CodecHalDecodeScalabilityIsScalableMode(m_scalabilityState) && MOS_VE_SUPPORTED(m_osInterface))
    {
        CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalDecodeScalability_ReturnSdryCmdBuffer_G12(m_scalabilityState, &scdryCmdBuffer));
    }

    return eStatus;
}

MOS_STATUS CodechalDecodeVp9G12 :: DecodePrimitiveLevel()
{
    MOS_STATUS                          eStatus = MOS_STATUS_SUCCESS;
    MHW_MI_VD_CONTROL_STATE_PARAMS      vdCtrlParam;

    PERF_UTILITY_AUTO(__FUNCTION__, PERF_DECODE, PERF_LEVEL_HAL);

    CODECHAL_DECODE_FUNCTION_ENTER;

    // Bitstream is incomplete, don't do any decoding work.
    if (m_incompletePicture)
    {
        eStatus = MOS_STATUS_SUCCESS;
        return eStatus;
    }

    CODECHAL_DECODE_CHK_NULL_RETURN(m_osInterface);

    CODECHAL_DECODE_CHK_COND_RETURN(
        (m_vdboxIndex > m_mfxInterface->GetMaxVdboxIndex()),
        "ERROR - vdbox index exceed the maximum");

    m_osInterface->pfnSetPerfTag(
        m_osInterface,
        (uint16_t)(((m_mode << 4) & 0xF0) | (m_perfType & 0xF)));
    m_osInterface->pfnResetPerfBufferID(m_osInterface);

    MOS_COMMAND_BUFFER primCmdBuffer;
    CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnGetCommandBuffer(m_osInterface, &primCmdBuffer, 0));

    PMOS_COMMAND_BUFFER cmdBufferInUse = &primCmdBuffer;
    MOS_COMMAND_BUFFER  scdryCmdBuffer;
    if (CodecHalDecodeScalabilityIsScalableMode(m_scalabilityState) && MOS_VE_SUPPORTED(m_osInterface))
    {
        CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalDecodeScalability_GetCmdBufferToUse_G12(
            m_scalabilityState,
            &scdryCmdBuffer,
            &cmdBufferInUse));
        CodecHalDecodeScalability_DecPhaseToSubmissionType_G12(m_scalabilityState,cmdBufferInUse);
    }

    // store CS ENGINE ID register
    if (static_cast<MhwVdboxMfxInterfaceG12*>(m_mfxInterface)->IsScalabilitySupported())
    {
        CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalDecodeScalability_ReadCSEngineIDReg_G12(
            m_scalabilityState,
            &m_decodeStatusBuf,
            cmdBufferInUse));
    }

    //no slice level command for Huc based DRM and scalability decode BE phases
    if (m_cencBuf == nullptr && !CodecHalDecodeScalabilityIsBEPhaseG12(m_scalabilityState))
    {
        MHW_VDBOX_HCP_BSD_PARAMS bsdParams;
        MOS_ZeroMemory(&bsdParams, sizeof(bsdParams));
        bsdParams.dwBsdDataLength =
            m_vp9PicParams->BSBytesInBuffer - m_vp9PicParams->UncompressedHeaderLengthInBytes;
        bsdParams.dwBsdDataStartOffset = m_vp9PicParams->UncompressedHeaderLengthInBytes;

        CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->AddHcpBsdObjectCmd(
            cmdBufferInUse,
            &bsdParams));
    }

    // Send VD_CONTROL_STATE Memory Implict Flush
    MOS_ZeroMemory(&vdCtrlParam, sizeof(MHW_MI_VD_CONTROL_STATE_PARAMS));
    vdCtrlParam.memoryImplicitFlush = true;
    CODECHAL_DECODE_CHK_STATUS_RETURN(static_cast<MhwMiInterfaceG12 *>(m_miInterface)->AddMiVdControlStateCmd(cmdBufferInUse, &vdCtrlParam));

    if (CodecHalDecodeScalabilityIsScalableMode(m_scalabilityState) &&
        CodecHalDecodeScalabilityIsBEPhaseG12(m_scalabilityState))
    {
        // Send VD_CONTROL_STATE HCP Pipe Unlock
        MOS_ZeroMemory(&vdCtrlParam, sizeof(MHW_MI_VD_CONTROL_STATE_PARAMS));
        vdCtrlParam.scalableModePipeUnlock = true;
        CODECHAL_DECODE_CHK_STATUS_RETURN(static_cast<MhwMiInterfaceG12 *>(m_miInterface)->AddMiVdControlStateCmd(cmdBufferInUse, &vdCtrlParam));
    }

    // Send VD Pipe Flush command for SKL+
    MHW_VDBOX_VD_PIPE_FLUSH_PARAMS vdpipeFlushParams;
    MOS_ZeroMemory(&vdpipeFlushParams, sizeof(vdpipeFlushParams));
    vdpipeFlushParams.Flags.bWaitDoneHEVC = 1;
    vdpipeFlushParams.Flags.bFlushHEVC = 1;
    vdpipeFlushParams.Flags.bWaitDoneVDCmdMsgParser = 1;
    CODECHAL_DECODE_CHK_STATUS_RETURN(m_vdencInterface->AddVdPipelineFlushCmd(
        cmdBufferInUse,
        &vdpipeFlushParams));

    MHW_MI_FLUSH_DW_PARAMS flushDwParams;
    MOS_ZeroMemory(&flushDwParams, sizeof(flushDwParams));
    CODECHAL_DECODE_CHK_STATUS_RETURN(m_miInterface->AddMiFlushDwCmd(
        cmdBufferInUse,
        &flushDwParams));

    if (CodecHalDecodeScalabilityIsFEPhase(m_scalabilityState))
    {
        if (m_scalabilityState->bIsEnableEndCurrentBatchBuffLevel)
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalDecodeScalablity_GetFEReportedCabacStreamoutBufferSize(
                m_scalabilityState,
                cmdBufferInUse));
        }
        else
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalDecodeScalablity_SetFECabacStreamoutOverflowStatus(
                m_scalabilityState,
                cmdBufferInUse));
        }

        CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalDecodeScalability_SignalFE2BESemaphore(
            m_scalabilityState,
            cmdBufferInUse));

        if (m_perfFEBETimingEnabled)
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(m_perfProfiler->AddPerfCollectEndCmd((void *)this, m_osInterface, m_miInterface, &scdryCmdBuffer));
        }
    }

    //Sync for decode completion in scalable mode
    if (CodecHalDecodeScalabilityIsBEPhaseG12(m_scalabilityState))
    {
        CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalDecodeScalability_BEsCompletionSync(
            m_scalabilityState,
            cmdBufferInUse));
    }

    //if scalable decode,  BE0 finish means whole frame complete.
    // Check if destination surface needs to be synchronized
    bool syncDestSurface = true;
    if (CodecHalDecodeScalabilityIsScalableMode(m_scalabilityState))
    {
        syncDestSurface = CodecHalDecodeScalabilityIsLastCompletePhase(m_scalabilityState);
    }

    MOS_SYNC_PARAMS syncParams;
    if (syncDestSurface)
    {
        syncParams                          = g_cInitSyncParams;
        syncParams.GpuContext               = m_videoContext;
        syncParams.presSyncResource         = &m_destSurface.OsResource;
        syncParams.bReadOnly                = false;
        syncParams.bDisableDecodeSyncLock   = m_disableDecodeSyncLock;
        syncParams.bDisableLockForTranscode = m_disableLockForTranscode;

        CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnPerformOverlaySync(
            m_osInterface,
            &syncParams));
        CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnResourceWait(
            m_osInterface,
            &syncParams));

        // Update the resource tag (s/w tag) for On-Demand Sync
        m_osInterface->pfnSetResourceSyncTag(m_osInterface, &syncParams);

        // Update the tag in GPU Sync eStatus buffer (H/W Tag) to match the current S/W tag
        if (m_osInterface->bTagResourceSync)
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(m_hwInterface->WriteSyncTagToResource(
                cmdBufferInUse,
                &syncParams));
        }

        if (m_statusQueryReportingEnabled)
        {
            CodechalDecodeStatusReport decodeStatusReport;

            decodeStatusReport.m_statusReportNumber = m_statusReportFeedbackNumber;
            decodeStatusReport.m_currDecodedPic     = m_vp9PicParams->CurrPic;
            decodeStatusReport.m_currDeblockedPic   = m_vp9PicParams->CurrPic;
            decodeStatusReport.m_codecStatus        = CODECHAL_STATUS_UNAVAILABLE;
            decodeStatusReport.m_numMbsAffected     = m_usFrameWidthAlignedMinBlk * m_usFrameHeightAlignedMinBlk;
            decodeStatusReport.m_currDecodedPicRes  = m_vp9RefList[m_vp9PicParams->CurrPic.FrameIdx]->resRefPic;

#ifdef _DECODE_PROCESSING_SUPPORTED
            CODECHAL_DEBUG_TOOL(
                if (m_downsampledSurfaces && m_sfcState && m_sfcState->m_sfcOutputSurface) {
                    m_downsampledSurfaces[m_vp9PicParams->CurrPic.FrameIdx].OsResource = m_sfcState->m_sfcOutputSurface->OsResource;
                    decodeStatusReport.m_currSfcOutputPicRes                           = &m_downsampledSurfaces[m_vp9PicParams->CurrPic.FrameIdx].OsResource;
                })
#endif

            // VP9 plug-in/out was NOT fully enabled; this is just to make sure driver would not crash in CodecHal_DecodeEndFrame(),
            // which requires the value of DecodeStatusReport.presCurrDecodedPic
            CODECHAL_DEBUG_TOOL(
                decodeStatusReport.m_frameType = m_perfType;
            )

            CODECHAL_DECODE_CHK_STATUS_RETURN(EndStatusReport(
                decodeStatusReport,
                cmdBufferInUse));
        }
        else
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(NullHW::StopPredicate(m_osInterface, m_miInterface, cmdBufferInUse));
        }
    }
    else
    {
        CODECHAL_DECODE_CHK_STATUS_RETURN(NullHW::StopPredicate(m_osInterface, m_miInterface, cmdBufferInUse));
    }

    MOS_ZeroMemory(&flushDwParams, sizeof(flushDwParams));
    CODECHAL_DECODE_CHK_STATUS_RETURN(m_miInterface->AddMiFlushDwCmd(
        cmdBufferInUse,
        &flushDwParams));

    CODECHAL_DECODE_CHK_STATUS_RETURN(m_miInterface->AddMiBatchBufferEnd(
        cmdBufferInUse,
        nullptr));

    m_osInterface->pfnReturnCommandBuffer(m_osInterface, &primCmdBuffer, 0);
    if (CodecHalDecodeScalabilityIsScalableMode(m_scalabilityState) && MOS_VE_SUPPORTED(m_osInterface))
    {
        CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalDecodeScalability_ReturnSdryCmdBuffer_G12(m_scalabilityState, &scdryCmdBuffer));
    }

    CODECHAL_DEBUG_TOOL(

        if (m_histogramDebug && m_histogramSurface) {
            CODECHAL_DECODE_CHK_STATUS_RETURN(m_debugInterface->DumpBuffer(
                &m_histogramSurface->OsResource,
                CodechalDbgAttr::attrSfcHistogram,
                "_DEC",
                256 * 4));
        }

        if (CodecHalDecodeScalabilityIsScalableMode(m_scalabilityState)) {
            CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalDecodeScalability_DbgDumpCmdBuffer_G12(
                this,
                m_scalabilityState,
                m_debugInterface,
                &primCmdBuffer));
        } else {
            CODECHAL_DECODE_CHK_STATUS_RETURN(m_debugInterface->DumpCmdBuffer(
                &primCmdBuffer,
                CODECHAL_NUM_MEDIA_STATES,
                "_DEC"));
            //CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHal_DbgReplaceAllCommands(
            //    m_debugInterface,
            //    &primCmdBuffer));
        }

        m_mmc->UpdateUserFeatureKey(&m_destSurface);)

    bool syncCompleteFrame =
            (m_copyDataBufferInUse && !m_osInterface->bSimIsActive);
    if (MOS_VE_SUPPORTED(m_osInterface) && CodecHalDecodeScalabilityIsScalableMode(m_scalabilityState))
    {
        syncCompleteFrame = syncCompleteFrame && CodecHalDecodeScalabilityIsFEPhase(m_scalabilityState);
    }

    MOS_SYNC_PARAMS copyDataSyncParams;
    if (syncCompleteFrame)
    {
        //Sync up complete frame
        copyDataSyncParams = g_cInitSyncParams;
        copyDataSyncParams.GpuContext = m_videoContextForWa;
        copyDataSyncParams.presSyncResource = &m_resSyncObjectWaContextInUse;

        CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnEngineSignal(
            m_osInterface,
            &copyDataSyncParams));

        copyDataSyncParams = g_cInitSyncParams;
        copyDataSyncParams.GpuContext = m_videoContext;
        copyDataSyncParams.presSyncResource = &m_resSyncObjectWaContextInUse;

        CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnEngineWait(
            m_osInterface,
            &copyDataSyncParams));
    }

    bool submitCommand = true;
    if (MOS_VE_SUPPORTED(m_osInterface) && CodecHalDecodeScalabilityIsScalableMode(m_scalabilityState))
    {
        submitCommand = CodecHalDecodeScalabilityIsToSubmitCmdBuffer_G12(m_scalabilityState);
        HalOcaInterface::On1stLevelBBEnd(scdryCmdBuffer, *m_osInterface);
    }
    else
    {
        HalOcaInterface::On1stLevelBBEnd(primCmdBuffer, *m_osInterface);
    }

    if (submitCommand)
    {
        uint32_t renderingFlags = m_videoContextUsesNullHw;

        //command buffer to submit is the primary cmd buffer.
        if ( MOS_VE_SUPPORTED(m_osInterface))
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(SetAndPopulateVEHintParams(&primCmdBuffer));
        }

        if (m_osInterface->phasedSubmission
            && MOS_VE_SUPPORTED(m_osInterface)
            && CodecHalDecodeScalabilityIsScalableMode(m_scalabilityState))
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnSubmitCommandBuffer(
                m_osInterface,
                cmdBufferInUse,
                renderingFlags));
        }
        else
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnSubmitCommandBuffer(
                m_osInterface,
                &primCmdBuffer,
                renderingFlags));
        }
    }

    // Reset status report
    if (m_statusQueryReportingEnabled)
    {
        bool resetStatusReport = true;

        //if scalable decode,  reset status report at final BE phase.
        if (CodecHalDecodeScalabilityIsScalableMode(m_scalabilityState))
        {
            resetStatusReport = CodecHalDecodeScalabilityIsFinalBEPhaseG12(m_scalabilityState);
        }

        if (resetStatusReport)
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(ResetStatusReport(
                m_videoContextUsesNullHw));
        }
    }

#ifdef CODECHAL_HUC_KERNEL_DEBUG
    CODECHAL_DEBUG_TOOL(
    CODECHAL_DECODE_CHK_STATUS(m_debugInterface->DumpHucRegion(
        &resHucSharedBuffer,
        0,
        CODEC_VP9_PROB_MAX_NUM_ELEM,
        15,
        "",
        false,
        1,
        CodechalHucRegionDumpType::hucRegionDumpDefault));
    )
#endif
    CODECHAL_DEBUG_TOOL(
        CODECHAL_DECODE_CHK_STATUS_RETURN(m_debugInterface->DumpBuffer(
            &m_resVp9SegmentIdBuffer,
            CodechalDbgAttr::attrSegId,
            "SegId",
            (m_allocatedWidthInSb * m_allocatedHeightInSb * CODECHAL_CACHELINE_SIZE)));
        CODECHAL_DECODE_CHK_STATUS_RETURN(m_debugInterface->DumpBuffer(
            &(m_resVp9ProbBuffer[m_frameCtxIdx]),
            CodechalDbgAttr::attrCoefProb,
            "PakHwCoeffProbs",
            CODEC_VP9_PROB_MAX_NUM_ELEM));)

    // Needs to be re-set for Linux buffer re-use scenarios
    //pVp9State->pVp9RefList[pVp9PicParams->ucCurrPicIndex]->resRefPic =
    //    pVp9State->sDestSurface.OsResource;

    // Send the signal to indicate decode completion, in case On-Demand Sync is not present
    CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnResourceSignal(
        m_osInterface,
        &syncParams));

 #ifdef LINUX 
#ifdef _DECODE_PROCESSING_SUPPORTED
    CODECHAL_DEBUG_TOOL(
    if (m_sfcState->m_sfcOutputSurface)
    {
        MOS_SURFACE dstSurface;
        MOS_ZeroMemory(&dstSurface, sizeof(dstSurface));
        dstSurface.Format = Format_NV12;
        dstSurface.OsResource = m_sfcState->m_sfcOutputSurface->OsResource;
        CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalGetResourceInfo(
                m_osInterface,
                &dstSurface));

        CODECHAL_DECODE_CHK_STATUS_RETURN(m_debugInterface->DumpYUVSurface(
                &dstSurface,
                CodechalDbgAttr::attrSfcOutputSurface,
                "SfcDstSurf"));
    }
   )
#endif
#endif
    return eStatus;
}

MOS_STATUS CodechalDecodeVp9G12::InitMmcState()
{
#ifdef _MMC_SUPPORTED
    m_mmc = MOS_New(CodechalMmcDecodeVp9G12, m_hwInterface, this);
    CODECHAL_DECODE_CHK_NULL_RETURN(m_mmc);
#endif
    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalDecodeVp9G12 :: AllocateStandard (
    CodechalSetting *          settings)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_DECODE_FUNCTION_ENTER;

    CODECHAL_DECODE_CHK_NULL_RETURN(settings);

    CODECHAL_DECODE_CHK_STATUS_RETURN(InitMmcState());

    m_width                      = settings->width;
    m_height                     = settings->height;
    if (settings->lumaChromaDepth & CODECHAL_LUMA_CHROMA_DEPTH_8_BITS)
        m_vp9DepthIndicator = 0;
    if (settings->lumaChromaDepth & CODECHAL_LUMA_CHROMA_DEPTH_10_BITS)
        m_vp9DepthIndicator = 1;
    if (settings->lumaChromaDepth & CODECHAL_LUMA_CHROMA_DEPTH_12_BITS)
        m_vp9DepthIndicator = 2;
    m_chromaFormatinProfile = settings->chromaFormat;
#ifdef _DECODE_PROCESSING_SUPPORTED
    // Initialize SFC state
    m_sfcState = MOS_New(CodechalVp9SfcStateG12);
    CODECHAL_DECODE_CHK_STATUS_RETURN(m_sfcState->InitializeSfcState(
        this,
        m_hwInterface,
        m_osInterface));
#endif
    MHW_VDBOX_STATE_CMDSIZE_PARAMS_G12   stateCmdSizeParams;
    stateCmdSizeParams.bHucDummyStream = false;
    stateCmdSizeParams.bScalableMode   = static_cast<MhwVdboxMfxInterfaceG12*>(m_mfxInterface)->IsScalabilitySupported();
    stateCmdSizeParams.bSfcInUse       = true;
    //FE has more commands than BE. To finer control of the cmd buffer size

    // Picture Level Commands
    m_hwInterface->GetHxxStateCommandSize(
        m_mode,
        &m_commandBufferSizeNeeded,
        &m_commandPatchListSizeNeeded,
        &stateCmdSizeParams);

    // Primitive Level Commands
    m_hwInterface->GetHxxPrimitiveCommandSize(
        m_mode,
        &m_standardDecodeSizeNeeded,
        &m_standardDecodePatchListSizeNeeded,
        false);

   if ( MOS_VE_SUPPORTED(m_osInterface))
    {
        if (static_cast<MhwVdboxMfxInterfaceG12*>(m_mfxInterface)->IsScalabilitySupported())
        {
            m_scalabilityState = (PCODECHAL_DECODE_SCALABILITY_STATE_G12)MOS_AllocAndZeroMemory(sizeof(CODECHAL_DECODE_SCALABILITY_STATE_G12));
            CODECHAL_DECODE_CHK_NULL_RETURN(m_scalabilityState);
            //scalability initialize
            CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalDecodeScalability_InitializeState_G12(
                this,
                m_scalabilityState,
                m_hwInterface,
                false,
                settings));
        }
        else
        {
            //single pipe VE initialize
            m_sinlgePipeVeState = (PCODECHAL_DECODE_SINGLEPIPE_VIRTUALENGINE_STATE)MOS_AllocAndZeroMemory(sizeof(CODECHAL_DECODE_SINGLEPIPE_VIRTUALENGINE_STATE));
            CODECHAL_DECODE_CHK_NULL_RETURN(m_sinlgePipeVeState);
            CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalDecodeSinglePipeVE_InitInterface(m_osInterface, m_sinlgePipeVeState));
        }
    }

    CODECHAL_DECODE_CHK_STATUS_RETURN(CodechalDecodeVp9::AllocateResourcesFixedSizes());

    // Prepare Pic Params
    m_picMhwParams.PipeModeSelectParams = MOS_New(MHW_VDBOX_PIPE_MODE_SELECT_PARAMS_G12);
    m_picMhwParams.PipeBufAddrParams = MOS_New(MHW_VDBOX_PIPE_BUF_ADDR_PARAMS_G12);
    m_picMhwParams.IndObjBaseAddrParams = MOS_New(MHW_VDBOX_IND_OBJ_BASE_ADDR_PARAMS);
    m_picMhwParams.Vp9PicState = MOS_New(MHW_VDBOX_VP9_PIC_STATE);
    m_picMhwParams.Vp9SegmentState = MOS_New(MHW_VDBOX_VP9_SEGMENT_STATE);

    MOS_ZeroMemory(m_picMhwParams.IndObjBaseAddrParams, sizeof(MHW_VDBOX_IND_OBJ_BASE_ADDR_PARAMS));
    MOS_ZeroMemory(m_picMhwParams.Vp9PicState, sizeof(MHW_VDBOX_VP9_PIC_STATE));
    MOS_ZeroMemory(m_picMhwParams.Vp9SegmentState, sizeof(MHW_VDBOX_VP9_SEGMENT_STATE));

    for (uint16_t i = 0; i < 4; i++)
    {
        m_picMhwParams.SurfaceParams[i] = MOS_New(MHW_VDBOX_SURFACE_PARAMS);
        MOS_ZeroMemory(m_picMhwParams.SurfaceParams[i], sizeof(MHW_VDBOX_SURFACE_PARAMS));
    }

    return eStatus;
}
