blob: 4757601b7f3e82719d76c568151de86d526b99a7 [file] [log] [blame]
/*
* Copyright (c) 2015-2021, 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_libva_common.cpp
//! \brief libva(and its extension) interface implemantation common functions
//!
#include "media_libva.h"
#include "media_libva_util.h"
#include "media_ddi_prot.h"
#include "mos_solo_generic.h"
#include "mos_interface.h"
#include "media_libva_caps.h"
static void* DdiMedia_GetVaContextFromHeap(PDDI_MEDIA_HEAP mediaHeap, uint32_t index, PMEDIA_MUTEX_T mutex)
{
PDDI_MEDIA_VACONTEXT_HEAP_ELEMENT vaCtxHeapElmt = nullptr;
void *context = nullptr;
DdiMediaUtil_LockMutex(mutex);
if(nullptr == mediaHeap || index >= mediaHeap->uiAllocatedHeapElements)
{
DdiMediaUtil_UnLockMutex(mutex);
return nullptr;
}
vaCtxHeapElmt = (PDDI_MEDIA_VACONTEXT_HEAP_ELEMENT)mediaHeap->pHeapBase;
vaCtxHeapElmt += index;
context = vaCtxHeapElmt->pVaContext;
DdiMediaUtil_UnLockMutex(mutex);
return context;
}
void DdiMedia_MediaSurfaceToMosResource(DDI_MEDIA_SURFACE *mediaSurface, MOS_RESOURCE *mosResource)
{
DDI_CHK_NULL(mediaSurface, "nullptr mediaSurface",);
DDI_CHK_NULL(mosResource, "nullptr mosResource",);
DDI_ASSERT(mosResource->bo);
MosInterface::ConvertResourceFromDdi(mediaSurface, mosResource, OS_SPECIFIC_RESOURCE_SURFACE, 0);
Mos_Solo_SetOsResource(mediaSurface->pGmmResourceInfo, mosResource);
return;
}
void DdiMedia_MediaBufferToMosResource(DDI_MEDIA_BUFFER *mediaBuffer, MOS_RESOURCE *mosResource)
{
DDI_CHK_NULL(mediaBuffer, "nullptr mediaBuffer",);
DDI_CHK_NULL(mosResource, "nullptr mosResource",);
DDI_ASSERT(mediaBuffer->bo);
MosInterface::ConvertResourceFromDdi(mediaBuffer, mosResource, OS_SPECIFIC_RESOURCE_BUFFER, 0);
Mos_Solo_SetOsResource(mediaBuffer->pGmmResourceInfo, mosResource);
return;
}
void* DdiMedia_GetContextFromContextID (VADriverContextP ctx, VAContextID vaCtxID, uint32_t *ctxType)
{
PDDI_MEDIA_CONTEXT mediaCtx = nullptr;
uint32_t index = 0;
DDI_CHK_NULL(ctx, "nullptr ctx", nullptr);
DDI_CHK_NULL(ctxType, "nullptr ctxType", nullptr);
mediaCtx = DdiMedia_GetMediaContext(ctx);
index = vaCtxID & DDI_MEDIA_MASK_VACONTEXTID;
if (index >= DDI_MEDIA_MAX_INSTANCE_NUMBER)
return nullptr;
if ((vaCtxID&DDI_MEDIA_MASK_VACONTEXT_TYPE) == DDI_MEDIA_VACONTEXTID_OFFSET_PROT)
{
DDI_VERBOSEMESSAGE("Protected session detected: 0x%x", vaCtxID);
*ctxType = DDI_MEDIA_CONTEXT_TYPE_PROTECTED;
index = index & DDI_MEDIA_MASK_VAPROTECTEDSESSION_ID;
return DdiMedia_GetVaContextFromHeap(mediaCtx->pProtCtxHeap, index, &mediaCtx->ProtMutex);
}
else if ((vaCtxID&DDI_MEDIA_MASK_VACONTEXT_TYPE) == DDI_MEDIA_VACONTEXTID_OFFSET_DECODER)
{
DDI_VERBOSEMESSAGE("Decode context detected: 0x%x", vaCtxID);
*ctxType = DDI_MEDIA_CONTEXT_TYPE_DECODER;
return DdiMedia_GetVaContextFromHeap(mediaCtx->pDecoderCtxHeap, index, &mediaCtx->DecoderMutex);
}
else if ((vaCtxID&DDI_MEDIA_MASK_VACONTEXT_TYPE) == DDI_MEDIA_VACONTEXTID_OFFSET_ENCODER)
{
*ctxType = DDI_MEDIA_CONTEXT_TYPE_ENCODER;
return DdiMedia_GetVaContextFromHeap(mediaCtx->pEncoderCtxHeap, index, &mediaCtx->EncoderMutex);
}
else if ((vaCtxID & DDI_MEDIA_MASK_VACONTEXT_TYPE) == DDI_MEDIA_VACONTEXTID_OFFSET_VP)
{
*ctxType = DDI_MEDIA_CONTEXT_TYPE_VP;
return DdiMedia_GetVaContextFromHeap(mediaCtx->pVpCtxHeap, index, &mediaCtx->VpMutex);
}
else if ((vaCtxID & DDI_MEDIA_MASK_VACONTEXT_TYPE) == DDI_MEDIA_VACONTEXTID_OFFSET_CM)
{
*ctxType = DDI_MEDIA_CONTEXT_TYPE_CM;
return DdiMedia_GetVaContextFromHeap(mediaCtx->pCmCtxHeap, index, &mediaCtx->CmMutex);
}
else if ((vaCtxID & DDI_MEDIA_MASK_VACONTEXT_TYPE) == DDI_MEDIA_VACONTEXTID_OFFSET_MFE)
{
*ctxType = DDI_MEDIA_CONTEXT_TYPE_MFE;
return DdiMedia_GetVaContextFromHeap(mediaCtx->pMfeCtxHeap, index, &mediaCtx->MfeMutex);
}
else
{
DDI_ASSERTMESSAGE("Invalid context: 0x%x", vaCtxID);
*ctxType = DDI_MEDIA_CONTEXT_TYPE_NONE;
return nullptr;
}
}
DDI_MEDIA_SURFACE* DdiMedia_GetSurfaceFromVASurfaceID (PDDI_MEDIA_CONTEXT mediaCtx, VASurfaceID surfaceID)
{
uint32_t i = 0;
PDDI_MEDIA_SURFACE_HEAP_ELEMENT surfaceElement = nullptr;
PDDI_MEDIA_SURFACE surface = nullptr;
DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", nullptr);
i = (uint32_t)surfaceID;
bool validSurface = (i != VA_INVALID_SURFACE);
if(validSurface)
{
DDI_CHK_LESS(i, mediaCtx->pSurfaceHeap->uiAllocatedHeapElements, "invalid surface id", nullptr);
DdiMediaUtil_LockMutex(&mediaCtx->SurfaceMutex);
surfaceElement = (PDDI_MEDIA_SURFACE_HEAP_ELEMENT)mediaCtx->pSurfaceHeap->pHeapBase;
surfaceElement += i;
surface = surfaceElement->pSurface;
DdiMediaUtil_UnLockMutex(&mediaCtx->SurfaceMutex);
}
return surface;
}
VASurfaceID DdiMedia_GetVASurfaceIDFromSurface(PDDI_MEDIA_SURFACE surface)
{
DDI_CHK_NULL(surface, "nullptr surface", VA_INVALID_SURFACE);
PDDI_MEDIA_SURFACE_HEAP_ELEMENT surfaceElement = (PDDI_MEDIA_SURFACE_HEAP_ELEMENT)surface->pMediaCtx->pSurfaceHeap->pHeapBase;
for(uint32_t i = 0; i < surface->pMediaCtx->pSurfaceHeap->uiAllocatedHeapElements; i ++)
{
if(surface == surfaceElement->pSurface)
{
return surfaceElement->uiVaSurfaceID;
}
surfaceElement ++;
}
return VA_INVALID_SURFACE;
}
PDDI_MEDIA_SURFACE DdiMedia_ReplaceSurfaceWithNewFormat(PDDI_MEDIA_SURFACE surface, DDI_MEDIA_FORMAT expectedFormat)
{
DDI_CHK_NULL(surface, "nullptr surface", nullptr);
PDDI_MEDIA_SURFACE_HEAP_ELEMENT surfaceElement = (PDDI_MEDIA_SURFACE_HEAP_ELEMENT)surface->pMediaCtx->pSurfaceHeap->pHeapBase;
PDDI_MEDIA_CONTEXT mediaCtx = surface->pMediaCtx;
//check some conditions
if(expectedFormat == surface->format)
{
return surface;
}
//create new dst surface and copy the structure
PDDI_MEDIA_SURFACE dstSurface = (DDI_MEDIA_SURFACE *)MOS_AllocAndZeroMemory(sizeof(DDI_MEDIA_SURFACE));
if (nullptr == surfaceElement)
{
MOS_FreeMemory(dstSurface);
return nullptr;
}
MOS_SecureMemcpy(dstSurface,sizeof(DDI_MEDIA_SURFACE),surface,sizeof(DDI_MEDIA_SURFACE));
DDI_CHK_NULL(dstSurface, "nullptr dstSurface", nullptr);
dstSurface->format = expectedFormat;
dstSurface->uiLockedBufID = VA_INVALID_ID;
dstSurface->uiLockedImageID = VA_INVALID_ID;
dstSurface->pSurfDesc = nullptr;
//lock surface heap
DdiMediaUtil_LockMutex(&mediaCtx->SurfaceMutex);
uint32_t i;
//get current element heap and index
for(i = 0; i < mediaCtx->pSurfaceHeap->uiAllocatedHeapElements; i ++)
{
if(surface == surfaceElement->pSurface)
{
break;
}
surfaceElement ++;
}
//if cant find
if(i == surface->pMediaCtx->pSurfaceHeap->uiAllocatedHeapElements)
{
DdiMediaUtil_LockMutex(&mediaCtx->SurfaceMutex);
MOS_FreeMemory(dstSurface);
return nullptr;
}
//FreeSurface
DdiMediaUtil_FreeSurface(surface);
MOS_FreeMemory(surface);
//CreateNewSurface
DdiMediaUtil_CreateSurface(dstSurface,mediaCtx);
surfaceElement->pSurface = dstSurface;
DdiMediaUtil_UnLockMutex(&mediaCtx->SurfaceMutex);
return dstSurface;
}
PDDI_MEDIA_SURFACE DdiMedia_ReplaceSurfaceWithVariant(PDDI_MEDIA_SURFACE surface, VAEntrypoint entrypoint)
{
DDI_CHK_NULL(surface, "nullptr surface", nullptr);
PDDI_MEDIA_CONTEXT mediaCtx = surface->pMediaCtx;
uint32_t aligned_width, aligned_height;
DDI_MEDIA_FORMAT aligned_format;
//check some conditions
if(surface->uiVariantFlag)
{
return surface;
}
VASurfaceID vaID = DdiMedia_GetVASurfaceIDFromSurface(surface);
if(VA_INVALID_SURFACE == vaID)
{
return nullptr;
}
PDDI_MEDIA_SURFACE_HEAP_ELEMENT surfaceElement = (PDDI_MEDIA_SURFACE_HEAP_ELEMENT)surface->pMediaCtx->pSurfaceHeap->pHeapBase;
if (nullptr == surfaceElement)
{
return nullptr;
}
surfaceElement += vaID;
aligned_format = surface->format;
switch (surface->format)
{
case Media_Format_AYUV:
aligned_width = MOS_ALIGN_CEIL(surface->iWidth, 128);
aligned_height = MOS_ALIGN_CEIL(surface->iHeight * 3 / 4, 64);
break;
case Media_Format_Y410:
aligned_width = MOS_ALIGN_CEIL(surface->iWidth, 64);
aligned_height = MOS_ALIGN_CEIL(surface->iHeight * 3 / 2, 64);
break;
case Media_Format_Y216:
#if VA_CHECK_VERSION(1, 9, 0)
case Media_Format_Y212:
#endif
case Media_Format_Y210:
aligned_width = (surface->iWidth + 1) >> 1;
aligned_height = surface->iHeight * 2;
aligned_format = Media_Format_Y216;
break;
case Media_Format_YUY2:
aligned_width = (surface->iWidth + 1) >> 1;
aligned_height = surface->iHeight * 2;
break;
case Media_Format_P016:
case Media_Format_P012:
case Media_Format_P010:
aligned_height = surface->iHeight;
aligned_width = surface->iWidth;
if(entrypoint == VAEntrypointEncSlice)
{
aligned_width = surface->iWidth * 2;
aligned_format = Media_Format_NV12;
}
else
{
aligned_format = Media_Format_P016;
}
break;
default:
return surface;
}
//create new dst surface and copy the structure
PDDI_MEDIA_SURFACE dstSurface = (DDI_MEDIA_SURFACE *)MOS_AllocAndZeroMemory(sizeof(DDI_MEDIA_SURFACE));
MOS_SecureMemcpy(dstSurface,sizeof(DDI_MEDIA_SURFACE),surface,sizeof(DDI_MEDIA_SURFACE));
DDI_CHK_NULL(dstSurface, "nullptr dstSurface", nullptr);
dstSurface->uiVariantFlag = 1;
dstSurface->format = aligned_format;
dstSurface->iWidth = aligned_width;
dstSurface->iHeight = aligned_height;
//CreateNewSurface
if(DdiMediaUtil_CreateSurface(dstSurface,mediaCtx) != VA_STATUS_SUCCESS)
{
MOS_FreeMemory(dstSurface);
return surface;
}
//replace the surface
surfaceElement->pSurface = dstSurface;
//FreeSurface
DdiMediaUtil_FreeSurface(surface);
MOS_FreeMemory(surface);
return dstSurface;
}
DDI_MEDIA_BUFFER* DdiMedia_GetBufferFromVABufferID (PDDI_MEDIA_CONTEXT mediaCtx, VABufferID bufferID)
{
uint32_t i = 0;
PDDI_MEDIA_BUFFER_HEAP_ELEMENT bufHeapElement = nullptr;
PDDI_MEDIA_BUFFER buf = nullptr;
i = (uint32_t)bufferID;
DDI_CHK_LESS(i, mediaCtx->pBufferHeap->uiAllocatedHeapElements, "invalid buffer id", nullptr);
DdiMediaUtil_LockMutex(&mediaCtx->BufferMutex);
bufHeapElement = (PDDI_MEDIA_BUFFER_HEAP_ELEMENT)mediaCtx->pBufferHeap->pHeapBase;
bufHeapElement += i;
buf = bufHeapElement->pBuffer;
DdiMediaUtil_UnLockMutex(&mediaCtx->BufferMutex);
return buf;
}
bool DdiMedia_DestroyBufFromVABufferID (PDDI_MEDIA_CONTEXT mediaCtx, VABufferID bufferID)
{
DdiMediaUtil_LockMutex(&mediaCtx->BufferMutex);
DdiMediaUtil_ReleasePMediaBufferFromHeap(mediaCtx->pBufferHeap, bufferID);
mediaCtx->uiNumBufs--;
DdiMediaUtil_UnLockMutex(&mediaCtx->BufferMutex);
return true;
}
void* DdiMedia_GetContextFromVABufferID (PDDI_MEDIA_CONTEXT mediaCtx, VABufferID bufferID)
{
uint32_t i;
PDDI_MEDIA_BUFFER_HEAP_ELEMENT bufHeapElement;
void * ctx;
i = (uint32_t)bufferID;
DDI_CHK_LESS(i, mediaCtx->pBufferHeap->uiAllocatedHeapElements, "invalid buffer id", nullptr);
DdiMediaUtil_LockMutex(&mediaCtx->BufferMutex);
bufHeapElement = (PDDI_MEDIA_BUFFER_HEAP_ELEMENT)mediaCtx->pBufferHeap->pHeapBase;
bufHeapElement += bufferID;
ctx = bufHeapElement->pCtx;
DdiMediaUtil_UnLockMutex(&mediaCtx->BufferMutex);
return ctx;
}
int32_t DdiMedia_GetGpuPriority (VADriverContextP ctx, VABufferID *buffers, int32_t numBuffers, bool *updatePriority, int32_t *priority)
{
void * data;
uint32_t updateSessionPriority = 0;
uint32_t priorityValue = 0;
int32_t priorityIndexInBuf = -1;
DDI_CHK_NULL(ctx, "nullptr context in DdiMedia_GetGpuPriority!", -1);
PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", -1);
#if VA_CHECK_VERSION(1, 10, 0)
for (int32_t i = 0; i < numBuffers; i++)
{
DDI_MEDIA_BUFFER *buf = DdiMedia_GetBufferFromVABufferID(mediaCtx, buffers[i]);
DDI_CHK_NULL(buf, "Invalid buffer.", -1);
if((int32_t)buf->uiType == VAContextParameterUpdateBufferType)
{
//Read the priority from the VAContextParameterUpdateBuffer
DdiMedia_MapBuffer(ctx, buffers[i], &data);
DDI_CHK_NULL(data, "nullptr data.", -1);
VAContextParameterUpdateBuffer *ContextParamBuf = (VAContextParameterUpdateBuffer *)data;
DDI_CHK_NULL(ContextParamBuf, "nullptr ContextParamBuf.", -1);
updateSessionPriority = ContextParamBuf->flags.bits.context_priority_update;
priorityValue = ContextParamBuf->context_priority.bits.priority;
if (updateSessionPriority)
{
*updatePriority = true;
if(priorityValue >= 0 && priorityValue <= CONTEXT_PRIORITY_MAX)
{
*priority = priorityValue - CONTEXT_PRIORITY_MAX/2;
}
else
{
*priority = 0;
}
}
else
{
*updatePriority = false;
*priority = 0;
}
DdiMedia_UnmapBuffer(ctx, buffers[i]);
priorityIndexInBuf = i;
break;
}
}
#endif
return priorityIndexInBuf;
}
//Move the priority bufferID to the end of buffers
void MovePriorityBufferIdToEnd (VABufferID *buffers, int32_t priorityIndexInBuf, int32_t numBuffers)
{
VABufferID vaBufferID = 0;
if( (numBuffers > 1) && (priorityIndexInBuf < numBuffers -1) )
{
vaBufferID = buffers[priorityIndexInBuf];
while(priorityIndexInBuf < (numBuffers - 1) )
{
buffers[priorityIndexInBuf] = buffers[priorityIndexInBuf+1];
priorityIndexInBuf++;
}
buffers[numBuffers -1] = vaBufferID;
}
}