/**
 * @file hv_drv_OsdResource.c
 * @brief Osd Driver resource management c file.
 * @details This file provides the following functions: \n
 *          (1) resource initialization functions \n
 *          (2) menu/logo resource load & clear 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_drv_Osd.h"
#include "hv_cal_Osd.h"
#include "hv_cal_Dma.h"
#include "hv_drv_Dma.h"

#ifdef HV_SCALER_DEBUG_VERSION
USHORT16 g_usResourceRealTotalSize = 0;
USHORT16 g_usResourceRealTotalSizeMax = 0;
#endif
static OsdResourceParam *s_pstResourceParam = NULL;

USHORT16 Hv_Drv_OsdResource_GetCurrentOffset(VOID)
{
    return s_pstResourceParam->usCurrentResourceOffset;
}

VOID Hv_Drv_OsdResource_GetSize(OsdResourceSize enSize, UCHAR8 *pucWidth, UCHAR8 *pucHeight)
{
    UCHAR8 aaResourceDim[15][2] = {
        {8, 8},
        {12, 12}, {12, 14}, {12, 16}, {12, 18},
        {16, 16}, {16, 18}, {16, 24},
        {20, 20}, {20, 24}, {20, 28},
        {24, 24}, {24, 30},
        {32, 32}, {32, 36},
    };

    if (enSize < OSD_RESOURCE_SIZE_USERDEFINED)
    {
        if (NULL != pucWidth)
        {
            *pucWidth = aaResourceDim[enSize][0];
        }
        if (NULL != pucHeight)
        {
            *pucHeight = aaResourceDim[enSize][1];
        }
        return;
    }

    if (NULL != pucWidth)
    {
        *pucWidth = (enSize >> OSD_RESOURCE_DEFINED_WIDTH_SHIFT) & 0x1f;
    }
    if (NULL != pucHeight)
    {
        *pucHeight = (enSize >> OSD_RESOURCE_DEFINED_HEIGHT_SHIFT) & 0x1f;
    }
}

OsdResourceSize Hv_Drv_OsdResource_ConvertSize(OsdResourceSize enSize)
{
    if (enSize < OSD_RESOURCE_SIZE_USERDEFINED)
    {
        return enSize;
    }
    else
    {
        return OSD_RESOURCE_SIZE_USERDEFINED;
    }
}

UCHAR8 Hv_Drv_OsdResource_GetBits(OsdResourceType enType)
{
    switch (enType)
    {
        case OSD_RESOURCE_TYPE_1BIT:
        {
            return 1;
        }
        case OSD_RESOURCE_TYPE_2BIT:
        {
            return 2;
        }
        case OSD_RESOURCE_TYPE_4BIT:
        {
            return 4;
        }
        case OSD_RESOURCE_TYPE_6BIT:
        {
            return 6;
        }
        case OSD_RESOURCE_TYPE_8BIT:
        {
            return 8;
        }
        default:
        {
            break;
        }
    }

    OSD_DRV_LOG_ERROR("unknown resource type: %d", enType);

    return 1;
}

VOID Hv_Drv_OsdResource_AllocBlankBank(VOID)
{
    OsdLoadedBank *pstBank = NULL;

    pstBank = s_pstResourceParam->pstOsdLoadedBanks
            + s_pstResourceParam->ucOsdMaxLoadBankCount - 1;
    pstBank->enSize = OSD_RESOURCE_SIZE_16X16;
    pstBank->enType = OSD_RESOURCE_TYPE_1BIT;
    pstBank->bIsBlankBank = HV_TRUE;
    pstBank->usCurrentResourceOffset = 0;

    s_pstResourceParam->pstBlankBank = pstBank;
}

UCHAR8 Hv_Drv_OsdResource_SearchForBlank(VOID)
{
    UCHAR8 ucIndex = 0;
    UCHAR8 ucHeight = 0;
    OsdPhyFontInfo *pstFontInfo = NULL;

    pstFontInfo = Hv_Drv_OsdFont_GetCurrentFontInfo();

    if (0xff != pstFontInfo->ucBlankBankIndex)
    {
        OSD_DRV_LOG_DEBUG("found blank resource: %d", pstFontInfo->ucBlankBankIndex);
        return pstFontInfo->ucBlankBankIndex;
    }

    for (ucIndex = 0; ucIndex < pstFontInfo->ucResourceCount; ++ucIndex)
    {
        Hv_Drv_OsdResource_GetSize(pstFontInfo->apResources[ucIndex]->enSize, NULL, &ucHeight);
        if (16 == ucHeight)
        {
            OSD_DRV_LOG_DEBUG("found height 16 resource for blank rows");
            pstFontInfo->ucBlankBankIndex = ucIndex;
            return ucIndex;
        }
    }

    HV_ASSERT_TRUE_RET(pstFontInfo->ucResourceCount < OSD_WINDOW_MAX_RESOURCE_COUNT, 0);

    if (NULL == s_pstResourceParam->pstBlankBank)
    {
        Hv_Drv_OsdResource_AllocBlankBank();
    }
    /* add virtual resource for blank rows */
    pstFontInfo->ucBlankBankIndex = pstFontInfo->ucResourceCount;
    pstFontInfo->apResources[pstFontInfo->ucResourceCount++] = s_pstResourceParam->pstBlankBank;

    OSD_DRV_LOG_DEBUG("add resource for blank rows %d", pstFontInfo->ucBlankBankIndex);
    return pstFontInfo->ucBlankBankIndex;
}

UCHAR8 Hv_Drv_OsdResource_FindResource(UCHAR8 ucBankID, BOOL bInsert)
{
    UCHAR8 ucIndex = 0;
    UCHAR8 ucAddPos = 0;
    OsdPhyFontInfo *pstFontInfo = NULL;
    OsdLoadedBank *pstLoadedBank = NULL;

    pstFontInfo = Hv_Drv_OsdFont_GetCurrentFontInfo();

    for (ucIndex = 0; ucIndex < pstFontInfo->ucResourceCount; ++ucIndex)
    {
        pstLoadedBank = pstFontInfo->apResources[ucIndex];

        if (pstLoadedBank->ucBankID == ucBankID)
        {
            OSD_DRV_LOG_DEBUG("found bank %d at index %d", ucBankID, ucIndex);
            return ucIndex;
        }
    }

    if (!bInsert)
    {
        OSD_DRV_LOG_WARN("bank %d not found", ucBankID);
        return 0;
    }

    ucAddPos = pstFontInfo->ucResourceCount;
    HV_ASSERT_TRUE_RET(ucAddPos < OSD_WINDOW_RESOURCE_SLOTS, 0);

    for (ucIndex = 0; ucIndex < s_pstResourceParam->ucOsdLoadBankCount; ++ucIndex)
    {
        pstLoadedBank = &s_pstResourceParam->pstOsdLoadedBanks[ucIndex];

        if (pstLoadedBank->ucBankID == ucBankID)
        {
            pstFontInfo->apResources[pstFontInfo->ucResourceCount++] = pstLoadedBank;

            OSD_DRV_LOG_DEBUG("bank %d add at index %d", ucBankID, ucAddPos);
            return ucAddPos;
        }
    }

    OSD_DRV_LOG_ERROR("Osd fatal error: bank %d not found", ucBankID);

    return 0;
}

VOID Hv_Drv_OsdResource_Init(VOID)
{
    s_pstResourceParam = (OsdResourceParam*)OSD_DRIVER_ALLOC_STATIC(OsdResourceParam, 1);
    HV_MEMSET(s_pstResourceParam, 0, sizeof(*s_pstResourceParam));
    s_pstResourceParam->bResourceCopyDone = HV_TRUE;

    s_pstResourceParam->ucOsdMaxLoadBankCount = HV_OSD_CONFIG_DYNAMIC_BANK_COUNT + 1;
    /* add additional blank bank */
    s_pstResourceParam->pstOsdLoadedBanks =
            (OsdLoadedBank*)OSD_DRIVER_ALLOC_STATIC(OsdLoadedBank,
                    s_pstResourceParam->ucOsdMaxLoadBankCount);
    s_pstResourceParam->pstBlankBank = NULL;
    s_pstResourceParam->pstOsdLoadedBlocks =
            (OsdLoadedBlock*)OSD_DRIVER_ALLOC_STATIC(OsdLoadedBlock, OSD_BLOCK_COUNT);

    OSD_DRV_LOG_DEBUG("%d OsdLoadedBank alloced at 0x%x, %d OsdLoadedBlock alloced at 0x%x",
            s_pstResourceParam->ucOsdMaxLoadBankCount, s_pstResourceParam->pstOsdLoadedBanks,
            OSD_BLOCK_COUNT, s_pstResourceParam->pstOsdLoadedBlocks);
}

VOID Hv_Drv_OsdResource_ClearLoadedResource(VOID)
{
    OSD_DRV_LOG_DEBUG("rearrange resource buffer");

    s_pstResourceParam->ucOsdLoadBankCount = 0;
    s_pstResourceParam->ucOsdLoadedBlockCount = 0;
    s_pstResourceParam->pstBlankBank = NULL;
    s_pstResourceParam->usCurrentResourceOffset = 0;
}

OsdLoadedBlock *Hv_Drv_OsdResource_FindLoadedBlock(UCHAR8 ucBlockID)
{
    UCHAR8 ucIndex = 0;
    OsdLoadedBlock *pstLoadedBlock = NULL;

    for (ucIndex = 0; ucIndex < s_pstResourceParam->ucOsdLoadedBlockCount; ++ucIndex)
    {
        pstLoadedBlock = s_pstResourceParam->pstOsdLoadedBlocks + ucIndex;
        if (pstLoadedBlock->ucBlockID == ucBlockID)
        {
            return pstLoadedBlock;
        }
    }

    return NULL;
}

UCHAR8 Hv_Drv_OsdResource_GetBlockId(const OsdBlock *pstBlock)
{
    return pstBlock - (OsdBlock*)g_astAllBlocks;
}

const UCHAR8* Hv_Drv_OsdResource_GetBlockMatrixAddr(const OsdBlock *pstBlock)
{
    OsdLanguage enCurrentLanguage = Hv_Drv_OsdFrame_GetCurrentLanguage();

    if (pstBlock->bSwitchLanguage)
    {
        return pstBlock->ppBlockAddr[enCurrentLanguage];
    }
    else
    {
        return (UCHAR8*)pstBlock->ppBlockAddr;
    }
}

USHORT16 Hv_Drv_OsdResource_GetBlockSize(const OsdBlock *pstBlock)
{
    USHORT16 usLen = 0;
    OsdLanguage enCurrentLanguage = Hv_Drv_OsdFrame_GetCurrentLanguage();

    if (pstBlock->bSwitchLanguage)
    {
        usLen =  *(pstBlock->ppBlockLength[enCurrentLanguage]);
    }
    else
    {
        usLen = (UINT32)(pstBlock->ppBlockLength);
    }

    return ALIGN(usLen, 16);
}

USHORT16 Hv_Drv_OsdResource_GetBlockMatrixCount(const OsdBlock *pstBlock)
{
    UCHAR8 ucWidth = 0;
    UCHAR8 ucHeight = 0;
    UCHAR8 ucBits = 0;
    UCHAR8 ucBytes = 0;
    USHORT16 usSize = 0;
    USHORT16 usPixels = 0;

    ucBits = Hv_Drv_OsdResource_GetBits(pstBlock->ucResourceType);
    Hv_Drv_OsdResource_GetSize(pstBlock->usResourceSize, &ucWidth, &ucHeight);
    usPixels = (USHORT16)ucWidth * ucHeight;
    ucBytes = (usPixels * ucBits) >> 3;

    usSize = Hv_Drv_OsdResource_GetBlockSize(pstBlock);

    return usSize / ucBytes;
}

const UCHAR8* Hv_Drv_OsdResource_GetRealWidth(const OsdBlock *pstBlock)
{
    OsdLanguage enCurrentLanguage = Hv_Drv_OsdFrame_GetCurrentLanguage();

    if (pstBlock->bSwitchLanguage)
    {
        return pstBlock->ppBlockRealWidth[enCurrentLanguage];
    }
    else
    {
        return (UCHAR8*)pstBlock->ppBlockRealWidth;
    }
}

const USHORT16* Hv_Drv_OsdResource_GetBlockCode(const OsdBlock *pstBlock)
{
    OsdLanguage enCurrentLanguage = Hv_Drv_OsdFrame_GetCurrentLanguage();

    if (NULL == pstBlock->ppBlockCode)
    {
        return NULL;
    }

    if (pstBlock->bSwitchLanguage)
    {
        return pstBlock->ppBlockCode[enCurrentLanguage];
    }
    else
    {
        return (USHORT16*)pstBlock->ppBlockCode;
    }
}

USHORT16 Hv_Drv_OsdResource_SearchFontIndexByCode(UCHAR8 ucBlockID, USHORT16 usCode)
{
    USHORT16 usIndex = 0;
    const OsdBlock *pstBlock = NULL;
    OsdLoadedBlock *pstLoadedBlock = NULL;
    const USHORT16 *pusCode = NULL;
    USHORT16 usBlockMatrixCount = 0;

    pstBlock = &g_astAllBlocks[ucBlockID];
    pusCode = Hv_Drv_OsdResource_GetBlockCode(pstBlock);
    OsdLanguage enCurrentLanguage = 0;

    enCurrentLanguage = Hv_Drv_OsdFrame_GetCurrentLanguage();
    usBlockMatrixCount = Hv_Drv_OsdResource_GetBlockMatrixCount(pstBlock);

    HV_ASSERT_TRUE_RET(pusCode != NULL, 0);

retry:
    for (usIndex = 0; usIndex < usBlockMatrixCount; ++usIndex)
    {
        if (pusCode[usIndex] == usCode)
        {
            return usIndex;
        }
    }

    if ('?' != usCode)
    {
        OSD_DRV_LOG_WARN("OSD warning: could not find code: 0x%x", usCode);
        usCode = '?';
        goto retry;
    }

    OSD_DRV_LOG_ERROR("OSD fatal error: could not find code: 0x%x", usCode);
    return 0;
}

VOID Hv_Drv_OsdResource_SetLanguage(OsdLanguage enLanguage)
{
    OSD_DRV_LOG_DEBUG("Osd language switch to %d", enLanguage);

    if (HV_TRUE == Hv_Drv_OsdFrame_SetCurrentLanguage(enLanguage))
    {
        Hv_Drv_OsdResource_ClearLoadedResource();
    }
}

VOID Hv_Drv_OsdResource_SetLanguageOnly(OsdLanguage enLanguage)
{
    OSD_DRV_LOG_DEBUG("Osd language switch to %d", enLanguage);
    Hv_Drv_OsdFrame_SetCurrentLanguage(enLanguage);
}

static Status Hv_Drv_OsdResource_CopyResourceCb(VOID *arg)
{
    s_pstResourceParam->bResourceCopyDone = HV_TRUE;

    return HV_SUCCESS;
}

VOID Hv_Drv_OsdResource_SetChangeRange(OsdSRAMChangeType enType, UINT32 uiChangeStart, UINT32 uiChangeEnd)
{
    OsdSRAMChange *pstChange = &s_pstResourceParam->stResourceChange;

    Hv_Drv_OsdMemory_SetSRAMChange(pstChange, enType, uiChangeStart, uiChangeEnd);

    OSD_DRV_LOG_DEBUG("Updated Osd Resource change, type: %s range: 0x%x - 0x%x",
            Hv_Drv_OsdCommon_GetSRAMChangeTypeStr(enType),
            pstChange->uiChangeStart, pstChange->uiChangeEnd);
}

VOID Hv_Drv_OsdResource_TransferResource(VOID)
{
    UINT32 uiAddr = 0;
    UINT32 uiLength = 0;
    OsdSRAMChange *pstChange = &s_pstResourceParam->stResourceChange;

    if (pstChange->enType == OSD_SRAM_CHANGE_NONE)
    {
        return;
    }
    else if (pstChange->enType == OSD_SRAM_CHANGE_FULL)
    {
        s_pstResourceParam->usCurrentResourceOffset
            = ALIGN(s_pstResourceParam->usCurrentResourceOffset, 16);

        Hv_Drv_OsdDMA_Pend(OSD_RESOURCE_DDR_START, OSD_RESOURCE_BUFFER_BASE_ADDR,
                s_pstResourceParam->usCurrentResourceOffset);
    }
    else
    {
        uiAddr = OSD_RESOURCE_BUFFER_BASE_ADDR + pstChange->uiChangeStart;
        uiLength = pstChange->uiChangeEnd - pstChange->uiChangeStart;

        Hv_Drv_OsdDMA_Pend(OSD_RESOURCE_DDR_START + pstChange->uiChangeStart, uiAddr, uiLength);
    }
    OSD_DRV_LOG_DEBUG("Resource total size = 0x%x", s_pstResourceParam->usCurrentResourceOffset);

    Hv_Drv_OsdResource_SetChangeRange(OSD_SRAM_CHANGE_NONE, 0, 0);
}

OsdLoadedBank* Hv_Drv_OsdResource_GetCurrentLoadedBank(VOID)
{
    return s_pstResourceParam->pstOsdLoadedBanks
            + s_pstResourceParam->ucOsdLoadBankCount - 1;
}

VOID Hv_Drv_OsdResource_AllocRegion(USHORT16 usSize)
{
    HV_ASSERT_TRUE_VOID((UINT32)s_pstResourceParam->usCurrentResourceOffset + usSize <= OSD_RESOURCE_BUFFER_SIZE);

    s_pstResourceParam->usCurrentResourceOffset += usSize;

#if (HV_OSD_CONFIG_RESERVE_SLOTS_BYROW == HV_CONFIG_OFF)
    s_pstResourceParam->usCurrentResourceOffset
            = ALIGN(s_pstResourceParam->usCurrentResourceOffset, 16);
#endif

    OSD_DRV_LOG_DEBUG("allocated resource size: %d, resource offset: %d",
            usSize, s_pstResourceParam->usCurrentResourceOffset);
}

OsdLoadedBank* Hv_Drv_OsdResource_NewLoadedBank(OsdResourceSize enSize, OsdResourceType enType)
{
    UCHAR8 ucHeight = 0;
    OsdLoadedBank *pstLoadedBank = NULL;

    pstLoadedBank = s_pstResourceParam->pstOsdLoadedBanks
            + s_pstResourceParam->ucOsdLoadBankCount;
    pstLoadedBank->ucBankID = s_pstResourceParam->ucOsdLoadBankCount;
    pstLoadedBank->enSize = enSize;
    pstLoadedBank->enType = enType;
    pstLoadedBank->bIsBlankBank = HV_FALSE;
    pstLoadedBank->usCurrentSlots = 0;

    s_pstResourceParam->usCurrentResourceOffset
            = ALIGN(s_pstResourceParam->usCurrentResourceOffset, 16);
    pstLoadedBank->usCurrentResourceOffset
            = s_pstResourceParam->usCurrentResourceOffset;

    HV_ASSERT_TRUE_RET(s_pstResourceParam->ucOsdLoadBankCount
            < s_pstResourceParam->ucOsdMaxLoadBankCount, NULL);

    s_pstResourceParam->ucOsdLoadBankCount++;

    Hv_Drv_OsdResource_GetSize(enSize, NULL, &ucHeight);
    if ((16 == ucHeight) && (NULL == s_pstResourceParam->pstBlankBank))
    {
        s_pstResourceParam->pstBlankBank = pstLoadedBank;
    }

    OSD_DRV_LOG_DEBUG("pick resource new bank: bankID: %u, size %s %s "
            "offset: 0x%x", pstLoadedBank->ucBankID,
            Hv_Drv_OsdCommon_GetResourceSizeStr(enSize),
            Hv_Drv_OsdCommon_GetResourceTypeStr(enType),
            pstLoadedBank->usCurrentResourceOffset);

    return pstLoadedBank;
}

USHORT16 Hv_Drv_OsdResource_PickLoadedBank(OsdResourceSize enSize,
                            OsdResourceType enType, USHORT16 usSlotsNeed)
{
    UCHAR8 ucIndex = 0;
    UCHAR8 ucHeight = 0;
    USHORT16 usBytes = 0;
    BOOL bFound = HV_FALSE;
    OsdLoadedBank *pstLoadedBank = NULL;
    UINT32 uiOffset = 0;
    UINT32 uiSizeNeed = 0;

    pstLoadedBank = Hv_Drv_OsdResource_GetCurrentLoadedBank();

    if (pstLoadedBank->usCurrentSlots + usSlotsNeed > OSD_BANK_CAPACITY)
    {
        OSD_DRV_LOG_DEBUG("current slots: %d need %d, exceed 512",
                pstLoadedBank->usCurrentSlots, usSlotsNeed);

        pstLoadedBank = Hv_Drv_OsdResource_NewLoadedBank(enSize, enType);
    }

    usBytes = Hv_Drv_OsdCommon_GetResourceBytes(enSize, enType);
    pstLoadedBank->usCurrentSlots += usSlotsNeed;

    uiOffset = s_pstResourceParam->usCurrentResourceOffset;
    uiSizeNeed = (UINT32)usBytes * usSlotsNeed;
    HV_ASSERT_TRUE_RET(uiOffset + uiSizeNeed <= OSD_RESOURCE_BUFFER_SIZE, uiOffset);

    s_pstResourceParam->usCurrentResourceOffset += uiSizeNeed;

    OSD_DRV_LOG_DEBUG("bank-%d(%s %s) allocate %d slots, current slots %d, "
            "resource offset changes from %d to %d",
            pstLoadedBank->ucBankID, Hv_Drv_OsdCommon_GetResourceSizeStr(enSize),
            Hv_Drv_OsdCommon_GetResourceTypeStr(enType), usSlotsNeed, pstLoadedBank->usCurrentSlots,
            uiOffset, s_pstResourceParam->usCurrentResourceOffset);

    return uiOffset;
}

USHORT16 Hv_Drv_OsdResource_PickBankLoadMatrix(OsdLoadedBank *pstLoadedBank,
                            const UCHAR8 *pucMatrixAddr, USHORT16 usOffset, USHORT16 usCount)
{
    USHORT16 usBytes = 0;
    UINT32 uiDDR = 0;
    USHORT16 usBankOffset = 0;
    USHORT16 usSlot = 0;
    UINT32 uiSizeNeed = 0;
    UINT32 uiOffset = 0;

    HV_ASSERT_TRUE_RET(pstLoadedBank->usCurrentSlots + usCount <= OSD_BANK_CAPACITY, 0);

    usBytes = Hv_Drv_OsdCommon_GetResourceBytes(pstLoadedBank->enSize,
            pstLoadedBank->enType);

    usSlot = pstLoadedBank->usCurrentSlots;
    uiOffset = (UINT32)usSlot * usBytes;
    uiSizeNeed = (UINT32)usCount * usBytes;

    uiDDR = OSD_RESOURCE_DDR_START + pstLoadedBank->usCurrentResourceOffset;

    HV_ASSERT_TRUE_RET(pstLoadedBank->usCurrentResourceOffset + uiOffset + uiSizeNeed <= OSD_RESOURCE_BUFFER_SIZE, usSlot);
#if (HV_PROJECT_CONFIG_OSD_CPU_CANVAS_SUPPORT == HV_CONFIG_ON)
    if (NULL != pucMatrixAddr)
    {
#endif
        HV_MEMCPY((VOID*)(uiDDR + uiOffset), pucMatrixAddr + (UINT32)usOffset * usBytes, uiSizeNeed);
#if (HV_PROJECT_CONFIG_OSD_CPU_CANVAS_SUPPORT == HV_CONFIG_ON)
    }
#endif
    pstLoadedBank->usCurrentSlots += usCount;

    OSD_DRV_LOG_DEBUG("bank-%d(%s %s) load %d matrix from 0x%x to 0x%x, "
            "resource offset changes from %d to %d",
            pstLoadedBank->ucBankID,
            Hv_Drv_OsdCommon_GetResourceSizeStr(pstLoadedBank->enSize),
            Hv_Drv_OsdCommon_GetResourceTypeStr(pstLoadedBank->enType),
            usCount, pucMatrixAddr + usOffset * usBytes, (uiDDR + usSlot * usBytes),
            s_pstResourceParam->usCurrentResourceOffset,
            s_pstResourceParam->usCurrentResourceOffset + usBytes * usCount);

#if (HV_OSD_CONFIG_RESERVE_SLOTS_BYROW == HV_CONFIG_ON)
    s_pstResourceParam->usCurrentResourceOffset += uiSizeNeed;
#endif

    return usSlot;
}

static USHORT16 Hv_Drv_OsdResource_PickRowAllocSlot(OsdRowInfo *pstRowInfo, UCHAR8 ucCount)
{
    USHORT16 usBankOffset = 0;

    usBankOffset = pstRowInfo->usBankSlot + pstRowInfo->ucCurIndex;
    pstRowInfo->ucCurIndex += ucCount;

    return usBankOffset;
}

#if (HV_OSD_CONFIG_RESERVE_SLOTS_BYROW == HV_CONFIG_ON)
USHORT16 Hv_Drv_OsdResource_PickRowLoadMatrix(OsdRowInfo *pstRowInfo,
                            const UCHAR8 *pucMatrixAddr, USHORT16 usOffset, UCHAR8 ucCount)
{
    USHORT16 usBytes = 0;
    OsdPhyFontInfo *pstFontInfo = NULL;
    UINT32 uiDDR = 0;
    UINT32 uiSizeNeed = 0;

    pstFontInfo = Hv_Drv_OsdFont_GetCurrentFontInfo();
    HV_ASSERT_TRUE_RET(pstRowInfo->ucCurIndex + 1 < pstRowInfo->ucRowLen, 0);

    usBytes = Hv_Drv_OsdCommon_GetResourceBytes(pstRowInfo->enSize,
            pstRowInfo->enType);
    uiSizeNeed = (UINT32)usBytes * ucCount;

    uiDDR = OSD_RESOURCE_DDR_START + pstRowInfo->usResourceOffset;
    HV_MEMCPY((VOID*)(uiDDR + pstRowInfo->ucCurIndex * usBytes),
            pucMatrixAddr + (UINT32)usOffset * usBytes, uiSizeNeed);

#ifdef HV_SCALER_DEBUG_VERSION
    g_usResourceRealTotalSize += uiSizeNeed;
#endif

    return Hv_Drv_OsdResource_PickRowAllocSlot(pstRowInfo, ucCount);
}
#endif
