blob: c372f539cc423a1709afd93a09e06205b8b72708 [file] [log] [blame]
/*
* 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 cm_surface_2d_rt.cpp
//! \brief Contains OS-agnostic CmSurface2DRT member functions.
//!
#include "cm_surface_2d_rt.h"
#include "cm_event_rt.h"
#include "cm_surface_manager.h"
#include "cm_device_rt.h"
#include "cm_mem.h"
#include "cm_queue_rt.h"
#define COPY_OPTION(option) (option & 0x1)
namespace CMRT_UMD
{
//*-----------------------------------------------------------------------------
//| Purpose: Create Surface 2D
//| Arguments :
//| index [in] index in runtime Surface2D table
//| handle [in] index in driver's surface2D table
//| width [in] width of the CmSurface2D
//| height [in] height of the CmSurface2D
//| pitch [in] pitch of the CmSurface2D
//| format [out] format of CmSurface2D
//| isCmCreated [out] ture,if the surface created by CM;
//| false,if the surface created externally
//| surfaceManager [out] Pointer to CmSurfaceManager
//| surface [out] Reference to the Pointer to CmSurface2D
//| Returns: Result of the operation.
//*-----------------------------------------------------------------------------
int32_t CmSurface2DRT::Create(
uint32_t index,
uint32_t handle,
uint32_t width,
uint32_t height,
uint32_t pitch,
CM_SURFACE_FORMAT format,
bool isCmCreated,
CmSurfaceManager* surfaceManager,
CmSurface2DRT* &surface )
{
int32_t result = CM_SUCCESS;
surface = new (std::nothrow) CmSurface2DRT( handle,width,height, pitch,format,surfaceManager, isCmCreated);
if( surface )
{
result = surface->Initialize( index );
if( result != CM_SUCCESS )
{
CmSurface* baseSurface = surface;
CmSurface::Destroy( baseSurface );
}
}
else
{
CM_ASSERTMESSAGE("Error: Failed to CmSurface2D due to out of system memory.")
result = CM_OUT_OF_HOST_MEMORY;
}
return result;
}
//*-----------------------------------------------------------------------------
//| Purpose: Initialize CmSurface2D
//| Returns: Result of the operation.
//*-----------------------------------------------------------------------------
int32_t CmSurface2DRT::Initialize( uint32_t index )
{
return CmSurface::Initialize( index );
}
bool CmSurface2DRT::IsGPUCopy(void *sysMem, uint32_t widthInBytes, uint32_t height, uint32_t horizontalStrideInBytes)
{
return ( (widthInBytes <= CM_MAX_THREADSPACE_WIDTH_FOR_MW*128) && (height <= CM_MAX_THREADSPACE_HEIGHT_FOR_MW*32) && (uintptr_t(sysMem) & 0xF) == 0 && (horizontalStrideInBytes & 0xF) == 0 );
}
bool CmSurface2DRT::IsUnalignedGPUCopy(uint32_t widthInBytes, uint32_t height)
{
return (widthInBytes <= CM_MAX_THREADSPACE_WIDTH_FOR_MW*64) && (height <= CM_MAX_THREADSPACE_HEIGHT_FOR_MW*8);
}
//*-----------------------------------------------------------------------------
//| Purpose: Hybrid memory copy from system memory to Surface 2D to with stride
//| Arguments :
//| sysMem [in] Pointer to system memory
//| event [in] Pointer to CmEvent
//| horizontalStride [in] Stride in system memory in bytes
//| verticalStride[in] Height Stride in system memory in rows
//| sysMemSize [in] Size of Memory need to read
//| option [in] Option to disable/enable hybrid memory copy
//| Returns: Result of the operation.
//*-----------------------------------------------------------------------------
CM_RT_API int32_t CmSurface2DRT::WriteSurfaceHybridStrides( const unsigned char* sysMem, CmEvent* event, const uint32_t horizontalStride, const uint32_t verticalStride, uint64_t sysMemSize, uint32_t option )
{
INSERT_API_CALL_LOG();
int32_t hr = CM_SUCCESS;
uint32_t sizePerPixel = 0;
uint32_t updatedHeight = 0;
uint32_t widthInBytes = 0;
CmQueue *cmQueue = nullptr;
CmDeviceRT *cmDevice = nullptr;
CmQueueRT *cmQueueRT = nullptr;
bool forceCPUCopy = COPY_OPTION(option);
CM_STATUS status;
m_surfaceMgr->GetCmDevice(cmDevice);
CMCHK_NULL_AND_RETURN(cmDevice);
int32_t result = m_surfaceMgr->GetPixelBytesAndHeight(m_width, m_height, m_format, sizePerPixel, updatedHeight);
if (result != CM_SUCCESS)
{
CM_ASSERTMESSAGE("Error: Failed to get correct surface info.")
return result;
}
widthInBytes = m_width * sizePerPixel;
if(sysMem == nullptr || horizontalStride < widthInBytes || verticalStride < m_height)
{
CM_ASSERTMESSAGE("Error: Invalid input arguments.")
return CM_INVALID_ARG_VALUE;
}
if( event )
{
CmEventRT *eventRT = static_cast<CmEventRT *>(event);
FlushDeviceQueue( eventRT ); //wait specific task finished
}
WaitForReferenceFree(); // wait all owner task finished
if (forceCPUCopy)
{
CMCHK_HR(WriteSurfaceFullStride(sysMem, event, horizontalStride, verticalStride, sysMemSize));
}
else
{
CMCHK_HR(cmDevice->CreateQueue(cmQueue));
if(IsGPUCopy((void*)sysMem, widthInBytes, m_height, horizontalStride))
{
CMCHK_HR(cmQueue->EnqueueCopyCPUToGPUFullStride(this, sysMem, horizontalStride, verticalStride, 0, event));
if(event)
{
CMCHK_HR(event->GetStatus(status));
while(status != CM_STATUS_FINISHED)
{
if (status == CM_STATUS_RESET)
{
hr = CM_TASK_MEDIA_RESET;
goto finish;
}
CMCHK_HR(event->GetStatus(status));
}
}
else
{
CM_ASSERTMESSAGE("Error: Hybrid memory copy from system memory to Surface 2D failure.")
return CM_FAILURE;
}
}
else if (IsUnalignedGPUCopy(widthInBytes, m_height))
{
cmQueueRT = static_cast<CmQueueRT *>(cmQueue);
CMCHK_HR(cmQueueRT->EnqueueUnalignedCopyInternal(this, (unsigned char*)sysMem, horizontalStride, verticalStride, CM_FASTCOPY_CPU2GPU, event));
}
else
{
CMCHK_HR(WriteSurfaceFullStride(sysMem, event, horizontalStride, verticalStride, sysMemSize));
}
}
finish:
return hr;
}
//*-----------------------------------------------------------------------------
//| Purpose: Write data from system memory to Surface 2D
//| Arguments :
//| sysMem [in] Pointer to system memory
//| event [in] Pointer to CmEvent
//| sysMemSize [out] Size of Memory need to write
//|
//| Returns: Result of the operation.
//*-----------------------------------------------------------------------------
CM_RT_API int32_t CmSurface2DRT::WriteSurface( const unsigned char* sysMem, CmEvent* event, uint64_t sysMemSize )
{
INSERT_API_CALL_LOG();
CM_RETURN_CODE hr = CM_SUCCESS;
uint8_t *dst = nullptr;
uint8_t *surf = nullptr;
uint32_t sizePerPixel = 0;
uint32_t updatedHeight = 0;
uint32_t size = 0;
uint32_t pitch = 0;
uint32_t row = 0;
UNUSED(sysMemSize);
if(sysMem == nullptr)
{
CM_ASSERTMESSAGE("Error: Pointer to system memory is null.")
return CM_INVALID_ARG_VALUE;
}
if( event )
{
CmEventRT *eventRT = static_cast<CmEventRT *>(event);
FlushDeviceQueue( eventRT ); //wait specific task finished
}
WaitForReferenceFree(); // wait all owner task finished
CmDeviceRT * cmDevice = nullptr;
m_surfaceMgr->GetCmDevice(cmDevice);
CMCHK_NULL_AND_RETURN(cmDevice);
//Lock for surface read/write
CSync* surfaceLock = cmDevice->GetSurfaceLock();
CM_ASSERT(surfaceLock);
CLock locker(*surfaceLock);
PCM_CONTEXT_DATA cmData = (PCM_CONTEXT_DATA)cmDevice->GetAccelData();
CMCHK_NULL_AND_RETURN(cmData);
CMCHK_NULL_AND_RETURN(cmData->cmHalState);
CM_HAL_SURFACE2D_LOCK_UNLOCK_PARAM inParam;
CmSafeMemSet( &inParam, 0, sizeof( CM_HAL_SURFACE2D_LOCK_UNLOCK_PARAM ) );
inParam.width = m_width;
inParam.height = m_height;
inParam.handle = m_handle;
inParam.lockFlag = CM_HAL_LOCKFLAG_WRITEONLY;
// Lock Surface Resource:
// Lock may fail due to the out of memory/out of page-in in KMD.
// Touch queue for the buffer/surface data release
CHK_MOSSTATUS_RETURN_CMERROR(cmData->cmHalState->pfnLock2DResource(cmData->cmHalState, &inParam));
CMCHK_NULL(inParam.data);
//Copy data
dst = ( uint8_t *)(inParam.data);
surf = ( uint8_t *)sysMem;
// Get the memory size according to the format
CMCHK_HR(m_surfaceMgr->GetPixelBytesAndHeight(m_width, m_height, m_format, sizePerPixel, updatedHeight));
size = m_width * sizePerPixel;
pitch = m_pitch;
if(pitch != size)
{
for (row = 0; row < updatedHeight; row ++)
{
CmFastMemCopyWC(dst, surf, size);
surf += size;
dst += pitch;
}
}
else
{
CmFastMemCopyWC(dst, surf, pitch * updatedHeight);
}
//Unlock Surface2D
inParam.data = nullptr;
CHK_MOSSTATUS_RETURN_CMERROR(cmData->cmHalState->pfnUnlock2DResource(cmData->cmHalState, &inParam));
finish:
return hr;
}
//*-----------------------------------------------------------------------------
//| Purpose: Hybrid memory copy from Surface 2D to system memory with stride
//| Arguments :
//| sysMem [out] Pointer to system memory
//| event [in] Pointer to CmEvent
//| horizontalStride [in] Width Stride in system memory in bytes
//| verticalStride[in] Height Stride in system memory in rows
//| sysMemSize [in] Size of Memory need to read
//| option [in] Option to disable/enable hybrid memory copy
//| Returns: Result of the operation.
//*-----------------------------------------------------------------------------
CM_RT_API int32_t CmSurface2DRT::ReadSurfaceHybridStrides( unsigned char* sysMem, CmEvent* event, const uint32_t horizontalStride, const uint32_t verticalStride, uint64_t sysMemSize, uint32_t option )
{
INSERT_API_CALL_LOG();
int32_t hr = CM_SUCCESS;
uint32_t sizePerPixel = 0;
uint32_t updatedHeight = 0;
uint32_t widthInBytes = 0;
CmQueue *cmQueue = nullptr;
CmDeviceRT *cmDevice = nullptr;
CmQueueRT *cmQueueRT = nullptr;
bool forceCPUCopy = COPY_OPTION(option);
CM_STATUS status;
m_surfaceMgr->GetCmDevice(cmDevice);
CMCHK_NULL_AND_RETURN(cmDevice);
int32_t result = m_surfaceMgr->GetPixelBytesAndHeight(m_width, m_height, m_format, sizePerPixel, updatedHeight);
if (result != CM_SUCCESS)
{
CM_ASSERTMESSAGE("Error: Failed to get correct surface info.")
return result;
}
widthInBytes = m_width * sizePerPixel;
if(sysMem == nullptr || horizontalStride < widthInBytes || verticalStride < m_height)
{
CM_ASSERTMESSAGE("Error: Invalid input arguments.")
return CM_INVALID_ARG_VALUE;
}
if( event )
{
CmEventRT *eventRT = static_cast<CmEventRT *>(event);
FlushDeviceQueue( eventRT );
}
WaitForReferenceFree(); // wait all owner task finished
if (forceCPUCopy)
{
CMCHK_HR(ReadSurfaceFullStride(sysMem, event, horizontalStride, verticalStride, sysMemSize));
}
else
{
CMCHK_HR(cmDevice->CreateQueue(cmQueue));
if(IsGPUCopy((void*)sysMem, widthInBytes, m_height, horizontalStride))
{
CMCHK_HR(cmQueue->EnqueueCopyGPUToCPUFullStride(this, sysMem, horizontalStride, verticalStride, 0, event));
if(event)
{
CMCHK_HR(event->GetStatus(status));
while(status != CM_STATUS_FINISHED)
{
if (status == CM_STATUS_RESET)
{
hr = CM_TASK_MEDIA_RESET;
goto finish;
}
CMCHK_HR(event->GetStatus(status));
}
}
else
{
CM_ASSERTMESSAGE("Error: Hybrid memory copy from surface 2D to system memory failure.")
return CM_FAILURE;
}
}
else if (IsUnalignedGPUCopy(widthInBytes, m_height))
{
cmQueueRT = static_cast<CmQueueRT *>(cmQueue);
CMCHK_HR(cmQueueRT->EnqueueUnalignedCopyInternal(this, (unsigned char*)sysMem, horizontalStride, verticalStride, CM_FASTCOPY_GPU2CPU, event));
}
else
{
CMCHK_HR(ReadSurfaceFullStride(sysMem, event, horizontalStride, verticalStride, sysMemSize));
}
}
finish:
return hr;
}
//*-----------------------------------------------------------------------------
//| Purpose: Read data from Surface 2D to system memory
//| Arguments :
//| sysMem [in] Pointer to system memory
//| event [in] Pointer to CmEvent
//| sysMemSize [out] Size of Memory need to read
//|
//| Returns: Result of the operation.
//*-----------------------------------------------------------------------------
CM_RT_API int32_t CmSurface2DRT::ReadSurface( unsigned char* sysMem, CmEvent* event, uint64_t sysMemSize )
{
INSERT_API_CALL_LOG();
CM_RETURN_CODE hr = CM_SUCCESS;
uint8_t *dst = nullptr;
uint8_t *surf = nullptr;
uint32_t sizePerPixel = 0;
uint32_t updatedHeight = 0;
uint32_t widthInByte = 0;
uint32_t pitch = 0;
uint32_t row = 0;
UNUSED(sysMemSize);
if(sysMem == nullptr)
{
CM_ASSERTMESSAGE("Error: Pointer to system memory is null.")
return CM_INVALID_ARG_VALUE;
}
if( event )
{
CmEventRT *eventRT = static_cast<CmEventRT *>(event);
FlushDeviceQueue( eventRT );
}
WaitForReferenceFree(); // wait all owner task finished
CmDeviceRT * cmDevice = nullptr;
m_surfaceMgr->GetCmDevice(cmDevice);
CMCHK_NULL_AND_RETURN(cmDevice);
//Lock for surface read/write
CSync* surfaceLock = cmDevice->GetSurfaceLock();
CM_ASSERT(surfaceLock);
CLock locker(*surfaceLock);
PCM_CONTEXT_DATA cmData = (PCM_CONTEXT_DATA)cmDevice->GetAccelData();
CMCHK_NULL_AND_RETURN(cmData);
CMCHK_NULL_AND_RETURN(cmData->cmHalState);
CM_HAL_SURFACE2D_LOCK_UNLOCK_PARAM inParam;
CmSafeMemSet( &inParam, 0, sizeof( CM_HAL_SURFACE2D_LOCK_UNLOCK_PARAM ) );
inParam.width = m_width;
inParam.height = m_height;
inParam.handle = m_handle;
inParam.lockFlag = CM_HAL_LOCKFLAG_READONLY;
// Lock Surface Resource:
// Lock may fail due to the out of memory/out of page-in in KMD.
// Touch queue for the buffer/surface data release
CHK_MOSSTATUS_RETURN_CMERROR(cmData->cmHalState->pfnLock2DResource(cmData->cmHalState, &inParam));
CMCHK_NULL(inParam.data);
//Copy data
dst = ( uint8_t *)sysMem;
surf= ( uint8_t *)(inParam.data);
CMCHK_HR(m_surfaceMgr->GetPixelBytesAndHeight(m_width, m_height, m_format, sizePerPixel, updatedHeight));
widthInByte = m_width * sizePerPixel;
pitch = m_pitch;
if (pitch != widthInByte)
{
for (row = 0; row < updatedHeight; row ++)
{
CmFastMemCopyFromWC(dst, surf, widthInByte, GetCpuInstructionLevel());
surf += pitch;
dst += widthInByte;
}
}
else
{
CmFastMemCopyFromWC(dst, surf, pitch * updatedHeight, GetCpuInstructionLevel());
}
//Unlock
inParam.data = nullptr;
CHK_MOSSTATUS_RETURN_CMERROR(cmData->cmHalState->pfnUnlock2DResource(cmData->cmHalState, &inParam));
finish:
return hr;
}
//*-----------------------------------------------------------------------------
//| Purpose: Get the index of CmSurface2D
//| Returns: Result of the operation.
//*-----------------------------------------------------------------------------
CM_RT_API int32_t CmSurface2DRT::GetIndex( SurfaceIndex*& index )
{
index = m_index;
return CM_SUCCESS;
}
//*-----------------------------------------------------------------------------
//| Purpose: Write data from system memory to Surface 2D to with stride
//| Arguments :
//| sysMem [in] Pointer to system memory
//| event [in] Pointer to CmEvent
//| Stride [in] Stride in system memory in bytes
//| sysMemSize [out] Size of Memory need to read
//|
//| Returns: Result of the operation.
//*-----------------------------------------------------------------------------
CM_RT_API int32_t CmSurface2DRT::WriteSurfaceStride( const unsigned char* sysMem, CmEvent* event, const uint32_t stride, uint64_t sysMemSize )
{
INSERT_API_CALL_LOG();
CM_RETURN_CODE hr = CM_SUCCESS;
uint8_t *dst = nullptr;
uint8_t *src = nullptr;
uint32_t sizePerPixel = 0;
uint32_t updatedHeight = 0;
uint32_t widthInByte = 0;
uint32_t pitch = 0;
uint32_t row = 0;
UNUSED(sysMemSize);
if(sysMem == nullptr)
{
CM_ASSERTMESSAGE("Error: Pointer to system memory is null.")
return CM_INVALID_ARG_VALUE;
}
if( event )
{
CmEventRT *eventRT = static_cast<CmEventRT *>(event);
FlushDeviceQueue( eventRT ); // wait specific owner task finished
}
WaitForReferenceFree(); // wait all owner tasks finished
CmDeviceRT * cmDevice = nullptr;
m_surfaceMgr->GetCmDevice(cmDevice);
CMCHK_NULL_AND_RETURN(cmDevice);
//Lock for surface read/write
CSync* surfaceLock = cmDevice->GetSurfaceLock();
CM_ASSERT(surfaceLock);
CLock locker(*surfaceLock);
PCM_CONTEXT_DATA cmData = (PCM_CONTEXT_DATA)cmDevice->GetAccelData();
CMCHK_NULL_AND_RETURN(cmData);
CMCHK_NULL_AND_RETURN(cmData->cmHalState);
CM_HAL_SURFACE2D_LOCK_UNLOCK_PARAM inParam;
CmSafeMemSet( &inParam, 0, sizeof( CM_HAL_SURFACE2D_LOCK_UNLOCK_PARAM ) );
inParam.width = m_width;
inParam.height = m_height;
inParam.handle = m_handle;
inParam.lockFlag = CM_HAL_LOCKFLAG_WRITEONLY;
// Lock Surface Resource:
// Lock may fail due to the out of memory/out of page-in in KMD.
// Touch queue for the buffer/surface data release
CHK_MOSSTATUS_RETURN_CMERROR(cmData->cmHalState->pfnLock2DResource(cmData->cmHalState, &inParam));
CMCHK_NULL(inParam.data);
//Copy data
dst = ( uint8_t *)(inParam.data);
src = ( uint8_t *)sysMem;
// Get the memory size according to the format
CMCHK_HR(m_surfaceMgr->GetPixelBytesAndHeight(m_width, m_height, m_format, sizePerPixel, updatedHeight));
widthInByte = m_width * sizePerPixel;
pitch = m_pitch;
if ((pitch != widthInByte) || (stride != pitch))
{
for (row = 0; row < updatedHeight; row ++)
{
CmFastMemCopyWC(dst, src, widthInByte);
src += stride;
dst += pitch;
}
}
else
{
CmFastMemCopyWC(dst, src, pitch * updatedHeight);
}
//Unlock Surface2D
inParam.data = nullptr; //Set pData to Null to differentiate route from app or cmrt@umd
CHK_MOSSTATUS_RETURN_CMERROR(cmData->cmHalState->pfnUnlock2DResource(cmData->cmHalState, &inParam));
finish:
return hr;
}
CM_RT_API int32_t CmSurface2DRT::SetCompressionMode(MEMCOMP_STATE mmcMode)
{
INSERT_API_CALL_LOG();
CM_RETURN_CODE hr = CM_SUCCESS;
CM_HAL_SURFACE2D_COMPRESSIOM_PARAM mmcModeParam;
CmDeviceRT * cmDevice = nullptr;
m_surfaceMgr->GetCmDevice(cmDevice);
CM_ASSERT(cmDevice);
mmcModeParam.handle = m_handle;
mmcModeParam.mmcMode = mmcMode;
PCM_CONTEXT_DATA cmData = (PCM_CONTEXT_DATA)cmDevice->GetAccelData();
CM_ASSERT(cmData);
CMCHK_NULL_AND_RETURN(cmData->cmHalState);
CHK_MOSSTATUS_RETURN_CMERROR(cmData->cmHalState->pfnSetCompressionMode(cmData->cmHalState, mmcModeParam));
finish:
return hr;
}
//*-----------------------------------------------------------------------------
//| Purpose: Read data from Surface 2D to system memory with stride
//| Arguments :
//| sysMem [in] Pointer to system memory
//| event [in] Pointer to CmEvent
//| Stride [in] Stride in system memory in bytes
//| sysMemSize [out] Size of Memory need to read
//|
//| Returns: Result of the operation.
//*-----------------------------------------------------------------------------
CM_RT_API int32_t CmSurface2DRT::ReadSurfaceStride( unsigned char* sysMem, CmEvent* event, const uint32_t stride, uint64_t sysMemSize )
{
INSERT_API_CALL_LOG();
return ReadSurfaceFullStride(sysMem, event, stride, m_height, sysMemSize);
}
//*-----------------------------------------------------------------------------
//| Purpose: Read data from Surface 2D to system memory with stride
//| Arguments :
//| sysMem [in] Pointer to system memory
//| event [in] Pointer to CmEvent
//| horizontalStride [in] Width Stride in system memory in bytes
//| verticalStride[in] Height Stride in system memory in rows
//| sysMemSize [out] Size of Memory need to read
//|
//| Returns: Result of the operation.
//*-----------------------------------------------------------------------------
CM_RT_API int32_t CmSurface2DRT::ReadSurfaceFullStride( unsigned char* sysMem, CmEvent* event,
const uint32_t horizontalStride, const uint32_t verticalStride, uint64_t sysMemSize )
{
INSERT_API_CALL_LOG();
CM_RETURN_CODE hr = CM_SUCCESS;
uint8_t *dst = nullptr;
uint8_t *src = nullptr;
uint32_t sizePerPixel = 0;
uint32_t updatedHeight = 0;
UNUSED(sysMemSize);
if(sysMem == nullptr)
{
CM_ASSERTMESSAGE("Error: Pointer to system memory is null.")
return CM_INVALID_ARG_VALUE;
}
if( event )
{
CmEventRT *eventRT = static_cast<CmEventRT *>(event);
FlushDeviceQueue( eventRT ); //wait specific task finished
}
WaitForReferenceFree(); // wait all owner task finished
CmDeviceRT * cmDevice = nullptr;
m_surfaceMgr->GetCmDevice(cmDevice);
CMCHK_NULL_AND_RETURN(cmDevice);
//Lock for surface read/write
CSync* surfaceLock = cmDevice->GetSurfaceLock();
CM_ASSERT(surfaceLock);
CLock locker(*surfaceLock);
PCM_CONTEXT_DATA cmData = (PCM_CONTEXT_DATA)cmDevice->GetAccelData();
CMCHK_NULL_AND_RETURN(cmData);
CMCHK_NULL_AND_RETURN(cmData->cmHalState);
CM_HAL_SURFACE2D_LOCK_UNLOCK_PARAM inParam;
CmSafeMemSet( &inParam, 0, sizeof( CM_HAL_SURFACE2D_LOCK_UNLOCK_PARAM ) );
inParam.width = m_width;
inParam.height = m_height;
inParam.handle = m_handle;
inParam.lockFlag = CM_HAL_LOCKFLAG_READONLY;
// Lock Data
CHK_MOSSTATUS_RETURN_CMERROR(cmData->cmHalState->pfnLock2DResource(cmData->cmHalState, &inParam));
CMCHK_NULL(inParam.data);
//Copy data
dst = ( uint8_t *)sysMem;
src = ( uint8_t *)(inParam.data);
// Get the memory size according to the format
CMCHK_HR(m_surfaceMgr->GetPixelBytesAndHeight(m_width, m_height, m_format, sizePerPixel, updatedHeight));
if( m_format == CM_SURFACE_FORMAT_NV12)
{
for( uint32_t i=0 ; i< m_height ; i++)
{ // Y plane
CmFastMemCopyFromWC(dst, src, m_width, GetCpuInstructionLevel());
src += m_pitch;
dst += horizontalStride;
}
src = ( uint8_t *)(inParam.data) + m_height * m_pitch;
dst = ( uint8_t *)sysMem + horizontalStride * verticalStride;
//To support NV12 format with odd height here.
//if original height is even, the UV plane's height is set as m_height/2, which equals to (m_height+1)/2
//if original height is odd, the UV plane's height is set as roundup(m_height/2), which equals to (m_height+1)/2 too
for (uint32_t i = 0; i< (m_height + 1) / 2; i++)
{ // UV plane
CmFastMemCopyFromWC(dst, src, m_width, GetCpuInstructionLevel());
src += m_pitch;
dst += horizontalStride;
}
}
else
{
uint32_t size = m_width * sizePerPixel;
uint32_t pitch = m_pitch;
if((pitch != size)||(horizontalStride != size))
{
for (uint32_t i=0; i < updatedHeight; i++)
{
CmFastMemCopyFromWC(dst, src, size, GetCpuInstructionLevel());
src += pitch;
dst += horizontalStride;
}
}
else
{
CmFastMemCopyFromWC(dst, src, pitch * updatedHeight, GetCpuInstructionLevel());
}
}
//Unlock
inParam.data = nullptr; //Set pData to Null to differentiate route from app or cmrt@umd
CHK_MOSSTATUS_RETURN_CMERROR(cmData->cmHalState->pfnUnlock2DResource(cmData->cmHalState, &inParam));
finish:
return hr;
}
//*-----------------------------------------------------------------------------
//| Purpose: Write data from system memory to Surface 2D to with stride
//| Arguments :
//| sysMem [in] Pointer to system memory
//| event [in] Pointer to CmEvent
//| horizontalStride [in] Stride in system memory in bytes
//| verticalStride[in] Height Stride in system memory in rows
//| sysMemSize [out] Size of Memory need to read
//|
//| Returns: Result of the operation.
//*-----------------------------------------------------------------------------
CM_RT_API int32_t CmSurface2DRT::WriteSurfaceFullStride( const unsigned char* sysMem, CmEvent* event, const uint32_t horizontalStride, const uint32_t verticalStride, uint64_t sysMemSize )
{
INSERT_API_CALL_LOG();
CM_RETURN_CODE hr = CM_SUCCESS;
uint8_t *dst = nullptr;
uint8_t *src = nullptr;
uint32_t sizePerPixel = 0;
uint32_t updatedHeight = 0;
UNUSED(sysMemSize);
if(sysMem == nullptr)
{
CM_ASSERTMESSAGE("Error: Pointer to system memory is null.")
return CM_INVALID_ARG_VALUE;
}
if( event )
{
CmEventRT *eventRT = static_cast<CmEventRT *>(event);
FlushDeviceQueue( eventRT ); // wait specific owner task finished
}
WaitForReferenceFree(); // wait all owner tasks finished
CmDeviceRT * cmDevice = nullptr;
m_surfaceMgr->GetCmDevice(cmDevice);
CMCHK_NULL_AND_RETURN(cmDevice);
//Lock for surface read/write
CSync* surfaceLock = cmDevice->GetSurfaceLock();
CM_ASSERT(surfaceLock);
CLock locker(*surfaceLock);
PCM_CONTEXT_DATA cmData = (PCM_CONTEXT_DATA)cmDevice->GetAccelData();
CMCHK_NULL_AND_RETURN(cmData);
CMCHK_NULL_AND_RETURN(cmData->cmHalState);
CM_HAL_SURFACE2D_LOCK_UNLOCK_PARAM inParam;
CmSafeMemSet( &inParam, 0, sizeof( CM_HAL_SURFACE2D_LOCK_UNLOCK_PARAM ) );
inParam.width = m_width;
inParam.height = m_height;
inParam.handle = m_handle;
inParam.lockFlag = CM_HAL_LOCKFLAG_WRITEONLY;
// Lock Surface Resource:
// Lock may fail due to the out of memory/out of page-in in KMD.
// Touch queue for the buffer/surface data release
CHK_MOSSTATUS_RETURN_CMERROR(cmData->cmHalState->pfnLock2DResource(cmData->cmHalState, &inParam));
CMCHK_NULL(inParam.data);
//Copy data
dst = ( uint8_t *)(inParam.data);
src = ( uint8_t *)sysMem;
// Get the memory size according to the format
CMCHK_HR(m_surfaceMgr->GetPixelBytesAndHeight(m_width, m_height, m_format, sizePerPixel, updatedHeight));
if( m_format == CM_SURFACE_FORMAT_NV12)
{
for( uint32_t i=0 ; i< m_height ; i++)
{ // Y plane
CmFastMemCopyFromWC(dst, src, m_width, GetCpuInstructionLevel());
src += horizontalStride ;
dst += m_pitch;
}
dst = ( uint8_t *)(inParam.data) + m_height * m_pitch;
src = ( uint8_t *)sysMem + horizontalStride * verticalStride;
//To support NV12 format with odd height here.
//if original height is even, the UV plane's height is set as m_height/2, which equals to (m_height+1)/2
//if original height is odd, the UV plane's height is set as roundup(m_height/2), which equals to (m_height+1)/2 too
for( uint32_t i=0 ; i< ( m_height + 1) /2 ; i++)
{ // UV plane
CmFastMemCopyFromWC(dst, src, m_width, GetCpuInstructionLevel());
src += horizontalStride ;
dst += m_pitch;
}
}
else
{
uint32_t size = m_width * sizePerPixel;
uint32_t pitch = m_pitch;
if((pitch != size)||(horizontalStride != pitch))
{
for (uint32_t i=0; i < updatedHeight; i++)
{
CmFastMemCopyWC(dst, src, size);
src += horizontalStride;
dst += pitch;
}
}
else
{
CmFastMemCopyWC(dst, src, pitch * updatedHeight);
}
}
//Unlock Surface2D
inParam.data = nullptr; //Set pData to Null to differentiate route from app or cmrt@umd
CHK_MOSSTATUS_RETURN_CMERROR(cmData->cmHalState->pfnUnlock2DResource(cmData->cmHalState, &inParam));
finish:
return hr;
}
//*-----------------------------------------------------------------------------
//| Purpose: Let CM know that the UMD resource of current CmSurface2D
// wrapper was changed. This change may happen at the CmSurface2D
// creation and destroy time or changed from outside of CM. This
// should be called immediately after the UMD resource changed.
//
//| Arguments :
//| umdResource [in] Pointer to the UMD resource for the CM
//| wrapper. Set it to nullptr when the
//| third party MosResource was deleted
//| before the CmSurface2D.
//| updateMosResource [in] 1: will update the MosResource.
//| 0: will not update the MosResource.
//| mosResource [in] Pointer to the new valid MosResource
//| that the CMSurface2D will be based on.
//| Do not set this parameter if the
//| MosResource is already deleted.
//| Returns: Result of the operation.
//*-----------------------------------------------------------------------------
CMRT_UMD_API int32_t
CmSurface2DRT::NotifyUmdResourceChanged(UMD_RESOURCE umdResource,
int updateMosResource,
PMOS_RESOURCE mosResource)
{
m_umdResource = umdResource;
//
if ( updateMosResource )
{
m_surfaceMgr->UpdateSurface2DTableMosResource( m_handle, mosResource );
}
return CM_SUCCESS;
}
//*-----------------------------------------------------------------------------
//| Purpose: Get the handle of CmSurface2D
//| Returns: Result of the operation.
//*-----------------------------------------------------------------------------
int32_t CmSurface2DRT::GetHandle( uint32_t& handle)
{
handle = m_handle;
return CM_SUCCESS;
}
//*-----------------------------------------------------------------------------
//| Purpose: Get the handle of CmSurface2D
//| Returns: Result of the operation.
//*-----------------------------------------------------------------------------
int32_t CmSurface2DRT::GetIndexFor2D( uint32_t& index )
{
index = m_handle;
return CM_SUCCESS;
}
int32_t CmSurface2DRT::SetSurfaceProperties(uint32_t width, uint32_t height, CM_SURFACE_FORMAT format)
{
if (format == CM_SURFACE_FORMAT_NV12)
{
m_pitch = MOS_ALIGN_CEIL(width * m_pitch /m_width , 2);
}
m_width = width;
m_height = height;
m_format = format;
return CM_SUCCESS;
}
//*-----------------------------------------------------------------------------
//| Purpose: Get the description of surface 2d, width,height,format and the size of pixel .
//| Arguments :
//| width [out] Reference to width of surface
//| height [out] Reference to height of surface
//| format [out] Reference to format of surface
//| sizeperpixel [out] Reference to the pixel's size in bytes
//|
//| Returns: Result of the operation.
//*-----------------------------------------------------------------------------
CM_RT_API int32_t CmSurface2DRT::GetSurfaceDesc(uint32_t &width, uint32_t &height, CM_SURFACE_FORMAT &format,uint32_t &sizeperpixel)
{
int ret = CM_SUCCESS;
uint32_t updatedHeight = 0 ;
width = m_width;
height = m_height;
format = m_format;
// Get size per pixel
ret = m_surfaceMgr->GetPixelBytesAndHeight(width, height, format, sizeperpixel, updatedHeight);
return CM_SUCCESS;
}
CM_RT_API int32_t CmSurface2DRT::InitSurface(const unsigned int initValue, CmEvent* event)
{
INSERT_API_CALL_LOG();
CM_RETURN_CODE hr = CM_SUCCESS;
CmDeviceRT* cmDevice = nullptr;
PCM_CONTEXT_DATA cmData = nullptr;
CM_HAL_SURFACE2D_LOCK_UNLOCK_PARAM inParam;
uint32_t pitch = 0;
uint32_t *surf = nullptr;
uint32_t widthInBytes = 0;
if( event )
{
CmEventRT *eventRT = static_cast<CmEventRT *>(event);
FlushDeviceQueue( eventRT );
}
WaitForReferenceFree(); // wait all owner task finished
uint32_t sizePerPixel = 0;
uint32_t updatedHeight = 0;
CMCHK_HR(m_surfaceMgr->GetPixelBytesAndHeight(m_width, m_height, m_format, sizePerPixel, updatedHeight));
m_surfaceMgr->GetCmDevice(cmDevice);
CMCHK_NULL_AND_RETURN(cmDevice);
cmData = (PCM_CONTEXT_DATA)cmDevice->GetAccelData();
CMCHK_NULL_AND_RETURN(cmData);
CMCHK_NULL_AND_RETURN(cmData->cmHalState);
CmSafeMemSet( &inParam, 0, sizeof( CM_HAL_SURFACE2D_LOCK_UNLOCK_PARAM ) );
inParam.width = m_width;
inParam.height = m_height;
inParam.handle = m_handle;
inParam.lockFlag = CM_HAL_LOCKFLAG_WRITEONLY;
CHK_MOSSTATUS_RETURN_CMERROR(cmData->cmHalState->pfnLock2DResource(cmData->cmHalState, &inParam));
CMCHK_NULL(inParam.data);
pitch = inParam.pitch;
surf = ( uint32_t *)inParam.data;
widthInBytes = m_width * sizePerPixel;
if(widthInBytes != pitch)
{
for (uint32_t i=0; i < updatedHeight; i++)
{
if (widthInBytes % sizeof(uint32_t) == 0)
{
CmDwordMemSet(surf, initValue, widthInBytes);
}
else
{
CmDwordMemSet(surf, initValue, widthInBytes + sizeof(uint32_t));
}
surf += (pitch >> 2); // divide by 4 byte to dword
}
}
else
{
CmDwordMemSet(surf, initValue, pitch * updatedHeight);
}
//Unlock Surface2D
inParam.data = nullptr;
CHK_MOSSTATUS_RETURN_CMERROR(cmData->cmHalState->pfnUnlock2DResource(cmData->cmHalState, &inParam));
finish:
return hr;
}
int32_t CmSurface2DRT::SetMemoryObjectControl( MEMORY_OBJECT_CONTROL memCtrl, MEMORY_TYPE memType, uint32_t age)
{
INSERT_API_CALL_LOG();
CM_RETURN_CODE hr = CM_SUCCESS;
uint16_t mocs = 0;
CmSurface::SetMemoryObjectControl( memCtrl, memType, age );
CmDeviceRT *cmDevice = nullptr;
m_surfaceMgr->GetCmDevice(cmDevice);
CMCHK_NULL_AND_RETURN(cmDevice);
PCM_CONTEXT_DATA cmData = (PCM_CONTEXT_DATA)cmDevice->GetAccelData();
CMCHK_NULL_AND_RETURN(cmData);
CMCHK_NULL_AND_RETURN(cmData->cmHalState);
mocs = (m_memObjCtrl.mem_ctrl << 8) | (m_memObjCtrl.mem_type<<4) | m_memObjCtrl.age;
CHK_MOSSTATUS_RETURN_CMERROR(cmData->cmHalState->pfnSetSurfaceMOCS(cmData->cmHalState, m_handle, mocs, ARG_KIND_SURFACE_2D));
finish:
return hr;
}
CM_RT_API int32_t CmSurface2DRT::SelectMemoryObjectControlSetting(MEMORY_OBJECT_CONTROL memCtrl)
{
return SetMemoryObjectControl(memCtrl, CM_USE_PTE, 0);
}
int32_t CmSurface2DRT::Create2DAlias(SurfaceIndex* & aliasIndex)
{
INSERT_API_CALL_LOG();
uint32_t surfArraySize = 0;
uint32_t newIndex = 0;
uint32_t origIndex = 0;
if( m_numAliases < CM_HAL_MAX_NUM_2D_ALIASES )
{
origIndex = m_index->get_data();
m_surfaceMgr->GetSurfaceArraySize(surfArraySize);
newIndex = origIndex + ( (m_numAliases + 1) * surfArraySize);
m_aliasIndexes[m_numAliases] = MOS_New(SurfaceIndex, newIndex);
if( m_aliasIndexes[m_numAliases] )
{
aliasIndex = m_aliasIndexes[m_numAliases];
m_numAliases++;
return CM_SUCCESS;
}
else
{
CM_ASSERTMESSAGE("Error: Failed to create surface 2d alias due to out of system memory.");
return CM_OUT_OF_HOST_MEMORY;
}
}
else
{
return CM_EXCEED_MAX_NUM_2D_ALIASES;
}
}
CM_RT_API int32_t CmSurface2DRT::GetNumAliases(uint32_t& numAliases)
{
numAliases = m_numAliases;
return CM_SUCCESS;
}
CM_RT_API int32_t CmSurface2DRT::SetSurfaceStateParam( SurfaceIndex *surfIndex, const CM_SURFACE2D_STATE_PARAM *surfStateParam )
{
CM_RETURN_CODE hr = CM_SUCCESS;
CmDeviceRT * cmDevice = nullptr;
PCM_CONTEXT_DATA cmData = nullptr;
CM_HAL_SURFACE2D_SURFACE_STATE_PARAM inParam;
uint32_t aliasIndex = 0;
m_surfaceMgr->GetCmDevice( cmDevice );
CMCHK_NULL(cmDevice);
cmData = ( PCM_CONTEXT_DATA )cmDevice->GetAccelData();
CMCHK_NULL(cmData);
CMCHK_NULL(cmData->cmHalState);
CmSafeMemSet( &inParam, 0, sizeof( inParam ) );
inParam.width = surfStateParam->width;
inParam.height = surfStateParam->height;
inParam.format = surfStateParam->format;
inParam.depth = surfStateParam->depth;
inParam.pitch = surfStateParam->pitch;
inParam.memoryObjectControl = surfStateParam->memory_object_control;
inParam.surfaceXOffset = surfStateParam->surface_x_offset;
inParam.surfaceYOffset = surfStateParam->surface_y_offset;
if (surfIndex)
{
aliasIndex = surfIndex->get_data();
}
else
{
aliasIndex = m_index->get_data();
}
CHK_MOSSTATUS_RETURN_CMERROR( cmData->cmHalState->pfnSet2DSurfaceStateParam(cmData->cmHalState, &inParam, aliasIndex, m_handle) );
finish:
return hr;
}
CMRT_UMD_API int32_t CmSurface2DRT::SetReadSyncFlag(bool readSync)
{
int32_t hr = CM_SUCCESS;
CmDeviceRT *cmDevice = nullptr;
m_surfaceMgr->GetCmDevice(cmDevice);
CMCHK_NULL_AND_RETURN(cmDevice);
PCM_CONTEXT_DATA cmData = (PCM_CONTEXT_DATA)cmDevice->GetAccelData();
CMCHK_NULL_AND_RETURN(cmData);
CMCHK_NULL_AND_RETURN(cmData->cmHalState);
hr = cmData->cmHalState->pfnSetSurfaceReadFlag(cmData->cmHalState, m_handle, readSync);
if( FAILED(hr) )
{
CM_ASSERTMESSAGE("Error: Set read sync flag failure.")
return CM_FAILURE;
}
return hr;
}
void CmSurface2DRT::Log(std::ostringstream &oss)
{
#if CM_LOG_ON
oss << " Surface2D Info "
<< " Width:" << m_width
<< " Height:"<< m_height
<< " Format:"<< GetFormatString(m_format)
<< " Pitch:" << m_pitch
<< " Handle:" << m_handle
<< " SurfaceIndex:" << m_index->get_data()
<< " IsCmCreated:"<<m_isCmCreated
<< std::endl;
#endif
}
void CmSurface2DRT::DumpContent(uint32_t kernelNumber, char *kernelName, int32_t taskId, uint32_t argIndex)
{
#if MDF_SURFACE_CONTENT_DUMP
std::ostringstream outputFileName;
static uint32_t surface2DDumpNumber = 0;
outputFileName << "t_" << taskId
<< "_k_" << kernelNumber
<< "_" << kernelName
<< "_argi_" << argIndex
<< "_surf2d_surfi_"<< m_index->get_data()
<< "_w_" << m_width
<< "_h_" << m_height
<< "_p_" << m_pitch
<< "_f_" << GetFormatString(m_format)
<< "_" << surface2DDumpNumber;
std::ofstream outputFileStream;
outputFileStream.open(outputFileName.str().c_str(), std::ofstream::binary);
CmDeviceRT * cmDevice = nullptr;
m_surfaceMgr->GetCmDevice(cmDevice);
CM_ASSERT(cmDevice);
CSync* surfaceLock = cmDevice->GetSurfaceLock();
CM_ASSERT(surfaceLock);
CLock locker(*surfaceLock);
uint32_t sizePerPixel = 0;
uint32_t updatedHeight = 0;
uint32_t surfaceSize = 0;
uint32_t widthInByte = 0;
uint8_t *dst = nullptr;
uint8_t *surf = nullptr;
m_surfaceMgr->GetPixelBytesAndHeight(m_width, m_height, m_format, sizePerPixel, updatedHeight);
surfaceSize = m_width*sizePerPixel*updatedHeight;
widthInByte = m_width * sizePerPixel;
std::vector<char>surface(surfaceSize);
PCM_CONTEXT_DATA cmData = (PCM_CONTEXT_DATA)cmDevice->GetAccelData();
CM_ASSERT(cmData);
CM_ASSERT(cmData->cmHalState);
CM_HAL_SURFACE2D_LOCK_UNLOCK_PARAM inParam;
CmSafeMemSet(&inParam, 0, sizeof(CM_HAL_SURFACE2D_LOCK_UNLOCK_PARAM));
inParam.width = m_width;
inParam.height = m_height;
inParam.handle = m_handle;
inParam.lockFlag = CM_HAL_LOCKFLAG_READONLY;
cmData->cmHalState->pfnLock2DResource(cmData->cmHalState, &inParam);
if (inParam.data == nullptr)
return;
dst = (uint8_t *)&surface[0];
surf = (uint8_t *)(inParam.data);
if (m_pitch != widthInByte)
{
for (uint32_t row = 0; row < updatedHeight; row++)
{
CmFastMemCopyFromWC(dst, surf, widthInByte, GetCpuInstructionLevel());
surf += m_pitch;
dst += widthInByte;
}
}
else
{
CmFastMemCopyFromWC((unsigned char *)&surface[0], surf, m_pitch * updatedHeight, GetCpuInstructionLevel());
}
inParam.data = nullptr;
cmData->cmHalState->pfnUnlock2DResource(cmData->cmHalState, &inParam);
outputFileStream.write(&surface[0], surfaceSize);
outputFileStream.close();
surface2DDumpNumber++;
#endif
}
CM_RT_API int32_t CmSurface2DRT::SetProperty(CM_FRAME_TYPE frameType)
{
m_frameType = frameType;
m_surfaceMgr->UpdateSurface2DTableFrameType(m_handle, frameType);
return CM_SUCCESS;
}
}