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

#include "codechal_hw.h"
#include "codeckrnheader.h"
#include "codechal_utilities.h"

MOS_STATUS CodecHalInitMediaObjectWalkerParams(
    CodechalHwInterface *hwInterface,
    PMHW_WALKER_PARAMS walkerParams,
    PCODECHAL_WALKER_CODEC_PARAMS walkerCodecParams)
{
    CODECHAL_PUBLIC_CHK_NULL_RETURN(hwInterface);
    CODECHAL_PUBLIC_CHK_NULL_RETURN(walkerParams);
    CODECHAL_PUBLIC_CHK_NULL_RETURN(walkerCodecParams);

    MOS_ZeroMemory(walkerParams, sizeof(MHW_WALKER_PARAMS));

    walkerParams->WalkerMode               =
        (MHW_WALKER_MODE)walkerCodecParams->WalkerMode;
    walkerParams->UseScoreboard            = walkerCodecParams->bUseScoreboard;

    walkerParams->BlockResolution.x        = walkerCodecParams->dwResolutionX;
    walkerParams->BlockResolution.y        = walkerCodecParams->dwResolutionY;

    walkerParams->GlobalResolution.x       = walkerCodecParams->dwResolutionX;
    walkerParams->GlobalResolution.y       = walkerCodecParams->dwResolutionY;

    walkerParams->GlobalOutlerLoopStride.x = walkerCodecParams->dwResolutionX;
    walkerParams->GlobalOutlerLoopStride.y = 0;

    walkerParams->GlobalInnerLoopUnit.x    = 0;
    walkerParams->GlobalInnerLoopUnit.y    = walkerCodecParams->dwResolutionY;

    // Gen7.5 & Gen8: 0x3FF, Gen9: 0x7FF
    walkerParams->dwLocalLoopExecCount     = 0xFFFF;  //MAX VALUE
    walkerParams->dwGlobalLoopExecCount    = 0xFFFF;  //MAX VALUE

    if (walkerCodecParams->bMbEncIFrameDistInUse || walkerCodecParams->bNoDependency)
    {
        walkerParams->ScoreboardMask         = 0;
        // Raster scan walking pattern
        walkerParams->LocalOutLoopStride.x   = 0;
        walkerParams->LocalOutLoopStride.y   = 1;
        walkerParams->LocalInnerLoopUnit.x   = 1;
        walkerParams->LocalInnerLoopUnit.y   = 0;
        walkerParams->LocalEnd.x             = walkerCodecParams->dwResolutionX - 1;
        walkerParams->LocalEnd.y             = 0;
    }
    else if (walkerCodecParams->bUseVerticalRasterScan)
    {
        walkerParams->ScoreboardMask         = 0x1;
        walkerParams->LocalOutLoopStride.x   = 1;
        walkerParams->LocalOutLoopStride.y   = 0;
        walkerParams->LocalInnerLoopUnit.x   = 0;
        walkerParams->LocalInnerLoopUnit.y   = 1;
        walkerParams->LocalEnd.x             = 0;
        walkerParams->LocalEnd.y             = walkerCodecParams->dwResolutionY - 1;
    }
    else
    {
        walkerParams->LocalEnd.x             = 0;
        walkerParams->LocalEnd.y             = 0;

        if (walkerCodecParams->WalkerDegree == CODECHAL_46_DEGREE)   // Gen6 only VP8 HybridPak2Pattern
        {
            // 46 degree walking pattern
            walkerParams->ScoreboardMask         = walkerCodecParams->ScoreboardMask;
            walkerParams->LocalOutLoopStride.x   = 1;
            walkerParams->LocalOutLoopStride.y   = 0;
            walkerParams->LocalInnerLoopUnit.x   = 0x3FF; // -1
            walkerParams->LocalInnerLoopUnit.y   = 1;
        }
        else if (walkerCodecParams->WalkerDegree == CODECHAL_45Z_DEGREE)
        {
            // 45z degree pattern
            walkerParams->ScoreboardMask = 0x0F;

            walkerParams->dwGlobalLoopExecCount = 0x3FF;
            walkerParams->dwLocalLoopExecCount = 0x3FF;

            walkerParams->GlobalResolution.x = uint32_t(walkerCodecParams->dwResolutionX / 2.f) + 1;
            walkerParams->GlobalResolution.y = 2 * walkerCodecParams->dwResolutionY;

            walkerParams->GlobalStart.x = 0;
            walkerParams->GlobalStart.y = 0;

            walkerParams->GlobalOutlerLoopStride.x = walkerParams->GlobalResolution.x;
            walkerParams->GlobalOutlerLoopStride.y = 0;

            walkerParams->GlobalInnerLoopUnit.x = 0;
            walkerParams->GlobalInnerLoopUnit.y = walkerParams->GlobalResolution.y;

            walkerParams->BlockResolution.x = walkerParams->GlobalResolution.x;
            walkerParams->BlockResolution.y = walkerParams->GlobalResolution.y;

            walkerParams->LocalStart.x = 0;
            walkerParams->LocalStart.y = 0;

            walkerParams->LocalOutLoopStride.x = 1;
            walkerParams->LocalOutLoopStride.y = 0;

            walkerParams->LocalInnerLoopUnit.x = MOS_BITFIELD_VALUE((uint32_t)-1, 16);
            walkerParams->LocalInnerLoopUnit.y = 4;

            walkerParams->MiddleLoopExtraSteps = 3;
            walkerParams->MidLoopUnitX = 0;
            walkerParams->MidLoopUnitY = 1;
        }
        else if ( walkerCodecParams->WalkerDegree == CODECHAL_45_DEGREE ||     // Gen8,9
                 ( ( walkerCodecParams->wPictureCodingType == I_TYPE || (walkerCodecParams->wPictureCodingType == B_TYPE && !walkerCodecParams->bDirectSpatialMVPredFlag) )     // CHECK B_TYPE ALWAYS
                   && walkerCodecParams->WalkerDegree != CODECHAL_26_DEGREE ) )
        {
            // 45 degree walking pattern
            walkerParams->ScoreboardMask         = 0x03;
            walkerParams->LocalOutLoopStride.x   = 1;
            walkerParams->LocalOutLoopStride.y   = 0;
            walkerParams->LocalInnerLoopUnit.x   = MOS_BITFIELD_VALUE((uint32_t)-1, 16);     // Gen9: 0xFFF Gen6,8: 0x3FF
            walkerParams->LocalInnerLoopUnit.y   = 1;
        }
        else if ( walkerCodecParams->WalkerDegree == CODECHAL_26Z_DEGREE )
        {
            // 26z degree walking pattern used for HEVC
            walkerParams->ScoreboardMask         = 0x7f;

            // z-order in the local loop
            walkerParams->LocalOutLoopStride.x   = 0;
            walkerParams->LocalOutLoopStride.y   = 1;
            walkerParams->LocalInnerLoopUnit.x   = 1;
            walkerParams->LocalInnerLoopUnit.y   = 0;

            // dispatch 4 threads together in one LCU
            walkerParams->BlockResolution.x        = 2;
            walkerParams->BlockResolution.y        = 2;

            // 26 degree in the global loop
            walkerParams->GlobalOutlerLoopStride.x = 2;
            walkerParams->GlobalOutlerLoopStride.y = 0;

            walkerParams->GlobalInnerLoopUnit.x    = 0xFFF -4 + 1; // -4 in 2's compliment format
            walkerParams->GlobalInnerLoopUnit.y    = 2;
        }
        else
        {
            // 26 degree walking pattern
            walkerParams->ScoreboardMask         = 0x0F;
            walkerParams->LocalOutLoopStride.x   = 1;
            walkerParams->LocalOutLoopStride.y   = 0;
            walkerParams->LocalInnerLoopUnit.x   = MOS_BITFIELD_VALUE((uint32_t)-2, 16);     // Gen9: 0xFFE Gen6,8: 0x3FE
            walkerParams->LocalInnerLoopUnit.y   = 1;
        }
    }

    if (walkerCodecParams->bMbaff)
    {
        walkerParams->ScoreboardMask              = 0xFF;
        walkerParams->MiddleLoopExtraSteps        = 1;
        walkerParams->MidLoopUnitY                = 1;
        walkerParams->LocalInnerLoopUnit.y        = 2;
    }

    // In case of multiple Slice scenarios, every slice can be processed parallelly
    // to enhance the performance. This is accomplished by  launching the slices concurrently,
    // providing the X and Y position of the thread along with Color bit. The AVC MBEnc kernel
    // uses the color bit sent in the header to identify the Slice and calculates the MBY index
    // accordingly.The color bit literally conveys the slice number of the MB.
    if (walkerCodecParams->bColorbitSupported && walkerCodecParams->dwNumSlices <= CODECHAL_MEDIA_WALKER_MAX_COLORS)
    {
        walkerParams->ColorCountMinusOne       = walkerCodecParams->dwNumSlices - 1;
        walkerParams->BlockResolution.y        = walkerCodecParams->usSliceHeight;
        walkerParams->GlobalResolution.y       = walkerCodecParams->usSliceHeight;
        walkerParams->GlobalInnerLoopUnit.y    = walkerCodecParams->usSliceHeight;
    }

    if(walkerCodecParams->bGroupIdSelectSupported)
    {
        walkerParams->GroupIdLoopSelect    = walkerCodecParams->ucGroupId;
    }

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodecHalGetKernelBinaryAndSize(
    uint8_t*   kernelBase,
    uint32_t   kernelUID,
    uint8_t**  kernelBinary,
    uint32_t*  size)
{
#ifdef ENABLE_KERNELS

    CODECHAL_PUBLIC_CHK_NULL_RETURN(kernelBase);
    CODECHAL_PUBLIC_CHK_NULL_RETURN(kernelBinary);
    CODECHAL_PUBLIC_CHK_NULL_RETURN(size);

    if (kernelUID >= IDR_CODEC_TOTAL_NUM_KERNELS)
    {
        return MOS_STATUS_INVALID_PARAMETER;
    }

    auto kernelOffsetTable = (uint32_t*)kernelBase;
    auto binaryBase = (uint8_t*)(kernelOffsetTable + IDR_CODEC_TOTAL_NUM_KERNELS + 1);

    *size = kernelOffsetTable[kernelUID + 1] - kernelOffsetTable[kernelUID];
    *kernelBinary = (*size) > 0 ? binaryBase + kernelOffsetTable[kernelUID] : nullptr;
#else
    *size = 0;
    *kernelBinary = nullptr;
#endif

    return MOS_STATUS_SUCCESS;
}

void CodecHal_GetSurfaceWidthInBytes(
    PMOS_SURFACE  surface,
    uint32_t     *widthInBytes)
{
    uint32_t        width;

    switch (surface->Format)
    {
        case Format_IMC1:
        case Format_IMC3:
        case Format_IMC2:
        case Format_IMC4:
        case Format_NV12:
        case Format_YV12:
        case Format_I420:
        case Format_IYUV:
        case Format_400P:
        case Format_411P:
        case Format_422H:
        case Format_422V:
        case Format_444P:
        case Format_RGBP:
        case Format_BGRP:
            width = surface->dwWidth;
            break;
        case Format_YUY2:
        case Format_YUYV:
        case Format_YVYU:
        case Format_UYVY:
        case Format_VYUY:
        case Format_P010:
            width = surface->dwWidth << 1;
            break;
        case Format_Y210:
        case Format_Y216:
        case Format_A8R8G8B8:
        case Format_X8R8G8B8:
        case Format_A8B8G8R8:
        case Format_R32U:
        case Format_R32F:
            width = surface->dwWidth << 2;
            break;
        default:
            width = surface->dwWidth;
            break;
    }

    *widthInBytes = width;
}

MOS_STATUS CodecHalSetRcsSurfaceState(
    CodechalHwInterface             *hwInterface,
    PMOS_COMMAND_BUFFER             cmdBuffer,
    PCODECHAL_SURFACE_CODEC_PARAMS  surfaceCodecParams,
    PMHW_KERNEL_STATE               kernelState)
{
    CODECHAL_PUBLIC_CHK_NULL_RETURN(hwInterface);
    CODECHAL_PUBLIC_CHK_NULL_RETURN(surfaceCodecParams);
    CODECHAL_PUBLIC_CHK_NULL_RETURN(hwInterface->GetRenderInterface());
    CODECHAL_PUBLIC_CHK_NULL_RETURN(hwInterface->GetRenderInterface()->m_stateHeapInterface);
    CODECHAL_PUBLIC_CHK_NULL_RETURN(hwInterface->GetOsInterface());

    PMHW_STATE_HEAP_INTERFACE stateHeapInterface = hwInterface->GetRenderInterface()->m_stateHeapInterface;
    PMOS_INTERFACE osInterface = hwInterface->GetOsInterface();

    MHW_RCS_SURFACE_PARAMS surfaceRcsParams;
    MOS_ZeroMemory(&surfaceRcsParams, sizeof(MHW_RCS_SURFACE_PARAMS));

    // default initial values
    surfaceRcsParams.dwNumPlanes                      = 1;    // MHW_GENERIC_PLANE = MHW_Y_PLANE
    surfaceRcsParams.dwCacheabilityControl            = surfaceCodecParams->dwCacheabilityControl;
    surfaceRcsParams.bRenderTarget                    = surfaceCodecParams->bRenderTarget;
    surfaceRcsParams.bIsWritable                      = surfaceCodecParams->bIsWritable;
    surfaceRcsParams.dwBaseAddrOffset[MHW_Y_PLANE]    = surfaceCodecParams->dwOffset;

    uint32_t                        surfaceFormat;
    MOS_SURFACE                     bufferSurface;
    if (surfaceCodecParams->bIs2DSurface)  // 2D
    {
        if (surfaceCodecParams->bUse32UnormSurfaceFormat)
        {
            surfaceFormat = MHW_GFX3DSTATE_SURFACEFORMAT_R32_UNORM;
        }
        else if (surfaceCodecParams->bUse16UnormSurfaceFormat)
        {
            surfaceFormat = MHW_GFX3DSTATE_SURFACEFORMAT_R16_UNORM;
        }
        else if (surfaceCodecParams->bUseARGB8Format)
        {
            // Ds+Copy kernel requires input surface set to ARGB8
            surfaceFormat = MHW_GFX3DSTATE_SURFACEFORMAT_R8G8B8A8_UNORM;
        }
        else if (surfaceCodecParams->bUse32UINTSurfaceFormat)
        {
            surfaceFormat = MHW_GFX3DSTATE_SURFACEFORMAT_R32_UINT;
        }
        else if (surfaceCodecParams->psSurface->Format == Format_YUY2)
        {
            surfaceFormat = MHW_GFX3DSTATE_SURFACEFORMAT_YCRCB_NORMAL;
        }
        else if (surfaceCodecParams->psSurface->Format == Format_UYVY)
        {
            surfaceFormat = MHW_GFX3DSTATE_SURFACEFORMAT_YCRCB_SWAPY;
        }
        else if (surfaceCodecParams->psSurface->Format == Format_P010)
        {
            surfaceFormat = MHW_GFX3DSTATE_SURFACEFORMAT_R16_UNORM;
        }
        else //NV12
        {
            surfaceFormat = MHW_GFX3DSTATE_SURFACEFORMAT_R8_UNORM;
        }

        surfaceRcsParams.ForceSurfaceFormat[MHW_Y_PLANE]      = surfaceFormat;
        surfaceRcsParams.dwSurfaceType                        = GFX3DSTATE_SURFACETYPE_2D;
        // MMC info passed with psSurface->CompressionMode
        surfaceRcsParams.psSurface                            = surfaceCodecParams->psSurface;

        uint32_t widthInBytes;
        if( surfaceCodecParams->bMediaBlockRW )
        {
            CodecHal_GetSurfaceWidthInBytes(surfaceCodecParams->psSurface, &widthInBytes);
            surfaceRcsParams.dwWidthToUse[MHW_Y_PLANE]        = WIDTH_IN_DW(widthInBytes);
        }
        else
        {
            surfaceRcsParams.dwWidthToUse[MHW_Y_PLANE]        = surfaceCodecParams->psSurface->dwWidth;
        }

        surfaceRcsParams.dwHeightToUse[MHW_Y_PLANE]           = (surfaceCodecParams->dwHeightInUse == 0) ?
            ((surfaceCodecParams->bUseHalfHeight) ? (surfaceCodecParams->psSurface->dwHeight / 2) : surfaceCodecParams->psSurface->dwHeight)
            : surfaceCodecParams->dwHeightInUse;

        if (surfaceCodecParams->bCheckCSC8Format &&
            (surfaceCodecParams->psSurface->Format == Format_AYUV || surfaceCodecParams->psSurface->Format == Format_Y410 ||
            surfaceCodecParams->psSurface->Format == Format_R10G10B10A2 || surfaceCodecParams->psSurface->Format == Format_B10G10R10A2))
        {
            surfaceRcsParams.ForceSurfaceFormat[MHW_Y_PLANE] = MHW_GFX3DSTATE_SURFACEFORMAT_R8_UNORM;
            surfaceRcsParams.dwWidthToUse[MHW_Y_PLANE] = surfaceRcsParams.dwWidthToUse[MHW_Y_PLANE] * 4;
        }

        surfaceRcsParams.dwBindingTableOffset[MHW_Y_PLANE]    = surfaceCodecParams->dwBindingTableOffset;
        surfaceRcsParams.dwYOffset[MHW_Y_PLANE]               = surfaceCodecParams->psSurface->YPlaneOffset.iYOffset;
        surfaceRcsParams.bVertLineStride                      = surfaceCodecParams->dwVerticalLineStride;
        surfaceRcsParams.bVertLineStrideOffs                  = surfaceCodecParams->dwVerticalLineStrideOffset;
        surfaceRcsParams.psSurface->dwDepth                   = 1;  // depth needs to be 0 for codec 2D surface

        if (surfaceCodecParams->bUseUVPlane)  // UV
        {
            surfaceRcsParams.dwNumPlanes                          = 2;    // Y, UV
            if (surfaceCodecParams->bForceChromaFormat)
            {
                surfaceRcsParams.ForceSurfaceFormat[MHW_U_PLANE]  = surfaceCodecParams->ChromaType;
            }
            else
            {
                MOS_MEMCOMP_STATE mmcstate;

                CODECHAL_PUBLIC_CHK_STATUS_RETURN(osInterface->pfnGetMemoryCompressionMode(
                    osInterface, &surfaceRcsParams.psSurface->OsResource, &mmcstate));

                // MMC HW requires GFX3DSTATE_SURFACEFORMAT_YCRCB_SWAPUVY format for P010 UV planes.
                surfaceRcsParams.ForceSurfaceFormat[MHW_U_PLANE] = (surfaceCodecParams->psSurface->Format == Format_P010) ?
                    ((mmcstate != MOS_MEMCOMP_DISABLED) ? MHW_GFX3DSTATE_SURFACEFORMAT_YCRCB_SWAPUVY : MHW_GFX3DSTATE_SURFACEFORMAT_R16G16_UNORM) :
                    MHW_GFX3DSTATE_SURFACEFORMAT_R16_UINT;
            }
            surfaceRcsParams.dwBindingTableOffset[MHW_U_PLANE]    = surfaceCodecParams->dwUVBindingTableOffset;

            widthInBytes = surfaceCodecParams->psSurface->dwWidth;
            if (surfaceCodecParams->psSurface->Format == Format_P010)
            {
                widthInBytes *= 2;
            }
            surfaceRcsParams.dwWidthToUse[MHW_U_PLANE]            = (surfaceCodecParams->bMediaBlockRW) ?
                WIDTH_IN_DW(widthInBytes) : (surfaceCodecParams->psSurface->dwWidth / 2);
            surfaceRcsParams.dwHeightToUse[MHW_U_PLANE]           = (surfaceCodecParams->bUseHalfHeight) ?
                (surfaceCodecParams->psSurface->dwHeight / 4) : (surfaceCodecParams->psSurface->dwHeight / 2);

            if (surfaceCodecParams->psSurface->Format == Format_YUY2V || surfaceCodecParams->psSurface->Format == Format_Y216V || surfaceCodecParams->psSurface->Format == Format_P208)
            {
                surfaceRcsParams.dwHeightToUse[MHW_U_PLANE] = surfaceRcsParams.dwHeightToUse[MHW_U_PLANE] * 2;
            }

            if (IS_Y_MAJOR_TILE_FORMAT(surfaceRcsParams.psSurface->TileType))
            {
                uint32_t tileHeightAlignment =
                    (MOS_TILE_YS == surfaceRcsParams.psSurface->TileType) ? MOS_YSTILE_H_ALIGNMENT : MOS_YTILE_H_ALIGNMENT;

                surfaceRcsParams.dwBaseAddrOffset[MHW_U_PLANE] =
                    surfaceCodecParams->psSurface->dwPitch *
                    MOS_ALIGN_FLOOR(surfaceCodecParams->psSurface->UPlaneOffset.iYOffset, tileHeightAlignment);
                surfaceRcsParams.dwYOffset[MHW_U_PLANE] =
                    (surfaceCodecParams->psSurface->UPlaneOffset.iYOffset % tileHeightAlignment);
            }
            else if( MOS_TILE_LINEAR == surfaceRcsParams.psSurface->TileType )
            {
                surfaceRcsParams.dwBaseAddrOffset[MHW_U_PLANE] =
                    surfaceCodecParams->psSurface->dwPitch * surfaceCodecParams->psSurface->UPlaneOffset.iYOffset;
                surfaceRcsParams.dwYOffset[MHW_U_PLANE] = 0;
            }
            else if( MOS_TILE_X == surfaceRcsParams.psSurface->TileType )
            {
                CODECHAL_PUBLIC_ASSERTMESSAGE("X_TILE surface not supported yet!");
                return MOS_STATUS_INVALID_PARAMETER;
            }
            else
            {
                CODECHAL_PUBLIC_ASSERTMESSAGE("Invalid surface TileType");
                return MOS_STATUS_INVALID_PARAMETER;
            }
        }

        if (surfaceCodecParams->bUseHalfHeight)
        {
            surfaceRcsParams.MediaBoundaryPixelMode       = GFX3DSTATE_BOUNDARY_INTERLACED_FRAME;
        }
    }
    else if (surfaceCodecParams->bUseAdvState)  // AdvState
    {
        surfaceRcsParams.bUseAdvState                       = surfaceCodecParams->bUseAdvState;
        // MMC info passed with psSurface->CompressionMode
        surfaceRcsParams.psSurface                          = surfaceCodecParams->psSurface;
        surfaceRcsParams.dwWidthToUse[MHW_Y_PLANE]            = surfaceCodecParams->dwWidthInUse;
        surfaceRcsParams.dwWidthToUse[MHW_U_PLANE]            = surfaceRcsParams.dwWidthToUse[MHW_V_PLANE] = surfaceCodecParams->dwWidthInUse / 2;
        surfaceRcsParams.dwHeightToUse[MHW_Y_PLANE]            = surfaceCodecParams->dwHeightInUse;
        surfaceRcsParams.dwHeightToUse[MHW_U_PLANE]         = surfaceRcsParams.dwHeightToUse[MHW_V_PLANE] =
            (surfaceCodecParams->psSurface->Format == Format_YUY2V || surfaceCodecParams->psSurface->Format == Format_Y216V) ?
            surfaceCodecParams->dwHeightInUse :
            surfaceCodecParams->dwHeightInUse / 2;

        surfaceRcsParams.ForceSurfaceFormat[MHW_Y_PLANE]    = MHW_MEDIASTATE_SURFACEFORMAT_PLANAR_420_8;
        surfaceRcsParams.dwBindingTableOffset[MHW_Y_PLANE]  = surfaceCodecParams->dwBindingTableOffset;
        surfaceRcsParams.bInterleaveChroma                  = true;
        surfaceRcsParams.Direction                          = (MHW_CHROMA_SITING_VDIRECTION) surfaceCodecParams->ucVDirection;
        surfaceRcsParams.dwYOffset[MHW_U_PLANE]             = surfaceCodecParams->psSurface->UPlaneOffset.iYOffset;
    }
    else // 1D Buffer
    {
        MOS_ZeroMemory(&bufferSurface, sizeof(MOS_SURFACE));
        MOS_SecureMemcpy(&bufferSurface.OsResource, sizeof(MOS_RESOURCE), surfaceCodecParams->presBuffer, sizeof(MOS_RESOURCE));

        surfaceRcsParams.psSurface = &bufferSurface;

        surfaceRcsParams.ForceSurfaceFormat[MHW_Y_PLANE]      = surfaceCodecParams->bRawSurface ?
            MHW_GFX3DSTATE_SURFACEFORMAT_RAW : MHW_GFX3DSTATE_SURFACEFORMAT_R32_UINT;
        surfaceRcsParams.dwBindingTableOffset[MHW_Y_PLANE]    = surfaceCodecParams->dwBindingTableOffset;

        surfaceRcsParams.psSurface->Type            = MOS_GFXRES_BUFFER;
        surfaceRcsParams.psSurface->Format          = Format_Buffer;
        surfaceRcsParams.psSurface->TileType        = MOS_TILE_LINEAR;
        surfaceRcsParams.psSurface->dwSize          = surfaceCodecParams->dwSize;
        surfaceRcsParams.psSurface->dwWidth         = (surfaceCodecParams->dwSize - 1) & 0x7F;
        surfaceRcsParams.psSurface->dwHeight        = ((surfaceCodecParams->dwSize - 1) & 0x1FFF80) >> 7;
        surfaceRcsParams.psSurface->dwDepth         = ((surfaceCodecParams->dwSize - 1) & 0xFE00000) >> 21;
        // GMM doesn't provide pitch info from surface
        surfaceRcsParams.psSurface->dwPitch         = surfaceCodecParams->bRawSurface ? sizeof(uint8_t) : sizeof(uint32_t);
        surfaceRcsParams.psSurface->bArraySpacing   = true;
    }

    CODECHAL_PUBLIC_CHK_STATUS_RETURN(stateHeapInterface->pfnSetSurfaceState(
        stateHeapInterface,
        kernelState,
        cmdBuffer,
        1,
        &surfaceRcsParams));

    return MOS_STATUS_SUCCESS;
}

MOS_STATUS CodecHalGetResourceInfo(
    PMOS_INTERFACE osInterface,
    PMOS_SURFACE surface)
{
    CODECHAL_PUBLIC_CHK_NULL_RETURN(surface);

    MOS_SURFACE details;
    MOS_ZeroMemory(&details, sizeof(details));
    details.Format = Format_Invalid;

    CODECHAL_PUBLIC_CHK_STATUS_RETURN(osInterface->pfnGetResourceInfo(osInterface, &surface->OsResource, &details));

    surface->Format        = details.Format;
    surface->dwWidth       = details.dwWidth;
    surface->dwHeight      = details.dwHeight;
    surface->dwPitch       = details.dwPitch;
    surface->dwDepth       = details.dwDepth;
    surface->dwQPitch      = details.dwQPitch;
    surface->bArraySpacing = details.bArraySpacing;
    surface->TileType      = details.TileType;
    surface->TileModeGMM   = details.TileModeGMM;
    surface->bGMMTileEnabled = details.bGMMTileEnabled;
    surface->dwOffset      = details.RenderOffset.YUV.Y.BaseOffset;
    surface->YPlaneOffset.iSurfaceOffset = details.RenderOffset.YUV.Y.BaseOffset;
    surface->YPlaneOffset.iXOffset = details.RenderOffset.YUV.Y.XOffset;
    surface->YPlaneOffset.iYOffset =
        (surface->YPlaneOffset.iSurfaceOffset - surface->dwOffset) / surface->dwPitch +
        details.RenderOffset.YUV.Y.YOffset;
    surface->UPlaneOffset.iSurfaceOffset = details.RenderOffset.YUV.U.BaseOffset;
    surface->UPlaneOffset.iXOffset       = details.RenderOffset.YUV.U.XOffset;
    surface->UPlaneOffset.iYOffset       =
        (surface->UPlaneOffset.iSurfaceOffset - surface->dwOffset) / surface->dwPitch +
        details.RenderOffset.YUV.U.YOffset;
    surface->UPlaneOffset.iLockSurfaceOffset = details.LockOffset.YUV.U;
    surface->VPlaneOffset.iSurfaceOffset = details.RenderOffset.YUV.V.BaseOffset;
    surface->VPlaneOffset.iXOffset       = details.RenderOffset.YUV.V.XOffset;
    surface->VPlaneOffset.iYOffset       =
        (surface->VPlaneOffset.iSurfaceOffset - surface->dwOffset) / surface->dwPitch +
        details.RenderOffset.YUV.V.YOffset;
    surface->VPlaneOffset.iLockSurfaceOffset = details.LockOffset.YUV.V;
    surface->bCompressible     = details.bCompressible;
    surface->CompressionMode   = details.CompressionMode;
    surface->bIsCompressed     = details.bIsCompressed;

    return MOS_STATUS_SUCCESS;
}
