blob: e668d8388b045824675b9c06ec84cbdf33f9ee4d [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_task_rt.cpp
//! \brief Contains OS-agnostic CmTaskRT member functions.
//!
#include "cm_task_rt.h"
#include "cm_kernel_rt.h"
#include "cm_mem.h"
#include "cm_thread_space_rt.h"
#include "cm_device_rt.h"
#include "cm_surface_manager.h"
#include "cm_buffer_rt.h"
namespace CMRT_UMD
{
//*-----------------------------------------------------------------------------
//| Purpose: Create CmTask
//| Returns: Result of the operation.
//*-----------------------------------------------------------------------------
int32_t CmTaskRT::Create(CmDeviceRT *device,
uint32_t index,
uint32_t maxKernelCount,
CmTaskRT* &kernelArray)
{
int32_t result = CM_SUCCESS;
kernelArray = new (std::nothrow) CmTaskRT( device, index, maxKernelCount );
if( kernelArray )
{
device->m_memObjectCount.taskCount++;
result = kernelArray->Initialize();
if( result != CM_SUCCESS )
{
CmTaskRT::Destroy( kernelArray);
}
}
else
{
CM_ASSERTMESSAGE("Error: Failed to create CmTask due to out of system memory.");
result = CM_OUT_OF_HOST_MEMORY;
}
return result;
}
//*-----------------------------------------------------------------------------
//| Purpose: Destroy CmTask
//| Returns: Result of the operation.
//*-----------------------------------------------------------------------------
int32_t CmTaskRT::Destroy( CmTaskRT* &kernelArray )
{
if( kernelArray )
{
kernelArray->m_device->m_memObjectCount.taskCount--;
delete kernelArray;
kernelArray = nullptr;
}
return CM_SUCCESS;
}
//*-----------------------------------------------------------------------------
//| Purpose: Constructor of CmTask
//| Returns: Result of the operation.
//*-----------------------------------------------------------------------------
CmTaskRT::CmTaskRT(CmDeviceRT *device,
uint32_t index,
uint32_t maxKernelCount):
m_kernelArray( nullptr ),
m_device( device ),
m_kernelCount(0),
m_maxKernelCount( maxKernelCount ),
m_indexTaskArray(index),
m_syncBitmap( 0 ),
m_conditionalEndBitmap( 0 )
{
CmSafeMemSet( &m_powerOption, 0, sizeof( m_powerOption ) );
CmSafeMemSet(&m_conditionalEndInfo, 0, sizeof(m_conditionalEndInfo));
CmSafeMemSet(&m_taskConfig, 0, sizeof(m_taskConfig));
m_taskConfig.turboBoostFlag = CM_TURBO_BOOST_DEFAULT;
PCM_HAL_STATE cmHalState = ((PCM_CONTEXT_DATA)m_device->GetAccelData())->cmHalState;
cmHalState->cmHalInterface->InitTaskProperty(m_taskConfig);
}
//*-----------------------------------------------------------------------------
//| Purpose: Destructor of CmTask
//| Returns: Result of the operation.
//*-----------------------------------------------------------------------------
CmTaskRT::~CmTaskRT( void )
{
MosSafeDeleteArray(m_kernelArray );
}
//*-----------------------------------------------------------------------------
//| Purpose: Initialize CmTask
//| Returns: Result of the operation.
//*-----------------------------------------------------------------------------
int32_t CmTaskRT::Initialize( )
{
m_kernelArray = MOS_NewArray(CmKernelRT*, m_maxKernelCount);
if(m_kernelArray)
{
CmSafeMemSet( m_kernelArray, 0, sizeof(CmKernelRT*) * m_maxKernelCount );
return CM_SUCCESS;
}
else
{
CM_ASSERTMESSAGE("Error: Failed to initialize CmTask due to out of system memory.");
return CM_OUT_OF_HOST_MEMORY;
}
}
//*-----------------------------------------------------------------------------
//| Purpose: Common implementation of Add Kernel to task
//| Returns: Result of the operation.
//*-----------------------------------------------------------------------------
int32_t CmTaskRT::AddKernelInternal( CmKernel *kernel, const CM_EXECUTION_CONFIG *config)
{
// already reached max kernel count
if(m_maxKernelCount <= m_kernelCount)
{
return CM_EXCEED_MAX_KERNEL_PER_ENQUEUE;
}
// passed in nullptr pointer
if(kernel == nullptr)
{
CM_ASSERTMESSAGE("Error: Pointer to kernel is null.");
return CM_INVALID_ARG_VALUE;
}
CmKernelRT *kernelRT = static_cast<CmKernelRT *>(kernel);
m_kernelArray[m_kernelCount] = kernelRT;
kernelRT->SetIndexInTask(m_kernelCount);
if(config)
{
m_kernelExecuteConfig[m_kernelCount] = *config;
}
else
{
MOS_ZeroMemory(&m_kernelExecuteConfig[m_kernelCount], sizeof(CM_EXECUTION_CONFIG));
}
m_kernelCount++;
#if USE_EXTENSION_CODE
AddKernelForGTPin(kernel);
#endif
return CM_SUCCESS;
}
//*-----------------------------------------------------------------------------
//| Purpose: Add Kernel to task
//| Returns: Result of the operation.
//*-----------------------------------------------------------------------------
CM_RT_API int32_t CmTaskRT::AddKernel( CmKernel *kernel )
{
INSERT_API_CALL_LOG(GetHalState());
return AddKernelInternal(kernel, nullptr);
}
//*-----------------------------------------------------------------------------
//| Purpose: Add Kernel to task with execution configure
//| Returns: Result of the operation.
//*-----------------------------------------------------------------------------
CM_RT_API int32_t CmTaskRT::AddKernelWithConfig( CmKernel *kernel,
const CM_EXECUTION_CONFIG *config )
{
INSERT_API_CALL_LOG(GetHalState());
return AddKernelInternal(kernel, config);
}
//*-----------------------------------------------------------------------------
//| Purpose: Reset task and clear all the kernel
//| Returns: Result of the operation.
//*-----------------------------------------------------------------------------
CM_RT_API int32_t CmTaskRT::Reset()
{
INSERT_API_CALL_LOG(GetHalState());
m_kernelCount = 0;
m_syncBitmap = 0;
m_conditionalEndBitmap = 0;
CmSafeMemSet(&m_conditionalEndInfo, 0, sizeof(m_conditionalEndInfo));
CmSafeMemSet(&m_taskConfig, 0, sizeof(m_taskConfig));
m_taskConfig.turboBoostFlag = CM_TURBO_BOOST_DEFAULT;
CM_CHK_NULL_RETURN_CMERROR(m_device);
CM_CHK_NULL_RETURN_CMERROR(m_device->GetAccelData());
PCM_HAL_STATE cmHalState = ((PCM_CONTEXT_DATA)m_device->GetAccelData())->cmHalState;
CM_CHK_NULL_RETURN_CMERROR(cmHalState);
CM_CHK_NULL_RETURN_CMERROR(cmHalState->cmHalInterface);
cmHalState->cmHalInterface->InitTaskProperty(m_taskConfig);
if(m_kernelArray)
{
CmSafeMemSet( m_kernelArray, 0, sizeof(CmKernelRT*) * m_maxKernelCount );
return CM_SUCCESS;
}
else
{
CM_ASSERTMESSAGE("Error: Pointer to kernel array is null.");
return CM_NULL_POINTER;
}
}
//*-----------------------------------------------------------------------------
//| Purpose: Get the kernel count
//| Returns: The count of kernels
//*-----------------------------------------------------------------------------
uint32_t CmTaskRT::GetKernelCount()
{
return m_kernelCount;
}
//*-----------------------------------------------------------------------------
//| Purpose: Get the kernel pointer by its index
//| Returns: Result of the operation.
//*-----------------------------------------------------------------------------
CmKernelRT* CmTaskRT::GetKernelPointer(uint32_t index)
{
if(index >= m_kernelCount)
{
CM_ASSERTMESSAGE("Error: The kernel index exceeds the kernel count.");
return nullptr;
}
return m_kernelArray[index];
}
uint32_t CmTaskRT::GetIndexInTaskArray()
{
return m_indexTaskArray;
}
//*-----------------------------------------------------------------------------
//| Purpose: Check the integrity of kernel threadspaces within a task
//| Returns: True if all kernel threadspaces are valid, False otherwise
//*-----------------------------------------------------------------------------
bool CmTaskRT::IntegrityCheckKernelThreadspace( void )
{
int32_t hr = CM_SUCCESS;
uint32_t kernelCount = 0;
uint32_t i = 0;
uint32_t j = 0;
CmKernelRT* kernelRT = nullptr;
CmKernelRT* kernelTmp = nullptr;
uint32_t threadCount = 0;
CmThreadSpaceRT* kernelThreadSpace = nullptr;
uint32_t width = 0;
uint32_t height = 0;
byte** threadSpaceMapping = nullptr;
byte* kernelInScoreboard = nullptr;
CM_THREAD_SPACE_UNIT* threadSpaceUnit = nullptr;
uint32_t kernelIndex = 0;
uint32_t unassociated = 0;
kernelCount = this->GetKernelCount();
threadSpaceMapping = MOS_NewArray(byte*, kernelCount);
kernelInScoreboard = MOS_NewArray(byte, kernelCount);
CM_CHK_NULL_GOTOFINISH(threadSpaceMapping, CM_OUT_OF_HOST_MEMORY);
CM_CHK_NULL_GOTOFINISH(kernelInScoreboard, CM_OUT_OF_HOST_MEMORY);
CmSafeMemSet(threadSpaceMapping, 0, kernelCount*sizeof(byte *));
CmSafeMemSet(kernelInScoreboard, 0, kernelCount*sizeof(byte));
for( i = 0; i < kernelCount; ++i )
{
kernelRT = this->GetKernelPointer(i);
CM_CHK_NULL_GOTOFINISH_CMERROR(kernelRT);
CM_CHK_CMSTATUS_GOTOFINISH(kernelRT->GetThreadSpace(kernelThreadSpace));
CM_CHK_NULL_GOTOFINISH(kernelThreadSpace, CM_KERNEL_THREADSPACE_NOT_SET);
CM_CHK_CMSTATUS_GOTOFINISH(kernelThreadSpace->GetThreadSpaceSize(width, height));
CM_CHK_CMSTATUS_GOTOFINISH(kernelRT->GetThreadCount(threadCount));
if (threadCount == 0)
{
threadCount = width * height;
}
if( kernelThreadSpace->IsThreadAssociated() )
{
threadSpaceMapping[i] = MOS_NewArray(byte, threadCount);
CM_CHK_NULL_GOTOFINISH(threadSpaceMapping[i], CM_OUT_OF_HOST_MEMORY);
CmSafeMemSet(threadSpaceMapping[i], 0, threadCount * sizeof(byte));
kernelInScoreboard[i] = false;
hr = kernelThreadSpace->GetThreadSpaceUnit(threadSpaceUnit);
if( hr != CM_SUCCESS || threadSpaceUnit == nullptr )
{
CM_ASSERTMESSAGE("Error: Invalid thread space unit");
MosSafeDeleteArray(threadSpaceMapping[i]);
hr = CM_FAILURE;
goto finish;
}
for( j = 0; j < width * height; ++j )
{
kernelTmp = static_cast<CmKernelRT*>(threadSpaceUnit[j].kernel);
if( kernelTmp == nullptr )
{
if (kernelThreadSpace->GetNeedSetKernelPointer())
{
kernelTmp = kernelThreadSpace->GetKernelPointer();
}
if (kernelTmp == nullptr)
{
CM_ASSERTMESSAGE("Error: Invalid kernel pointer.");
MosSafeDeleteArray(threadSpaceMapping[i]);
hr = CM_FAILURE;
goto finish;
}
}
kernelIndex = kernelTmp->GetIndexInTask();
threadSpaceMapping[kernelIndex][threadSpaceUnit[j].threadId] = 1;
kernelInScoreboard[kernelIndex] = 1;
}
if( kernelInScoreboard[i] )
{
kernelRT->SetAssociatedToTSFlag(true);
for( j = 0; j < threadCount; ++j )
{
if( threadSpaceMapping[i][j] == 0 )
{
unassociated++;
break;
}
}
}
MosSafeDeleteArray(threadSpaceMapping[i]);
}
if( unassociated != 0 )
{
CM_ASSERTMESSAGE("Error: kernel threadspace is not associated.");
hr = CM_KERNEL_THREADSPACE_THREADS_NOT_ASSOCIATED;
goto finish;
}
}
finish:
MosSafeDeleteArray(threadSpaceMapping);
MosSafeDeleteArray(kernelInScoreboard);
return (hr == CM_SUCCESS)? true: false;
}
//*-----------------------------------------------------------------------------
//| Purpose: Insert synchronization point before next kernel
//| Returns: Result of the operation.
//*-----------------------------------------------------------------------------
CM_RT_API int32_t CmTaskRT::AddSync()
{
INSERT_API_CALL_LOG(GetHalState());
if (m_kernelCount > 0)
{
m_syncBitmap |= (uint64_t)1 << (m_kernelCount - 1);
}
return CM_SUCCESS;
}
uint64_t CmTaskRT::GetSyncBitmap()
{
return m_syncBitmap;
}
//*-----------------------------------------------------------------------------
//| Purpose: Set the conditional value, compare mask and handle for the
//| surface associated with index
//| Returns: Result of the operation.
//*-----------------------------------------------------------------------------
int32_t CmTaskRT::SetConditionalEndInfo(SurfaceIndex* index,
uint32_t offset,
CM_CONDITIONAL_END_PARAM *conditionalParam)
{
CmSurface* surface = nullptr;
CmSurfaceManager* surfaceMgr = nullptr;
uint32_t surfIndex = 0;
m_device->GetSurfaceManager(surfaceMgr);
if (!surfaceMgr)
{
CM_ASSERTMESSAGE("Error: Pointer to surface manager is null.");
return CM_NULL_POINTER;
}
surfIndex = index->get_data();
surfaceMgr->GetSurface(surfIndex, surface);
if (!surface)
{
CM_ASSERTMESSAGE("Error: Pointer to surface is null.");
return CM_NULL_POINTER;
}
if (surface->Type() == CM_ENUM_CLASS_TYPE_CMBUFFER_RT)
{
uint32_t handle = 0;
CmBuffer_RT* surf1D = static_cast<CmBuffer_RT*> (surface);
surf1D->GetHandle(handle);
m_conditionalEndInfo[m_kernelCount].compareValue = conditionalParam->opValue;
m_conditionalEndInfo[m_kernelCount].bufferTableIndex = handle;
m_conditionalEndInfo[m_kernelCount].disableCompareMask = !conditionalParam->opMask;
m_conditionalEndInfo[m_kernelCount].endCurrentLevel = conditionalParam->opLevel;
m_conditionalEndInfo[m_kernelCount].operatorCode = conditionalParam->opCode;
m_conditionalEndInfo[m_kernelCount].offset = offset;
}
else
{
return CM_NOT_IMPLEMENTED;
}
return CM_SUCCESS;
}
uint64_t CmTaskRT::GetConditionalEndBitmap()
{
return m_conditionalEndBitmap;
}
CM_HAL_CONDITIONAL_BB_END_INFO* CmTaskRT::GetConditionalEndInfo()
{
return m_conditionalEndInfo;
}
PCM_POWER_OPTION CmTaskRT::GetPowerOption()
{
return &m_powerOption;
}
#if CM_LOG_ON
std::string CmTaskRT::Log()
{
std::ostringstream oss;
oss << " Kernel Count:" << m_kernelCount
<< " Sync Bit:"<<m_syncBitmap
<< " Conditional End Bit: " << m_conditionalEndBitmap
<< std::endl;
for (uint32_t i=0 ; i< m_kernelCount; i++)
{
CmKernelRT* kernel = (CmKernelRT*)m_kernelArray[i];
oss << kernel->Log(); // log each kernel
}
return oss.str();
}
CM_HAL_STATE* CmTaskRT::GetHalState() { return m_device->GetHalState(); }
#endif // #if CM_LOG_ON
CM_RT_API int32_t CmTaskRT::SetProperty(const CM_TASK_CONFIG &taskConfig)
{
m_taskConfig = taskConfig;
return CM_SUCCESS;
}
CM_RT_API int32_t CmTaskRT::GetProperty(CM_TASK_CONFIG &taskConfig)
{
taskConfig = m_taskConfig;
return CM_SUCCESS;
}
CM_RT_API int32_t
CmTaskRT::AddConditionalEnd(SurfaceIndex* conditionalSurfaceIndex,
uint32_t offset,
CM_CONDITIONAL_END_PARAM *conditionalParam)
{
INSERT_API_CALL_LOG(GetHalState());
int32_t hr = CM_SUCCESS;
m_conditionalEndBitmap |= (uint64_t)1 << m_kernelCount;
hr = SetConditionalEndInfo(conditionalSurfaceIndex, offset, conditionalParam);
return hr;
}
} // namespace CMRT_UMD