/*
* Copyright (c) 2014-2017, Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
//!
//! \file     mhw_render_generic.h
//! \brief    MHW interface templates for render engine commands
//! \details  Impelements shared HW command construction functions across all platforms as templates
//!

#ifndef __MHW_RENDER_GENERIC_H__
#define __MHW_RENDER_GENERIC_H__

#include "mhw_render.h"

template <class TRenderCmds>
class MhwRenderInterfaceGeneric : public MhwRenderInterface
{
protected:
    MhwRenderInterfaceGeneric(
        MhwMiInterface          *miInterface,
        PMOS_INTERFACE          osInterface,
        MEDIA_SYSTEM_INFO       *gtSystemInfo,
        uint8_t                 newStateHeapManagerRequested) :
        MhwRenderInterface(miInterface, osInterface, gtSystemInfo, newStateHeapManagerRequested){}

public:
    virtual ~MhwRenderInterfaceGeneric() { MHW_FUNCTION_ENTER; }

    MOS_STATUS AddPipelineSelectCmd(
        PMOS_COMMAND_BUFFER             cmdBuffer,
        bool                            gpGpuPipe)
    {
        MHW_FUNCTION_ENTER;

        MHW_MI_CHK_NULL(cmdBuffer);

        typename TRenderCmds::PIPELINE_SELECT_CMD  cmd;
        cmd.DW0.PipelineSelection = (gpGpuPipe) ? cmd.PIPELINE_SELECTION_GPGPU : cmd.PIPELINE_SELECTION_MEDIA;

        MHW_MI_CHK_STATUS(Mos_AddCommand(cmdBuffer, &cmd, cmd.byteSize));

        return MOS_STATUS_SUCCESS;
    }

    MOS_STATUS AddStateBaseAddrCmd(
        PMOS_COMMAND_BUFFER                 cmdBuffer,
        PMHW_STATE_BASE_ADDR_PARAMS         params)
    {
        MHW_FUNCTION_ENTER;

        MHW_MI_CHK_NULL(cmdBuffer);
        MHW_MI_CHK_NULL(params);

        MHW_RESOURCE_PARAMS resourceParams;
        MOS_ZeroMemory(&resourceParams, sizeof(resourceParams));
        resourceParams.dwLsbNum      = MHW_RENDER_ENGINE_STATE_BASE_ADDRESS_SHIFT;
        resourceParams.HwCommandType = MOS_STATE_BASE_ADDR;

        typename TRenderCmds::STATE_BASE_ADDRESS_CMD cmd;

        if (params->presGeneralState)
        {
            cmd.DW1_2.GeneralStateBaseAddressModifyEnable    = true;
            cmd.DW12.GeneralStateBufferSizeModifyEnable      = true;
            resourceParams.presResource                      = params->presGeneralState;
            resourceParams.dwOffset                          = 0;
            resourceParams.pdwCmd                            = cmd.DW1_2.Value;
            resourceParams.dwLocationInCmd                   = 1;

            // upper bound of the allocated resource will not be set
            resourceParams.dwUpperBoundLocationOffsetFromCmd = 0;

            InitMocsParams(resourceParams, &cmd.DW1_2.Value[0], 5, 10);

            MHW_MI_CHK_STATUS(AddResourceToCmd(
                m_osInterface,
                cmdBuffer,
                &resourceParams));

            if (params->mocs4GeneralState != 0)
            {
                cmd.DW1_2.GeneralStateMemoryObjectControlState   = params->mocs4GeneralState;
            }

            cmd.DW12.GeneralStateBufferSize = (params->dwGeneralStateSize + MHW_PAGE_SIZE - 1) / MHW_PAGE_SIZE;
        }

        if (m_osInterface->bNoParsingAssistanceInKmd)
        {
            uint32_t indirectStateOffset, indirectStateSize;
            MHW_MI_CHK_STATUS(m_osInterface->pfnGetIndirectState(m_osInterface, &indirectStateOffset, &indirectStateSize));

            // When KMD parsing assistance is not used,
            // UMD is required to set up the SSH
            // in the STATE_BASE_ADDRESS command.
            // All addresses used in the STATE_BASE_ADDRESS
            // command need to have the modify
            // bit associated with it set to 1.
            cmd.DW4_5.SurfaceStateBaseAddressModifyEnable    = true;
            resourceParams.presResource                      = &cmdBuffer->OsResource;
            resourceParams.dwOffset                          = indirectStateOffset;
            resourceParams.pdwCmd                            = cmd.DW4_5.Value;
            resourceParams.dwLocationInCmd                   = 4;

            // upper bound of the allocated resource will not be set
            resourceParams.dwUpperBoundLocationOffsetFromCmd = 0;

            InitMocsParams(resourceParams, &cmd.DW4_5.Value[0], 5, 10);

            MHW_MI_CHK_STATUS(AddResourceToCmd(
                m_osInterface,
                cmdBuffer,
                &resourceParams));

            if (params->mocs4SurfaceState != 0)
            {
                cmd.DW4_5.SurfaceStateMemoryObjectControlState = params->mocs4SurfaceState;
            }
        }

        if (params->presDynamicState)
        {
            cmd.DW6_7.DynamicStateBaseAddressModifyEnable    = true;
            cmd.DW13.DynamicStateBufferSizeModifyEnable      = true;
            resourceParams.presResource                      = params->presDynamicState;
            resourceParams.dwOffset                          = 0;
            resourceParams.pdwCmd                            = cmd.DW6_7.Value;
            resourceParams.dwLocationInCmd                   = 6;
            resourceParams.bIsWritable                       = params->bDynamicStateRenderTarget;

            // upper bound of the allocated resource will not be set
            resourceParams.dwUpperBoundLocationOffsetFromCmd = 0;

            InitMocsParams(resourceParams, &cmd.DW6_7.Value[0], 5, 10);

            MHW_MI_CHK_STATUS(AddResourceToCmd(
                m_osInterface,
                cmdBuffer,
                &resourceParams));

            if (params->mocs4DynamicState != 0)
            {
                cmd.DW6_7.DynamicStateMemoryObjectControlState = params->mocs4DynamicState;
            }

            cmd.DW13.DynamicStateBufferSize                  = (params->dwDynamicStateSize + MHW_PAGE_SIZE - 1) / MHW_PAGE_SIZE;

            //Reset bRenderTarget as it should be enabled only for Dynamic State
            resourceParams.bIsWritable = false;
        }

        if (params->presIndirectObjectBuffer)
        {
            cmd.DW8_9.IndirectObjectBaseAddressModifyEnable     = true;
            cmd.DW14.IndirectObjectBufferSizeModifyEnable       = true;
            resourceParams.presResource                         = params->presIndirectObjectBuffer;
            resourceParams.dwOffset                             = 0;
            resourceParams.pdwCmd                               = cmd.DW8_9.Value;
            resourceParams.dwLocationInCmd                      = 8;

            // upper bound of the allocated resource will not be set
            resourceParams.dwUpperBoundLocationOffsetFromCmd    = 0;

            InitMocsParams(resourceParams, &cmd.DW8_9.Value[0], 5, 10);

            MHW_MI_CHK_STATUS(AddResourceToCmd(
                m_osInterface,
                cmdBuffer,
                &resourceParams));

            if (params->mocs4IndirectObjectBuffer != 0)
            {
                cmd.DW8_9.IndirectObjectMemoryObjectControlState = params->mocs4IndirectObjectBuffer;
            }

            cmd.DW14.IndirectObjectBufferSize                   = (params->dwIndirectObjectBufferSize + MHW_PAGE_SIZE - 1) / MHW_PAGE_SIZE;
        }

        if (params->presInstructionBuffer)
        {
            cmd.DW10_11.InstructionBaseAddressModifyEnable   = true;
            cmd.DW15.InstructionBufferSizeModifyEnable       = true;
            resourceParams.presResource                      = params->presInstructionBuffer;
            resourceParams.dwOffset                          = 0;
            resourceParams.pdwCmd                            = cmd.DW10_11.Value;
            resourceParams.dwLocationInCmd                   = 10;

            // upper bound of the allocated resource will not be set
            resourceParams.dwUpperBoundLocationOffsetFromCmd = 0;

            InitMocsParams(resourceParams, &cmd.DW10_11.Value[0], 5, 10);

            MHW_MI_CHK_STATUS(AddResourceToCmd(
                m_osInterface,
                cmdBuffer,
                &resourceParams));

            if (params->mocs4InstructionCache != 0)
            {
                cmd.DW10_11.InstructionMemoryObjectControlState = params->mocs4InstructionCache;
            }

            cmd.DW15.InstructionBufferSize = (params->dwInstructionBufferSize + MHW_PAGE_SIZE - 1) / MHW_PAGE_SIZE;
        }

        // stateless dataport access
        cmd.DW3.StatelessDataPortAccessMemoryObjectControlState = params->mocs4StatelessDataport;

        MHW_MI_CHK_STATUS(Mos_AddCommand(cmdBuffer, &cmd, cmd.byteSize));

        return MOS_STATUS_SUCCESS;
    }

    MOS_STATUS AddMediaVfeCmd(
        PMOS_COMMAND_BUFFER             cmdBuffer,
        PMHW_VFE_PARAMS                 params)
    {
        MHW_FUNCTION_ENTER;

        MHW_MI_CHK_NULL(cmdBuffer);
        MHW_MI_CHK_NULL(params);

        typename TRenderCmds::MEDIA_VFE_STATE_CMD cmd;

        if (params->pKernelState)
        {
            MHW_MI_CHK_NULL(params->pKernelState);

            cmd.DW3.MaximumNumberOfThreads          = (params->dwMaximumNumberofThreads) ?
                params->dwMaximumNumberofThreads - 1 : params->pKernelState->KernelParams.iThreadCount - 1;
            cmd.DW5.CurbeAllocationSize             =
                MOS_ROUNDUP_SHIFT(params->pKernelState->KernelParams.iCurbeLength, 5);
            cmd.DW5.UrbEntryAllocationSize          = MOS_MAX(1,
                MOS_ROUNDUP_SHIFT(params->pKernelState->KernelParams.iInlineDataLength, 5));

            uint32_t numberofURBEntries   =
                (m_hwCaps.dwMaxURBSize -
                cmd.DW5.CurbeAllocationSize -
                params->pKernelState->KernelParams.iIdCount) /
                cmd.DW5.UrbEntryAllocationSize;
            numberofURBEntries            = MOS_CLAMP_MIN_MAX(numberofURBEntries, 1, 64);
            cmd.DW3.NumberOfUrbEntries      = numberofURBEntries;
        }
        else
        {
            if (params->dwNumberofURBEntries == 0)
            {
                MHW_ASSERTMESSAGE("Parameter dwNumberofURBEntries is 0 will cause divided by zero.");
                return MOS_STATUS_INVALID_PARAMETER;
            }

            if (params->dwPerThreadScratchSpace)
            {
                cmd.DW1.PerThreadScratchSpace       = params->dwPerThreadScratchSpace;
                cmd.DW1.ScratchSpaceBasePointer     = params->dwScratchSpaceBasePointer >> 10;
                cmd.DW2.ScratchSpaceBasePointerHigh = 0;
            }
            cmd.DW3.MaximumNumberOfThreads          = (params->dwMaximumNumberofThreads) ?
                params->dwMaximumNumberofThreads - 1 : m_hwCaps.dwMaxThreads - 1;
            cmd.DW3.NumberOfUrbEntries              = params->dwNumberofURBEntries;
            cmd.DW5.CurbeAllocationSize             = params->dwCURBEAllocationSize >> 5;
            cmd.DW5.UrbEntryAllocationSize          = (params->dwURBEntryAllocationSize) ?
                params->dwURBEntryAllocationSize :
                (m_hwCaps.dwMaxURBSize -
                cmd.DW5.CurbeAllocationSize -
                m_hwCaps.dwMaxInterfaceDescriptorEntries) /
                params->dwNumberofURBEntries;
        }

        if ((cmd.DW3.NumberOfUrbEntries > m_hwCaps.dwMaxURBEntries) ||
            (cmd.DW5.CurbeAllocationSize > m_hwCaps.dwMaxCURBEAllocationSize) ||
            (cmd.DW5.UrbEntryAllocationSize > m_hwCaps.dwMaxURBEntryAllocationSize) ||
            (cmd.DW3.NumberOfUrbEntries * cmd.DW5.UrbEntryAllocationSize +
            cmd.DW5.CurbeAllocationSize +
            m_hwCaps.dwMaxInterfaceDescriptorEntries > m_hwCaps.dwMaxURBSize))
        {
            MHW_ASSERTMESSAGE("Parameters requested exceed maximum supported by HW.");
            return MOS_STATUS_INVALID_PARAMETER;
        }

        MHW_MI_CHK_STATUS(Mos_AddCommand(cmdBuffer, &cmd, cmd.byteSize));

        return MOS_STATUS_SUCCESS;
    }

    MOS_STATUS AddMediaCurbeLoadCmd(
        PMOS_COMMAND_BUFFER             cmdBuffer,
        PMHW_CURBE_LOAD_PARAMS          params)
    {
        MHW_FUNCTION_ENTER;

        MHW_MI_CHK_NULL(cmdBuffer);
        MHW_MI_CHK_NULL(params);

        typename TRenderCmds::MEDIA_CURBE_LOAD_CMD cmd;

        if (params->pKernelState)
        {
            MHW_MI_CHK_NULL(m_stateHeapInterface->pStateHeapInterface);

            auto kernelState = params->pKernelState;

            cmd.DW2.CurbeTotalDataLength    = (uint32_t)MOS_ALIGN_CEIL(
                kernelState->KernelParams.iCurbeLength,
                m_stateHeapInterface->pStateHeapInterface->GetCurbeAlignment());
            cmd.DW3.CurbeDataStartAddress   = MOS_ALIGN_CEIL(
                (kernelState->m_dshRegion.GetOffset() +
                kernelState->dwCurbeOffset),
                m_stateHeapInterface->pStateHeapInterface->GetCurbeAlignment());
        }
        else
        {
            cmd.DW2.CurbeTotalDataLength    = params->dwCURBETotalDataLength;
            cmd.DW3.CurbeDataStartAddress   = params->dwCURBEDataStartAddress;
        }

        // Send the command only if there is data to load
        if (cmd.DW2.CurbeTotalDataLength)
        {
            MHW_MI_CHK_STATUS(Mos_AddCommand(cmdBuffer, &cmd, cmd.byteSize));
        }
        else
        {
            MHW_NORMALMESSAGE("MEDIA_CURBE_LOAD must load data. Command skipped.");
        }

        return MOS_STATUS_SUCCESS;
    }

    MOS_STATUS AddMediaIDLoadCmd(
        PMOS_COMMAND_BUFFER             cmdBuffer,
        PMHW_ID_LOAD_PARAMS             params)
    {
        MHW_FUNCTION_ENTER;

        MHW_MI_CHK_NULL(cmdBuffer);
        MHW_MI_CHK_NULL(params);
        MHW_MI_CHK_NULL(m_stateHeapInterface->pStateHeapInterface);

        typename TRenderCmds::MEDIA_INTERFACE_DESCRIPTOR_LOAD_CMD cmd;

        if (params->pKernelState)
        {
            auto kernelState = params->pKernelState;

            cmd.DW2.InterfaceDescriptorTotalLength      =
                m_stateHeapInterface->pStateHeapInterface->GetSizeofCmdInterfaceDescriptorData() * params->dwNumKernelsLoaded;
            cmd.DW3.InterfaceDescriptorDataStartAddress = MOS_ALIGN_CEIL(
                kernelState->m_dshRegion.GetOffset() +
                kernelState->dwIdOffset +
                (params->dwIdIdx * m_stateHeapInterface->pStateHeapInterface->GetSizeofCmdInterfaceDescriptorData()),
                m_stateHeapInterface->pStateHeapInterface->GetIdAlignment());
        }
        // Client managed MediaIDs
        else if (params->dwInterfaceDescriptorLength)
        {
            cmd.DW2.InterfaceDescriptorTotalLength      = params->dwInterfaceDescriptorLength;
            cmd.DW3.InterfaceDescriptorDataStartAddress = params->dwInterfaceDescriptorStartOffset;
        }

        if (cmd.DW2.InterfaceDescriptorTotalLength > 0)
        {
            MHW_MI_CHK_STATUS(Mos_AddCommand(cmdBuffer, &cmd, cmd.byteSize));
        }
        else
        {
            MHW_NORMALMESSAGE("MEDIA_INTERFACE_DESCRIPTOR_LOAD must load data. Command skipped.");
        }

        return MOS_STATUS_SUCCESS;
    }

    MOS_STATUS AddMediaObject(
        PMOS_COMMAND_BUFFER             cmdBuffer,
        PMHW_BATCH_BUFFER               batchBuffer,
        PMHW_MEDIA_OBJECT_PARAMS        params)
    {
        MHW_FUNCTION_ENTER;

        MHW_MI_CHK_NULL(params);

        if (cmdBuffer == nullptr && batchBuffer == nullptr)
        {
            MHW_ASSERTMESSAGE("No valid buffer to add the command to!");
            return MOS_STATUS_INVALID_PARAMETER;
        }

        typename TRenderCmds::MEDIA_OBJECT_CMD cmd;

        if (params->dwInlineDataSize > 0)
        {
            cmd.DW0.DwordLength             =
                TRenderCmds::GetOpLength(((params->dwInlineDataSize / sizeof(uint32_t)) + cmd.dwSize));
        }

        cmd.DW1.InterfaceDescriptorOffset   = params->dwInterfaceDescriptorOffset;
        cmd.DW2.IndirectDataLength          = params->dwIndirectLoadLength;
        cmd.DW2.SubsliceDestinationSelect   = params->dwHalfSliceDestinationSelect;
        cmd.DW2.SliceDestinationSelect      = params->dwSliceDestinationSelect;
        cmd.DW2.ForceDestination            = params->bForceDestination;
        cmd.DW3.IndirectDataStartAddress    = params->dwIndirectDataStartAddress;

        MHW_MI_CHK_STATUS(Mhw_AddCommandCmdOrBB(
            cmdBuffer,
            batchBuffer,
            &cmd,
            cmd.byteSize));

        if (params->pInlineData && params->dwInlineDataSize > 0)
        {
            MHW_MI_CHK_STATUS(Mhw_AddCommandCmdOrBB(
                cmdBuffer,
                batchBuffer,
                params->pInlineData,
                params->dwInlineDataSize));
        }

        return MOS_STATUS_SUCCESS;
    }

    MOS_STATUS AddMediaObjectWalkerCmd(
        PMOS_COMMAND_BUFFER             cmdBuffer,
        PMHW_WALKER_PARAMS              params)
    {
        MHW_FUNCTION_ENTER;

        MHW_MI_CHK_NULL(cmdBuffer);
        MHW_MI_CHK_NULL(params);

        typename TRenderCmds::MEDIA_OBJECT_WALKER_CMD cmd;

        if (params->pInlineData)
        {
            cmd.DW0.DwordLength =
                TRenderCmds::GetOpLength(cmd.dwSize + params->InlineDataLength / sizeof(uint32_t));
        }

        cmd.DW1.InterfaceDescriptorOffset   = params->InterfaceDescriptorOffset;
        cmd.DW5.GroupIdLoopSelect           = params->GroupIdLoopSelect;
        cmd.DW6.ColorCountMinusOne          = params->ColorCountMinusOne;
        cmd.DW6.MiddleLoopExtraSteps        = params->MiddleLoopExtraSteps;
        cmd.DW6.MidLoopUnitX                = params->MidLoopUnitX;
        cmd.DW6.LocalMidLoopUnitY           = params->MidLoopUnitY;
        cmd.DW7.LocalLoopExecCount          = params->dwLocalLoopExecCount;
        cmd.DW7.GlobalLoopExecCount         = params->dwGlobalLoopExecCount;
        cmd.DW8.BlockResolutionX            = params->BlockResolution.x;
        cmd.DW8.BlockResolutionY            = params->BlockResolution.y;
        cmd.DW9.LocalStartX                 = params->LocalStart.x;
        cmd.DW9.LocalStartY                 = params->LocalStart.y;
        cmd.DW11.LocalOuterLoopStrideX      = params->LocalOutLoopStride.x;
        cmd.DW11.LocalOuterLoopStrideY      = params->LocalOutLoopStride.y;
        cmd.DW12.LocalInnerLoopUnitX        = params->LocalInnerLoopUnit.x;
        cmd.DW12.LocalInnerLoopUnitY        = params->LocalInnerLoopUnit.y;
        cmd.DW13.GlobalResolutionX          = params->GlobalResolution.x;
        cmd.DW13.GlobalResolutionY          = params->GlobalResolution.y;
        cmd.DW14.GlobalStartX               = params->GlobalStart.x;
        cmd.DW14.GlobalStartY               = params->GlobalStart.y;
        cmd.DW15.GlobalOuterLoopStrideX     = params->GlobalOutlerLoopStride.x;
        cmd.DW15.GlobalOuterLoopStrideY     = params->GlobalOutlerLoopStride.y;
        cmd.DW16.GlobalInnerLoopUnitX       = params->GlobalInnerLoopUnit.x;
        cmd.DW16.GlobalInnerLoopUnitY       = params->GlobalInnerLoopUnit.y;

        MHW_MI_CHK_STATUS(Mos_AddCommand(cmdBuffer, &cmd, cmd.byteSize));

        if (params->pInlineData)
        {
            if (params->InlineDataLength > 0)
            {
                MHW_MI_CHK_STATUS(Mos_AddCommand(
                    cmdBuffer,
                    params->pInlineData,
                    params->InlineDataLength));
            }
            else
            {
                MHW_NORMALMESSAGE("Inline data indicated, however cannot insert without valid length.");
            }
        }

        return MOS_STATUS_SUCCESS;
    }

    MOS_STATUS AddGpGpuWalkerStateCmd(
        PMOS_COMMAND_BUFFER             cmdBuffer,
        PMHW_GPGPU_WALKER_PARAMS        params)
    {
        MHW_FUNCTION_ENTER;

        MHW_MI_CHK_NULL(cmdBuffer);
        MHW_MI_CHK_NULL(params);

        if (params->ThreadDepth == 0)
        {
            params->ThreadDepth = 1;
        }
        if (params->GroupDepth == 0)
        {
            params->GroupDepth = 1;
        }

        typename TRenderCmds::GPGPU_WALKER_CMD cmd;
        cmd.DW1.InterfaceDescriptorOffset       = params->InterfaceDescriptorOffset;
        cmd.DW4.SimdSize                        = 2; // SIMD32
        cmd.DW4.ThreadWidthCounterMaximum       = params->ThreadWidth - 1;
        cmd.DW4.ThreadHeightCounterMaximum      = params->ThreadHeight - 1;
        cmd.DW4.ThreadDepthCounterMaximum       = params->ThreadDepth - 1;
        cmd.DW5.ThreadGroupIdStartingX          = 0;
        cmd.DW7.ThreadGroupIdXDimension         = params->GroupWidth;
        cmd.DW8.ThreadGroupIdStartingY          = 0;
        cmd.DW10.ThreadGroupIdYDimension        = params->GroupHeight;
        cmd.DW11.ThreadGroupIdStartingResumeZ   = 0;
        cmd.DW12.ThreadGroupIdZDimension        = params->GroupDepth;
        cmd.DW13.RightExecutionMask             = 0xffffffff;
        cmd.DW14.BottomExecutionMask            = 0xffffffff;

        MHW_MI_CHK_STATUS(Mos_AddCommand(cmdBuffer, &cmd, cmd.byteSize));

        return MOS_STATUS_SUCCESS;
    }
    MOS_STATUS AddChromaKeyCmd(
        PMOS_COMMAND_BUFFER             cmdBuffer,
        PMHW_CHROMAKEY_PARAMS           params)
    {
        MHW_FUNCTION_ENTER;

        MHW_MI_CHK_NULL(cmdBuffer);
        MHW_MI_CHK_NULL(params);

        typename TRenderCmds::_3DSTATE_CHROMA_KEY_CMD cmd;
        cmd.DW1.ChromakeyTableIndex = params->dwIndex;
        cmd.DW2.ChromakeyLowValue   = params->dwLow;
        cmd.DW3.ChromakeyHighValue  = params->dwHigh;

        MHW_MI_CHK_STATUS(Mos_AddCommand(cmdBuffer, &cmd, cmd.byteSize));

        return MOS_STATUS_SUCCESS;
    }

    MOS_STATUS AddSipStateCmd(
        PMOS_COMMAND_BUFFER             cmdBuffer,
        PMHW_SIP_STATE_PARAMS           params)
    {
        MHW_FUNCTION_ENTER;

        MHW_MI_CHK_NULL(cmdBuffer);
        MHW_MI_CHK_NULL(params);

        typename TRenderCmds::STATE_SIP_CMD cmd;
        cmd.DW1_2.SystemInstructionPointer = (uint64_t)(params->dwSipBase >> 4);

        MHW_MI_CHK_STATUS(Mos_AddCommand(cmdBuffer, &cmd, cmd.byteSize))

        return MOS_STATUS_SUCCESS;
    }

    inline uint32_t GetMediaObjectCmdSize()
    {
        return TRenderCmds::MEDIA_OBJECT_CMD::byteSize;
    }
};

#endif // __MHW_RENDER_GENERIC_H__
