/*
* Copyright (c) 2015-2020, Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
//!
//! \file      renderhal_dsh.cpp 
//! \brief         This module implements render engine state heap management functions based     on dynamic state heap (DSH) infrastructure, rather than static state heap.     It allows dynamic allocation and expansion of general state heap (media states)     and instraction state heaps (media kernels) based on demand. It also allows     dynamic configuration of media states based on specific workload requirements,     as well as dynamic allocation of kernel scratch space (spill area). 
//!
#include "renderhal_legacy.h"
#include "renderhal_platform_interface.h"

// Defined in renderhal.c
extern const RENDERHAL_SURFACE_STATE_ENTRY g_cInitSurfaceStateEntry;

MOS_STATUS RenderHal_AllocateDebugSurface(
    PRENDERHAL_INTERFACE     pRenderHal);

//!
//! \brief    Extend the media state pool
//! \details  Extends the media state pool by adding 16 media state objects
//! \param    PRENDERHAL_STATE_HEAP pStateHeap
//!           [in] Pointer to the state heap
//! \return   MOS_STATUS
//!           SUCCESS    if media state pool was successfully extended
//!           NO_SPACE   if the pool of objects cannot be extended
//!
MOS_STATUS RenderHal_DSH_ExtendMediaStatePool(
    PRENDERHAL_STATE_HEAP pStateHeap)
{
    int32_t iSize;
    uint8_t *pPtr;
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    //---------------------------------------
    MHW_RENDERHAL_CHK_NULL_RETURN(pStateHeap);
    MHW_RENDERHAL_CHK_NULL_RETURN(pStateHeap->pMediaStatesMemPool);
    //---------------------------------------

    int32_t iCount = RENDERHAL_DSH_DYN_STATE_INC;

    // Extend pool and get pointer to first element of the new pool object
    PRENDERHAL_MEDIA_STATE_LEGACY      pFirst, pLast, pPrev;
    PRENDERHAL_MEDIA_STATE_LIST pList = &pStateHeap->FreeStates;

    uint32_t ID = pStateHeap->pMediaStatesMemPool->m_dwObjCount;
    pLast = pFirst = (PRENDERHAL_MEDIA_STATE_LEGACY)(pStateHeap->pMediaStatesMemPool->Allocate(iCount));
    if (!pLast)
    {
        eStatus = MOS_STATUS_NO_SPACE;
        goto finish;
    }

    // Increment size of the list
    pList->iCount += iCount;

    // Initialize new doubled linked list and internal structure
    iSize = pStateHeap->pMediaStatesMemPool->m_dwObjSize; // enough for media state and dynamic state objects
    pPtr  = (uint8_t*) pFirst;
    for (pPrev = nullptr; iCount > 0; iCount--, pPtr += iSize, pPrev = pLast)
    {
        // Create doubled linked list
        pLast = (PRENDERHAL_MEDIA_STATE_LEGACY) pPtr;
        pLast->Reserved = ID++;
        pLast->pPrev    = pPrev;
        if (pPrev) pPrev->pNext = pLast;

        // Point to dynamic states (co-located)
        pLast->pDynamicState = (PRENDERHAL_DYNAMIC_STATE) (pLast + 1);
    }
    pLast->pNext = nullptr;

    // Attach to end of existing pool
    pFirst->pPrev = pList->pTail;
    pList->pTail  = pLast;
    if (pFirst->pPrev)
        pFirst->pPrev->pNext = pFirst;
    else
        pList->pHead = pFirst;

finish:
    return eStatus;
}

//!
//! \brief    Get a media state from the pool
//! \details  Returns a pointer to a media state from the pool
//!           If pool is empty, the pool is extended (adds 16 media states)
//! \param    PRENDERHAL_STATE_HEAP pStateHeap
//!           [in] Pointer to the state heap
//! \return   PRENDERHAL_MEDIA_STATE pointer to a media state
//!
PRENDERHAL_MEDIA_STATE RenderHal_DSH_GetMediaStateFromPool(
    PRENDERHAL_STATE_HEAP pStateHeap)
{
    MOS_STATUS             eStatus;
    PRENDERHAL_MEDIA_STATE pMediaState = nullptr;

    //---------------------------------------
    if (pStateHeap == nullptr)
    {
        MHW_RENDERHAL_ASSERTMESSAGE("Null pointer detected!");
        return nullptr;
    }
    //---------------------------------------

    PRENDERHAL_MEDIA_STATE_LIST pList = &pStateHeap->FreeStates;

    // If pool is empty, extend pool of free media states
    if (pList->iCount == 0)
    {
        MHW_RENDERHAL_CHK_STATUS(RenderHal_DSH_ExtendMediaStatePool(pStateHeap));
    }

    // Get Element from the head of the list
    pMediaState = pList->pHead;

    // Detach element from the list
    if (pMediaState)
    {
        pList->iCount--;
        pList->pHead = pMediaState->pNext;
        if (pMediaState->pNext)
        {
            pMediaState->pNext->pPrev = nullptr;
        }
        else
        {   // List is now empty - last element was removed
            pList->pTail = nullptr;
            MHW_ASSERT(pList->iCount == 0);
        }

        pMediaState->pNext = pMediaState->pPrev = nullptr;
    }

finish:
    return pMediaState;
}

//!
//! \brief    Returns a media state to the pool
//! \details  Returns the media state to the pool list
//! \param    PRENDERHAL_STATE_HEAP pStateHeap
//!           [in] Pointer to the state heap
//! \param    PRENDERHAL_MEDIA_STATE  pMediaState
//!           [in] Pointer to the media state
//! \return   NONE
//!
void RenderHal_DSH_ReturnMediaStateToPool(
    PRENDERHAL_STATE_HEAP   pStateHeap,
    PRENDERHAL_MEDIA_STATE  pMediaState)
{
    //---------------------------------------
    MHW_RENDERHAL_CHK_NULL_NO_STATUS_RETURN(pStateHeap);
    MHW_RENDERHAL_CHK_NULL_NO_STATUS_RETURN(pMediaState);
    //---------------------------------------

    PRENDERHAL_MEDIA_STATE_LIST pList = &pStateHeap->FreeStates;

    // Attach element to the head of the list
    pMediaState->pPrev = pList->pTail;
    pList->pTail = pMediaState;
    if (pMediaState->pPrev)
    {
        pMediaState->pPrev->pNext = pMediaState;
    }
    else
    {   // List was empty - insert first element
        MHW_ASSERT(pList->iCount == 0);
        pList->pHead = pMediaState;
    }
    pList->iCount++;

    return;
}

//!
//! \brief    Extend the kernel allocation pool
//! \details  Extends the kernel allocation pool by adding 16 kernel allocations
//! \param    PRENDERHAL_STATE_HEAP pStateHeap
//!           [in] Pointer to the state heap
//! \return   MOS_STATUS
//!           SUCCESS    if kernel allocation pool was successfully extended
//!           NO_SPACE   if the pool of objects cannot be extended
//!
MOS_STATUS RenderHal_DSH_ExtendKernelAllocPool(
    PRENDERHAL_STATE_HEAP pStateHeap)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    //---------------------------------------
    MHW_RENDERHAL_CHK_NULL_RETURN(pStateHeap);
    MHW_RENDERHAL_CHK_NULL_RETURN(pStateHeap->pKernelAllocMemPool);
    //---------------------------------------

    int32_t iCount = RENDERHAL_DSH_KRN_ALLOC_INC;

    // Extend pool and get pointer to first element of the new pool object
    PRENDERHAL_KRN_ALLOCATION   pFirst, pLast;
    PRENDERHAL_KRN_ALLOC_LIST   pList = &pStateHeap->KernelAllocationPool;

    uint32_t ObjID = pStateHeap->pKernelAllocMemPool->m_dwObjCount;
    pLast = pFirst = (PRENDERHAL_KRN_ALLOCATION)(pStateHeap->pKernelAllocMemPool->Allocate(iCount));

    if (!pLast)
    {
        eStatus = MOS_STATUS_NO_SPACE;
        goto finish;
    }

    // Increment size of the list
    pList->iCount += iCount;

    // Initialize new doubled linked list
    for ( ; iCount > 0; iCount--, pLast++)
    {
        pLast->Reserved = ObjID++;
        pLast->pPrev = pLast - 1;
        pLast->pNext = pLast + 1;
        pLast->pList = pList;
        pLast->szKernelName = nullptr;
    }
    pLast--;
    pLast->pNext = nullptr;

    // Attach to end of existing pool
    pFirst->pPrev = pList->pTail;
    pList->pTail  = pLast;
    if (pFirst->pPrev)
    {
        pFirst->pPrev->pNext = pFirst;
    }
    else
    {
        pList->pHead = pFirst;
    }

finish:
    return eStatus;
}

//!
//! \brief    Detach kernel allocation
//! \details  Removes the kernel allocation from the current list
//! \param    PRENDERHAL_KRN_ALLOCATION pKernel
//!           [in] Pointer to the kernel allocation
//! \return   NONE
//!
void RenderHal_DSH_KernelDetach(PRENDERHAL_KRN_ALLOCATION pKernel)
{
    PRENDERHAL_KRN_ALLOC_LIST pList;

    if (!pKernel || !pKernel->pList) return;
    pList = pKernel->pList;

    // Kernel is last in its list
    if (pKernel->pNext == nullptr)
    {
        pList->pTail = pKernel->pPrev;
    }
    else
    {
        pKernel->pNext->pPrev = pKernel->pPrev;
    }

    // Kernel is first in its list
    if (pKernel->pPrev == nullptr)
    {
        pList->pHead = pKernel->pNext;
    }
    else
    {
        pKernel->pPrev->pNext = pKernel->pNext;
    }

    pKernel->pNext = nullptr;
    pKernel->pPrev = nullptr;
    pKernel->pList = nullptr;
    pList->iCount--;
}

//!
//! \brief    Removes kernel allocation from current list and attaches to designated list
//! \details  Removes the kernel allocation from the current list (pKernel->pList)
//|           and attaches kernel to pList (passed in as a parameter)
//! \param    PRENDERHAL_KRN_ALLOC_LIST pList
//!           [in] Pointer to the kernel allocation list to attach to
//! \param    PRENDERHAL_KRN_ALLOCATION pKernel
//!           [in] Pointer to the kernel allocation
//! \param    bool bHead
//!           [in] Indicates whether to attach to head of list or tail
//! \return   NONE
//!
void RenderHal_DSH_KernelAttach(PRENDERHAL_KRN_ALLOC_LIST pList, PRENDERHAL_KRN_ALLOCATION pKernel, bool bHead)
{
    if (!pList || !pKernel) return;

    // Detach from current list
    if (pKernel->pList)
    {
        RenderHal_DSH_KernelDetach(pKernel);
    }

    if (bHead)
    {
        pKernel->pPrev = nullptr;
        pKernel->pNext = pList->pHead;
        pList->pHead   = pKernel;
        if (pKernel->pNext)
        {
            pKernel->pNext->pPrev = pKernel;
        }
        else
        {
            pList->pTail = pKernel;
        }
    }
    else
    {
        pKernel->pPrev = pList->pTail;
        pKernel->pNext = nullptr;
        pList->pTail   = pKernel;
        if (pKernel->pPrev)
        {
            pKernel->pPrev->pNext = pKernel;
        }
        else
        {
            pList->pHead = pKernel;
        }
    }

    pKernel->pList = pList;
    pList->iCount++;
}

//!
//! \brief    Get a kernel allocation from the pool
//! \details  Returns a pointer to the kernel allocation from the pool
//!           If pool is empty, the pool is extended (adds 16 kernel allocations)
//! \param    PRENDERHAL_STATE_HEAP pStateHeap
//!           [in] Pointer to the state heap
//! \return   PRENDERHAL_KRN_ALLOCATION pointer to a kernel allocation
//!
PRENDERHAL_KRN_ALLOCATION RenderHal_DSH_GetKernelAllocationFromPool(PRENDERHAL_STATE_HEAP pStateHeap)
{
    MOS_STATUS                eStatus = MOS_STATUS_SUCCESS;
    PRENDERHAL_KRN_ALLOCATION pKernelAllocation = nullptr;

    MHW_RENDERHAL_CHK_NULL(pStateHeap);

    if (pStateHeap->KernelAllocationPool.iCount == 0)
    {
        MHW_RENDERHAL_CHK_STATUS(RenderHal_DSH_ExtendKernelAllocPool(pStateHeap));
    }

    pKernelAllocation = pStateHeap->KernelAllocationPool.pHead;
    RenderHal_DSH_KernelDetach(pKernelAllocation);

finish:
    return pKernelAllocation;
}

//!
//! \brief    Touch dynamic kernel
//! \details  Updates sync tag on kernel allocation
//!           Moves kernel to the tail of the pStateHeap->KernelsSubmitted list
//!           Submits the dynamic memory block
//!           Updates kernel usage
//! \param    PRENDERHAL_INTERFACE      pRenderHal
//!           [in] Pointer to the renderhal interface
//! \param    PRENDERHAL_KRN_ALLOCATION pKernelAllocation
//!           [in] Pointer to the kernel allocation
//! \return   NONE
//!
void RenderHal_DSH_TouchDynamicKernel(
    PRENDERHAL_INTERFACE      pRenderHal,
    PRENDERHAL_KRN_ALLOCATION pKernelAllocation)
{
    PRENDERHAL_STATE_HEAP      pStateHeap;
    PXMHW_STATE_HEAP_INTERFACE pMhwStateHeap;

    if (pRenderHal == nullptr || pRenderHal->pStateHeap == nullptr || pKernelAllocation == nullptr)
    {
        return;
    }

    pStateHeap    = pRenderHal->pStateHeap;
    pMhwStateHeap = pRenderHal->pMhwStateHeap;

    // Set sync tag, for deallocation control
    pKernelAllocation->dwFlags = RENDERHAL_KERNEL_ALLOCATION_LOCKED;
    FrameTrackerTokenFlat_SetProducer(&pKernelAllocation->trackerToken, &pRenderHal->trackerProducer);
    FrameTrackerTokenFlat_Merge(&pKernelAllocation->trackerToken,
                                pRenderHal->currentTrackerIndex,
                                pRenderHal->trackerProducer.GetNextTracker(pRenderHal->currentTrackerIndex));

    // Move kernel to the tail of the submitted list (list is sorted with the most recently used at the end)
    RenderHal_DSH_KernelAttach(&pStateHeap->KernelsSubmitted, pKernelAllocation, false);

    // Update memory block
    pMhwStateHeap->SubmitDynamicBlockDyn(MHW_ISH_TYPE, pKernelAllocation->pMemoryBlock, &pKernelAllocation->trackerToken);

    // Update kernel usage - this is where kernels age if they are not constantly used, and may be removed
    pKernelAllocation->dwCount++;
}

//!
//! \brief    Searches the hash table for the kernel
//! \details  Searches the hash table for the kernel using the UniqID and CacheID to determine if the
//!           kernel is already allocated in the ISH
//! \param    PRENDERHAL_INTERFACE      pRenderHal
//!           [in] Pointer to the renderhal interface
//! \param    int32_t iUniqID
//!           [in] unique kernel identifier
//! \param    int32_t iCacheID
//!           [in] cache identifier
//! \return   PRENDERHAL_KRN_ALLOCATION
//!           pKernelAllocation    if kernel is found in hash table
//!           nullptr              otherwise
//!
PRENDERHAL_KRN_ALLOCATION RenderHal_DSH_SearchDynamicKernel(PRENDERHAL_INTERFACE pRenderHal, int32_t iUniqID, int32_t iCacheID)
{
    PRENDERHAL_STATE_HEAP_LEGACY    pStateHeap;
    PRENDERHAL_KRN_ALLOCATION       pKernelAllocation = nullptr;

    pStateHeap = (pRenderHal) ? ((PRENDERHAL_STATE_HEAP_LEGACY)pRenderHal->pStateHeap) : nullptr;
    if (pStateHeap)
    {
        uint16_t wSearchIndex = 0;
        pKernelAllocation = (PRENDERHAL_KRN_ALLOCATION) pStateHeap->kernelHashTable.Search(iUniqID, iCacheID, wSearchIndex);
    }

    return pKernelAllocation;
}

//!
//! \brief    Allocates a kernel allocation
//! \details  Searches the hash table for the kernel and if not found
//!           gets a kernel allocation from the pool then
//!           registers it in the hash table and attaches it to the allocated list
//!           returns a pointer to the kernel allocation
//! \param    PRENDERHAL_INTERFACE      pRenderHal
//!           [in] Pointer to the renderhal interface
//! \param    int32_t iUniqID
//!           [in] unique kernel identifier
//! \param    int32_t iCacheID
//!           [in] cache identifier
//! \return   PRENDERHAL_KRN_ALLOCATION
//!
PRENDERHAL_KRN_ALLOCATION RenderHal_DSH_AllocateDynamicKernel(PRENDERHAL_INTERFACE pRenderHal, int32_t iUniqID, int32_t iCacheID)
{
    PRENDERHAL_STATE_HEAP_LEGACY    pStateHeap;
    PRENDERHAL_KRN_ALLOCATION       pKernelAllocation = nullptr;
    uint16_t                        wSearchIndex = 0;
    MOS_STATUS                      eStatus = MOS_STATUS_SUCCESS;

    pStateHeap = (pRenderHal) ? ((PRENDERHAL_STATE_HEAP_LEGACY)pRenderHal->pStateHeap) : nullptr;
    if (pStateHeap == nullptr)
    {
        goto finish;
    }

    pKernelAllocation = (PRENDERHAL_KRN_ALLOCATION)pStateHeap->kernelHashTable.Search(iUniqID, iCacheID, wSearchIndex);

    if (!pKernelAllocation)
    {
        // Get new kernel allocation entry
        pKernelAllocation = RenderHal_DSH_GetKernelAllocationFromPool(pStateHeap);
        MHW_RENDERHAL_CHK_NULL(pKernelAllocation);

        // Clear kernel allocation entry, setup kernel uniq id
        uint32_t Reserved = pKernelAllocation->Reserved; // Preserve before
        MOS_ZeroMemory(pKernelAllocation, sizeof(RENDERHAL_KRN_ALLOCATION));
        pKernelAllocation->dwFlags  = RENDERHAL_KERNEL_ALLOCATION_FREE;    // Krn allocation does not point to a kernel
        pKernelAllocation->Reserved = Reserved;
        pKernelAllocation->iKUID    = iUniqID;
        pKernelAllocation->iKCID    = iCacheID;

        // Register kernel in hash table to speed up future search
        pStateHeap->kernelHashTable.Register(iUniqID, iCacheID, pKernelAllocation);

        // Insert kernel in allocated list
        RenderHal_DSH_KernelAttach(&pStateHeap->KernelsAllocated, pKernelAllocation, false);
    }

finish:
    return pKernelAllocation;
}

//!
//! \brief    Unregister a kernel
//! \details  Frees the memory block of the kernel in the ISH
//!           removes the kernel from the hash table and
//!           attaches the kernel to the allocation pool
//! \param    PRENDERHAL_INTERFACE      pRenderHal
//!           [in] Pointer to the renderhal interface
//! \param    PRENDERHAL_KRN_ALLOCATION pKernelAllocation
//!           [in] Pointer to the kernel allocation
//! \return   MOS_STATUS
//!
MOS_STATUS RenderHal_DSH_UnregisterKernel(PRENDERHAL_INTERFACE pRenderHal, PRENDERHAL_KRN_ALLOCATION pKernelAllocation)
{
    PRENDERHAL_STATE_HEAP_LEGACY    pStateHeap;
    MOS_STATUS                      eStatus = MOS_STATUS_SUCCESS;

    pStateHeap = (pRenderHal) ? ((PRENDERHAL_STATE_HEAP_LEGACY)pRenderHal->pStateHeap) : nullptr;
    if (pStateHeap == nullptr)
    {
        goto finish;
    }

    // Free kernel before releasing
    if (pKernelAllocation->pMemoryBlock)
    {
        // Get new kernel allocation entry
        pRenderHal->pMhwStateHeap->FreeDynamicBlockDyn(MHW_ISH_TYPE, pKernelAllocation->pMemoryBlock);
        pKernelAllocation->pMemoryBlock = nullptr;
    }

    pStateHeap->kernelHashTable.Unregister(pKernelAllocation->iKUID, pKernelAllocation->iKCID);

    // Return the kernel allocation to pool
    RenderHal_DSH_KernelAttach(&pStateHeap->KernelAllocationPool, pKernelAllocation, false);

finish:
    return eStatus;
}

//!
//! \brief    Allocate GSH, SSH, ISH control structures and heaps
//! \details  Allocates State Heap control structure (system memory)
//!           and associated State Buffer in gfx/sys memory (GSH,ISH,SSH)
//!           initializes the State Heap control structure and state buffers
//!
//! \param    PRENDERHAL_INTERFACE pRenderHal
//!           [in] Pointer to Rendering Interface Structure
//! \param    PRENDERHAL_STATE_HEAP_SETTINGS pSettings
//!           [in] Pointer to state heap settings (GSH/SSH/ISH)
//! \return   MOS_STATUS
//!           SUCCESS if state heaps were successfully allocated and initialized
//!           OTHER   if bad parameters or allocation failed
//!
MOS_STATUS RenderHal_DSH_AllocateStateHeaps(
    PRENDERHAL_INTERFACE           pRenderHal,
    PRENDERHAL_STATE_HEAP_SETTINGS pSettings)
{
    MHW_STATE_HEAP_SETTINGS      MhwStateHeapSettings;
    PXMHW_STATE_HEAP_INTERFACE   pMhwStateHeap;
    MhwRenderInterface           *pMhwRender;
    PMHW_RENDER_STATE_SIZES      pHwSizes;
    PRENDERHAL_STATE_HEAP        pStateHeap = nullptr;
    MOS_STATUS                   eStatus;
    int32_t                      iSize;
    PRENDERHAL_INTERFACE_LEGACY  pRenderHalLegacy = (PRENDERHAL_INTERFACE_LEGACY)pRenderHal;
    // Initialize locals
    eStatus          = MOS_STATUS_UNKNOWN;

    //---------------------------------------
    MHW_RENDERHAL_CHK_NULL(pRenderHalLegacy);
    MHW_RENDERHAL_CHK_NULL(pRenderHalLegacy->pOsInterface);
    MHW_RENDERHAL_CHK_NULL(pRenderHalLegacy->pMhwRenderInterface);
    MHW_RENDERHAL_CHK_NULL(pRenderHalLegacy->pStateHeap);
    MHW_RENDERHAL_CHK_NULL(pSettings);

    // verify GSH parameters and alignments
    MHW_RENDERHAL_ASSERT((pSettings->iSyncSize        % RENDERHAL_SYNC_BLOCK_ALIGN)   == 0);
    MHW_RENDERHAL_ASSERT((pSettings->iCurbeSize       % RENDERHAL_URB_BLOCK_ALIGN)    == 0);
    MHW_RENDERHAL_ASSERT((pSettings->iKernelHeapSize  % RENDERHAL_KERNEL_BLOCK_ALIGN) == 0);
    MHW_RENDERHAL_ASSERT((pSettings->iKernelBlockSize % RENDERHAL_KERNEL_BLOCK_ALIGN) == 0);
    // verify SSH parameters
    MHW_RENDERHAL_ASSERT(pSettings->iBindingTables >= RENDERHAL_SSH_BINDING_TABLES_MIN);
    MHW_RENDERHAL_ASSERT(pSettings->iBindingTables <= RENDERHAL_SSH_BINDING_TABLES_MAX);
    MHW_RENDERHAL_ASSERT(pSettings->iSurfaceStates >= RENDERHAL_SSH_SURFACE_STATES_MIN);
    MHW_RENDERHAL_ASSERT(pSettings->iSurfaceStates <= RENDERHAL_SSH_SURFACE_STATES_MAX);
    MHW_RENDERHAL_ASSERT(pSettings->iSurfacesPerBT >= RENDERHAL_SSH_SURFACES_PER_BT_MIN);
    MHW_RENDERHAL_ASSERT(pSettings->iSurfacesPerBT <= RENDERHAL_SSH_SURFACES_PER_BT_MAX);
    //---------------------------------------

    pMhwRender  = pRenderHalLegacy->pMhwRenderInterface;
    pStateHeap  = pRenderHalLegacy->pStateHeap;
    pHwSizes    = pRenderHalLegacy->pHwSizes;

    // Reset media state lists
    MOS_ZeroMemory(&pStateHeap->FreeStates           , sizeof(RENDERHAL_MEDIA_STATE_LIST));
    MOS_ZeroMemory(&pStateHeap->ReservedStates       , sizeof(RENDERHAL_MEDIA_STATE_LIST));
    MOS_ZeroMemory(&pStateHeap->SubmittedStates      , sizeof(RENDERHAL_MEDIA_STATE_LIST));
    MOS_ZeroMemory(&pStateHeap->KernelsAllocated     , sizeof(RENDERHAL_KRN_ALLOC_LIST));
    MOS_ZeroMemory(&pStateHeap->KernelsSubmitted     , sizeof(RENDERHAL_KRN_ALLOC_LIST));
    MOS_ZeroMemory(&pStateHeap->KernelAllocationPool , sizeof(RENDERHAL_KRN_ALLOC_LIST));

    // Create pool of media state objects
    iSize = sizeof(RENDERHAL_MEDIA_STATE_LEGACY) + sizeof(RENDERHAL_DYNAMIC_STATE) + 16; // Media state object + Dynamic states object (co-located)

    pStateHeap->pMediaStatesMemPool = MOS_New(MHW_MEMORY_POOL, iSize, sizeof(void *));
    MHW_RENDERHAL_CHK_NULL(pStateHeap->pMediaStatesMemPool);

    MHW_RENDERHAL_CHK_STATUS(RenderHal_DSH_ExtendMediaStatePool(pStateHeap));

    //-------------------------------------------------------------------------
    // Calculate offsets/sizes in GSH
    //-------------------------------------------------------------------------
    // Synchronization, debugging data
    pStateHeap->dwOffsetSync = 0;
    pStateHeap->dwSizeSync   = pSettings->iSyncSize;

    // Synchronization
    pStateHeap->dwNextTag    = 0;
    pStateHeap->dwSyncTag    = 0;
    pStateHeap->dwFrameId    = 0;

    //----------------------------------
    // Instruction State Heap
    //----------------------------------
    // Kernel Spill Area - allocated on demand
    pStateHeap->dwScratchSpaceSize = 0;

    //----------------------------------
    // Surface State Heap
    //----------------------------------
    // Reset initial SSH allocations
    pStateHeap->iCurSshBufferIndex    = 0;
    pStateHeap->iCurrentBindingTable  = 0;
    pStateHeap->iCurrentSurfaceState  = 0;

    // Calculate size of each Binding Table
    pStateHeap->iBindingTableSize =
        MOS_ALIGN_CEIL(pSettings->iSurfacesPerBT * pHwSizes->dwSizeBindingTableState, pSettings->iBTAlignment);

    // Calculate memory size to store all binding tables and surface states
    pStateHeap->dwSizeSSH = pSettings->iBindingTables * pStateHeap->iBindingTableSize +
                            pSettings->iSurfaceStates *
                            pRenderHalLegacy->pRenderHalPltInterface->GetSurfaceStateCmdSize();
    pRenderHalLegacy->dwIndirectHeapSize = MOS_ALIGN_CEIL(pStateHeap->dwSizeSSH, MHW_PAGE_SIZE);

    // Allocate local copy of SSH
    pStateHeap->pSshBuffer = (uint8_t*)MOS_AllocAndZeroMemory(pStateHeap->dwSizeSSH);
    if (!pStateHeap->pSshBuffer)
    {
        MHW_RENDERHAL_ASSERTMESSAGE("Fail to Allocate SSH buffer.");
        eStatus = MOS_STATUS_NO_SPACE;
        goto finish;
    }

    pStateHeap->iBindingTableOffset  = 0;
    pStateHeap->iSurfaceStateOffset  = pSettings->iBindingTables * pStateHeap->iBindingTableSize;
    pStateHeap->pSurfaceEntry        = (PRENDERHAL_SURFACE_STATE_ENTRY) MOS_AllocAndZeroMemory(pSettings->iSurfaceStates * sizeof(RENDERHAL_SURFACE_STATE_ENTRY));
    MHW_RENDERHAL_CHK_NULL(pStateHeap->pSurfaceEntry);

    //----------------------------------
    // Allocate Instruction State Heap in MHW
    //----------------------------------
    MhwStateHeapSettings.dwIshSize         = pRenderHalLegacy->DynamicHeapSettings.dwIshInitialSize;
    MhwStateHeapSettings.m_keepIshLocked   = true;
    MhwStateHeapSettings.dwNumSyncTags     = pSettings->iSyncSize;
    MhwStateHeapSettings.dwIshIncrement    = pRenderHalLegacy->DynamicHeapSettings.dwIshSizeIncrement;
    MhwStateHeapSettings.dwIshMaxSize      = pRenderHalLegacy->DynamicHeapSettings.dwIshMaximumSize;

    MHW_RENDERHAL_CHK_STATUS(pMhwRender->AllocateHeaps(MhwStateHeapSettings));
    MHW_RENDERHAL_CHK_NULL(pMhwRender->m_stateHeapInterface);
    pMhwStateHeap = pRenderHalLegacy->pMhwStateHeap = pMhwRender->m_stateHeapInterface->pStateHeapInterface;

    // Size of a Media ID entry
    pStateHeap->dwSizeMediaID = pHwSizes->dwSizeInterfaceDescriptor;

    // Not used in Dynamic mode - heaps may change
    Mos_ResetResource(&pStateHeap->GshOsResource);
    pStateHeap->pGshBuffer = nullptr;
    pStateHeap->bGshLocked = false;

    Mos_ResetResource(&pStateHeap->IshOsResource);
    pStateHeap->pIshBuffer = nullptr;
    pStateHeap->bIshLocked = false;

    // Setup pointer to sync tags
    pStateHeap->pSync = (uint32_t *)pRenderHalLegacy->pMhwStateHeap->GetCmdBufIdGlobalPointer();

    // Reset pool of Kernel allocations objects
    pStateHeap->pKernelAllocMemPool = MOS_New(MHW_MEMORY_POOL,
                                sizeof(RENDERHAL_KRN_ALLOCATION),
                                sizeof(void *));
    MHW_RENDERHAL_CHK_NULL(pStateHeap->pKernelAllocMemPool);

    MHW_RENDERHAL_CHK_STATUS(RenderHal_DSH_ExtendKernelAllocPool(pStateHeap));

    eStatus = MOS_STATUS_SUCCESS;

finish:
    if (eStatus != MOS_STATUS_SUCCESS)
    {
        // Free SSH buffer
        if (pStateHeap)
        {
            if (pStateHeap->pSurfaceEntry)
            {
                MOS_FreeMemory(pStateHeap->pSurfaceEntry);
            }

            if (pStateHeap->pSshBuffer)
            {
                MOS_FreeMemory(pStateHeap->pSshBuffer);
            }
        }
    }

    return eStatus;
}

//!
//! \brief    Free State Heaps (including MHW interfaces)
//! \details  Free State Heap resources allocated by RenderHal
//! \param    PRENDERHAL_INTERFACE pRenderHal
//!           [in] Pointer to Render Hal Interface
//! \return   MOS_STATUS
//!
MOS_STATUS RenderHal_DSH_FreeStateHeaps(PRENDERHAL_INTERFACE pRenderHal)
{
    PMOS_INTERFACE                  pOsInterface;
    PRENDERHAL_STATE_HEAP_LEGACY    pStateHeap;
    MOS_STATUS                      eStatus;

    //------------------------------------------------
    MHW_RENDERHAL_CHK_NULL(pRenderHal);
    MHW_RENDERHAL_CHK_NULL(pRenderHal->pOsInterface);
    MHW_RENDERHAL_CHK_NULL(pRenderHal->pStateHeap);
    //------------------------------------------------

    eStatus      = MOS_STATUS_UNKNOWN;

    pOsInterface = pRenderHal->pOsInterface;
    pStateHeap   = (PRENDERHAL_STATE_HEAP_LEGACY)pRenderHal->pStateHeap;

    // Free Surface State Entries
    if (pStateHeap->pSurfaceEntry)
    {
        // Free MOS surface in surface state entry
        for (int32_t index = 0; index < pRenderHal->StateHeapSettings.iSurfaceStates; ++index) {
            PRENDERHAL_SURFACE_STATE_ENTRY entry = pStateHeap->pSurfaceEntry + index;
            MOS_SafeFreeMemory(entry->pSurface);
            entry->pSurface = nullptr;
        }

        MOS_FreeMemory(pStateHeap->pSurfaceEntry);
        pStateHeap->pSurfaceEntry = nullptr;
    }

    // Free SSH Resource
    if (pStateHeap->pSshBuffer)
    {
        MOS_FreeMemory(pStateHeap->pSshBuffer);
        pStateHeap->pSshBuffer = nullptr;
    }

    if(pStateHeap->pMediaStatesMemPool)
    {
        MOS_Delete(pStateHeap->pMediaStatesMemPool);
        pStateHeap->pMediaStatesMemPool = nullptr;
    }

    if(pStateHeap->pKernelAllocMemPool)
    {
        MOS_Delete(pStateHeap->pKernelAllocMemPool);
        pStateHeap->pKernelAllocMemPool = nullptr;
    }

    // Free kernel hash table
    pStateHeap->kernelHashTable.Free();

    // Free State Heap Control structure
    MOS_AlignedFreeMemory(pStateHeap);
    pRenderHal->pStateHeap = nullptr;

    pRenderHal->pRenderHalPltInterface->FreeScratchSpaceBuffer(pRenderHal);

    eStatus = MOS_STATUS_SUCCESS;

finish:
    return eStatus;
}

//!
//! \brief    Assign memory block in state heap
//! \param    RENDERHAL_TR_RESOURCE trackerInfo
//!           [in] Pointer to tracker resource
//! \param    HeapManager heapManager
//!           [in] Pointer to heap manager
//! \param    MemoryBlock block
//!           [out] Pointer to memory block
//! \param    uint32_t size
//!           [in] size of requested memory block
//! \return   MOS_STATUS
//!
MOS_STATUS RenderHal_DSH_AssignSpaceInStateHeap(
    uint32_t trackerIndex,
    FrameTrackerProducer *trackerProducer,
    HeapManager *heapManager,
    MemoryBlock *block,
    uint32_t size)
{
    MOS_STATUS eStatus     = MOS_STATUS_SUCCESS;
    uint32_t   spaceNeeded = 0;
    std::vector<MemoryBlock> blocks;
    std::vector<uint32_t> blockSizes;

    MemoryBlockManager::AcquireParams acquireParams = 
        MemoryBlockManager::AcquireParams(trackerProducer->GetNextTracker(trackerIndex),
                                          blockSizes);
    acquireParams.m_trackerIndex = trackerIndex; // use the first tracker only

    MHW_RENDERHAL_CHK_NULL(heapManager);    
    MHW_RENDERHAL_CHK_NULL(block);
    MHW_RENDERHAL_CHK_NULL(trackerProducer);

    if (blockSizes.empty())
    {
        blockSizes.emplace_back(size);
    }
    else
    {
        blockSizes[0] = size;
    }

    MHW_RENDERHAL_CHK_STATUS(heapManager->AcquireSpace(acquireParams, blocks, spaceNeeded));

    if (blocks.empty())
    {
        MHW_RENDERHAL_ASSERTMESSAGE("No blocks were acquired");
        return MOS_STATUS_UNKNOWN;
    }
    if (!(blocks[0].IsValid()))
    {
        MHW_RENDERHAL_ASSERTMESSAGE("No blocks were acquired");
        return MOS_STATUS_UNKNOWN;
    }

    *block = blocks[0];

    // zero memory block
    block->AddData(nullptr, 0, 0, true);

finish:
    return eStatus;
}

//!
//! \brief    Refresh Sync
//! \details  Update Sync tags
//! \param    PRENDERHAL_INTERFACE pRenderHal
//!           [in] Pointer to Hardware Interface Structure
//! \return   MOS_STATUS
//!
MOS_STATUS RenderHal_DSH_RefreshSync(PRENDERHAL_INTERFACE pRenderHal)
{
    PRENDERHAL_STATE_HEAP       pStateHeap;
    PRENDERHAL_MEDIA_STATE      pCurMediaState;
    PRENDERHAL_MEDIA_STATE      pNextMediaState;
    PRENDERHAL_DYNAMIC_STATE    pDynamicState;
    PMHW_BATCH_BUFFER           pBatchBuffer;
    uint32_t                    dwCurrentTag;
    uint32_t                    dwCurrentFrameId;
    int32_t                     iStatesInUse;
    int32_t                     iBuffersInUse;
    int32_t                     iKernelsInUse;
    MOS_STATUS                  eStatus;
    MOS_NULL_RENDERING_FLAGS    NullRenderingFlags;
    PXMHW_STATE_HEAP_INTERFACE  pMhwStateHeap;
    PRENDERHAL_MEDIA_STATE_LIST pList;
    PRENDERHAL_KRN_ALLOCATION   pKrnAllocation, pNext;

    //----------------------------------
    MHW_RENDERHAL_CHK_NULL(pRenderHal);
    MHW_RENDERHAL_CHK_NULL(pRenderHal->pStateHeap);
    MHW_RENDERHAL_CHK_NULL(pRenderHal->pMhwStateHeap);
    //----------------------------------

    eStatus         = MOS_STATUS_UNKNOWN;

    // GSH must be locked
    pStateHeap    = pRenderHal->pStateHeap;
    pMhwStateHeap = pRenderHal->pMhwStateHeap;
    if (!pMhwStateHeap->GetCmdBufIdGlobalPointer())
    {
        goto finish;
    }

    // Most recent tags
    pStateHeap->dwSyncTag = dwCurrentTag     = pStateHeap->pSync[0];

    // Refresh batch buffers
    iBuffersInUse = 0;
    pBatchBuffer  = pRenderHal->pBatchBufferList;

    NullRenderingFlags  = pRenderHal->pOsInterface->pfnGetNullHWRenderFlags(pRenderHal->pOsInterface);

    for (; pBatchBuffer != nullptr; pBatchBuffer = pBatchBuffer->pNext)
    {
        if (!pBatchBuffer->bBusy) continue;

        // Clear BB busy flag when Sync Tag is reached
        if ((int32_t)(dwCurrentTag - pBatchBuffer->dwSyncTag) > 0 ||
            NullRenderingFlags.VPGobal)
        {
            pBatchBuffer->bBusy = false;
        }
        else
        {
            iBuffersInUse++;
        }
    }

    // Refresh media states
    pList = &(pStateHeap->SubmittedStates);

    pNextMediaState = nullptr;
    pCurMediaState  = pList->pHead;
    iStatesInUse    = 0;
    for (; pCurMediaState != nullptr; pCurMediaState = pNextMediaState)
    {
        // Save next media state before moving current state back to pool (if complete)
        pNextMediaState = pCurMediaState->pNext;

        if (!pCurMediaState->bBusy) continue;

        // The condition below is valid when sync tag wraps from 2^32-1 to 0
        if (FrameTrackerTokenFlat_IsExpired(&pCurMediaState->trackerToken))
        {
            PRENDERHAL_MEDIA_STATE_LEGACY pCurMediaStateLegacy = (PRENDERHAL_MEDIA_STATE_LEGACY)pCurMediaState;
            pDynamicState = pCurMediaStateLegacy->pDynamicState;
            pCurMediaState->bBusy = false;
            if (pRenderHal->bKerneltimeDump)
            {
                uint64_t uiNS;
                uint8_t *pCurrentPtr;
                uint64_t uiStartTime;
                uint64_t uiEndTime;
                uint64_t uiDiff;
                double  TimeMS;
                uint32_t uiComponent;
                uint32_t performanceSize = sizeof(uint64_t) * 2 + sizeof(RENDERHAL_COMPONENT);
                uint8_t *data = (uint8_t*)MOS_AllocAndZeroMemory(performanceSize);
                if (data == nullptr)
                {
                    eStatus = MOS_STATUS_NO_SPACE;
                    goto finish;
                }
                // Dump Kernel execution time when media state is being freed
                pDynamicState->memoryBlock.ReadData(data, pDynamicState->Performance.dwOffset, performanceSize);
                pCurrentPtr = data;
                uiStartTime = *((uint64_t *)pCurrentPtr);
                pCurrentPtr += sizeof(uint64_t);
                uiEndTime = *((uint64_t *)pCurrentPtr);
                pCurrentPtr += sizeof(uint64_t);
                uiComponent = *((RENDERHAL_COMPONENT *)pCurrentPtr);
                if (uiComponent < (uint32_t)RENDERHAL_COMPONENT_COUNT)
                {
                    // Convert ticks to ns
                    uiDiff = uiEndTime - uiStartTime;
                    uiNS = 0;
                    pRenderHal->pfnConvertToNanoSeconds(pRenderHal, uiDiff, &uiNS);

                    TimeMS = ((double)uiNS) / (1000 * 1000); // Convert to ms (double)

                    pRenderHal->kernelTime[uiComponent] += TimeMS;
                }

                MOS_SafeFreeMemory(data);
            }

            // Detach from submitted states, return to pool
            *((pCurMediaState->pNext) ? &(pCurMediaState->pNext->pPrev) : &(pList->pTail)) = pCurMediaState->pPrev;
            *((pCurMediaState->pPrev) ? &(pCurMediaState->pPrev->pNext) : &(pList->pHead)) = pCurMediaState->pNext;
            pCurMediaState->pPrev = pCurMediaState->pNext = nullptr;
            pList->iCount--;

            // Return media state object back to pool
            RenderHal_DSH_ReturnMediaStateToPool(pStateHeap, pCurMediaState);
        }
        else
        {
            iStatesInUse++;
        }
    }

    // Refresh kernels
    iKernelsInUse  = 0;
    pKrnAllocation = pStateHeap->KernelsSubmitted.pHead;
    for ( ; pKrnAllocation != nullptr; pKrnAllocation = pNext)
    {
        pNext = pKrnAllocation->pNext;

        // Move kernels back to allocated list (kernel remains cached)
        if (FrameTrackerTokenFlat_IsExpired(&pKrnAllocation->trackerToken))
        {
            RenderHal_DSH_KernelAttach(&pStateHeap->KernelsAllocated, pKrnAllocation, false);

            // Kernel block is flagged for removal (growing ISH) - delete block, mark kernel as stale
            if (pKrnAllocation->pMemoryBlock && pKrnAllocation->pMemoryBlock->bDelete)
            {
                pMhwStateHeap->FreeDynamicBlockDyn(MHW_ISH_TYPE, pKrnAllocation->pMemoryBlock);
                pKrnAllocation->dwFlags = RENDERHAL_KERNEL_ALLOCATION_USED;
            }
            else
            {
                // Mark kernel as in use, not locked
                pKrnAllocation->dwFlags = RENDERHAL_KERNEL_ALLOCATION_USED;
            }
        }
        else
        {
            iKernelsInUse++;
        }
    }

    // Refresh blocks
    pMhwStateHeap->RefreshDynamicHeapDyn(MHW_ISH_TYPE);

    // Save number of states/buffers in use
    pRenderHal->iBuffersInUse     = iBuffersInUse;
    pRenderHal->iKernelsInUse     = iKernelsInUse;
    pRenderHal->iMediaStatesInUse = iStatesInUse;

    eStatus = MOS_STATUS_SUCCESS;

finish:
    return eStatus;
}

//!
//! \brief    Extend the kernel state heap
//! \details  Increases the size of the ISH (up to the maximum size)
//!           Flags all submitted and allocated kernels as "stale" so can reload into new heap
//!           Allocates new ISH and deletes old heap
//!           Moves SIP binary to new heap
//! \param    PRENDERHAL_STATE_HEAP pStateHeap
//!           [in] Pointer to the state heap
//! \param    uint32_t dwAdditionalKernelSpaceNeeded
//!           [in] amount of additional space needed for kernel
//! \return   MOS_STATUS
//!
MOS_STATUS RenderHal_DSH_ExpandKernelStateHeap(
    PRENDERHAL_INTERFACE pRenderHal,
    uint32_t             dwAdditionalKernelSpaceNeeded)
{
    PXMHW_STATE_HEAP_INTERFACE pMhwStateHeap;
    PRENDERHAL_KRN_ALLOCATION pKrnAllocation;
    PRENDERHAL_STATE_HEAP     pStateHeap;
    uint32_t                  dwNewSize;
    MOS_STATUS                eStatus = MOS_STATUS_SUCCESS;
    PMHW_STATE_HEAP              pOldInstructionHeap;
    PMHW_STATE_HEAP_MEMORY_BLOCK pOldSipKernelBlock;
    PRENDERHAL_INTERFACE_LEGACY pRenderHalLegacy = static_cast<PRENDERHAL_INTERFACE_LEGACY>(pRenderHal);

    MHW_RENDERHAL_CHK_NULL(pRenderHalLegacy);
    MHW_RENDERHAL_CHK_NULL(pRenderHalLegacy->pStateHeap);
    MHW_RENDERHAL_CHK_NULL(pRenderHalLegacy->pMhwStateHeap);

    pMhwStateHeap = pRenderHalLegacy->pMhwStateHeap;
    pStateHeap    = pRenderHalLegacy->pStateHeap;

    // Increase size of the ISH (up to max size)
    dwNewSize = MOS_ALIGN_CEIL(pMhwStateHeap->GetISHPointer()->dwSize + dwAdditionalKernelSpaceNeeded,
                               pRenderHalLegacy->DynamicHeapSettings.dwIshSizeIncrement);
    if (dwNewSize > pRenderHalLegacy->DynamicHeapSettings.dwIshMaximumSize)
    {
        goto finish;
    }

    // Flag all submitted kernels as "stale", so they can be reloaded into the new heap
    for (pKrnAllocation = pStateHeap->KernelsSubmitted.pHead; pKrnAllocation != nullptr; pKrnAllocation = pKrnAllocation->pNext)
    {
        pKrnAllocation->dwFlags = RENDERHAL_KERNEL_ALLOCATION_STALE;
        if (pKrnAllocation->pMemoryBlock)
        {
            pKrnAllocation->pMemoryBlock->bStatic = false;
            MHW_RENDERHAL_CHK_STATUS(pMhwStateHeap->FreeDynamicBlockDyn(MHW_ISH_TYPE, pKrnAllocation->pMemoryBlock));
            pKrnAllocation->pMemoryBlock = nullptr;
        }
    }

    // Flag all kernels allocated as "stale", so they can be reloaded into the new heap
    for (pKrnAllocation = pStateHeap->KernelsAllocated.pHead; pKrnAllocation != nullptr; pKrnAllocation = pKrnAllocation->pNext)
    {
        pKrnAllocation->dwFlags = RENDERHAL_KERNEL_ALLOCATION_STALE;
        if (pKrnAllocation->pMemoryBlock)
        {
            MHW_RENDERHAL_CHK_STATUS(pMhwStateHeap->FreeDynamicBlockDyn(MHW_ISH_TYPE, pKrnAllocation->pMemoryBlock));
            pKrnAllocation->pMemoryBlock = nullptr;
        }
    }

    // Get SIP kernel block prior to expansion
    // NOTE: SIP kernel block is NOT associated with any KRN allocation and will be freed after copying to the new heap
    pOldInstructionHeap = pMhwStateHeap->GetISHPointer();
    pOldSipKernelBlock  = pOldInstructionHeap->pDebugKernel;

    // Allocate new instruction state heap
    MHW_RENDERHAL_CHK_STATUS(pMhwStateHeap->ExtendStateHeap(MHW_ISH_TYPE, dwNewSize));

    // Copy SIP kernel into the newly loaded ISH, mark old SIP block to be released when no longer in use
    if (pOldSipKernelBlock)
    {
        MHW_RENDERHAL_CHK_STATUS(pRenderHalLegacy->pfnLoadSipKernel(pRenderHalLegacy, pOldSipKernelBlock->pDataPtr, pOldSipKernelBlock->dwDataSize));
        pOldSipKernelBlock->bStatic = false;
        pOldInstructionHeap->pDebugKernel = nullptr;
    }

    // Free old instruction state heap
    MHW_RENDERHAL_CHK_STATUS(pMhwStateHeap->ReleaseStateHeapDyn(pOldInstructionHeap));

finish:
    return eStatus;
}

//!
//! \brief    Refresh available space in Dynamic ISH, create space by either unloading
//!           expired kernels or expanding the ISH (up to its max size)
//! \details  Refresh space in Dynamic ISH, creating contiguous space for kernel load
//! \param    PRENDERHAL_INTERFACE pRenderHal
//!           [in] Pointer to Hardware Interface Structure
//! \param    uint32_t dwSpaceNeeded
//!           [in] Space needed in dynamic ISH for new kernel to be loaded
//! \return   MOS_STATUS
//!
MOS_STATUS RenderHal_DSH_RefreshDynamicKernels(
    PRENDERHAL_INTERFACE        pRenderHal,
    uint32_t                    dwSpaceNeeded,
    uint32_t                    *pdwSizes,
    int32_t                     iCount)
{
    uint32_t                            TempArray[1] = { dwSpaceNeeded };
    MHW_STATE_HEAP_DYNAMIC_ALLOC_PARAMS Params;
    PRENDERHAL_STATE_HEAP               pStateHeap;
    PXMHW_STATE_HEAP_INTERFACE          pMhwStateHeap;
    PRENDERHAL_KRN_ALLOCATION           pKrnAllocation, pNext;
    MOS_STATUS                          eStatus = MOS_STATUS_SUCCESS;

    MHW_RENDERHAL_CHK_NULL(pRenderHal);
    MHW_RENDERHAL_CHK_NULL(pRenderHal->pStateHeap);
    MHW_RENDERHAL_CHK_NULL(pRenderHal->pMhwStateHeap);

    pStateHeap    = pRenderHal->pStateHeap;
    pMhwStateHeap = pRenderHal->pMhwStateHeap;

    // Release move kernels from submitted back to allocated list according to Sync Tag
    pRenderHal->pfnRefreshSync(pRenderHal);

    // No block sizes provided, assume that the space requested must be contiguous
    if (!pdwSizes)
    {
        pdwSizes = TempArray;
        iCount   = 1;
    }

    // The function below will calculate how much space is still needed in state heap
    // considering the size of the blocks provided. This function accounts for fragmentation,
    // so even if the heap has enough space, the call may still return a non-zero value.

    Params.piSizes       = (int32_t*)pdwSizes;
    Params.iCount        = iCount;
    Params.dwAlignment   = 0;
    Params.bHeapAffinity = true;
    Params.pHeapAffinity = pMhwStateHeap->GetISHPointer(); // only search for space in active heap
    Params.dwScratchSpace= 0;

    dwSpaceNeeded = pMhwStateHeap->CalculateSpaceNeededDyn(MHW_ISH_TYPE, &Params);

    // Implementation note:
    // Kernels are moved from the KernelsAllocated list to the KernelsSubmitted
    // list whenever they are used via pfnTouchDynamicKernel function. When complete
    // they are moved back to end end of the KernelsAllocated list via pfnRefreshSync.
    // As a result, the allocation list is always sorted based on recent usage
    // (older kernels remain at the head of the list)
    //
    // The caching algorithm tries to find a balance between amount of times
    // the kernels was used, and how recently it was used - so kernels that are
    // heavily used but at the beginning of the list are less likely to be removed
    // compared with a kernel that was barely used (dwCount)
    //
    // IMPORTANT - Only one kernel allocation entry per Kernel UID (1:1 mapping)
    //

    pKrnAllocation = pStateHeap->KernelsAllocated.pHead;
    for ( ; (pKrnAllocation != nullptr) && (dwSpaceNeeded > 0); pKrnAllocation = pNext)
    {
        pNext = pKrnAllocation->pNext;

        if (pKrnAllocation->pMemoryBlock && pKrnAllocation->dwFlags != RENDERHAL_KERNEL_ALLOCATION_LOCKED)
        {
            // Only count this as available space if the block is in current heap!
            if (pKrnAllocation->pMemoryBlock->pStateHeap == pMhwStateHeap->GetISHPointer())
            {
                dwSpaceNeeded -= MOS_MIN(dwSpaceNeeded, pKrnAllocation->pMemoryBlock->dwBlockSize);
            }

            MHW_RENDERHAL_CHK_STATUS(pMhwStateHeap->FreeDynamicBlockDyn(MHW_ISH_TYPE, pKrnAllocation->pMemoryBlock));
            pKrnAllocation->pMemoryBlock = nullptr;
            pKrnAllocation->dwOffset     = 0;
            pKrnAllocation->dwFlags      = RENDERHAL_KERNEL_ALLOCATION_REMOVED;
        }
    }

    // Failed to remove enough kernels
    if (dwSpaceNeeded > 0)
    {
        eStatus = MOS_STATUS_UNKNOWN;
    }

finish:
    return eStatus;
}

void RenderHal_DSH_ResetDynamicKernels(
    PRENDERHAL_INTERFACE        pRenderHal)
{
    return;
}

//!
//! \brief    Load Kernel using dynamic state heap model
//! \details  Load a kernel from cache into GSH; do not unload kernels
//! \param    PRENDERHAL_INTERFACE pRenderHal
//!           [in] Pointer to Hardware Interface Structure
//! \param    PCRENDERHAL_KERNEL_PARAM pParameters
//!           [in] Pointer to Kernel Parameters
//! \param    PMHW_KERNEL_PARAMS pKernel
//!           [in] Pointer to Kernel entry
//! \param    Kdll_CacheEntry pKernelEntry
//!           [in] The cache entry pointer maintaining the load status.
//!                For cache entries from local variable,
//!                set it to nullptr to avoid memory corruption
//! \return   int32_t
//!           Index to a kernel allocation index
//!           -1 if invalid parameters, no available space and no
//!            deallocation possible
//!
PRENDERHAL_KRN_ALLOCATION RenderHal_DSH_LoadDynamicKernel(
    PRENDERHAL_INTERFACE        pRenderHal,
    PCRENDERHAL_KERNEL_PARAM    pParameters,
    PMHW_KERNEL_PARAM           pKernel,
    uint32_t                    *pdwLoaded)
{
    MHW_STATE_HEAP_DYNAMIC_ALLOC_PARAMS Params;              // Block allocation parameters
    PRENDERHAL_STATE_HEAP_LEGACY        pStateHeap;          // Renderhal State Heap control structure
    PXMHW_STATE_HEAP_INTERFACE   pMhwStateHeap;              // Dynamic MHW state heap interface
    PRENDERHAL_KRN_ALLOCATION    pKernelAllocation = nullptr;   // Kernel Allocation
    PMHW_STATE_HEAP_MEMORY_BLOCK pKernelMemoryBlock;         // Memory block in ISH where kernel is loaded
    int32_t                      iKernelSize;                // Kernel size
    int32_t                      iKernelUniqueID;            // Kernel unique ID
    int32_t                      iKernelCacheID;             // Kernel cache ID
    uint16_t                     wSearchIndex = 0;
    MOS_STATUS                   eStatus = MOS_STATUS_SUCCESS;

    MHW_RENDERHAL_CHK_NULL(pRenderHal);
    MHW_RENDERHAL_CHK_NULL(pRenderHal->pStateHeap);
    MHW_RENDERHAL_CHK_NULL(pParameters);
    MHW_RENDERHAL_CHK_NULL(pKernel);

    pStateHeap = (PRENDERHAL_STATE_HEAP_LEGACY)pRenderHal->pStateHeap;
    pMhwStateHeap = pRenderHal->pMhwStateHeap;

    // Validate parameters
    if (pKernel->iSize == 0)
    {
        eStatus = MOS_STATUS_INVALID_PARAMETER;
        MHW_RENDERHAL_NORMALMESSAGE("Failed to load kernel - invalid parameters.");
        goto finish;
    }

    // Kernel parameters
    iKernelSize     = pKernel->iSize;
    iKernelUniqueID = pKernel->iKUID;
    iKernelCacheID  = pKernel->iKCID;

    pKernelAllocation = (PRENDERHAL_KRN_ALLOCATION)pStateHeap->kernelHashTable.Search(iKernelUniqueID, iKernelCacheID, wSearchIndex);

    // Kernel already loaded
    if (pKernelAllocation)
    {
        // found match and Update kernel usage
        pRenderHal->pfnTouchDynamicKernel(pRenderHal, pKernelAllocation);

        // Increment reference counter
        pKernel->bLoaded = 1;

        goto finish;
    }

    // Get new kernel allocation entry
    pKernelAllocation = RenderHal_DSH_GetKernelAllocationFromPool(pRenderHal->pStateHeap);
    MHW_RENDERHAL_CHK_NULL(pKernelAllocation);

    // Simple allocation - get next kernel allocation entry available from pool

    // Prepare Media State Allocation in DSH
    Params.piSizes          = &iKernelSize;
    Params.iCount           = 1;
    Params.dwAlignment      = RENDERHAL_KERNEL_BLOCK_ALIGN;
    Params.bHeapAffinity    = 0;
    Params.pHeapAffinity    = 0;
    Params.dwScratchSpace   = 0;
    Params.pScratchSpace    = nullptr;
    Params.bZeroAssignedMem = 0;
    Params.bStatic          = true;
    Params.bGrow            = 0;

    pKernelMemoryBlock = pMhwStateHeap->AllocateDynamicBlockDyn(MHW_ISH_TYPE, &Params);

    // Here is where the dynamic state heap comes into play - by expanding ISH on demand to load a new kernel (ISH can literally start from size 0)
    if (!pKernelMemoryBlock)
    {
        // Extend ISH, making enough room to load the new kernel
        MHW_RENDERHAL_CHK_STATUS(RenderHal_DSH_ExpandKernelStateHeap(pRenderHal, iKernelSize));

        // Try again to load the kernel - this should now work, unless something went wrong with the allocation (max size reached)
        pKernelMemoryBlock = pMhwStateHeap->AllocateDynamicBlockDyn(MHW_ISH_TYPE, &Params);
    }

    // Failed to load kernel
    if (!pKernelMemoryBlock)
    {
        MHW_RENDERHAL_NORMALMESSAGE("Failed to load kernel - no space available in GSH.");
        // Return the kernel allocation to pool
        RenderHal_DSH_KernelAttach(&pStateHeap->KernelAllocationPool, pKernelAllocation, false);
        pKernelAllocation = nullptr;
        goto finish;
    }

    // Allocate kernel
    pKernelAllocation->iKID            = -1;
    pKernelAllocation->iKUID           = iKernelUniqueID;
    pKernelAllocation->iKCID           = iKernelCacheID;
    FrameTrackerTokenFlat_Clear(&pKernelAllocation->trackerToken);
    pKernelAllocation->dwOffset        = pKernelMemoryBlock->dwDataOffset;  // NOT USED IN DSH - KEPT FOR DEBUG SUPPORT
    pKernelAllocation->iSize           = pKernelMemoryBlock->dwDataSize;    // NOT USED IN DSH - KEPT FOR DEBUG SUPPORT
    pKernelAllocation->dwFlags         = RENDERHAL_KERNEL_ALLOCATION_USED;
    pKernelAllocation->dwCount         = 0;  // will be updated by "TouchKernel"
    pKernelAllocation->Params          = *pParameters;
    pKernelAllocation->pKernelEntry    = nullptr; // CURRENTLY NOT USED
    pKernelAllocation->iAllocIndex     = -1;   // DSH NOT USED
    pKernelAllocation->pMemoryBlock    = pKernelMemoryBlock;

    // Copy kernel data - securely erase unused part of the block
    MOS_SecureMemcpy(pKernelMemoryBlock->pDataPtr, iKernelSize, pKernel->pBinary, iKernelSize);
    if (iKernelSize < (int32_t)pKernelMemoryBlock->dwDataSize)
    {
        MOS_ZeroMemory((uint8_t*)pKernelMemoryBlock->pDataPtr + iKernelSize, pKernelMemoryBlock->dwDataSize - iKernelSize);
    }

finish:
    // Move kernel to the tail of the list of kernels (head of the list contains oldest kernels)
    if (pKernelAllocation)
    {
        // Move kernel allocation to end of list of kernels (sorted by usage)
        pRenderHal->pfnTouchDynamicKernel(pRenderHal, pKernelAllocation);
    }

    // Return kernel allocation
    return pKernelAllocation;
}

//!
//! \brief    Unload Kernel using dynamic model
//! \details  Unload a kernel from GSH, free kernel heap space
//!           Notify that the kernel has been unloaded (for tracking)
//! \param    PRENDERHAL_INTERFACE pRenderHal
//!           [in] Pointer to Hardware Interface Structure
//! \param    int32_t iKernelAllocationID
//!           [in] Kernel allocation index in GSH
//! \return   MOS_STATUS
//!           true if success
//!           false if invalid parameters or if kernel cannot be unloaded
//!
MOS_STATUS RenderHal_DSH_UnloadDynamicKernel(
    PRENDERHAL_INTERFACE        pRenderHal,
    PRENDERHAL_KRN_ALLOCATION   pKernelAllocation)
{
    PRENDERHAL_STATE_HEAP       pStateHeap;
    MOS_STATUS                  eStatus;

    //---------------------------------------
    MHW_RENDERHAL_CHK_NULL(pRenderHal);
    MHW_RENDERHAL_CHK_NULL(pKernelAllocation);
    MHW_RENDERHAL_CHK_NULL(pRenderHal->pStateHeap);
    //---------------------------------------

    eStatus    = MOS_STATUS_UNKNOWN;
    pStateHeap = pRenderHal->pStateHeap;

    //---------------------------------------
    MHW_RENDERHAL_CHK_NULL(pStateHeap->pKernelAllocation);
    //---------------------------------------

    // Kernel already free - return it to pool
    if (pKernelAllocation->dwFlags == RENDERHAL_KERNEL_ALLOCATION_FREE)
    {
        goto finish;
    }

    // Update Sync tags
    MHW_RENDERHAL_CHK_STATUS(pRenderHal->pfnRefreshSync(pRenderHal));

    // Check if kernel may be unloaded
    if (!FrameTrackerTokenFlat_IsExpired(&pKernelAllocation->trackerToken))
    {
        goto finish;
    }

    // Release kernel entry (Offset/size may be used for reallocation)
    pKernelAllocation->iKID             = -1;
    pKernelAllocation->iKUID            = -1;
    pKernelAllocation->iKCID            = -1;
    FrameTrackerTokenFlat_Clear(&pKernelAllocation->trackerToken);
    pKernelAllocation->dwFlags          = RENDERHAL_KERNEL_ALLOCATION_FREE;
    pKernelAllocation->dwCount          = 0;
    pKernelAllocation->pKernelEntry     = nullptr;

    eStatus = MOS_STATUS_SUCCESS;

finish:
    return eStatus;
}

//!
//! \brief    Load Debug Kernel
//! \details  Load SIP Debug kernel from cache into GSH.
//!           Replace debug surface binding table index with the specified value.
//! \param    PRENDERHAL_INTERFACE pRenderHal
//!           [in] Pointer to Hardware Interface Structure
//! \param    void   *pSipKernel
//!           [in] Pointer to Debug (Sip) Kernel binary
//! \param    uint32_t dwSipSize
//!           [in] Debug (Sip) Kernel size
//! \return   MOS_STATUS
//!
MOS_STATUS RenderHal_DSH_LoadSipKernel(
    PRENDERHAL_INTERFACE    pRenderHal,
    void                    *pSipKernel,
    uint32_t                dwSipSize)
{
    PXMHW_STATE_HEAP_INTERFACE   pMhwStateHeap;
    PMHW_STATE_HEAP              pInstructionStateHeap = nullptr;
    PMHW_STATE_HEAP_MEMORY_BLOCK pIshMemoryBlock;
    MHW_STATE_HEAP_DYNAMIC_ALLOC_PARAMS Params;
    MOS_STATUS                   eStatus = MOS_STATUS_SUCCESS;

    MHW_RENDERHAL_CHK_NULL(pRenderHal);
    MHW_RENDERHAL_CHK_NULL(pRenderHal->pMhwStateHeap);

    pMhwStateHeap = pRenderHal->pMhwStateHeap;

    // Mark previous SIP kernel for auto-release so it can be replaced
    pInstructionStateHeap = pMhwStateHeap->GetISHPointer();
    MHW_RENDERHAL_CHK_NULL(pInstructionStateHeap);
    if (pInstructionStateHeap->pDebugKernel)
    {
        pInstructionStateHeap->pDebugKernel->bStatic = false;
        pInstructionStateHeap->pDebugKernel = nullptr;
    }

    // If SIP size is zero or binary is nullptr, goto finish (SIP kernel unloaded)
    if (dwSipSize == 0 || pSipKernel == nullptr)
    {
        goto finish;
    }

    // Allocate new block for Debug (SIP) kernel
    MOS_ZeroMemory(&Params, sizeof(Params));
    Params.piSizes           = (int32_t*)&dwSipSize;
    Params.iCount            = 1;
    Params.dwAlignment       = RENDERHAL_KERNEL_BLOCK_ALIGN;
    Params.bHeapAffinity     = true;
    Params.pHeapAffinity     = pInstructionStateHeap;
    Params.dwScratchSpace    = 0;
    Params.pScratchSpace     = nullptr;
    Params.bZeroAssignedMem  = false;
    Params.bStatic           = true;
    Params.bGrow             = false;
#ifdef MHW_DYNAMIC_STATE_HEAP_DEBUGGING
    Params.dwBlockType       = MHW_BLOCK_DATA_SIP_KERNEL;
    Params.pClientObject     = nullptr;
#endif
    pIshMemoryBlock = pInstructionStateHeap->pDebugKernel = pMhwStateHeap->AllocateDynamicBlockDyn(MHW_ISH_TYPE, &Params);
    if (!pIshMemoryBlock)
    {
        eStatus = MOS_STATUS_NO_SPACE;
        goto finish;
    }

    // Copy SIP Debug kernel into SIP location in ISH (Instruction State Heap)
    MOS_SecureMemcpy(pIshMemoryBlock->pDataPtr, dwSipSize, pSipKernel, dwSipSize);

finish:
    return eStatus;
}

//!
//! \brief    Send SIP state command
//! \details  Send SIP state command pointing to the SIP kernel.
//! \param    PRENDERHAL_INTERFACE pRenderHal
//!           [in] Pointer to Hardware Interface Structure
//! \param    PMOS_COMMAND_BUFFER pCmdBuffer
//!           [in] Pointer to Command Buffer
//! \return   MOS_STATUS
//!
MOS_STATUS RenderHal_DSH_SendSipStateCmd(
    PRENDERHAL_INTERFACE  pRenderHal,
    PMOS_COMMAND_BUFFER   pCmdBuffer)
{
    PMHW_STATE_HEAP_MEMORY_BLOCK pSipMemoryBlock;
    PRENDERHAL_INTERFACE_LEGACY  pRenderHalLegacy = (PRENDERHAL_INTERFACE_LEGACY)pRenderHal;

    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    MHW_RENDERHAL_CHK_NULL(pRenderHalLegacy);
    MHW_RENDERHAL_CHK_NULL(pRenderHalLegacy->pMhwStateHeap);
    MHW_RENDERHAL_CHK_NULL(pRenderHalLegacy->pMhwRenderInterface);

    pSipMemoryBlock = pRenderHalLegacy->pMhwStateHeap->GetISHPointer()->pDebugKernel;

    if ((pRenderHalLegacy->bSIPKernel || pRenderHalLegacy->bCSRKernel) && pSipMemoryBlock != nullptr)
    {
        MhwRenderInterface *pMhwRender        = pRenderHalLegacy->pMhwRenderInterface;
        pRenderHalLegacy->SipStateParams.bSipKernel = true;
        pRenderHalLegacy->SipStateParams.dwSipBase  = pSipMemoryBlock->dwDataOffset;
        eStatus = pMhwRender->AddSipStateCmd(pCmdBuffer, &pRenderHalLegacy->SipStateParams);
    }
    else
    {   // Fail - SIP kernel not loaded
        eStatus = MOS_STATUS_UNKNOWN;
    }

finish:
    return eStatus;
}
//!
//! \brief    Allocate Media ID
//! \details  Allocates an setup Interface Descriptor for Media Pipeline
//!           Kernel        must be preloaded using pfnLoadKernel
//!           Curbe         must be allocated using pfnAllocateCurbe
//!           Binding Table must be allocated using pfnAllocateBindingTable
//! \param    PRENDERHAL_INTERFACE pRenderHal
//!           [in] Pointer to Hardware Interface Structure
//! \param    int32_t iKernelAllocationID
//!           [in] Kernel Allocation ID
//! \param    int32_t iBindingTableID
//!           [in] Binding Table ID
//! \param    int32_t iCurbeOffset
//!           [in] Curbe Offset (from Curbe base)
//! \param    int32_t iCurbeLength
//!           [in] Curbe Length
//! \param    int32_t iCrsThrdConstDataLn
//!           [in] Cross Thread constant data length
//! \param    PMHW_GPGPU_WALKER_PARAMS pGpGpuWalkerParams
//!           [in] Pointer to GpGpu Walker Params
//! \return   int32_t
//!           Media Interface descriptor ID
//!           -1 if invalid parameters, no ID entry available in GSH
//!
int32_t RenderHal_DSH_AllocateDynamicMediaID(
    PRENDERHAL_INTERFACE        pRenderHal,
    PRENDERHAL_KRN_ALLOCATION   pKernelAllocation,
    int32_t                     iBindingTableID,
    int32_t                     iCurbeOffset,
    int32_t                     iCurbeLength,
    int32_t                     iCrsThrdConstDataLn,
    PMHW_GPGPU_WALKER_PARAMS    pGpGpuWalkerParams)
{
    PRENDERHAL_MEDIA_STATE_LEGACY   pMediaState;
    PRENDERHAL_DYNAMIC_STATE        pDynamicState;
    PRENDERHAL_KRN_ALLOCATION       *pKrnAllocationTable;
    int32_t                         iCurbeSize;
    int32_t                         iInterfaceDescriptor;
    RENDERHAL_INTERFACE_DESCRIPTOR_PARAMS InterfaceDescriptorParams;

    iInterfaceDescriptor = -1;

    // Validate Renderhal and state heap
    if (pRenderHal == nullptr || pRenderHal->pStateHeap == nullptr)
    {
        MHW_RENDERHAL_ASSERTMESSAGE("Invalid State.");
        goto finish;
    }

    // Obtain pointer to current media state
    pMediaState = (PRENDERHAL_MEDIA_STATE_LEGACY)pRenderHal->pStateHeap->pCurMediaState;
    if (pMediaState == nullptr || pMediaState->pDynamicState == nullptr)
    {
        MHW_RENDERHAL_ASSERTMESSAGE("Invalid Media State.");
        goto finish;
    }

    // Obtain pointer to dynamic media state
    pDynamicState = pMediaState->pDynamicState;

    // Validate kernel allocation ID (kernel must be pre-loaded into GSH)
    if (pKernelAllocation == nullptr            ||                      // Allocation must be valid
        pKernelAllocation->pMemoryBlock == nullptr ||                      // Kernel must be loaded
        //pKernelAllocation->dwFlags == RENDERHAL_KERNEL_ALLOCATION_FREE ||  kernel may be reused
        pKernelAllocation->iSize == 0)                                  // Size must be valid
    {
        MHW_RENDERHAL_ASSERTMESSAGE("Invalid Kernel Allocation");
        goto finish;
    }

    // Check Curbe allocation (CURBE_Lenght is in 256-bit count -> convert to bytes)
    iCurbeSize = iCurbeLength;
    if (iCurbeSize <= 0)
    {
        // Curbe is not used by the kernel
        iCurbeSize = iCurbeOffset = 0;
    }
    // Validate Curbe Offset (curbe must be pre-allocated)
    else if ( iCurbeOffset < 0 ||                                           // Not allocated
             (iCurbeOffset & 0x1F) != 0 ||                                  // Invalid alignment
             (iCurbeOffset + iCurbeSize) > pDynamicState->Curbe.iCurrent)   // Invalid size
    {
        MHW_RENDERHAL_ASSERTMESSAGE("Invalid Curbe Allocation.");
        goto finish;
    }

    // Try to reuse interface descriptor (for 2nd level buffer optimizations)
    // Check if ID already in use by another kernel - must use a different ID
    pKrnAllocationTable  = pDynamicState->pKrnAllocations;
    iInterfaceDescriptor = pKernelAllocation->iKID;
    if (iInterfaceDescriptor >= 0 &&                                            // If kernel has a preferred interface descriptor
        pKrnAllocationTable[iInterfaceDescriptor] != pKernelAllocation)         // AND the interface descriptor is used by another kernel ....
    {
        iInterfaceDescriptor = -1;                                              // Choose another media interface descriptor
    }

    // Search available ID in current media state heap
    if (iInterfaceDescriptor < 0)
    {
        int32_t iMax = pDynamicState->MediaID.iCount;
        for (iInterfaceDescriptor = 0;
             iInterfaceDescriptor < iMax;
             iInterfaceDescriptor++)
        {
            if (pKrnAllocationTable[iInterfaceDescriptor] == nullptr)
            {
                break;
            }
        }

        // All IDs are in use - fail
        if (iInterfaceDescriptor >= iMax)
        {
            MHW_RENDERHAL_ASSERTMESSAGE("No Interface Descriptor available.");
            iInterfaceDescriptor = -1;
            goto finish;
        }
    }

    if (iInterfaceDescriptor >= pDynamicState->MediaID.iCount)
    {
        MHW_RENDERHAL_ASSERTMESSAGE("Invalid Interface Descriptor.");
        iInterfaceDescriptor = -1;
        goto finish;
    }

    MOS_ZeroMemory((void *)&InterfaceDescriptorParams, sizeof(InterfaceDescriptorParams));

    InterfaceDescriptorParams.iMediaID            = iInterfaceDescriptor;
    InterfaceDescriptorParams.iBindingTableID     = iBindingTableID;
    InterfaceDescriptorParams.iCurbeOffset        = iCurbeOffset;
    InterfaceDescriptorParams.iCurbeLength        = iCurbeLength;
    InterfaceDescriptorParams.iCrsThrdConstDataLn = iCrsThrdConstDataLn;

    // barrier and slm
    if (pGpGpuWalkerParams && pGpGpuWalkerParams->GpGpuEnable)
    {
        InterfaceDescriptorParams.blBarrierEnable = true;
        InterfaceDescriptorParams.iNumberThreadsInGroup = pGpGpuWalkerParams->ThreadWidth * pGpGpuWalkerParams->ThreadHeight;
        InterfaceDescriptorParams.iSLMSize = pGpGpuWalkerParams->SLMSize; // The shift will be handled by pfnEncodeSLMSize()
        InterfaceDescriptorParams.blGlobalBarrierEnable = false;   // BDW+, default is 0
    }
    else //Reset barrier and slm setting since they may be set before
    {
        InterfaceDescriptorParams.blBarrierEnable = false;
        InterfaceDescriptorParams.iNumberThreadsInGroup = pRenderHal->dwMinNumberThreadsInGroup;
        InterfaceDescriptorParams.iSLMSize = 0;
        InterfaceDescriptorParams.iCrsThrdConstDataLn &= pRenderHal->dwMaskCrsThdConDataRdLn;
        InterfaceDescriptorParams.blGlobalBarrierEnable = false;   // BDW+, default is 0
    }

    // Setup Media ID entry - this call could be HW dependent
    if (MOS_STATUS_SUCCESS != pRenderHal->pfnSetupInterfaceDescriptor(
                                             pRenderHal,
                                             pMediaState,
                                             pKernelAllocation,
                                             &InterfaceDescriptorParams))
    {
        MHW_RENDERHAL_ASSERTMESSAGE("Failed to setup Interface Descriptor.");
        iInterfaceDescriptor = -1;
        goto finish;
    }

    // Set kernel allocation for the current Media ID
    pKrnAllocationTable[iInterfaceDescriptor] = pKernelAllocation;

    // Set preferred Media ID for the current kernel
    // This is necessary for 2nd level BB optimization.
    if (pKernelAllocation->iKID < 0)
    {
        pKernelAllocation->iKID = iInterfaceDescriptor;
    }

    // Update kernel usage
    pRenderHal->pfnTouchDynamicKernel(pRenderHal, pKernelAllocation);

finish:
    return iInterfaceDescriptor;
}

//!
//! \brief    Get a media ID
//! \details  Returns an interface descriptor for this media state
//!           sets kernel allocation for the media ID
//! \param    PRENDERHAL_INTERFACE pRenderHal
//!           [in] Pointer to the renderhal interface
//! \param    PRENDERHAL_MEDIA_STATE pMediaState
//!           [in] Pointer to the media state
//! \param    PRENDERHAL_KRN_ALLOCATION   pKernelAllocation
//!           [in] Pointer to the kernel allocation
//! \return   int32_t mediaID
//!
int32_t RenderHal_DSH_GetMediaID(
    PRENDERHAL_INTERFACE        pRenderHal,
    PRENDERHAL_MEDIA_STATE      pMediaState,
    PRENDERHAL_KRN_ALLOCATION   pKernelAllocation)
{
    PRENDERHAL_KRN_ALLOCATION    *pKrnAllocations;
    int32_t                       iInterfaceDescriptor = -1;
    MOS_STATUS                    eStatus = MOS_STATUS_UNKNOWN;
    PRENDERHAL_MEDIA_STATE_LEGACY pMediaStateLegacy = (PRENDERHAL_MEDIA_STATE_LEGACY)pMediaState;

    MHW_RENDERHAL_CHK_NULL(pMediaStateLegacy);
    MHW_RENDERHAL_CHK_NULL(pMediaStateLegacy->pDynamicState);
    MHW_RENDERHAL_CHK_NULL(pMediaStateLegacy->pDynamicState->pKrnAllocations);
    MHW_RENDERHAL_CHK_NULL(pKernelAllocation);

    iInterfaceDescriptor = pKernelAllocation->iKID;
    pKrnAllocations      = pMediaStateLegacy->pDynamicState->pKrnAllocations;

    // Try to reuse interface descriptor (for 2nd level buffer optimizations)
    // Check if ID already in use by another kernel - must use a different ID
    if (iInterfaceDescriptor >= 0 &&
        pKrnAllocations[iInterfaceDescriptor] != nullptr &&
        pKrnAllocations[iInterfaceDescriptor] != pKernelAllocation)
    {
        iInterfaceDescriptor = -1;
    }

    // Search available ID in current media state heap
    if (iInterfaceDescriptor < 0)
    {
        int32_t iMax = pMediaStateLegacy->pDynamicState->MediaID.iCount;
        for (iInterfaceDescriptor = 0;
             iInterfaceDescriptor < iMax;
             iInterfaceDescriptor++)
        {
            if (pKrnAllocations[iInterfaceDescriptor] == nullptr)
            {
                break;
            }
        }

        // All IDs are in use - fail
        if (iInterfaceDescriptor >= iMax)
        {
            MHW_RENDERHAL_ASSERT("No Interface Descriptor available.");
            iInterfaceDescriptor = -1;
            goto finish;
        }
    }

    // Set kernel allocation for the current Media ID
    pKrnAllocations[iInterfaceDescriptor] = pKernelAllocation;

    // Set preferred Media ID for the current kernel
    // This is necessary for 2nd level BB optimization.
    if (pKernelAllocation->iKID < 0)
    {
        pKernelAllocation->iKID = iInterfaceDescriptor;
    }

finish:
    return iInterfaceDescriptor;
}

//!
//! \brief    Assign Dynamic Media State
//! \details  Gets a pointer to the next available media state in GSH;
//!           fails if not available
//! \param    PRENDERHAL_INTERFACE pRenderHal
//!           [in] Pointer to Hadrware Interface Structure
//! \param    PRENDERHAL_INTERFACE pRenderHal
//!           [in] Pointer to Hadrware Interface Structure
//! \param    RENDERHAL_COMPONENT componentID
//!           [in] Identifier of the requesting component
//! \return   PRENDERHAL_MEDIA_STATE
//!           gets a new Media State, returns pointer to Media State structure
//!           nullptr - invalid, no states available + timeout
//!
PRENDERHAL_MEDIA_STATE RenderHal_DSH_AssignDynamicState(
    PRENDERHAL_INTERFACE                  pRenderHal,
    PRENDERHAL_DYNAMIC_MEDIA_STATE_PARAMS pParams,
    RENDERHAL_COMPONENT                   componentID)
{
    MHW_STATE_HEAP_DYNAMIC_ALLOC_PARAMS Params;              // Block allocation parameters
    PRENDERHAL_MEDIA_STATE_LEGACY       pMediaState = nullptr;  // Media state structure
    PRENDERHAL_DYNAMIC_STATE            pDynamicState;       // Dynamic media state structure
    PXMHW_STATE_HEAP_INTERFACE          pMhwStateHeap;
    PMHW_RENDER_STATE_SIZES             pHwSizes;
    MOS_STATUS                          eStatus = MOS_STATUS_SUCCESS;
    uint32_t                            dwSizeMediaState = 0;
    uint32_t                            dwMediaStateAlign;
    uint32_t                            dwSamplerStateAlign;
    uint8_t                             *pCurrentPtr;
    uint8_t                             *performanceMemory = nullptr;
    uint32_t                            performanceSize;
    uint32_t                            currentExtendSize = 0;
    PRENDERHAL_INTERFACE_LEGACY         pRenderHalLegacy = (PRENDERHAL_INTERFACE_LEGACY)pRenderHal;

    MHW_RENDERHAL_CHK_NULL(pRenderHalLegacy);
    MHW_RENDERHAL_CHK_NULL(pRenderHalLegacy->pStateHeap);
    MHW_RENDERHAL_CHK_NULL(pRenderHalLegacy->pMhwStateHeap);
    MHW_RENDERHAL_CHK_NULL(pRenderHalLegacy->pOsInterface);

    // Assign new media state (get from pool)
    pMediaState = (PRENDERHAL_MEDIA_STATE_LEGACY)RenderHal_DSH_GetMediaStateFromPool(pRenderHalLegacy->pStateHeap);
    MHW_RENDERHAL_CHK_NULL(pMediaState);
    MHW_RENDERHAL_CHK_NULL(pMediaState->pDynamicState);

    // Get pointer to state heap interface
    pMhwStateHeap = pRenderHalLegacy->pMhwStateHeap;

    // Get hw structure sizes
    pHwSizes = pRenderHalLegacy->pHwSizes;

    // Point to dynamic state
    pDynamicState = pMediaState->pDynamicState;
    MOS_ZeroMemory(pDynamicState, sizeof(RENDERHAL_DYNAMIC_STATE));

    // Reset some states
    pMediaState->bBusy = false; // will be busy after submission

    // Setup parameters
    pDynamicState->Curbe.dwOffset = dwSizeMediaState;
    pDynamicState->Curbe.dwSize   = (uint32_t)MOS_MAX(pParams->iMaxCurbeSize, pParams->iMaxCurbeOffset);

    // Align media state for CURBE
    dwMediaStateAlign = pRenderHalLegacy->dwCurbeBlockAlign;
    dwSizeMediaState  = MOS_ALIGN_CEIL(pDynamicState->Curbe.dwSize, dwMediaStateAlign);

    // Align media states for Samplers
    dwSamplerStateAlign = MHW_SAMPLER_STATE_ALIGN;
    dwSizeMediaState    = MOS_ALIGN_CEIL(dwSizeMediaState, dwSamplerStateAlign);

    // Allocate Samplers
    if (pRenderHalLegacy->bHasCombinedAVSSamplerState == false)
    {
        uint32_t dwSamplerSize = 0;

        // This is needed regardless of 3D samplers
        /// Used to calculate offset to sampler area during interface descriptor setup
        pDynamicState->Sampler3D.dwOffset = dwSizeMediaState;

        // 3D Sampler states
        if (pParams->iMaxSamplerIndex3D > 0)
        {
            pDynamicState->Sampler3D.iCount   = pParams->iMaxSamplerIndex3D;
            pDynamicState->Sampler3D.dwSize   = MOS_ALIGN_CEIL(pParams->iMaxSamplerIndex3D * pHwSizes->dwSizeSamplerState,  MHW_SAMPLER_STATE_ALIGN);
            dwSamplerSize                     = pDynamicState->Sampler3D.dwSize;
        }

        // AVS sampler states (colocated with 3D => make sure the area is large enough for both)
        if (pParams->iMaxSamplerIndexAVS > 0)
        {
            pDynamicState->SamplerAVS.dwOffset = dwSizeMediaState;
            pDynamicState->SamplerAVS.iCount   = pParams->iMaxSamplerIndexAVS;
            pDynamicState->SamplerAVS.dwSize   = MOS_ALIGN_CEIL(pParams->iMaxSamplerIndexAVS * pHwSizes->dwSizeSamplerStateAvs,  MHW_SAMPLER_STATE_ALIGN);
            dwSamplerSize                      = MOS_MAX(dwSamplerSize, pDynamicState->SamplerAVS.dwSize);
        }

        // Sampler Indirect State (border color associated with each 3D sampler)
        if (pParams->iMaxSamplerIndex3D > 0)
        {
            pDynamicState->SamplerInd.dwOffset = MOS_ALIGN_CEIL(dwSizeMediaState + dwSamplerSize, MHW_SAMPLER_STATE_ALIGN);
            pDynamicState->SamplerInd.iCount   = pParams->iMaxSamplerIndex3D;
            pDynamicState->SamplerInd.dwSize   = MOS_ALIGN_CEIL(pParams->iMaxSamplerIndex3D * pHwSizes->dwSizeSamplerIndirectState, MHW_SAMPLER_STATE_ALIGN);
            dwSamplerSize                     += pDynamicState->SamplerInd.dwSize;
        }

        pDynamicState->dwSizeSamplers = dwSamplerSize = MOS_ALIGN_CEIL(dwSamplerSize, dwSamplerStateAlign);
        dwSamplerSize *= pParams->iMaxMediaIDs;     // Move tables to end of all sampler states

        // 8x8 tables
        if (pParams->iMax8x8Tables > 0)
        {
            pDynamicState->Table8x8.dwOffset   = MOS_ALIGN_CEIL(dwSizeMediaState + dwSamplerSize, MHW_SAMPLER_STATE_ALIGN);
            pDynamicState->Table8x8.iCount     = pParams->iMax8x8Tables;
            pDynamicState->Table8x8.dwSize     = MOS_ALIGN_CEIL(pHwSizes->dwSizeSamplerStateTable8x8,  MHW_SAMPLER_STATE_ALIGN);
            dwSamplerSize                     += pParams->iMax8x8Tables * pDynamicState->Table8x8.dwSize;
       }

        dwSamplerSize     = MOS_ALIGN_CEIL(dwSamplerSize, dwSamplerStateAlign);
        dwSizeMediaState += dwSamplerSize;
    }
    else
    {
        uint32_t dwSamplerSize = 0;

        // common base for all sampler types
        pDynamicState->Sampler3D  .dwOffset = dwSizeMediaState;
        pDynamicState->SamplerAVS .dwOffset = dwSizeMediaState;
        pDynamicState->SamplerConv.dwOffset = dwSizeMediaState;
        pDynamicState->SamplerMisc.dwOffset = dwSizeMediaState;

        // 3D sampler
        pDynamicState->Sampler3D.iCount = pParams->iMaxSamplerIndex3D;
        pDynamicState->Sampler3D.dwSize = pParams->iMaxSamplerIndex3D * pHwSizes->dwSizeSamplerState;

        // Misc (VA) sampler
        if (pParams->iMaxSamplerIndexMisc > 0)
        {
            dwSamplerStateAlign = MOS_MAX(dwMediaStateAlign, MHW_SAMPLER_STATE_VA_ALIGN);
            pDynamicState->SamplerMisc.iCount = pParams->iMaxSamplerIndexMisc;
            pDynamicState->SamplerMisc.dwSize = pParams->iMaxSamplerIndexMisc * pHwSizes->dwSizeSamplerStateVA;
        }

        // AVS sampler
        if (pParams->iMaxSamplerIndexAVS > 0)
        {
            uint32_t dwAlign = GFX_IS_GEN_9_OR_LATER(pRenderHalLegacy->Platform) ? MHW_SAMPLER_STATE_AVS_ALIGN_G9 : MHW_SAMPLER_STATE_AVS_ALIGN;
            uint32_t dwInc   = pRenderHalLegacy->pMhwRenderInterface->GetSamplerStateAVSIncUnit();

            dwSamplerStateAlign = MOS_MAX(dwMediaStateAlign, dwAlign);
            pDynamicState->SamplerAVS.iCount = pParams->iMaxSamplerIndexAVS;
            pDynamicState->SamplerAVS.dwSize = (pParams->iMaxSamplerIndexAVS - 1) * dwInc + pHwSizes->dwSizeSamplerStateAvs;
        }

        // Conv sampler
        if (pParams->iMaxSamplerIndexConv > 0)
        {
            uint32_t dwAlign = GFX_IS_GEN_9_OR_LATER(pRenderHalLegacy->Platform) ? MHW_SAMPLER_STATE_AVS_ALIGN_G9 : MHW_SAMPLER_STATE_AVS_ALIGN;
            uint32_t dwInc   = pRenderHalLegacy->pMhwRenderInterface->GetSamplerStateConvIncUnit();

            dwSamplerStateAlign = MOS_MAX(dwMediaStateAlign, dwAlign);
            pDynamicState->SamplerConv.iCount = pParams->iMaxSamplerIndexConv;
            pDynamicState->SamplerConv.dwSize = (pParams->iMaxSamplerIndexConv - 1) * dwInc + pHwSizes->dwSizeSamplerStateVAConvolve;
        }

        // Get largest of all
        dwSamplerSize = MOS_MAX(pDynamicState->Sampler3D.dwSize, pDynamicState->SamplerMisc.dwSize);
        dwSamplerSize = MOS_MAX(pDynamicState->SamplerAVS.dwSize, dwSamplerSize);
        dwSamplerSize = MOS_MAX(pDynamicState->SamplerConv.dwSize, dwSamplerSize);

        // Sampler Indirect State (border color associated with each 3D sampler)
        if (pParams->iMaxSamplerIndex3D > 0)
        {
            dwSamplerSize                      = MOS_ALIGN_CEIL(dwSamplerSize, MHW_SAMPLER_STATE_ALIGN);
            pDynamicState->SamplerInd.dwOffset = dwSizeMediaState + dwSamplerSize;
            pDynamicState->SamplerInd.iCount   = pParams->iMaxSamplerIndex3D;
            pDynamicState->SamplerInd.dwSize   = pParams->iMaxSamplerIndex3D * pHwSizes->dwSizeSamplerIndirectState;
            dwSamplerSize                     += pDynamicState->SamplerInd.dwSize;
        }

        dwSamplerSize = MOS_ALIGN_CEIL(dwSamplerSize, dwSamplerStateAlign);

        pDynamicState->dwSizeSamplers = dwSamplerSize;
        dwSizeMediaState += pParams->iMaxMediaIDs * pDynamicState->dwSizeSamplers;
    }

    // Interface Descriptors
    pDynamicState->MediaID.iCount   = pParams->iMaxMediaIDs;
    pDynamicState->MediaID.dwOffset = dwSizeMediaState;
    pDynamicState->MediaID.dwSize   = pParams->iMaxMediaIDs * pHwSizes->dwSizeInterfaceDescriptor;
    dwSizeMediaState               += pDynamicState->MediaID.dwSize;

    // Area for Performance collection
    pDynamicState->Performance.iCount   = 1;
    pDynamicState->Performance.dwOffset = dwSizeMediaState;
    pDynamicState->Performance.dwSize   = 64;
    dwSizeMediaState                   += pDynamicState->Performance.dwSize;

    // Kernel Spill Area
    if (pParams->iMaxSpillSize > 0)
    {
        // per thread scratch space must be 1K*(2^n), (2K*(2^n) for BDW A0), alignment is 1kB
        int iPerThreadScratchSpace = 0;
        if (pRenderHalLegacy->pfnPerThreadScratchSpaceStart2K(pRenderHalLegacy))
        {
            iPerThreadScratchSpace = 2048;
        }
        else if (pRenderHalLegacy->pRenderHalPltInterface
                 ->PerThreadScratchSpaceStart64Byte(pRenderHalLegacy))
        {
            iPerThreadScratchSpace = 64;
        }
        else
        {
            iPerThreadScratchSpace = 1024;
        }

        for (iPerThreadScratchSpace; iPerThreadScratchSpace < pParams->iMaxSpillSize; iPerThreadScratchSpace <<= 1);
        pDynamicState->iMaxScratchSpacePerThread = pParams->iMaxSpillSize
                = iPerThreadScratchSpace;

        MOS_STATUS result = pRenderHalLegacy->pRenderHalPltInterface
            ->AllocateScratchSpaceBuffer(iPerThreadScratchSpace, pRenderHalLegacy);
        if (MOS_STATUS_UNIMPLEMENTED == result)  // Scratch space buffer is not supported
        {
            pDynamicState->dwScratchSpace
                    = pRenderHalLegacy->pfnGetScratchSpaceSize(pRenderHalLegacy,
                                                         iPerThreadScratchSpace);
            pDynamicState->scratchSpaceOffset = dwSizeMediaState;

            // Allocate more 1k space in state heap, which is used to make scratch space offset 1k-aligned.
            dwSizeMediaState += pDynamicState->dwScratchSpace + MHW_SCRATCH_SPACE_ALIGN;
            currentExtendSize = pRenderHalLegacy->dgsheapManager->GetExtendSize();
            if (currentExtendSize < pDynamicState->dwScratchSpace)
            {
                // update extend size for scratch space
                MHW_RENDERHAL_CHK_STATUS(
                    pRenderHalLegacy->dgsheapManager->SetExtendHeapSize(
                        pDynamicState->dwScratchSpace));
            }
        }
        else
        {
            MHW_RENDERHAL_CHK_STATUS(result);
        }
    }

    // Use generic heap manager to allocate memory block for dynamic general state heap
    MHW_RENDERHAL_CHK_STATUS(pRenderHalLegacy->pfnAssignSpaceInStateHeap(
        pRenderHalLegacy->currentTrackerIndex,
        &pRenderHalLegacy->trackerProducer,
        pRenderHalLegacy->dgsheapManager,
        &pDynamicState->memoryBlock,
        dwSizeMediaState)); 

    if (pParams->iMaxSpillSize > 0 && currentExtendSize > 0)
    {
        // Restore original extend heap size
        MHW_RENDERHAL_CHK_STATUS(
            pRenderHalLegacy->dgsheapManager->SetExtendHeapSize(
                currentExtendSize));

        // Specifies the 1k-byte aligned address offset to scratch space for
        // use by the kernel.  This pointer is relative to the
        // General State Base Address (1k aligned)
        // Format = GeneralStateOffset[31:10]
        pDynamicState->scratchSpaceOffset += pDynamicState->memoryBlock.GetOffset();
        pDynamicState->scratchSpaceOffset = MOS_ALIGN_CEIL(pDynamicState->scratchSpaceOffset, MHW_SCRATCH_SPACE_ALIGN);
    }
 
    // set the sync tag for the media state
    FrameTrackerTokenFlat_SetProducer(&pMediaState->trackerToken, &pRenderHalLegacy->trackerProducer);
    FrameTrackerTokenFlat_Merge(&pMediaState->trackerToken, 
                                pRenderHalLegacy->currentTrackerIndex,
                                pRenderHalLegacy->trackerProducer.GetNextTracker(pRenderHalLegacy->currentTrackerIndex));

    // Reset HW allocations
    pRenderHalLegacy->iChromaKeyCount = 0;
    for (int32_t i = 0; i < pRenderHalLegacy->iMaxPalettes; i++)
    {
        pRenderHalLegacy->Palette[i].iNumEntries = 0;
    }

    // Zero Memory start time and end time
    performanceSize = (sizeof(uint64_t) * 2) + sizeof(RENDERHAL_COMPONENT);
    performanceMemory = (uint8_t*)MOS_AllocAndZeroMemory(performanceSize);
    pCurrentPtr = performanceMemory;
    pCurrentPtr += (sizeof(uint64_t) * 2);
    *((RENDERHAL_COMPONENT *)pCurrentPtr) = componentID;
    pDynamicState->memoryBlock.AddData(
        performanceMemory, 
        pDynamicState->Performance.dwOffset, 
        performanceSize);

finish:

    MOS_SafeFreeMemory(performanceMemory);

    if (eStatus == MOS_STATUS_SUCCESS)
    {
        if (pRenderHalLegacy && pRenderHalLegacy->pStateHeap)
        {
            pRenderHalLegacy->pStateHeap->pCurMediaState = pMediaState;
        }

        if (pRenderHalLegacy)
        {
            // Refresh sync tag for all media states in submitted queue
            pRenderHalLegacy->pfnRefreshSync(pRenderHalLegacy);
        }
    }
    else
    {
        RenderHal_DSH_ReturnMediaStateToPool(pRenderHalLegacy->pStateHeap, pMediaState);
        pMediaState = nullptr;
    }

    return pMediaState;
}

//!
//! \brief    Releases the dynamic state
//! \details  Returns the media state to the pool
//! \param    PRENDERHAL_INTERFACE pRenderHal
//!           [in] Pointer to renderhal interface
//! \param    PRENDERHAL_MEDIA_STATE pMediaState
//!           [in] Pointer to media state
//! \return   MOS_STATUS
//!
MOS_STATUS RenderHal_DSH_ReleaseDynamicState(
    PRENDERHAL_INTERFACE   pRenderHal,
    PRENDERHAL_MEDIA_STATE pMediaState)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    MHW_RENDERHAL_CHK_NULL(pRenderHal);
    MHW_RENDERHAL_CHK_NULL(pRenderHal->pStateHeap);
    MHW_RENDERHAL_CHK_NULL(pMediaState);

    // Media state cannot be busy or attached to any list (free/submitted)
    if (pMediaState->bBusy || pMediaState->pNext || pMediaState->pPrev)
    {
        MHW_RENDERHAL_ASSERTMESSAGE("Invalid Media State object");
        eStatus = MOS_STATUS_INVALID_PARAMETER;
        goto finish;
    }

    // Return media state to pool for reuse
    RenderHal_DSH_ReturnMediaStateToPool(pRenderHal->pStateHeap, pMediaState);

finish:
    return eStatus;
}

//!
//! \brief    Submit the dynamic state
//! \details  Move memory block to the submitted queue
//!           Updates the sync tag for the scratch space
//! \param    PRENDERHAL_INTERFACE pRenderHal
//!           [in] Pointer to renderhal interface
//! \param    PRENDERHAL_MEDIA_STATE pMediaState
//!           [in] Pointer to media state
//! \return   MOS_STATUS
//!
MOS_STATUS RenderHal_DSH_SubmitDynamicState(
    PRENDERHAL_INTERFACE   pRenderHal,
    PRENDERHAL_MEDIA_STATE pMediaState)
{
    PRENDERHAL_MEDIA_STATE_LIST pList;
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
    std::vector<MemoryBlock> blocks;
    PRENDERHAL_MEDIA_STATE_LEGACY pMediaStateLegacy = (PRENDERHAL_MEDIA_STATE_LEGACY)pMediaState;

    MHW_RENDERHAL_CHK_NULL(pRenderHal);
    MHW_RENDERHAL_CHK_NULL(pRenderHal->pStateHeap);
    MHW_RENDERHAL_CHK_NULL(pRenderHal->pMhwStateHeap);
    MHW_RENDERHAL_CHK_NULL(pMediaStateLegacy);
    MHW_RENDERHAL_CHK_NULL(pMediaStateLegacy->pDynamicState);

    // Media state cannot be attached to any list (free/submitted)
    if (pMediaStateLegacy->pNext || pMediaStateLegacy->pPrev)
    {
        MHW_RENDERHAL_ASSERTMESSAGE("Invalid Media State object");
        eStatus = MOS_STATUS_INVALID_PARAMETER;
        goto finish;
    }

    // Flag as busy (should be already)
    pMediaStateLegacy->bBusy = true;

    blocks.push_back(pMediaStateLegacy->pDynamicState->memoryBlock);
    pRenderHal->dgsheapManager->SubmitBlocks(blocks);

    // Attached to end of submitted queue (media state in execution queue)
    pList = &pRenderHal->pStateHeap->SubmittedStates;

    pMediaStateLegacy->pPrev = pList->pTail;
    pList->pTail = pMediaStateLegacy;
    if (pMediaStateLegacy->pPrev)
    {
        pMediaStateLegacy->pPrev->pNext = pMediaStateLegacy;
    }
    else
    {   // List was empty - insert first element
        MHW_ASSERT(pList->iCount == 0);
        pList->pHead = pMediaStateLegacy;
    }
    pList->iCount++;

finish:
    return eStatus;
}

//!
//! \brief    Load Curbe Data
//! \details  Allocates and load CURBE data for Media
//! \param    PRENDERHAL_INTERFACE pRenderHal
//!           [in]  Pointer to RenderHal Interface structure
//! \param    PRENDERHAL_MEDIA_STATE pCurMediaState
//!           [out] Pointer to Current Media State structure
//! \param    void  *pData
//!           [in]  Pointer to Data
//! \param    int32_t iSize
//!           [in]  Number of bytes to allocate
//! \return   int32_t
//!           Offset of the CURBE block from CURBE base (in bytes)
//!           -1 if no CURBE space available in GSH
//!
int32_t RenderHal_DSH_LoadCurbeData(
    PRENDERHAL_INTERFACE    pRenderHal,
    PRENDERHAL_MEDIA_STATE  pMediaState,
    void                    *pData,
    int32_t                 iSize)
{
    MOS_STATUS                    eStatus = MOS_STATUS_SUCCESS;
    int32_t                       iOffset;
    int32_t                       iCurbeSize;
    PRENDERHAL_DYNAMIC_STATE      pDynamicState;
    uint8_t*                      pRemainingCurbe;
    PRENDERHAL_MEDIA_STATE_LEGACY pMediaStateLegacy = (PRENDERHAL_MEDIA_STATE_LEGACY)pMediaState;

    iOffset         = -1;
    pRemainingCurbe =  nullptr;

    if (pRenderHal == nullptr || pMediaStateLegacy == nullptr || pData == nullptr)
    {
        MHW_RENDERHAL_ASSERTMESSAGE("Null pointer found.");
        eStatus = MOS_STATUS_INVALID_PARAMETER;
        goto finish;
    }

    if (pMediaStateLegacy && pMediaStateLegacy->pDynamicState)
    {
        // Check if dynamic state is valid
        pDynamicState = pMediaStateLegacy->pDynamicState;
        if (!pDynamicState->memoryBlock.IsValid())
        {
            goto finish;
        }

        iCurbeSize = MOS_ALIGN_CEIL(iSize, pRenderHal->dwCurbeBlockAlign);
        if (pDynamicState->Curbe.iCurrent + iCurbeSize <= (int)pDynamicState->Curbe.dwSize)
        {
            iOffset = pDynamicState->Curbe.iCurrent;
            pDynamicState->Curbe.iCurrent += iCurbeSize;

            if (pData)
            {
                MHW_RENDERHAL_CHK_STATUS(pDynamicState->memoryBlock.AddData(
                    pData,
                    pDynamicState->Curbe.dwOffset + iOffset,
                    iSize));

                // Zero remaining CURBE (for buffer alignment)
                iCurbeSize -= iSize;
                if (iCurbeSize > 0)
                {
                    pRemainingCurbe = (uint8_t*)MOS_AllocAndZeroMemory(sizeof(uint8_t)*iCurbeSize);
                    MHW_RENDERHAL_CHK_STATUS(pDynamicState->memoryBlock.AddData(
                        pRemainingCurbe,
                        pDynamicState->Curbe.dwOffset + iOffset + iSize,
                        iCurbeSize));
                }
            }
        }
    }

finish:
    if(pRemainingCurbe)
    {
        MOS_SafeFreeMemory(pRemainingCurbe);
    }

    if (eStatus != MOS_STATUS_SUCCESS)
    {
        iOffset = -1;
    }
    return iOffset;
}

//!
//! \brief    Send Curbe Load
//! \details  Send Curbe Load command
//! \param    PRENDERHAL_INTERFACE pRenderHal
//!           [in] Pointer to Hardware Interface Structure
//! \param    PMOS_COMMAND_BUFFER pCmdBuffer
//!           [in] Pointer to Command Buffer
//! \return   MOS_STATUS
//!
MOS_STATUS RenderHal_DSH_SendCurbeLoad(
    PRENDERHAL_INTERFACE    pRenderHal,
    PMOS_COMMAND_BUFFER     pCmdBuffer)
{
    MHW_CURBE_LOAD_PARAMS           CurbeLoadParams;
    PRENDERHAL_STATE_HEAP           pStateHeap;
    PRENDERHAL_MEDIA_STATE_LEGACY   pMediaState;
    PRENDERHAL_DYNAMIC_STATE        pDynamicState;
    MOS_STATUS                      eStatus = MOS_STATUS_SUCCESS;
    PRENDERHAL_INTERFACE_LEGACY     pRenderHalLegacy = (PRENDERHAL_INTERFACE_LEGACY)pRenderHal;
    //-----------------------------------------
    MHW_RENDERHAL_CHK_NULL(pRenderHalLegacy);
    MHW_RENDERHAL_CHK_NULL(pCmdBuffer);
    MHW_RENDERHAL_CHK_NULL(pRenderHalLegacy->pStateHeap);
    MHW_RENDERHAL_CHK_NULL(pRenderHalLegacy->pMhwRenderInterface);
    MHW_RENDERHAL_CHK_NULL(pRenderHalLegacy->pStateHeap->pCurMediaState);
    //-----------------------------------------

    pMediaState = (PRENDERHAL_MEDIA_STATE_LEGACY)pRenderHalLegacy->pStateHeap->pCurMediaState;
    MHW_RENDERHAL_CHK_NULL(pMediaState->pDynamicState);

    eStatus       = MOS_STATUS_SUCCESS;
    pStateHeap    = pRenderHalLegacy->pStateHeap;
    pDynamicState = pMediaState->pDynamicState;

    // CURBE size is in bytes
    if (pDynamicState->Curbe.iCurrent != 0)
    {
        CurbeLoadParams.pKernelState            = nullptr;
        CurbeLoadParams.bOldInterface           = false;
        CurbeLoadParams.dwCURBETotalDataLength  = pDynamicState->Curbe.iCurrent;
        CurbeLoadParams.dwCURBEDataStartAddress = pDynamicState->memoryBlock.GetOffset() +   // media state offset from GSH base
                                                  pDynamicState->Curbe.dwOffset;                // curbe data offset in media state

        MHW_RENDERHAL_CHK_STATUS(pRenderHalLegacy->pMhwRenderInterface->AddMediaCurbeLoadCmd(pCmdBuffer, &CurbeLoadParams));
    }

finish:
    return eStatus;
}

//!
//! \brief    Send state base address
//! \details  Send state base address command
//! \param    PRENDERHAL_INTERFACE pRenderHal
//!           [in] Pointer to Hardware Interface Structure
//! \param    PMOS_COMMAND_BUFFER pCmdBuffer
//!           [in] Pointer to Command Buffer
//! \return   MOS_STATUS
//!
MOS_STATUS RenderHal_DSH_SendStateBaseAddress(PRENDERHAL_INTERFACE pRenderHal, PMOS_COMMAND_BUFFER pCmdBuffer)
{
    PRENDERHAL_STATE_HEAP       pStateHeap;
    PRENDERHAL_DYNAMIC_STATE    pDynamicState;
    PMOS_RESOURCE               pGshResource;
    uint32_t                    dwGshSize;
    PMOS_RESOURCE               pIshResource;
    uint32_t                    dwIshSize;
    MOS_STATUS                  eStatus = MOS_STATUS_SUCCESS;
    PRENDERHAL_INTERFACE_LEGACY pRenderHalLegacy = (PRENDERHAL_INTERFACE_LEGACY)pRenderHal;

    //----------------------------------------
    MHW_RENDERHAL_CHK_NULL(pCmdBuffer);
    MHW_RENDERHAL_CHK_NULL(pRenderHalLegacy);
    MHW_RENDERHAL_CHK_NULL(pRenderHalLegacy->pStateHeap);
    MHW_RENDERHAL_CHK_NULL(pRenderHalLegacy->pStateHeap->pCurMediaState);
    MHW_RENDERHAL_CHK_NULL(pRenderHalLegacy->pMhwStateHeap);
    MHW_RENDERHAL_CHK_NULL(pRenderHalLegacy->pMhwRenderInterface);
    //----------------------------------------

    pStateHeap    = pRenderHalLegacy->pStateHeap;
    pDynamicState = ((PRENDERHAL_MEDIA_STATE_LEGACY)pStateHeap->pCurMediaState)->pDynamicState;

    MHW_RENDERHAL_CHK_NULL(pDynamicState);

    pGshResource  = pDynamicState->memoryBlock.GetResource();
    dwGshSize     = pDynamicState->memoryBlock.GetHeapSize();
    pIshResource  = &(pRenderHalLegacy->pMhwStateHeap->GetISHPointer()->resHeap);
    dwIshSize     = pRenderHalLegacy->pMhwStateHeap->GetISHPointer()->dwSize;

    pRenderHalLegacy->StateBaseAddressParams.presGeneralState              = pGshResource;
    pRenderHalLegacy->StateBaseAddressParams.dwGeneralStateSize            = dwGshSize;
    pRenderHalLegacy->StateBaseAddressParams.presDynamicState              = pGshResource;
    pRenderHalLegacy->StateBaseAddressParams.dwDynamicStateSize            = dwGshSize;
    pRenderHalLegacy->StateBaseAddressParams.bDynamicStateRenderTarget     = false;
    pRenderHalLegacy->StateBaseAddressParams.presIndirectObjectBuffer      = pGshResource;
    pRenderHalLegacy->StateBaseAddressParams.dwIndirectObjectBufferSize    = dwGshSize;
    pRenderHalLegacy->StateBaseAddressParams.presInstructionBuffer         = pIshResource;
    pRenderHalLegacy->StateBaseAddressParams.dwInstructionBufferSize       = dwIshSize;

    eStatus = pRenderHalLegacy->pMhwRenderInterface->AddStateBaseAddrCmd(pCmdBuffer,
                                                                   &pRenderHalLegacy->StateBaseAddressParams);
finish:
    return eStatus;
}

//!
//! \brief    Reset RenderHal States
//! \details  Reset RenderHal States in preparation for a new command buffer
//! \param    PRENDERHAL_INTERFACE pRenderHal
//!           [in] Pointer to RenderHal Interface Structure
//! \return   MOS_STATUS
//!
MOS_STATUS RenderHal_DSH_Reset(
    PRENDERHAL_INTERFACE pRenderHal)
{
    MOS_STATUS eStatus;

    //----------------------------------
    MHW_RENDERHAL_CHK_NULL(pRenderHal);
    //----------------------------------

    eStatus         = MOS_STATUS_SUCCESS;

    // Do not register GSH resource until we allocate the Media State
    // Media State can be in any of the current DSH instances

    // Do not register ISH resource until we load all kernels
    // ISH could be reallocated to accomodate kernels being loaded in heap

    //MHW_RENDERHAL_CHK_STATUS(pOsInterface->pfnRegisterResource(pOsInterface,
    //                                        &pStateHeap->IshOsResource,
    //                                        true,
    //                                        true));

    // Reset Slice Shutdown Mode
    pRenderHal->bRequestSingleSlice   = false;
    pRenderHal->PowerOption.nSlice    = 0;
    pRenderHal->PowerOption.nEU       = 0;
    pRenderHal->PowerOption.nSubSlice = 0;

finish:
    return eStatus;
}

//!
//! \brief    Send Sync Tag
//! \details  Sends Synchronization Tags for G75
//! \param    PRENDERHAL_INTERFACE pRenderHal
//!           [in] Pointer to RenderHal Interface Structure
//! \param    PMOS_COMMAND_BUFFER pCmdBuffer
//!           [in] Pointer to Command Buffer
//! \return   MOS_STATUS
//!
MOS_STATUS RenderHal_DSH_SendSyncTag(
    PRENDERHAL_INTERFACE    pRenderHal,
    PMOS_COMMAND_BUFFER     pCmdBuffer)
{
    PRENDERHAL_STATE_HEAP           pStateHeap;
    MOS_STATUS                      eStatus = MOS_STATUS_SUCCESS;
    PXMHW_STATE_HEAP_INTERFACE      pMhwStateHeap;
    PMHW_MI_INTERFACE               pMhwMiInterface;
    MHW_PIPE_CONTROL_PARAMS         PipeCtl;

    //-------------------------------------
    MHW_RENDERHAL_CHK_NULL(pRenderHal);
    MHW_RENDERHAL_CHK_NULL(pRenderHal->pMhwStateHeap);
    MHW_RENDERHAL_CHK_NULL(pRenderHal->pStateHeap);
    //-------------------------------------

    pStateHeap      = pRenderHal->pStateHeap;
    pMhwStateHeap   = pRenderHal->pMhwStateHeap;
    pMhwMiInterface = pRenderHal->pMhwMiInterface;

    // Send PIPE_CONTROL Token
    // CMD_MI_FLUSH is disabled by default on GT, use PIPE_CONTROL
    // Requires a token and the actual pipe control command
    // Flush write caches
    PipeCtl = g_cRenderHal_InitPipeControlParams;
    PipeCtl.presDest          = pMhwStateHeap->GetResCmdBufIdGlobal();
    PipeCtl.dwPostSyncOp      = MHW_FLUSH_NOWRITE;
    PipeCtl.dwFlushMode       = MHW_FLUSH_WRITE_CACHE;
    MHW_RENDERHAL_CHK_STATUS(pMhwMiInterface->AddPipeControl(pCmdBuffer, nullptr, &PipeCtl));

    // Invalidate read-only caches and perform a post sync write
    PipeCtl = g_cRenderHal_InitPipeControlParams;
    PipeCtl.presDest          = pMhwStateHeap->GetResCmdBufIdGlobal();
    PipeCtl.dwResourceOffset  = pStateHeap->dwOffsetSync;
    PipeCtl.dwPostSyncOp      = MHW_FLUSH_WRITE_IMMEDIATE_DATA;
    PipeCtl.dwFlushMode       = MHW_FLUSH_READ_CACHE;
    PipeCtl.dwDataDW1         = pStateHeap->dwNextTag;
    MHW_RENDERHAL_CHK_STATUS(pMhwMiInterface->AddPipeControl(pCmdBuffer, nullptr, &PipeCtl));

finish:
    return eStatus;
}

//!
//! \brief      Sets Sampler States
//! \details    Initialize and set sampler states
//! \param      PRENDERHAL_INTERFACE pRenderHal
//!             [in]    Pointer to HW interface
//! \param      int32_t iMediaID
//!             [in]    Media ID
//! \param      PRENDERHAL_SAMPLER_STATE_PARAMS pSamplerParams
//!             [in]    Pointer to Sampler parameters
//! \param      int32_t iSamplers
//!             [in]    Number of samplers
//! \return     MOS_STATUS MOS_STATUS_SUCCESS if success, otherwise MOS_STATUS_UNKNOWN
//!
MOS_STATUS RenderHal_DSH_SetSamplerStates(
    PRENDERHAL_INTERFACE        pRenderHal,
    int32_t                     iMediaID,
    PMHW_SAMPLER_STATE_PARAM    pSamplerParams,
    int32_t                     iSamplers)
{
    MHW_RENDERHAL_ASSERT(true);
    return MOS_STATUS_UNIMPLEMENTED;
}

//!
//! \brief      Setup Interface Descriptor
//! \details    Set interface descriptor
//! \param      PRENDERHAL_INTERFACE                    pRenderHal
//!             [in]    Pointer to HW interface
//! \param      PRENDERHAL_MEDIA_STATE                  pMediaState
//!             [in]    Pointer to media state
//! \param      PRENDERHAL_KRN_ALLOCATION               pKernelAllocation
//!             [in]    Pointer to kernel allocation
//! \param      PRENDERHAL_INTERFACE_DESCRIPTOR_PARAMS  pInterfaceDescriptorParams
//!             [in]    Pointer to interface descriptor parameters
//! \param      PMHW_GPGPU_WALKER_PARAMS          pGpGpuWalkerParams
//!             [in]    Pointer to gpgpu walker parameters
//! \return     MOS_STATUS
//!
MOS_STATUS RenderHal_DSH_SetupInterfaceDescriptor(
    PRENDERHAL_INTERFACE                   pRenderHal,
    PRENDERHAL_MEDIA_STATE                 pMediaState,
    PRENDERHAL_KRN_ALLOCATION              pKernelAllocation,
    PRENDERHAL_INTERFACE_DESCRIPTOR_PARAMS pInterfaceDescriptorParams)
{
    MOS_STATUS                    eStatus = MOS_STATUS_SUCCESS;
    MHW_ID_ENTRY_PARAMS           Params;
    PRENDERHAL_STATE_HEAP         pStateHeap;
    PRENDERHAL_DYNAMIC_STATE      pDynamicState;
    uint32_t                      dwMediaStateOffset;
    PRENDERHAL_MEDIA_STATE_LEGACY pMediaStateLegacy = (PRENDERHAL_MEDIA_STATE_LEGACY)pMediaState;

    //-----------------------------------------
    MHW_RENDERHAL_CHK_NULL(pRenderHal);
    MHW_RENDERHAL_CHK_NULL(pRenderHal->pMhwStateHeap);
    MHW_RENDERHAL_CHK_NULL(pMediaStateLegacy);
    MHW_RENDERHAL_CHK_NULL(pMediaStateLegacy->pDynamicState);
    MHW_RENDERHAL_CHK_NULL(pKernelAllocation);
    MHW_RENDERHAL_CHK_NULL(pKernelAllocation->pMemoryBlock);
    MHW_RENDERHAL_CHK_NULL(pInterfaceDescriptorParams);
    //-----------------------------------------

    // Get states, params
    pStateHeap = pRenderHal->pStateHeap;
    pDynamicState = pMediaStateLegacy->pDynamicState;
    dwMediaStateOffset = pDynamicState->memoryBlock.GetOffset();

    Params.dwMediaIdOffset = dwMediaStateOffset + pDynamicState->MediaID.dwOffset;
    Params.iMediaId = pInterfaceDescriptorParams->iMediaID;
    Params.dwKernelOffset = pKernelAllocation->dwOffset;
    Params.dwSamplerOffset = dwMediaStateOffset + pDynamicState->Sampler3D.dwOffset +
        pInterfaceDescriptorParams->iMediaID * pDynamicState->dwSizeSamplers;
    Params.dwSamplerCount = pKernelAllocation->Params.Sampler_Count;
    Params.dwBindingTableOffset = pInterfaceDescriptorParams->iBindingTableID * pStateHeap->iBindingTableSize;
    Params.iCurbeOffset = pInterfaceDescriptorParams->iCurbeOffset;
    Params.iCurbeLength = pInterfaceDescriptorParams->iCurbeLength;

    Params.bBarrierEnable = pInterfaceDescriptorParams->blBarrierEnable;
    Params.bGlobalBarrierEnable = pInterfaceDescriptorParams->blGlobalBarrierEnable;    //It's only applied for BDW+
    Params.dwNumberofThreadsInGPGPUGroup = pInterfaceDescriptorParams->iNumberThreadsInGroup;
    Params.dwSharedLocalMemorySize = pRenderHal->pfnEncodeSLMSize(pRenderHal, pInterfaceDescriptorParams->iSLMSize);
    Params.iCrsThdConDataRdLn = pInterfaceDescriptorParams->iCrsThrdConstDataLn;
    Params.memoryBlock = &pDynamicState->memoryBlock;

    MHW_RENDERHAL_CHK_STATUS(pRenderHal->pMhwStateHeap->AddInterfaceDescriptorData(&Params));
    pDynamicState->MediaID.iCurrent++;

finish:
    return eStatus;
}

//!
//! \brief    Set Vfe State Params
//! \details  Sets VFE State parameters
//!           this functions must be called to setup
//!           parameters for pMhwRender->AddMediaVfeCmd()
//! \param    PRENDERHAL_INTERFACE pRenderHal
//!           [in] Pointer to Hardware Interface Structure
//! \param    uint32_t dwDebugCounterControl
//!           [in] Debug Counter Control
//! \param    uint32_t dwMaximumNumberofThreads
//!           [in] Maximum Number of Threads
//! \param    uint32_t dwCURBEAllocationSize
//!           [in] CURBE Allocation Size
//! \param    uint32_t dwURBEntryAllocationSize
//!           [in] URB Entry Allocation Size
//! \param    PRENDERHAL_SCOREBOARD_PARAMS pScoreboardParams
//!           [in] Pointer to Scoreboard Params
//! \return   MOS_STATUS
//!
MOS_STATUS RenderHal_DSH_SetVfeStateParams(
    PRENDERHAL_INTERFACE    pRenderHal,
    uint32_t                dwDebugCounterControl,
    uint32_t                dwMaximumNumberofThreads,
    uint32_t                dwCURBEAllocationSize,
    uint32_t                dwURBEntryAllocationSize,
    PMHW_VFE_SCOREBOARD     pScoreboardParams)
{
    PMHW_VFE_PARAMS                 pVfeParams;
    PRENDERHAL_STATE_HEAP           pStateHeap;
    PRENDERHAL_DYNAMIC_STATE        pDynamicState;
    PMHW_RENDER_ENGINE_CAPS         pHwCaps;
    PRENDERHAL_STATE_HEAP_SETTINGS  pSettings;
    uint32_t                        dwMaxURBSize;
    uint32_t                        dwMaxCURBEAllocationSize;
    uint32_t                        dwMaxURBEntryAllocationSize;
    uint32_t                        dwNumberofURBEntries;
    uint32_t                        dwMaxURBEntries;
    uint32_t                        dwMaxInterfaceDescriptorEntries;
    MOS_STATUS                      eStatus;
    uint32_t i;

    //---------------------------------------------
    MHW_RENDERHAL_CHK_NULL(pRenderHal);
    MHW_RENDERHAL_CHK_NULL(pRenderHal->pWaTable);
    MHW_RENDERHAL_CHK_NULL(pRenderHal->pStateHeap);
    MHW_RENDERHAL_CHK_NULL(pRenderHal->pHwCaps);
    //---------------------------------------------

    eStatus = MOS_STATUS_SUCCESS;
    pStateHeap = pRenderHal->pStateHeap;
    pHwCaps = pRenderHal->pHwCaps;
    pVfeParams = pRenderHal->pRenderHalPltInterface->GetVfeStateParameters();
    pSettings = &(pRenderHal->StateHeapSettings);

    pVfeParams->pKernelState = nullptr;
    pVfeParams->eVfeSliceDisable = MHW_VFE_SLICE_ALL;

    // Get pointer to current dynamic state
    MHW_RENDERHAL_CHK_NULL(pStateHeap->pCurMediaState);
    pDynamicState = ((PRENDERHAL_MEDIA_STATE_LEGACY)pStateHeap->pCurMediaState)->pDynamicState;
    MHW_RENDERHAL_CHK_NULL(pDynamicState);
    //-------------------------------------------------------------------------
    // In this calculation, URBEntryAllocationSize and CURBEAllocationSize are
    // in 256-bit units:
    // (URBEntryAllocationSize * NumberofURBEntries + CURBEAllocationSize +
    //  MaxInterfaceDescriptorEntries) <= 2048
    //-------------------------------------------------------------------------

    // get the Max for all the fields
    dwMaxURBSize = pHwCaps->dwMaxURBSize;
    dwMaxURBEntries = pHwCaps->dwMaxURBEntries;
    dwMaxURBEntryAllocationSize = pHwCaps->dwMaxURBEntryAllocationSize;
    dwMaxCURBEAllocationSize = pHwCaps->dwMaxCURBEAllocationSize;
    dwMaxInterfaceDescriptorEntries = pHwCaps->dwMaxInterfaceDescriptorEntries;

    dwCURBEAllocationSize = MOS_MAX(dwCURBEAllocationSize, (uint32_t)pDynamicState->Curbe.iCurrent);
    dwCURBEAllocationSize = MOS_ROUNDUP_SHIFT(dwCURBEAllocationSize, 5);
    dwURBEntryAllocationSize = MOS_ROUNDUP_SHIFT(dwURBEntryAllocationSize, 5);
    dwURBEntryAllocationSize = MOS_MAX(1, dwURBEntryAllocationSize);
    dwNumberofURBEntries = (dwMaxURBSize - dwCURBEAllocationSize - dwMaxInterfaceDescriptorEntries) / dwURBEntryAllocationSize;
    dwNumberofURBEntries = MOS_CLAMP_MIN_MAX(dwNumberofURBEntries, 1, 32);

    pVfeParams->dwDebugCounterControl = dwDebugCounterControl;
    pVfeParams->dwNumberofURBEntries = dwNumberofURBEntries;
    pVfeParams->dwMaximumNumberofThreads = (dwMaximumNumberofThreads == RENDERHAL_USE_MEDIA_THREADS_MAX) ?
        pHwCaps->dwMaxThreads : MOS_MIN(dwMaximumNumberofThreads, pHwCaps->dwMaxThreads);
    pVfeParams->dwCURBEAllocationSize = dwCURBEAllocationSize << 5;
    pVfeParams->dwURBEntryAllocationSize = dwURBEntryAllocationSize;

    MHW_RENDERHAL_ASSERT(dwNumberofURBEntries <= dwMaxURBEntries);
    MHW_RENDERHAL_ASSERT(dwCURBEAllocationSize <= dwMaxCURBEAllocationSize);
    MHW_RENDERHAL_ASSERT(dwURBEntryAllocationSize <= dwMaxURBEntryAllocationSize);
    MHW_RENDERHAL_ASSERT(dwNumberofURBEntries * dwURBEntryAllocationSize + dwCURBEAllocationSize + dwMaxInterfaceDescriptorEntries <= dwMaxURBSize);

    // Setup Scoreboard Parameters
    if (pScoreboardParams)
    {
        MHW_RENDERHAL_ASSERT(pScoreboardParams->ScoreboardMask < 8);

        pRenderHal->VfeScoreboard.ScoreboardEnable = true;
        pRenderHal->VfeScoreboard.ScoreboardMask = (1 << pScoreboardParams->ScoreboardMask) - 1;
        pRenderHal->VfeScoreboard.ScoreboardType = pScoreboardParams->ScoreboardType;
        for (i = 0; i < pScoreboardParams->ScoreboardMask; i++)
        {
            pRenderHal->VfeScoreboard.ScoreboardDelta[i].x = pScoreboardParams->ScoreboardDelta[i].x;
            pRenderHal->VfeScoreboard.ScoreboardDelta[i].y = pScoreboardParams->ScoreboardDelta[i].y;
        }
    }
    else
    {
        pRenderHal->VfeScoreboard.ScoreboardEnable = true;
        pRenderHal->VfeScoreboard.ScoreboardMask = 0x0;
    }

    // Setup VFE Scoreboard parameters
    pVfeParams->Scoreboard = pRenderHal->VfeScoreboard;

    // Setup Kernel Scratch Space
    if (pDynamicState->dwScratchSpace > 0)
    {
        int32_t iSize;
        int32_t iRemain;
        int32_t iPerThreadScratchSize;

        MHW_RENDERHAL_ASSERT(pDynamicState->iMaxScratchSpacePerThread ==
            MOS_ALIGN_CEIL(pDynamicState->iMaxScratchSpacePerThread, 1024));

        if (pRenderHal->pfnPerThreadScratchSpaceStart2K(pRenderHal))
            iPerThreadScratchSize = pDynamicState->iMaxScratchSpacePerThread >> 10;
        else
            iPerThreadScratchSize = pDynamicState->iMaxScratchSpacePerThread >> 9;

        iRemain = iPerThreadScratchSize % 2;
        iPerThreadScratchSize = iPerThreadScratchSize / 2;
        iSize = 0;
        while (!iRemain && (iPerThreadScratchSize / 2))
        {
            iSize++;
            iRemain = iPerThreadScratchSize % 2;
            iPerThreadScratchSize = iPerThreadScratchSize / 2;
        }

        MHW_RENDERHAL_ASSERT(!iRemain && iPerThreadScratchSize);
        MHW_RENDERHAL_ASSERT(iSize < 12);

        pVfeParams->dwPerThreadScratchSpace   = (uint32_t)iSize;
        pVfeParams->dwScratchSpaceBasePointer = pDynamicState->scratchSpaceOffset;
    }
    else
    {
        pVfeParams->dwPerThreadScratchSpace = 0;
        pVfeParams->dwScratchSpaceBasePointer = 0;
    }

finish:
    return eStatus;
}

//!
//! \brief    Get offset and/or pointer to sampler state
//! \details  Get offset and/or pointer to sampler state in General State Heap
//! \param    PRENDERHAL_INTERFACE pRenderHal
//!           [in] Pointer to RenderHal Interface
//! \param    int32_t iMediaID
//!           [in] Media ID associated with sampler
//! \param    int32_t iSamplerID
//!           [in] Sampler ID
//! \param    uint32_t *pdwSamplerOffset
//!           [out] optional; offset of sampler state from GSH base
//! \param    void  **ppSampler
//!           [out] optional; pointer to sampler state in GSH
//! \return   MOS_STATUS
//!
MOS_STATUS RenderHal_DSH_GetSamplerOffsetAndPtr(
    PRENDERHAL_INTERFACE     pRenderHal,
    int32_t                  iMediaID,
    int32_t                  iSamplerID,
    PMHW_SAMPLER_STATE_PARAM pSamplerParams,
    uint32_t                 *pdwSamplerOffset,
    void                    **ppSampler)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
    MHW_RENDERHAL_CHK_NULL(pRenderHal->pRenderHalPltInterface);

    MHW_RENDERHAL_CHK_STATUS( pRenderHal->pRenderHalPltInterface->GetSamplerOffsetAndPtr_DSH(
                                                    pRenderHal,
                                                    iMediaID,
                                                    iSamplerID,
                                                    pSamplerParams,
                                                    pdwSamplerOffset,
                                                    ppSampler));
finish:
    return eStatus;
}

//!
//! \brief    Initialize
//! \details  Initialize HW states
//! \param    PRENDERHAL_INTERFACE pRenderHal
//!           [in] Pointer to RenderHal Interface Structure
//! \param    PCRENDERHAL_SETTINGS pSettings
//!           [in] Pointer to Settings
//! \return   MOS_STATUS
//!           true  if succeeded
//!           false if failed to allocate/initialize HW commands
//!
MOS_STATUS RenderHal_DSH_Initialize(
    PRENDERHAL_INTERFACE   pRenderHal,
    PRENDERHAL_SETTINGS    pSettings)
{
    MOS_STATUS eStatus = MOS_STATUS_SUCCESS;

    PRENDERHAL_STATE_HEAP_LEGACY pStateHeap;

    PRENDERHAL_SETTINGS_LEGACY pSettingsLegacy = (PRENDERHAL_SETTINGS_LEGACY)pSettings;
    //------------------------------------------------
    MHW_RENDERHAL_CHK_NULL(pRenderHal);
    //------------------------------------------------

    // Allocate State Heap control structure (aligned)
    pStateHeap = (PRENDERHAL_STATE_HEAP_LEGACY)MOS_AlignedAllocMemory(sizeof(RENDERHAL_STATE_HEAP_LEGACY), 16);
    MOS_ZeroMemory(pStateHeap, sizeof(RENDERHAL_STATE_HEAP_LEGACY));
    pRenderHal->pStateHeap = pStateHeap;
    pRenderHal->dwStateHeapSize = sizeof(RENDERHAL_STATE_HEAP_LEGACY);
    MHW_RENDERHAL_CHK_NULL(pStateHeap);

    pStateHeap->kernelHashTable = CmHashTable();
    pStateHeap->kernelHashTable.Init();

    // Apply state heap settings (iMediaStates not actually used in DSH)
    if (pSettingsLegacy)
    {
        pRenderHal->StateHeapSettings.iMediaStateHeaps = pSettingsLegacy->iMediaStates;
    }

    // Apply Dynamic state heap settings
    if (pSettingsLegacy && pSettingsLegacy->pDynSettings)
    {
        PRENDERHAL_INTERFACE_LEGACY pRenderHalLegacy = (PRENDERHAL_INTERFACE_LEGACY)pRenderHal;
        pRenderHalLegacy->DynamicHeapSettings = *(pSettingsLegacy->pDynSettings);
    }

    // Apply SSH settings for the current platform
    pRenderHal->StateHeapSettings.iSurfaceStateHeaps =
                                pRenderHal->StateHeapSettings.iMediaStateHeaps;

    // Allocate and initialize state heaps (GSH, SSH, ISH)
    MHW_RENDERHAL_CHK_STATUS(pRenderHal->pfnAllocateStateHeaps(pRenderHal, &pRenderHal->StateHeapSettings));

    // If ASM debug is enabled, allocate debug resource
    MHW_RENDERHAL_CHK_STATUS(RenderHal_AllocateDebugSurface(pRenderHal));

finish:
    return eStatus;
}

//!
//! \brief    Issue command to write timestamp
//! \param    [in] pRenderHal
//! \param    [in] pCmdBuffer
//! \param    [in] bStartTime
//! \return   MOS_STATUS
//!
MOS_STATUS RenderHal_DSH_SendTimingData(
    PRENDERHAL_INTERFACE         pRenderHal,
    PMOS_COMMAND_BUFFER          pCmdBuffer,
    bool                         bStartTime);

//! Following functions are defined in RenderHal and are not used by RenderHal_DSH
//! ------------------------------------------------------------------------------
PRENDERHAL_MEDIA_STATE RenderHal_DSH_AssignMediaState(
    PRENDERHAL_INTERFACE     pRenderHal,
    RENDERHAL_COMPONENT      componentID)
{
    MHW_RENDERHAL_ASSERT( true );
    return nullptr;
}

int32_t RenderHal_DSH_AllocateMediaID(
    PRENDERHAL_INTERFACE        pRenderHal,
    int32_t                     iKernelAllocationID,
    int32_t                     iBindingTableID,
    int32_t                     iCurbeOffset,
    int32_t                     iCurbeLength,
    int32_t                     iCrsThrdConstDataLn,
    PMHW_GPGPU_WALKER_PARAMS    pGpGpuWalkerParams)
{
    MHW_RENDERHAL_ASSERT( true );
    return -1;
}

int32_t RenderHal_DSH_LoadKernel(
    PRENDERHAL_INTERFACE        pRenderHal,
    PCRENDERHAL_KERNEL_PARAM    pParameters,
    PMHW_KERNEL_PARAM           pKernel,
    Kdll_CacheEntry             *pKernelEntry)
{
    MHW_RENDERHAL_ASSERT( true );
    return -1;
}

MOS_STATUS RenderHal_DSH_UnloadKernel(
    PRENDERHAL_INTERFACE        pRenderHal,
    int32_t                     iKernelAllocationID)
{
    MHW_RENDERHAL_ASSERT( true );
    return MOS_STATUS_UNIMPLEMENTED;
}

void RenderHal_DSH_ResetKernels(
    PRENDERHAL_INTERFACE        pRenderHal)
{
    MHW_RENDERHAL_ASSERT( true );
    return;
}

void RenderHal_DSH_TouchKernel(
    PRENDERHAL_INTERFACE        pRenderHal,
    int32_t                     iKernelAllocationID)
{
    MHW_RENDERHAL_ASSERT( true );
    return;
}

int32_t RenderHal_DSH_GetKernelOffset(
    PRENDERHAL_INTERFACE        pRenderHal,
    int32_t                     iKernelAllocationIndex)
{
    MHW_RENDERHAL_ASSERT( true );
    return 0;
}
//! ------------------------------------------------------------------------------

void RenderHal_InitInterfaceEx_Legacy(PRENDERHAL_INTERFACE_LEGACY pRenderHal);

//!
//! \brief    Init Interface using Dynamic State Heap
//! \details  Initializes RenderHal Interface structure, responsible for HW
//!           abstraction of HW Rendering Engine for CM(MDF) and VP.
//! \param    PRENDERHAL_INTERFACE pRenderHal
//!           [in] Pointer to RenderHal Interface Structure
//! \param    MhwCpInterface** ppCpInterface
//!           [in/out] Pointer of pointer to MHW CP Interface Structure, which 
//!           is created during renderhal initialization
//! \param    PMOS_INTERFACE pOsInterface
//!           [in] Pointer to OS Interface Structure
//! \return   MOS_STATUS
//!           MOS_STATUS_UNKNOWN : Invalid parameters
//!
MOS_STATUS RenderHal_InitInterface_Dynamic(
    PRENDERHAL_INTERFACE_LEGACY pRenderHal,
    MhwCpInterface              **ppCpInterface,
    PMOS_INTERFACE              pOsInterface)
{
    MOS_STATUS eStatus;

    //---------------------------------------
    MHW_RENDERHAL_ASSERT(pRenderHal);
    //---------------------------------------
    // Init interfaces - some of which will be later replaced for DSH
    MHW_RENDERHAL_CHK_STATUS(RenderHal_InitInterface_Legacy(pRenderHal, ppCpInterface, pOsInterface));

    // Initialization/Cleanup function
    pRenderHal->pfnInitialize                 = RenderHal_DSH_Initialize;

    // Allocate/Destroy state heaps
    pRenderHal->pfnAllocateStateHeaps         = RenderHal_DSH_AllocateStateHeaps;
    pRenderHal->pfnFreeStateHeaps             = RenderHal_DSH_FreeStateHeaps;

    pRenderHal->pfnAssignSpaceInStateHeap     = RenderHal_DSH_AssignSpaceInStateHeap;

    // Media states management functions
    pRenderHal->pfnAssignMediaState           = RenderHal_DSH_AssignMediaState;
    pRenderHal->pfnAllocateMediaID            = RenderHal_DSH_AllocateMediaID;
    pRenderHal->pfnGetMediaID                 = RenderHal_DSH_GetMediaID;
    pRenderHal->pfnAssignDynamicState         = RenderHal_DSH_AssignDynamicState;
    pRenderHal->pfnReleaseDynamicState        = RenderHal_DSH_ReleaseDynamicState;
    pRenderHal->pfnSubmitDynamicState         = RenderHal_DSH_SubmitDynamicState;
    pRenderHal->pfnAllocateDynamicMediaID     = RenderHal_DSH_AllocateDynamicMediaID;

    // Kernel management functions
    pRenderHal->pfnRefreshSync                = RenderHal_DSH_RefreshSync;
    pRenderHal->pfnLoadKernel                 = RenderHal_DSH_LoadKernel;
    pRenderHal->pfnUnloadKernel               = RenderHal_DSH_UnloadKernel;
    pRenderHal->pfnResetKernels               = RenderHal_DSH_ResetKernels;
    pRenderHal->pfnTouchKernel                = RenderHal_DSH_TouchKernel;
    pRenderHal->pfnGetKernelOffset            = RenderHal_DSH_GetKernelOffset;
    pRenderHal->pfnUnregisterKernel           = RenderHal_DSH_UnregisterKernel;

    // Dynamic Kernel management functions (not implemented here)
    pRenderHal->pfnLoadDynamicKernel          = RenderHal_DSH_LoadDynamicKernel;
    pRenderHal->pfnAllocateDynamicKernel      = RenderHal_DSH_AllocateDynamicKernel;
    pRenderHal->pfnSearchDynamicKernel        = RenderHal_DSH_SearchDynamicKernel;
    pRenderHal->pfnUnloadDynamicKernel        = RenderHal_DSH_UnloadDynamicKernel;
    pRenderHal->pfnRefreshDynamicKernels      = RenderHal_DSH_RefreshDynamicKernels;
    pRenderHal->pfnResetDynamicKernels        = RenderHal_DSH_ResetDynamicKernels;
    pRenderHal->pfnTouchDynamicKernel         = RenderHal_DSH_TouchDynamicKernel;
    pRenderHal->pfnExpandKernelStateHeap      = RenderHal_DSH_ExpandKernelStateHeap;

    // ISA ASM Debug support functions
    pRenderHal->pfnLoadSipKernel              = RenderHal_DSH_LoadSipKernel;
    pRenderHal->pfnSendSipStateCmd            = RenderHal_DSH_SendSipStateCmd;

    // Command buffer programming functions
    pRenderHal->pfnLoadCurbeData              = RenderHal_DSH_LoadCurbeData;
    pRenderHal->pfnSendCurbeLoad              = RenderHal_DSH_SendCurbeLoad;
    pRenderHal->pfnSendStateBaseAddress       = RenderHal_DSH_SendStateBaseAddress;

    // Initialize OS dependent RenderHal Interfaces common to all platforms
    pRenderHal->pfnReset                      = RenderHal_DSH_Reset;
    pRenderHal->pfnSendTimingData             = RenderHal_DSH_SendTimingData;
    pRenderHal->pfnSendSyncTag                = RenderHal_DSH_SendSyncTag;

    // Sampler state, interface descriptor, VFE params
    pRenderHal->pfnSetSamplerStates           = RenderHal_DSH_SetSamplerStates;
    pRenderHal->pfnSetupInterfaceDescriptor   = RenderHal_DSH_SetupInterfaceDescriptor;
    pRenderHal->pfnSetVfeStateParams          = RenderHal_DSH_SetVfeStateParams;

    // Hardware dependent calls
    pRenderHal->pfnGetSamplerOffsetAndPtr     = RenderHal_DSH_GetSamplerOffsetAndPtr;

    // Special functions
    RenderHal_InitInterfaceEx_Legacy(pRenderHal);

    // Initialize the DSH settings
    pRenderHal->pRenderHalPltInterface->InitDynamicHeapSettings(pRenderHal);

finish:
    return eStatus;
}
