/*
* Copyright (c) 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     media_ddi_base.cpp
//! \brief    Defines base class for DDI media encode/decoder.
//!

#include "media_ddi_base.h"

int32_t DdiMediaBase::GetRenderTargetID(DDI_CODEC_RENDER_TARGET_TABLE *rtTbl, DDI_MEDIA_SURFACE *surface)
{
    if((nullptr == surface) || (nullptr == rtTbl))
    {
        return DDI_CODEC_INVALID_FRAME_INDEX;
    }

    if (0 == rtTbl->iNumRenderTargets)
    {
        return DDI_CODEC_INVALID_FRAME_INDEX;
    }

    for(int32_t i = 0; i < DDI_MEDIA_MAX_SURFACE_NUMBER_CONTEXT; i++)
    {
        if(rtTbl->pRT[i] == surface)
        {
            return i;
        }
    }
    return DDI_CODEC_INVALID_FRAME_INDEX;
}

VAStatus DdiMediaBase::RegisterRTSurfaces(DDI_CODEC_RENDER_TARGET_TABLE *rtTbl, DDI_MEDIA_SURFACE *surface)
{
    DDI_CHK_NULL(surface, "nullptr surface", VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(rtTbl, "nullptr rtTbl", VA_STATUS_ERROR_INVALID_PARAMETER);

    int32_t i = 0;
    uint32_t emptyEntry = DDI_MEDIA_MAX_SURFACE_NUMBER_CONTEXT + 1;
    for (i = 0; i < DDI_MEDIA_MAX_SURFACE_NUMBER_CONTEXT; i++)
    {
        if (rtTbl->pRT[i] == surface)
        {
            //pCurrRT has already been registered
            emptyEntry = DDI_MEDIA_MAX_SURFACE_NUMBER_CONTEXT + 1;
            break;
        }
        else if ((rtTbl->pRT[i] == nullptr) && (emptyEntry == (DDI_MEDIA_MAX_SURFACE_NUMBER_CONTEXT + 1)))
        {
            //find the first empty entry
            emptyEntry = i;
        }
    }

    if (emptyEntry < DDI_MEDIA_MAX_SURFACE_NUMBER_CONTEXT)
    {
        i = emptyEntry;
    }
    //if pCurrRT has not registered in pRT, add it into the array
    if (i < DDI_MEDIA_MAX_SURFACE_NUMBER_CONTEXT)
    {
        if (emptyEntry < DDI_MEDIA_MAX_SURFACE_NUMBER_CONTEXT)
        {
            rtTbl->pRT[emptyEntry] = surface;
            rtTbl->ucRTFlag[emptyEntry] = SURFACE_STATE_ACTIVE_IN_CURFRAME;
            rtTbl->iNumRenderTargets++;
        }
        else
        {
            rtTbl->ucRTFlag[i] = SURFACE_STATE_ACTIVE_IN_CURFRAME;
        }
    }
    else
    {
        uint32_t j = 0;
        for(j = 0; j < DDI_MEDIA_MAX_SURFACE_NUMBER_CONTEXT; j ++)
        {
            if(rtTbl->ucRTFlag[j] == SURFACE_STATE_INACTIVE)
            {
                rtTbl->pRT[j] = surface;
                rtTbl->ucRTFlag[j] = SURFACE_STATE_ACTIVE_IN_CURFRAME;
                break;
            }
        }
        if(j == DDI_MEDIA_MAX_SURFACE_NUMBER_CONTEXT)
        {
            DDI_VERBOSEMESSAGE("RT table is full, and have no one can be resued");
            return VA_STATUS_ERROR_INVALID_PARAMETER;
        }
    }

    return VA_STATUS_SUCCESS;
}

VAStatus DdiMediaBase::ClearRefList(DDI_CODEC_RENDER_TARGET_TABLE *rtTbl, bool withDpb)
{
    DDI_CHK_NULL(rtTbl, "nullptr rtTbl", VA_STATUS_ERROR_INVALID_PARAMETER);

    if(withDpb)
    {
        for(int32_t i = 0; i < DDI_MEDIA_MAX_SURFACE_NUMBER_CONTEXT; i ++)
        {
            if(rtTbl->ucRTFlag[i] == SURFACE_STATE_ACTIVE_IN_LASTFRAME)
            {
                rtTbl->ucRTFlag[i] = SURFACE_STATE_INACTIVE;
            }
            else if(rtTbl->ucRTFlag[i] == SURFACE_STATE_ACTIVE_IN_CURFRAME)
            {
                rtTbl->ucRTFlag[i] = SURFACE_STATE_ACTIVE_IN_LASTFRAME;
            }
        }
    }
    else
    {
        for(int32_t i = 0; i < DDI_MEDIA_MAX_SURFACE_NUMBER_CONTEXT; i ++)
        {
            if(rtTbl->ucRTFlag[i])
            {
               rtTbl->ucRTFlag[i] --;
            }
        }
    }
    return VA_STATUS_SUCCESS;
}

VAStatus DdiMediaBase::UpdateRegisteredRTSurfaceFlag(DDI_CODEC_RENDER_TARGET_TABLE *rtTbl, DDI_MEDIA_SURFACE *surface)
{
    DDI_CHK_NULL(rtTbl, "nullptr rtTbl", VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(surface, "nullptr surface", VA_STATUS_ERROR_INVALID_PARAMETER);

    for(int32_t i = 0; i < DDI_MEDIA_MAX_SURFACE_NUMBER_CONTEXT; i ++)
    {
        if(rtTbl->pRT[i] == surface)
        {
            rtTbl->ucRTFlag[i] = SURFACE_STATE_ACTIVE_IN_CURFRAME;
            return VA_STATUS_SUCCESS;
        }
    }
    DDI_VERBOSEMESSAGE("frame was not registered in the RTtbl");
    return VA_STATUS_ERROR_INVALID_PARAMETER;
}

VAStatus DdiMediaBase::UnRegisterRTSurfaces(DDI_CODEC_RENDER_TARGET_TABLE *rtTbl, DDI_MEDIA_SURFACE *surface)
{
    DDI_CHK_NULL(rtTbl, "nullptr rtTbl", VA_STATUS_ERROR_INVALID_PARAMETER);
    DDI_CHK_NULL(surface, "nullptr surface", VA_STATUS_ERROR_INVALID_PARAMETER);

    uint32_t i;

    for (i = 0; i < DDI_MEDIA_MAX_SURFACE_NUMBER_CONTEXT; i++)
    {
        if (rtTbl->pRT[i] == surface)
        {
            rtTbl->pRT[i] = nullptr;
            rtTbl->ucRTFlag[i] = SURFACE_STATE_INACTIVE;
            rtTbl->iNumRenderTargets--;
            break;
        }
    }
    if (i == DDI_MEDIA_MAX_SURFACE_NUMBER_CONTEXT)
    {
        DDI_VERBOSEMESSAGE("The surface to be unregistered can not find in RTtbl!");
        return VA_STATUS_ERROR_INVALID_PARAMETER;
    }
    return VA_STATUS_SUCCESS;
}

