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

#include "codechal_decoder.h"
#include "codechal_secure_decode_interface.h"
#include "codechal_decode_vp9.h"
#include "codechal_mmc_decode_vp9.h"
#include "hal_oca_interface.h"
#if USE_CODECHAL_DEBUG_TOOL
#include <sstream>
#include <fstream>
#include "codechal_debug.h"
#endif
#include "mos_os_cp_interface_specific.h"

CodechalDecodeVp9 :: ~CodechalDecodeVp9 ()
{
    CODECHAL_DECODE_FUNCTION_ENTER;

    m_osInterface->pfnDestroySyncResource(m_osInterface, &m_resSyncObject);
    m_osInterface->pfnDestroySyncResource(m_osInterface, &m_resSyncObjectWaContextInUse);
    m_osInterface->pfnDestroySyncResource(m_osInterface, &m_resSyncObjectVideoContextInUse);

    CodecHalFreeDataList(m_vp9RefList, CODECHAL_NUM_UNCOMPRESSED_SURFACE_VP9);

    if (!Mos_ResourceIsNull(&m_resDeblockingFilterLineRowStoreScratchBuffer))
    {
        m_osInterface->pfnFreeResource(
            m_osInterface,
            &m_resDeblockingFilterLineRowStoreScratchBuffer);
    }

    m_osInterface->pfnFreeResource(
        m_osInterface,
        &m_resDeblockingFilterTileRowStoreScratchBuffer);

    m_osInterface->pfnFreeResource(
        m_osInterface,
        &m_resDeblockingFilterColumnRowStoreScratchBuffer);

    m_osInterface->pfnFreeResource(
        m_osInterface,
        &m_resMetadataLineBuffer);

    m_osInterface->pfnFreeResource(
        m_osInterface,
        &m_resMetadataTileLineBuffer);

    m_osInterface->pfnFreeResource(
        m_osInterface,
        &m_resMetadataTileColumnBuffer);

    if (!Mos_ResourceIsNull(&m_resHvcLineRowstoreBuffer))
    {
        m_osInterface->pfnFreeResource(
            m_osInterface,
            &m_resHvcLineRowstoreBuffer);
    }

    m_osInterface->pfnFreeResource(
        m_osInterface,
        &m_resHvcTileRowstoreBuffer);

    for (uint8_t i = 0; i < CODEC_VP9_NUM_CONTEXTS + 1; i++)
    {
        m_osInterface->pfnFreeResource(
            m_osInterface,
            &m_resVp9ProbBuffer[i]);
    }

    m_osInterface->pfnFreeResource(
        m_osInterface,
        &m_resVp9SegmentIdBuffer);

    m_osInterface->pfnFreeResource(
        m_osInterface,
        &m_resSegmentIdBuffReset);

    for (uint8_t i = 0; i < CODECHAL_VP9_NUM_MV_BUFFERS; i++)
    {
        m_osInterface->pfnFreeResource(
            m_osInterface,
            &m_resVp9MvTemporalBuffer[i]);
    }

    if (!Mos_ResourceIsNull(&m_resCopyDataBuffer))
    {
        m_osInterface->pfnFreeResource(
            m_osInterface,
            &m_resCopyDataBuffer);
    }

    m_osInterface->pfnFreeResource(
        m_osInterface,
        &m_resHucSharedBuffer);

    m_osInterface->pfnFreeResource(
        m_osInterface,
        &m_resDmemBuffer);

    m_osInterface->pfnFreeResource(
        m_osInterface,
        &m_resInterProbSaveBuffer);

    if (m_picMhwParams.PipeModeSelectParams)
    {
        MOS_Delete(m_picMhwParams.PipeModeSelectParams);
        m_picMhwParams.PipeModeSelectParams = nullptr;
    }
    for (uint8_t i = 0; i < 4; i++)
    {
        if (m_picMhwParams.SurfaceParams[i])
        {
            MOS_Delete(m_picMhwParams.SurfaceParams[i]);
            m_picMhwParams.SurfaceParams[i] = nullptr;
        }
    }
    if (m_picMhwParams.PipeBufAddrParams)
    {
        MOS_Delete(m_picMhwParams.PipeBufAddrParams);
        m_picMhwParams.PipeBufAddrParams = nullptr;
    }
    if (m_picMhwParams.IndObjBaseAddrParams)
    {
        MOS_Delete(m_picMhwParams.IndObjBaseAddrParams);
        m_picMhwParams.IndObjBaseAddrParams = nullptr;
    }
    if (m_picMhwParams.Vp9PicState)
    {
        MOS_Delete(m_picMhwParams.Vp9PicState);
        m_picMhwParams.Vp9PicState = nullptr;
    }
    if (m_picMhwParams.Vp9SegmentState)
    {
        MOS_Delete(m_picMhwParams.Vp9SegmentState);
        m_picMhwParams.Vp9SegmentState = nullptr;
    }
}

CodechalDecodeVp9 ::CodechalDecodeVp9(
    CodechalHwInterface *   hwInterface,
    CodechalDebugInterface *debugInterface,
    PCODECHAL_STANDARD_INFO standardInfo) : CodechalDecode(hwInterface, debugInterface, standardInfo),
                                            m_usFrameWidthAlignedMinBlk(0),
                                            m_usFrameHeightAlignedMinBlk(0),
                                            m_vp9DepthIndicator(0),
                                            m_chromaFormatinProfile(0),
                                            m_dataSize(0),
                                            m_dataOffset(0),
                                            m_frameCtxIdx(0),
                                            m_curMvTempBufIdx(0),
                                            m_colMvTempBufIdx(0),
                                            m_copyDataBufferSize(0),
                                            m_copyDataOffset(0),
                                            m_copyDataBufferInUse(false),
                                            m_hcpDecPhase(0),
                                            m_prevFrmWidth(0),
                                            m_prevFrmHeight(0),
                                            m_allocatedWidthInSb(0),
                                            m_allocatedHeightInSb(0),
                                            m_mvBufferSize(0),
                                            m_resetSegIdBuffer(false),
                                            m_pendingResetPartial(0),
                                            m_saveInterProbs(0),
                                            m_fullProbBufferUpdate(false),
                                            m_dmemBufferSize(0)
{
    CODECHAL_DECODE_FUNCTION_ENTER;

    MOS_ZeroMemory(&m_resDeblockingFilterLineRowStoreScratchBuffer, sizeof(m_resDeblockingFilterLineRowStoreScratchBuffer));
    MOS_ZeroMemory(&m_resDeblockingFilterTileRowStoreScratchBuffer, sizeof(m_resDeblockingFilterTileRowStoreScratchBuffer));
    MOS_ZeroMemory(&m_resDeblockingFilterColumnRowStoreScratchBuffer, sizeof(m_resDeblockingFilterColumnRowStoreScratchBuffer));
    MOS_ZeroMemory(&m_resMetadataLineBuffer, sizeof(m_resMetadataLineBuffer));
    MOS_ZeroMemory(&m_resMetadataTileLineBuffer, sizeof(m_resMetadataTileLineBuffer));
    MOS_ZeroMemory(&m_resMetadataTileColumnBuffer, sizeof(m_resMetadataTileColumnBuffer));
    MOS_ZeroMemory(&m_resHvcLineRowstoreBuffer, sizeof(m_resHvcLineRowstoreBuffer));
    MOS_ZeroMemory(&m_resHvcTileRowstoreBuffer, sizeof(m_resHvcTileRowstoreBuffer));
    MOS_ZeroMemory(&m_resVp9SegmentIdBuffer, sizeof(m_resVp9SegmentIdBuffer));
    MOS_ZeroMemory(&m_resVp9MvTemporalBuffer, sizeof(m_resVp9MvTemporalBuffer));
    MOS_ZeroMemory(&m_resCopyDataBuffer, sizeof(m_resCopyDataBuffer));
    MOS_ZeroMemory(&m_segTreeProbs, sizeof(m_segTreeProbs));
    MOS_ZeroMemory(&m_segPredProbs, sizeof(m_segPredProbs));
    MOS_ZeroMemory(&m_interProbSaved, sizeof(m_interProbSaved));
    MOS_ZeroMemory(&m_resDmemBuffer, sizeof(m_resDmemBuffer));
    MOS_ZeroMemory(&m_resInterProbSaveBuffer, sizeof(m_resInterProbSaveBuffer));
    MOS_ZeroMemory(&m_probUpdateFlags, sizeof(m_probUpdateFlags));
    MOS_ZeroMemory(&m_resSegmentIdBuffReset, sizeof(m_resSegmentIdBuffReset));
    MOS_ZeroMemory(&m_resHucSharedBuffer, sizeof(m_resHucSharedBuffer));
    MOS_ZeroMemory(&m_picMhwParams, sizeof(m_picMhwParams));
    MOS_ZeroMemory(&m_destSurface, sizeof(m_destSurface));
    MOS_ZeroMemory(&m_lastRefSurface, sizeof(m_lastRefSurface));
    MOS_ZeroMemory(&m_goldenRefSurface, sizeof(m_goldenRefSurface));
    MOS_ZeroMemory(&m_altRefSurface, sizeof(m_altRefSurface));
    MOS_ZeroMemory(&m_resDataBuffer, sizeof(m_resDataBuffer));
    MOS_ZeroMemory(&m_resCoefProbBuffer, sizeof(m_resCoefProbBuffer));
    MOS_ZeroMemory(&m_resSyncObject, sizeof(m_resSyncObject));
    MOS_ZeroMemory(&m_resSyncObjectWaContextInUse, sizeof(m_resSyncObjectWaContextInUse));
    MOS_ZeroMemory(&m_resSyncObjectVideoContextInUse, sizeof(m_resSyncObjectVideoContextInUse));

    m_prevFrameParams.value = 0;
#if (_DEBUG || _RELEASE_INTERNAL)
    m_reportFrameCrc        = true;
#endif
    for (uint8_t i = 0; i < CODEC_VP9_NUM_CONTEXTS; i++)
    {
        m_pendingResetFullTables[i] = 0;
        m_pendingCopySegProbs[i]    = 0;
    }

    m_hcpInUse = true;
    m_hwInterface = hwInterface;
}

MOS_STATUS CodechalDecodeVp9 :: ProbBufferPartialUpdatewithDrv()
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_DECODE_FUNCTION_ENTER;

    if (m_probUpdateFlags.bSegProbCopy ||
        m_probUpdateFlags.bProbSave ||
        m_probUpdateFlags.bProbReset ||
        m_probUpdateFlags.bProbRestore)
    {
        CodechalResLock ResourceLock(m_osInterface, &m_resVp9ProbBuffer[m_frameCtxIdx]);
        auto            data = (uint8_t *)ResourceLock.Lock(CodechalResLock::writeOnly);
        CODECHAL_DECODE_CHK_NULL_RETURN(data);

        if (m_probUpdateFlags.bSegProbCopy)
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(MOS_SecureMemcpy(
                (data + CODEC_VP9_SEG_PROB_OFFSET),
                7,
                m_probUpdateFlags.SegTreeProbs,
                7));
            CODECHAL_DECODE_CHK_STATUS_RETURN(MOS_SecureMemcpy(
                (data + CODEC_VP9_SEG_PROB_OFFSET + 7),
                3,
                m_probUpdateFlags.SegPredProbs,
                3));
        }

        if (m_probUpdateFlags.bProbSave)
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(MOS_SecureMemcpy(
                m_interProbSaved,
                CODECHAL_VP9_INTER_PROB_SIZE,
                data + CODEC_VP9_INTER_PROB_OFFSET,
                CODECHAL_VP9_INTER_PROB_SIZE));
        }

        if (m_probUpdateFlags.bProbReset)
        {
            if (m_probUpdateFlags.bResetFull)
            {
                CODECHAL_DECODE_CHK_STATUS_RETURN(ContextBufferInit(
                    data, (m_probUpdateFlags.bResetKeyDefault ? true : false)));
            }
            else
            {
                CODECHAL_DECODE_CHK_STATUS_RETURN(CtxBufDiffInit(
                    data, (m_probUpdateFlags.bResetKeyDefault ? true : false)));
            }
        }

        if (m_probUpdateFlags.bProbRestore)
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(MOS_SecureMemcpy(
                data + CODEC_VP9_INTER_PROB_OFFSET,
                CODECHAL_VP9_INTER_PROB_SIZE,
                m_interProbSaved,
                CODECHAL_VP9_INTER_PROB_SIZE));
        }
    }

    return eStatus;
}

MOS_STATUS CodechalDecodeVp9 :: ProbBufFullUpdatewithDrv()
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_DECODE_FUNCTION_ENTER;

    CodechalResLock ResourceLock(m_osInterface, &m_resVp9ProbBuffer[m_frameCtxIdx]);
    auto data = (uint8_t*)ResourceLock.Lock(CodechalResLock::writeOnly);
    CODECHAL_DECODE_CHK_NULL_RETURN(data);

    CODECHAL_DECODE_CHK_STATUS_RETURN(ContextBufferInit(
        data, (m_probUpdateFlags.bResetKeyDefault ? true : false)));
    CODECHAL_DECODE_CHK_STATUS_RETURN(MOS_SecureMemcpy(
        (data + CODEC_VP9_SEG_PROB_OFFSET),
        7,
        m_probUpdateFlags.SegTreeProbs,
        7));
    CODECHAL_DECODE_CHK_STATUS_RETURN(MOS_SecureMemcpy(
        (data + CODEC_VP9_SEG_PROB_OFFSET + 7),
        3,
        m_probUpdateFlags.SegPredProbs,
        3));

    return eStatus;
}

MOS_STATUS CodechalDecodeVp9 :: ResetSegIdBufferwithDrv()
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_DECODE_FUNCTION_ENTER;

    CodechalResLock ResourceLock(m_osInterface, &m_resVp9SegmentIdBuffer);
    auto data = (uint8_t*)ResourceLock.Lock(CodechalResLock::writeOnly);
    CODECHAL_DECODE_CHK_NULL_RETURN(data);

    MOS_ZeroMemory(
        data,
        m_allocatedWidthInSb * m_allocatedHeightInSb * CODECHAL_CACHELINE_SIZE);

    return eStatus;
}

MOS_STATUS CodechalDecodeVp9 :: ProbBufFullUpdatewithHucStreamout(
    PMOS_COMMAND_BUFFER         cmdBuffer)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_DECODE_FUNCTION_ENTER;

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

    uint32_t bufSize = CODEC_VP9_PROB_MAX_NUM_ELEM; // 16 byte aligned

    CodechalResLock ResourceLock(m_osInterface, &m_resVp9ProbBuffer[CODEC_VP9_NUM_CONTEXTS]);
    auto data = (uint8_t*)ResourceLock.Lock(CodechalResLock::writeOnly);
    CODECHAL_DECODE_CHK_NULL_RETURN(data);

    CODECHAL_DECODE_CHK_STATUS_RETURN(ContextBufferInit(
        data,
        (m_probUpdateFlags.bResetKeyDefault ? true : false)));
    CODECHAL_DECODE_CHK_STATUS_RETURN(MOS_SecureMemcpy(
        (data + CODEC_VP9_SEG_PROB_OFFSET),
        7,
        m_probUpdateFlags.SegTreeProbs,
        7));
    CODECHAL_DECODE_CHK_STATUS_RETURN(MOS_SecureMemcpy(
        (data + CODEC_VP9_SEG_PROB_OFFSET + 7),
        3,
        m_probUpdateFlags.SegPredProbs,
        3));

    CODECHAL_DECODE_CHK_STATUS_RETURN(HucCopy(
        cmdBuffer,                                    // cmdBuffer
        &m_resVp9ProbBuffer[CODEC_VP9_NUM_CONTEXTS],  // presSrc
        &m_resVp9ProbBuffer[m_frameCtxIdx],           // presDst
        bufSize,                                      // u32CopyLength
        0,                                            // u32CopyInputOffset
        0));                                          // u32CopyOutputOffset

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

    return eStatus;
}

MOS_STATUS CodechalDecodeVp9 :: ResetSegIdBufferwithHucStreamout(
    PMOS_COMMAND_BUFFER         cmdBuffer)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_DECODE_FUNCTION_ENTER;

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

    uint32_t bufSize =
        m_allocatedWidthInSb * m_allocatedHeightInSb * CODECHAL_CACHELINE_SIZE;  // 16 byte aligned

    CODECHAL_DECODE_CHK_STATUS_RETURN(HucCopy(
        cmdBuffer,                 // cmdBuffer
        &m_resSegmentIdBuffReset,  // presSrc
        &m_resVp9SegmentIdBuffer,  // presDst
        bufSize,                   // u32CopyLength
        0,                         // u32CopyInputOffset
        0));                       // u32CopyOutputOffset

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

    return eStatus;
}

MOS_STATUS CodechalDecodeVp9 :: DetermineInternalBufferUpdate()
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_DECODE_FUNCTION_ENTER;

    bool    keyFrame       = !m_vp9PicParams->PicFlags.fields.frame_type;
    bool    intraOnly      = m_vp9PicParams->PicFlags.fields.intra_only;
    uint8_t curFrameCtxIdx = (uint8_t)m_vp9PicParams->PicFlags.fields.frame_context_idx;
    bool    isScaling      = (m_destSurface.dwWidth == m_prevFrmWidth) &&
                             (m_destSurface.dwHeight == m_prevFrmHeight)
                         ? false
                         : true;
    bool resetAll       = (keyFrame |
                         m_vp9PicParams->PicFlags.fields.error_resilient_mode ||
                     (m_vp9PicParams->PicFlags.fields.reset_frame_context == 3 &&
                         m_vp9PicParams->PicFlags.fields.intra_only));
    bool resetSpecified = (m_vp9PicParams->PicFlags.fields.reset_frame_context == 2 &&
                           m_vp9PicParams->PicFlags.fields.intra_only);

    bool copySegProbs       = false;  // indicating if current frame's prob buffer need to update seg tree/pred probs.
    bool resetFullTbl       = false;  // indicating if current frame will do full frame context table reset
    bool resetPartialTbl    = false;  // indicating if current frame need to do partial reset from offset 1667 to 2010.
    bool restoreInterProbs  = false;  // indicating if current frame need to restore offset 1667 to 2010 from saved one, this is only for prob buffer 0.
    bool saveInterProbsTmp  = false;  // indicating if current frame need to save offset from 1667 to 2010 for prob buffer 0.

    m_resetSegIdBuffer = keyFrame ||
                         isScaling ||
                         m_vp9PicParams->PicFlags.fields.error_resilient_mode ||
                         m_vp9PicParams->PicFlags.fields.intra_only;

    m_frameCtxIdx = curFrameCtxIdx;  //indicate which prob buffer need to be used by current frame decode
    if (!m_vp9PicParams->PicFlags.fields.frame_type ||
        m_vp9PicParams->PicFlags.fields.intra_only ||
        m_vp9PicParams->PicFlags.fields.error_resilient_mode)
    {
        //always use frame context idx 0 in this case
        m_frameCtxIdx = 0;
    }

    //check if seg tree/pred probs need to be updated in prob buffer of current frame
    //and also mark the flag bPendingResetSegProbs for other prob buffers
    if (m_vp9PicParams->PicFlags.fields.segmentation_enabled &&
        m_vp9PicParams->PicFlags.fields.segmentation_update_map)
    {
        copySegProbs = true;
        for ( uint8_t ctxIdx = 0; ctxIdx < CODEC_VP9_NUM_CONTEXTS; ctxIdx++)
        {
            m_pendingCopySegProbs[ctxIdx] = true;
        }
        //set current frame's prob buffer pending copy to false
        m_pendingCopySegProbs[m_frameCtxIdx] = false;

        //save probs for pending copy
        MOS_SecureMemcpy(m_segTreeProbs, 7, m_vp9PicParams->SegTreeProbs, 7);
        MOS_SecureMemcpy(m_segPredProbs, 3, m_vp9PicParams->SegPredProbs, 3);
    }
    else if (m_vp9PicParams->PicFlags.fields.segmentation_enabled &&
             m_pendingCopySegProbs[m_frameCtxIdx])
    {
        copySegProbs = true;
        m_pendingCopySegProbs[m_frameCtxIdx] = false;
    }

    //check if probs in frame context table need to be updated for current frame's prob buffer
    //and also mark the flag bPendingResetFullTables for other prob buffers
    if (resetAll)
    {
        resetFullTbl = true;
        m_pendingResetPartial = (keyFrame || intraOnly);

        //prob buffer 0 will be used for current frame decoding
        for ( uint8_t ctxIdx = 1; ctxIdx < CODEC_VP9_NUM_CONTEXTS; ctxIdx++)
        {
            m_pendingResetFullTables[ctxIdx] = true;
        }
        m_saveInterProbs = false;
    }
    else if (resetSpecified)
    {
        //intra only frame:prob buffer 0 will always be used for current frame decoding
        if (curFrameCtxIdx == 0)
        {
            //do prob table 0 reset
            resetFullTbl = true;
            m_pendingResetPartial = true;
            m_saveInterProbs      = false;
        }
        else
        {
            //not do reset right now, pending the reset full table of specified ctx until a later frame use it to do decode
            m_pendingResetFullTables[curFrameCtxIdx] = true;
            if (!m_pendingResetPartial)
            {
                if (!m_saveInterProbs)
                {
                    saveInterProbsTmp = true;
                    m_saveInterProbs  = true;
                }
                resetPartialTbl = true;
            }
        }
    }
    else if (intraOnly)
    {
        //prob buffer 0 will be used for current frame decoding
        if (!m_pendingResetPartial)
        {
            if (!m_saveInterProbs)
            {
                saveInterProbsTmp = true;
                m_saveInterProbs  = true;
            }
            resetPartialTbl = true;
        }
    }
    else if (m_pendingResetFullTables[curFrameCtxIdx])
    {
        //here curFrameCtxIdx != 0, frame is inter frame
        resetFullTbl = true;
        m_pendingResetFullTables[curFrameCtxIdx] = false;
    }
    else if (curFrameCtxIdx == 0 && m_pendingResetPartial)
    {
        //here curFrameCtxIdx = 0, frame is inter frame
        resetPartialTbl = true;
        m_pendingResetPartial = false;
    }
    else if (curFrameCtxIdx == 0 && m_saveInterProbs)
    {
        //here curFrameCtxIdx = 0, frame is inter frame
        restoreInterProbs = true;
        m_saveInterProbs  = false;
    }

    //decide if prob buffer need to do a full udpate or partial upate
    if (resetFullTbl && copySegProbs)
    {
        //update the whole prob buffer
        m_fullProbBufferUpdate = true;
    }
    else
    {
        //partial buffer update
        m_fullProbBufferUpdate = false;
    }

    //propogate ProbUpdateFlags
    MOS_ZeroMemory(&m_probUpdateFlags, sizeof(m_probUpdateFlags));
    if (copySegProbs)
    {
        m_probUpdateFlags.bSegProbCopy = true;
        MOS_SecureMemcpy(m_probUpdateFlags.SegTreeProbs, 7, m_segTreeProbs, 7);
        MOS_SecureMemcpy(m_probUpdateFlags.SegPredProbs, 3, m_segPredProbs, 3);
    }
    m_probUpdateFlags.bProbReset       = resetFullTbl || resetPartialTbl;
    m_probUpdateFlags.bResetFull       = resetFullTbl;
    m_probUpdateFlags.bResetKeyDefault = (keyFrame || intraOnly);
    m_probUpdateFlags.bProbSave        = saveInterProbsTmp;
    m_probUpdateFlags.bProbRestore     = restoreInterProbs;

    return eStatus;
}

MOS_STATUS CodechalDecodeVp9 :: AllocateResourcesFixedSizes()
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_DECODE_FUNCTION_ENTER;

    CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnCreateSyncResource(
        m_osInterface, &m_resSyncObject));
    CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnCreateSyncResource(
        m_osInterface, &m_resSyncObjectWaContextInUse));
    CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnCreateSyncResource(
        m_osInterface, &m_resSyncObjectVideoContextInUse));

    CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalAllocateDataList(
        m_vp9RefList,
        CODECHAL_NUM_UNCOMPRESSED_SURFACE_VP9));

    // VP9 Probability buffer
    for (uint8_t i = 0; i < CODEC_VP9_NUM_CONTEXTS + 1; i++)
    {
        CODECHAL_DECODE_CHK_STATUS_MESSAGE_RETURN(AllocateBuffer(
                                                      &m_resVp9ProbBuffer[i],
                                                      MOS_ALIGN_CEIL(CODEC_VP9_PROB_MAX_NUM_ELEM, CODECHAL_PAGE_SIZE),
                                                      "Vp9ProbabilityBuffer"),
            "Failed to allocate VP9 probability Buffer.");

        CodechalResLock ResourceLock(m_osInterface, &m_resVp9ProbBuffer[i]);
        auto data = (uint8_t*)ResourceLock.Lock(CodechalResLock::writeOnly);
        CODECHAL_DECODE_CHK_NULL_RETURN(data);

        MOS_ZeroMemory(data, CODEC_VP9_PROB_MAX_NUM_ELEM);
        //initialize seg_tree_prob and seg_pred_prob
        MOS_FillMemory((data + CODEC_VP9_SEG_PROB_OFFSET), 7, CODEC_VP9_MAX_PROB);
        MOS_FillMemory((data + CODEC_VP9_SEG_PROB_OFFSET + 7), 3, CODEC_VP9_MAX_PROB);
    }

    // DMEM buffer send to HuC FW
    m_dmemBufferSize = MOS_ALIGN_CEIL(sizeof(CODECHAL_DECODE_VP9_PROB_UPDATE), CODECHAL_CACHELINE_SIZE);
    CODECHAL_DECODE_CHK_STATUS_MESSAGE_RETURN(AllocateBuffer(
                                                  &m_resDmemBuffer,
                                                  m_dmemBufferSize,
                                                  "DmemBuffer"),
        "Failed to allocate Dmem Buffer.");

    // VP9 Interprobs save buffer
    CODECHAL_DECODE_CHK_STATUS_MESSAGE_RETURN(AllocateBuffer(
                                                  &m_resInterProbSaveBuffer,
                                                  MOS_ALIGN_CEIL(CODECHAL_VP9_INTER_PROB_SIZE, CODECHAL_PAGE_SIZE),
                                                  "VP9InterProbsSaveBuffer"),
        "Failed to allocate VP9 inter probability save Buffer.");

    // VP9 shared buffer with HuC FW, mapping to region 15
    CODECHAL_DECODE_CHK_STATUS_MESSAGE_RETURN(AllocateBuffer(
                                                  &m_resHucSharedBuffer,
                                                  MOS_ALIGN_CEIL(CODEC_VP9_PROB_MAX_NUM_ELEM, CODECHAL_PAGE_SIZE),
                                                  "VP9HucSharedBuffer"),
        "Failed to allocate VP9 Huc shared Buffer.");

    return eStatus;
}

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

    CODECHAL_DECODE_FUNCTION_ENTER;

    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);
    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;

    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;

    if (!m_hcpInterface->IsVp9DfRowstoreCacheEnabled())
    {
        CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->IsVp9BufferReallocNeeded(
            MHW_VDBOX_HCP_INTERNAL_BUFFER_DBLK_LINE,
            &reallocParam));
        if (reallocParam.bNeedBiggerSize ||
            Mos_ResourceIsNull(&m_resDeblockingFilterLineRowStoreScratchBuffer))
        {
            if (!Mos_ResourceIsNull(&m_resDeblockingFilterLineRowStoreScratchBuffer))
            {
                m_osInterface->pfnFreeResource(
                    m_osInterface,
                    &m_resDeblockingFilterLineRowStoreScratchBuffer);
            }

            // Deblocking Filter Line Row Store Scratch data surface
            CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->GetVp9BufferSize(
                MHW_VDBOX_HCP_INTERNAL_BUFFER_DBLK_LINE,
                &hcpBufSizeParam));

            CODECHAL_DECODE_CHK_STATUS_MESSAGE_RETURN(AllocateBuffer(
                                                          &m_resDeblockingFilterLineRowStoreScratchBuffer,
                                                          hcpBufSizeParam.dwBufferSize,
                                                          "DeblockingLineScratchBuffer"),
                "Failed to allocate deblocking line scratch Buffer.");
        }
    }

    CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->IsVp9BufferReallocNeeded(
        MHW_VDBOX_HCP_INTERNAL_BUFFER_DBLK_TILE_LINE,
        &reallocParam));
    if (reallocParam.bNeedBiggerSize ||
        Mos_ResourceIsNull(&m_resDeblockingFilterTileRowStoreScratchBuffer))
    {
        if (!Mos_ResourceIsNull(&m_resDeblockingFilterTileRowStoreScratchBuffer))
        {
            m_osInterface->pfnFreeResource(
                m_osInterface,
                &m_resDeblockingFilterTileRowStoreScratchBuffer);
        }

        // Deblocking Filter Tile Row Store Scratch data surface
        CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->GetVp9BufferSize(
            MHW_VDBOX_HCP_INTERNAL_BUFFER_DBLK_TILE_LINE,
            &hcpBufSizeParam));

        CODECHAL_DECODE_CHK_STATUS_MESSAGE_RETURN(AllocateBuffer(
                                                      &m_resDeblockingFilterTileRowStoreScratchBuffer,
                                                      hcpBufSizeParam.dwBufferSize,
                                                      "DeblockingTileScratchBuffer"),
            "Failed to allocate deblocking tile scratch Buffer.");
    }

    CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->IsVp9BufferReallocNeeded(
        MHW_VDBOX_HCP_INTERNAL_BUFFER_DBLK_TILE_COL,
        &reallocParam));
    if (reallocParam.bNeedBiggerSize ||
        Mos_ResourceIsNull(&m_resDeblockingFilterColumnRowStoreScratchBuffer))
    {
        if (!Mos_ResourceIsNull(&m_resDeblockingFilterColumnRowStoreScratchBuffer))
        {
            m_osInterface->pfnFreeResource(
                m_osInterface,
                &m_resDeblockingFilterColumnRowStoreScratchBuffer);
        }
        // Deblocking Filter Column Row Store Scratch data surface
        CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->GetVp9BufferSize(
            MHW_VDBOX_HCP_INTERNAL_BUFFER_DBLK_TILE_COL,
            &hcpBufSizeParam));

        CODECHAL_DECODE_CHK_STATUS_MESSAGE_RETURN(AllocateBuffer(
                                                      &m_resDeblockingFilterColumnRowStoreScratchBuffer,
                                                      hcpBufSizeParam.dwBufferSize,
                                                      "DeblockingColumnScratchBuffer"),
            "Failed to allocate deblocking column scratch Buffer.");
    }

    if (!m_hcpInterface->IsVp9DatRowstoreCacheEnabled())
    {
        CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->IsVp9BufferReallocNeeded(
            MHW_VDBOX_HCP_INTERNAL_BUFFER_META_LINE,
            &reallocParam));
        if (reallocParam.bNeedBiggerSize ||
            Mos_ResourceIsNull(&m_resMetadataLineBuffer))
        {
            if (!Mos_ResourceIsNull(&m_resMetadataLineBuffer))
            {
                m_osInterface->pfnFreeResource(
                    m_osInterface,
                    &m_resMetadataLineBuffer);
            }

            // Metadata Line buffer
            CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->GetVp9BufferSize(
                MHW_VDBOX_HCP_INTERNAL_BUFFER_META_LINE,
                &hcpBufSizeParam));

            CODECHAL_DECODE_CHK_STATUS_MESSAGE_RETURN(AllocateBuffer(
                                                          &m_resMetadataLineBuffer,
                                                          hcpBufSizeParam.dwBufferSize,
                                                          "MetadataLineBuffer"),
                "Failed to allocate meta data line Buffer.");
        }
    }

    CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->IsVp9BufferReallocNeeded(
        MHW_VDBOX_HCP_INTERNAL_BUFFER_META_TILE_LINE,
        &reallocParam));
    if (reallocParam.bNeedBiggerSize ||
        Mos_ResourceIsNull(&m_resMetadataTileLineBuffer))
    {
        if (!Mos_ResourceIsNull(&m_resMetadataTileLineBuffer))
        {
            m_osInterface->pfnFreeResource(
                m_osInterface,
                &m_resMetadataTileLineBuffer);
        }
        // Metadata Tile Line buffer
        CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->GetVp9BufferSize(
            MHW_VDBOX_HCP_INTERNAL_BUFFER_META_TILE_LINE,
            &hcpBufSizeParam));

        CODECHAL_DECODE_CHK_STATUS_MESSAGE_RETURN(AllocateBuffer(
                                                      &m_resMetadataTileLineBuffer,
                                                      hcpBufSizeParam.dwBufferSize,
                                                      "MetadataTileLineBuffer"),
            "Failed to allocate meta data tile line Buffer.");
    }

    CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->IsVp9BufferReallocNeeded(
        MHW_VDBOX_HCP_INTERNAL_BUFFER_META_TILE_COL,
        &reallocParam));
    if (reallocParam.bNeedBiggerSize ||
        Mos_ResourceIsNull(&m_resMetadataTileColumnBuffer))
    {
        if (!Mos_ResourceIsNull(&m_resMetadataTileColumnBuffer))
        {
            m_osInterface->pfnFreeResource(
                m_osInterface,
                &m_resMetadataTileColumnBuffer);
        }
        // Metadata Tile Column buffer
        CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->GetVp9BufferSize(
        MHW_VDBOX_HCP_INTERNAL_BUFFER_META_TILE_COL,
        &hcpBufSizeParam));

        CODECHAL_DECODE_CHK_STATUS_MESSAGE_RETURN(AllocateBuffer(
                                                      &m_resMetadataTileColumnBuffer,
                                                      hcpBufSizeParam.dwBufferSize,
                                                      "MetadataTileColumnBuffer"),
            "Failed to allocate meta data tile column Buffer.");
    }

    if (!m_hcpInterface->IsVp9HvdRowstoreCacheEnabled())
    {
        CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->IsVp9BufferReallocNeeded(
            MHW_VDBOX_VP9_INTERNAL_BUFFER_HVD_LINE,
            &reallocParam));
        if (reallocParam.bNeedBiggerSize ||
            Mos_ResourceIsNull(&m_resHvcLineRowstoreBuffer))
        {
            if (!Mos_ResourceIsNull(&m_resHvcLineRowstoreBuffer))
            {
                m_osInterface->pfnFreeResource(
                    m_osInterface,
                    &m_resHvcLineRowstoreBuffer);
            }

            // HVC Line Row Store Buffer
            CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->GetVp9BufferSize(
                MHW_VDBOX_VP9_INTERNAL_BUFFER_HVD_LINE,
                &hcpBufSizeParam));

            CODECHAL_DECODE_CHK_STATUS_MESSAGE_RETURN(AllocateBuffer(
                                                          &m_resHvcLineRowstoreBuffer,
                                                          hcpBufSizeParam.dwBufferSize,
                                                          "HvcLineRowStoreBuffer"),
                "Failed to allocate Hvc line row store Buffer.");
        }
    }

    CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->IsVp9BufferReallocNeeded(
        MHW_VDBOX_VP9_INTERNAL_BUFFER_HVD_TILE,
        &reallocParam));
    if (reallocParam.bNeedBiggerSize ||
        Mos_ResourceIsNull(&m_resHvcTileRowstoreBuffer))
    {
        if (!Mos_ResourceIsNull(&m_resHvcTileRowstoreBuffer))
        {
            m_osInterface->pfnFreeResource(
                m_osInterface,
                &m_resHvcTileRowstoreBuffer);
        }
        // HVC Tile Row Store Buffer
        CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->GetVp9BufferSize(
            MHW_VDBOX_VP9_INTERNAL_BUFFER_HVD_TILE,
            &hcpBufSizeParam));

        CODECHAL_DECODE_CHK_STATUS_MESSAGE_RETURN(AllocateBuffer(
                                                      &m_resHvcTileRowstoreBuffer,
                                                      hcpBufSizeParam.dwBufferSize,
                                                      "HvcTileRowStoreBuffer"),
            "Failed to allocate Hvc tile row store Buffer.");
    }

    CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->IsVp9BufferReallocNeeded(
            MHW_VDBOX_VP9_INTERNAL_BUFFER_SEGMENT_ID,
            &reallocParam));
    if (reallocParam.bNeedBiggerSize ||
        Mos_ResourceIsNull(&m_resVp9SegmentIdBuffer))
    {
        if (!Mos_ResourceIsNull(&m_resVp9SegmentIdBuffer))
        {
            m_osInterface->pfnFreeResource(
                m_osInterface,
                &m_resVp9SegmentIdBuffer);
        }
        // VP9 Segment ID buffer
        CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->GetVp9BufferSize(
            MHW_VDBOX_VP9_INTERNAL_BUFFER_SEGMENT_ID,
            &hcpBufSizeParam));

        CODECHAL_DECODE_CHK_STATUS_MESSAGE_RETURN(AllocateBuffer(
                                                      &m_resVp9SegmentIdBuffer,
                                                      hcpBufSizeParam.dwBufferSize,
                                                      "Vp9SegmentIdBuffer"),
            "Failed to allocate VP9 segment ID Buffer.");
    }

    CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->IsVp9BufferReallocNeeded(
        MHW_VDBOX_VP9_INTERNAL_BUFFER_SEGMENT_ID,
        &reallocParam));
    if (reallocParam.bNeedBiggerSize || Mos_ResourceIsNull(&m_resSegmentIdBuffReset))
    {
        if (!Mos_ResourceIsNull(&m_resSegmentIdBuffReset))
        {
            m_osInterface->pfnFreeResource(
                m_osInterface,
                &m_resSegmentIdBuffReset);
        }
        // VP9 Segment ID Reset buffer
        CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->GetVp9BufferSize(
            MHW_VDBOX_VP9_INTERNAL_BUFFER_SEGMENT_ID,
            &hcpBufSizeParam));

        CODECHAL_DECODE_CHK_STATUS_MESSAGE_RETURN(AllocateBuffer(
                                                      &m_resSegmentIdBuffReset,
                                                      hcpBufSizeParam.dwBufferSize,
                                                      "SegmentIdBuffreset",
                                                      true,
                                                      0),
            "Failed to allocate segment ID reset Buffer.");
    }

    CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->IsVp9BufferReallocNeeded(
        MHW_VDBOX_HCP_INTERNAL_BUFFER_CURR_MV_TEMPORAL,
        &reallocParam));
    if (reallocParam.bNeedBiggerSize || m_mvBufferSize == 0)
    {
        for (uint8_t i = 0; i < CODECHAL_VP9_NUM_MV_BUFFERS; i++)
        {
            if (!Mos_ResourceIsNull(&m_resVp9MvTemporalBuffer[i]))
            {
                m_osInterface->pfnFreeResource(
                    m_osInterface,
                    &m_resVp9MvTemporalBuffer[i]);
            }
        }

        // VP9 MV Temporal buffers
        CODECHAL_DECODE_CHK_STATUS_RETURN(m_hcpInterface->GetVp9BufferSize(
            MHW_VDBOX_HCP_INTERNAL_BUFFER_CURR_MV_TEMPORAL,
            &hcpBufSizeParam));

        for (uint8_t i = 0; i < CODECHAL_VP9_NUM_MV_BUFFERS; i++)
        {
            CODECHAL_DECODE_CHK_STATUS_MESSAGE_RETURN(AllocateBuffer(
                                                          &m_resVp9MvTemporalBuffer[i],
                                                          hcpBufSizeParam.dwBufferSize,
                                                          "MvTemporalBuffer"),
                "Failed to allocate Mv temporal Buffer.");
        }

        m_mvBufferSize = hcpBufSizeParam.dwBufferSize;
    }

    if (m_secureDecoder)
    {
        CODECHAL_DECODE_CHK_STATUS_RETURN(m_secureDecoder->AllocateResource(this));
    }

    //backup allocated memory size
    m_allocatedWidthInSb  = widthInSb;
    m_allocatedHeightInSb = heightInSb;

    return eStatus;
}

MOS_STATUS CodechalDecodeVp9 :: InitializeBeginFrame()
{
    CODECHAL_DECODE_FUNCTION_ENTER;

    m_incompletePicture = false;
    m_copyDataBufferInUse = false;
    m_copyDataOffset      = 0;

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalDecodeVp9 :: CopyDataSurface()
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_DECODE_FUNCTION_ENTER;

    CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnSetGpuContext(
        m_osInterface,
        m_videoContextForWa));
    m_osInterface->pfnResetOsStates(m_osInterface);

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

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

    // Send command buffer header at the beginning (OS dependent)
    CODECHAL_DECODE_CHK_STATUS_RETURN(SendPrologWithFrameTracking(
        &cmdBuffer,
        false));

    CODECHAL_DECODE_CHK_STATUS_RETURN(HucCopy(
        &cmdBuffer,            // pCmdBuffer
        &m_resDataBuffer,      // presSrc
        &m_resCopyDataBuffer,  // presDst
        m_dataSize,            // u32CopyLength
        m_dataOffset,          // u32CopyInputOffset
        m_copyDataOffset));    // u32CopyOutputOffset

    m_copyDataOffset += MOS_ALIGN_CEIL(m_dataSize, MHW_CACHELINE_SIZE);

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

    CODECHAL_DECODE_CHK_STATUS_RETURN(m_miInterface->AddMiBatchBufferEnd(
        &cmdBuffer,
        nullptr));

    m_osInterface->pfnReturnCommandBuffer(m_osInterface, &cmdBuffer, 0);

    // sync resource
    if (!m_incompletePicture)
    {
        MOS_SYNC_PARAMS syncParams = g_cInitSyncParams;
        syncParams.GpuContext = m_videoContext;
        syncParams.presSyncResource = &m_resSyncObjectVideoContextInUse;
        CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnEngineSignal(m_osInterface, &syncParams));

        syncParams = g_cInitSyncParams;
        syncParams.GpuContext = m_videoContextForWa;
        syncParams.presSyncResource = &m_resSyncObjectVideoContextInUse;
        CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnEngineWait(m_osInterface, &syncParams));
    }

    CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnSubmitCommandBuffer(
        m_osInterface,
        &cmdBuffer,
        m_videoContextForWaUsesNullHw));

    CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnSetGpuContext(
        m_osInterface,
        m_videoContext));

    return eStatus;
}

MOS_STATUS CodechalDecodeVp9 :: CheckAndCopyBitStream()
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_DECODE_FUNCTION_ENTER;

    uint32_t badSliceChopping = 0;
    // No pVp9SliceParams is set from APP.
    if (m_vp9SliceParams == nullptr)
    {
        badSliceChopping = 0;
    }
    else
    {
        badSliceChopping = m_vp9SliceParams->wBadSliceChopping;
    }

    // No BSBytesInBuffer is sent from App, driver here just give an estimation.
    if (badSliceChopping != 0)
    {
        m_vp9PicParams->BSBytesInBuffer =
            (m_vp9PicParams->FrameWidthMinus1 + 1) * (m_vp9PicParams->FrameHeightMinus1 + 1) * 6;
    }

    if (IsFirstExecuteCall()) // first exec call
    {
        if (m_dataSize < m_vp9PicParams->BSBytesInBuffer)  // Current bitstream buffer is not big enough
        {
            // Allocate or reallocate the copy data buffer.
            if (m_copyDataBufferSize < MOS_ALIGN_CEIL(m_vp9PicParams->BSBytesInBuffer, 64))
            {
                if (!Mos_ResourceIsNull(&m_resCopyDataBuffer))
                {
                    m_osInterface->pfnFreeResource(
                        m_osInterface,
                        &m_resCopyDataBuffer);
                }

                m_copyDataBufferSize = MOS_ALIGN_CEIL(m_vp9PicParams->BSBytesInBuffer, 64);

                CODECHAL_DECODE_CHK_STATUS_MESSAGE_RETURN(AllocateBuffer(
                                                              &m_resCopyDataBuffer,
                                                              m_copyDataBufferSize,
                                                              "Vp9CopyDataBuffer"),
                    "Failed to allocate Vp9 copy data Buffer.");
            }

            // Copy bitstream into the copy buffer
            if (m_dataSize)
            {
                CODECHAL_DECODE_CHK_STATUS_RETURN(CopyDataSurface());

                m_copyDataBufferInUse = true;
            }

            m_incompletePicture = true;
        }
    }
    else // second and later exec calls
    {
        CODECHAL_DECODE_CHK_COND_RETURN(
            (m_copyDataOffset + m_dataSize > m_copyDataBufferSize),
            "Bitstream size exceeds copy data buffer size!");

        // Copy bitstream into the copy buffer
        if (m_dataSize)
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(CopyDataSurface());
        }

        if (m_copyDataOffset >= m_vp9PicParams->BSBytesInBuffer || badSliceChopping == 2)
        {
            m_incompletePicture = false;
        }
    }

    return eStatus;
}
MOS_STATUS CodechalDecodeVp9 :: InitializeDecodeMode ()
{
    //do nothing for VP9 Base class. will be overloaded by inherited class to support dynamic mode switch
    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalDecodeVp9::InitSfcState()
{
    // Default no SFC support
    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalDecodeVp9::SetFrameStates ()
{
    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_decodeParams.m_destSurface);
    CODECHAL_DECODE_CHK_NULL_RETURN(m_decodeParams.m_dataBuffer);

    m_dataSize         = m_decodeParams.m_dataSize;
    m_dataOffset       = m_decodeParams.m_dataOffset;
    m_vp9PicParams     = (PCODEC_VP9_PIC_PARAMS)m_decodeParams.m_picParams;
    m_vp9SegmentParams = (PCODEC_VP9_SEGMENT_PARAMS)m_decodeParams.m_iqMatrixBuffer;
    m_vp9SliceParams   = (PCODEC_VP9_SLICE_PARAMS)m_decodeParams.m_sliceParams;

    CODECHAL_DECODE_CHK_NULL_RETURN(m_vp9SegmentParams);

    m_destSurface   = *(m_decodeParams.m_destSurface);
    m_resDataBuffer = *(m_decodeParams.m_dataBuffer);
    if (m_decodeParams.m_coefProbBuffer)        // This is an optional buffer passed from App. To be removed once VP9 FF Decode Driver is mature.
    {
        m_resCoefProbBuffer = *(m_decodeParams.m_coefProbBuffer);
    }

    if (IsFirstExecuteCall())
    {
        CODECHAL_DECODE_CHK_STATUS_RETURN(InitializeBeginFrame());
    }

    CODECHAL_DECODE_CHK_STATUS_RETURN(CheckAndCopyBitStream());

    m_cencBuf = m_decodeParams.m_cencBuf;

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

    CODECHAL_DEBUG_TOOL(
        CODECHAL_DECODE_CHK_STATUS_RETURN(m_debugInterface->DumpBuffer(
            m_copyDataBufferInUse ? &m_resCopyDataBuffer : &m_resDataBuffer,
            CodechalDbgAttr::attrDecodeBitstream,
            "_DEC",
            m_copyDataBufferInUse ? m_copyDataBufferSize : m_dataSize,
            m_copyDataBufferInUse ? 0 : m_dataOffset,
            CODECHAL_NUM_MEDIA_STATES));)

    m_statusReportFeedbackNumber = m_vp9PicParams->StatusReportFeedbackNumber;
    m_width =
        MOS_MAX(m_width, (uint32_t)(m_vp9PicParams->FrameWidthMinus1 + 1));
    m_height =
        MOS_MAX(m_height, (uint32_t)(m_vp9PicParams->FrameHeightMinus1 + 1));
    m_usFrameWidthAlignedMinBlk =
        MOS_ALIGN_CEIL(m_vp9PicParams->FrameWidthMinus1 + 1, CODEC_VP9_MIN_BLOCK_WIDTH);
    m_usFrameHeightAlignedMinBlk =
        MOS_ALIGN_CEIL(m_vp9PicParams->FrameHeightMinus1 + 1, CODEC_VP9_MIN_BLOCK_WIDTH);

    // Overwrite the actual surface height with the coded height and width of the frame
    // for VP9 since it's possible for a VP9 frame to change size during playback
    m_destSurface.dwWidth  = m_vp9PicParams->FrameWidthMinus1 + 1;
    m_destSurface.dwHeight = m_vp9PicParams->FrameHeightMinus1 + 1;

    PCODEC_REF_LIST destEntry = m_vp9RefList[m_vp9PicParams->CurrPic.FrameIdx];

    // Clear FilterLevel Array inside segment data when filter_level inside picparam is zero
    if (m_cencBuf == nullptr)
    {
        MOS_ZeroMemory(destEntry, sizeof(CODEC_REF_LIST));
        // Clear FilterLevel Array inside segment data when filter_level inside picparam is zero
        if ((!m_vp9PicParams->filter_level))
        {
            PCODEC_VP9_SEG_PARAMS vp9SegData = &m_vp9SegmentParams->SegData[0];

            for (uint8_t i = 0; i < 8; i++)
            {
                *((uint32_t *)&vp9SegData->FilterLevel[0][0]) = 0;
                *((uint32_t *)&vp9SegData->FilterLevel[2][0]) = 0;
                vp9SegData++;      // Go on to next record.
            }
        }
    }
    destEntry->resRefPic     = m_destSurface.OsResource;
    destEntry->dwFrameWidth  = m_vp9PicParams->FrameWidthMinus1 + 1;
    destEntry->dwFrameHeight = m_vp9PicParams->FrameHeightMinus1 + 1;

    if (m_hcpInterface->IsRowStoreCachingSupported() &&
        m_usFrameWidthAlignedMinBlk != MOS_ALIGN_CEIL(m_prevFrmWidth, CODEC_VP9_MIN_BLOCK_WIDTH))
    {
        MHW_VDBOX_ROWSTORE_PARAMS rowstoreParams;
        uint8_t usChromaSamplingFormat;
        if (m_vp9PicParams->subsampling_x == 1 && m_vp9PicParams->subsampling_y == 1)
        {
            usChromaSamplingFormat = HCP_CHROMA_FORMAT_YUV420;
        }
        else if (m_vp9PicParams->subsampling_x == 0 && m_vp9PicParams->subsampling_y == 0)
        {
            usChromaSamplingFormat = HCP_CHROMA_FORMAT_YUV444;
        }
        else
        {
            CODECHAL_DECODE_ASSERTMESSAGE("Invalid Chroma sampling format!");
            eStatus = MOS_STATUS_INVALID_PARAMETER;
            return eStatus;
        }
        MOS_ZeroMemory(&rowstoreParams, sizeof(rowstoreParams));
        rowstoreParams.dwPicWidth       = m_usFrameWidthAlignedMinBlk;
        rowstoreParams.bMbaff       = false;
        rowstoreParams.Mode         = CODECHAL_DECODE_MODE_VP9VLD;
        rowstoreParams.ucBitDepthMinus8 = m_vp9PicParams->BitDepthMinus8;
        rowstoreParams.ucChromaFormat   = usChromaSamplingFormat;
        CODECHAL_DECODE_CHK_STATUS_RETURN(m_hwInterface->SetRowstoreCachingOffsets(&rowstoreParams));
    }

    CODECHAL_DECODE_CHK_STATUS_RETURN(InitializeDecodeMode());
    CODECHAL_DECODE_CHK_STATUS_RETURN(InitSfcState());

    // Allocate internal buffer or reallocate When current resolution is bigger than allocated internal buffer size
    CODECHAL_DECODE_CHK_STATUS_RETURN(AllocateResourcesVariableSizes());

    CODECHAL_DECODE_CHK_STATUS_RETURN(DetermineInternalBufferUpdate());

    m_hcpDecPhase = CodechalHcpDecodePhaseInitialized;

    m_perfType = m_vp9PicParams->PicFlags.fields.frame_type ? P_TYPE : I_TYPE;

    m_crrPic = m_vp9PicParams->CurrPic;

    if (m_vp9PicParams->PicFlags.fields.frame_type == CODEC_VP9_INTER_FRAME &&
        !m_vp9PicParams->PicFlags.fields.intra_only)
    {
        m_curMvTempBufIdx = (m_curMvTempBufIdx + 1) % CODECHAL_VP9_NUM_MV_BUFFERS;
        m_colMvTempBufIdx = (m_curMvTempBufIdx < 1) ? (CODECHAL_VP9_NUM_MV_BUFFERS - 1) : (m_curMvTempBufIdx - 1);
    }

    CODECHAL_DEBUG_TOOL(
        CODECHAL_DECODE_CHK_NULL_RETURN(m_debugInterface);
        m_vp9PicParams->CurrPic.PicFlags = PICTURE_FRAME;
        m_debugInterface->m_currPic      = m_crrPic;
        m_debugInterface->m_frameType    = m_perfType;

        CODECHAL_DECODE_CHK_STATUS_RETURN(DumpDecodePicParams(
            m_vp9PicParams));

        CODECHAL_DECODE_CHK_STATUS_RETURN(DumpDecodeSliceParams(
            m_vp9SliceParams));

        if (m_vp9SegmentParams) {
            CODECHAL_DECODE_CHK_STATUS_RETURN(DumpDecodeSegmentParams(
                m_vp9SegmentParams));
        })

    return eStatus;
}

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

    CODECHAL_DECODE_FUNCTION_ENTER;

    uint32_t curPhase = m_hcpDecPhase;
    switch (curPhase)
    {
    case CodechalHcpDecodePhaseInitialized:
        m_hcpDecPhase = CodechalHcpDecodePhaseLegacyLong;
        break;
    default:
        eStatus = MOS_STATUS_INVALID_PARAMETER;
        CODECHAL_DECODE_ASSERTMESSAGE("invalid decode phase.");
        return eStatus;
    }

    return eStatus;
}

MOS_STATUS CodechalDecodeVp9 :: InitPicStateMhwParams()
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
    PMOS_RESOURCE usedDummyReference = nullptr;

    CODECHAL_DECODE_FUNCTION_ENTER;

    // Reset all pic Mhw Params
    *m_picMhwParams.PipeModeSelectParams = {};
    *m_picMhwParams.PipeBufAddrParams = {};
    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));

    PCODEC_PICTURE refFrameList      = &(m_vp9PicParams->RefFrameList[0]);
    uint8_t        lastRefPicIndex   = m_vp9PicParams->PicFlags.fields.LastRefIdx;
    uint8_t        goldenRefPicIndex = m_vp9PicParams->PicFlags.fields.GoldenRefIdx;
    uint8_t        altRefPicIndex    = m_vp9PicParams->PicFlags.fields.AltRefIdx;
    if (m_vp9PicParams->PicFlags.fields.frame_type == CODEC_VP9_KEY_FRAME ||
        m_vp9PicParams->PicFlags.fields.intra_only)
    {
        // reference surface should be nullptr when key_frame == true or intra only frame
        m_presLastRefSurface   = nullptr;
        m_presGoldenRefSurface = nullptr;
        m_presAltRefSurface    = nullptr;
    }
    else
    {
        if (lastRefPicIndex > 7 || goldenRefPicIndex > 7 || altRefPicIndex > 7)
        {
            CODECHAL_DECODE_ASSERTMESSAGE("invalid ref index (should be in [0,7]) in pic parameter!");
            eStatus = MOS_STATUS_INVALID_PARAMETER;
            return eStatus;
        }

        if (refFrameList[lastRefPicIndex].FrameIdx >= CODECHAL_NUM_UNCOMPRESSED_SURFACE_VP9)
        {
            refFrameList[lastRefPicIndex].FrameIdx = CODECHAL_NUM_UNCOMPRESSED_SURFACE_VP9 - 1;
        }
        if (refFrameList[goldenRefPicIndex].FrameIdx >= CODECHAL_NUM_UNCOMPRESSED_SURFACE_VP9)
        {
            refFrameList[goldenRefPicIndex].FrameIdx = CODECHAL_NUM_UNCOMPRESSED_SURFACE_VP9 - 1;
        }
        if (refFrameList[altRefPicIndex].FrameIdx >= CODECHAL_NUM_UNCOMPRESSED_SURFACE_VP9)
        {
            refFrameList[altRefPicIndex].FrameIdx = CODECHAL_NUM_UNCOMPRESSED_SURFACE_VP9 - 1;
        }
        PCODEC_REF_LIST *vp9RefList = &(m_vp9RefList[0]);
        m_presLastRefSurface        = &(vp9RefList[refFrameList[lastRefPicIndex].FrameIdx]->resRefPic);
        m_presGoldenRefSurface      = &(vp9RefList[refFrameList[goldenRefPicIndex].FrameIdx]->resRefPic);
        m_presAltRefSurface         = &(vp9RefList[refFrameList[altRefPicIndex].FrameIdx]->resRefPic);
    }

    uint16_t usChromaSamplingFormat;
    if (m_vp9PicParams->subsampling_x == 1 && m_vp9PicParams->subsampling_y == 1)
    {
        usChromaSamplingFormat = HCP_CHROMA_FORMAT_YUV420;
    }
    else if (m_vp9PicParams->subsampling_x == 0 && m_vp9PicParams->subsampling_y == 0)
    {
        usChromaSamplingFormat = HCP_CHROMA_FORMAT_YUV444;
    }
    else
    {
        CODECHAL_DECODE_ASSERTMESSAGE("Invalid Chroma sampling format!");
        eStatus = MOS_STATUS_INVALID_PARAMETER;
        return eStatus;
    }

    m_picMhwParams.PipeModeSelectParams->Mode                  = m_mode;
    m_picMhwParams.PipeModeSelectParams->bStreamOutEnabled     = m_streamOutEnabled;

    // Populate surface param for decoded picture
    m_picMhwParams.SurfaceParams[0]->Mode               = m_mode;
    m_picMhwParams.SurfaceParams[0]->psSurface              = &m_destSurface;
    m_picMhwParams.SurfaceParams[0]->ChromaType         = (uint8_t)usChromaSamplingFormat;
    m_picMhwParams.SurfaceParams[0]->ucSurfaceStateId   = CODECHAL_HCP_DECODED_SURFACE_ID;
    m_picMhwParams.SurfaceParams[0]->ucBitDepthLumaMinus8   = m_vp9PicParams->BitDepthMinus8;
    m_picMhwParams.SurfaceParams[0]->ucBitDepthChromaMinus8 = m_vp9PicParams->BitDepthMinus8;
    m_picMhwParams.SurfaceParams[0]->dwUVPlaneAlignment = 8;

    if (MEDIA_IS_WA(m_waTable, WaDummyReference) &&
        !Mos_ResourceIsNull(&m_dummyReference.OsResource))
    {
        usedDummyReference = &m_dummyReference.OsResource;
    }
    else
    {
        usedDummyReference = &m_destSurface.OsResource;
    }

    // Populate surface param for reference pictures
    if (m_vp9PicParams->PicFlags.fields.frame_type == CODEC_VP9_INTER_FRAME &&
        !m_vp9PicParams->PicFlags.fields.intra_only &&
        m_presLastRefSurface != nullptr &&
        m_presGoldenRefSurface != nullptr &&
        m_presAltRefSurface != nullptr)
    {
        if (Mos_ResourceIsNull(m_presLastRefSurface))
        {
            m_presLastRefSurface = usedDummyReference;
        }
        if (Mos_ResourceIsNull(m_presGoldenRefSurface))
        {
            m_presGoldenRefSurface = usedDummyReference;
        }
        if (Mos_ResourceIsNull(m_presAltRefSurface))
        {
            m_presAltRefSurface = usedDummyReference;
        }

        //MOS_SURFACE lastRefSurface;
        CODECHAL_DECODE_CHK_STATUS_RETURN(MOS_SecureMemcpy(
            &m_lastRefSurface.OsResource,
            sizeof(MOS_RESOURCE),
            m_presLastRefSurface,
            sizeof(MOS_RESOURCE)));
        CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalGetResourceInfo(
            m_osInterface,
            &m_lastRefSurface));

        //MOS_SURFACE goldenRefSurface;
        CODECHAL_DECODE_CHK_STATUS_RETURN(MOS_SecureMemcpy(
            &m_goldenRefSurface.OsResource,
            sizeof(MOS_RESOURCE),
            m_presGoldenRefSurface,
            sizeof(MOS_RESOURCE)));
        CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalGetResourceInfo(
            m_osInterface,
            &m_goldenRefSurface));

        //MOS_SURFACE altRefSurface;
        CODECHAL_DECODE_CHK_STATUS_RETURN(MOS_SecureMemcpy(
            &m_altRefSurface.OsResource,
            sizeof(MOS_RESOURCE),
            m_presAltRefSurface,
            sizeof(MOS_RESOURCE)));
        CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalGetResourceInfo(
            m_osInterface,
            &m_altRefSurface));

        for (uint8_t i = 1; i < 4; i++)
        {
            m_picMhwParams.SurfaceParams[i]->Mode               = m_mode;
            m_picMhwParams.SurfaceParams[i]->ChromaType         = (uint8_t)usChromaSamplingFormat;
            m_picMhwParams.SurfaceParams[i]->dwUVPlaneAlignment = 8;

            switch (i)
            {
                case 1:
                    m_picMhwParams.SurfaceParams[i]->psSurface          = &m_lastRefSurface;
                    m_picMhwParams.SurfaceParams[i]->ucSurfaceStateId   = CODECHAL_HCP_LAST_SURFACE_ID;
                    break;
                case 2:
                    m_picMhwParams.SurfaceParams[i]->psSurface          = &m_goldenRefSurface;
                    m_picMhwParams.SurfaceParams[i]->ucSurfaceStateId   = CODECHAL_HCP_GOLDEN_SURFACE_ID;
                    break;
                case 3:
                    m_picMhwParams.SurfaceParams[i]->psSurface          = &m_altRefSurface;
                    m_picMhwParams.SurfaceParams[i]->ucSurfaceStateId   = CODECHAL_HCP_ALTREF_SURFACE_ID;
                    break;
            }
        }
    }

    m_picMhwParams.PipeBufAddrParams->Mode                                          = m_mode;
    m_picMhwParams.PipeBufAddrParams->psPreDeblockSurface                           = &m_destSurface;

    m_picMhwParams.PipeBufAddrParams->presReferences[CodechalDecodeLastRef]      = m_presLastRefSurface;
    m_picMhwParams.PipeBufAddrParams->presReferences[CodechalDecodeGoldenRef]    = m_presGoldenRefSurface;
    m_picMhwParams.PipeBufAddrParams->presReferences[CodechalDecodeAlternateRef] = m_presAltRefSurface;

    // set all ref pic addresses in HCP_PIPE_BUF_ADDR_STATE command to valid addresses for error concealment purpose, set the unused ones to the first used one
    for (uint8_t i = 0; i < CODECHAL_DECODE_VP9_MAX_NUM_REF_FRAME; i++)
    {
        if (!m_picMhwParams.PipeBufAddrParams->presReferences[i])
        {
            m_picMhwParams.PipeBufAddrParams->presReferences[i] = usedDummyReference;
        }
    }

#ifdef _MMC_SUPPORTED
    CODECHAL_DECODE_CHK_STATUS_RETURN(m_mmc->SetPipeBufAddr(m_picMhwParams.PipeBufAddrParams));
#endif

    if (m_streamOutEnabled)
    {
        m_picMhwParams.PipeBufAddrParams->presStreamOutBuffer =
            &(m_streamOutBuffer[m_streamOutCurrBufIdx]);
    }

#ifdef _MMC_SUPPORTED
    CODECHAL_DECODE_CHK_STATUS_RETURN(m_mmc->CheckReferenceList(m_picMhwParams.PipeBufAddrParams));

    CODECHAL_DECODE_CHK_STATUS_RETURN(m_mmc->SetRefrenceSync(m_disableDecodeSyncLock, m_disableLockForTranscode));
#endif

    m_picMhwParams.PipeBufAddrParams->presMfdDeblockingFilterRowStoreScratchBuffer =
        &m_resDeblockingFilterLineRowStoreScratchBuffer;
    m_picMhwParams.PipeBufAddrParams->presDeblockingFilterTileRowStoreScratchBuffer =
        &m_resDeblockingFilterTileRowStoreScratchBuffer;
    m_picMhwParams.PipeBufAddrParams->presDeblockingFilterColumnRowStoreScratchBuffer =
        &m_resDeblockingFilterColumnRowStoreScratchBuffer;

    m_picMhwParams.PipeBufAddrParams->presMetadataLineBuffer       = &m_resMetadataLineBuffer;
    m_picMhwParams.PipeBufAddrParams->presMetadataTileLineBuffer   = &m_resMetadataTileLineBuffer;
    m_picMhwParams.PipeBufAddrParams->presMetadataTileColumnBuffer = &m_resMetadataTileColumnBuffer;
    m_picMhwParams.PipeBufAddrParams->presVp9ProbBuffer            = &m_resVp9ProbBuffer[m_frameCtxIdx];
    m_picMhwParams.PipeBufAddrParams->presVp9SegmentIdBuffer       = &m_resVp9SegmentIdBuffer;
    m_picMhwParams.PipeBufAddrParams->presHvdLineRowStoreBuffer    = &m_resHvcLineRowstoreBuffer;
    m_picMhwParams.PipeBufAddrParams->presHvdTileRowStoreBuffer    = &m_resHvcTileRowstoreBuffer;

    if (m_vp9PicParams->PicFlags.fields.frame_type == CODEC_VP9_INTER_FRAME &&
        !m_vp9PicParams->PicFlags.fields.intra_only)
    {
        m_picMhwParams.PipeBufAddrParams->presCurMvTempBuffer = &m_resVp9MvTemporalBuffer[m_curMvTempBufIdx];

        if (!m_prevFrameParams.fields.KeyFrame && !m_prevFrameParams.fields.IntraOnly)
        {
            // For VP9, only index 0 is required to be filled
            m_picMhwParams.PipeBufAddrParams->presColMvTempBuffer[0] = &m_resVp9MvTemporalBuffer[m_colMvTempBufIdx];
        }
    }

    m_picMhwParams.IndObjBaseAddrParams->Mode           = m_mode;
    m_picMhwParams.IndObjBaseAddrParams->dwDataSize     = m_copyDataBufferInUse ? m_copyDataBufferSize : m_dataSize;
    m_picMhwParams.IndObjBaseAddrParams->dwDataOffset   = m_copyDataBufferInUse ? 0 : m_dataOffset;
    m_picMhwParams.IndObjBaseAddrParams->presDataBuffer = m_copyDataBufferInUse ? &m_resCopyDataBuffer : &m_resDataBuffer;

    if (m_secureDecoder)
    {
        CODECHAL_DECODE_CHK_STATUS_RETURN(m_secureDecoder->SetBitstreamBuffer(m_picMhwParams.IndObjBaseAddrParams));
    }

    m_picMhwParams.Vp9PicState->pVp9PicParams         = m_vp9PicParams;
    m_picMhwParams.Vp9PicState->ppVp9RefList          = &(m_vp9RefList[0]);
    m_picMhwParams.Vp9PicState->PrevFrameParams.value = m_prevFrameParams.value;
    m_picMhwParams.Vp9PicState->dwPrevFrmWidth        = m_prevFrmWidth;
    m_picMhwParams.Vp9PicState->dwPrevFrmHeight       = m_prevFrmHeight;

    m_prevFrameParams.fields.KeyFrame  = !m_vp9PicParams->PicFlags.fields.frame_type;
    m_prevFrameParams.fields.IntraOnly = m_vp9PicParams->PicFlags.fields.intra_only;
    m_prevFrameParams.fields.Display   = m_vp9PicParams->PicFlags.fields.show_frame;
    m_prevFrmWidth                     = m_vp9PicParams->FrameWidthMinus1 + 1;
    m_prevFrmHeight                    = m_vp9PicParams->FrameHeightMinus1 + 1;

    m_picMhwParams.Vp9SegmentState->Mode                = m_mode;
    m_picMhwParams.Vp9SegmentState->pVp9SegmentParams   = m_vp9SegmentParams;

    CODECHAL_DEBUG_TOOL(
        if (m_vp9PicParams->PicFlags.fields.frame_type == CODEC_VP9_INTER_FRAME)
        {
            for (uint16_t n = 0; n < CODECHAL_MAX_CUR_NUM_REF_FRAME_VP9; n++)
            {
                if (m_picMhwParams.PipeBufAddrParams->presReferences[n])
                {
                    MOS_SURFACE dstSurface;
                    MOS_ZeroMemory(&dstSurface, sizeof(MOS_SURFACE));
                    dstSurface.OsResource = *(m_picMhwParams.PipeBufAddrParams->presReferences[n]);
                    CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalGetResourceInfo(
                        m_osInterface,
                        &dstSurface));

                    m_debugInterface->m_refIndex = n;
                    std::string refSurfName      = "RefSurf[" + std::to_string(static_cast<uint32_t>(m_debugInterface->m_refIndex)) + "]";
                    CODECHAL_DECODE_CHK_STATUS_RETURN(m_debugInterface->DumpYUVSurface(
                        &dstSurface,
                        CodechalDbgAttr::attrDecodeReferenceSurfaces,
                        refSurfName.c_str()));
                }
            }
        }

        if (m_picMhwParams.PipeBufAddrParams->presColMvTempBuffer[0])
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(m_debugInterface->DumpBuffer(
                m_picMhwParams.PipeBufAddrParams->presColMvTempBuffer[0],
                CodechalDbgAttr::attrMvData,
                "DEC_Col_MV_",
                m_mvBufferSize));
        }

        if (m_picMhwParams.PipeBufAddrParams->presCurMvTempBuffer)
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(m_debugInterface->DumpBuffer(
                m_picMhwParams.PipeBufAddrParams->presCurMvTempBuffer,
                CodechalDbgAttr::attrMvData,
                "DEC_Cur_MV_",
                m_mvBufferSize));
        };
    );

    return eStatus;
}

MOS_STATUS CodechalDecodeVp9 :: AddPicStateMhwCmds(
    PMOS_COMMAND_BUFFER       cmdBuffer)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_DECODE_FUNCTION_ENTER;

    CODECHAL_DECODE_CHK_NULL_RETURN(cmdBuffer);

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

    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)
    {
        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)
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(m_secureDecoder->AddHcpSecureState(
                cmdBuffer,
                this));
        }
    }
    return eStatus;
}

MOS_STATUS CodechalDecodeVp9 :: UpdatePicStateBuffers(
    PMOS_COMMAND_BUFFER       cmdBuffe)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_DECODE_FUNCTION_ENTER;

    if (m_resetSegIdBuffer)
    {
        if (m_osInterface->osCpInterface->IsHMEnabled())
        {
            if (m_secureDecoder)
            {
                CODECHAL_DECODE_CHK_STATUS_RETURN(m_secureDecoder->ResetVP9SegIdBufferWithHuc(this, cmdBuffe));
            }
        }
        else
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(ResetSegIdBufferwithDrv());
        }
    }

    if (m_osInterface->osCpInterface->IsHMEnabled())
    {
        if (m_secureDecoder)
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(m_secureDecoder->UpdateVP9ProbBufferWithHuc(m_fullProbBufferUpdate, this, cmdBuffe));
        }
    }
    else
    {
        if (m_fullProbBufferUpdate)
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(ProbBufFullUpdatewithDrv());
        }
        else
        {
            CODECHAL_DECODE_CHK_STATUS_RETURN(ProbBufferPartialUpdatewithDrv());
        }
    }

    CODECHAL_DEBUG_TOOL(
        CODECHAL_DECODE_CHK_STATUS_RETURN(m_debugInterface->DumpBuffer(
            &m_resVp9SegmentIdBuffer,
            CodechalDbgAttr::attrSegId,
            "SegId_beforeHCP",
            (m_allocatedWidthInSb * m_allocatedHeightInSb * CODECHAL_CACHELINE_SIZE)));
        CODECHAL_DECODE_CHK_STATUS_RETURN(m_debugInterface->DumpBuffer(
            &(m_resVp9ProbBuffer[m_frameCtxIdx]),
            CodechalDbgAttr::attrCoefProb,
            "PakHwCoeffProbs_beforeHCP",
            CODEC_VP9_PROB_MAX_NUM_ELEM));)

    return eStatus;
}

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

    PERF_UTILITY_AUTO(__FUNCTION__, PERF_DECODE, PERF_LEVEL_HAL);
    CODECHAL_DECODE_FUNCTION_ENTER;

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

    //HCP Decode Phase State Machine
    DetermineDecodePhase();

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

    auto mmioRegisters = m_hwInterface->GetMfxInterface()->GetMmioRegisters(m_vdboxIndex);
    HalOcaInterface::On1stLevelBBStart(cmdBuffer, *m_osInterface->pOsContext, m_osInterface->CurrentGpuContextHandle, *m_miInterface, *mmioRegisters);

    //Frame tracking functionality is called at the start of a command buffer.
    //Called at FE decode phase, since BE decode phase will only construct BE batch buffers.
    CODECHAL_DECODE_CHK_STATUS_RETURN(SendPrologWithFrameTracking(
        &cmdBuffer, true));

    CODECHAL_DECODE_CHK_STATUS_RETURN(InitPicStateMhwParams());

    CODECHAL_DECODE_CHK_STATUS_RETURN(UpdatePicStateBuffers(&cmdBuffer));

    if (m_statusQueryReportingEnabled)
    {
        CODECHAL_DECODE_CHK_STATUS_RETURN(
            StartStatusReport(&cmdBuffer));
    }

    CODECHAL_DECODE_CHK_STATUS_RETURN(AddPicStateMhwCmds(
        &cmdBuffer));
    m_osInterface->pfnReturnCommandBuffer(m_osInterface, &cmdBuffer, 0);

    return eStatus;
}

MOS_STATUS CodechalDecodeVp9 :: DecodePrimitiveLevel()
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    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_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 cmdBuffer;
    CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnGetCommandBuffer(
        m_osInterface,
        &cmdBuffer,
        0));

    if (m_cencBuf == nullptr)
    {
        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(
            &cmdBuffer,
            &bsdParams));
    }

    // 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(
        &cmdBuffer,
        &vdpipeFlushParams));

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

    MOS_SYNC_PARAMS syncParams;
    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(
            &cmdBuffer,
            &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;

        // 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,
            &cmdBuffer));
    }

    CODECHAL_DECODE_CHK_STATUS_RETURN(m_miInterface->AddMiFlushDwCmd(
        &cmdBuffer,
        &flushDwParams));

    CODECHAL_DECODE_CHK_STATUS_RETURN(m_miInterface->AddMiBatchBufferEnd(
        &cmdBuffer,
        nullptr));

    m_osInterface->pfnReturnCommandBuffer(m_osInterface, &cmdBuffer, 0);

    CODECHAL_DEBUG_TOOL(
        CODECHAL_DECODE_CHK_STATUS_RETURN(m_debugInterface->DumpCmdBuffer(
            &cmdBuffer,
            CODECHAL_NUM_MEDIA_STATES,
            "_DEC"));

        //CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHal_DbgReplaceAllCommands(
        //    m_debugInterface,
        //    &cmdBuffer));

        m_mmc->UpdateUserFeatureKey(&m_destSurface);)

    bool syncCompleteFrame = m_copyDataBufferInUse;

    if (syncCompleteFrame)
    {
        //Sync up complete frame
        MOS_SYNC_PARAMS 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));
    }

    uint32_t renderingFlags = m_videoContextUsesNullHw;

    HalOcaInterface::On1stLevelBBEnd(cmdBuffer, *m_osInterface);

    //submit command buffer
    CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnSubmitCommandBuffer(
        m_osInterface,
        &cmdBuffer,
        renderingFlags));

    // Reset status report
    if (m_statusQueryReportingEnabled)
    {
        CODECHAL_DECODE_CHK_STATUS_RETURN(ResetStatusReport(
            m_videoContextUsesNullHw));
    }

#ifdef CODECHAL_HUC_KERNEL_DEBUG
    CODECHAL_DEBUG_TOOL(
    CODECHAL_DECODE_CHK_STATUS(m_debugInterface->DumpHucRegion(
        &pVp9State->resHucSharedBuffer,
        0,
        CODEC_VP9_PROB_MAX_NUM_ELEM,
        15,
        "",
        false,
        0,
        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
    // pVp9RefList[pVp9PicParams->ucCurrPicIndex]->resRefPic =
    //    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));

    return eStatus;
}

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

MOS_STATUS CodechalDecodeVp9 :: 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;

    MHW_VDBOX_STATE_CMDSIZE_PARAMS      stateCmdSizeParams;
    stateCmdSizeParams.bHucDummyStream = false;

    // 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);

    CODECHAL_DECODE_CHK_STATUS_RETURN(AllocateResourcesFixedSizes());

    // Prepare Pic Params
    m_picMhwParams.PipeModeSelectParams = MOS_New(MHW_VDBOX_PIPE_MODE_SELECT_PARAMS);
    m_picMhwParams.PipeBufAddrParams = MOS_New(MHW_VDBOX_PIPE_BUF_ADDR_PARAMS);
    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;
}

#if USE_CODECHAL_DEBUG_TOOL
MOS_STATUS CodechalDecodeVp9::DumpDecodePicParams(
    PCODEC_VP9_PIC_PARAMS picParams)
{
    CODECHAL_DEBUG_FUNCTION_ENTER;

    if (!m_debugInterface->DumpIsEnabled(CodechalDbgAttr::attrPicParams))
    {
        return MOS_STATUS_SUCCESS;
    }
    CODECHAL_DEBUG_CHK_NULL(picParams);

    std::ostringstream oss;
    oss.setf(std::ios::showbase | std::ios::uppercase);

    oss << "CurrPic FrameIdx: " << std::hex << +picParams->CurrPic.FrameIdx << std::endl;
    oss << "CurrPic PicFlags: " << std::hex << +picParams->CurrPic.PicFlags << std::endl;

    for (uint8_t i = 0; i < 8; ++i)
    {
        oss << "RefFrameList["<<+i<<"] FrameIdx:" << std::hex << +picParams->RefFrameList[i].FrameIdx << std::endl;
        oss << "RefFrameList["<<+i<<"] PicFlags:" << std::hex << +picParams->RefFrameList[i].PicFlags << std::endl;
    }
    oss << "FrameWidthMinus1: " << std::hex << +picParams->FrameWidthMinus1 << std::endl;
    oss << "FrameHeightMinus1: " << std::hex << +picParams->FrameHeightMinus1 << std::endl;
    oss << "PicFlags value: " << std::hex << +picParams->PicFlags.value << std::endl;
    oss << "frame_type: " << std::hex << +picParams->PicFlags.fields.frame_type << std::endl;
    oss << "show_frame: " << std::hex << +picParams->PicFlags.fields.show_frame << std::endl;
    oss << "error_resilient_mode: " << std::hex << +picParams->PicFlags.fields.error_resilient_mode << std::endl;
    oss << "intra_only: " << std::hex << +picParams->PicFlags.fields.intra_only << std::endl;
    oss << "LastRefIdx: " << std::hex << +picParams->PicFlags.fields.LastRefIdx << std::endl;
    oss << "LastRefSignBias: " << std::hex << +picParams->PicFlags.fields.LastRefSignBias << std::endl;
    oss << "GoldenRefIdx: " << std::hex << +picParams->PicFlags.fields.GoldenRefIdx << std::endl;
    oss << "GoldenRefSignBias: " << std::hex << +picParams->PicFlags.fields.GoldenRefSignBias << std::endl;
    oss << "AltRefIdx: " << std::hex << +picParams->PicFlags.fields.AltRefIdx << std::endl;
    oss << "AltRefSignBias: " << std::hex << +picParams->PicFlags.fields.AltRefSignBias << std::endl;
    oss << "allow_high_precision_mv: " << std::hex << +picParams->PicFlags.fields.allow_high_precision_mv << std::endl;
    oss << "mcomp_filter_type: " << std::hex << +picParams->PicFlags.fields.mcomp_filter_type << std::endl;
    oss << "frame_parallel_decoding_mode: " << std::hex << +picParams->PicFlags.fields.frame_parallel_decoding_mode << std::endl;
    oss << "segmentation_enabled: " << std::hex << +picParams->PicFlags.fields.segmentation_enabled << std::endl;
    oss << "segmentation_temporal_update: " << std::hex << +picParams->PicFlags.fields.segmentation_temporal_update << std::endl;
    oss << "segmentation_update_map: " << std::hex << +picParams->PicFlags.fields.segmentation_update_map << std::endl;
    oss << "reset_frame_context: " << std::hex << +picParams->PicFlags.fields.reset_frame_context << std::endl;
    oss << "refresh_frame_context: " << std::hex << +picParams->PicFlags.fields.refresh_frame_context << std::endl;
    oss << "frame_context_idx: " << std::hex << +picParams->PicFlags.fields.frame_context_idx << std::endl;
    oss << "LosslessFlag: " << std::hex << +picParams->PicFlags.fields.LosslessFlag << std::endl;
    oss << "ReservedField: " << std::hex << +picParams->PicFlags.fields.ReservedField << std::endl;
    oss << "filter_level: " << std::hex << +picParams->filter_level << std::endl;
    oss << "sharpness_level: " << std::hex << +picParams->sharpness_level << std::endl;
    oss << "log2_tile_rows: " << std::hex << +picParams->log2_tile_rows << std::endl;
    oss << "log2_tile_columns: " << std::hex << +picParams->log2_tile_columns << std::endl;
    oss << "UncompressedHeaderLengthInBytes: " << std::hex << +picParams->UncompressedHeaderLengthInBytes << std::endl;
    oss << "FirstPartitionSize: " << std::hex << +picParams->FirstPartitionSize << std::endl;
    oss << "profile: " << std::hex << +picParams->profile << std::endl;
    oss << "BitDepthMinus8: " << std::hex << +picParams->BitDepthMinus8 << std::endl;
    oss << "subsampling_x: " << std::hex << +picParams->subsampling_x << std::endl;
    oss << "subsampling_y: " << std::hex << +picParams->subsampling_y << std::endl;

    for (uint8_t i = 0; i < 7; ++i)
    {
        oss << "SegTreeProbs["<<+i<<"]: " << std::hex << +picParams->SegTreeProbs[i] << std::endl;
    }
    for (uint8_t i = 0; i < 3; ++i)
    {
        oss << "SegPredProbs["<<+i<<"]: " << std::hex << +picParams->SegPredProbs[i] << std::endl;
    }
    oss << "BSBytesInBuffer: " << std::hex << +picParams->BSBytesInBuffer << std::endl;
    oss << "StatusReportFeedbackNumber: " << std::hex << +picParams->StatusReportFeedbackNumber << std::endl;

    const char* fileName = m_debugInterface->CreateFileName(
        "_DEC",
        CodechalDbgBufferType::bufPicParams,
        CodechalDbgExtType::txt);

    std::ofstream ofs(fileName, std::ios::out);
    ofs << oss.str();
    ofs.close();

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalDecodeVp9::DumpDecodeSliceParams(CODEC_VP9_SLICE_PARAMS *slcParams)
{
    CODECHAL_DEBUG_FUNCTION_ENTER;

    if (slcParams == nullptr)
    {
        return MOS_STATUS_SUCCESS;
    }

    if (m_debugInterface->DumpIsEnabled(CodechalDbgAttr::attrSlcParams))
    {
        const char *fileName = m_debugInterface->CreateFileName(
            "_DEC",
            CodechalDbgBufferType::bufSlcParams,
            CodechalDbgExtType::txt);

        DumpDecodeVp9SliceParams(slcParams, fileName);
    }

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalDecodeVp9::DumpDecodeSegmentParams(
    PCODEC_VP9_SEGMENT_PARAMS segmentParams)
{
    CODECHAL_DEBUG_FUNCTION_ENTER;

    if (!m_debugInterface->DumpIsEnabled(CodechalDbgAttr::attrSegmentParams))
    {
        return MOS_STATUS_SUCCESS;
    }

    CODECHAL_DEBUG_CHK_NULL(segmentParams);

    std::ostringstream oss;
    oss.setf(std::ios::showbase | std::ios::uppercase);

    for (uint8_t i = 0; i < 8; ++i)
    {
        oss << "SegData["<<+i<<"] SegmentFlags value: " << std::hex << +segmentParams->SegData[i].SegmentFlags.value << std::endl;
        oss << "SegData["<<+i<<"] SegmentReferenceEnabled: " << std::hex << +segmentParams->SegData[i].SegmentFlags.fields.SegmentReferenceEnabled << std::endl;
        oss << "SegData["<<+i<<"] SegmentReference: " << std::hex << +segmentParams->SegData[i].SegmentFlags.fields.SegmentReference << std::endl;
        oss << "SegData["<<+i<<"] SegmentReferenceSkipped: " << std::hex << +segmentParams->SegData[i].SegmentFlags.fields.SegmentReferenceSkipped << std::endl;
        oss << "SegData["<<+i<<"] ReservedField3: " << std::hex << +segmentParams->SegData[i].SegmentFlags.fields.ReservedField3 << std::endl;

        for (uint8_t j = 0; j < 4; ++j)
        {
            oss << "SegData["<<+i<<"] FilterLevel["<<+j<<"]:";
            oss << std::hex << +segmentParams->SegData[i].FilterLevel[j][0]<<" ";
            oss << std::hex<< +segmentParams->SegData[i].FilterLevel[j][1] << std::endl;
        }
        oss << "SegData["<<+i<<"] LumaACQuantScale: " << std::hex << +segmentParams->SegData[i].LumaACQuantScale << std::endl;
        oss << "SegData["<<+i<<"] LumaDCQuantScale: " << std::hex << +segmentParams->SegData[i].LumaDCQuantScale << std::endl;
        oss << "SegData["<<+i<<"] ChromaACQuantScale: " << std::hex << +segmentParams->SegData[i].ChromaACQuantScale << std::endl;
        oss << "SegData["<<+i<<"] ChromaDCQuantScale: " << std::hex << +segmentParams->SegData[i].ChromaDCQuantScale << std::endl;
    }

    const char* fileName = m_debugInterface->CreateFileName(
        "_DEC",
        CodechalDbgBufferType::bufSegmentParams,
        CodechalDbgExtType::txt);

    std::ofstream ofs(fileName, std::ios::out);
    ofs << oss.str();
    ofs.close();
    return MOS_STATUS_SUCCESS;
}

#endif

MOS_STATUS CodechalDecodeVp9::CtxBufDiffInit(
    uint8_t             *ctxBuffer,
    bool                 setToKey)
{
    int32_t i, j;
    uint32_t byteCnt = CODEC_VP9_INTER_PROB_OFFSET;
    //inter mode probs. have to be zeros for Key frame
    for (i = 0; i < CODEC_VP9_INTER_MODE_CONTEXTS; i++)
    {
        for (j = 0; j < CODEC_VP9_INTER_MODES - 1; j++)
        {
            if (!setToKey)
            {
                ctxBuffer[byteCnt++] = DefaultInterModeProbs[i][j];
            }
            else
            {
                //zeros for key frame
                byteCnt++;
            }
        }
    }
    //switchable interprediction probs
    for (i = 0; i < CODEC_VP9_SWITCHABLE_FILTERS + 1; i++)
    {
        for (j = 0; j < CODEC_VP9_SWITCHABLE_FILTERS - 1; j++)
        {
            if (!setToKey)
            {
                ctxBuffer[byteCnt++] = DefaultSwitchableInterpProb[i][j];
            }
            else
            {
                //zeros for key frame
                byteCnt++;
            }
        }
    }
    //intra inter probs
    for (i = 0; i < CODEC_VP9_INTRA_INTER_CONTEXTS; i++)
    {
        if (!setToKey)
        {
            ctxBuffer[byteCnt++] = DefaultIntraInterProb[i];
        }
        else
        {
            //zeros for key frame
            byteCnt++;
        }
    }
    //comp inter probs
    for (i = 0; i < CODEC_VP9_COMP_INTER_CONTEXTS; i++)
    {
        if (!setToKey)
        {
            ctxBuffer[byteCnt++] = DefaultCompInterProb[i];
        }
        else
        {
            //zeros for key frame
            byteCnt++;
        }
    }
    //single ref probs
    for (i = 0; i < CODEC_VP9_REF_CONTEXTS; i++)
    {
        for (j = 0; j < 2; j++)
        {
            if (!setToKey)
            {
                ctxBuffer[byteCnt++] = DefaultSingleRefProb[i][j];
            }
            else
            {
                //zeros for key frame
                byteCnt++;
            }
        }
    }
    //comp ref probs
    for (i = 0; i < CODEC_VP9_REF_CONTEXTS; i++)
    {
        if (!setToKey)
        {
            ctxBuffer[byteCnt++] = DefaultCompRefProb[i];
        }
        else
        {
            //zeros for key frame
            byteCnt++;
        }
    }
    //y mode probs
    for (i = 0; i < CODEC_VP9_BLOCK_SIZE_GROUPS; i++)
    {
        for (j = 0; j < CODEC_VP9_INTRA_MODES - 1; j++)
        {
            if (!setToKey)
            {
                ctxBuffer[byteCnt++] = DefaultIFYProb[i][j];
            }
            else
            {
                //zeros for key frame, since HW will not use this buffer, but default right buffer.
                byteCnt++;
            }
        }
    }
    //partition probs, key & intra-only frames use key type, other inter frames use inter type
    for (i = 0; i < CODECHAL_VP9_PARTITION_CONTEXTS; i++)
    {
        for (j = 0; j < CODEC_VP9_PARTITION_TYPES - 1; j++)
        {
            if (setToKey)
            {
                ctxBuffer[byteCnt++] = DefaultKFPartitionProb[i][j];
            }
            else
            {
                ctxBuffer[byteCnt++] = DefaultPartitionProb[i][j];
            }
        }
    }
    //nmvc joints
    for (i = 0; i < (CODEC_VP9_MV_JOINTS - 1); i++)
    {
        if (!setToKey)
        {
            ctxBuffer[byteCnt++] = DefaultNmvContext.joints[i];
        }
        else
        {
            //zeros for key frame
            byteCnt++;
        }
    }
    //nmvc comps
    for (i = 0; i < 2; i++)
    {
        if (!setToKey)
        {
            ctxBuffer[byteCnt++] = DefaultNmvContext.comps[i].sign;
            for (j = 0; j < (CODEC_VP9_MV_CLASSES - 1); j++)
            {
                ctxBuffer[byteCnt++] = DefaultNmvContext.comps[i].classes[j];
            }
            for (j = 0; j < (CODECHAL_VP9_CLASS0_SIZE - 1); j++)
            {
                ctxBuffer[byteCnt++] = DefaultNmvContext.comps[i].class0[j];
            }
            for (j = 0; j < CODECHAL_VP9_MV_OFFSET_BITS; j++)
            {
                ctxBuffer[byteCnt++] = DefaultNmvContext.comps[i].bits[j];
            }
        }
        else
        {
            byteCnt += 1;
            byteCnt += (CODEC_VP9_MV_CLASSES - 1);
            byteCnt += (CODECHAL_VP9_CLASS0_SIZE - 1);
            byteCnt += (CODECHAL_VP9_MV_OFFSET_BITS);
        }
    }
    for (i = 0; i < 2; i++)
    {
        if (!setToKey)
        {
            for (j = 0; j < CODECHAL_VP9_CLASS0_SIZE; j++)
            {
                for (int32_t k = 0; k < (CODEC_VP9_MV_FP_SIZE - 1); k++)
                {
                    ctxBuffer[byteCnt++] = DefaultNmvContext.comps[i].class0_fp[j][k];
                }
            }
            for (j = 0; j < (CODEC_VP9_MV_FP_SIZE - 1); j++)
            {
                ctxBuffer[byteCnt++] = DefaultNmvContext.comps[i].fp[j];
            }
        }
        else
        {
            byteCnt += (CODECHAL_VP9_CLASS0_SIZE * (CODEC_VP9_MV_FP_SIZE - 1));
            byteCnt += (CODEC_VP9_MV_FP_SIZE - 1);
        }
    }
    for (i = 0; i < 2; i++)
    {
        if (!setToKey)
        {
            ctxBuffer[byteCnt++] = DefaultNmvContext.comps[i].class0_hp;
            ctxBuffer[byteCnt++] = DefaultNmvContext.comps[i].hp;
        }
        else
        {
            byteCnt += 2;
        }
    }

    //47 bytes of zeros
    byteCnt += 47;

    //uv mode probs
    for (i = 0; i < CODEC_VP9_INTRA_MODES; i++)
    {
        for (j = 0; j < CODEC_VP9_INTRA_MODES - 1; j++)
        {
            if (setToKey)
            {
                ctxBuffer[byteCnt++] = DefaultKFUVModeProb[i][j];
            }
            else
            {
                ctxBuffer[byteCnt++] = DefaultIFUVProbs[i][j];
            }
        }
    }

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalDecodeVp9::ContextBufferInit(
    uint8_t             *ctxBuffer,
    bool                 setToKey)
{

    MOS_ZeroMemory(ctxBuffer, CODEC_VP9_SEG_PROB_OFFSET);

    int32_t i, j;
    uint32_t byteCnt = 0;
    //TX probs
    for (i = 0; i < CODEC_VP9_TX_SIZE_CONTEXTS; i++)
    {
        for (j = 0; j < CODEC_VP9_TX_SIZES - 3; j++)
        {
            ctxBuffer[byteCnt++] = DefaultTxProbs.p8x8[i][j];
        }
    }
    for (i = 0; i < CODEC_VP9_TX_SIZE_CONTEXTS; i++)
    {
        for (j = 0; j < CODEC_VP9_TX_SIZES - 2; j++)
        {
            ctxBuffer[byteCnt++] = DefaultTxProbs.p16x16[i][j];
        }
    }
    for (i = 0; i < CODEC_VP9_TX_SIZE_CONTEXTS; i++)
    {
        for (j = 0; j < CODEC_VP9_TX_SIZES - 1; j++)
        {
            ctxBuffer[byteCnt++] = DefaultTxProbs.p32x32[i][j];
        }
    }

    //52 bytes of zeros
    byteCnt += 52;

    uint8_t blocktype = 0;
    uint8_t reftype = 0;
    uint8_t coeffbands = 0;
    uint8_t unConstrainedNodes = 0;
    uint8_t prevCoefCtx = 0;
    //coeff probs
    for (blocktype = 0; blocktype < CODEC_VP9_BLOCK_TYPES; blocktype++)
    {
        for (reftype = 0; reftype < CODEC_VP9_REF_TYPES; reftype++)
        {
            for (coeffbands = 0; coeffbands < CODEC_VP9_COEF_BANDS; coeffbands++)
            {
                uint8_t numPrevCoeffCtxts = (coeffbands == 0) ? 3 : CODEC_VP9_PREV_COEF_CONTEXTS;
                for (prevCoefCtx = 0; prevCoefCtx < numPrevCoeffCtxts; prevCoefCtx++)
                {
                    for (unConstrainedNodes = 0; unConstrainedNodes < CODEC_VP9_UNCONSTRAINED_NODES; unConstrainedNodes++)
                    {
                        ctxBuffer[byteCnt++] = DefaultCoefProbs4x4[blocktype][reftype][coeffbands][prevCoefCtx][unConstrainedNodes];
                    }
                }
            }
        }
    }

    for (blocktype = 0; blocktype < CODEC_VP9_BLOCK_TYPES; blocktype++)
    {
        for (reftype = 0; reftype < CODEC_VP9_REF_TYPES; reftype++)
        {
            for (coeffbands = 0; coeffbands < CODEC_VP9_COEF_BANDS; coeffbands++)
            {
                uint8_t numPrevCoeffCtxts = (coeffbands == 0) ? 3 : CODEC_VP9_PREV_COEF_CONTEXTS;
                for (prevCoefCtx = 0; prevCoefCtx < numPrevCoeffCtxts; prevCoefCtx++)
                {
                    for (unConstrainedNodes = 0; unConstrainedNodes < CODEC_VP9_UNCONSTRAINED_NODES; unConstrainedNodes++)
                    {
                        ctxBuffer[byteCnt++] = DefaultCoefPprobs8x8[blocktype][reftype][coeffbands][prevCoefCtx][unConstrainedNodes];
                    }
                }
            }
        }
    }

    for (blocktype = 0; blocktype < CODEC_VP9_BLOCK_TYPES; blocktype++)
    {
        for (reftype = 0; reftype < CODEC_VP9_REF_TYPES; reftype++)
        {
            for (coeffbands = 0; coeffbands < CODEC_VP9_COEF_BANDS; coeffbands++)
            {
                uint8_t numPrevCoeffCtxts = (coeffbands == 0) ? 3 : CODEC_VP9_PREV_COEF_CONTEXTS;
                for (prevCoefCtx = 0; prevCoefCtx < numPrevCoeffCtxts; prevCoefCtx++)
                {
                    for (unConstrainedNodes = 0; unConstrainedNodes < CODEC_VP9_UNCONSTRAINED_NODES; unConstrainedNodes++)
                    {
                        ctxBuffer[byteCnt++] = DefaultCoefProbs16x16[blocktype][reftype][coeffbands][prevCoefCtx][unConstrainedNodes];
                    }
                }
            }
        }
    }

    for (blocktype = 0; blocktype < CODEC_VP9_BLOCK_TYPES; blocktype++)
    {
        for (reftype = 0; reftype < CODEC_VP9_REF_TYPES; reftype++)
        {
            for (coeffbands = 0; coeffbands < CODEC_VP9_COEF_BANDS; coeffbands++)
            {
                uint8_t numPrevCoeffCtxts = (coeffbands == 0) ? 3 : CODEC_VP9_PREV_COEF_CONTEXTS;
                for (prevCoefCtx = 0; prevCoefCtx < numPrevCoeffCtxts; prevCoefCtx++)
                {
                    for (unConstrainedNodes = 0; unConstrainedNodes < CODEC_VP9_UNCONSTRAINED_NODES; unConstrainedNodes++)
                    {
                        ctxBuffer[byteCnt++] = DefaultCoefProbs32x32[blocktype][reftype][coeffbands][prevCoefCtx][unConstrainedNodes];
                    }
                }
            }
        }
    }

    //16 bytes of zeros
    byteCnt += 16;

    // mb skip probs
    for (i = 0; i < CODEC_VP9_MBSKIP_CONTEXTS; i++)
    {
        ctxBuffer[byteCnt++] = DefaultMbskipProbs[i];
    }

    // populate prob values which are different between Key and Non-Key frame
    CtxBufDiffInit(ctxBuffer, setToKey);

    //skip Seg tree/pred probs, updating not done in this function.
    byteCnt = CODEC_VP9_SEG_PROB_OFFSET;
    byteCnt += 7;
    byteCnt += 3;

    //28 bytes of zeros
    for (i = 0; i < 28; i++)
    {
        ctxBuffer[byteCnt++] = 0;
    }

    //Just a check.
    if (byteCnt > CODEC_VP9_PROB_MAX_NUM_ELEM)
    {
        CODECHAL_PUBLIC_ASSERTMESSAGE("Error: FrameContext array out-of-bounds, byteCnt = %d!\n", byteCnt);
        return MOS_STATUS_NO_SPACE;
    }
    else
    {
        return MOS_STATUS_SUCCESS;
    }
}
