/**
 * @file hv_drv_OsdShift.c
 * @brief Osd Driver font prop c file.
 * @details This file provides the following functions: \n
 *          (1) prop font drawing functions \n
 *
 * @author HiView SoC Software Team
 * @version 1.0.0
 * @date 2022-08-31
 * @copyright Copyright(c),2022-8, Hiview Software. All rights reserved.
 * @par History:
 * <table>
 * <tr><th>Author         <th>Date        <th>Change Description
 * <tr><td>OSD Group      <td>2022-08-31   <td>create
 * </table>
*/

#include "hv_mw_OsdLog.h"
#include "hv_comm_DataType.h"
#include "hv_vos_Memory.h"
#include "hv_res_OsdMoeRes.h"
#include "hv_drv_Osd.h"

static OsdShiftParam *s_pstShiftParam;

#if (HV_PROJECT_CONFIG_OSD_MARQUEE == HV_CONFIG_ON)
VOID Hv_Drv_OsdShift_SetReplaceEnable(OsdIndexColumn *pstColumn, BOOL bEnable)
{
    s_pstShiftParam->bReplaceMatrix = bEnable;
    s_pstShiftParam->pstCurColumn = pstColumn;
}

OsdIndexColumn *Hv_Drv_OsdShift_GetCurrentColumn(VOID)
{
    return s_pstShiftParam->pstCurColumn;
}

BOOL Hv_Drv_OsdShift_IsReplace(VOID)
{
    return s_pstShiftParam->bReplaceMatrix;
}

VOID Hv_Drv_OsdShift_DropNext(VOID)
{
    s_pstShiftParam->bDropNext = HV_TRUE;
}
#endif

VOID Hv_Drv_OsdShift_InitTransaction(OsdRowInfo *pstRowInfo, BOOL bIsUpdate, BOOL bUseUpdateRegion)
{
    OsdResourceSize enSize = pstRowInfo->enSize;
    OsdResourceType enType = pstRowInfo->enType;

    HV_MEMSET(s_pstShiftParam, 0, sizeof(*s_pstShiftParam));

    s_pstShiftParam->pstCurrentRowInfo = pstRowInfo;
    s_pstShiftParam->enSize = enSize;
    s_pstShiftParam->usBytes = Hv_Drv_OsdCommon_GetResourceBytes(enSize, enType);
    s_pstShiftParam->bIsUpdate = bIsUpdate;
#if (HV_OSD_CONFIG_RESERVE_SLOTS_BYROW == HV_CONFIG_OFF)
    s_pstShiftParam->bUseUpdateRegion = bUseUpdateRegion;
#endif

    Hv_Drv_OsdResource_GetSize(enSize, &s_pstShiftParam->ucWidth, &s_pstShiftParam->ucHeight);
    /* fast way */
    if ((s_pstShiftParam->ucWidth == 16) && (enType == OSD_RESOURCE_TYPE_1BIT))
    {
        s_pstShiftParam->pfShiftRoutine = Hv_Drv_OsdShift_16_1Bit;
    }
    else if ((s_pstShiftParam->ucWidth == 16) && (enType == OSD_RESOURCE_TYPE_2BIT))
    {
        s_pstShiftParam->pfShiftRoutine = Hv_Drv_OsdShift_16_2Bit;
    }
    else
    {
        s_pstShiftParam->pfShiftRoutine = Hv_Drv_OsdShift_General;
    }

#if (HV_PROJECT_CONFIG_OSD_MARQUEE == HV_CONFIG_ON)
    s_pstShiftParam->bReplaceMatrix = HV_FALSE;
#endif
}

UCHAR8 Hv_Drv_OsdShift_GetCurrentWidth(VOID)
{
    return s_pstShiftParam->ucMergeWidth;
}

BOOL Hv_Drv_OsdShift_WriteCharacter(OsdRowInfo *pstRowInfo, const UCHAR8 *pucMatrix,
                                    USHORT16 usOffset, UCHAR8 ucRealWidth)
{
    return s_pstShiftParam->pfShiftRoutine(pstRowInfo, pucMatrix, usOffset, ucRealWidth);
}

UCHAR8* Hv_Drv_OsdShift_GetCurrentDstAddr(OsdRowInfo *pstRowInfo)
{
    OsdRowCatalog *pstCatalog = NULL;
    OsdLoadedBank *pstLoadedBank = NULL;
    OsdLoadedBank *pstPrevLoadedBank = NULL;
    OsdIndexColumn *pstColumn = NULL;
    OsdUpdateManager *pstManager = NULL;
    UCHAR8 *pucDstAddr = NULL;
    UCHAR8 *pucSrc = NULL;
    UCHAR8 *pucDst = NULL;
    USHORT16 usSlot = 0;
    BOOL bCopied = HV_FALSE;
    BOOL bAllocated = HV_FALSE;
    BOOL bLeftLeaned = HV_TRUE;
    UCHAR8 ucIndex = 0;

#if (HV_PROJECT_CONFIG_OSD_MARQUEE == HV_CONFIG_ON)
    if (s_pstShiftParam->bReplaceMatrix)
    {
        pstLoadedBank = pstRowInfo->pstLoadedBank;
        usSlot = Hv_Cal_OsdIndex_GetColIndex(s_pstShiftParam->pstCurColumn);

        OSD_DRV_LOG_DEBUG("Matrix load at %x", usSlot);
        pucDstAddr = (UCHAR8*)(OSD_RESOURCE_DDR_ADDR(
                pstLoadedBank->usCurrentResourceOffset + usSlot * s_pstShiftParam->usBytes));
        ++s_pstShiftParam->pstCurColumn;

        return pucDstAddr;
    }
#endif

#if (HV_OSD_CONFIG_RESERVE_SLOTS_BYROW == HV_CONFIG_ON)
    pstLoadedBank = pstRowInfo->pstLoadedBank;
    usSlot = pstRowInfo->usBankSlot + pstRowInfo->ucCurIndex;
#else
    pstCatalog = Hv_Drv_OsdFont_GetCurrentCatalog();

    if (s_pstShiftParam->bIsUpdate)
    {
        if (!s_pstShiftParam->bUseUpdateRegion)
        {
            pstLoadedBank = pstRowInfo->pstLoadedBank;
            bLeftLeaned = (pstRowInfo->pstLoadedBank == pstCatalog->pstCatalogBank);

            bAllocated = Hv_Drv_OsdRadix_AllocSlot(pstCatalog->pstSlotsManager, !bLeftLeaned, &usSlot);
            if (HV_FALSE == bAllocated)
            {
                OSD_DRV_LOG_ERROR("osd fatal error: not enough slots to allocate from redraw region");

                usSlot = 0;
            }

            OSD_DRV_LOG_DEBUG("Update allocated slot: %d from %s child", usSlot,
                    bLeftLeaned ? "left" : "right");

            //Hv_Drv_OsdRadix_PrintTree(pstCatalog->pstSlotsManager);
        }
        else
        {
            pstManager = pstCatalog->pstUpdateManager;
            pstLoadedBank = pstManager->pstUpdateBank;

            bAllocated = Hv_Drv_OsdRadix_AllocSlot(pstManager->pstUpdateSlotsManager, HV_FALSE, &usSlot);
            if (HV_FALSE == bAllocated)
            {
                OSD_DRV_LOG_ERROR("osd fatal error: not enough slots to allocate from update region");

                usSlot = 0;
            }

            OSD_DRV_LOG_DEBUG("Update allocated slot: %d from update-tree", usSlot);

            //Hv_Drv_OsdRadix_PrintTree(pstManager->pstUpdateSlotsManager);
        }
    }
    else
    {
        pstLoadedBank = Hv_Drv_OsdResource_GetCurrentLoadedBank();
        usSlot = pstLoadedBank->usCurrentSlots;
        if (usSlot == OSD_BANK_CAPACITY)
        {
            OSD_DRV_LOG_DEBUG("resource count excess 512, create new bank");

            pstPrevLoadedBank = pstLoadedBank;
            /* alloc resource region */
            Hv_Drv_OsdResource_AllocRegion(OSD_BANK_CAPACITY * s_pstShiftParam->usBytes);

            pstLoadedBank = Hv_Drv_OsdResource_NewLoadedBank(
                    pstRowInfo->enSize, pstRowInfo->enType);

            pstColumn = (OsdIndexColumn*)pstRowInfo->pucColumnStart;
            /* copy drawn columns to new bank */
            for (ucIndex = 0; ucIndex < pstRowInfo->ucRowLen; ++ucIndex)
            {
                if (!Hv_Cal_OsdIndex_IsBlankColumn(pstColumn))
                {
                    if (!bCopied)
                    {
                        usSlot = Hv_Cal_OsdIndex_GetColIndex(pstColumn);

                        pucDst = OSD_RESOURCE_DDR_ADDR(pstLoadedBank->usCurrentResourceOffset);
                        pucSrc = OSD_RESOURCE_DDR_ADDR(pstPrevLoadedBank->usCurrentResourceOffset
                                + usSlot * s_pstShiftParam->usBytes);
                        HV_MEMCPY(pucDst, pucSrc, (OSD_BANK_CAPACITY - usSlot) * s_pstShiftParam->usBytes);
                        pstCatalog->ucUnusedSlots = OSD_BANK_CAPACITY - usSlot;

                        OSD_DRV_LOG_DEBUG("Copy %d slots from 0x%x to 0x%x", OSD_BANK_CAPACITY - usSlot, pucSrc, pucDst);

                        bCopied = HV_TRUE;
                    }

                    Hv_Cal_OsdIndex_SetColIndex(pstColumn, pstLoadedBank->usCurrentSlots++);
                }
                pstColumn++;
            }

            /* change row's loaded bank */
            pstRowInfo->pstLoadedBank = pstLoadedBank;
        }

        usSlot = pstLoadedBank->usCurrentSlots;
    }
#endif

    pucDstAddr = (UCHAR8*)(OSD_RESOURCE_DDR_ADDR(
            pstLoadedBank->usCurrentResourceOffset +
            usSlot * s_pstShiftParam->usBytes));

    return pucDstAddr;
}

BOOL Hv_Drv_OsdShift_WriteBlank(UCHAR8 ucWidth)
{
    UCHAR8 ucMergeWidth = s_pstShiftParam->ucMergeWidth;
    UCHAR8 *pucDstAddr = NULL;
    OsdRowInfo *pstRowInfo = s_pstShiftParam->pstCurrentRowInfo;
    BOOL bReadOut = HV_FALSE;

    s_pstShiftParam->ucMergeWidth += ucWidth;
    if (s_pstShiftParam->ucMergeWidth >= s_pstShiftParam->ucWidth)
    {
#if (HV_PROJECT_CONFIG_OSD_MARQUEE == HV_CONFIG_ON)
        if (!s_pstShiftParam->bDropNext)
        {
#endif
            pucDstAddr = Hv_Drv_OsdShift_GetCurrentDstAddr(pstRowInfo);
            HV_MEMCPY(pucDstAddr, s_pstShiftParam->aucBuffer,
                s_pstShiftParam->usBytes);
#if (HV_PROJECT_CONFIG_OSD_MARQUEE == HV_CONFIG_ON)
        }
        else
        {
            s_pstShiftParam->bDropNext = HV_FALSE;
        }
#endif

        HV_MEMSET(s_pstShiftParam->aucBuffer, 0, sizeof(s_pstShiftParam->aucBuffer));
        s_pstShiftParam->ucMergeWidth -= s_pstShiftParam->ucWidth;

        bReadOut = HV_TRUE;
    }
    return bReadOut;
}

UCHAR8 Hv_Drv_OsdShift_EndTransaction(BOOL bReturnRealWidth)
{
    UCHAR8 ucMergeWidth = s_pstShiftParam->ucMergeWidth;
    UCHAR8 *pucDstAddr = NULL;
    OsdRowInfo *pstRowInfo = s_pstShiftParam->pstCurrentRowInfo;

    OSD_DRV_LOG_DEBUG("osd shift, end of transaction");

    if (0 == ucMergeWidth)
    {
        OSD_DRV_LOG_DEBUG("no need to append empty character");
        return 0;
    }

    if (!bReturnRealWidth)
    {
        ucMergeWidth = OSD_REAL_FONTWIDTH(ucMergeWidth);
    }

#if (HV_PROJECT_CONFIG_OSD_MARQUEE == HV_CONFIG_ON)
    if (!s_pstShiftParam->bDropNext)
    {
#endif
        pucDstAddr = Hv_Drv_OsdShift_GetCurrentDstAddr(pstRowInfo);
        HV_MEMCPY(pucDstAddr, s_pstShiftParam->aucBuffer,
                s_pstShiftParam->usBytes);
#if (HV_PROJECT_CONFIG_OSD_MARQUEE == HV_CONFIG_ON)
    }
    else
    {
        s_pstShiftParam->bDropNext = HV_FALSE;
    }
#endif

    HV_MEMSET(s_pstShiftParam->aucBuffer, 0, sizeof(s_pstShiftParam->aucBuffer));
    s_pstShiftParam->ucMergeWidth = 0;

    return ucMergeWidth;
}

VOID Hv_Drv_OsdShift_CopyDirectly(OsdRowInfo *pstRowInfo, const UCHAR8 *pucMatrix, USHORT16 usOffset)
{
    USHORT16 usBytes = s_pstShiftParam->usBytes;
    USHORT16 *pusFont = NULL;
    UCHAR8 *pucDstAddr = NULL;

    pusFont = (USHORT16*)(&pucMatrix[usOffset * usBytes]);

    // copy out
    pucDstAddr = Hv_Drv_OsdShift_GetCurrentDstAddr(pstRowInfo);
    HV_MEMCPY(pucDstAddr, pusFont, usBytes);
}

BOOL Hv_Drv_OsdShift_16_1Bit(OsdRowInfo *pstRowInfo, const UCHAR8 *pucMatrix, USHORT16 usOffset, UCHAR8 ucRealWidth)
{
    UCHAR8 ucHIdx = 0;
    UCHAR8 ucWidth = 16;
    UCHAR8 ucFontOff = 0;
    UCHAR8 ucShift = 0;
    USHORT16 usBytes = s_pstShiftParam->usBytes;
    USHORT16 *pusBuffer = (USHORT16*)s_pstShiftParam->aucBuffer;
    USHORT16 *pusFont = NULL;
    UCHAR8 *pucDstAddr = NULL;
    //OsdRowInfo *pstRowInfo = s_pstShiftParam->pstCurrentRowInfo;
    BOOL bReadOut = HV_FALSE;

    pusFont = (USHORT16*)(&pucMatrix[usOffset * usBytes]);

    ucShift = 16 - ucRealWidth;
    for (ucHIdx = 0; ucHIdx < s_pstShiftParam->ucHeight; ++ucHIdx)
    {
        pusBuffer[ucHIdx] |= (((pusFont[ucHIdx] << ucShift) >> ucShift) << s_pstShiftParam->ucMergeWidth);
    }

    ucFontOff = ucWidth - s_pstShiftParam->ucMergeWidth;
    s_pstShiftParam->ucMergeWidth += ucRealWidth;
    if (s_pstShiftParam->ucMergeWidth >= ucWidth)
    {
        // copy out
#if (HV_PROJECT_CONFIG_OSD_MARQUEE == HV_CONFIG_ON)
        if (!s_pstShiftParam->bDropNext)
        {
#endif
            pucDstAddr = Hv_Drv_OsdShift_GetCurrentDstAddr(pstRowInfo);
            HV_MEMCPY(pucDstAddr, pusBuffer, usBytes);
#if (HV_PROJECT_CONFIG_OSD_MARQUEE == HV_CONFIG_ON)
        }
        else
        {
            s_pstShiftParam->bDropNext = HV_FALSE;
        }
#endif

        // copy remaining dots
        HV_MEMSET(pusBuffer, 0, sizeof(s_pstShiftParam->aucBuffer));
        for (ucHIdx = 0; ucHIdx < s_pstShiftParam->ucHeight; ++ucHIdx)
        {
            /* convert to USHORT16 explicitly to avoid arithmetic shift right */
            pusBuffer[ucHIdx] |= ((USHORT16)((USHORT16)(pusFont[ucHIdx] << ucShift) >> ucShift) >> ucFontOff);
        }
        s_pstShiftParam->ucMergeWidth -= ucWidth;

        bReadOut = HV_TRUE;
    }

    return bReadOut;
}

BOOL Hv_Drv_OsdShift_16_2Bit(OsdRowInfo *pstRowInfo, const UCHAR8 *pucMatrix, USHORT16 usOffset, UCHAR8 ucRealWidth)
{
    UCHAR8 ucHIdx = 0;
    UCHAR8 ucWidth = 16;
    UCHAR8 ucFontOff = 0;
    UCHAR8 ucShift = 0;
    USHORT16 usBytes = s_pstShiftParam->usBytes;
    UINT32 *puiFont = NULL;
    UINT32 *puiBuffer = (UINT32*)s_pstShiftParam->aucBuffer;
    UCHAR8 *pucDstAddr = NULL;
    //OsdRowInfo *pstRowInfo = s_pstShiftParam->pstCurrentRowInfo;
    BOOL bReadOut = HV_FALSE;

    puiFont = (UINT32*)(&pucMatrix[usOffset * usBytes]);

    ucShift = (16 - ucRealWidth) * 2;
    for (ucHIdx = 0; ucHIdx < s_pstShiftParam->ucHeight; ++ucHIdx)
    {
        puiBuffer[ucHIdx] |= (((puiFont[ucHIdx] << ucShift) >> ucShift) << (s_pstShiftParam->ucMergeWidth * 2));
    }

    ucFontOff = ucWidth - s_pstShiftParam->ucMergeWidth;
    s_pstShiftParam->ucMergeWidth += ucRealWidth;
    if (s_pstShiftParam->ucMergeWidth >= ucWidth)
    {
        // copy out
#if (HV_PROJECT_CONFIG_OSD_MARQUEE == HV_CONFIG_ON)
        if (!s_pstShiftParam->bDropNext)
        {
#endif
            pucDstAddr = Hv_Drv_OsdShift_GetCurrentDstAddr(pstRowInfo);
            HV_MEMCPY(pucDstAddr, puiBuffer, usBytes);
#if (HV_PROJECT_CONFIG_OSD_MARQUEE == HV_CONFIG_ON)
        }
        else
        {
            s_pstShiftParam->bDropNext = HV_FALSE;
        }
#endif

        // copy remaining dots
        HV_MEMSET(puiBuffer, 0, sizeof(s_pstShiftParam->aucBuffer));
        for (ucHIdx = 0; ucHIdx < s_pstShiftParam->ucHeight; ++ucHIdx)
        {
            /* convert to UINT32 explicitly to avoid arithmetic shift right */
            puiBuffer[ucHIdx] |= ((UINT32)((UINT32)(puiFont[ucHIdx] << ucShift) >> ucShift) >> (ucFontOff * 2));
        }
        s_pstShiftParam->ucMergeWidth -= ucWidth;

        bReadOut = HV_TRUE;
    }

    return bReadOut;
}

static VOID Hv_Drv_OsdShift_ShiftOneRow(UINT32 *puiDst, USHORT16 usDstStartBit,
                                        UINT32 *puiSrc, USHORT16 usSrcStartBit,
                                        UCHAR8 ucToMergeBits)
{
    USHORT16 usQuo = 0;
    USHORT16 usFontQuo = 0;
    UCHAR8 ucRmd = 0;
    UCHAR8 ucFontRmd = 0;
    UCHAR8 ucNewMergedBits = 0;
    UCHAR8 ucRowBits = 32;
    UCHAR8 ucEffectiveBits = 0;
    UINT32 uiMask = 0;

    usQuo = usDstStartBit >> 5;
    ucRmd = usDstStartBit & 0x1f;

    usFontQuo = usSrcStartBit >> 5;
    ucFontRmd = usSrcStartBit & 0x1f;

    while (ucNewMergedBits < ucToMergeBits)
    {
        ucEffectiveBits = ucRowBits - max(ucFontRmd, ucRmd);
        ucEffectiveBits = ucEffectiveBits < ucToMergeBits - ucNewMergedBits
            ? ucEffectiveBits : ucToMergeBits - ucNewMergedBits;

        uiMask = ((1ULL << ucEffectiveBits) - 1) << ucFontRmd;

        puiDst[usQuo] |= (((UINT32)(puiSrc[usFontQuo] & uiMask) >> ucFontRmd) << ucRmd);
        ucNewMergedBits += ucEffectiveBits;
        if (ucRmd > ucFontRmd)
        {
            ucFontRmd += ucRowBits - ucRmd;
            ucRmd = 0;
            ++usQuo;
        }
        else if (ucRmd < ucFontRmd)
        {
            ucRmd += ucRowBits - ucFontRmd;

            ucFontRmd = 0;
            ++usFontQuo;
        }
        else
        {
            ucFontRmd = 0;
            ++usFontQuo;
            ucRmd = 0;
            ++usQuo;
        }
    }
}

BOOL Hv_Drv_OsdShift_General(OsdRowInfo *pstRowInfo, const UCHAR8 *pucMatrix, USHORT16 usOffset, UCHAR8 ucRealWidth)
{
    //OsdRowInfo *pstRowInfo = s_pstShiftParam->pstCurrentRowInfo;
    UCHAR8 ucWidth = s_pstShiftParam->ucWidth;
    UCHAR8 ucHIdx = 0;
    UCHAR8 ucBits = 1 << pstRowInfo->enType;
    UCHAR8 ucMergeWidth = s_pstShiftParam->ucMergeWidth;
    UCHAR8 ucToMergeWidth = 0;
    UCHAR8 ucToMergeBits = 0;
    UCHAR8 ucPrePendingBits = 0;
    UCHAR8 ucRemainWidth = ucWidth - ucMergeWidth;
    UINT32 *puiBuffer = (UINT32*)s_pstShiftParam->aucBuffer;
    UINT32 *puiFont = NULL;
    UINT32 *puiOrigFont = NULL;
    USHORT16 usMulti = 0;
    USHORT16 usFontMulti = 0;
    UCHAR8 *pucDstAddr = NULL;
    USHORT16 usBytes = s_pstShiftParam->usBytes;
    UINT32 uiMask = 0;
    USHORT16 ausMulti[36];
    BOOL bReadOut = HV_FALSE;

    for (ucHIdx = 0; ucHIdx < s_pstShiftParam->ucHeight; ++ucHIdx)
    {
        ausMulti[ucHIdx] = ucHIdx * ucWidth * ucBits;
    }

    ucToMergeWidth = ucRemainWidth > ucRealWidth ? ucRealWidth : ucRemainWidth;
    ucToMergeBits = ucToMergeWidth * ucBits;

    puiOrigFont = puiFont = (UINT32*)(&pucMatrix[usOffset * usBytes]);
    // font起始地址可能不是4字节对齐的，所以要补齐
    ucPrePendingBits = ((UINT32)puiFont & 0x03) * 8;
    puiFont = (UINT32*)((UINT32)puiFont & (~0x03UL));

    if (0 != ucMergeWidth)
    {
        for (ucHIdx = 0; ucHIdx < s_pstShiftParam->ucHeight; ++ucHIdx)
        {
            usMulti = ausMulti[ucHIdx] + ucMergeWidth * ucBits;
            usFontMulti = ausMulti[ucHIdx] + ucPrePendingBits;

            Hv_Drv_OsdShift_ShiftOneRow(puiBuffer, usMulti, puiFont, usFontMulti, ucToMergeBits);
        }
    }
    else
    {
        // fast way, copy directly
        HV_MEMCPY(puiBuffer, puiOrigFont, usBytes);
    }

    s_pstShiftParam->ucMergeWidth += ucRealWidth;

    if (ucRemainWidth <= ucRealWidth)
    {
        // copy out
#if (HV_PROJECT_CONFIG_OSD_MARQUEE == HV_CONFIG_ON)
        if (!s_pstShiftParam->bDropNext)
        {
#endif
            pucDstAddr = Hv_Drv_OsdShift_GetCurrentDstAddr(pstRowInfo);
            HV_MEMCPY(pucDstAddr, puiBuffer, usBytes);
#if (HV_PROJECT_CONFIG_OSD_MARQUEE == HV_CONFIG_ON)
        }
        else
        {
            s_pstShiftParam->bDropNext = HV_FALSE;
        }
#endif

        // copy remaining dots
        HV_MEMSET(puiBuffer, 0, sizeof(s_pstShiftParam->aucBuffer));
        ucToMergeBits = (ucRealWidth - ucRemainWidth) * ucBits;
        for (ucHIdx = 0; ucHIdx < s_pstShiftParam->ucHeight; ++ucHIdx)
        {
            usMulti = ausMulti[ucHIdx];
            usFontMulti = ausMulti[ucHIdx] + ucRemainWidth * ucBits + ucPrePendingBits;

            Hv_Drv_OsdShift_ShiftOneRow(puiBuffer, usMulti, puiFont, usFontMulti, ucToMergeBits);
        }

        s_pstShiftParam->ucMergeWidth -= ucWidth;

        bReadOut = HV_TRUE;
    }

    return bReadOut;
}

VOID Hv_Drv_OsdShift_Preserve(UCHAR8 *pucBuffer, UCHAR8 *pucRealWidth)
{
    HV_MEMCPY(pucBuffer, s_pstShiftParam->aucBuffer, s_pstShiftParam->usBytes);
    *pucRealWidth = s_pstShiftParam->ucMergeWidth;

    return;
}

VOID Hv_Drv_OsdShift_Restore(UCHAR8 *pucBuffer, UCHAR8 ucRealWidth)
{
    HV_MEMSET(s_pstShiftParam->aucBuffer, 0, sizeof(s_pstShiftParam->aucBuffer));
    HV_MEMCPY(s_pstShiftParam->aucBuffer, pucBuffer, s_pstShiftParam->usBytes);
    s_pstShiftParam->ucMergeWidth = ucRealWidth;

    return;
}

VOID Hv_Drv_OsdShift_Init(VOID)
{
    s_pstShiftParam = (OsdShiftParam*)OSD_DRIVER_ALLOC_STATIC(OsdShiftParam, 1);
    HV_MEMSET(s_pstShiftParam, 0, sizeof(*s_pstShiftParam));
}
