/* * 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 ) { INSERT_API_CALL_LOG(nullptr); 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(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(); CM_CHK_NULL_RETURN_CMERROR(cmData); CM_CHK_NULL_RETURN_CMERROR(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 CM_CHK_MOSSTATUS_GOTOFINISH_CMERROR(cmData->cmHalState->pfnLock3DResource(cmData->cmHalState, &inParam)); CM_CHK_NULL_GOTOFINISH_CMERROR(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 CM_CHK_MOSSTATUS_GOTOFINISH_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 ) { INSERT_API_CALL_LOG(nullptr); 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(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(); CM_CHK_NULL_RETURN_CMERROR(cmData); CM_CHK_NULL_RETURN_CMERROR(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 CM_CHK_MOSSTATUS_GOTOFINISH_CMERROR(cmData->cmHalState->pfnLock3DResource(cmData->cmHalState, &inParam)); CM_CHK_NULL_GOTOFINISH_CMERROR(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 CM_CHK_MOSSTATUS_GOTOFINISH_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) { INSERT_API_CALL_LOG(nullptr); 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(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(); CM_CHK_NULL_RETURN_CMERROR(cmData); CM_CHK_NULL_RETURN_CMERROR(cmData->cmHalState); uint32_t sizePerPixel = 0; uint32_t updatedHeight = 0; CM_CHK_CMSTATUS_GOTOFINISH(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; CM_CHK_MOSSTATUS_GOTOFINISH_CMERROR(cmData->cmHalState->pfnLock3DResource(cmData->cmHalState, &inParam)); CM_CHK_NULL_GOTOFINISH_CMERROR(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; CM_CHK_MOSSTATUS_GOTOFINISH_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); CM_CHK_NULL_RETURN_CMERROR(cmDevice); PCM_CONTEXT_DATA cmData = (PCM_CONTEXT_DATA)cmDevice->GetAccelData(); CM_CHK_NULL_RETURN_CMERROR(cmData); CM_CHK_NULL_RETURN_CMERROR(cmData->cmHalState); mocs = (m_memObjCtrl.mem_ctrl << 8) | (m_memObjCtrl.mem_type<<4) | m_memObjCtrl.age; CM_CHK_MOSSTATUS_GOTOFINISH_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); } CMRT_UMD_API int32_t CmSurface3DRT::SetResourceUsage(const MOS_HW_RESOURCE_DEF mosUsage) { int32_t hr = CM_SUCCESS; uint16_t mocs = 0; hr = CmSurface::SetResourceUsage(mosUsage); CmDeviceRT *cmDevice = nullptr; m_surfaceMgr->GetCmDevice(cmDevice); CM_CHK_NULL_RETURN_CMERROR(cmDevice); PCM_CONTEXT_DATA cmData = (PCM_CONTEXT_DATA)cmDevice->GetAccelData(); CM_CHK_NULL_RETURN_CMERROR(cmData); CM_CHK_NULL_RETURN_CMERROR(cmData->cmHalState); mocs = (m_memObjCtrl.mem_ctrl << 8) | (m_memObjCtrl.mem_type << 4) | m_memObjCtrl.age; CM_CHK_MOSSTATUS_GOTOFINISH_CMERROR(cmData->cmHalState->pfnSetSurfaceMOCS(cmData->cmHalState, m_handle, mocs, ARG_KIND_SURFACE_3D)); finish: return hr; } 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, uint32_t vectorIndex) { #if MDF_SURFACE_CONTENT_DUMP std::ostringstream outputFileName; static uint32_t surface3DDumpNumber = 0; char fileNamePrefix[MAX_PATH] = { 0 }; std::ofstream outputFileStream; outputFileName << "t_" << taskId << "_k_" << kernelNumber << "_" << kernelName << "_argi_" << argIndex << "_vector_index_" << vectorIndex << "_surf2d_surfi_" << m_index->get_data() << "_w_" << m_width << "_h_" << m_height << "_d_" << m_depth << "_f_" << GetFormatString(m_format) << "_" << surface3DDumpNumber; GetLogFileLocation(outputFileName.str().c_str(), fileNamePrefix, GetMosContext()); // Open file outputFileStream.open(fileNamePrefix, std::ios::app | std::ios::binary); CM_ASSERT(outputFileStream); 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::vectorsurface(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 } }