/*
* Copyright (c) 2017-2018, 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_encoder_base.cpp
//! \brief    Implements the encode interface for CodecHal.
//! \details  The encode interface is further sub-divided by standard, this file is for the base interface which is shared by all encode standards.
//!

#include "codechal_encoder_base.h"
#include "codechal_encode_tracked_buffer_hevc.h"
#include "mos_solo_generic.h"

void CodechalEncoderState::PrepareNodes(
    MOS_GPU_NODE& videoGpuNode,
    bool&         setVideoNode)
{
    if (m_vdboxOneDefaultUsed)
    {
        setVideoNode = true;
        videoGpuNode = MOS_GPU_NODE_VIDEO;
    }
    else if (m_needCheckCpEnabled)
    {
        if (m_osInterface->osCpInterface->IsCpEnabled() ||
            m_vdencEnabled)
        {
            setVideoNode = true;
            videoGpuNode = MOS_GPU_NODE_VIDEO;
        }
    }
}

MOS_STATUS CodechalEncoderState::SetGpuCtxCreatOption()
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    m_gpuCtxCreatOpt = MOS_New(MOS_GPUCTX_CREATOPTIONS);
    CODECHAL_ENCODE_CHK_NULL_RETURN(m_gpuCtxCreatOpt);

    return eStatus;
}

MOS_STATUS CodechalEncoderState::CreateGpuContexts()
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    if (CodecHalUsesVideoEngine(m_codecFunction))
    {
        MOS_GPU_NODE videoGpuNode = MOS_GPU_NODE_VIDEO;
        bool setVideoNode = false;

        // Create Video Context
        if (MEDIA_IS_SKU(m_skuTable, FtrVcs2))
        {
            setVideoNode = false;

            PrepareNodes(videoGpuNode, setVideoNode);

            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_osInterface->pfnCreateVideoNodeAssociation(
                m_osInterface,
                setVideoNode,
                &videoGpuNode));
            m_videoNodeAssociationCreated = true;
        }
        m_videoGpuNode = videoGpuNode;

        CODECHAL_ENCODE_CHK_STATUS_RETURN(SetGpuCtxCreatOption());
        CODECHAL_ENCODE_CHK_NULL_RETURN(m_gpuCtxCreatOpt);

        MOS_GPU_CONTEXT gpuContext = ((videoGpuNode == MOS_GPU_NODE_VIDEO2) ? MOS_GPU_CONTEXT_VDBOX2_VIDEO3 : MOS_GPU_CONTEXT_VIDEO3);
        eStatus = (MOS_STATUS)m_osInterface->pfnCreateGpuContext(
            m_osInterface,
            gpuContext,
            videoGpuNode,
            m_gpuCtxCreatOpt);

        if (eStatus != MOS_STATUS_SUCCESS)
        {
            // Failed to create new context. Try to reuse the existing one on the same VDBox.
            if (videoGpuNode == MOS_GPU_NODE_VIDEO2)
            {
                // check other GPU contexts on VDBox2
                gpuContext = MOS_GPU_CONTEXT_VDBOX2_VIDEO;
                if (m_osInterface->pfnIsGpuContextValid(m_osInterface, gpuContext) != MOS_STATUS_SUCCESS)
                {
                    gpuContext = MOS_GPU_CONTEXT_VDBOX2_VIDEO2;
                    eStatus = (MOS_STATUS)m_osInterface->pfnIsGpuContextValid(m_osInterface, gpuContext);
                }
            }
            else // videoGpuNode == MOS_GPU_NODE_VIDEO
            {
                // check other GPU contexts on VDBox1
                gpuContext = MOS_GPU_CONTEXT_VIDEO;
                if (m_osInterface->pfnIsGpuContextValid(m_osInterface, gpuContext) != MOS_STATUS_SUCCESS)
                {
                    gpuContext = MOS_GPU_CONTEXT_VIDEO2;
                    eStatus = (MOS_STATUS)m_osInterface->pfnIsGpuContextValid(m_osInterface, gpuContext);
                }
            }

            if (eStatus != MOS_STATUS_SUCCESS)
            {
                // No valid GPU context on current VDBox, so destroy the video node association.
                if (MEDIA_IS_SKU(m_skuTable, FtrVcs2))
                {
                    m_osInterface->pfnDestroyVideoNodeAssociation(m_osInterface, videoGpuNode);
                    m_videoNodeAssociationCreated = false;
                }

                if (videoGpuNode == MOS_GPU_NODE_VIDEO2)
                {
                    // If no valid GPU context on VDBox2, check GPU contexts on VDBox1
                    gpuContext = MOS_GPU_CONTEXT_VIDEO3;
                    if (m_osInterface->pfnIsGpuContextValid(m_osInterface, gpuContext) != MOS_STATUS_SUCCESS)
                    {
                        gpuContext = MOS_GPU_CONTEXT_VIDEO;
                        if (m_osInterface->pfnIsGpuContextValid(m_osInterface, gpuContext) != MOS_STATUS_SUCCESS)
                        {
                            // If this context is also invalid, return an error as no context for the video engine
                            // is available, so PAK cannot occur
                            gpuContext = MOS_GPU_CONTEXT_VIDEO2;
                            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_osInterface->pfnIsGpuContextValid(m_osInterface, gpuContext));
                        }
                    }

                    // When using existing VDBOX1, UMD needs to notify KMD to increase the VDBOX1 counter
                    setVideoNode = true;
                    videoGpuNode = MOS_GPU_NODE_VIDEO;
                    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_osInterface->pfnCreateVideoNodeAssociation(
                        m_osInterface,
                        setVideoNode,
                        &videoGpuNode));
                    m_videoNodeAssociationCreated = true;
                }
                else // videoGpuNode == MOS_GPU_NODE_VIDEO
                {
                    // We won't check GPU contexts on VDBox2 if there is no valid GPU context on VDBox1
                    // since VDBox2 is not full featured.
                    CODECHAL_ENCODE_CHK_STATUS_RETURN(eStatus);
                }
            }

            // save the updated VDBox ordinal
            m_videoGpuNode = videoGpuNode;
        }

        if (m_videoNodeAssociationCreated)
        {
            CODECHAL_UPDATE_VDBOX_USER_FEATURE(videoGpuNode);
        }

        m_videoContext = gpuContext;

        m_osInterface->pfnSetEncodePakContext(m_osInterface, m_videoContext);
    }

    if (CodecHalUsesRenderEngine(m_codecFunction, m_standard))
    {
        MOS_GPU_CONTEXT gpuContext = MOS_GPU_CONTEXT_RENDER2;
        MOS_GPU_NODE renderGpuNode = MOS_GPU_NODE_3D;

        if (!MEDIA_IS_SKU(m_skuTable, FtrCCSNode))
        {
            m_computeContextEnabled = false;
        }

        if (m_computeContextEnabled)
        {
            gpuContext = MOS_GPU_CONTEXT_COMPUTE;
            renderGpuNode = MOS_GPU_NODE_COMPUTE;
        }
        else
        {
            gpuContext = MOS_GPU_CONTEXT_RENDER2;
            renderGpuNode = MOS_GPU_NODE_3D;
        }
        MOS_GPUCTX_CREATOPTIONS createOption;

        if (m_hwInterface->m_slicePowerGate)
        {
            createOption.packed.SubSliceCount = (m_gtSystemInfo->SubSliceCount / m_gtSystemInfo->SliceCount) >> 1;
            createOption.packed.SliceCount = (uint8_t)m_gtSystemInfo->SliceCount;
            createOption.packed.MaxEUcountPerSubSlice = (uint8_t)(m_gtSystemInfo->EUCount / m_gtSystemInfo->SubSliceCount);
            createOption.packed.MinEUcountPerSubSlice = (uint8_t)(m_gtSystemInfo->EUCount / m_gtSystemInfo->SubSliceCount);
        }

        eStatus = (MOS_STATUS)m_osInterface->pfnCreateGpuContext(m_osInterface, gpuContext, renderGpuNode, &createOption);

        if (eStatus != MOS_STATUS_SUCCESS)
        {
            // If this context is also invalid, return an error as no context for the 3D engine
            // is available, so ENC cannot occur
            gpuContext = MOS_GPU_CONTEXT_RENDER;
            CODECHAL_ENCODE_ASSERTMESSAGE("create gpu context failure for Render Engine!");
            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_osInterface->pfnIsGpuContextValid(m_osInterface, gpuContext));
        }

        m_renderContext = gpuContext;
        m_osInterface->pfnSetEncodeEncContext(m_osInterface, m_renderContext);
    }

    // Set Vdbox index in use
    m_vdboxIndex = (m_videoGpuNode == MOS_GPU_NODE_VIDEO2)? MHW_VDBOX_NODE_2 : MHW_VDBOX_NODE_1;

    return eStatus;
}

MOS_STATUS CodechalEncoderState::DestroyMeResources(
    HmeParams* param)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    CODECHAL_ENCODE_CHK_NULL_RETURN(param);

    if (param->ps16xMeMvDataBuffer != nullptr)
    {
        m_osInterface->pfnFreeResource(
            m_osInterface,
            &param->ps16xMeMvDataBuffer->OsResource);
    }

    if (param->ps32xMeMvDataBuffer != nullptr)
    {
        m_osInterface->pfnFreeResource(
            m_osInterface,
            &param->ps32xMeMvDataBuffer->OsResource);
    }

    if (param->ps4xMeDistortionBuffer != nullptr)
    {
        m_osInterface->pfnFreeResource(
            m_osInterface,
            &param->ps4xMeDistortionBuffer->OsResource);
    }

    if (param->ps4xMeMvDataBuffer != nullptr)
    {
        m_osInterface->pfnFreeResource(
            m_osInterface,
            &param->ps4xMeMvDataBuffer->OsResource);
    }

    if (param->presMvAndDistortionSumSurface != nullptr)
    {
        m_osInterface->pfnFreeResource(
            m_osInterface,
            param->presMvAndDistortionSumSurface);
    }

    return eStatus;
}

MOS_STATUS CodechalEncoderState::CleanUpResource(
    PMOS_RESOURCE            resource,
    PMOS_ALLOC_GFXRES_PARAMS allocParams)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    CODECHAL_ENCODE_CHK_NULL_RETURN(resource);
    CODECHAL_ENCODE_CHK_NULL_RETURN(allocParams);

    MOS_LOCK_PARAMS lockFlag;
    MOS_ZeroMemory(&lockFlag, sizeof(lockFlag));
    lockFlag.WriteOnly = true;
    uint8_t* data = (uint8_t*)m_osInterface->pfnLockResource(m_osInterface, resource, &lockFlag);
    if(data == nullptr)
    {
        return MOS_STATUS_NULL_POINTER;
    }

    if(allocParams->Format == Format_Buffer)
    {
        MOS_ZeroMemory(data, allocParams->dwBytes);
    }
    else if(allocParams->Format == Format_Buffer_2D)
    {
        MOS_ZeroMemory(data, allocParams->dwHeight * allocParams->dwWidth);
    }
    else
    {
        eStatus = MOS_STATUS_INVALID_PARAMETER;
    }

    m_osInterface->pfnUnlockResource(m_osInterface, resource);

    return eStatus;
}

MOS_STATUS CodechalEncoderState::AllocateResources4xMe(
    HmeParams* param)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    CODECHAL_ENCODE_CHK_NULL_RETURN(param);

    if(!m_encEnabled || !m_hmeSupported)
    {
        return eStatus;
    }

    MOS_ALLOC_GFXRES_PARAMS allocParamsForBuffer2D;
    MOS_ZeroMemory(&allocParamsForBuffer2D, sizeof(MOS_ALLOC_GFXRES_PARAMS));
    allocParamsForBuffer2D.Type     = MOS_GFXRES_2D;
    allocParamsForBuffer2D.TileType = MOS_TILE_LINEAR;
    allocParamsForBuffer2D.Format   = Format_Buffer_2D;

    MOS_ZeroMemory(param->ps4xMeMvDataBuffer, sizeof(MOS_SURFACE));
    param->ps4xMeMvDataBuffer->TileType        = MOS_TILE_LINEAR;
    param->ps4xMeMvDataBuffer->bArraySpacing   = true;
    param->ps4xMeMvDataBuffer->Format          = Format_Buffer_2D;
    param->ps4xMeMvDataBuffer->dwWidth         = MOS_ALIGN_CEIL((m_downscaledWidthInMb4x * 32), 64); // MediaBlockRW requires pitch multiple of 64 bytes when linear.
    param->ps4xMeMvDataBuffer->dwHeight        = (m_downscaledHeightInMb4x * 2 * 4 * CODECHAL_ENCODE_ME_DATA_SIZE_MULTIPLIER);
    param->ps4xMeMvDataBuffer->dwPitch         = param->ps4xMeMvDataBuffer->dwWidth;

    allocParamsForBuffer2D.dwWidth  = param->ps4xMeMvDataBuffer->dwWidth;
    allocParamsForBuffer2D.dwHeight = param->ps4xMeMvDataBuffer->dwHeight;
    allocParamsForBuffer2D.pBufName = "4xME MV Data Buffer";

    eStatus = (MOS_STATUS)m_osInterface->pfnAllocateResource(
        m_osInterface,
        &allocParamsForBuffer2D,
        &param->ps4xMeMvDataBuffer->OsResource);

    if (eStatus != MOS_STATUS_SUCCESS)
    {
        CODECHAL_ENCODE_ASSERTMESSAGE("Failed to allocate 4xME MV Data Buffer.");
        return eStatus;
    }

    CleanUpResource(&param->ps4xMeMvDataBuffer->OsResource, &allocParamsForBuffer2D);

    if (param->b4xMeDistortionBufferSupported)
    {
        uint32_t adjustedHeight                   =
                        m_downscaledHeightInMb4x * CODECHAL_MACROBLOCK_HEIGHT * SCALE_FACTOR_4x;
        uint32_t downscaledFieldHeightInMb4x     =
                        CODECHAL_GET_HEIGHT_IN_MACROBLOCKS(((adjustedHeight + 1) >> 1)/4);

        MOS_ZeroMemory(param->ps4xMeDistortionBuffer, sizeof(MOS_SURFACE));
        param->ps4xMeDistortionBuffer->TileType        = MOS_TILE_LINEAR;
        param->ps4xMeDistortionBuffer->bArraySpacing   = true;
        param->ps4xMeDistortionBuffer->Format          = Format_Buffer_2D;
        param->ps4xMeDistortionBuffer->dwWidth         = MOS_ALIGN_CEIL((m_downscaledWidthInMb4x * 8), 64);
        param->ps4xMeDistortionBuffer->dwHeight        = 2 * MOS_ALIGN_CEIL((downscaledFieldHeightInMb4x * 4 * 10), 8);
        param->ps4xMeDistortionBuffer->dwPitch         = MOS_ALIGN_CEIL((m_downscaledWidthInMb4x * 8), 64);

        allocParamsForBuffer2D.dwWidth  = param->ps4xMeDistortionBuffer->dwWidth;
        allocParamsForBuffer2D.dwHeight = param->ps4xMeDistortionBuffer->dwHeight;
        allocParamsForBuffer2D.pBufName = "4xME Distortion Buffer";

        eStatus = (MOS_STATUS)m_osInterface->pfnAllocateResource(
            m_osInterface,
            &allocParamsForBuffer2D,
            &param->ps4xMeDistortionBuffer->OsResource);

        if (eStatus != MOS_STATUS_SUCCESS)
        {
            CODECHAL_ENCODE_ASSERTMESSAGE("Failed to allocate 4xME Distortion Buffer.");
            return eStatus;
        }
        CleanUpResource(&param->ps4xMeDistortionBuffer->OsResource, &allocParamsForBuffer2D);
    }

    return eStatus;
}

MOS_STATUS CodechalEncoderState::AllocateResources16xMe(
    HmeParams* param)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    CODECHAL_ENCODE_CHK_NULL_RETURN(param);

    if (!m_encEnabled || !m_hmeSupported)
    {
        return eStatus;
    }

    MOS_ALLOC_GFXRES_PARAMS    allocParamsForBuffer2D;
    MOS_ZeroMemory(&allocParamsForBuffer2D, sizeof(MOS_ALLOC_GFXRES_PARAMS));
    allocParamsForBuffer2D.Type     = MOS_GFXRES_2D;
    allocParamsForBuffer2D.TileType = MOS_TILE_LINEAR;
    allocParamsForBuffer2D.Format   = Format_Buffer_2D;

    if (m_16xMeSupported)
    {
        MOS_ZeroMemory(param->ps16xMeMvDataBuffer, sizeof(MOS_SURFACE));
        param->ps16xMeMvDataBuffer->TileType      = MOS_TILE_LINEAR;
        param->ps16xMeMvDataBuffer->bArraySpacing = true;
        param->ps16xMeMvDataBuffer->Format        = Format_Buffer_2D;
        param->ps16xMeMvDataBuffer->dwWidth       = MOS_ALIGN_CEIL((m_downscaledWidthInMb16x * 32), 64); // MediaBlockRW requires pitch multiple of 64 bytes when linear
        param->ps16xMeMvDataBuffer->dwHeight      = (m_downscaledHeightInMb16x * 2 * 4 * CODECHAL_ENCODE_ME_DATA_SIZE_MULTIPLIER);
        param->ps16xMeMvDataBuffer->dwPitch       = param->ps16xMeMvDataBuffer->dwWidth;

        allocParamsForBuffer2D.dwWidth  = param->ps16xMeMvDataBuffer->dwWidth;
        allocParamsForBuffer2D.dwHeight = param->ps16xMeMvDataBuffer->dwHeight;
        allocParamsForBuffer2D.pBufName = "16xME MV Data Buffer";

        eStatus = (MOS_STATUS)m_osInterface->pfnAllocateResource(
            m_osInterface,
            &allocParamsForBuffer2D,
            &param->ps16xMeMvDataBuffer->OsResource);

        if (eStatus != MOS_STATUS_SUCCESS)
        {
            CODECHAL_ENCODE_ASSERTMESSAGE("Failed to allocate 16xME MV Data Buffer.");
            return eStatus;
        }
        CleanUpResource(&param->ps16xMeMvDataBuffer->OsResource, &allocParamsForBuffer2D);
    }

    return eStatus;
}

MOS_STATUS CodechalEncoderState::AllocateResources32xMe(
    HmeParams* param)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    CODECHAL_ENCODE_CHK_NULL_RETURN(param);
    if (!m_encEnabled || !m_hmeSupported)
    {
        return eStatus;
    }

    MOS_ALLOC_GFXRES_PARAMS allocParamsForBuffer2D;
    MOS_ZeroMemory(&allocParamsForBuffer2D, sizeof(MOS_ALLOC_GFXRES_PARAMS));
    allocParamsForBuffer2D.Type     = MOS_GFXRES_2D;
    allocParamsForBuffer2D.TileType = MOS_TILE_LINEAR;
    allocParamsForBuffer2D.Format   = Format_Buffer_2D;

    if (m_32xMeSupported)
    {
        MOS_ZeroMemory(param->ps32xMeMvDataBuffer, sizeof(MOS_SURFACE));
        param->ps32xMeMvDataBuffer->TileType      = MOS_TILE_LINEAR;
        param->ps32xMeMvDataBuffer->bArraySpacing = true;
        param->ps32xMeMvDataBuffer->Format        = Format_Buffer_2D;
        param->ps32xMeMvDataBuffer->dwWidth       = MOS_ALIGN_CEIL((m_downscaledWidthInMb32x * 32), 64); // MediaBlockRW requires pitch multiple of 64 bytes when linear
        param->ps32xMeMvDataBuffer->dwHeight      = (m_downscaledHeightInMb32x * 2 * 4 * CODECHAL_ENCODE_ME_DATA_SIZE_MULTIPLIER);
        param->ps32xMeMvDataBuffer->dwPitch       = param->ps32xMeMvDataBuffer->dwWidth;

        allocParamsForBuffer2D.dwWidth  = param->ps32xMeMvDataBuffer->dwWidth;
        allocParamsForBuffer2D.dwHeight = param->ps32xMeMvDataBuffer->dwHeight;
        allocParamsForBuffer2D.pBufName = "32xME MV Data Buffer";

        eStatus = (MOS_STATUS)m_osInterface->pfnAllocateResource(
            m_osInterface,
            &allocParamsForBuffer2D,
            &param->ps32xMeMvDataBuffer->OsResource);

        if (eStatus != MOS_STATUS_SUCCESS)
        {
            CODECHAL_ENCODE_ASSERTMESSAGE("%s: Failed to allocate 32xME MV Data Buffer\n", __FUNCTION__);
            return eStatus;
        }
        CleanUpResource(&param->ps32xMeMvDataBuffer->OsResource, &allocParamsForBuffer2D);
    }

    return eStatus;
}

// Encode Public Interface Functions
MOS_STATUS CodechalEncoderState::Allocate(CodechalSetting * codecHalSettings)
{
    CODECHAL_ENCODE_FUNCTION_ENTER;

    if (m_cscDsState)
    {
        // call before m_hwInterface->Initialize() to reserve ISH space for CscDs kernel
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_cscDsState->Initialize());
    }

    CODECHAL_ENCODE_CHK_STATUS_RETURN(Codechal::Allocate(codecHalSettings));

    CODECHAL_ENCODE_CHK_STATUS_RETURN(Initialize(codecHalSettings));

    // Create MMC state
    if (m_mmcState == nullptr)
    {
        CODECHAL_ENCODE_CHK_NULL_RETURN(m_mmcState = MOS_New(CodecHalMmcState, m_hwInterface));
    }

    // create resource allocator
    CODECHAL_ENCODE_CHK_NULL_RETURN(m_allocator = MOS_New(CodechalEncodeAllocator, this));

    // create tracked buffer state
    if (m_standard == CODECHAL_HEVC)
    {
        CODECHAL_ENCODE_CHK_NULL_RETURN(m_trackedBuf = MOS_New(CodechalEncodeTrackedBufferHevc, this));
    }
    else
    {
        CODECHAL_ENCODE_CHK_NULL_RETURN(m_trackedBuf = MOS_New(CodechalEncodeTrackedBuffer, this));
    }

    MotionEstimationDisableCheck();

    CODECHAL_ENCODE_CHK_STATUS_RETURN(AllocateResources());

    CODECHAL_ENCODE_CHK_STATUS_RETURN(CreateGpuContexts());

    if (CodecHalUsesRenderEngine(codecHalSettings->codecFunction, codecHalSettings->standard))
    {
        m_renderContextUsesNullHw = m_useNullHw[m_renderContext];
    }

    if (CodecHalUsesVideoEngine(codecHalSettings->codecFunction))
    {
        m_videoContextUsesNullHw = m_useNullHw[m_videoContext];
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_osInterface->pfnRegisterBBCompleteNotifyEvent(
            m_osInterface,
            m_videoContext));
    }
    else
    {
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_osInterface->pfnRegisterBBCompleteNotifyEvent(
            m_osInterface,
            m_renderContext));
    }

    if (!m_perfProfiler)
    {
        m_perfProfiler = MediaPerfProfiler::Instance();
        CODECHAL_ENCODE_CHK_NULL_RETURN(m_perfProfiler);

        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_perfProfiler->Initialize((void*)this, m_osInterface));
    }
    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalEncoderState::Execute(void *params)
{
    CODECHAL_ENCODE_FUNCTION_ENTER;

    CODECHAL_ENCODE_CHK_STATUS_RETURN(Codechal::Execute(params));

    EncoderParams *encodeParams = (EncoderParams *)params;
    // MSDK event handling
    CODECHAL_ENCODE_CHK_STATUS_RETURN(Mos_Solo_SetGpuAppTaskEvent(m_osInterface,encodeParams->gpuAppTaskEvent));

    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->SetWatchdogTimerThreshold(m_frameWidth, m_frameHeight));

    if (m_codecFunction == CODECHAL_FUNCTION_FEI_PRE_ENC)
    {
        CODECHAL_ENCODE_CHK_STATUS_RETURN(ExecutePreEnc(encodeParams));
    }
    else
    {
        CODECHAL_ENCODE_CHK_STATUS_RETURN(ExecuteEnc(encodeParams));
    }

    return MOS_STATUS_SUCCESS;
}

// Encoder Public Interface Functions
MOS_STATUS CodechalEncoderState::Initialize(
    CodechalSetting * settings)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
    MOS_STATUS statusKey = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    CODECHAL_ENCODE_CHK_NULL_RETURN(settings);

    m_storeData      = 1;
    m_firstFrame     = true;
    m_firstTwoFrames = true;
    m_standard       = settings->standard;
    m_mode           = settings->mode;
    m_codecFunction  = settings->codecFunction;

    if (CodecHalUsesVideoEngine(m_codecFunction))
    {
        m_pakEnabled = true;
    }

    if (CodecHalUsesRenderEngine(m_codecFunction, m_standard))
    {
        m_encEnabled = true;
    }

    MOS_USER_FEATURE_VALUE_DATA userFeatureData;
    if (m_encEnabled)
    {
        m_brcPakStatisticsSize = CODECHAL_ENCODE_BRC_PAK_STATISTICS_SIZE;

        m_hwScoreboardType = 1;

        m_encodeVfeMaxThreads = 0;
#if (_DEBUG || _RELEASE_INTERNAL)
        MOS_ZeroMemory(&userFeatureData, sizeof(userFeatureData));
        MOS_UserFeature_ReadValue_ID(
            nullptr,
            __MEDIA_USER_FEATURE_VALUE_ENCODE_VFE_MAX_THREADS_ID,
            &userFeatureData);
        m_encodeVfeMaxThreads = (uint32_t)userFeatureData.u32Data;
#endif // _DEBUG || _RELEASE_INTERNAL

        m_encodeVfeMaxThreadsScaling = 0;
#if (_DEBUG || _RELEASE_INTERNAL)
        MOS_ZeroMemory(&userFeatureData, sizeof(userFeatureData));
        MOS_UserFeature_ReadValue_ID(
            nullptr,
            __MEDIA_USER_FEATURE_VALUE_ENCODE_VFE_MAX_THREADS_SCALING_ID,
            &userFeatureData);
        m_encodeVfeMaxThreadsScaling = (uint32_t)userFeatureData.i32Data;
#endif // _DEBUG || _RELEASE_INTERNAL

        {
            MOS_ZeroMemory(&userFeatureData, sizeof(userFeatureData));
            MOS_UserFeature_ReadValue_ID(
                nullptr,
                __MEDIA_USER_FEATURE_VALUE_ENCODE_HW_WALKER_ID,
                &userFeatureData);

            m_hwWalker = (userFeatureData.i32Data) ? true : false;

            if (m_hwWalker)
            {
                m_walkerMode = (MHW_WALKER_MODE)0;
#if (_DEBUG || _RELEASE_INTERNAL)
                MOS_ZeroMemory(&userFeatureData, sizeof(userFeatureData));
                MOS_UserFeature_ReadValue_ID(
                    nullptr,
                    __MEDIA_USER_FEATURE_VALUE_ENCODE_HW_WALKER_MODE_ID,
                    &userFeatureData);
                m_walkerMode = (MHW_WALKER_MODE)userFeatureData.u32Data;
#endif // _DEBUG || _RELEASE_INTERNAL

                if (MEDIA_IS_SKU(m_skuTable, FtrSliceShutdownOverride))
                {
                    //Default Slice State
                    m_sliceShutdownDefaultState = (uint32_t)0;
#if (_DEBUG || _RELEASE_INTERNAL)
                    MOS_ZeroMemory(&userFeatureData, sizeof(userFeatureData));
                    MOS_UserFeature_ReadValue_ID(
                        nullptr,
                        __MEDIA_USER_FEATURE_VALUE_SLICE_SHUTDOWN_DEFAULT_STATE_ID,
                        &userFeatureData);
                    m_sliceShutdownDefaultState = (uint32_t)userFeatureData.u32Data;
#endif // _DEBUG || _RELEASE_INTERNAL

                    //Requested Slice State
                    m_sliceShutdownRequestState = (uint32_t)0;
#if (_DEBUG || _RELEASE_INTERNAL)
                    MOS_ZeroMemory(&userFeatureData, sizeof(userFeatureData));
                    MOS_UserFeature_ReadValue_ID(
                        nullptr,
                        __MEDIA_USER_FEATURE_VALUE_SLICE_SHUTDOWN_REQUEST_STATE_ID,
                        &userFeatureData);
                    m_sliceShutdownRequestState = (uint32_t)userFeatureData.u32Data;
#endif // _DEBUG || _RELEASE_INTERNAL

                    //Slice Shutdown Resolution Threshold
                    m_ssdResolutionThreshold = (uint32_t)0;
#if (_DEBUG || _RELEASE_INTERNAL)
                    MOS_ZeroMemory(&userFeatureData, sizeof(userFeatureData));
                    MOS_UserFeature_ReadValue_ID(
                        nullptr,
                        __MEDIA_USER_FEATURE_VALUE_SLICE_SHUTDOWN_RESOLUTION_THRESHOLD_ID,
                        &userFeatureData);
                    m_ssdResolutionThreshold = (uint32_t)userFeatureData.i32Data;
#endif // _DEBUG || _RELEASE_INTERNAL

                    //Slice Shutdown Target Usage Threshold
                    m_ssdTargetUsageThreshold = (uint32_t)0;
#if (_DEBUG || _RELEASE_INTERNAL)
                    MOS_ZeroMemory(&userFeatureData, sizeof(userFeatureData));
                    MOS_UserFeature_ReadValue_ID(
                        nullptr,
                        __MEDIA_USER_FEATURE_VALUE_SLICE_SHUTDOWN_TARGET_USAGE_THRESHOLD_ID,
                        &userFeatureData);
                    m_ssdTargetUsageThreshold = (uint32_t)userFeatureData.i32Data;
#endif // _DEBUG || _RELEASE_INTERNAL

#if (_DEBUG || _RELEASE_INTERNAL)
                    MOS_ZeroMemory(&userFeatureData, sizeof(userFeatureData));
                    MOS_UserFeature_ReadValue_ID(
                        nullptr,
                        __MEDIA_USER_FEATURE_VALUE_ENCODE_BRC_SOFTWARE_ID,
                        &userFeatureData);

                    if (userFeatureData.i32Data)
                    {
                        char path_buffer[256];
                        MOS_ZeroMemory(&userFeatureData, sizeof(userFeatureData));
                        MOS_ZeroMemory(path_buffer, 256);
                        userFeatureData.StringData.pStringData = path_buffer;

                        statusKey = MOS_UserFeature_ReadValue_ID(
                            nullptr,
                            __MEDIA_USER_FEATURE_VALUE_ENCODE_BRC_SOFTWARE_PATH_ID,
                            &userFeatureData);

                        if (statusKey == MOS_STATUS_SUCCESS && userFeatureData.StringData.uSize > 0)
                        {
                            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_osInterface->pfnLoadLibrary(m_osInterface, path_buffer, &m_swBrcMode));
                        }
                    }
                    // SW BRC DLL Reporting
                    CodecHalEncode_WriteKey(__MEDIA_USER_FEATURE_VALUE_ENCODE_BRC_SOFTWARE_IN_USE_ID, (m_swBrcMode == nullptr) ? false : true);
#endif // _DEBUG || _RELEASE_INTERNAL

                    if (!m_sliceShutdownDefaultState &&
                        !m_sliceShutdownRequestState &&
                        !m_ssdTargetUsageThreshold   &&
                        !m_ssdResolutionThreshold)
                    {
                        // slice shutdown used for power efficiency
                        // use it in case of ult and if hw has more than 2 slices
                        if (MEDIA_IS_SKU(m_skuTable, FtrULT))
                        {
                            if ((GFX_IS_GEN_10_OR_LATER(m_platform) && m_gtSystemInfo->SliceCount >= 2) ||
                                MEDIA_IS_SKU(m_skuTable, FtrGT3))
                            {
                                m_sliceShutdownDefaultState   = CODECHAL_SLICE_SHUTDOWN_ONE_SLICE;
                                m_sliceShutdownRequestState   = CODECHAL_SLICE_SHUTDOWN_TWO_SLICES;
                                m_ssdResolutionThreshold      = m_hwInterface->m_ssdResolutionThreshold;
                                m_ssdTargetUsageThreshold     = m_hwInterface->m_ssdTargetUsageThreshold;
                            }
                        }
                        else if (MEDIA_IS_SKU(m_skuTable, FtrGT4))
                        {
                            m_sliceShutdownDefaultState   = CODECHAL_SLICE_SHUTDOWN_ONE_SLICE;
                            m_sliceShutdownRequestState   = CODECHAL_SLICE_SHUTDOWN_TWO_SLICES;
                            m_ssdResolutionThreshold      = m_hwInterface->m_ssdResolutionThreshold;
                            m_ssdTargetUsageThreshold     = m_hwInterface->m_ssdTargetUsageThreshold;
                        }
                    }
                }
            }
        }

        if (MEDIA_IS_SKU(m_skuTable, FtrSliceShutdown))
        {
            MOS_ZeroMemory(&userFeatureData, sizeof(userFeatureData));
            MOS_UserFeature_ReadValue_ID(
                nullptr,
                __MEDIA_USER_FEATURE_VALUE_SLICE_SHUTDOWN_ENABLE_ID,
                &userFeatureData);
            m_sliceShutdownEnable = (userFeatureData.i32Data) ? true : false;
        }

        m_targetUsageOverride = (uint8_t)0;
#if (_DEBUG || _RELEASE_INTERNAL)
        MOS_ZeroMemory(&userFeatureData, sizeof(userFeatureData));
        MOS_UserFeature_ReadValue_ID(
            nullptr,
            __MEDIA_USER_FEATURE_VALUE_ENCODE_TARGET_USAGE_OVERRIDE_ID,
            &userFeatureData);
        m_targetUsageOverride = (uint8_t)userFeatureData.u32Data;
#endif // _DEBUG || _RELEASE_INTERNAL
    }

    if (m_pakEnabled)
    {
        //RCPanic settings
        MOS_ZeroMemory(&userFeatureData, sizeof(userFeatureData));
        MOS_UserFeature_ReadValue_ID(
            nullptr,
            __MEDIA_USER_FEATURE_VALUE_RC_PANIC_ENABLE_ID,
            &userFeatureData);
        m_panicEnable = (userFeatureData.i32Data) ? true : false;

        MOS_ZeroMemory(&userFeatureData, sizeof(userFeatureData));
        userFeatureData.i32Data = 1;
        userFeatureData.i32DataFlag = MOS_USER_FEATURE_VALUE_DATA_FLAG_CUSTOM_DEFAULT_VALUE_TYPE;
        MOS_UserFeature_ReadValue_ID(
            nullptr,
            __MEDIA_USER_FEATURE_VALUE_ENCODE_SUPPRESS_RECON_PIC_ENABLE_ID,
            &userFeatureData);
        m_suppressReconPicSupported = (userFeatureData.u32Data) ? true : false;
    }

#if (_DEBUG || _RELEASE_INTERNAL)
    MOS_ZeroMemory(&userFeatureData, sizeof(userFeatureData));
    MOS_UserFeature_ReadValue_ID(
        NULL,
        __MEDIA_USER_FEATURE_VALUE_ENCODE_ENABLE_COMPUTE_CONTEXT_ID,
        &userFeatureData);
    m_computeContextEnabled = (userFeatureData.u32Data) ? true : false;
#endif

#if USE_CODECHAL_DEBUG_TOOL
    MOS_ZeroMemory(&userFeatureData, sizeof(userFeatureData));
    MOS_UserFeature_ReadValue_ID(
        nullptr,
        __MEDIA_USER_FEATURE_VALUE_CODECHAL_ENABLE_FAKE_HEADER_SIZE_ID,
        &userFeatureData);
    m_enableFakeHrdSize = (uint32_t)userFeatureData.u32Data;

    MOS_ZeroMemory(&userFeatureData, sizeof(userFeatureData));
    MOS_UserFeature_ReadValue_ID(
        nullptr,
        __MEDIA_USER_FEATURE_VALUE_CODECHAL_FAKE_IFRAME_HEADER_SIZE_ID,
        &userFeatureData);
    m_fakeIFrameHrdSize = (uint32_t)userFeatureData.u32Data;

    MOS_ZeroMemory(&userFeatureData, sizeof(userFeatureData));
    MOS_UserFeature_ReadValue_ID(
        nullptr,
        __MEDIA_USER_FEATURE_VALUE_CODECHAL_FAKE_PBFRAME_HEADER_SIZE_ID,
        &userFeatureData);
    m_fakePBFrameHrdSize = (uint32_t)userFeatureData.u32Data;
#endif

    m_oriFrameWidth   = settings->width;
    m_oriFrameHeight  = settings->height;
    m_picWidthInMb    = (uint16_t)CODECHAL_GET_WIDTH_IN_MACROBLOCKS(m_oriFrameWidth);
    m_picHeightInMb   = (uint16_t)CODECHAL_GET_HEIGHT_IN_MACROBLOCKS(m_oriFrameHeight);
    m_frameWidth      = m_picWidthInMb * CODECHAL_MACROBLOCK_WIDTH;
    m_frameHeight     = m_picHeightInMb * CODECHAL_MACROBLOCK_HEIGHT;

    // HME Scaling WxH
    m_downscaledWidthInMb4x               =
        CODECHAL_GET_WIDTH_IN_MACROBLOCKS(m_frameWidth / SCALE_FACTOR_4x);
    m_downscaledHeightInMb4x              =
        CODECHAL_GET_HEIGHT_IN_MACROBLOCKS(m_frameHeight / SCALE_FACTOR_4x);
    m_downscaledWidth4x                   =
        m_downscaledWidthInMb4x * CODECHAL_MACROBLOCK_WIDTH;
    m_downscaledHeight4x                  =
        m_downscaledHeightInMb4x * CODECHAL_MACROBLOCK_HEIGHT;

    // SuperHME Scaling WxH
    m_downscaledWidthInMb16x              =
        CODECHAL_GET_WIDTH_IN_MACROBLOCKS(m_frameWidth / SCALE_FACTOR_16x);
    m_downscaledHeightInMb16x             =
        CODECHAL_GET_HEIGHT_IN_MACROBLOCKS(m_frameHeight / SCALE_FACTOR_16x);
    m_downscaledWidth16x                   =
        m_downscaledWidthInMb16x * CODECHAL_MACROBLOCK_WIDTH;
    m_downscaledHeight16x                  =
        m_downscaledHeightInMb16x * CODECHAL_MACROBLOCK_HEIGHT;

    // UltraHME Scaling WxH
    m_downscaledWidthInMb32x              =
        CODECHAL_GET_WIDTH_IN_MACROBLOCKS(m_frameWidth / SCALE_FACTOR_32x);
    m_downscaledHeightInMb32x             =
        CODECHAL_GET_HEIGHT_IN_MACROBLOCKS(m_frameHeight / SCALE_FACTOR_32x);
    m_downscaledWidth32x                   =
        m_downscaledWidthInMb32x * CODECHAL_MACROBLOCK_WIDTH;
    m_downscaledHeight32x                  =
        m_downscaledHeightInMb32x * CODECHAL_MACROBLOCK_HEIGHT;

    m_minScaledDimension      = CODECHAL_ENCODE_MIN_SCALED_SURFACE_SIZE;
    m_minScaledDimensionInMb  = (CODECHAL_ENCODE_MIN_SCALED_SURFACE_SIZE + 15) >> 4;

    m_currOriginalPic.PicFlags              = PICTURE_INVALID;
    m_currOriginalPic.FrameIdx = 0;
    m_currOriginalPic.PicEntry = 0;

    m_hwInterface->GetCpInterface()->RegisterParams(settings->GetCpParams());

    // flag to enable kmd for the frame tracking (so encoder driver doesn't need to send a separate command buffer
    // for frame tracking purpose). Currently this feature is disabled for HEVC.
    // For HEVC, this feature will be enabled later.

    MOS_ZeroMemory(&userFeatureData, sizeof(userFeatureData));
    statusKey = MOS_UserFeature_ReadValue_ID(
        nullptr,
        __MEDIA_USER_FEATURE_VALUE_ENCODE_ENABLE_FRAME_TRACKING_ID,
        &userFeatureData);
    if (statusKey == MOS_STATUS_SUCCESS)
    {
        m_frameTrackingEnabled = userFeatureData.i32Data ? true : false;
    }
    else
    {
        m_frameTrackingEnabled = m_osInterface->bEnableKmdMediaFrameTracking ? true: false;
    }

    if (m_standard == CODECHAL_AVC)
    {
        if (CodecHalUsesVideoEngine(m_codecFunction))
        {
            m_inlineEncodeStatusUpdate = m_osInterface->bInlineCodecStatusUpdate ? true: false;
        }
    }

    // Disable SHME and UHME if HME is disabled
    if(!m_hmeSupported)
    {
        m_16xMeSupported = false;
        m_32xMeSupported = false;
    }
    // Disable UHME if SHME is disabled
    else if(!m_16xMeSupported)
    {
        m_32xMeSupported = false;
    }

    // Set Vdbox index in use
    m_vdboxIndex = (m_videoGpuNode == MOS_GPU_NODE_VIDEO2)? MHW_VDBOX_NODE_2 : MHW_VDBOX_NODE_1;

    if (eStatus != MOS_STATUS_SUCCESS)
    {
        Destroy();
    }

    if (!m_feiEnable)
    {
        CODECHAL_ENCODE_CHK_STATUS_RETURN(AllocateMDFResources());
    }

    return eStatus;
}

MOS_STATUS CodechalEncoderState::AllocateMDFResources()
{
    uint32_t devOp;

    if (CodecHalIsFeiEncode(m_codecFunction) && m_codecFunction != CODECHAL_FUNCTION_FEI_PAK)
    {
        devOp = CM_DEVICE_CREATE_OPTION_SCRATCH_SPACE_DISABLE;

        if (m_cmDev == nullptr)
        {
            m_osInterface->pfnNotifyStreamIndexSharing(m_osInterface);
            CODECHAL_ENCODE_CHK_STATUS_RETURN(CreateCmDevice(m_osInterface->pOsContext, m_cmDev, devOp));
        }
        //just WA for issues in MDF null support
        if (!m_cmQueue)
        {
            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_cmDev->CreateQueue(m_cmQueue));
        }
        if (!m_cmTask)
        {
            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_cmDev->CreateTask(m_cmTask));
        }
    }
    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalEncoderState::DestroyMDFResources()
{
    uint32_t i;

    if (m_cmDev && m_cmTask)
    {
        m_cmDev->DestroyTask(m_cmTask);
        m_cmTask = nullptr;
    }
    if (m_cmDev)
    {
        DestroyCmDevice(m_cmDev);
        m_cmDev = nullptr;
    }

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalEncoderState::AddKernelMdf(
    CmDevice *     device,
    CmQueue *      queue,
    CmKernel *     kernel,
    CmTask *       task,
    CmThreadSpace *threadspace,
    CmEvent *&     event,
    bool           isEnqueue)
{
    CODECHAL_ENCODE_CHK_NULL_RETURN(device);
    CODECHAL_ENCODE_CHK_NULL_RETURN(kernel);
    CODECHAL_ENCODE_CHK_NULL_RETURN(queue);
    CODECHAL_ENCODE_CHK_NULL_RETURN(task);
    CODECHAL_ENCODE_CHK_NULL_RETURN(threadspace);

    CODECHAL_ENCODE_CHK_STATUS_RETURN(kernel->AssociateThreadSpace(threadspace));
    CODECHAL_ENCODE_CHK_STATUS_RETURN(task->AddKernel(kernel));
    if (isEnqueue)
    {
        queue->Enqueue(task, event);
        task->Reset();
    }
    else
    {
        CODECHAL_ENCODE_CHK_STATUS_RETURN(task->AddSync());
    }

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalEncoderState::CreateMDFKernelResource(
    CodechalEncodeMdfKernelResource *resource,
    uint8_t                          kernelNum,
    uint8_t                          bufNum,
    uint8_t                          surfNum,
    uint8_t                          vmeSurfNum,
    uint16_t                         curbeSize)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_CHK_NULL_RETURN(resource);
    if (kernelNum > 0)
    {
        resource->ppKernel  = (CmKernel **)MOS_AllocAndZeroMemory(sizeof(CmKernel *) * kernelNum);
        resource->KernelNum = kernelNum;
    }
    if (bufNum > 0)
    {
        resource->ppCmBuf = (CmBuffer **)MOS_AllocAndZeroMemory(sizeof(CmBuffer *) * bufNum);
        resource->BufNum  = bufNum;
    }
    if (surfNum > 0)
    {
        resource->ppCmSurf = (CmSurface2D **)MOS_AllocAndZeroMemory(sizeof(CmSurface2D *) * surfNum);
        resource->SurfNum  = surfNum;
    }
    if (vmeSurfNum > 0)
    {
        resource->ppCmVmeSurf = (SurfaceIndex **)MOS_AllocAndZeroMemory(sizeof(SurfaceIndex *) * vmeSurfNum);
        resource->VmeSurfNum  = vmeSurfNum;
    }
    if (curbeSize > 0)
    {
        resource->pCurbe     = (uint8_t *)MOS_AllocAndZeroMemory(curbeSize);
        resource->wCurbeSize = curbeSize;
    }

    resource->e = nullptr;

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalEncoderState::DestroyMDFKernelResource(
    CodechalEncodeMdfKernelResource *resource)
{
    int i;
    CODECHAL_ENCODE_CHK_NULL_RETURN(resource);

    CODECHAL_ENCODE_CHK_STATUS_RETURN(FreeMDFKernelSurfaces(resource));

    if (resource->ppKernel && resource->KernelNum)
    {
        for (i = 0; i < resource->KernelNum; i++)
        {
            if (resource->ppKernel != nullptr)
            {
                m_cmDev->DestroyKernel(resource->ppKernel[i]);
                resource->ppKernel[i] = nullptr;
            }
        }
        MOS_FreeMemory(resource->ppKernel);
        resource->ppKernel = nullptr;
    }
    if (resource->pTS)
    {
        m_cmDev->DestroyThreadSpace(resource->pTS);
        resource->pTS = nullptr;
    }
    if (resource->ppCmBuf && resource->BufNum)
    {
        MOS_FreeMemory(resource->ppCmBuf);
        resource->ppCmBuf = nullptr;
        resource->BufNum  = 0;
    }
    if (resource->ppCmSurf && resource->SurfNum)
    {
        MOS_FreeMemory(resource->ppCmSurf);
        resource->ppCmSurf = nullptr;
        resource->SurfNum  = 0;
    }
    if (resource->ppCmVmeSurf && resource->VmeSurfNum)
    {
        MOS_FreeMemory(resource->ppCmVmeSurf);
        resource->ppCmVmeSurf = nullptr;
        resource->VmeSurfNum  = 0;
    }
    if (resource->ppKernel && resource->KernelNum)
    {
        MOS_FreeMemory(resource->ppKernel);
        resource->ppKernel  = nullptr;
        resource->KernelNum = 0;
    }
    if (resource->pCurbe && resource->wCurbeSize)
    {
        MOS_FreeMemory(resource->pCurbe);
        resource->pCurbe     = nullptr;
        resource->wCurbeSize = 0;
    }
    if (resource->pCommonISA)
    {
        MOS_FreeMemory(resource->pCommonISA);
        resource->pCommonISA = nullptr;
    }

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS  CodechalEncoderState::FreeMDFKernelSurfaces(
    CodechalEncodeMdfKernelResource*    resource)
{
    int i;

    for (i = 0; i < resource->VmeSurfNum; i++)
    {
        if (resource->ppCmVmeSurf[i] != nullptr && resource->ppCmVmeSurf[i] != (SurfaceIndex *)CM_NULL_SURFACE)
        {
            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_cmDev->DestroyVmeSurfaceG7_5(resource->ppCmVmeSurf[i]));
            resource->ppCmVmeSurf[i] = nullptr;
        }
    }
    for (i = 0; i < resource->BufNum; i++)
    {
        if (resource->ppCmBuf[i] != nullptr)
        {
            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_cmDev->DestroySurface(resource->ppCmBuf[i]));
            resource->ppCmBuf[i] = nullptr;
        }
    }
    for (i = 0; i < resource->SurfNum; i++)
    {
        if (resource->ppCmSurf[i] != nullptr)
        {
            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_cmDev->DestroySurface(resource->ppCmSurf[i]));
            resource->ppCmSurf[i] = nullptr;
        }
    }

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalEncoderState::InitCommon()
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    EncoderParams* encodeParams = &m_encodeParams;
    m_newSeq                = encodeParams->bNewSeq ? true: false;          // used by all except JPEG
    m_mbDataBufferSize      = encodeParams->dwMbDataBufferSize;             // used by all except JPEG
    m_newVuiData            = encodeParams->bNewVuiData ? true: false;      // used by AVC and MPEG2
    m_picQuant              = encodeParams->bPicQuant ? true: false;        // used by AVC and MPEG2
    m_newQmatrixData        = encodeParams->bNewQmatrixData ? true: false;  // used by AVC and MPEG2
    m_numSlices             = encodeParams->dwNumSlices;                    // used by all except VP9
    m_slcData               =
        (PCODEC_ENCODER_SLCDATA)(encodeParams->pSlcHeaderData);             // used by AVC, MPEG2, and HEVC

    CODECHAL_ENCODE_CHK_NULL_RETURN(encodeParams->presBitstreamBuffer);
    m_rawSurface           = *(encodeParams->psRawSurface);           // used by all
    m_resBitstreamBuffer    = *(encodeParams->presBitstreamBuffer);   // used by all

    CODECHAL_ENCODE_CHK_COND_RETURN(
        Mos_ResourceIsNull(&m_rawSurface.OsResource),
        "Raw surface is nullptr!");

    m_rawSurfaceToEnc     =
    m_rawSurfaceToPak     = &m_rawSurface;

    if(encodeParams->psReconSurface)
    {
        m_reconSurface     = *(encodeParams->psReconSurface);         // used by all except JPEG
    }

    if(encodeParams->pBSBuffer)
    {
        m_bsBuffer          = *(encodeParams->pBSBuffer);              // used by all except VP9
    }

    return eStatus;
}

void CodechalEncoderState::ResizeOnResChange()
{
    CODECHAL_ENCODE_FUNCTION_ENTER;

    // if resolution changed, free existing tracked buffer resources
    m_trackedBuf->Resize();
}

MOS_STATUS CodechalEncoderState::CheckResChangeAndCsc()
{
    CODECHAL_ENCODE_FUNCTION_ENTER;

    if (m_resolutionChanged)
    {
        ResizeOnResChange();
    }
#ifndef _FULL_OPEN_SOURCE
    // check recon surface's alignment meet HW requirement
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_cscDsState->CheckReconSurfaceAlignment(&m_reconSurface));

    if (!m_cscDsState->IsEnabled() ||
        CodecHal_PictureIsField(m_currOriginalPic) ||
        CodecHal_PictureIsInterlacedFrame(m_currOriginalPic))
    {
        // CSC disabled for interlaced frame
        m_cscDsState->ResetCscFlag();

        // check raw surface's alignment meet HW requirement
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_cscDsState->CheckRawSurfaceAlignment(m_rawSurfaceToEnc));
    }
    else
    {
        // check if we need to do CSC or copy non-aligned surface
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_cscDsState->CheckCondition());
    }
#endif
    return MOS_STATUS_SUCCESS;
}

// Function to allocate all resources common to all encoders
MOS_STATUS CodechalEncoderState::AllocateResources()
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    uint32_t numMbs = m_picWidthInMb * ((m_picHeightInMb+1)>>1)<<1;

    // initiate allocation paramters and lock flags
    MOS_ALLOC_GFXRES_PARAMS allocParamsForBufferLinear;
    MOS_ZeroMemory(&allocParamsForBufferLinear, sizeof(MOS_ALLOC_GFXRES_PARAMS));
    allocParamsForBufferLinear.Type     = MOS_GFXRES_BUFFER;
    allocParamsForBufferLinear.TileType = MOS_TILE_LINEAR;
    allocParamsForBufferLinear.Format   = Format_Buffer;

    MOS_ALLOC_GFXRES_PARAMS allocParams2D;
    MOS_ZeroMemory(&allocParams2D, sizeof(allocParams2D));
    allocParams2D.Type              = MOS_GFXRES_2D;
    allocParams2D.TileType          = MOS_TILE_LINEAR;
    allocParams2D.Format            = Format_Buffer_2D;

    MOS_LOCK_PARAMS lockFlagsNoOverWrite;;
    MOS_ZeroMemory(&lockFlagsNoOverWrite, sizeof(MOS_LOCK_PARAMS));
    lockFlagsNoOverWrite.WriteOnly = 1;
    lockFlagsNoOverWrite.NoOverWrite = 1;

    MOS_LOCK_PARAMS lockFlags;
    MOS_ZeroMemory(&lockFlags, sizeof(MOS_LOCK_PARAMS));
    lockFlags.WriteOnly = 1;

    // create VME and MFX sync objects
    if ((m_codecFunction == CODECHAL_FUNCTION_ENC_PAK) ||
        (m_codecFunction == (CODECHAL_FUNCTION_ENC | CODECHAL_FUNCTION_ENC_PAK)) ||
        (m_codecFunction == CODECHAL_FUNCTION_FEI_ENC_PAK) ||
        (m_codecFunction == (CODECHAL_FUNCTION_FEI_ENC | CODECHAL_FUNCTION_FEI_ENC_PAK)))
    {
        // Create OS synchronization object to sync between MFX => VME
        // if 3 is not good enough, need to increase MBCode buffer number
        m_semaphoreMaxCount = MOS_MAX_SEMAPHORE_COUNT;
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_osInterface->pfnCreateSyncResource(m_osInterface, &m_resSyncObjectRenderContextInUse));

        // Create OS synchronization object to sync between VME => MFX
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_osInterface->pfnCreateSyncResource(m_osInterface, &m_resSyncObjectVideoContextInUse));
    }

    // Create VME and VDENC/PAK sync objects
    if (m_codecFunction == CODECHAL_FUNCTION_ENC_VDENC_PAK)
    {
        m_semaphoreMaxCount = MOS_MAX_SEMAPHORE_COUNT;
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_osInterface->pfnCreateSyncResource(m_osInterface, &m_resSyncObjectRenderContextInUse));
    }

    //For HEVC, moved to standard specific as LCU size is not available here
    if  (m_hwInterface->GetMfxInterface()->IsRowStoreCachingSupported() &&
         ((m_mode == CODECHAL_ENCODE_MODE_AVC)                              ||
          (m_mode == CODECHAL_ENCODE_MODE_VP9 && m_vdencEnabled)))
    {
        MHW_VDBOX_ROWSTORE_PARAMS rowstoreParams = {};
        rowstoreParams.Mode         = m_mode;
        rowstoreParams.dwPicWidth   = m_frameWidth;
        rowstoreParams.bMbaff       = false;
        m_hwInterface->SetRowstoreCachingOffsets(&rowstoreParams);
    }

    if (m_osInterface->osCpInterface->IsCpEnabled() && m_hwInterface->GetCpInterface()->IsHWCounterAutoIncrementEnforced(m_osInterface) && m_skipFrameBasedHWCounterRead == false)
    {
        // eStatus query reporting
        m_encodeStatusBuf.dwReportSize           = MOS_ALIGN_CEIL(sizeof(EncodeStatus), sizeof(uint64_t));
        uint32_t size                            = sizeof(HwCounter) * CODECHAL_ENCODE_STATUS_NUM + sizeof(HwCounter);
        allocParamsForBufferLinear.dwBytes       = size;
        allocParamsForBufferLinear.pBufName      = "HWCounterQueryBuffer";
        allocParamsForBufferLinear.bIsPersistent = true;                    // keeping status buffer persistent since its used in all command buffers

        eStatus = (MOS_STATUS)m_osInterface->pfnAllocateResource(
            m_osInterface,
            &allocParamsForBufferLinear,
            &m_resHwCount);

        if (eStatus != MOS_STATUS_SUCCESS)
        {
            CODECHAL_ENCODE_ASSERTMESSAGE("Failed to allocate Encode eStatus Buffer.");
            return eStatus;
        }

        CODECHAL_ENCODE_CHK_STATUS_RETURN(
            m_osInterface->pfnSkipResourceSync(
                &m_resHwCount));

        uint8_t *dataHwCount = (uint8_t *)m_osInterface->pfnLockResource(
            m_osInterface,
            &(m_resHwCount),
            &lockFlagsNoOverWrite);

        if (!dataHwCount)
        {
            CODECHAL_ENCODE_ASSERTMESSAGE("Failed to Local Resource for MbEnc Adv Count Query Buffer.");
            return eStatus;
        }

        MOS_ZeroMemory(dataHwCount, size);
        m_dataHwCount = (uint32_t*)dataHwCount;
    }

    // eStatus query reporting
    m_encodeStatusBuf.dwReportSize = MOS_ALIGN_CEIL(sizeof(EncodeStatus), sizeof(uint64_t));
    uint32_t size = m_encodeStatusBuf.dwReportSize * CODECHAL_ENCODE_STATUS_NUM + sizeof(uint32_t) * 2;
    allocParamsForBufferLinear.dwBytes  = size;
    allocParamsForBufferLinear.pBufName = "StatusQueryBuffer";
    allocParamsForBufferLinear.bIsPersistent = true;                    // keeping status buffer persistent since its used in all command buffers

    CODECHAL_ENCODE_CHK_STATUS_MESSAGE_RETURN(
        m_osInterface->pfnAllocateResource(
            m_osInterface,
            &allocParamsForBufferLinear,
            &m_encodeStatusBuf.resStatusBuffer),
        "Failed to allocate Encode eStatus Buffer.");

    CODECHAL_ENCODE_CHK_STATUS_RETURN(
        m_osInterface->pfnSkipResourceSync(
        &m_encodeStatusBuf.resStatusBuffer));

    uint8_t* data = (uint8_t*)m_osInterface->pfnLockResource(
        m_osInterface,
        &(m_encodeStatusBuf.resStatusBuffer),
        &lockFlagsNoOverWrite);

    MOS_ZeroMemory(data, size);
    m_encodeStatusBuf.pData           = (uint32_t*)data;
    m_encodeStatusBuf.pEncodeStatus   = (uint8_t*)(data + sizeof(uint32_t) * 2);
    m_encodeStatusBuf.dwSize          = size;

    // Addresses writen to by HW commands (MI_STORE_DATA_IMM, MI_FLUSH_DW, PIPE_CONTROL) must be QW aligned since these
    // commands are capable of writing QWs so the least significant 3 bits of the address field are not used for the
    // actual address
    m_encodeStatusBuf.dwStoreDataOffset       = 0;
    m_encodeStatusBuf.dwBSByteCountOffset     = CODECHAL_OFFSETOF(EncodeStatus, dwMFCBitstreamByteCountPerFrame);
    m_encodeStatusBuf.dwBSSEBitCountOffset    = CODECHAL_OFFSETOF(EncodeStatus, dwMFCBitstreamSyntaxElementOnlyBitCount);
    m_encodeStatusBuf.dwImageStatusMaskOffset = CODECHAL_OFFSETOF(EncodeStatus, dwImageStatusMask);
    m_encodeStatusBuf.dwImageStatusCtrlOffset = CODECHAL_OFFSETOF(EncodeStatus, ImageStatusCtrl);
    m_encodeStatusBuf.dwNumSlicesOffset       = CODECHAL_OFFSETOF(EncodeStatus, NumSlices);
    m_encodeStatusBuf.dwErrorFlagOffset       = CODECHAL_OFFSETOF(EncodeStatus, dwErrorFlags);
    m_encodeStatusBuf.dwBRCQPReportOffset     = CODECHAL_OFFSETOF(EncodeStatus, BrcQPReport);
    m_encodeStatusBuf.dwNumPassesOffset       = CODECHAL_OFFSETOF(EncodeStatus, dwNumberPasses);
    m_encodeStatusBuf.dwQpStatusCountOffset   = CODECHAL_OFFSETOF(EncodeStatus, QpStatusCount);
    m_encodeStatusBuf.dwImageStatusCtrlOfLastBRCPassOffset = CODECHAL_OFFSETOF(EncodeStatus, ImageStatusCtrlOfLastBRCPass);
    m_encodeStatusBuf.dwSceneChangedOffset    = CODECHAL_OFFSETOF(EncodeStatus, dwSceneChangedFlag);
    m_encodeStatusBuf.dwSumSquareErrorOffset  = CODECHAL_OFFSETOF(EncodeStatus, sumSquareError[0]);
    m_encodeStatusBuf.dwSliceReportOffset     = CODECHAL_OFFSETOF(EncodeStatus, sliceReport);
    m_encodeStatusBuf.dwHuCStatusMaskOffset   = CODECHAL_OFFSETOF(EncodeStatus, HuCStatusRegMask);
    m_encodeStatusBuf.dwHuCStatusRegOffset    = CODECHAL_OFFSETOF(EncodeStatus, HuCStatusReg);

    m_encodeStatusBuf.wCurrIndex  = 0;
    m_encodeStatusBuf.wFirstIndex = 0;

    if (m_encEnabled)
    {
        m_encodeStatusBufRcs.dwReportSize = MOS_ALIGN_CEIL(sizeof(EncodeStatus), sizeof(uint64_t));
        size = m_encodeStatusBufRcs.dwReportSize * CODECHAL_ENCODE_STATUS_NUM + sizeof(uint32_t) * 2;
        allocParamsForBufferLinear.dwBytes  = size;
        allocParamsForBufferLinear.pBufName = "StatusQueryBufferRcs";
        allocParamsForBufferLinear.bIsPersistent = true;                    // keeping status buffer persistent since its used in all command buffers
        eStatus = (MOS_STATUS)m_osInterface->pfnAllocateResource(
            m_osInterface,
            &allocParamsForBufferLinear,
            &m_encodeStatusBufRcs.resStatusBuffer);

        if (eStatus != MOS_STATUS_SUCCESS)
        {
            CODECHAL_ENCODE_ASSERTMESSAGE("Failed to allocate Encode eStatus Buffer.");
            return eStatus;
        }

        data = (uint8_t*)m_osInterface->pfnLockResource(
            m_osInterface,
            &(m_encodeStatusBufRcs.resStatusBuffer),
            &lockFlagsNoOverWrite);

        if (data == nullptr)
        {
            CODECHAL_ENCODE_ASSERTMESSAGE("Failed to lock Encode eStatus Buffer RCS.");
            return eStatus;
        }

        MOS_ZeroMemory(data, size);
        m_encodeStatusBufRcs.pData                   = (uint32_t*)data;
        m_encodeStatusBufRcs.pEncodeStatus           = (uint8_t*)(data + sizeof(uint32_t) * 2);
        m_encodeStatusBufRcs.dwSize                  = size;
        m_encodeStatusBufRcs.dwStoreDataOffset       = 0;
        m_encodeStatusBufRcs.wCurrIndex              = 0;
        m_encodeStatusBufRcs.wFirstIndex             = 0;
    }

    if (m_pakEnabled)
    {
        m_stateHeapInterface->pfnSetCmdBufStatusPtr(m_stateHeapInterface, m_encodeStatusBuf.pData);
    }
    else
    {
        m_stateHeapInterface->pfnSetCmdBufStatusPtr(m_stateHeapInterface, m_encodeStatusBufRcs.pData);
    }

    MOS_LOCK_PARAMS lockFlagsWriteOnly;
    MOS_ZeroMemory(&lockFlagsWriteOnly, sizeof(MOS_LOCK_PARAMS));
    lockFlagsWriteOnly.WriteOnly = 1;

    if(m_inlineEncodeStatusUpdate)
    {
        m_atomicScratchBuf.dwSize = MOS_ALIGN_CEIL(sizeof(AtomicScratchBuffer), sizeof(uint64_t));
        allocParamsForBufferLinear.Type     = MOS_GFXRES_BUFFER;
        allocParamsForBufferLinear.TileType = MOS_TILE_LINEAR;
        allocParamsForBufferLinear.Format   = Format_Buffer;

        size  = MHW_CACHELINE_SIZE * 4 * 2; //  each set of scratch is 4 cacheline size, and allocate 2 set.
        allocParamsForBufferLinear.dwBytes  = size;
        allocParamsForBufferLinear.pBufName = "atomic sratch buffer";

        eStatus = (MOS_STATUS)m_osInterface->pfnAllocateResource(
                m_osInterface,
                &allocParamsForBufferLinear,
                &(m_atomicScratchBuf.resAtomicScratchBuffer));

        if (eStatus != MOS_STATUS_SUCCESS)
        {
            CODECHAL_ENCODE_ASSERTMESSAGE("Failed to allocate Finger Print Source Buffer.");
            return eStatus;
        }

        data = (uint8_t*)m_osInterface->pfnLockResource(
                m_osInterface,
                &(m_atomicScratchBuf.resAtomicScratchBuffer),
                &lockFlagsWriteOnly);

        if (data == nullptr)
        {
            CODECHAL_ENCODE_ASSERTMESSAGE("Failed to lock Finger Print Source Buffer.");
            return eStatus;
        }

        MOS_ZeroMemory(data, size);
        m_atomicScratchBuf.pData                 = (uint32_t*)data;
        m_atomicScratchBuf.dwSize                = size;
        m_atomicScratchBuf.dwZeroValueOffset    = 0;
        m_atomicScratchBuf.dwOperand1Offset     = MHW_CACHELINE_SIZE;
        m_atomicScratchBuf.dwOperand2Offset     = MHW_CACHELINE_SIZE * 2;
        m_atomicScratchBuf.dwOperand3Offset     = MHW_CACHELINE_SIZE * 3;
        m_atomicScratchBuf.wEncodeUpdateIndex   = 0;
        m_atomicScratchBuf.wTearDownIndex       = 1;
        m_atomicScratchBuf.dwOperandSetSize     = MHW_CACHELINE_SIZE * 4;
    }

    if (m_pakEnabled)
    {
        if(m_hwInterface->GetMfxInterface()->IsDeblockingFilterRowstoreCacheEnabled() == false)
        {
            // Deblocking Filter Row Store Scratch buffer
            allocParamsForBufferLinear.dwBytes  = m_picWidthInMb * 4 * CODECHAL_CACHELINE_SIZE; // 4 cachelines per MB
            allocParamsForBufferLinear.pBufName = "Deblocking Filter Row Store Scratch Buffer";

            CODECHAL_ENCODE_CHK_STATUS_MESSAGE_RETURN(
                m_osInterface->pfnAllocateResource(
                    m_osInterface,
                    &allocParamsForBufferLinear,
                    &m_resDeblockingFilterRowStoreScratchBuffer),
                "Failed to allocate Deblocking Filter Row Store Scratch Buffer.");
        }

        if(m_hwInterface->GetMfxInterface()->IsBsdMpcRowstoreCacheEnabled() == false)
        {
            // MPC Row Store Scratch buffer
            allocParamsForBufferLinear.dwBytes  = m_picWidthInMb * 2 * 64; // 2 cachelines per MB
            allocParamsForBufferLinear.pBufName = "MPC Row Store Scratch Buffer";

            CODECHAL_ENCODE_CHK_STATUS_MESSAGE_RETURN(
                m_osInterface->pfnAllocateResource(
                    m_osInterface,
                    &allocParamsForBufferLinear,
                    &m_resMPCRowStoreScratchBuffer),
                "Failed to allocate MPC Row Store Scratch Buffer.");
        }

        if (!m_vdencEnabled && m_standard != CODECHAL_HEVC)    // StreamOut is needed for HEVC VDEnc
        {
            // streamout data buffer
            allocParamsForBufferLinear.dwBytes  = numMbs * MFX_PAK_STREAMOUT_DATA_BYTE_SIZE * sizeof(uint32_t);
            allocParamsForBufferLinear.pBufName = "Pak StreamOut Buffer";

            for (auto i = 0; i < CODECHAL_ENCODE_RECYCLED_BUFFER_NUM; i++)
            {
                CODECHAL_ENCODE_CHK_STATUS_MESSAGE_RETURN(
                    m_osInterface->pfnAllocateResource(
                        m_osInterface,
                        &allocParamsForBufferLinear,
                        &m_resStreamOutBuffer[i]),
                    "Failed to allocate Pak Stream Out Buffer.");
            }
        }
    }

    if (m_encEnabled || m_vdencEnabled)
    {
        // Scaled surfaces are required to run both HME and IFrameDist
        CODECHAL_ENCODE_CHK_STATUS_RETURN(AllocateScalingResources());
    }

    if(m_encEnabled && (!m_vdencEnabled))
    {
        for (auto i = 0; i < CODECHAL_ENCODE_MAX_NUM_MAD_BUFFERS; i++)
        {
            allocParamsForBufferLinear.dwBytes  = CODECHAL_MAD_BUFFER_SIZE;
            allocParamsForBufferLinear.pBufName = "MAD Data Buffer";

            CODECHAL_ENCODE_CHK_STATUS_MESSAGE_RETURN(
                m_osInterface->pfnAllocateResource(
                    m_osInterface,
                    &allocParamsForBufferLinear,
                    &m_resMadDataBuffer[i]),
                "Failed to allocate MAD Data Buffer.");
        }
    }

    if (m_vdencEnabled)
    {
        // VDENC BRC PAK MMIO buffer
        allocParamsForBufferLinear.dwBytes  = sizeof(VdencBrcPakMmio);
        allocParamsForBufferLinear.pBufName = "VDENC BRC PAK MMIO Buffer";

        CODECHAL_ENCODE_CHK_STATUS_MESSAGE_RETURN(
            m_osInterface->pfnAllocateResource(
                m_osInterface,
                &allocParamsForBufferLinear,
                &m_resPakMmioBuffer),
            "%s: Failed to allocate VDENC BRC PAK MMIO Buffer\n", __FUNCTION__);

        // VDEnc StreamIn data buffers, shared between driver/ME kernel/VDEnc
        if ((m_mode == CODECHAL_ENCODE_MODE_HEVC) || (m_mode == CODECHAL_ENCODE_MODE_VP9))
        {
            allocParamsForBufferLinear.dwBytes = (MOS_ALIGN_CEIL(m_frameWidth, 64)/32) * (MOS_ALIGN_CEIL(m_frameHeight, 64)/32) * CODECHAL_CACHELINE_SIZE;
        }
        else
        {
            allocParamsForBufferLinear.dwBytes = m_picWidthInMb * m_picHeightInMb * CODECHAL_CACHELINE_SIZE;
        }
        allocParamsForBufferLinear.pBufName = "VDEnc StreamIn Data Buffer";

        for (auto i = 0; i < CODECHAL_ENCODE_RECYCLED_BUFFER_NUM; i++)
        {
            CODECHAL_ENCODE_CHK_STATUS_MESSAGE_RETURN(
                m_osInterface->pfnAllocateResource(
                    m_osInterface,
                    &allocParamsForBufferLinear,
                    &m_resVdencStreamInBuffer[i]),
                "Failed to allocate VDEnc StreamIn Data Buffer.");

            data = (uint8_t*)m_osInterface->pfnLockResource(
                m_osInterface,
                &m_resVdencStreamInBuffer[i],
                &lockFlags);

            CODECHAL_ENCODE_CHK_NULL_RETURN(data);

            MOS_ZeroMemory(
                data,
                allocParamsForBufferLinear.dwBytes);

            m_osInterface->pfnUnlockResource(m_osInterface, &m_resVdencStreamInBuffer[i]);
        }
    }

    if (m_vdencEnabled)
    {
        // HUC STATUS 2 Buffer for HuC status check in COND_BB_END
        allocParamsForBufferLinear.dwBytes = sizeof(uint64_t);
        allocParamsForBufferLinear.pBufName = "HUC STATUS 2 Buffer";

        CODECHAL_ENCODE_CHK_STATUS_MESSAGE_RETURN(
            m_osInterface->pfnAllocateResource(
                m_osInterface,
                &allocParamsForBufferLinear,
                &m_resHucStatus2Buffer),
            "%s: Failed to allocate HUC STATUS 2 Buffer\n", __FUNCTION__);
    }

    return eStatus;
}

MOS_STATUS CodechalEncoderState::AllocateScalingResources()
{
    uint32_t                    numMBs, size;
    MOS_ALLOC_GFXRES_PARAMS     allocParamsForBuffer2D;
    MOS_ALLOC_GFXRES_PARAMS     allocParamsForBufferLinear;
    MOS_STATUS                  eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    //Allocate the Batch Buffer for scaling Kernel.
    numMBs = m_picWidthInMb * ((m_picHeightInMb + 1) >> 1) << 1;
    size = m_hwInterface->GetMediaObjectBufferSize(
        numMBs,
        64);

    for (int i = 0; i < CODECHAL_ENCODE_VME_BBUF_NUM; i++)
    {
        MOS_ZeroMemory(&m_scalingBBUF[i].BatchBuffer, sizeof(m_scalingBBUF[0].BatchBuffer));

        /* For CM based Downscale kernel, unlike the old asm based downscale kernel,
        HW walker can be used as no inline data is required by the kernel. */
        if (!m_useCmScalingKernel && !m_useMwWlkrForAsmScalingKernel)
        {
            m_scalingBBUF[i].BatchBuffer.bSecondLevel = true;
            CODECHAL_ENCODE_CHK_STATUS_RETURN(Mhw_AllocateBb(
                m_osInterface,
                &m_scalingBBUF[i].BatchBuffer,
                NULL,
                size));

            m_scalingBBUF[i].dwSize         = size;
            m_scalingBBUF[i].dwNumMbsInBBuf = 0;
            m_scalingBBufIdx              = CODECHAL_ENCODE_VME_BBUF_NUM - 1;
        }
    }

    //MB stats buffer is supported by AVC kernels on g9+.
    if(m_mbStatsSupported)
    {
        MOS_ZeroMemory(&allocParamsForBufferLinear, sizeof(MOS_ALLOC_GFXRES_PARAMS));
        allocParamsForBufferLinear.Type     = MOS_GFXRES_BUFFER;
        allocParamsForBufferLinear.TileType = MOS_TILE_LINEAR;
        allocParamsForBufferLinear.Format   = Format_Buffer;

        // Starting from g9 HVS kernel, MBEnc Curbe is decoupled from BRC kernel and a new MBEnc BRC surface is added.
        // new HVS-based BRC kernel requires size of MBStat surface be 1024-aligned
        m_hwInterface->m_avcMbStatBufferSize = MOS_ALIGN_CEIL(m_picWidthInMb * 16 * sizeof(uint32_t)* (4 * m_downscaledHeightInMb4x), 1024);

        allocParamsForBufferLinear.dwBytes  = m_hwInterface->m_avcMbStatBufferSize;
        allocParamsForBufferLinear.pBufName = "MB Statistics Buffer";

        CODECHAL_ENCODE_CHK_STATUS_MESSAGE_RETURN(m_osInterface->pfnAllocateResource(
            m_osInterface,
            &allocParamsForBufferLinear,
            &m_resMbStatsBuffer), "Failed to allocate  MB Statistics Buffer.");

        m_mbStatsBottomFieldOffset = m_picWidthInMb * 16 * sizeof(uint32_t) * (2 * m_downscaledHeightInMb4x);
    }
    else if(m_flatnessCheckSupported)
    {
        MOS_ZeroMemory(&m_flatnessCheckSurface, sizeof(MOS_SURFACE));
        m_flatnessCheckSurface.TileType         = MOS_TILE_LINEAR;
        m_flatnessCheckSurface.bArraySpacing    = true;
        m_flatnessCheckSurface.Format           = Format_Buffer_2D;

        MOS_ZeroMemory(&allocParamsForBuffer2D, sizeof(MOS_ALLOC_GFXRES_PARAMS));
        allocParamsForBuffer2D.Type     = MOS_GFXRES_2D;
        allocParamsForBuffer2D.TileType = MOS_TILE_LINEAR;
        allocParamsForBuffer2D.Format   = Format_Buffer_2D;
        // Data size for 1MB is 1DWORDs (4Bytes)
        allocParamsForBuffer2D.dwWidth  = MOS_ALIGN_CEIL(m_picWidthInMb * 4, 64);
        // Because FlatnessCheckSurface was referenced and filled during 4xDownScaling operation,
        // the height should be fit to MediaWalker height setting for 4xDS Kernel.
        allocParamsForBuffer2D.dwHeight = MOS_ALIGN_CEIL(4 * m_downscaledHeightInMb4x, 64);
        allocParamsForBuffer2D.pBufName = "Flatness Check Surface";

        eStatus = (MOS_STATUS)m_osInterface->pfnAllocateResource(
            m_osInterface,
            &allocParamsForBuffer2D,
            &m_flatnessCheckSurface.OsResource);

        if (eStatus != MOS_STATUS_SUCCESS)
        {
            CODECHAL_ENCODE_ASSERTMESSAGE("Failed to allocate FlatnessCheck Surface.");
            return eStatus;
        }

        CODECHAL_ENCODE_CHK_STATUS_RETURN(CodecHalGetResourceInfo(
            m_osInterface,
            &m_flatnessCheckSurface));

        m_flatnessCheckBottomFieldOffset = m_flatnessCheckSurface.dwPitch * m_flatnessCheckSurface.dwHeight >> 1;
    }

    return eStatus;
}

MOS_STATUS CodechalEncoderState::ExecuteMeKernel(
    MeCurbeParams *meParams,
    MeSurfaceParams *meSurfaceParams,
    HmeLevel hmeLevel)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    CODECHAL_ENCODE_CHK_NULL_RETURN(meParams);
    CODECHAL_ENCODE_CHK_NULL_RETURN(meSurfaceParams);

    PerfTagSetting perfTag;
    perfTag.Value = 0;
    perfTag.Mode = (uint16_t)m_mode & CODECHAL_ENCODE_MODE_BIT_MASK;
    perfTag.CallType = m_singleTaskPhaseSupported ? CODECHAL_ENCODE_PERFTAG_CALL_SCALING_KERNEL : CODECHAL_ENCODE_PERFTAG_CALL_ME_KERNEL;
    perfTag.PictureCodingType = m_pictureCodingType;
    m_osInterface->pfnSetPerfTag(m_osInterface, perfTag.Value);
    // Each ME kernel buffer counts as a separate perf task
    m_osInterface->pfnResetPerfBufferID(m_osInterface);

    CODECHAL_MEDIA_STATE_TYPE encFunctionType = (hmeLevel == HME_LEVEL_32x) ? CODECHAL_MEDIA_STATE_32X_ME :
        (hmeLevel == HME_LEVEL_16x) ? CODECHAL_MEDIA_STATE_16X_ME : CODECHAL_MEDIA_STATE_4X_ME;

    bool vdencMeInUse = false;
    if (m_vdencEnabled && (encFunctionType == CODECHAL_MEDIA_STATE_4X_ME))
    {
        vdencMeInUse = true;
        // Non legacy stream in is for hevc vp9 streamin kernel
        encFunctionType = m_useNonLegacyStreamin ? CODECHAL_MEDIA_STATE_4X_ME : CODECHAL_MEDIA_STATE_ME_VDENC_STREAMIN;
    }

    uint32_t krnStateIdx = vdencMeInUse ?
        CODECHAL_ENCODE_ME_IDX_VDENC :
        ((m_pictureCodingType == P_TYPE) ? CODECHAL_ENCODE_ME_IDX_P : CODECHAL_ENCODE_ME_IDX_B);

    PMHW_KERNEL_STATE kernelState = &m_meKernelStates[krnStateIdx];

    // If Single Task Phase is not enabled, use BT count for the kernel state.
    if (m_firstTaskInPhase == true || !m_singleTaskPhaseSupported)
    {
        uint32_t maxBtCount = m_singleTaskPhaseSupported ?
            m_maxBtCount : kernelState->KernelParams.iBTCount;
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_stateHeapInterface->pfnRequestSshSpaceForCmdBuf(
            m_stateHeapInterface,
            maxBtCount));
        m_vmeStatesSize = m_hwInterface->GetKernelLoadCommandSize(maxBtCount);
        CODECHAL_ENCODE_CHK_STATUS_RETURN(VerifySpaceAvailable());
    }

    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hwInterface->AssignDshAndSshSpace(
        m_stateHeapInterface,
        kernelState,
        false,
        0,
        false,
        m_storeData));
    MHW_INTERFACE_DESCRIPTOR_PARAMS idParams;
    MOS_ZeroMemory(&idParams, sizeof(idParams));
    idParams.pKernelState = kernelState;
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_stateHeapInterface->pfnSetInterfaceDescriptor(
        m_stateHeapInterface,
        1,
        &idParams));

    // Setup Additional MeParams (Most of them set up in codec specific function, so don't zero out here)
    meParams->hmeLvl = hmeLevel;
    meParams->pKernelState = kernelState;

    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_encoderGenState->SetCurbeMe(meParams));

    CODECHAL_DEBUG_TOOL(
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_debugInterface->DumpKernelRegion(
            encFunctionType,
            MHW_DSH_TYPE,
            kernelState));
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_debugInterface->DumpCurbe(
        encFunctionType,
        kernelState));
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_debugInterface->DumpKernelRegion(
        encFunctionType,
        MHW_ISH_TYPE,
        kernelState));
    )
    MOS_COMMAND_BUFFER cmdBuffer;
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_osInterface->pfnGetCommandBuffer(m_osInterface, &cmdBuffer, 0));
    SendKernelCmdsParams sendKernelCmdsParams;
    sendKernelCmdsParams = SendKernelCmdsParams();
    sendKernelCmdsParams.EncFunctionType = encFunctionType;
    sendKernelCmdsParams.pKernelState = kernelState;

    CODECHAL_ENCODE_CHK_STATUS_RETURN(SendGenericKernelCmds(&cmdBuffer, &sendKernelCmdsParams));

    // Add binding table
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_stateHeapInterface->pfnSetBindingTable(
        m_stateHeapInterface,
        kernelState));

    // Setup Additional ME surface params (Most of them set up in codec specific function, so don't zero out here)
    meSurfaceParams->dwDownscaledWidthInMb = (hmeLevel == HME_LEVEL_32x) ? m_downscaledWidthInMb32x :
        (hmeLevel == HME_LEVEL_16x) ? m_downscaledWidthInMb16x : m_downscaledWidthInMb4x;
    meSurfaceParams->dwDownscaledHeightInMb = (hmeLevel == HME_LEVEL_32x) ? m_downscaledFrameFieldHeightInMb32x :
        (hmeLevel == HME_LEVEL_16x) ? m_downscaledFrameFieldHeightInMb16x : m_downscaledFrameFieldHeightInMb4x;
    meSurfaceParams->b32xMeInUse = (hmeLevel == HME_LEVEL_32x) ? true : false;
    meSurfaceParams->b16xMeInUse = (hmeLevel == HME_LEVEL_16x) ? true : false;
    meSurfaceParams->pKernelState = kernelState;

    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_encoderGenState->SendMeSurfaces(&cmdBuffer, meSurfaceParams));

    // Dump SSH for ME kernel
    CODECHAL_DEBUG_TOOL(
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_debugInterface->DumpKernelRegion(
            encFunctionType,
            MHW_SSH_TYPE,
            kernelState)));

    /* zero out the mv data memory and me distortion buffer for the driver ULT
    kernel only writes out this data used for current frame, in some cases the the data used for
    previous frames would be left in the buffer (for example, the L1 mv for B frame would still show
    in the P frame mv data buffer */

    // Zeroing out the buffers has perf impact, so zero it out only when dumps are actually enabled
    CODECHAL_DEBUG_TOOL(
    CODECHAL_ENCODE_CHK_NULL_RETURN(m_debugInterface);
    uint8_t* data = NULL;
    uint32_t size = 0;
    bool driverMeDumpEnabled = m_debugInterface->DumpIsEnabled(CodechalDbgAttr::attrOutput, encFunctionType);

    if (driverMeDumpEnabled)
    {
        MOS_LOCK_PARAMS lockFlags;
        MOS_ZeroMemory(&lockFlags, sizeof(MOS_LOCK_PARAMS));
        lockFlags.WriteOnly = 1;

        switch (hmeLevel)
        {
        case HME_LEVEL_32x:
            data = (uint8_t*)m_osInterface->pfnLockResource(
                m_osInterface,
                &meSurfaceParams->ps32xMeMvDataBuffer->OsResource,
                &lockFlags);
            CODECHAL_ENCODE_CHK_NULL_RETURN(data);
            size = MOS_ALIGN_CEIL((m_downscaledWidthInMb32x * 32), 64) *
                (m_downscaledHeightInMb32x * 2 * 4 * CODECHAL_ENCODE_ME_DATA_SIZE_MULTIPLIER);
            MOS_ZeroMemory(data, size);
            m_osInterface->pfnUnlockResource(
                m_osInterface,
                &meSurfaceParams->ps32xMeMvDataBuffer->OsResource);
            break;
        case HME_LEVEL_16x:
            data = (uint8_t*)m_osInterface->pfnLockResource(
                m_osInterface,
                &meSurfaceParams->ps16xMeMvDataBuffer->OsResource,
                &lockFlags);
            CODECHAL_ENCODE_CHK_NULL_RETURN(data);
            size = MOS_ALIGN_CEIL((m_downscaledWidthInMb16x * 32), 64) *
                (m_downscaledHeightInMb16x * 2 * 4 * CODECHAL_ENCODE_ME_DATA_SIZE_MULTIPLIER);
            MOS_ZeroMemory(data, size);
            m_osInterface->pfnUnlockResource(
                m_osInterface,
                &meSurfaceParams->ps16xMeMvDataBuffer->OsResource);
            break;
        case HME_LEVEL_4x:
            if (!m_vdencEnabled)
            {
                data = (uint8_t*)m_osInterface->pfnLockResource(
                    m_osInterface,
                    &meSurfaceParams->ps4xMeMvDataBuffer->OsResource,
                    &lockFlags);
                CODECHAL_ENCODE_CHK_NULL_RETURN(data);
                size = MOS_ALIGN_CEIL((m_downscaledWidthInMb4x * 32), 64) *
                    (m_downscaledHeightInMb4x * 2 * 4 * CODECHAL_ENCODE_ME_DATA_SIZE_MULTIPLIER);
                MOS_ZeroMemory(data, size);
                m_osInterface->pfnUnlockResource(
                    m_osInterface,
                    &meSurfaceParams->ps4xMeMvDataBuffer->OsResource);
            }
            break;
        default:
            return MOS_STATUS_INVALID_PARAMETER;
        }

        // zeroing out ME dist buffer
        if (meSurfaceParams->b4xMeDistortionBufferSupported)
        {
            data = (uint8_t*)m_osInterface->pfnLockResource(
                m_osInterface, &meSurfaceParams->psMeDistortionBuffer->OsResource, &lockFlags);
            CODECHAL_ENCODE_CHK_NULL_RETURN(data);
            size = meSurfaceParams->psMeDistortionBuffer->dwHeight * meSurfaceParams->psMeDistortionBuffer->dwPitch;
            MOS_ZeroMemory(data, size);
            m_osInterface->pfnUnlockResource(
                m_osInterface,
                &meSurfaceParams->psMeDistortionBuffer->OsResource);
        }
    }
    );

    uint32_t scalingFactor = (hmeLevel == HME_LEVEL_32x) ? SCALE_FACTOR_32x :
        (hmeLevel == HME_LEVEL_16x) ? SCALE_FACTOR_16x : SCALE_FACTOR_4x;

    uint32_t resolutionX = CODECHAL_GET_WIDTH_IN_MACROBLOCKS(m_frameWidth / scalingFactor);
    uint32_t resolutionY = CODECHAL_GET_HEIGHT_IN_MACROBLOCKS(m_frameFieldHeight / scalingFactor);

    CODECHAL_WALKER_CODEC_PARAMS walkerCodecParams;
    MOS_ZeroMemory(&walkerCodecParams, sizeof(walkerCodecParams));
    walkerCodecParams.WalkerMode = m_walkerMode;
    walkerCodecParams.dwResolutionX = resolutionX;
    walkerCodecParams.dwResolutionY = resolutionY;
    walkerCodecParams.bNoDependency = true;
    walkerCodecParams.bMbaff = meSurfaceParams->bMbaff;
    walkerCodecParams.bGroupIdSelectSupported = m_groupIdSelectSupported;
    walkerCodecParams.ucGroupId = m_groupId;

    MHW_WALKER_PARAMS walkerParams;
    CODECHAL_ENCODE_CHK_STATUS_RETURN(CodecHalInitMediaObjectWalkerParams(
        m_hwInterface,
        &walkerParams,
        &walkerCodecParams));

    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_renderEngineInterface->AddMediaObjectWalkerCmd(
        &cmdBuffer,
        &walkerParams));

    CODECHAL_ENCODE_CHK_STATUS_RETURN(EndStatusReport(&cmdBuffer, encFunctionType));

    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_stateHeapInterface->pfnSubmitBlocks(
        m_stateHeapInterface,
        kernelState));
    if (!m_singleTaskPhaseSupported || m_lastTaskInPhase)
    {
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_stateHeapInterface->pfnUpdateGlobalCmdBufId(
            m_stateHeapInterface));
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiBatchBufferEnd(&cmdBuffer, nullptr));
    }

    CODECHAL_DEBUG_TOOL(CODECHAL_ENCODE_CHK_STATUS_RETURN(m_debugInterface->DumpCmdBuffer(
        &cmdBuffer,
        encFunctionType,
        nullptr)));

    m_hwInterface->UpdateSSEuForCmdBuffer(&cmdBuffer, m_singleTaskPhaseSupported, m_lastTaskInPhase);

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

    if (!m_singleTaskPhaseSupported || m_lastTaskInPhase)
    {
        m_osInterface->pfnSubmitCommandBuffer(m_osInterface, &cmdBuffer, m_renderContextUsesNullHw);
        m_lastTaskInPhase = false;
    }

    return eStatus;
}

bool CodechalEncoderState::CheckSupportedFormat(
    PMOS_SURFACE surface)
{
    bool isColorFormatSupported = true;

    if (!surface)
    {
        CODECHAL_ENCODE_ASSERTMESSAGE("Invalid (NULL) Pointer.");
        return isColorFormatSupported;
    }

    // if input is not Tile-Y, or color format not NV12, invoke Ds+Copy kernel
    if (!IS_Y_MAJOR_TILE_FORMAT(surface->TileType) ||
        surface->Format != Format_NV12)
    {
        isColorFormatSupported = false;
    }

    return isColorFormatSupported;
}

void CodechalEncoderState::FreeResources()
{
    CODECHAL_ENCODE_FUNCTION_ENTER;

    // destroy sync objects
    if (!Mos_ResourceIsNull(&m_resSyncObjectRenderContextInUse))
    {
        m_osInterface->pfnDestroySyncResource(m_osInterface, &m_resSyncObjectRenderContextInUse);
    }
    if (!Mos_ResourceIsNull(&m_resSyncObjectVideoContextInUse))
    {
        m_osInterface->pfnDestroySyncResource(m_osInterface, &m_resSyncObjectVideoContextInUse);
    }

    // Release eStatus buffer
    if (!Mos_ResourceIsNull(&m_encodeStatusBuf.resStatusBuffer))
    {
        m_osInterface->pfnUnlockResource(
            m_osInterface,
            &(m_encodeStatusBuf.resStatusBuffer));

        m_osInterface->pfnFreeResource(
            m_osInterface,
            &m_encodeStatusBuf.resStatusBuffer);
    }

    // Release HW Counter buffer
    if (m_osInterface->osCpInterface->IsCpEnabled() && m_hwInterface->GetCpInterface()->IsHWCounterAutoIncrementEnforced(m_osInterface) && m_skipFrameBasedHWCounterRead == false)
    {
        if (!Mos_ResourceIsNull(&m_resHwCount))
        {
            m_osInterface->pfnUnlockResource(
                m_osInterface,
                &(m_resHwCount));

            m_osInterface->pfnFreeResource(
                m_osInterface,
                &m_resHwCount);
        }
    }

    if (!Mos_ResourceIsNull(&m_encodeStatusBufRcs.resStatusBuffer))
    {
        m_osInterface->pfnUnlockResource(
            m_osInterface,
            &(m_encodeStatusBufRcs.resStatusBuffer));

        m_osInterface->pfnFreeResource(
            m_osInterface,
            &m_encodeStatusBufRcs.resStatusBuffer);
    }

    if (m_pakEnabled)
    {
        if (!Mos_ResourceIsNull(&m_resDeblockingFilterRowStoreScratchBuffer))
        {
            m_osInterface->pfnFreeResource(
                m_osInterface,
                &m_resDeblockingFilterRowStoreScratchBuffer);
        }
        if (!Mos_ResourceIsNull(&m_resMPCRowStoreScratchBuffer))
        {
            m_osInterface->pfnFreeResource(
                m_osInterface,
                &m_resMPCRowStoreScratchBuffer);
        }

        for (auto i = 0; i < CODECHAL_ENCODE_RECYCLED_BUFFER_NUM; i++)
        {
            if (!Mos_ResourceIsNull(&m_resStreamOutBuffer[i]))
            {
                m_osInterface->pfnFreeResource(
                    m_osInterface,
                    &m_resStreamOutBuffer[i]);
            }

            if (!Mos_ResourceIsNull(&m_sliceMapSurface[i].OsResource))
            {
                m_osInterface->pfnFreeResource(
                    m_osInterface,
                    &m_sliceMapSurface[i].OsResource);
            }
        }
    }
#ifndef _FULL_OPEN_SOURCE
    // release CSC Downscaling kernel resources
    if (m_cscDsState)
    {
        MOS_Delete(m_cscDsState);
        m_cscDsState = nullptr;
    }
#endif
    if (m_encoderGenState)
    {
        MOS_Delete(m_encoderGenState);
        m_encoderGenState = nullptr;
    }

    if(m_inlineEncodeStatusUpdate)
    {
        if (!Mos_ResourceIsNull(&m_atomicScratchBuf.resAtomicScratchBuffer))
        {
            m_osInterface->pfnUnlockResource(
            m_osInterface,
            &(m_atomicScratchBuf.resAtomicScratchBuffer));

            m_osInterface->pfnFreeResource(
                m_osInterface,
                &m_atomicScratchBuf.resAtomicScratchBuffer);
        }
    }

    if (m_encEnabled)
    {
        for (auto i = 0; i < CODECHAL_ENCODE_VME_BBUF_NUM; i++)
        {
            if (!Mos_ResourceIsNull(&m_scalingBBUF[i].BatchBuffer.OsResource))
            {
                Mhw_FreeBb(m_osInterface, &m_scalingBBUF[i].BatchBuffer, nullptr);
            }
        }

        if(!Mos_ResourceIsNull(&m_flatnessCheckSurface.OsResource))
        {
            m_osInterface->pfnFreeResource(
                m_osInterface,
                &m_flatnessCheckSurface.OsResource);
        }

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

        for (auto i = 0; i < CODECHAL_ENCODE_MAX_NUM_MAD_BUFFERS; i++)
        {
            if (!Mos_ResourceIsNull(&m_resMadDataBuffer[i]))
            {
                m_osInterface->pfnFreeResource(
                    m_osInterface,
                    &m_resMadDataBuffer[i]);
            }
        }
    }

    if (m_vdencEnabled)
    {
        m_osInterface->pfnFreeResource(
            m_osInterface,
            &m_resPakMmioBuffer);

        m_osInterface->pfnFreeResource(m_osInterface, &m_resHucFwBuffer);

        for (auto i = 0; i < CODECHAL_ENCODE_RECYCLED_BUFFER_NUM; i++)
        {
            m_osInterface->pfnFreeResource(
                m_osInterface,
                &m_resVdencStreamInBuffer[i]);
        }
    }

    if (m_vdencEnabled)
    {
        m_osInterface->pfnFreeResource(m_osInterface, &m_resHucStatus2Buffer);
    }

    m_osInterface->pfnFreeResource(m_osInterface, &m_resVdencCmdInitializerDmemBuffer);
    for (auto i = 0; i < 2; i++)
    {
        m_osInterface->pfnFreeResource(m_osInterface, &m_resVdencCmdInitializerDataBuffer[i]);
    }

    return;
}

void CodechalEncoderState::Destroy()
{
    CODECHAL_ENCODE_FUNCTION_ENTER;

    if (m_videoNodeAssociationCreated  &&
        MEDIA_IS_SKU(m_skuTable, FtrVcs2)            &&
        (m_videoGpuNode < MOS_GPU_NODE_MAX))
    {
        // Destroy encode video node associations
        m_osInterface->pfnDestroyVideoNodeAssociation(m_osInterface, m_videoGpuNode);
    }

    if (m_mmcState != nullptr)
    {
        MOS_Delete(m_mmcState);
        m_mmcState = nullptr;
    }

    MOS_Delete(m_allocator);
    m_allocator = nullptr;

    MOS_Delete(m_trackedBuf);
    m_trackedBuf = nullptr;

    // Release encoder resources
    FreeResources();
    return;
}

uint32_t CodechalEncoderState::CalculateCommandBufferSize()
{
    uint32_t commandBufferSize =
        m_pictureStatesSize        +
        m_extraPictureStatesSize   +
        (m_sliceStatesSize * m_numSlices);

    if (m_singleTaskPhaseSupported)
    {
        commandBufferSize *= (m_numPasses + 1);
    }

    // 4K align since allocation is in chunks of 4K bytes.
    commandBufferSize = MOS_ALIGN_CEIL(commandBufferSize, 0x1000);

    return commandBufferSize;
}

MOS_STATUS CodechalEncoderState::VerifySpaceAvailable()
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    uint32_t requestedSize = 0;
    if (m_osInterface->pfnGetGpuContext(m_osInterface) == m_renderContext)
    {
        requestedSize = m_vmeStatesSize;

        eStatus = (MOS_STATUS)m_osInterface->pfnVerifyCommandBufferSize(
            m_osInterface,
            requestedSize,
            0);

        return eStatus;
    }

    uint32_t requestedPatchListSize = 0;
    MOS_STATUS statusPatchList = MOS_STATUS_SUCCESS, statusCmdBuf;

    bool m_usePatchList = m_osInterface->bUsesPatchList || MEDIA_IS_SKU(m_skuTable, FtrMediaPatchless);
    if (m_osInterface->pfnGetGpuContext(m_osInterface) == m_videoContext)
    {
        if (m_usePatchList)
        {
            requestedPatchListSize =
            m_picturePatchListSize +
            m_extraPicturePatchListSize +
            (m_slicePatchListSize * m_numSlices);

            if (m_singleTaskPhaseSupported)
            {
                requestedPatchListSize *= (m_numPasses + 1);
            }
        }

        requestedSize = CalculateCommandBufferSize();

        // Try a maximum of 3 attempts to request the required sizes from OS
        // OS could reset the sizes if necessary, therefore, requires to re-verify
        for (auto i = 0; i < 3; i++)
        {
            //Experiment shows resizing CmdBuf size and PatchList size in two calls one after the other would cause previously
            //successfully requested size to fallback to wrong value, hence never satisfying the requirement. So we call pfnResize()
            //only once depending on whether CmdBuf size not enough, or PatchList size not enough, or both.
            if (m_usePatchList)
            {
                statusPatchList = (MOS_STATUS)m_osInterface->pfnVerifyPatchListSize(
                    m_osInterface,
                    requestedPatchListSize);
            }

            statusCmdBuf = (MOS_STATUS)m_osInterface->pfnVerifyCommandBufferSize(
                m_osInterface,
                requestedSize,
                0);

            if (statusPatchList != MOS_STATUS_SUCCESS && statusCmdBuf != MOS_STATUS_SUCCESS)
            {
                CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hwInterface->ResizeCommandBufferAndPatchList(requestedSize + COMMAND_BUFFER_RESERVED_SPACE, requestedPatchListSize));
            }
            else if (statusPatchList != MOS_STATUS_SUCCESS)
            {
                CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hwInterface->ResizeCommandBufferAndPatchList(0, requestedPatchListSize));
            }
            else if (statusCmdBuf != MOS_STATUS_SUCCESS)
            {
                CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hwInterface->ResizeCommandBufferAndPatchList(requestedSize + COMMAND_BUFFER_RESERVED_SPACE, 0));
            }
            else
            {
                m_singleTaskPhaseSupportedInPak = m_singleTaskPhaseSupported;
                return eStatus;
            }
        }
    }

    if (m_usePatchList)
    {
        statusPatchList = (MOS_STATUS)m_osInterface->pfnVerifyPatchListSize(
            m_osInterface,
            requestedPatchListSize);
    }

    statusCmdBuf = (MOS_STATUS)m_osInterface->pfnVerifyCommandBufferSize(
        m_osInterface,
        requestedSize,
        0);

    if ((statusCmdBuf == MOS_STATUS_SUCCESS) && (statusPatchList == MOS_STATUS_SUCCESS))
    {
        m_singleTaskPhaseSupportedInPak = m_singleTaskPhaseSupported;
        return eStatus;
    }

    if (m_singleTaskPhaseSupported)
    {
        uint32_t requestedSizeOriginal = 0, requestedPatchListSizeOriginal = 0;
        for (auto i = 0; i < 3; i++)
        {
            //Experiment shows resizing CmdBuf size and PatchList size in two calls one after the other would cause previously
            //successfully requested size to fallback to wrong value, hence never satisfying the requirement. So we call pfnResize()
            //only once depending on whether CmdBuf size not enough, or PatchList size not enough, or both.
            if (m_usePatchList)
            {
                statusPatchList = (MOS_STATUS)m_osInterface->pfnVerifyPatchListSize(
                    m_osInterface,
                    requestedPatchListSizeOriginal);
            }

            statusCmdBuf = (MOS_STATUS)m_osInterface->pfnVerifyCommandBufferSize(
                m_osInterface,
                requestedSizeOriginal,
                0);

            if (statusPatchList != MOS_STATUS_SUCCESS && statusCmdBuf != MOS_STATUS_SUCCESS)
            {
                CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hwInterface->ResizeCommandBufferAndPatchList(requestedSizeOriginal + COMMAND_BUFFER_RESERVED_SPACE, requestedPatchListSizeOriginal));
            }
            else if (statusPatchList != MOS_STATUS_SUCCESS)
            {
                CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hwInterface->ResizeCommandBufferAndPatchList(0, requestedPatchListSizeOriginal));
            }
            else if (statusCmdBuf != MOS_STATUS_SUCCESS)
            {
                CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hwInterface->ResizeCommandBufferAndPatchList(requestedSizeOriginal + COMMAND_BUFFER_RESERVED_SPACE, 0));
            }
            else
            {
                m_singleTaskPhaseSupportedInPak = false;
                return eStatus;
            }
        }
        if (m_usePatchList)
        {
            statusPatchList = (MOS_STATUS)m_osInterface->pfnVerifyPatchListSize(
                m_osInterface,
                requestedPatchListSizeOriginal);
        }

        statusCmdBuf = (MOS_STATUS)m_osInterface->pfnVerifyCommandBufferSize(
            m_osInterface,
            requestedSizeOriginal,
            0);

        if (statusPatchList == MOS_STATUS_SUCCESS && statusCmdBuf == MOS_STATUS_SUCCESS)
        {
            m_singleTaskPhaseSupportedInPak = false;
        }
        else
        {
            eStatus = MOS_STATUS_NO_SPACE;
        }
    }
    else
    {
        eStatus = MOS_STATUS_NO_SPACE;
    }

    return eStatus;
}

MOS_STATUS CodechalEncoderState::AddMediaVfeCmd(
    PMOS_COMMAND_BUFFER cmdBuffer,
    SendKernelCmdsParams *params)
{
    CODECHAL_ENCODE_CHK_NULL_RETURN(params);

    MHW_VFE_PARAMS vfeParams = {};
    vfeParams.pKernelState                      = params->pKernelState;
    vfeParams.eVfeSliceDisable                  = MHW_VFE_SLICE_ALL;
    vfeParams.Scoreboard.ScoreboardEnable       = m_useHwScoreboard;
    vfeParams.Scoreboard.ScoreboardType         = m_hwScoreboardType;
    vfeParams.dwMaximumNumberofThreads          = m_encodeVfeMaxThreads;

    if (!m_useHwScoreboard)
    {
        vfeParams.Scoreboard.ScoreboardMask = 0;
    }
    else if (params->bEnableCustomScoreBoard == true)
    {
        MOS_SecureMemcpy(&vfeParams.Scoreboard, sizeof(vfeParams.Scoreboard),
            params->pCustomScoreBoard, sizeof(*params->pCustomScoreBoard));
    }
    else if (params->bEnable45ZWalkingPattern == true)
    {
        vfeParams.Scoreboard.ScoreboardMask = 0x0F;
        vfeParams.Scoreboard.ScoreboardType = 1;

        // Scoreboard 0
        vfeParams.Scoreboard.ScoreboardDelta[0].x = 0;
        vfeParams.Scoreboard.ScoreboardDelta[0].y = 0xF;
        // Scoreboard 1
        vfeParams.Scoreboard.ScoreboardDelta[1].x = 0;
        vfeParams.Scoreboard.ScoreboardDelta[1].y = 0xE;
        // Scoreboard 2
        vfeParams.Scoreboard.ScoreboardDelta[2].x = 0xF;
        vfeParams.Scoreboard.ScoreboardDelta[2].y = 3;
        // Scoreboard 3
        vfeParams.Scoreboard.ScoreboardDelta[3].x = 0xF;
        vfeParams.Scoreboard.ScoreboardDelta[3].y = 1;
    }
    else
    {
        vfeParams.Scoreboard.ScoreboardMask       = 0xFF;

        // Scoreboard 0
        vfeParams.Scoreboard.ScoreboardDelta[0].x = 0xF;
        vfeParams.Scoreboard.ScoreboardDelta[0].y = 0;

        // Scoreboard 1
        vfeParams.Scoreboard.ScoreboardDelta[1].x = 0;
        vfeParams.Scoreboard.ScoreboardDelta[1].y = 0xF;

        // Scoreboard 2
        vfeParams.Scoreboard.ScoreboardDelta[2].x = 1;
        vfeParams.Scoreboard.ScoreboardDelta[2].y = 0xF;
        // Scoreboard 3
        vfeParams.Scoreboard.ScoreboardDelta[3].x = 0xF;
        vfeParams.Scoreboard.ScoreboardDelta[3].y = 0xF;
        // Scoreboard 4
        vfeParams.Scoreboard.ScoreboardDelta[4].x = 0xF;
        vfeParams.Scoreboard.ScoreboardDelta[4].y = 1;
        // Scoreboard 5
        vfeParams.Scoreboard.ScoreboardDelta[5].x = 0;
        vfeParams.Scoreboard.ScoreboardDelta[5].y = 0xE;
        // Scoreboard 6
        vfeParams.Scoreboard.ScoreboardDelta[6].x = 1;
        vfeParams.Scoreboard.ScoreboardDelta[6].y = 0xE;
        // Scoreboard 7
        vfeParams.Scoreboard.ScoreboardDelta[7].x = 0xF;
        vfeParams.Scoreboard.ScoreboardDelta[7].y = 0xE;
    }

    if (MEDIA_IS_WA(m_waTable, WaUseStallingScoreBoard))
        vfeParams.Scoreboard.ScoreboardType = 0;

    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_renderEngineInterface->AddMediaVfeCmd(cmdBuffer, &vfeParams));

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalEncoderState::SendGenericKernelCmds(
    PMOS_COMMAND_BUFFER cmdBuffer,
    SendKernelCmdsParams *params)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_CHK_NULL_RETURN(params->pKernelState);

    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hwInterface->GetDefaultSSEuSetting(params->EncFunctionType, m_setRequestedEUSlices, m_setRequestedSubSlices, m_setRequestedEUs));

    if (!m_singleTaskPhaseSupported || m_firstTaskInPhase)
    {
        bool requestFrameTracking = false;

        if (CodecHalUsesOnlyRenderEngine(m_codecFunction) && m_lastEncPhase)
        {
            // frame tracking tag is only added in the last command buffer header
            requestFrameTracking = m_singleTaskPhaseSupported ? m_firstTaskInPhase : m_lastTaskInPhase;
        }
        // Send command buffer header at the beginning (OS dependent)
        CODECHAL_ENCODE_CHK_STATUS_RETURN(SendPrologWithFrameTracking(cmdBuffer, requestFrameTracking));

        m_firstTaskInPhase = false;
    }

    CODECHAL_ENCODE_CHK_STATUS_RETURN(StartStatusReport(cmdBuffer, params->EncFunctionType));

    if (m_renderEngineInterface->GetL3CacheConfig()->bL3CachingEnabled)
    {
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_renderEngineInterface->SetL3Cache(cmdBuffer));
    }

    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_renderEngineInterface->EnablePreemption(cmdBuffer));

    // Add Pipeline select command
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_renderEngineInterface->AddPipelineSelectCmd(cmdBuffer, false));

    // Add State Base Addr command
    MHW_STATE_BASE_ADDR_PARAMS stateBaseAddrParams;
    MOS_ZeroMemory(&stateBaseAddrParams, sizeof(stateBaseAddrParams));
    // This bit will not be used in Driver ID but it will be used to determine if Render Target Flag has to be Clear or Set
    // Read this bit in pfnAddStateBaseAddrCmd and propagate it using ResourceParams via bRenderTarget
    stateBaseAddrParams.bDynamicStateRenderTarget = params->bDshInUse;

    MOS_RESOURCE* dsh = params->pKernelState->m_dshRegion.GetResource();
    CODECHAL_ENCODE_CHK_NULL_RETURN(dsh);
    MOS_RESOURCE* ish = params->pKernelState->m_ishRegion.GetResource();
    CODECHAL_ENCODE_CHK_NULL_RETURN(ish);
    stateBaseAddrParams.presDynamicState = dsh;
    stateBaseAddrParams.dwDynamicStateSize = params->pKernelState->m_dshRegion.GetHeapSize();
    stateBaseAddrParams.presInstructionBuffer = ish;
    stateBaseAddrParams.dwInstructionBufferSize = params->pKernelState->m_ishRegion.GetHeapSize();
    stateBaseAddrParams.mocs4InstructionCache = m_hwInterface->GetCacheabilitySettings()[MOS_CODEC_RESOURCE_USAGE_SURFACE_ELLC_LLC_L3].Value;

    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_renderEngineInterface->AddStateBaseAddrCmd(cmdBuffer, &stateBaseAddrParams));

    // Add Media VFE command
    CODECHAL_ENCODE_CHK_STATUS_RETURN(AddMediaVfeCmd(cmdBuffer, params));

    // Add Media Curbe Load command
    if (params->pKernelState->KernelParams.iCurbeLength)
    {
        MHW_CURBE_LOAD_PARAMS curbeLoadParams;
        MOS_ZeroMemory(&curbeLoadParams, sizeof(curbeLoadParams));
        curbeLoadParams.pKernelState = params->pKernelState;
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_renderEngineInterface->AddMediaCurbeLoadCmd(cmdBuffer, &curbeLoadParams));
    }

    MHW_ID_LOAD_PARAMS idLoadParams;
    MOS_ZeroMemory(&idLoadParams, sizeof(idLoadParams));
    idLoadParams.pKernelState = params->pKernelState;
    idLoadParams.dwNumKernelsLoaded = 1;
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_renderEngineInterface->AddMediaIDLoadCmd(cmdBuffer, &idLoadParams));

    return eStatus;
}

// Refer to layout of EncodeBRCPAKStatistics_g7
MOS_STATUS CodechalEncoderState::ReadBrcPakStatistics(
    PMOS_COMMAND_BUFFER cmdBuffer,
    EncodeReadBrcPakStatsParams* params)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    CODECHAL_ENCODE_CHK_NULL_RETURN(cmdBuffer);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->presBrcPakStatisticBuffer);
    CODECHAL_ENCODE_CHK_NULL_RETURN(params->presStatusBuffer);

    CODECHAL_ENCODE_CHK_COND_RETURN((m_vdboxIndex > m_hwInterface->GetMfxInterface()->GetMaxVdboxIndex()),"ERROR - vdbox index exceed the maximum");
    MmioRegistersMfx* mmioRegisters = m_hwInterface->SelectVdboxAndGetMmioRegister(m_vdboxIndex, cmdBuffer);

    MHW_MI_STORE_REGISTER_MEM_PARAMS miStoreRegMemParams;
    MOS_ZeroMemory(&miStoreRegMemParams, sizeof(miStoreRegMemParams));

    miStoreRegMemParams.presStoreBuffer = params->presBrcPakStatisticBuffer;
    miStoreRegMemParams.dwOffset        = 0;
    miStoreRegMemParams.dwRegister      = mmioRegisters->mfcBitstreamBytecountFrameRegOffset;
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiStoreRegisterMemCmd(cmdBuffer, &miStoreRegMemParams));

    miStoreRegMemParams.presStoreBuffer = params->presBrcPakStatisticBuffer;
    miStoreRegMemParams.dwOffset        = sizeof(uint32_t);
    miStoreRegMemParams.dwRegister      = mmioRegisters->mfcBitstreamBytecountSliceRegOffset;
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiStoreRegisterMemCmd(cmdBuffer, &miStoreRegMemParams));

    MHW_MI_STORE_DATA_PARAMS storeDataParams;
    storeDataParams.pOsResource         = params->presBrcPakStatisticBuffer;
    storeDataParams.dwResourceOffset    = sizeof(uint32_t) * 2;
    storeDataParams.dwValue             = params->ucPass + 1;
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiStoreDataImmCmd(cmdBuffer, &storeDataParams));

    storeDataParams.pOsResource         = params->presStatusBuffer;
    storeDataParams.dwResourceOffset    = params->dwStatusBufNumPassesOffset;
    storeDataParams.dwValue             = params->ucPass + 1;
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiStoreDataImmCmd(cmdBuffer, &storeDataParams));

    miStoreRegMemParams.presStoreBuffer = params->presBrcPakStatisticBuffer;
    miStoreRegMemParams.dwOffset        = sizeof(uint32_t) * (4 + params->ucPass);
    miStoreRegMemParams.dwRegister      = mmioRegisters->mfcImageStatusCtrlRegOffset;
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiStoreRegisterMemCmd(cmdBuffer, &miStoreRegMemParams));

    return eStatus;
}

//------------------------------------------------------------------------------
//| Purpose:    Retrieves the MFC image eStatus information
//| Return:     N/A
//------------------------------------------------------------------------------
MOS_STATUS CodechalEncoderState::ReadImageStatus(
    PMOS_COMMAND_BUFFER cmdBuffer)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    CODECHAL_ENCODE_CHK_NULL_RETURN(cmdBuffer);

    CODECHAL_ENCODE_CHK_COND_RETURN((m_vdboxIndex > m_hwInterface->GetMfxInterface()->GetMaxVdboxIndex()),"ERROR - vdbox index exceed the maximum");
    MmioRegistersMfx* mmioRegisters = m_hwInterface->SelectVdboxAndGetMmioRegister(m_vdboxIndex, cmdBuffer);

    EncodeStatusBuffer*  encodeStatusBuf    = &m_encodeStatusBuf;

    uint32_t baseOffset =
        (encodeStatusBuf->wCurrIndex * m_encodeStatusBuf.dwReportSize) +
        sizeof(uint32_t) * 2;  // pEncodeStatus is offset by 2 DWs in the resource

    MHW_MI_STORE_REGISTER_MEM_PARAMS miStoreRegMemParams;
    MOS_ZeroMemory(&miStoreRegMemParams, sizeof(miStoreRegMemParams));

    miStoreRegMemParams.presStoreBuffer = &encodeStatusBuf->resStatusBuffer;
    miStoreRegMemParams.dwOffset        = baseOffset + encodeStatusBuf->dwImageStatusMaskOffset;
    miStoreRegMemParams.dwRegister      = mmioRegisters->mfcImageStatusMaskRegOffset;
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiStoreRegisterMemCmd(cmdBuffer, &miStoreRegMemParams));

    miStoreRegMemParams.presStoreBuffer = &encodeStatusBuf->resStatusBuffer;
    miStoreRegMemParams.dwOffset        = baseOffset + encodeStatusBuf->dwImageStatusCtrlOffset;
    miStoreRegMemParams.dwRegister      = mmioRegisters->mfcImageStatusCtrlRegOffset;
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiStoreRegisterMemCmd(cmdBuffer, &miStoreRegMemParams));

    // VDEnc dynamic slice overflow semaphore, DW0 is SW programmed mask(MFX_IMAGE_MASK does not support), DW1 is MFX_IMAGE_STATUS_CONTROL
    if (m_vdencBrcEnabled)
    {
        MHW_VDBOX_PIPE_MODE_SELECT_PARAMS pipeModeSelectParams;

        // Added for VDEnc slice overflow bit in MFC_IMAGE_STATUS_CONTROL
        // The bit is connected on the non-AVC encoder side of MMIO register.
        // Need a dummy MFX_PIPE_MODE_SELECT to decoder and read this register.
        if (m_waReadVDEncOverflowStatus)
        {
            pipeModeSelectParams = {};
            pipeModeSelectParams.Mode               = CODECHAL_DECODE_MODE_AVCVLD;
            m_hwInterface->GetMfxInterface()->SetDecodeInUse(true);
            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hwInterface->GetMfxInterface()->AddMfxPipeModeSelectCmd(cmdBuffer, &pipeModeSelectParams));
        }

        // Store MFC_IMAGE_STATUS_CONTROL MMIO to DMEM for HuC next BRC pass of current frame and first pass of next frame.
        for (int i = 0; i < 2; i++)
        {
            if (m_resVdencBrcUpdateDmemBufferPtr[i])
            {
                miStoreRegMemParams.presStoreBuffer    = m_resVdencBrcUpdateDmemBufferPtr[i];
                miStoreRegMemParams.dwOffset           = 7 * sizeof(uint32_t); // offset of SliceSizeViolation in HUC_BRC_UPDATE_DMEM
                miStoreRegMemParams.dwRegister         = mmioRegisters->mfcImageStatusCtrlRegOffset;
                CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiStoreRegisterMemCmd(cmdBuffer, &miStoreRegMemParams));
            }
        }

        // Restore MFX_PIPE_MODE_SELECT to encode mode
        if (m_waReadVDEncOverflowStatus)
        {
            pipeModeSelectParams = {};
            pipeModeSelectParams.Mode               = m_mode;
            pipeModeSelectParams.bVdencEnabled      = true;
            m_hwInterface->GetMfxInterface()->SetDecodeInUse(false);
            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hwInterface->GetMfxInterface()->AddMfxPipeModeSelectCmd(cmdBuffer, &pipeModeSelectParams));
        }
    }

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

    return eStatus;
}

//------------------------------------------------------------------------------
//| Purpose:    Retrieves the MFC registers and stores them in the eStatus report
//| Return:     N/A
//------------------------------------------------------------------------------
MOS_STATUS CodechalEncoderState::ReadMfcStatus(
    PMOS_COMMAND_BUFFER cmdBuffer)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    CODECHAL_ENCODE_CHK_NULL_RETURN(cmdBuffer);

    CODECHAL_ENCODE_CHK_COND_RETURN((m_vdboxIndex > m_hwInterface->GetMfxInterface()->GetMaxVdboxIndex()),"ERROR - vdbox index exceed the maximum");
    MmioRegistersMfx* mmioRegisters = m_hwInterface->SelectVdboxAndGetMmioRegister(m_vdboxIndex, cmdBuffer);

    EncodeStatusBuffer* encodeStatusBuf    = &m_encodeStatusBuf;

    uint32_t baseOffset =
        (encodeStatusBuf->wCurrIndex * m_encodeStatusBuf.dwReportSize) +
        sizeof(uint32_t) * 2;  // pEncodeStatus is offset by 2 DWs in the resource

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

    MHW_MI_STORE_REGISTER_MEM_PARAMS miStoreRegMemParams;
    MOS_ZeroMemory(&miStoreRegMemParams, sizeof(miStoreRegMemParams));

    miStoreRegMemParams.presStoreBuffer = &encodeStatusBuf->resStatusBuffer;
    miStoreRegMemParams.dwOffset        = baseOffset + encodeStatusBuf->dwBSByteCountOffset;
    miStoreRegMemParams.dwRegister      = mmioRegisters->mfcBitstreamBytecountFrameRegOffset;
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiStoreRegisterMemCmd(cmdBuffer, &miStoreRegMemParams));

    miStoreRegMemParams.presStoreBuffer = &encodeStatusBuf->resStatusBuffer;
    miStoreRegMemParams.dwOffset        = baseOffset + encodeStatusBuf->dwBSSEBitCountOffset;
    miStoreRegMemParams.dwRegister      = mmioRegisters->mfcBitstreamSeBitcountFrameRegOffset;
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiStoreRegisterMemCmd(cmdBuffer, &miStoreRegMemParams));

    miStoreRegMemParams.presStoreBuffer = &encodeStatusBuf->resStatusBuffer;
    miStoreRegMemParams.dwOffset        = baseOffset + encodeStatusBuf->dwQpStatusCountOffset;
    miStoreRegMemParams.dwRegister      = mmioRegisters->mfcQPStatusCountOffset;
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiStoreRegisterMemCmd(cmdBuffer, &miStoreRegMemParams));

    if (mmioRegisters->mfcAvcNumSlicesRegOffset > 0)
    {
        //read MFC_AVC_NUM_SLICES register to status report
        miStoreRegMemParams.presStoreBuffer = &encodeStatusBuf->resStatusBuffer;
        miStoreRegMemParams.dwOffset        = baseOffset + encodeStatusBuf->dwNumSlicesOffset;
        miStoreRegMemParams.dwRegister      = mmioRegisters->mfcAvcNumSlicesRegOffset;
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiStoreRegisterMemCmd(cmdBuffer, &miStoreRegMemParams));
    }

    if (m_vdencBrcEnabled)
    {
        // Store PAK FrameSize MMIO to DMEM for HuC next BRC pass of current frame and first pass of next frame.
        for (int i = 0; i < 2; i++)
        {
            if (m_resVdencBrcUpdateDmemBufferPtr[i])
            {
                miStoreRegMemParams.presStoreBuffer = m_resVdencBrcUpdateDmemBufferPtr[i];
                miStoreRegMemParams.dwOffset        = 5 * sizeof(uint32_t);
                miStoreRegMemParams.dwRegister      = mmioRegisters->mfcBitstreamBytecountFrameRegOffset;
                CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiStoreRegisterMemCmd(cmdBuffer, &miStoreRegMemParams));

                if (m_vdencBrcNumOfSliceOffset)
                {
                    miStoreRegMemParams.presStoreBuffer = m_resVdencBrcUpdateDmemBufferPtr[i];
                    miStoreRegMemParams.dwOffset        = m_vdencBrcNumOfSliceOffset;
                    miStoreRegMemParams.dwRegister      = mmioRegisters->mfcAvcNumSlicesRegOffset;
                    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiStoreRegisterMemCmd(cmdBuffer, &miStoreRegMemParams));
                }
            }
        }
    }

    CODECHAL_ENCODE_CHK_STATUS_RETURN(ReadImageStatus(cmdBuffer));

    return eStatus;
}

//------------------------------------------------------------------------------
//| Purpose:    Retrieves the MFC registers and stores them in the eStatus report
//| Return:     N/A
//------------------------------------------------------------------------------
MOS_STATUS CodechalEncoderState::SetStatusReportParams(
    PCODEC_REF_LIST currRefList)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    EncodeStatusBuffer*  encodeStatusBuf = nullptr;
    if ((m_codecFunction == CODECHAL_FUNCTION_ENC)         ||
        (m_codecFunction == CODECHAL_FUNCTION_FEI_PRE_ENC) ||
        (m_codecFunction == CODECHAL_FUNCTION_FEI_ENC)     ||
        (m_codecFunction == CODECHAL_FUNCTION_HYBRIDPAK))
    {
        encodeStatusBuf = &m_encodeStatusBufRcs;
    }
    else
    {
        encodeStatusBuf = &m_encodeStatusBuf;
    }

    EncodeStatus* encodeStatus =
        (EncodeStatus*)(encodeStatusBuf->pEncodeStatus +
        encodeStatusBuf->wCurrIndex * encodeStatusBuf->dwReportSize);

    EncodeStatusReport* encodeStatusReport = &encodeStatus->encodeStatusReport;

    encodeStatus->dwStoredData             = m_storeData;
    encodeStatusReport->StatusReportNumber = m_statusReportFeedbackNumber;
    encodeStatusReport->CurrOriginalPic    = m_currOriginalPic;
    encodeStatus->wPictureCodingType       = m_pictureCodingType;
    switch (m_codecFunction)
    {
    case CODECHAL_FUNCTION_ENC:
        encodeStatusReport->Func       = CODECHAL_ENCODE_ENC_ID;
        break;
    case CODECHAL_FUNCTION_PAK:
        encodeStatusReport->Func       = CODECHAL_ENCODE_PAK_ID;
        break;
    case CODECHAL_FUNCTION_ENC_PAK:
    case CODECHAL_FUNCTION_ENC_VDENC_PAK:
        encodeStatusReport->Func       = CODECHAL_ENCODE_ENC_PAK_ID;
        break;
    case CODECHAL_FUNCTION_FEI_PRE_ENC:
        encodeStatusReport->Func       = CODECHAL_ENCODE_FEI_PRE_ENC_ID;
        break;
    case CODECHAL_FUNCTION_FEI_ENC:
        encodeStatusReport->Func       = CODECHAL_ENCODE_FEI_ENC_ID;
        break;
    case CODECHAL_FUNCTION_FEI_PAK:
        encodeStatusReport->Func       = CODECHAL_ENCODE_FEI_PAK_ID;
        break;
    case CODECHAL_FUNCTION_FEI_ENC_PAK:
        encodeStatusReport->Func       = CODECHAL_ENCODE_FEI_ENC_PAK_ID;
        break;
    case CODECHAL_FUNCTION_HYBRIDPAK:
        encodeStatusReport->Func       = CODECHAL_ENCODE_ENC_ID; /* Only the render engine(EU) is used, MFX is not used */
        break;
    default:
        break;
    }
    encodeStatusReport->pCurrRefList       = m_currRefList;
    encodeStatusReport->NumberTilesInFrame = m_numberTilesInFrame;
    encodeStatusReport->UsedVdBoxNumber    = m_numUsedVdbox;

    return eStatus;
}

//------------------------------------------------------------------------------
//| Purpose:    Set each of status report buffer to completed status (only render context)
//| Return:     N/A
//------------------------------------------------------------------------------
MOS_STATUS CodechalEncoderState::InitStatusReport()
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    EncodeStatusBuffer* encodeStatusBuf = &m_encodeStatusBuf;
    CODECHAL_ENCODE_CHK_NULL_RETURN(encodeStatusBuf);

    EncodeStatus* encodeStatus = (EncodeStatus*)(encodeStatusBuf->pEncodeStatus + encodeStatusBuf->wCurrIndex * encodeStatusBuf->dwReportSize);
    CODECHAL_ENCODE_CHK_NULL_RETURN(encodeStatus);

    for (auto i = 0; i < CODECHAL_NUM_MEDIA_STATES; i += 1)
    {
        encodeStatus->qwStoredDataEnc[i].dwStoredData = CODECHAL_STATUS_QUERY_END_FLAG;
    }

    if (m_encEnabled)
    {
        EncodeStatusBuffer* encodeStatusBufRcs = &m_encodeStatusBufRcs;
        CODECHAL_ENCODE_CHK_NULL_RETURN(encodeStatusBufRcs);

        encodeStatus = (EncodeStatus*)(encodeStatusBufRcs->pEncodeStatus + encodeStatusBufRcs->wCurrIndex * encodeStatusBufRcs->dwReportSize);
        CODECHAL_ENCODE_CHK_NULL_RETURN(encodeStatus);

        for (auto i = 0; i < CODECHAL_NUM_MEDIA_STATES; i += 1)
        {
            encodeStatus->qwStoredDataEnc[i].dwStoredData = CODECHAL_STATUS_QUERY_END_FLAG;
        }
    }

    return eStatus;
}

//------------------------------------------------------------------------------
//| Purpose:    Indicates to the driver that the batch buffer has started processing
//| Return:     N/A
//------------------------------------------------------------------------------
MOS_STATUS CodechalEncoderState::StartStatusReport(
    PMOS_COMMAND_BUFFER cmdBuffer,
    CODECHAL_MEDIA_STATE_TYPE encFunctionType)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    CODECHAL_ENCODE_CHK_NULL_RETURN(cmdBuffer);

    EncodeStatusBuffer* encodeStatusBuf    = &m_encodeStatusBuf;
    EncodeStatusBuffer* encodeStatusBufRcs = &m_encodeStatusBufRcs;

    if (m_osInterface->pfnGetGpuContext(m_osInterface) == m_renderContext)
    {
        uint32_t offset =
            (encodeStatusBufRcs->wCurrIndex * m_encodeStatusBufRcs.dwReportSize) +
            encodeStatusBufRcs->dwStoreDataOffset + 8                                    +   // VME stored data offset is 2nd
            sizeof(uint32_t) * 2 * encFunctionType                                           +   // Each VME stored data is 1 QW
            sizeof(uint32_t) * 2;                                                                // encodeStatus is offset by 2 DWs in the resource

        MHW_PIPE_CONTROL_PARAMS pipeControlParams;
        MOS_ZeroMemory(&pipeControlParams, sizeof(pipeControlParams));
        pipeControlParams.presDest                  = &encodeStatusBufRcs->resStatusBuffer;
        pipeControlParams.dwPostSyncOp              = MHW_FLUSH_WRITE_IMMEDIATE_DATA;
        pipeControlParams.dwResourceOffset          = offset;
        pipeControlParams.dwDataDW1                 = CODECHAL_STATUS_QUERY_START_FLAG;
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddPipeControl(
            cmdBuffer,
            nullptr,
            &pipeControlParams));
    }

    if (m_osInterface->pfnGetGpuContext(m_osInterface) == m_videoContext)
    {
        uint32_t offset =
            (encodeStatusBuf->wCurrIndex * m_encodeStatusBuf.dwReportSize) +
            encodeStatusBuf->dwStoreDataOffset +    // MFX stored data offset is 1st, so no additional offset is needed
            sizeof(uint32_t) * 2;                   // encodeStatus is offset by 2 DWs in the resource

        MHW_MI_STORE_DATA_PARAMS storeDataParams;
        storeDataParams.pOsResource      = &encodeStatusBuf->resStatusBuffer;
        storeDataParams.dwResourceOffset = offset;
        storeDataParams.dwValue          = CODECHAL_STATUS_QUERY_START_FLAG;

        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiStoreDataImmCmd(
            cmdBuffer,
            &storeDataParams));

        if (m_osInterface->osCpInterface->IsCpEnabled() && m_hwInterface->GetCpInterface()->IsHWCounterAutoIncrementEnforced(m_osInterface) && m_skipFrameBasedHWCounterRead == false )
        {
            uint32_t writeOffset = sizeof(HwCounter) * CODECHAL_ENCODE_STATUS_NUM;

            CODECHAL_ENCODE_CHK_NULL_RETURN(m_hwInterface->GetCpInterface());

            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hwInterface->GetCpInterface()->SetMfxInlineStatusRead(
                m_osInterface,
                cmdBuffer,
                &m_resHwCount,
                encodeStatusBuf->wCurrIndex,
                writeOffset));
        }
    }

    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_perfProfiler->AddPerfCollectStartCmd((void*)this, m_osInterface, m_miInterface, cmdBuffer));
    
    return eStatus;
}

//------------------------------------------------------------------------------
//| Purpose:    Indicates to the driver that the batch buffer has completed processing
//| Return:     N/A
//------------------------------------------------------------------------------
MOS_STATUS CodechalEncoderState::EndStatusReport(
    PMOS_COMMAND_BUFFER cmdBuffer,
    CODECHAL_MEDIA_STATE_TYPE encFunctionType)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    CODECHAL_ENCODE_CHK_NULL_RETURN(cmdBuffer);

    // Update the tag in GPU Sync eStatus buffer (H/W Tag) to match the current S/W tag if applicable
    if (m_frameTrackingEnabled && m_osInterface->bTagResourceSync)
    {
        MOS_SYNC_PARAMS syncParams = g_cInitSyncParams;
        bool writeResourceSyncTag = false;

        if (m_osInterface->pfnGetGpuContext(m_osInterface) == m_renderContext)
        {
            syncParams.GpuContext = m_renderContext;

            // Enc only and VDEnc SHME requires render engine GPU tag
            if (CodecHalUsesOnlyRenderEngine(m_codecFunction) ||
                (m_vdencEnabled && m_16xMeSupported))
            {
                writeResourceSyncTag = m_lastEncPhase && m_lastTaskInPhase;
            }
        }
        else if (m_osInterface->pfnGetGpuContext(m_osInterface) == m_videoContext)
        {
            syncParams.GpuContext = m_videoContext;
            writeResourceSyncTag = m_lastTaskInPhase;
        }

        if (writeResourceSyncTag)
        {
            if (!m_firstField || CodecHal_PictureIsFrame(m_currOriginalPic))
            {
                CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hwInterface->WriteSyncTagToResource(cmdBuffer, &syncParams));
            }
        }
    }

    MHW_MI_STORE_DATA_PARAMS storeDataParams;
    uint32_t offset = 0;
    if (m_osInterface->pfnGetGpuContext(m_osInterface) == m_renderContext)
    {
        // Flush the write cache for ENC output
        MHW_PIPE_CONTROL_PARAMS pipeControlParams;
        MOS_ZeroMemory(&pipeControlParams, sizeof(pipeControlParams));
        pipeControlParams.dwFlushMode  = MHW_FLUSH_WRITE_CACHE;
        pipeControlParams.bGenericMediaStateClear = true;
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddPipeControl(cmdBuffer, nullptr, &pipeControlParams));

        if (MEDIA_IS_WA(m_waTable, WaSendDummyVFEafterPipelineSelect))
        {
            MHW_VFE_PARAMS vfeStateParams = {};
            vfeStateParams.dwNumberofURBEntries = 1;
            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_renderEngineInterface->AddMediaVfeCmd(cmdBuffer, &vfeStateParams));
        }

        offset =
                (m_encodeStatusBufRcs.wCurrIndex * m_encodeStatusBufRcs.dwReportSize) +
                m_encodeStatusBufRcs.dwStoreDataOffset + 8 +   // VME stored data offset is 2nd
                sizeof(uint32_t) * 2 * encFunctionType     +   // Each VME stored data is 1 QW
                sizeof(uint32_t) * 2;                          // encodeStatus is offset by 2 DWs in the resource
        storeDataParams.pOsResource  = &m_encodeStatusBufRcs.resStatusBuffer;
    }
    else if (m_osInterface->pfnGetGpuContext(m_osInterface) == m_videoContext)
    {
        offset =
            m_encodeStatusBuf.wCurrIndex * m_encodeStatusBuf.dwReportSize +
            m_encodeStatusBuf.dwStoreDataOffset +   // MFX stored data offset is 1st, so no additional offset is needed
            sizeof(uint32_t) * 2;                   // encodeStatus is offset by 2 DWs in the resource
        storeDataParams.pOsResource  = &m_encodeStatusBuf.resStatusBuffer;
    }

    storeDataParams.dwResourceOffset = offset;
    storeDataParams.dwValue          = CODECHAL_STATUS_QUERY_END_FLAG;
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiStoreDataImmCmd(
        cmdBuffer,
        &storeDataParams));

    if (encFunctionType == CODECHAL_NUM_MEDIA_STATES && m_inlineEncodeStatusUpdate)
    {
        if (m_currPass < m_numPasses)
        {
            if(m_vdencBrcEnabled)
            {
                //delay to check at the beginning of next pass util huc status updated;
            }
            else
            {
                // inc m_storeData conditionaly
                UpdateEncodeStatus(cmdBuffer, false);
            }
        }
        else
        {
            // inc m_storeData forcely
            UpdateEncodeStatus(cmdBuffer, true);
        }
    }

    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_perfProfiler->AddPerfCollectEndCmd((void*)this, m_osInterface, m_miInterface, cmdBuffer));
    
    return eStatus;
}

//!
//! \brief    Update m_storeData in offset 0 of statusReport.
//! \details  Add conditonal encode status report to avoid of extra small batch buffer
//!           to avoid of extra context switch interrupt. if ImageStatusRegister show
//!           encoding completion, update the m_storeData, otherwise continue.
//!                   n0                n1                n2                n3
//!           +-------+--------+--------+--------+--------+--------+--------+--------+
//!           |   0       0    |    0            |  val/0   1/0    |    0       1    |
//!           +-------+--------+--------+--------+--------+--------+--------+--------+
//!              low     high      low     high      low     high     low     high
//!
//!           if(m_forceOperation==true)
//!              step-1:    m_storeData = m_storeData + 1                              // ADD directly
//!           else
//!              step-1:    n2_lo = ImageStatusCtrl & dwImageStatusMask                // AND
//!              step-2:    n2_lo = (n2_lo == 0) ? 0 : n2_lo                           // uint32_t CMP
//!              step-3:    n2_lo:n2_hi = (n2_lo:n2_hi == 0:1) ? 0:0 : n2_lo:n2_hi     // uint64_t CMP
//!              step-4:    n2_hi = n2_hi ^ n3_hi                                      // XOR
//!              step-5:    m_storeData = m_storeData + n2_hi                          // ADD conditionaly
//!
//! \param    [in] cmdBuffer
//!           Command buffer
//! \param    [in] forceOperation
//!           whether add m_storeData directly
//! \return   MOS_STATUS
//!           MOS_STATUS_SUCCESS if success, else fail reason
//!
MOS_STATUS CodechalEncoderState::UpdateEncodeStatus(
    PMOS_COMMAND_BUFFER cmdBuffer,
    bool                forceOperation)
{
    MmioRegistersMfx                                *mmioRegisters;
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_CHK_NULL_RETURN(cmdBuffer);

    CODECHAL_ENCODE_CHK_COND_RETURN((m_vdboxIndex > m_hwInterface->GetMfxInterface()->GetMaxVdboxIndex()),"ERROR - vdbox index exceed the maximum");
    mmioRegisters = m_hwInterface->SelectVdboxAndGetMmioRegister(m_vdboxIndex, cmdBuffer);

    // Get the right offset of EncodeStatusUpdate Operand scratch buffer
    uint32_t baseOffset        = m_atomicScratchBuf.dwOperandSetSize * m_atomicScratchBuf.wEncodeUpdateIndex;
    uint32_t zeroValueOffset   = baseOffset;
    uint32_t operand1Offset    = baseOffset + m_atomicScratchBuf.dwOperand1Offset;
    uint32_t operand2Offset    = baseOffset + m_atomicScratchBuf.dwOperand2Offset;
    uint32_t operand3Offset    = baseOffset + m_atomicScratchBuf.dwOperand3Offset;

    // Forcely ADD m_storeData, always happened in last pass.
    if(forceOperation)
    {
        // Make Flush DW call to make sure all previous work is done
        MHW_MI_FLUSH_DW_PARAMS flushDwParams;
        MOS_ZeroMemory(&flushDwParams , sizeof(flushDwParams));
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiFlushDwCmd(
            cmdBuffer,
            &flushDwParams));

        // n2_hi = 0x1
        MHW_MI_STORE_DATA_PARAMS storeDataParams;
        MOS_ZeroMemory(&storeDataParams, sizeof(storeDataParams));
        storeDataParams.pOsResource = &(m_atomicScratchBuf.resAtomicScratchBuffer);
        storeDataParams.dwResourceOffset =  operand2Offset + sizeof(uint32_t) ;
        storeDataParams.dwValue          = 0x1;
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiStoreDataImmCmd(
            cmdBuffer,
            &storeDataParams));

        // VCS_GPR0_Lo = n2_hi = 0x1
        MHW_MI_STORE_REGISTER_MEM_PARAMS registerMemParams;
        MOS_ZeroMemory(&registerMemParams, sizeof(registerMemParams));
        registerMemParams.presStoreBuffer = &(m_atomicScratchBuf.resAtomicScratchBuffer);
        registerMemParams.dwOffset = operand2Offset + sizeof(uint32_t) ;
        registerMemParams.dwRegister = mmioRegisters->generalPurposeRegister0LoOffset; // VCS_GPR0_Lo
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiLoadRegisterMemCmd(
            cmdBuffer,
            &registerMemParams));

        // Make Flush DW call to make sure all previous work is done
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiFlushDwCmd(
            cmdBuffer,
            &flushDwParams));

        // m_storeData = m_storeData + VCS_GPR0_Lo = m_storeData + 1
        MHW_MI_ATOMIC_PARAMS atomicParams;
        MOS_ZeroMemory(&atomicParams, sizeof(atomicParams));
        atomicParams.pOsResource =&m_encodeStatusBuf.resStatusBuffer;
        atomicParams.dwResourceOffset =  0;
        atomicParams.dwDataSize = sizeof(uint32_t);
        atomicParams.Operation = MHW_MI_ATOMIC_ADD;
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiAtomicCmd(
            cmdBuffer,
            &atomicParams));

        // Make Flush DW call to make sure all previous work is done
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiFlushDwCmd(
            cmdBuffer,
            &flushDwParams));
        return MOS_STATUS_SUCCESS;
    }
    else
    {
        // Make Flush DW call to make sure all previous work is done
        MHW_MI_FLUSH_DW_PARAMS flushDwParams;
        MOS_ZeroMemory(&flushDwParams , sizeof(flushDwParams));
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiFlushDwCmd(
            cmdBuffer,
            &flushDwParams));

        // n1_lo = 0x00
        MHW_MI_STORE_DATA_PARAMS storeDataParams;
        MOS_ZeroMemory(&storeDataParams, sizeof(storeDataParams));
        storeDataParams.pOsResource = &(m_atomicScratchBuf.resAtomicScratchBuffer);
        storeDataParams.dwResourceOffset = operand1Offset;
        storeDataParams.dwValue          = 0x00;
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiStoreDataImmCmd(
            cmdBuffer,
            &storeDataParams));

        // n2_lo = dwImageStatusMask
        MHW_MI_COPY_MEM_MEM_PARAMS copyMemMemParams;
        MOS_ZeroMemory(&copyMemMemParams , sizeof(copyMemMemParams));
        if(!m_vdencBrcEnabled)
        {
            copyMemMemParams.presSrc     = &m_encodeStatusBuf.resStatusBuffer;
            copyMemMemParams.dwSrcOffset =    (m_encodeStatusBuf.wCurrIndex * m_encodeStatusBuf.dwReportSize) +
                        m_encodeStatusBuf.dwImageStatusMaskOffset                               +
                        (sizeof(uint32_t) * 2);
        }
        else
        {
            copyMemMemParams.presSrc     = &m_resPakMmioBuffer;
            copyMemMemParams.dwSrcOffset = (sizeof(uint32_t) * 1);
        }
        copyMemMemParams.presDst     = &m_atomicScratchBuf.resAtomicScratchBuffer;
        copyMemMemParams.dwDstOffset = operand2Offset;
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiCopyMemMemCmd(
            cmdBuffer,
            &copyMemMemParams));

        // VCS_GPR0_Lo = ImageStatusCtrl
        MHW_MI_STORE_REGISTER_MEM_PARAMS registerMemParams;
        MOS_ZeroMemory(&registerMemParams, sizeof(registerMemParams));
        if(!m_vdencBrcEnabled)
        {
            registerMemParams.presStoreBuffer = &m_encodeStatusBuf.resStatusBuffer;
            registerMemParams.dwOffset =  (m_encodeStatusBuf.wCurrIndex * m_encodeStatusBuf.dwReportSize) +
                        m_encodeStatusBuf.dwImageStatusMaskOffset                               +
                        (sizeof(uint32_t) * 2) + sizeof(uint32_t);
        }
        else
        {
            registerMemParams.presStoreBuffer = &m_resPakMmioBuffer;
            registerMemParams.dwOffset =  (sizeof(uint32_t) * 0);
        }
        registerMemParams.dwRegister = mmioRegisters->generalPurposeRegister0LoOffset; // VCS_GPR0_Lo
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiLoadRegisterMemCmd(
            cmdBuffer,
            &registerMemParams));

        // Reset GPR4_Lo
        MOS_ZeroMemory(&registerMemParams, sizeof(registerMemParams));
        registerMemParams.presStoreBuffer = &(m_atomicScratchBuf.resAtomicScratchBuffer);
        registerMemParams.dwOffset        = zeroValueOffset; //Offset 0, has value of 0.
        registerMemParams.dwRegister      = mmioRegisters->generalPurposeRegister4LoOffset; // VCS_GPR4
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiLoadRegisterMemCmd(
            cmdBuffer,
            &registerMemParams));

        // Make Flush DW call to make sure all previous work is done
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiFlushDwCmd(
            cmdBuffer,
            &flushDwParams));

        // step-1: n2_lo = n2_lo & VCS_GPR0_Lo = dwImageStatusMask & ImageStatusCtrl
        MHW_MI_ATOMIC_PARAMS atomicParams;
        MOS_ZeroMemory(&atomicParams, sizeof(atomicParams));
        atomicParams.pOsResource =  &m_atomicScratchBuf.resAtomicScratchBuffer;
        atomicParams.dwResourceOffset = operand2Offset;
        atomicParams.dwDataSize = sizeof(uint32_t);
        atomicParams.Operation = MHW_MI_ATOMIC_AND;
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiAtomicCmd(
            cmdBuffer,
            &atomicParams));

        // n3_lo = 0
        MOS_ZeroMemory(&storeDataParams, sizeof(storeDataParams));
        storeDataParams.pOsResource = &(m_atomicScratchBuf.resAtomicScratchBuffer);
        storeDataParams.dwResourceOffset = operand3Offset;
        storeDataParams.dwValue          = 0;
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiStoreDataImmCmd(
            cmdBuffer,
            &storeDataParams));

        // Make Flush DW call to make sure all previous work is done
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiFlushDwCmd(
            cmdBuffer,
            &flushDwParams));

        // GPR0_lo = n1_lo = 0
        MOS_ZeroMemory(&registerMemParams, sizeof(registerMemParams));
        registerMemParams.presStoreBuffer = &(m_atomicScratchBuf.resAtomicScratchBuffer);
        registerMemParams.dwOffset        = operand1Offset;
        registerMemParams.dwRegister      = mmioRegisters->generalPurposeRegister0LoOffset; // VCS_GPR0
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiLoadRegisterMemCmd(
            cmdBuffer,
            &registerMemParams));

        // Reset GPR4_Lo
        MOS_ZeroMemory(&registerMemParams, sizeof(registerMemParams));
        registerMemParams.presStoreBuffer = &(m_atomicScratchBuf.resAtomicScratchBuffer);
        registerMemParams.dwOffset        = zeroValueOffset; //Offset 0, has value of 0.
        registerMemParams.dwRegister      = mmioRegisters->generalPurposeRegister4LoOffset; // VCS_GPR4
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiLoadRegisterMemCmd(
            cmdBuffer,
            &registerMemParams));

        // Make Flush DW call to make sure all previous work is done
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiFlushDwCmd(
            cmdBuffer,
            &flushDwParams));

        // step-2: n2_lo == n1_lo ? 0 : n2_lo
        // compare n1 vs n2. i.e. GRP0 vs. memory of operand2
        MOS_ZeroMemory(&atomicParams, sizeof(atomicParams));
        atomicParams.pOsResource = &(m_atomicScratchBuf.resAtomicScratchBuffer);
        atomicParams.dwResourceOffset = operand2Offset;
        atomicParams.dwDataSize = sizeof(uint32_t);
        atomicParams.Operation = MHW_MI_ATOMIC_CMP;
        atomicParams.bReturnData = true;

        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiAtomicCmd(
            cmdBuffer,
            &atomicParams));

        // n2_hi = 1
        MOS_ZeroMemory(&storeDataParams, sizeof(storeDataParams));
        storeDataParams.pOsResource =&(m_atomicScratchBuf.resAtomicScratchBuffer);
        storeDataParams.dwResourceOffset = operand2Offset + sizeof(uint32_t);
        storeDataParams.dwValue          = 1;
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiStoreDataImmCmd(
            cmdBuffer,
            &storeDataParams));

        // n3_hi = 1
        MOS_ZeroMemory(&storeDataParams, sizeof(storeDataParams));
        storeDataParams.pOsResource =&(m_atomicScratchBuf.resAtomicScratchBuffer);
        storeDataParams.dwResourceOffset = operand3Offset + sizeof(uint32_t);
        storeDataParams.dwValue          = 1;
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiStoreDataImmCmd(
            cmdBuffer,
            &storeDataParams));

        // VCS_GPR0_Lo = n3_lo = 0
        MOS_ZeroMemory(&registerMemParams, sizeof(registerMemParams));
        registerMemParams.presStoreBuffer = &(m_atomicScratchBuf.resAtomicScratchBuffer);
        registerMemParams.dwOffset   = operand3Offset;
        registerMemParams.dwRegister = mmioRegisters->generalPurposeRegister0LoOffset; // VCS_GPR0_Lo
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiLoadRegisterMemCmd(
            cmdBuffer,
            &registerMemParams));

        // GPR0_Hi = n2_hi = 1
        MOS_ZeroMemory(&registerMemParams, sizeof(registerMemParams));
        registerMemParams.presStoreBuffer = &(m_atomicScratchBuf.resAtomicScratchBuffer);
        registerMemParams.dwOffset = operand2Offset + sizeof(uint32_t) ; // update 1
        registerMemParams.dwRegister = mmioRegisters->generalPurposeRegister0HiOffset; // VCS_GPR0_Hi
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiLoadRegisterMemCmd(
            cmdBuffer,
            &registerMemParams));

        // Reset GPR4_Lo and GPR4_Hi
        MOS_ZeroMemory(&registerMemParams, sizeof(registerMemParams));
        registerMemParams.presStoreBuffer =&(m_atomicScratchBuf.resAtomicScratchBuffer);
        registerMemParams.dwOffset = zeroValueOffset ;
        registerMemParams.dwRegister = mmioRegisters->generalPurposeRegister4LoOffset; // VCS_GPR4_Hi
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiLoadRegisterMemCmd(
            cmdBuffer,
            &registerMemParams));
        MOS_ZeroMemory(&registerMemParams, sizeof(registerMemParams));
        registerMemParams.presStoreBuffer = &(m_atomicScratchBuf.resAtomicScratchBuffer);
        registerMemParams.dwOffset  =  zeroValueOffset ;
        registerMemParams.dwRegister = mmioRegisters->generalPurposeRegister4HiOffset; // VCS_GPR4_Hi
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiLoadRegisterMemCmd(
            cmdBuffer,
            &registerMemParams));

        // Make Flush DW call to make sure all previous work is done
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiFlushDwCmd(
            cmdBuffer,
            &flushDwParams));

        // steop-3: n2 = (n2 == 0:1) ? 0:0 : n2      // uint64_t CMP
        // If n2==0 (Lo) and 1 (Hi), covert n2 to 0 (Lo)and 0 (Hi), else no change.
        // n2 == 0:1 means encoding completsion. the n2 memory will be updated with 0:0, otherwise, no change.
        MOS_ZeroMemory(&atomicParams, sizeof(atomicParams));
        atomicParams.pOsResource = &(m_atomicScratchBuf.resAtomicScratchBuffer);
        atomicParams.dwResourceOffset = operand2Offset;
        atomicParams.dwDataSize = sizeof(uint64_t);
        atomicParams.Operation = MHW_MI_ATOMIC_CMP;
        atomicParams.bReturnData = true;
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiAtomicCmd(
            cmdBuffer,
            &atomicParams));

        // Make Flush DW call to make sure all previous work is done
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiFlushDwCmd(
            cmdBuffer,
            &flushDwParams));

        // VCS_GPR0_Lo = n3_hi = 1
        MOS_ZeroMemory(&registerMemParams, sizeof(registerMemParams));
        registerMemParams.presStoreBuffer =  &(m_atomicScratchBuf.resAtomicScratchBuffer);
        registerMemParams.dwOffset = operand3Offset + sizeof(uint32_t);
        registerMemParams.dwRegister = mmioRegisters->generalPurposeRegister0LoOffset; // VCS_GPR0_Lo
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiLoadRegisterMemCmd(
            cmdBuffer,
            &registerMemParams));

        // Make Flush DW call to make sure all previous work is done
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiFlushDwCmd(
            cmdBuffer,
            &flushDwParams));

        // step-4: n2_hi = n2_hi ^ VCS_GPR0_Lo = n2_hi ^ n3_hi
        MOS_ZeroMemory(&atomicParams, sizeof(atomicParams));
        atomicParams.pOsResource =&(m_atomicScratchBuf.resAtomicScratchBuffer);
        atomicParams.dwResourceOffset = operand2Offset + sizeof(uint32_t);
        atomicParams.dwDataSize = sizeof(uint32_t);
        atomicParams.Operation = MHW_MI_ATOMIC_XOR;
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiAtomicCmd(
            cmdBuffer,
            &atomicParams));

        // VCS_GPR0_Lo = n2_hi
        MOS_ZeroMemory(&registerMemParams, sizeof(registerMemParams));
        registerMemParams.presStoreBuffer = &(m_atomicScratchBuf.resAtomicScratchBuffer);
        registerMemParams.dwOffset = operand2Offset + sizeof(uint32_t) ;
        registerMemParams.dwRegister = mmioRegisters->generalPurposeRegister0LoOffset; // VCS_GPR0_Lo
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiLoadRegisterMemCmd(
            cmdBuffer,
            &registerMemParams));

        // step-5: m_storeData = m_storeData + VCS_GPR0_Lo = m_storeData + n2_hi
        // if not completed n2_hi should be 0, then m_storeData = m_storeData + 0
        // if completed, n2_hi should be 1, then m_storeData = m_storeData + 1
        MOS_ZeroMemory(&atomicParams, sizeof(atomicParams));
        atomicParams.pOsResource =&m_encodeStatusBuf.resStatusBuffer;
        atomicParams.dwResourceOffset =  0;
        atomicParams.dwDataSize = sizeof(uint32_t);
        atomicParams.Operation = MHW_MI_ATOMIC_ADD;
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiAtomicCmd(
            cmdBuffer,
            &atomicParams));

        // Make Flush DW call to make sure all previous work is done
        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiFlushDwCmd(
            cmdBuffer,
            &flushDwParams));
    }

    return eStatus;
}

//------------------------------------------------------------------------------
//| Purpose:    Sets up the eStatus reporting values for the next frame
//| Return:     N/A
//------------------------------------------------------------------------------
MOS_STATUS CodechalEncoderState::ResetStatusReport()
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    CODECHAL_ENCODE_CHK_NULL_RETURN(m_encodeStatusBuf.pEncodeStatus);

    EncodeStatusBuffer* encodeStatusBuf    = &m_encodeStatusBuf;
    EncodeStatusBuffer* encodeStatusBufRcs = &m_encodeStatusBufRcs;

    EncodeStatus* encodeStatus =
        (EncodeStatus*)(encodeStatusBuf->pEncodeStatus +
        encodeStatusBuf->wCurrIndex * encodeStatusBuf->dwReportSize);

    if (!m_frameTrackingEnabled && !m_inlineEncodeStatusUpdate)
    {
        bool renderEngineInUse = m_osInterface->pfnGetGpuContext(m_osInterface) == m_renderContext;
        bool nullRendering = false;

        MOS_SYNC_PARAMS syncParams = g_cInitSyncParams;
        if (renderEngineInUse)
        {
            syncParams.GpuContext = m_renderContext;
            nullRendering = m_renderContextUsesNullHw;
        }
        else
        {
            syncParams.GpuContext = m_videoContext;
            nullRendering = m_videoContextUsesNullHw;
        }

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

        cmdBuffer.Attributes.bTurboMode             = m_hwInterface->m_turboMode;
        cmdBuffer.Attributes.dwNumRequestedEUSlices = m_hwInterface->m_numRequestedEuSlices;

        CODECHAL_ENCODE_CHK_STATUS_RETURN(UpdateCmdBufAttribute(&cmdBuffer, renderEngineInUse));

        MHW_GENERIC_PROLOG_PARAMS genericPrologParams;
        MOS_ZeroMemory(&genericPrologParams, sizeof(genericPrologParams));
        genericPrologParams.pOsInterface = m_osInterface;
        genericPrologParams.pvMiInterface = m_miInterface;
        genericPrologParams.bMmcEnabled = CodecHalMmcState::IsMmcEnabled();
        genericPrologParams.presStoreData = (renderEngineInUse) ?
            &encodeStatusBufRcs->resStatusBuffer : &encodeStatusBuf->resStatusBuffer;
        genericPrologParams.dwStoreDataValue = m_storeData;
        CODECHAL_ENCODE_CHK_STATUS_RETURN(Mhw_SendGenericPrologCmd(&cmdBuffer, &genericPrologParams));

        // Update the tag in GPU Sync eStatus buffer (H/W Tag) to match the current S/W tag
        if (m_osInterface->bTagResourceSync)
        {
            if (!m_firstField || CodecHal_PictureIsFrame(m_currOriginalPic))
            {
                CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hwInterface->WriteSyncTagToResource(&cmdBuffer, &syncParams));
            }
        }

        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiBatchBufferEnd(
            &cmdBuffer,
            nullptr));
        CODECHAL_DEBUG_TOOL(CODECHAL_ENCODE_CHK_STATUS_RETURN(m_debugInterface->DumpCmdBuffer(
            &cmdBuffer,
            CODECHAL_NUM_MEDIA_STATES,
            "_RESET_STATUS")));

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

        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_osInterface->pfnSubmitCommandBuffer(m_osInterface, &cmdBuffer, nullRendering));
    }

    if (m_videoContextUsesNullHw ||
        m_renderContextUsesNullHw)
    {
        if (CodecHalUsesOnlyRenderEngine(m_codecFunction))
        {
            *(encodeStatusBufRcs->pData) = m_storeData;
        }
        else
        {
            *(encodeStatusBuf->pData) = m_storeData;
        }
    }

    encodeStatus->dwHeaderBytesInserted = m_headerBytesInserted;
    m_headerBytesInserted = 0;

    if (!m_disableStatusReport)
    {
        m_storeData++;
        encodeStatusBuf->wCurrIndex    = (encodeStatusBuf->wCurrIndex + 1) % CODECHAL_ENCODE_STATUS_NUM;
        encodeStatusBufRcs->wCurrIndex = (encodeStatusBufRcs->wCurrIndex + 1) % CODECHAL_ENCODE_STATUS_NUM;
    }

    // clean up the Status for next frame
    encodeStatus =
        (EncodeStatus*)(encodeStatusBuf->pEncodeStatus +
        encodeStatusBuf->wCurrIndex * encodeStatusBuf->dwReportSize);
    MOS_ZeroMemory((uint8_t*)encodeStatus, sizeof(EncodeStatus));

    if (m_encEnabled)
    {
        EncodeStatus* pEncodeStatusRcs =
            (EncodeStatus*)(encodeStatusBufRcs->pEncodeStatus +
                encodeStatusBufRcs->wCurrIndex * encodeStatusBufRcs->dwReportSize);
        MOS_ZeroMemory((uint8_t*)pEncodeStatusRcs, sizeof(EncodeStatus));
    }

    return eStatus;
}

MOS_STATUS CodechalEncoderState::ReadCounterValue(uint16_t index, EncodeStatusReport* encodeStatusReport)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
    CODECHAL_ENCODE_FUNCTION_ENTER;
    CODECHAL_ENCODE_CHK_NULL_RETURN(encodeStatusReport);
    uint64_t *address2Counter = nullptr;

    // Report out counter read from HW
    if (m_hwInterface->GetCpInterface()->IsHWCounterAutoIncrementEnforced(m_osInterface))
    {
        address2Counter = (uint64_t *)(((char *)(m_dataHwCount)) + (index * sizeof(HwCounter)));

        if (MEDIA_IS_WA(m_waTable, WaReadCtrNounceRegister))
        {
            CODECHAL_ENCODE_CHK_STATUS_RETURN(
                m_osInterface->osCpInterface->ReadCtrNounceRegister(
                    true,
                    (uint32_t *)&m_regHwCount[index]));
            address2Counter = (uint64_t *)&m_regHwCount[index];
            CODECHAL_ENCODE_NORMALMESSAGE("MMIO returns end ctr is %llx", *address2Counter);
            CODECHAL_ENCODE_NORMALMESSAGE("bitstream size = %d.", encodeStatusReport->bitstreamSize);

            // Here gets the end counter of current bit stream, which should minus counter increment.
            *address2Counter = *address2Counter - (((encodeStatusReport->bitstreamSize + 63) >> 6) << 2);
        }
    }

    // KBL- cann't read counter from HW
    else
    {
        uint32_t ctr[4] = { 0 };
        eStatus = m_hwInterface->GetCpInterface()->GetCounterValue(ctr);
        if (MOS_STATUS_SUCCESS == eStatus)
        {
            address2Counter = (uint64_t *)ctr;
        }
        else
        {
            return eStatus;
        }
    }
    encodeStatusReport->HWCounterValue.Count = *address2Counter;
    //Report back in Big endian
    encodeStatusReport->HWCounterValue.Count = SwapEndianness(encodeStatusReport->HWCounterValue.Count);
    //IV value computation
    encodeStatusReport->HWCounterValue.IV = *(++address2Counter); 
    encodeStatusReport->HWCounterValue.IV = SwapEndianness(encodeStatusReport->HWCounterValue.IV);
    CODECHAL_ENCODE_NORMALMESSAGE(
        "encodeStatusReport->HWCounterValue.Count = 0x%llx, encodeStatusReport->HWCounterValue.IV = 0x%llx",
        encodeStatusReport->HWCounterValue.Count,
        encodeStatusReport->HWCounterValue.IV);
    return eStatus;
}

//------------------------------------------------------------------------------
//| Purpose:    Gets available eStatus report data
//| Return:     N/A
//------------------------------------------------------------------------------
MOS_STATUS CodechalEncoderState::GetStatusReport(
    void *status,
    uint16_t numStatus)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    CODECHAL_ENCODE_CHK_NULL_RETURN(status);
    EncodeStatusReport *codecStatus = (EncodeStatusReport *)status;

    EncodeStatusBuffer* encodeStatusBuf = nullptr;
    if (m_pakEnabled)
    {
        encodeStatusBuf = &m_encodeStatusBuf;
    }
    else
    {
        encodeStatusBuf = &m_encodeStatusBufRcs;
    }

    CODECHAL_ENCODE_CHK_NULL_RETURN(encodeStatusBuf->pEncodeStatus);

    uint16_t numReportsAvailable    =
        (encodeStatusBuf->wCurrIndex - encodeStatusBuf->wFirstIndex) &
        (CODECHAL_ENCODE_STATUS_NUM - 1); // max is (CODECHAL_ENCODE_STATUS_NUM - 1)

    uint32_t globalHWStoredData = 0;
    if (m_pakEnabled)
    {
        globalHWStoredData = *(m_encodeStatusBuf.pData);      // HW stored Data
    }
    else
    {
        globalHWStoredData = *(m_encodeStatusBufRcs.pData);   // HW stored Data
    }
    uint32_t globalCount = m_storeData - globalHWStoredData;

    uint16_t reportsGenerated = 0;
    if (m_videoContextUsesNullHw ||
        m_renderContextUsesNullHw)
    {
        for (auto i = 0; i < numReportsAvailable; i++)
        {
            codecStatus[i].CodecStatus = CODECHAL_STATUS_SUCCESSFUL;
            // Set fake bitstream size to avoid DDI report error
            codecStatus[i].bitstreamSize = 1024;
            reportsGenerated++;
        }

        encodeStatusBuf->wFirstIndex =
            (encodeStatusBuf->wFirstIndex + reportsGenerated) % CODECHAL_ENCODE_STATUS_NUM;

        return eStatus;
    }

    CODECHAL_ENCODE_VERBOSEMESSAGE("    numStatus = %d, dwNumReportsAvailable = %d.", numStatus, numReportsAvailable);
    CODECHAL_ENCODE_VERBOSEMESSAGE("    hwstoreData = %d, globalCount = %d", globalHWStoredData, globalCount);

    if (numReportsAvailable < numStatus && numStatus < CODECHAL_ENCODE_STATUS_NUM)
    {
        for (auto i = numReportsAvailable; i < numStatus; i++)
        {
            codecStatus[i].CodecStatus = CODECHAL_STATUS_UNAVAILABLE;
        }
        numStatus = numReportsAvailable;
    }

    if (numReportsAvailable == 0)
    {
        CODECHAL_ENCODE_ASSERTMESSAGE("No reports available, wCurrIndex = %d, wFirstIndex = %d", encodeStatusBuf->wCurrIndex, encodeStatusBuf->wFirstIndex);
        return MOS_STATUS_SUCCESS;
    }

    uint16_t index = 0;

    for (auto i = 0; i < numStatus; i++)
    {
        if(codecStatus->bSequential)
        {
            index = (encodeStatusBuf->wFirstIndex + i) & (CODECHAL_ENCODE_STATUS_NUM - 1);
        }
        else
        {
            index = (encodeStatusBuf->wFirstIndex + numStatus - i - 1) & (CODECHAL_ENCODE_STATUS_NUM - 1);
        }

        EncodeStatus* encodeStatus =
            (EncodeStatus*)(encodeStatusBuf->pEncodeStatus +
            index * encodeStatusBuf->dwReportSize);
        EncodeStatusReport* encodeStatusReport = &encodeStatus->encodeStatusReport;
        PCODEC_REF_LIST refList = encodeStatusReport->pCurrRefList;
        PMHW_VDBOX_IMAGE_STATUS_CONTROL imgStatusCtrl = &encodeStatus->ImageStatusCtrl;
        PMHW_VDBOX_PAK_NUM_OF_SLICES numSlices = &encodeStatus->NumSlices;
        uint32_t localCount = encodeStatus->dwStoredData - globalHWStoredData;

        if (localCount == 0 || localCount > globalCount)
        {
            CODECHAL_DEBUG_TOOL(
                m_statusReportDebugInterface->m_bufferDumpFrameNum = encodeStatus->dwStoredData;
            )
            
            // Current command is executed
            if (m_osInterface->pfnIsGPUHung(m_osInterface))
            {
                encodeStatusReport->CodecStatus = CODECHAL_STATUS_ERROR;
                *(encodeStatusBuf->pData) += 1;
            }
            else if (encodeStatusReport->Func != CODECHAL_ENCODE_ENC_ID &&
                encodeStatusReport->Func != CODECHAL_ENCODE_FEI_ENC_ID &&
                encodeStatus->dwStoredDataMfx != CODECHAL_STATUS_QUERY_END_FLAG)
            {
                if(encodeStatusReport->Func == CODECHAL_ENCODE_FEI_PRE_ENC_ID)
                {
                    CODECHAL_DEBUG_TOOL(
                        m_statusReportDebugInterface->m_scaledBottomFieldOffset = m_scaledBottomFieldOffset;
                        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_statusReportDebugInterface->DumpYUVSurface(
                            m_trackedBuf->Get4xDsSurface(CODEC_CURR_TRACKED_BUFFER),
                            CodechalDbgAttr::attrReconstructedSurface,
                            "4xScaledSurf"));

                        /*CODECHAL_ENCODE_CHK_STATUS_RETURN(CodecHal_DbgDumpEncode1Dbuffer(
                            m_debugInterface,
                            pEncoder));*/

                        // dump EncodeFeiPreproc
                        FeiPreEncParams PreEncParams;
                        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_statusReportDebugInterface->DumpBuffer(
                            CodecHal_PictureIsBottomField(m_currOriginalPic) ? &PreEncParams.resStatsBotFieldBuffer
                                                                             : &PreEncParams.resStatsBotFieldBuffer,
                            CodechalDbgAttr::attrOutput,
                            "MbStats",
                            m_picWidthInMb * m_frameFieldHeightInMb * 64,
                            CodecHal_PictureIsBottomField(m_currOriginalPic) ? m_mbvProcStatsBottomFieldOffset : 0,
                            CODECHAL_MEDIA_STATE_PREPROC));)
                    encodeStatusReport->CodecStatus = CODECHAL_STATUS_SUCCESSFUL;
                }
                else
                {
                    CODECHAL_ENCODE_NORMALMESSAGE("Media reset may have occured.");
                    encodeStatusReport->CodecStatus = CODECHAL_STATUS_ERROR;
                }
            }
            else if (m_hwWalker && encodeStatusReport->Func == CODECHAL_ENCODE_ENC_ID)
            {
                // iterate over all media states and check that all of them completed
                for (auto j = 0; j < CODECHAL_NUM_MEDIA_STATES; j += 1)
                {
                    if (encodeStatus->qwStoredDataEnc[j].dwStoredData != CODECHAL_STATUS_QUERY_END_FLAG)
                    {
                        // some media state failed to complete
                        CODECHAL_ENCODE_ASSERTMESSAGE("Error: Unable to finish encoding");
                        encodeStatusReport->CodecStatus = CODECHAL_STATUS_ERROR;
                        break;
                    }
                }

                encodeStatusReport->CodecStatus = CODECHAL_STATUS_SUCCESSFUL;

                if (m_codecFunction == CODECHAL_FUNCTION_HYBRIDPAK && m_mode == CODECHAL_ENCODE_MODE_VP9 &&
                    encodeStatusReport->CodecStatus != CODECHAL_STATUS_ERROR)
                {
                     unsigned int size = ((m_frameWidth + 63) >> 6) * ((m_frameHeight + 63) >> 6) + 1;
                     encodeStatusReport->bitstreamSize = CODECHAL_VP9_MB_CODE_SIZE * sizeof(uint32_t) * size;
                }
            }
            // The huffman tables sent by application were incorrect (used only for JPEG encoding)
            else if(m_standard == CODECHAL_JPEG && imgStatusCtrl->MissingHuffmanCode == 1)
            {
                CODECHAL_ENCODE_ASSERTMESSAGE("Error: JPEG standard encoding: missing huffman code");
                encodeStatusReport->CodecStatus = CODECHAL_STATUS_ERROR;
            }
            else
            {
                if (m_codecGetStatusReportDefined)
                {
                    // Call corresponding CODEC's status report function if existing
                    eStatus = GetStatusReport(encodeStatus, encodeStatusReport);
                    if (MOS_STATUS_SUCCESS != eStatus)
                    {
                        return eStatus;
                    }

                    if (m_osInterface->osCpInterface->IsCpEnabled() && m_skipFrameBasedHWCounterRead == false)
                    {
                        eStatus = ReadCounterValue(index, encodeStatusReport);
                        if (MOS_STATUS_SUCCESS != eStatus)
                        {
                            return eStatus;
                        }
                    }
                }
                else
                {
                    encodeStatusReport->CodecStatus = CODECHAL_STATUS_SUCCESSFUL;
                    encodeStatusReport->bitstreamSize =
                        encodeStatus->dwMFCBitstreamByteCountPerFrame + encodeStatus->dwHeaderBytesInserted;

                    // dwHeaderBytesInserted is for WAAVCSWHeaderInsertion
                    // and is 0 otherwise
                    encodeStatusReport->QpY = encodeStatus->BrcQPReport.DW0.QPPrimeY;
                    encodeStatusReport->SuggestedQpYDelta =
                        encodeStatus->ImageStatusCtrl.CumulativeSliceDeltaQP;
                    encodeStatusReport->NumberPasses = (uint8_t)(encodeStatus->ImageStatusCtrl.TotalNumPass + 1);
                    encodeStatusReport->SceneChangeDetected =
                        (encodeStatus->dwSceneChangedFlag & CODECHAL_ENCODE_SCENE_CHANGE_DETECTED_MASK) ? 1 : 0;

                    CODECHAL_ENCODE_CHK_NULL_RETURN(m_skuTable);

                    if (m_osInterface->osCpInterface->IsCpEnabled() && m_skipFrameBasedHWCounterRead == false)
                    {
                        eStatus = ReadCounterValue(index, encodeStatusReport);
                        if (MOS_STATUS_SUCCESS != eStatus)
                        {
                            return eStatus;
                        }
                    }

                    if (m_picWidthInMb != 0 && m_frameFieldHeightInMb != 0)
                    {
                        encodeStatusReport->AverageQp = (unsigned char)(((uint32_t)encodeStatus->QpStatusCount.cumulativeQP)
                            / (m_picWidthInMb * m_frameFieldHeightInMb));
                    }
                    encodeStatusReport->PanicMode = encodeStatus->ImageStatusCtrl.Panic;

                    // If Num slices is greater than spec limit set NumSlicesNonCompliant to 1 and report error
                    if (numSlices->NumberOfSlices > m_maxNumSlicesAllowed)
                    {
                        encodeStatusReport->NumSlicesNonCompliant = 1;
                    }
                    encodeStatusReport->NumberSlices = numSlices->NumberOfSlices;
                }

                if (encodeStatusReport->bitstreamSize > m_bitstreamUpperBound)
                {
                    encodeStatusReport->CodecStatus = CODECHAL_STATUS_ERROR;
                    encodeStatusReport->bitstreamSize = 0;
                    CODECHAL_ENCODE_ASSERTMESSAGE("Bit-stream size exceeds upper bound!");
                    return MOS_STATUS_NOT_ENOUGH_BUFFER;
                }

                if(refList && refList->bMADEnabled)
                {
                    // set lock flag to READ_ONLY
                    MOS_LOCK_PARAMS lockFlags;
                    MOS_ZeroMemory(&lockFlags, sizeof(MOS_LOCK_PARAMS));
                    lockFlags.ReadOnly = 1;

                    uint8_t* data = (uint8_t* )m_osInterface->pfnLockResource(
                        m_osInterface,
                        &m_resMadDataBuffer[refList->ucMADBufferIdx],
                        &lockFlags);

                    CODECHAL_ENCODE_CHK_NULL_RETURN(data);

                    eStatus = MOS_SecureMemcpy(
                         &encodeStatusReport->MAD,
                        CODECHAL_MAD_BUFFER_SIZE,
                         data,
                        CODECHAL_MAD_BUFFER_SIZE);
                    if(eStatus != MOS_STATUS_SUCCESS)
                    {
                        CODECHAL_ENCODE_ASSERTMESSAGE("Failed to copy memory.");
                        return eStatus;
                    }

                    m_osInterface->pfnUnlockResource(
                        m_osInterface,
                        &m_resMadDataBuffer[refList->ucMADBufferIdx]);

                    // The driver needs to divide the output distortion by 4 before sending to the app
                    encodeStatusReport->MAD /= 4;
                }
                else
                {
                    encodeStatusReport->MAD  = 0;
                }

                CODECHAL_DEBUG_TOOL(
                    CODEC_REF_LIST currRefList = *refList;
                    currRefList.RefPic         = encodeStatusReport->CurrOriginalPic;

                    m_statusReportDebugInterface->m_currPic            = encodeStatusReport->CurrOriginalPic;
                    m_statusReportDebugInterface->m_bufferDumpFrameNum = encodeStatus->dwStoredData;
                    m_statusReportDebugInterface->m_frameType          = encodeStatus->wPictureCodingType;

                    if (!m_vdencEnabled) {
                        if (currRefList.bMADEnabled)
                        {
                            CODECHAL_ENCODE_CHK_STATUS_RETURN(
                                m_statusReportDebugInterface->DumpBuffer(
                                &m_resMadDataBuffer[currRefList.ucMADBufferIdx],
                                CodechalDbgAttr::attrInput,
                                "MADWrite",
                                CODECHAL_MAD_BUFFER_SIZE,
                                0,
                                CODECHAL_MEDIA_STATE_ENC_NORMAL));
                        }

                        DumpMbEncPakOutput(refList, m_statusReportDebugInterface);
                    }

                    if (CodecHalUsesVideoEngine(m_codecFunction)) {
                        /*  Only where the MFX engine is used the bitstream surface will be available */
                        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_statusReportDebugInterface->DumpBuffer(
                            &currRefList.resBitstreamBuffer,
                            CodechalDbgAttr::attrBitstream,
                            "_PAK",
                            encodeStatusReport->bitstreamSize,
                            0,
                            CODECHAL_NUM_MEDIA_STATES));

                        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_statusReportDebugInterface->DumpData(
                            encodeStatusReport,
                            sizeof(EncodeStatusReport),
                            CodechalDbgAttr::attrStatusReport,
                            "EncodeStatusReport_Buffer"));

                        CODECHAL_ENCODE_CHK_STATUS_RETURN(DumpFrameStatsBuffer(m_statusReportDebugInterface));

                        if (m_vdencEnabled)
                        {
                            /*CODECHAL_ENCODE_CHK_STATUS_RETURN(CodecHal_DbgDumpEncodeVdencOutputs(
                                m_debugInterface, pEncoder));

                            if (m_cmdGenHucUsed)
                            {
                                CODECHAL_ENCODE_CHK_STATUS_RETURN(CodecHal_DbgDumpEncodeHucCmdGen(
                                    m_debugInterface, pEncoder));
                            }*/
                        }
                    }

                    if (currRefList.b32xScalingUsed) {
                        m_statusReportDebugInterface->m_scaledBottomFieldOffset = m_scaled32xBottomFieldOffset;
                        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_statusReportDebugInterface->DumpYUVSurface(
                            m_trackedBuf->Get32xDsSurface(currRefList.ucScalingIdx),
                            CodechalDbgAttr::attrReconstructedSurface,
                            "32xScaledSurf"))
                    }

                    if (currRefList.b2xScalingUsed)  // Currently only used for Gen10 Hevc Encode
                    {
                        m_statusReportDebugInterface->m_scaledBottomFieldOffset = 0;  // No bottom field offset for Hevc
                        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_statusReportDebugInterface->DumpYUVSurface(
                            m_trackedBuf->Get2xDsSurface(currRefList.ucScalingIdx),
                            CodechalDbgAttr::attrReconstructedSurface,
                            "2xScaledSurf"))
                    }

                    if (currRefList.b16xScalingUsed) {
                        m_statusReportDebugInterface->m_scaledBottomFieldOffset = m_scaled16xBottomFieldOffset;
                        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_statusReportDebugInterface->DumpYUVSurface(
                            m_trackedBuf->Get16xDsSurface(currRefList.ucScalingIdx),
                            CodechalDbgAttr::attrReconstructedSurface,
                            "16xScaledSurf"))
                    }

                    if (currRefList.b4xScalingUsed) {
                        m_statusReportDebugInterface->m_scaledBottomFieldOffset = m_scaledBottomFieldOffset;
                        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_statusReportDebugInterface->DumpYUVSurface(
                            m_trackedBuf->Get4xDsSurface(currRefList.ucScalingIdx),
                            CodechalDbgAttr::attrReconstructedSurface,
                            "4xScaledSurf"))
                    }

                    if (!(m_codecFunction == CODECHAL_FUNCTION_ENC || m_codecFunction == CODECHAL_FUNCTION_FEI_ENC)) {
                        if (m_codecFunction == CODECHAL_FUNCTION_HYBRIDPAK)
                        {
                            m_statusReportDebugInterface->m_hybridPakP1 = false;
                        }

                        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_statusReportDebugInterface->DumpYUVSurface(
                            &currRefList.sRefReconBuffer,
                            CodechalDbgAttr::attrReconstructedSurface,
                            "ReconSurf"))
                    })
            }
            CODECHAL_ENCODE_VERBOSEMESSAGE("Incrementing reports generated to %d.", (reportsGenerated + 1));
            reportsGenerated++;
        }
        else
        {
            //update GPU status, and skip the hang frame
            if(m_osInterface->pfnIsGPUHung(m_osInterface))
            {
                *(encodeStatusBuf->pData) += 1;
                reportsGenerated++;
            }

            CODECHAL_ENCODE_VERBOSEMESSAGE("Status buffer %d is INCOMPLETE.", i);
            encodeStatusReport->CodecStatus = CODECHAL_STATUS_INCOMPLETE;
        }
        codecStatus[i] = *encodeStatusReport;
    }

    encodeStatusBuf->wFirstIndex =
        (encodeStatusBuf->wFirstIndex + reportsGenerated) % CODECHAL_ENCODE_STATUS_NUM;
    CODECHAL_ENCODE_VERBOSEMESSAGE("wFirstIndex now becomes %d.", encodeStatusBuf->wFirstIndex);

    return eStatus;
}

//------------------------------------------------------------------------------
//| Purpose:    Reports user feature keys used for encoding
//| Return:     N/A
//------------------------------------------------------------------------------
MOS_STATUS CodechalEncoderState::UserFeatureKeyReport()
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    MOS_USER_FEATURE_VALUE_WRITE_DATA userFeatureWriteData;

    // Encode HW Walker Reporting
    userFeatureWriteData = __NULL_USER_FEATURE_VALUE_WRITE_DATA__;
    userFeatureWriteData.Value.i32Data = m_hwWalker;
    userFeatureWriteData.ValueID = __MEDIA_USER_FEATURE_VALUE_ENCODE_HW_WALKER_ID;
    MOS_UserFeature_WriteValues_ID(nullptr, &userFeatureWriteData, 1);

    if (m_hwWalker)
    {
        // Encode HW Walker m_mode Reporting
#if (_DEBUG || _RELEASE_INTERNAL)
        userFeatureWriteData = __NULL_USER_FEATURE_VALUE_WRITE_DATA__;
        userFeatureWriteData.Value.i32Data = m_walkerMode;
        userFeatureWriteData.ValueID = __MEDIA_USER_FEATURE_VALUE_ENCODE_HW_WALKER_MODE_ID;
        MOS_UserFeature_WriteValues_ID(nullptr, &userFeatureWriteData, 1);
#endif // _DEBUG || _RELEASE_INTERNAL
    }

    if (MEDIA_IS_SKU(m_skuTable, FtrSliceShutdown))
    {
        // SliceShutdownEnable Reporting
        userFeatureWriteData = __NULL_USER_FEATURE_VALUE_WRITE_DATA__;
        userFeatureWriteData.Value.i32Data = m_sliceShutdownEnable;
        userFeatureWriteData.ValueID = __MEDIA_USER_FEATURE_VALUE_SLICE_SHUTDOWN_ENABLE_ID;
        MOS_UserFeature_WriteValues_ID(nullptr, &userFeatureWriteData, 1);
    }

#if (_DEBUG || _RELEASE_INTERNAL)
#ifndef _FULL_OPEN_SOURCE
    // report encode CSC method
    if (m_cscDsState)
    {
        userFeatureWriteData = __NULL_USER_FEATURE_VALUE_WRITE_DATA__;
        userFeatureWriteData.Value.i32Data = m_cscDsState->CscMethod();
        userFeatureWriteData.ValueID = __MEDIA_USER_FEATURE_VALUE_ENCODE_CSC_METHOD_ID;
        MOS_UserFeature_WriteValues_ID(nullptr, &userFeatureWriteData, 1);

        userFeatureWriteData = __NULL_USER_FEATURE_VALUE_WRITE_DATA__;
        userFeatureWriteData.Value.u32Data = (uint32_t)m_rawSurface.TileType;
        userFeatureWriteData.ValueID = __MEDIA_USER_FEATURE_VALUE_ENCODE_RAW_TILE_ID;
        MOS_UserFeature_WriteValues_ID(nullptr, &userFeatureWriteData, 1);

        userFeatureWriteData = __NULL_USER_FEATURE_VALUE_WRITE_DATA__;
        userFeatureWriteData.Value.u32Data = (uint32_t)m_rawSurface.Format;
        userFeatureWriteData.ValueID = __MEDIA_USER_FEATURE_VALUE_ENCODE_RAW_FORMAT_ID;
        MOS_UserFeature_WriteValues_ID(nullptr, &userFeatureWriteData, 1);
    }

    // Encode compute context Reporting
    userFeatureWriteData = __NULL_USER_FEATURE_VALUE_WRITE_DATA__;
    userFeatureWriteData.Value.i32Data = m_computeContextEnabled;
    userFeatureWriteData.ValueID = __MEDIA_USER_FEATURE_VALUE_ENCODE_ENABLE_COMPUTE_CONTEXT_ID;
    MOS_UserFeature_WriteValues_ID(nullptr, &userFeatureWriteData, 1);

#endif
#endif

    return eStatus;
}

MOS_STATUS CodechalEncoderState::SubmitCommandBuffer(
    PMOS_COMMAND_BUFFER cmdBuffer,
    int32_t         nullRendering)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    CODECHAL_ENCODE_CHK_NULL_RETURN(cmdBuffer);

    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_osInterface->pfnSubmitCommandBuffer(m_osInterface, cmdBuffer, nullRendering));
    return eStatus;
}

void CodechalEncoderState::MotionEstimationDisableCheck()
{
    CODECHAL_ENCODE_FUNCTION_ENTER;

    if (m_downscaledWidth4x < m_minScaledDimension || m_downscaledWidthInMb4x < m_minScaledDimensionInMb ||
        m_downscaledHeight4x < m_minScaledDimension || m_downscaledHeightInMb4x < m_minScaledDimensionInMb)
    {
        m_32xMeSupported = false;
        m_16xMeSupported = false;
        if (m_downscaledWidth4x < m_minScaledDimension || m_downscaledWidthInMb4x < m_minScaledDimensionInMb)
        {
            m_downscaledWidth4x     = m_minScaledDimension;
            m_downscaledWidthInMb4x = CODECHAL_GET_WIDTH_IN_MACROBLOCKS(m_downscaledWidth4x);
        }
        if (m_downscaledHeight4x < m_minScaledDimension || m_downscaledHeightInMb4x < m_minScaledDimensionInMb)
        {
            m_downscaledHeight4x     = m_minScaledDimension;
            m_downscaledHeightInMb4x = CODECHAL_GET_HEIGHT_IN_MACROBLOCKS(m_downscaledHeight4x);
        }
    }
    else if (m_downscaledWidth16x < m_minScaledDimension  || m_downscaledWidthInMb16x < m_minScaledDimensionInMb ||
             m_downscaledHeight16x < m_minScaledDimension || m_downscaledHeightInMb16x < m_minScaledDimensionInMb)
    {
        m_32xMeSupported = false;
        if (m_downscaledWidth16x < m_minScaledDimension || m_downscaledWidthInMb16x < m_minScaledDimensionInMb)
        {
            m_downscaledWidth16x     = m_minScaledDimension;
            m_downscaledWidthInMb16x = CODECHAL_GET_WIDTH_IN_MACROBLOCKS(m_downscaledWidth16x);
        }
        if (m_downscaledHeight16x < m_minScaledDimension || m_downscaledHeightInMb16x < m_minScaledDimensionInMb)
        {
            m_downscaledHeight16x     = m_minScaledDimension;
            m_downscaledHeightInMb16x = CODECHAL_GET_HEIGHT_IN_MACROBLOCKS(m_downscaledHeight16x);
        }
    }
    else
    {
        if (m_downscaledWidth32x < m_minScaledDimension || m_downscaledWidthInMb32x < m_minScaledDimensionInMb)
        {
            m_downscaledWidth32x     = m_minScaledDimension;
            m_downscaledWidthInMb32x = CODECHAL_GET_WIDTH_IN_MACROBLOCKS(m_downscaledWidth32x);
        }
        if (m_downscaledHeight32x < m_minScaledDimension || m_downscaledHeightInMb32x < m_minScaledDimensionInMb)
        {
            m_downscaledHeight32x     = m_minScaledDimension;
            m_downscaledHeightInMb32x = CODECHAL_GET_HEIGHT_IN_MACROBLOCKS(m_downscaledHeight32x);
        }
    }
}

MOS_STATUS CodechalEncoderState::SendPrologWithFrameTracking(
    PMOS_COMMAND_BUFFER cmdBuffer,
    bool frameTrackingRequested)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    CODECHAL_ENCODE_CHK_NULL_RETURN(cmdBuffer);

    MOS_GPU_CONTEXT gpuContext = m_osInterface->pfnGetGpuContext(m_osInterface);

    // initialize command buffer attributes
    cmdBuffer->Attributes.bTurboMode               = m_hwInterface->m_turboMode;
    cmdBuffer->Attributes.bMediaPreemptionEnabled  = MOS_RCS_ENGINE_USED(gpuContext) ?
        m_renderEngineInterface->IsPreemptionEnabled() : 0;
    cmdBuffer->Attributes.dwNumRequestedEUSlices   = m_hwInterface->m_numRequestedEuSlices;
    cmdBuffer->Attributes.dwNumRequestedSubSlices  = m_hwInterface->m_numRequestedSubSlices;
    cmdBuffer->Attributes.dwNumRequestedEUs        = m_hwInterface->m_numRequestedEus;
    cmdBuffer->Attributes.bValidPowerGatingRequest = true;

    if (frameTrackingRequested && m_frameTrackingEnabled)
    {
        cmdBuffer->Attributes.bEnableMediaFrameTracking        = true;
        cmdBuffer->Attributes.resMediaFrameTrackingSurface     =
            m_encodeStatusBuf.resStatusBuffer;
        cmdBuffer->Attributes.dwMediaFrameTrackingTag          = m_storeData;
        // Set media frame tracking address offset(the offset from the encoder status buffer page)
        cmdBuffer->Attributes.dwMediaFrameTrackingAddrOffset   = 0;
    }

#ifdef _MMC_SUPPORTED
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_mmcState->SendPrologCmd(m_miInterface, cmdBuffer, MOS_RCS_ENGINE_USED(gpuContext)));
#endif

    MHW_GENERIC_PROLOG_PARAMS genericPrologParams;
    MOS_ZeroMemory(&genericPrologParams, sizeof(genericPrologParams));
    genericPrologParams.pOsInterface            = m_osInterface;
    genericPrologParams.pvMiInterface     = m_miInterface;
    genericPrologParams.bMmcEnabled             = CodecHalMmcState::IsMmcEnabled();
    genericPrologParams.dwStoreDataValue = m_storeData - 1;
    CODECHAL_ENCODE_CHK_STATUS_RETURN(Mhw_SendGenericPrologCmd(cmdBuffer, &genericPrologParams));

    return eStatus;
}

MOS_STATUS CodechalEncoderState::UpdateCmdBufAttribute(
        PMOS_COMMAND_BUFFER cmdBuffer,
        bool                renderEngineInUse)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    return eStatus;
}

MOS_STATUS CodechalEncoderState::ExecuteEnc(
    EncoderParams* encodeParams)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    CODECHAL_ENCODE_CHK_NULL_RETURN(m_hwInterface->GetCpInterface());

    if (m_mfeEnabled == false || encodeParams->ExecCodecFunction == CODECHAL_FUNCTION_ENC
        || encodeParams->ExecCodecFunction == CODECHAL_FUNCTION_FEI_ENC)
    {
        // No need to wait if the driver is executing on a simulator
        EncodeStatusBuffer* pencodeStatusBuf = CodecHalUsesOnlyRenderEngine(m_codecFunction) ? &m_encodeStatusBufRcs : &m_encodeStatusBuf;
        if (!m_osInterface->bSimIsActive &&
            m_recycledBufStatusNum[m_currRecycledBufIdx] >
            *(pencodeStatusBuf->pData))
        {
            uint32_t waitMs;

            // Wait for Batch Buffer complete event OR timeout
            for (waitMs = MHW_TIMEOUT_MS_DEFAULT; waitMs > 0; waitMs -= MHW_EVENT_TIMEOUT_MS)
            {
                if (m_recycledBufStatusNum[m_currRecycledBufIdx] <= *(pencodeStatusBuf->pData))
                {
                    break;
                }

                MOS_Sleep(MHW_EVENT_TIMEOUT_MS);
            }

            CODECHAL_ENCODE_VERBOSEMESSAGE("Waited for %d ms", (MHW_TIMEOUT_MS_DEFAULT - waitMs));

            if (m_recycledBufStatusNum[m_currRecycledBufIdx] >
                *(pencodeStatusBuf->pData))
            {
                CODECHAL_ENCODE_ASSERTMESSAGE("No recycled buffers available, wait timed out at %d ms!", MHW_TIMEOUT_MS_DEFAULT);
                CODECHAL_ENCODE_ASSERTMESSAGE("m_storeData = %d, m_recycledBufStatusNum[%d] = %d, data = %d", m_storeData, m_currRecycledBufIdx, m_recycledBufStatusNum[m_currRecycledBufIdx], *(pencodeStatusBuf->pData));
                return MOS_STATUS_CLIENT_AR_NO_SPACE;
            }
        }

        m_recycledBufStatusNum[m_currRecycledBufIdx] = m_storeData;

        // These parameters are updated at the DDI level
        if (encodeParams->bMbDisableSkipMapEnabled)
        {
            CodecHalGetResourceInfo(m_osInterface, encodeParams->psMbDisableSkipMapSurface);
        }

        CODECHAL_ENCODE_CHK_NULL_RETURN(encodeParams->psRawSurface);
        CodecHalGetResourceInfo(m_osInterface, encodeParams->psRawSurface);
        if (encodeParams->bMbQpDataEnabled)
        {
            CodecHalGetResourceInfo(m_osInterface, encodeParams->psMbQpDataSurface);
        }

        if (m_standard != CODECHAL_JPEG)
        {
            CODECHAL_ENCODE_CHK_NULL_RETURN(encodeParams->psReconSurface);
            CodecHalGetResourceInfo(m_osInterface, encodeParams->psReconSurface);
        }

        m_encodeParams = *encodeParams;

        CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hwInterface->GetCpInterface()->UpdateParams(true));

        if (CodecHalUsesVideoEngine(m_codecFunction))
        {
            // Get resource details of the bitstream resource
            MOS_SURFACE details;
            MOS_ZeroMemory(&details, sizeof(details));
            details.Format = Format_Invalid;
            CODECHAL_ENCODE_CHK_NULL_RETURN(encodeParams->presBitstreamBuffer);
            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_osInterface->pfnGetResourceInfo(m_osInterface, encodeParams->presBitstreamBuffer, &details));

            m_encodeParams.dwBitstreamSize = details.dwHeight * details.dwWidth;
        }

        m_osInterface->pfnIncPerfFrameID(m_osInterface);

        // init function common to all codecs, before encode each frame
        CODECHAL_ENCODE_CHK_STATUS_RETURN(InitCommon());

        CODECHAL_ENCODE_CHK_STATUS_MESSAGE_RETURN(InitializePicture(m_encodeParams),
            "Encoding initialization failed.");

        if (m_newSeq)
        {
            CODECHAL_ENCODE_CHK_STATUS_RETURN(CheckResChangeAndCsc());
        }

        if (FRAME_SKIP_NORMAL == m_skipFrameFlag)
        {
            if (m_standard == CODECHAL_MPEG2)
            {
                CODECHAL_ENCODE_CHK_STATUS_MESSAGE_RETURN(EncodeCopySkipFrame(), "Skip-frame failed.\n");
                m_skipFrameFlag = FRAME_NO_SKIP;
                CODECHAL_ENCODE_CHK_STATUS_MESSAGE_RETURN(ResetStatusReport(), "Flushing encode status buffer for skipped frame failed.\n");
                m_firstFrame = false;
                return eStatus;
            }
        }

        // Check if source surface needs to be synchronized and should wait for decode or VPP or any other context
        MOS_SYNC_PARAMS syncParams = g_cInitSyncParams;
        syncParams.presSyncResource = &m_rawSurface.OsResource;
        syncParams.bReadOnly = true;

        if (CodecHalUsesRenderEngine(m_codecFunction, m_standard) &&
            m_firstField)
        {
            syncParams.GpuContext = m_renderContext;
            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_osInterface->pfnResourceWait(m_osInterface, &syncParams));

            if (CodecHalUsesVideoEngine(m_codecFunction))
            {
                // Perform Sync on PAK context if it is not ENC only case.
                // This is done to set the read mask for PAK context for on demand sync
                syncParams.GpuContext = m_videoContext;
                CODECHAL_ENCODE_CHK_STATUS_RETURN(m_osInterface->pfnResourceWait(m_osInterface, &syncParams));
            }
            // Update the resource tag (s/w tag) for On-Demand Sync
            // set the tag on render context for ENC case only, else set it on video context for ENC+PAK case
            m_osInterface->pfnSetResourceSyncTag(m_osInterface, &syncParams);
        }
        else if (CodecHalUsesVideoEngine(m_codecFunction))
        {
            // Perform resource sync for encode uses only video engine
            syncParams.GpuContext = m_videoContext;
            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_osInterface->pfnResourceWait(m_osInterface, &syncParams));
            m_osInterface->pfnSetResourceSyncTag(m_osInterface, &syncParams);
        }

        CODECHAL_ENCODE_CHK_NULL_RETURN(m_currRefList);

        if (CODECHAL_JPEG != m_standard &&  m_firstField)
        {
            for (int i = 0; i < m_currRefList->ucNumRef; i++)
            {
                CODECHAL_ENCODE_CHK_COND_RETURN(
                    m_currReconstructedPic.FrameIdx == m_currRefList->RefList[i].FrameIdx,
                    "the same frame (FrameIdx = %d) cannot be used as both Recon surface and ref frame",
                    m_currReconstructedPic.FrameIdx);
            }

            // clear flags
            m_currRefList->b2xScalingUsed =
            m_currRefList->b4xScalingUsed =
            m_currRefList->b16xScalingUsed =
            m_currRefList->b32xScalingUsed = false;

            // allocate tracked buffer for current frame
            CODECHAL_ENCODE_CHK_STATUS_RETURN(m_trackedBuf->AllocateForCurrFrame());
            m_currRefList->ucScalingIdx = m_trackedBuf->GetCurrIndex();

            if (m_trackedBuf->IsMbCodeAllocationNeeded())
            {
                // MbCode/MvData buffer can be tracked using the same index as DS surface
                m_currRefList->ucMbCodeIdx = m_currMbCodeIdx = m_trackedBuf->GetCurrIndexMbCode();

                m_resMbCodeSurface = m_currRefList->resRefMbCodeBuffer = *m_trackedBuf->GetCurrMbCodeBuffer();
                if (m_trackedBuf->GetCurrMvDataBuffer())
                {
                    m_resMvDataSurface = m_currRefList->resRefMvDataBuffer = *m_trackedBuf->GetCurrMvDataBuffer();
                }
            }
            else
            {
                CODECHAL_ENCODE_NORMALMESSAGE("App provides MbCode and MvData buffer!");
            }

            m_trackedBuf->SetAllocationFlag(false);
        }

        if (CodecHalUsesRenderEngine(m_codecFunction, m_standard))
        {
            // set render engine context
            m_osInterface->pfnSetGpuContext(m_osInterface, m_renderContext);
            m_osInterface->pfnResetOsStates(m_osInterface);

            // set all status reports to completed state
            InitStatusReport();

            // on-demand sync for tracked buffer
            syncParams = g_cInitSyncParams;
            syncParams.GpuContext = m_renderContext;
            syncParams.bReadOnly = false;
            if (m_trackedBuf->GetWait() && !Mos_ResourceIsNull(&m_resMbCodeSurface))
            {
                syncParams.presSyncResource = &m_resMbCodeSurface;
                CODECHAL_ENCODE_CHK_STATUS_RETURN(m_osInterface->pfnResourceWait(m_osInterface, &syncParams));
                m_osInterface->pfnSetResourceSyncTag(m_osInterface, &syncParams);
            }

            // Call ENC Kernels
            CODECHAL_ENCODE_CHK_STATUS_MESSAGE_RETURN(ExecuteKernelFunctions(),
                "ENC failed.");
        }
    }

    if (m_mfeEnabled == false || encodeParams->ExecCodecFunction == CODECHAL_FUNCTION_PAK
        || encodeParams->ExecCodecFunction == CODECHAL_FUNCTION_FEI_PAK)
    {
        CODECHAL_ENCODE_CHK_STATUS_RETURN(Mos_Solo_PreProcessEncode(m_osInterface, &m_resBitstreamBuffer, &m_reconSurface));

        if (CodecHalUsesVideoEngine(m_codecFunction))
        {
            // Set to video context
            m_osInterface->pfnSetGpuContext(m_osInterface, m_videoContext);
            m_osInterface->pfnResetOsStates(m_osInterface);
            m_currPass = 0;

            CODECHAL_ENCODE_CHK_STATUS_RETURN(VerifySpaceAvailable());

            for (m_currPass = 0; m_currPass <= m_numPasses; m_currPass++)
            {
                m_firstTaskInPhase = (m_currPass == 0);
                m_lastTaskInPhase = (m_currPass == m_numPasses);

                // Setup picture level PAK commands
                CODECHAL_ENCODE_CHK_STATUS_MESSAGE_RETURN(ExecutePictureLevel(),
                    "Picture level encoding failed.");

                // Setup slice level PAK commands
                CODECHAL_ENCODE_CHK_STATUS_MESSAGE_RETURN(ExecuteSliceLevel(),
                    "Slice level encoding failed.");

                m_lastTaskInPhase = false;
            }
        }

        // User Feature Key Reporting - only happens after first frame
        if (m_firstFrame == true)
        {
            CODECHAL_ENCODE_CHK_STATUS_MESSAGE_RETURN(UserFeatureKeyReport(),
                "Reporting user feature keys failed.");
        }

        m_currRecycledBufIdx =
            (m_currRecycledBufIdx + 1) % CODECHAL_ENCODE_RECYCLED_BUFFER_NUM;

        if (m_currRecycledBufIdx == 0)
        {
            MOS_ZeroMemory(m_recycledBufStatusNum, sizeof(m_recycledBufStatusNum));
        }

        // Flush encode eStatus buffer
        CODECHAL_ENCODE_CHK_STATUS_MESSAGE_RETURN(ResetStatusReport(),
            "Flushing encode eStatus buffer failed.");

        if (m_firstFrame == false && m_firstTwoFrames == true)
        {
            m_firstTwoFrames = false;
        }
        m_firstFrame = false;

        CODECHAL_ENCODE_CHK_STATUS_RETURN(Mos_Solo_PostProcessEncode(m_osInterface, &m_resBitstreamBuffer, &m_reconSurface));
    }
    return eStatus;
}

uint8_t CodechalEncoderState::GetNumBrcPakPasses(uint16_t usBRCPrecision)
{
    uint8_t numBRCPAKPasses = CODECHAL_ENCODE_BRC_DEFAULT_NUM_PASSES;

    switch (usBRCPrecision)
    {
    case 0:
    case 2:     numBRCPAKPasses = CODECHAL_ENCODE_BRC_DEFAULT_NUM_PASSES;
        break;

    case 1:     numBRCPAKPasses = CODECHAL_ENCODE_BRC_MINIMUM_NUM_PASSES;
        break;

    case 3:     numBRCPAKPasses = CODECHAL_ENCODE_BRC_MAXIMUM_NUM_PASSES;
        break;

    default:    CODECHAL_ENCODE_ASSERT("Invalid BRC Precision value in Pic Params.");
        numBRCPAKPasses = CODECHAL_ENCODE_BRC_DEFAULT_NUM_PASSES;
        break;
    }

    return numBRCPAKPasses;
}

CodechalEncoderGenState::CodechalEncoderGenState(CodechalEncoderState* encoder)
{
    CODECHAL_ENCODE_ASSERT(encoder);
    m_encoder = encoder;
    m_hwInterface = encoder->GetHwInterface();
    m_osInterface = encoder->GetOsInterface();
    m_miInterface = encoder->m_miInterface;
    m_renderEngineInterface = encoder->m_renderEngineInterface;
    m_stateHeapInterface = encoder->m_stateHeapInterface;
}

CodechalEncoderState::CodechalEncoderState(
    CodechalHwInterface* hwInterface,
    CodechalDebugInterface* debugInterface,
    PCODECHAL_STANDARD_INFO standardInfo):
    Codechal(hwInterface, debugInterface)
{
    // Add Null checks here for all interfaces.
    CODECHAL_ENCODE_CHK_NULL_NO_STATUS_RETURN(m_hwInterface);
    m_mfxInterface = m_hwInterface->GetMfxInterface();
    m_hcpInterface = m_hwInterface->GetHcpInterface();
    m_hucInterface = m_hwInterface->GetHucInterface();
    m_vdencInterface = m_hwInterface->GetVdencInterface();
    m_miInterface = hwInterface->GetMiInterface();
    m_renderEngineInterface = hwInterface->GetRenderInterface();
    CODECHAL_ENCODE_CHK_NULL_NO_STATUS_RETURN(m_renderEngineInterface);
    m_stateHeapInterface = m_renderEngineInterface->m_stateHeapInterface;
    CODECHAL_ENCODE_ASSERT(m_renderEngineInterface->GetHwCaps());

    CODECHAL_ENCODE_CHK_NULL_NO_STATUS_RETURN(m_osInterface);
    m_osInterface->pfnGetPlatform(m_osInterface, &m_platform);
    m_skuTable     = m_osInterface->pfnGetSkuTable(m_osInterface);
    m_waTable      = m_osInterface->pfnGetWaTable(m_osInterface);
    m_gtSystemInfo = m_osInterface->pfnGetGtSystemInfo(m_osInterface);
    m_videoGpuNode = MOS_GPU_NODE_MAX;
    m_renderContext = MOS_GPU_CONTEXT_INVALID_HANDLE;
    m_videoContext  = MOS_GPU_CONTEXT_INVALID_HANDLE;

    m_vdencEnabled = CodecHalUsesVdencEngine(standardInfo->CodecFunction);
    m_codecFunction = standardInfo->CodecFunction;

    m_vdencMeKernelState = MHW_KERNEL_STATE();
    m_vdencStreaminKernelState = MHW_KERNEL_STATE();
    for (auto i = 0; i < CODEC_NUM_FIELDS_PER_FRAME; i++)
    {
        m_scaling2xKernelStates[i] = MHW_KERNEL_STATE();
        m_scaling4xKernelStates[i] = MHW_KERNEL_STATE();
    }
    for (auto i = 0; i < CODECHAL_ENCODE_ME_IDX_NUM; i++)
    {
        m_meKernelStates[i] = MHW_KERNEL_STATE();
    }

    MOS_ZeroMemory(&m_encodeParams, sizeof(m_encodeParams));
    MOS_ZeroMemory(&m_resHwCount, sizeof(m_resHwCount));
    MOS_ZeroMemory(&m_rawSurface, sizeof(m_rawSurface));                // Pointer to MOS_SURFACE of raw surface
    MOS_ZeroMemory(&m_reconSurface, sizeof(m_reconSurface));              // Pointer to MOS_SURFACE of reconstructed surface
    MOS_ZeroMemory(&m_resBitstreamBuffer, sizeof(m_resBitstreamBuffer));         // Pointer to MOS_SURFACE of bitstream surface
    MOS_ZeroMemory(&m_resMbCodeSurface, sizeof(m_resMbCodeSurface));           // Pointer to MOS_SURFACE of MbCode surface
    MOS_ZeroMemory(&m_resMvDataSurface, sizeof(m_resMvDataSurface));           // Pointer to MOS_SURFACE of MvData surface

    MOS_ZeroMemory(&m_resSyncObjectRenderContextInUse, sizeof(m_resSyncObjectRenderContextInUse));
    MOS_ZeroMemory(&m_resSyncObjectVideoContextInUse, sizeof(m_resSyncObjectVideoContextInUse));
    MOS_ZeroMemory(&m_encodeStatusBuf, sizeof(m_encodeStatusBuf));                    // Stores all the status_query related data for PAK engine
    MOS_ZeroMemory(&m_encodeStatusBufRcs, sizeof(m_encodeStatusBufRcs));                 // Stores all the status_query related data for render ring (RCS)
    MOS_ZeroMemory(&m_imgStatusControlBuffer, sizeof(m_imgStatusControlBuffer));         // Stores image eStatus control data
    MOS_ZeroMemory(&m_atomicScratchBuf, sizeof(m_atomicScratchBuf));             // Stores atomic operands and result
    MOS_ZeroMemory(&m_bsBuffer, sizeof(m_bsBuffer));

    MOS_ZeroMemory(&m_resVdencCmdInitializerDmemBuffer, sizeof(m_resVdencCmdInitializerDmemBuffer));
    MOS_ZeroMemory(&m_resVdencCmdInitializerDataBuffer, sizeof(m_resVdencCmdInitializerDataBuffer));

    MOS_ZeroMemory(&m_resDistortionBuffer, sizeof(m_resDistortionBuffer));        // MBEnc Distortion Buffer
    for (auto i = 0; i < CODECHAL_ENCODE_MAX_NUM_MAD_BUFFERS; i++)
    {
        MOS_ZeroMemory(&m_resMadDataBuffer[i], sizeof(m_resMadDataBuffer[i])); // Buffers to store Mean of Absolute Differences
    }
    for (auto i = 0; i < CODECHAL_ENCODE_RECYCLED_BUFFER_NUM; i++)
    {
        MOS_ZeroMemory(&m_sliceMapSurface[i], sizeof(m_sliceMapSurface[i]));
    }

    for (auto i = 0; i < CODECHAL_ENCODE_RECYCLED_BUFFER_NUM; i++)
    {
        MOS_ZeroMemory(&m_resVdencStreamInBuffer[i], sizeof(m_resVdencStreamInBuffer[i]));
    }
    MOS_ZeroMemory(&m_resPakMmioBuffer, sizeof(m_resPakMmioBuffer));
    MOS_ZeroMemory(&m_resHucStatus2Buffer, sizeof(m_resHucStatus2Buffer));
    MOS_ZeroMemory(&m_resHucFwBuffer, sizeof(m_resHucFwBuffer));

    MOS_ZeroMemory(&m_resDeblockingFilterRowStoreScratchBuffer, sizeof(m_resDeblockingFilterRowStoreScratchBuffer));               // Handle of deblock row store surface
    MOS_ZeroMemory(&m_resMPCRowStoreScratchBuffer, sizeof(m_resMPCRowStoreScratchBuffer));                            // Handle of mpc row store surface
    for (auto i = 0; i < CODECHAL_ENCODE_RECYCLED_BUFFER_NUM; i++)
    {
        MOS_ZeroMemory(&m_resStreamOutBuffer[i], sizeof(m_resStreamOutBuffer[i]));    // Handle of streamout data surface
    }

    MOS_ZeroMemory(&m_scaling4xBindingTable, sizeof(m_scaling4xBindingTable));
    MOS_ZeroMemory(&m_scaling2xBindingTable, sizeof(m_scaling2xBindingTable));
    for (auto i = 0; i < CODECHAL_ENCODE_VME_BBUF_NUM; i++)
    {
        MOS_ZeroMemory(&m_scalingBBUF[i], sizeof(m_scalingBBUF[i]));          // This Batch Buffer is used for scaling kernel.
    }
    MOS_ZeroMemory(&m_flatnessCheckSurface, sizeof(m_flatnessCheckSurface));
    MOS_ZeroMemory(&m_resMbStatisticsSurface, sizeof(m_resMbStatisticsSurface));
    MOS_ZeroMemory(&m_resMbStatsBuffer, sizeof(m_resMbStatsBuffer));

    MOS_ZeroMemory(&m_meBindingTable, sizeof(m_meBindingTable));

    MOS_ZeroMemory(&m_vdencMeKernelBindingTable, sizeof(m_vdencMeKernelBindingTable));

    MOS_ZeroMemory(&m_vdencStreaminKernelBindingTable, sizeof(m_vdencStreaminKernelBindingTable));
}

CodechalEncoderState::~CodechalEncoderState()
{
    if (m_gpuCtxCreatOpt)
    {
        MOS_Delete(m_gpuCtxCreatOpt);
        m_gpuCtxCreatOpt = nullptr;
    }

    DestroyMDFResources();

    if (m_perfProfiler)
    {
        MediaPerfProfiler::Destroy(m_perfProfiler, (void*)this, m_osInterface);
        m_perfProfiler = nullptr;
    }
}

#if USE_CODECHAL_DEBUG_TOOL
MOS_STATUS CodechalEncoderState::DumpMbEncPakOutput(PCODEC_REF_LIST currRefList, CodechalDebugInterface* debugInterface)
{
    CODECHAL_ENCODE_FUNCTION_ENTER;
    CODECHAL_ENCODE_CHK_NULL_RETURN(currRefList);
    CODECHAL_ENCODE_CHK_NULL_RETURN(debugInterface);

    CODECHAL_ENCODE_CHK_STATUS_RETURN(debugInterface->DumpBuffer(
            &currRefList->resRefMbCodeBuffer,
            CodechalDbgAttr::attrOutput,
            "MbCode",
            m_picWidthInMb * m_frameFieldHeightInMb * 64,
            CodecHal_PictureIsBottomField(currRefList->RefPic) ? m_frameFieldHeightInMb * m_picWidthInMb * 64 : 0,
            (m_codecFunction != CODECHAL_FUNCTION_HYBRIDPAK) ?
            CODECHAL_MEDIA_STATE_ENC_NORMAL : CODECHAL_MEDIA_STATE_HYBRID_PAK_P2));

    if (m_mvDataSize)
    {
        CODECHAL_ENCODE_CHK_STATUS_RETURN(debugInterface->DumpBuffer(
            &currRefList->resRefMvDataBuffer,
            CodechalDbgAttr::attrOutput,
            "MbData",
            m_picWidthInMb * m_frameFieldHeightInMb * (32 * 4),
            CodecHal_PictureIsBottomField(currRefList->RefPic) ? MOS_ALIGN_CEIL(m_frameFieldHeightInMb * m_picWidthInMb * (32 * 4), 0x1000) : 0,
            (m_codecFunction != CODECHAL_FUNCTION_HYBRIDPAK) ?
            CODECHAL_MEDIA_STATE_ENC_NORMAL : CODECHAL_MEDIA_STATE_HYBRID_PAK_P2));
    }
    if (CodecHalIsFeiEncode(m_codecFunction))
    {
        CODECHAL_ENCODE_CHK_STATUS_RETURN(debugInterface->DumpBuffer(
            &m_resDistortionBuffer,
            CodechalDbgAttr::attrOutput,
            "DistortionSurf",
            m_picWidthInMb * m_frameFieldHeightInMb * 48,
            CodecHal_PictureIsBottomField(currRefList->RefPic) ? MOS_ALIGN_CEIL(m_frameFieldHeightInMb * m_picWidthInMb * 48, 0x1000) : 0,
            (m_codecFunction != CODECHAL_FUNCTION_HYBRIDPAK) ?
            CODECHAL_MEDIA_STATE_ENC_NORMAL : CODECHAL_MEDIA_STATE_HYBRID_PAK_P2));
    }
    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodechalEncoderState::AddBufferWithIMMValue(
    PMOS_COMMAND_BUFFER         cmdBuffer,
    PMOS_RESOURCE               presStoreBuffer,
    uint32_t                    offset,
    uint32_t                    value,
    bool                        bAdd)
{
    MHW_MI_STORE_REGISTER_MEM_PARAMS    StoreRegParams;
    MHW_MI_STORE_DATA_PARAMS            StoreDataParams;
    MHW_MI_LOAD_REGISTER_REG_PARAMS     LoadRegRegParams;
    MHW_MI_LOAD_REGISTER_IMM_PARAMS     LoadRegisterImmParams;
    MHW_MI_FLUSH_DW_PARAMS              FlushDwParams;
    MHW_MI_MATH_PARAMS                  MiMathParams;
    MHW_MI_ALU_PARAMS                   MiAluParams[4];
    MOS_STATUS                          eStatus = MOS_STATUS_SUCCESS;

    CODECHAL_ENCODE_FUNCTION_ENTER;

    if (m_vdboxIndex > m_mfxInterface->GetMaxVdboxIndex())                                                                         \
    {
        CODECHAL_ENCODE_ASSERTMESSAGE("ERROR - vdbox index exceed the maximum");
        eStatus = MOS_STATUS_INVALID_PARAMETER;
        return eStatus;
    }

    auto pMmioRegistersMfx = m_mfxInterface->GetMmioRegisters(m_vdboxIndex);
    auto pMmioRegistersHcp = m_hcpInterface->GetMmioRegisters(m_vdboxIndex);

    MOS_ZeroMemory(&FlushDwParams, sizeof(FlushDwParams));
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiFlushDwCmd(cmdBuffer, &FlushDwParams));

    MOS_ZeroMemory(&LoadRegRegParams, sizeof(LoadRegRegParams));

    MHW_MI_LOAD_REGISTER_MEM_PARAMS miLoadRegMemParams;
    MOS_ZeroMemory(&miLoadRegMemParams, sizeof(miLoadRegMemParams));

    miLoadRegMemParams.presStoreBuffer = presStoreBuffer;
    miLoadRegMemParams.dwOffset = offset;
    miLoadRegMemParams.dwRegister = pMmioRegistersMfx->generalPurposeRegister0LoOffset;
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiLoadRegisterMemCmd(cmdBuffer, &miLoadRegMemParams));

    MOS_ZeroMemory(&LoadRegisterImmParams, sizeof(LoadRegisterImmParams));
    LoadRegisterImmParams.dwData = 0;
    LoadRegisterImmParams.dwRegister = pMmioRegistersMfx->generalPurposeRegister0HiOffset;
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiLoadRegisterImmCmd(
        cmdBuffer,
        &LoadRegisterImmParams));

    MOS_ZeroMemory(&LoadRegisterImmParams, sizeof(LoadRegisterImmParams));
    LoadRegisterImmParams.dwData = value;
    LoadRegisterImmParams.dwRegister = pMmioRegistersMfx->generalPurposeRegister4LoOffset;
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiLoadRegisterImmCmd(
        cmdBuffer,
        &LoadRegisterImmParams));
    MOS_ZeroMemory(&LoadRegisterImmParams, sizeof(LoadRegisterImmParams));
    LoadRegisterImmParams.dwData = 0;
    LoadRegisterImmParams.dwRegister = pMmioRegistersMfx->generalPurposeRegister4HiOffset;
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiLoadRegisterImmCmd(
        cmdBuffer,
        &LoadRegisterImmParams));

    MOS_ZeroMemory(&MiMathParams, sizeof(MiMathParams));
    MOS_ZeroMemory(&MiAluParams, sizeof(MiAluParams));
    // load     srcA, reg0
    MiAluParams[0].AluOpcode = MHW_MI_ALU_LOAD;
    MiAluParams[0].Operand1 = MHW_MI_ALU_SRCA;
    MiAluParams[0].Operand2 = MHW_MI_ALU_GPREG0;
    // load     srcB, reg4
    MiAluParams[1].AluOpcode = MHW_MI_ALU_LOAD;
    MiAluParams[1].Operand1 = MHW_MI_ALU_SRCB;
    MiAluParams[1].Operand2 = MHW_MI_ALU_GPREG4;

    if (bAdd)
    {
        // add      srcA, srcB
        MiAluParams[2].AluOpcode = MHW_MI_ALU_ADD;
    }
    else
    {
        // sub      srcA, srcB
        MiAluParams[2].AluOpcode = MHW_MI_ALU_SUB;
    }

    // store      reg0, ACCU
    MiAluParams[3].AluOpcode = MHW_MI_ALU_STORE;
    MiAluParams[3].Operand1 = MHW_MI_ALU_GPREG0;
    MiAluParams[3].Operand2 = MHW_MI_ALU_ACCU;

    MiMathParams.pAluPayload = MiAluParams;
    MiMathParams.dwNumAluParams = 4; // four ALU commands needed for this substract opertaion. see following ALU commands.
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiMathCmd(
        cmdBuffer,
        &MiMathParams));

    // update the value
    MOS_ZeroMemory(&StoreRegParams, sizeof(StoreRegParams));
    StoreRegParams.presStoreBuffer = presStoreBuffer;
    StoreRegParams.dwOffset = offset;
    StoreRegParams.dwRegister = pMmioRegistersMfx->generalPurposeRegister0LoOffset;
    CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiStoreRegisterMemCmd(cmdBuffer, &StoreRegParams));

    return eStatus;
}
#endif
