blob: 913159530bd379fbc828d8be8a7b22b5a600bef7 [file] [log] [blame]
/*
* Copyright (c) 2007-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_3d_rt.cpp
//! \brief Contains CmSurface3DRT implementations.
//!
#include "cm_surface_3d_rt.h"
#include "cm_device_rt.h"
#include "cm_event_rt.h"
#include "cm_mem.h"
#include "cm_surface_manager.h"
#include "cm_hal.h"
namespace CMRT_UMD
{
int32_t CmSurface3DRT::Create( uint32_t index, uint32_t handle,
uint32_t width, uint32_t height, uint32_t depth,
CM_SURFACE_FORMAT format,
CmSurfaceManager* surfaceManager, CmSurface3DRT* &surface )
{
int32_t result = CM_SUCCESS;
surface = new (std::nothrow) CmSurface3DRT( handle, width, height, depth, format, surfaceManager );
if( surface )
{
result = surface->Initialize( index );
if( result != CM_SUCCESS )
{
CmSurface* baseSurface = surface;
CmSurface::Destroy( baseSurface );
}
}
else
{
CM_ASSERTMESSAGE("Error: Failed to create CmSurface3D due to out of system memory.")
result = CM_OUT_OF_HOST_MEMORY;
}
return result;
}
CmSurface3DRT::CmSurface3DRT( uint32_t handle,
uint32_t width,
uint32_t height,
uint32_t depth,
CM_SURFACE_FORMAT format,
CmSurfaceManager* surfaceManager ):
CmSurface( surfaceManager,true ),
m_handle( handle ),
m_width( width ),
m_height( height ),
m_depth( depth ),
m_format( format )
{
CmSurface::SetMemoryObjectControl(MEMORY_OBJECT_CONTROL_UNKNOW, CM_USE_PTE, 0);
}
CmSurface3DRT::~CmSurface3DRT( void )
{
}
int32_t CmSurface3DRT::Initialize( uint32_t index )
{
return CmSurface::Initialize( index );
}
int32_t CmSurface3DRT::GetHandle( uint32_t& handle)
{
handle = m_handle;
return CM_SUCCESS;
}
CM_RT_API int32_t CmSurface3DRT::WriteSurface( const unsigned char* sysMem,
CmEvent* event,
uint64_t sysMemSize )
{
CM_RETURN_CODE hr = CM_SUCCESS;
uint64_t uSizeInBytes = 0;
uint32_t uWidthInBytes = 0;
uint8_t *tempDst = nullptr;
uint8_t *tempSrc = nullptr;
uint8_t *rPlane = nullptr;
if(sysMem == nullptr)
{
CM_ASSERTMESSAGE("Error: Pointer to system memory is null.")
return CM_INVALID_ARG_VALUE;
}
uint32_t pixel = 0;
switch (m_format)
{
case CM_SURFACE_FORMAT_X8R8G8B8:
case CM_SURFACE_FORMAT_A8R8G8B8:
pixel = 4;
break;
case CM_SURFACE_FORMAT_A16B16G16R16:
pixel = 8;
break;
default:
CM_ASSERTMESSAGE("Error: Unsupported surface format.")
return CM_INVALID_ARG_VALUE;
}
uSizeInBytes = m_width * m_height * m_depth * pixel;
if (sysMemSize < uSizeInBytes)
{
CM_ASSERTMESSAGE("Error: Invalid copy size.")
return CM_INVALID_ARG_VALUE;
}
// It makes sense to flush the whole enqueued tasks for each surface read
// because usually we read the output of the last task.
// Update: using event not to flush the whole enqueued tasks
if( event )
{
CmEventRT *eventRT = static_cast<CmEventRT *>(event);
FlushDeviceQueue( eventRT ); // wait specific owner task finished
}
WaitForReferenceFree(); // wait all owner task finished
CM_HAL_3DRESOURCE_PARAM inParam;
CmSafeMemSet( &inParam, 0, sizeof( CM_HAL_3DRESOURCE_PARAM ) );
CmDeviceRT* device = nullptr;
m_surfaceMgr->GetCmDevice( device );
CM_ASSERT( device );
PCM_CONTEXT_DATA cmData = (PCM_CONTEXT_DATA)device->GetAccelData();
CMCHK_NULL_AND_RETURN(cmData);
CMCHK_NULL_AND_RETURN(cmData->cmHalState);
inParam.handle = m_handle;
inParam.data = (void*)sysMem; //Any non-nullptr value will work
inParam.width = m_width;
inParam.height = m_height;
inParam.depth = m_depth;
inParam.lockFlag = CM_HAL_LOCKFLAG_WRITEONLY;
// Lock 3D 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->pfnLock3DResource(cmData->cmHalState, &inParam));
CMCHK_NULL(inParam.data);
uWidthInBytes = inParam.width * pixel;
//Copy Resource
tempDst = (uint8_t*)inParam.data;
tempSrc = (uint8_t*)sysMem;
rPlane = (uint8_t*)inParam.data;
// Only use Qpitch when Qpitch is supported by HW
if (inParam.qpitchEnabled)
{
if (inParam.pitch == uWidthInBytes && inParam.qpitch == inParam.height)
{
CmFastMemCopyWC(tempDst, tempSrc, (size_t)uSizeInBytes);
}
else
{
for (uint32_t uZ = 0; uZ < inParam.depth; uZ++)
{
tempDst = rPlane;
for (uint32_t uY = 0; uY < inParam.height; uY++)
{
CmFastMemCopyWC(tempDst, tempSrc, uWidthInBytes);
tempSrc += uWidthInBytes;
tempDst += inParam.pitch;
}
rPlane += inParam.qpitch * inParam.pitch;
}
}
}
else
{
if (inParam.pitch == uWidthInBytes)
{
CmFastMemCopyWC(tempDst, tempSrc, (size_t)uSizeInBytes);
}
else
{
for (uint32_t uZ = 0; uZ < inParam.depth; uZ++)
{
for (uint32_t uY = 0; uY < inParam.height; uY++)
{
CmFastMemCopyWC(tempDst, tempSrc, uWidthInBytes);
tempSrc += uWidthInBytes;
tempDst += inParam.pitch;
}
}
}
}
// unlock 3D resource
CHK_MOSSTATUS_RETURN_CMERROR(cmData->cmHalState->pfnUnlock3DResource(cmData->cmHalState, &inParam));
finish:
if (hr < CM_MOS_STATUS_CONVERTED_CODE_OFFSET) {
hr = CM_LOCK_SURFACE_FAIL;
}
return hr;
}
CM_RT_API int32_t CmSurface3DRT::ReadSurface( unsigned char* sysMem, CmEvent* event, uint64_t sysMemSize )
{
CM_RETURN_CODE hr = CM_SUCCESS;
uint64_t uSizeInBytes = 0;
uint32_t uWidthInBytes = 0;
uint8_t *tempDst = nullptr;
uint8_t *tempSrc = nullptr;
uint8_t *rPlane = nullptr;
if(sysMem == nullptr)
{
CM_ASSERTMESSAGE("Error: Pointer to system memory is null.")
return CM_INVALID_ARG_VALUE;
}
uint32_t pixel = 0;
switch (m_format)
{
case CM_SURFACE_FORMAT_X8R8G8B8:
case CM_SURFACE_FORMAT_A8R8G8B8:
pixel = 4;
break;
case CM_SURFACE_FORMAT_A16B16G16R16:
pixel = 8;
break;
default:
CM_ASSERTMESSAGE("Error: Unsupported surface format.")
return CM_INVALID_ARG_VALUE;
}
uSizeInBytes = m_width * m_height * m_depth * pixel;
if (sysMemSize < uSizeInBytes)
{
CM_ASSERTMESSAGE("Error: Invalid copy size.")
return CM_INVALID_ARG_VALUE;
}
// It makes sense to flush the whole enqueued tasks for each surface read
// because usually we read the output of the last task.
// Update: using event not to flush the whole enqueued tasks
if( event )
{
CmEventRT *eventRT = static_cast<CmEventRT *>(event);
int hr = FlushDeviceQueue( eventRT ); // wait specific owner task finished
{
CM_ASSERTMESSAGE("Fail to flush queue.");
return hr;
}
}
WaitForReferenceFree(); // wait all owner task finished
CM_HAL_3DRESOURCE_PARAM inParam;
CmSafeMemSet( &inParam, 0, sizeof( CM_HAL_3DRESOURCE_PARAM ) );
CmDeviceRT* device = nullptr;
m_surfaceMgr->GetCmDevice( device );
CM_ASSERT( device );
PCM_CONTEXT_DATA cmData = (PCM_CONTEXT_DATA)device->GetAccelData();
CMCHK_NULL_AND_RETURN(cmData);
CMCHK_NULL_AND_RETURN(cmData->cmHalState);
inParam.handle = m_handle;
inParam.data = (void*)sysMem; //Any non-nullptr value will work
inParam.width = m_width;
inParam.height = m_height;
inParam.depth = m_depth;
inParam.lockFlag = CM_HAL_LOCKFLAG_READONLY;
// Lock 3D 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->pfnLock3DResource(cmData->cmHalState, &inParam));
CMCHK_NULL(inParam.data);
uWidthInBytes = inParam.width * pixel;
//Copy Resource
tempDst = (uint8_t*)sysMem;
tempSrc = (uint8_t*)inParam.data;
rPlane = (uint8_t*)inParam.data;
// Only use Qpitch when Qpitch is supported by HW
if (inParam.qpitchEnabled)
{
if (inParam.pitch == uWidthInBytes && inParam.qpitch == inParam.height)
{
CmFastMemCopyFromWC(tempDst, tempSrc, (size_t)uSizeInBytes, GetCpuInstructionLevel());
}
else
{
for (uint32_t uZ = 0; uZ < inParam.depth; uZ++)
{
tempSrc = rPlane;
for (uint32_t uY = 0; uY < inParam.height; uY++)
{
CmFastMemCopyFromWC(tempDst, tempSrc, uWidthInBytes, GetCpuInstructionLevel());
tempSrc += inParam.pitch;
tempDst += uWidthInBytes;
}
rPlane += inParam.qpitch * inParam.pitch;
}
}
}
else
{
if (inParam.pitch == uWidthInBytes)
{
CmFastMemCopyFromWC(tempDst, tempSrc, (size_t)uSizeInBytes, GetCpuInstructionLevel());
}
else
{
for (uint32_t uZ = 0; uZ < inParam.depth; uZ++)
{
for (uint32_t uY = 0; uY < inParam.height; uY++)
{
CmFastMemCopyFromWC(tempDst, tempSrc, uWidthInBytes, GetCpuInstructionLevel());
tempSrc += inParam.pitch;
tempDst += uWidthInBytes;
}
}
}
}
// unlock 3D resource
CHK_MOSSTATUS_RETURN_CMERROR(cmData->cmHalState->pfnUnlock3DResource(cmData->cmHalState, &inParam));
finish:
if (hr < CM_MOS_STATUS_CONVERTED_CODE_OFFSET) {
hr = CM_LOCK_SURFACE_FAIL;
}
return hr;
}
CM_RT_API int32_t CmSurface3DRT::GetIndex( SurfaceIndex*& index )
{
index = m_index;
return CM_SUCCESS;
}
//*-----------------------------------------------------------------------------
//| Purpose: Get Properties of CmSurface3DRT
//| Returns: CM_SUCCESS.
//*-----------------------------------------------------------------------------
int32_t CmSurface3DRT::GetProperties( uint32_t& width, uint32_t& height, uint32_t& depth, CM_SURFACE_FORMAT& format)
{
width = m_width;
height = m_height;
depth = m_depth;
format = m_format;
return CM_SUCCESS;
}
int32_t CmSurface3DRT::SetProperties( uint32_t width, uint32_t height, uint32_t depth, CM_SURFACE_FORMAT format)
{
m_width = width;
m_height = height;
m_depth = depth;
m_format = format;
return CM_SUCCESS;
}
CM_RT_API int32_t CmSurface3DRT::InitSurface(const uint32_t initValue, CmEvent* event)
{
CM_RETURN_CODE hr = CM_SUCCESS;
uint32_t uSizeInBytes = 0;
uint32_t uWidthInBytes = 0;
uint8_t *tempDst = nullptr;
uint8_t *rPlane = nullptr;
// It makes sense to flush the whole enqueued tasks for each surface read
// because usually we read the output of the last task.
// Update: using event not to flush the whole enqueued tasks
if( event )
{
CmEventRT *eventRT = static_cast<CmEventRT *>(event);
FlushDeviceQueue( eventRT ); // wait specific owner task finished
}
WaitForReferenceFree(); // wait all owner task finished
CM_HAL_3DRESOURCE_PARAM inParam;
CmSafeMemSet( &inParam, 0, sizeof( CM_HAL_3DRESOURCE_PARAM ) );
CmDeviceRT* device = nullptr;
m_surfaceMgr->GetCmDevice( device );
CM_ASSERT( device );
PCM_CONTEXT_DATA cmData = (PCM_CONTEXT_DATA)device->GetAccelData();
CMCHK_NULL_AND_RETURN(cmData);
CMCHK_NULL_AND_RETURN(cmData->cmHalState);
uint32_t sizePerPixel = 0;
uint32_t updatedHeight = 0;
CMCHK_HR(m_surfaceMgr->GetPixelBytesAndHeight(m_width, m_height, m_format, sizePerPixel, updatedHeight));
inParam.handle = m_handle;
inParam.data = (void*)0x44; //Any non-nullptr value will work
inParam.width = m_width;
inParam.height = m_height;
inParam.depth = m_depth;
inParam.lockFlag = CM_HAL_LOCKFLAG_WRITEONLY;
CHK_MOSSTATUS_RETURN_CMERROR(cmData->cmHalState->pfnLock3DResource(cmData->cmHalState, &inParam));
CMCHK_NULL(inParam.data);
uSizeInBytes = inParam.width * inParam.height * inParam.depth * sizePerPixel;
uWidthInBytes = inParam.width * sizePerPixel;
//Copy Resource
tempDst = (uint8_t*)inParam.data;
rPlane = (uint8_t*)inParam.data;
// Only use Qpitch when Qpitch is supported by HW
if (inParam.qpitchEnabled)
{
if (inParam.pitch == uWidthInBytes && inParam.qpitch == inParam.height)
{
CmDwordMemSet(tempDst, initValue, uSizeInBytes);
}
else
{
for (uint32_t uZ = 0; uZ < inParam.depth; uZ++)
{
tempDst = rPlane;
for (uint32_t uY = 0; uY < inParam.height; uY++)
{
CmDwordMemSet(tempDst, initValue, uWidthInBytes);
tempDst += inParam.pitch;
}
rPlane += inParam.qpitch * inParam.pitch;
}
}
}
else
{
if (inParam.pitch == uWidthInBytes)
{
CmDwordMemSet(tempDst, initValue, uSizeInBytes);
}
else
{
for (uint32_t uZ = 0; uZ < inParam.depth; uZ++)
{
for (uint32_t uY = 0; uY < inParam.height; uY++)
{
CmDwordMemSet(tempDst, initValue, uWidthInBytes);
tempDst += inParam.pitch;
}
}
}
}
// unlock
inParam.data = nullptr;
inParam.handle = m_handle;
CHK_MOSSTATUS_RETURN_CMERROR(cmData->cmHalState->pfnUnlock3DResource(cmData->cmHalState, &inParam));
finish:
if (hr < CM_MOS_STATUS_CONVERTED_CODE_OFFSET) {
hr = CM_LOCK_SURFACE_FAIL;
}
return hr;
}
int32_t CmSurface3DRT::SetMemoryObjectControl( MEMORY_OBJECT_CONTROL memCtrl, MEMORY_TYPE memType, uint32_t age)
{
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_3D));
finish:
return hr;
}
CM_RT_API int32_t CmSurface3DRT::SelectMemoryObjectControlSetting(MEMORY_OBJECT_CONTROL memCtrl)
{
return SetMemoryObjectControl(memCtrl, CM_USE_PTE, 0);
}
void CmSurface3DRT::Log(std::ostringstream &oss)
{
#if CM_LOG_ON
oss << " Surface3D Info "
<< " Width:" << m_width
<< " Height:" << m_height
<< " Depth:" << m_depth
<< " Format:" << GetFormatString(m_format)
<< " Handle:" << m_handle
<< " SurfaceIndex:" << m_index->get_data()
<< " IsCmCreated:" << m_isCmCreated
<< std::endl;
#endif
}
void CmSurface3DRT::DumpContent(uint32_t kernelNumber, char *kernelName, int32_t taskId, uint32_t argIndex)
{
#if MDF_SURFACE_CONTENT_DUMP
std::ostringstream outputFileName;
static uint32_t surface3DDumpNumber = 0;
outputFileName << "t_" << taskId
<< "_k_" << kernelNumber
<< "_" << kernelName
<< "_argi_" << argIndex
<< "_surf2d_surfi_" << m_index->get_data()
<< "_w_" << m_width
<< "_h_" << m_height
<< "_d_" << m_depth
<< "_f_" << GetFormatString(m_format)
<< "_" << surface3DDumpNumber;
std::ofstream outputFileStream;
outputFileStream.open(outputFileName.str().c_str(), std::ofstream::binary);
uint32_t surfaceSize = 0;
uint32_t sizePerPixel = 0;
uint32_t updatedHeight = 0;
uint32_t uWidthInBytes = 0;
uint8_t *tempDst = nullptr;
uint8_t *tempSrc = nullptr;
uint8_t *rPlane = nullptr;
m_surfaceMgr->GetPixelBytesAndHeight(m_width, m_height, m_format, sizePerPixel, updatedHeight);
surfaceSize = m_width * updatedHeight * m_depth * sizePerPixel;
uWidthInBytes = m_width * sizePerPixel;
std::vector<char>surface(surfaceSize);
CM_HAL_3DRESOURCE_PARAM inParam;
CmSafeMemSet(&inParam, 0, sizeof(CM_HAL_3DRESOURCE_PARAM));
CmDeviceRT* device = nullptr;
m_surfaceMgr->GetCmDevice(device);
CM_ASSERT(device);
PCM_CONTEXT_DATA cmData = (PCM_CONTEXT_DATA)device->GetAccelData();
CM_ASSERT(cmData);
CM_ASSERT(cmData->cmHalState);
inParam.handle = m_handle;
inParam.data = (void*)&surface[0];
inParam.width = m_width;
inParam.height = m_height;
inParam.depth = m_depth;
inParam.lockFlag = CM_HAL_LOCKFLAG_READONLY;
cmData->cmHalState->pfnLock3DResource(cmData->cmHalState, &inParam);
if (inParam.data == nullptr)
return;
tempDst = (uint8_t*)&surface[0];
tempSrc = (uint8_t*)inParam.data;
rPlane = (uint8_t*)inParam.data;
if (inParam.qpitchEnabled)
{
if (inParam.pitch == uWidthInBytes && inParam.qpitch == inParam.height)
{
CmFastMemCopyFromWC(tempDst, tempSrc, (size_t)surfaceSize, GetCpuInstructionLevel());
}
else
{
for (uint32_t uZ = 0; uZ < inParam.depth; uZ++)
{
tempSrc = rPlane;
for (uint32_t uY = 0; uY < inParam.height; uY++)
{
CmFastMemCopyFromWC(tempDst, tempSrc, uWidthInBytes, GetCpuInstructionLevel());
tempSrc += inParam.pitch;
tempDst += uWidthInBytes;
}
rPlane += inParam.qpitch * inParam.pitch;
}
}
}
else
{
if (inParam.pitch == uWidthInBytes)
{
CmFastMemCopyFromWC(tempDst, tempSrc, (size_t)surfaceSize, GetCpuInstructionLevel());
}
else
{
for (uint32_t uZ = 0; uZ < inParam.depth; uZ++)
{
for (uint32_t uY = 0; uY < inParam.height; uY++)
{
CmFastMemCopyFromWC(tempDst, tempSrc, uWidthInBytes, GetCpuInstructionLevel());
tempSrc += inParam.pitch;
tempDst += uWidthInBytes;
}
}
}
}
cmData->cmHalState->pfnUnlock3DResource(cmData->cmHalState, &inParam);
outputFileStream.write(&surface[0], surfaceSize);
outputFileStream.close();
surface3DDumpNumber++;
#endif
}
}