blob: 4248d304ed5cc7738fcec613bed69620bc62a927 [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.
*/
#include "cm_device.h"
#include <dlfcn.h>
#include <cstdio>
#include "cm_mem.h"
#include "cm_surface_manager.h"
#include "cm_queue.h"
#include "cm_timer.h"
#include "cm_debug.h"
#include "cm_extension_creator.h"
#if USE_EXTENSION_CODE
#include "cm_gtpin_external_interface.h"
#endif
#include <unistd.h>
#include <fcntl.h>
#ifndef ANDROID
uint32_t CmDevice_RT::m_vaReferenceCount = 0;
CSync CmDevice_RT::m_vaReferenceCountCriticalSection;
void *CmDevice_RT::m_vaDrm = nullptr;
pfVAGetDisplayDRM CmDevice_RT::m_vaGetDisplayDrm = nullptr;
#endif
// current binary version, query by command "strings",
// e.g. "strings -a igfxcmrt64.so | grep current_version "
volatile static char cmrtCurrentVersion[] = "cmrt_current_version: " \
"6.0.0.9010\0";
CSync gDeviceCreationCriticalSection;
int32_t CmDevice_RT::Create( CmDevice_RT* &device, uint32_t createOption )
{
INSERT_PROFILER_RECORD();
int32_t result = CM_SUCCESS;
device = new CmDevice_RT(nullptr, createOption);
if( device )
{
result = device->Initialize(true);
if( result != CM_SUCCESS )
{
CmAssert(0);
Destroy(device);
}
}
else
{
CmAssert( 0 );
result = CM_OUT_OF_HOST_MEMORY;
}
return result;
}
int32_t CmDevice_RT::Create(VADisplay &vaDisplay , CmDevice_RT* &device, uint32_t createOption )
{
INSERT_PROFILER_RECORD();
int32_t result = CM_FAILURE;
device = new (std::nothrow) CmDevice_RT(vaDisplay, createOption);
if( device )
{
result = device->Initialize(false);
if( result != CM_SUCCESS )
{
Destroy( device );
}
}
else
{
CmAssert( 0 );
result = CM_OUT_OF_HOST_MEMORY;
}
// leave critical section
return result;
}
int32_t CmDevice_RT::Destroy( CmDevice_RT* &device )
{
if(device == nullptr)
{
return CM_FAILURE;
}
// Destroy the cm device object
device->FreeResources();
//Destroy the Device at CMRT@UMD
CM_DESTROYCMDEVICE_PARAM destroyCmDeviceParam;
CmSafeMemSet(&destroyCmDeviceParam, 0, sizeof(CM_DESTROYCMDEVICE_PARAM));
destroyCmDeviceParam.cmDeviceHandle = device->m_deviceInUmd;
uint32_t inputDataLen = sizeof(CM_DESTROYCMDEVICE_PARAM);
int32_t result = device->OSALExtensionExecute(CM_FN_DESTROYCMDEVICE,
&destroyCmDeviceParam,
inputDataLen);
CmSafeRelease( device );
CHK_FAILURE_RETURN(result);
// leave critical section
return destroyCmDeviceParam.returnValue;
}
CmDevice_RT::CmDevice_RT(
VADisplay vaDisplay,
uint32_t createOption
):
m_cmVersion(0),
m_deviceInUmd(nullptr),
m_cmCreated ( true ),
m_vaDisplay (vaDisplay),
#ifdef ANDROID
m_display (nullptr),
#endif
m_fvaCmExtSendReqMsg (nullptr),
m_gtpinEnabled( false ),
m_gtpinBufferUP0( nullptr ),
m_gtpinBufferUP1( nullptr ),
m_gtpinBufferUP2( nullptr ),
m_printBuffer( nullptr ),
m_printEnabled ( false),
m_printBufferSize( 0),
m_createOption(createOption),
m_driverStoreEnabled(0)
{
// New Surface Manager
m_surfaceManager = new CmSurfaceManager(this);
// New Kernel Debugger
m_kernelDebugger = CmExtensionCreator<CmKernelDebugger>::CreateClass();
//Initialize L3 cache config
CmSafeMemSet(&m_l3Config, 0, sizeof(L3ConfigRegisterValues));
}
CmDevice_RT::~CmDevice_RT( void )
{
if (m_cmCreated)
{
vaTerminate(m_vaDisplay);
#ifndef ANDROID
FreeLibvaDrm();
#else
free(m_display); //Android
#endif
}
if (m_kernelDebugger != nullptr)
{
delete m_kernelDebugger;
}
}
int32_t CmDevice_RT::FreeResources()
{
//Destroy Queue
m_criticalSectionQueue.Acquire();
for (auto iter = m_queue.begin(); iter != m_queue.end();)
{
if (*iter != nullptr)
{
CmQueue_RT::Destroy(*iter);
}
iter = m_queue.erase(iter);
}
m_criticalSectionQueue.Release();
//Destroy GTPin Used BufferUp
if( m_gtpinBufferUP0 != nullptr)
{
DestroyBufferUP(m_gtpinBufferUP0);
}
if( m_gtpinBufferUP1 != nullptr)
{
DestroyBufferUP(m_gtpinBufferUP1);
}
if( m_gtpinBufferUP2 != nullptr)
{
DestroyBufferUP(m_gtpinBufferUP2);
}
CmSafeRelease(m_surfaceManager);
return CM_SUCCESS;
}
static int32_t CmrtVaSurfaceRelease(void *vaDisplay, void *vaSurface)
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
VADisplay *display = (VADisplay *)(vaDisplay);
//Destroy VaSurface
vaStatus = vaDestroySurfaces(*display, (VASurfaceID *)vaSurface, 1);
return vaStatus;
}
int32_t CmDevice_RT::Initialize( bool isCmCreated )
{
int32_t result = CM_SUCCESS;
m_cmCreated = isCmCreated;
CLock locker(gDeviceCreationCriticalSection);
CHK_RET(InitializeLibvaDisplay());
CHK_RET(CreateDeviceInUmd());
CHK_RET(CheckDdiVersionSupported(m_cmVersion));
#if USE_EXTENSION_CODE
if(GTpinVariables.GTPinEnabled)
{
CHK_RET(EnableGtpin());
CHK_RET(RegisterGtpinMarkerFunctions());
}
#endif
if (m_kernelDebugger != nullptr)
{
m_kernelDebugger->NotifyNewDevice(this, m_deviceInUmd, m_driverStoreEnabled);
}
finish:
return result;
}
int32_t CmDevice_RT::CreateDeviceInUmd()
{
CmDeviceCreationParam createCmDeviceParam;
CmSafeMemSet(&createCmDeviceParam, 0, sizeof(createCmDeviceParam));
createCmDeviceParam.returnValue = CM_FAILURE;
createCmDeviceParam.createOption = m_createOption;
createCmDeviceParam.releaseSurfaceFunc = &CmrtVaSurfaceRelease;
uint32_t inputDataLen = sizeof(createCmDeviceParam);
int32_t result = OSALExtensionExecute(CM_FN_CREATECMDEVICE,
&createCmDeviceParam, inputDataLen);
CHK_FAILURE_RETURN(result);
CHK_FAILURE_RETURN(createCmDeviceParam.returnValue);
m_cmVersion = createCmDeviceParam.version;
m_deviceInUmd = createCmDeviceParam.deviceHandleInUmd;
m_driverStoreEnabled = createCmDeviceParam.driverStoreEnabled;
return CM_SUCCESS;
}
//!
//! Create Libva Surface and wrap it as a CmSurface
//! It is CALLER's responsibility to allocation memory for all pointers to CmSurface2D
//! Input :
//! 1) Surface's width [in]
//! 2) Surface's height [in]
//! 3) Surface's format [in]
//! 4) Reference to created VASurfaceID [out]
//! 5) Reference to pointer of created Cm Surface [out]
//! Output:
//! CM_SUCCESS if all CmSurface2D are successfully created;
//! CM_VA_SURFACE_NOT_SUPPORTED if libva surface creation fail;
//! CM_FAILURE otherwise;
CM_RT_API int32_t CmDevice_RT::CreateVaSurface2D( uint32_t width, uint32_t height, CM_SURFACE_FORMAT format, VASurfaceID &vaSurface, CmSurface2D* &surface)
{
INSERT_PROFILER_RECORD();
return m_surfaceManager->CreateVaSurface2D(width, height, format, vaSurface, surface);
}
//!
//!
//! Create a CmSurface2D from an existing LIBVA surface
//! Input :
//! Reference to the pointer to the CmSurface2D .
//! VASurfaceID
//! Output:
//! CM_SUCCESS if the CmSurface2D are successfully created;
//! CM_OUT_OF_HOST_MEMORY if out of system memory;
//! CM_FAILURE otherwise;
//!
CM_RT_API int32_t CmDevice_RT::CreateSurface2D( VASurfaceID vaSurface, CmSurface2D* &surface )
{
INSERT_PROFILER_RECORD();
return m_surfaceManager->CreateSurface2D(vaSurface, surface);
}
//!
//! Create an array of CmSurface2D from an existing array of LIBVA surfaces, which are created by LIBVA's vaCreateSurfaces
//! It is CALLER's responsibility to allocation memory for all pointers to CmSurface2D
//! Input :
//! 1) Pointer to the array of pointers pointing to LIBVA surface
//! 2) array size
//! 3) Pointer to the array of pointers pointing to CmSurface2D .
//! Output:
//! CM_SUCCESS if all CmSurface2D are successfully created;
//! CM_OUT_OF_HOST_MEMORY if out of system memory;
//! CM_FAILURE otherwise;
CM_RT_API int32_t CmDevice_RT::CreateSurface2D( VASurfaceID* vaSurfaceArray, const uint32_t surfaceCount, CmSurface2D** surfaceArray)
{
INSERT_PROFILER_RECORD();
return m_surfaceManager->CreateSurface2D(vaSurfaceArray, surfaceCount, surfaceArray);
}
int32_t CmDevice_RT::OSALExtensionExecute(uint32_t functionId,
void *inputData,
uint32_t inputDataLength,
void **resourceList,
uint32_t resourceCount)
{
CmAssert(inputData);
// uint32_t functionId = functionId;
// void* inputData = pInputData;
// uint32_t inputDataLen = iInputDataLen;
void* outputData = m_deviceInUmd; // pass cm device handle to umd
uint32_t outputDataLen = sizeof(m_deviceInUmd);
uint32_t vaModuleId = VAExtModuleCMRT;
VAStatus hr = VA_STATUS_SUCCESS;
if (m_fvaCmExtSendReqMsg != nullptr)
{
hr = m_fvaCmExtSendReqMsg(m_vaDisplay, &vaModuleId, &functionId, inputData, &inputDataLength , 0, outputData , &outputDataLen);
}
return hr;
}
//Initalize LibVA's VADisplay
int32_t CmDevice_RT::InitializeLibvaDisplay()
{
if ( m_cmCreated )
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
int vaMajorVersion, vaMinorVersion;
#ifndef ANDROID
int32_t ret = GetLibvaDisplayDrm(m_vaDisplay);
if ( ret != CM_SUCCESS)
{
CmAssert(0);
return ret;
}
#else
m_display = (Display*)malloc(sizeof(Display));
if (m_display == nullptr)
{
fprintf(stderr, "Can't connect X server!\n");
return CM_INVALID_LIBVA_INITIALIZE;
}
*(m_display) = ANDROID_DISPLAY;
m_vaDisplay = vaGetDisplay(m_display);
if (m_vaDisplay == nullptr)
{
return CM_INVALID_LIBVA_INITIALIZE;
}
#endif //ANDROID
vaStatus = vaInitialize(m_vaDisplay, &vaMajorVersion, &vaMinorVersion);
if ( VA_STATUS_SUCCESS != vaStatus ) {
return CM_INVALID_LIBVA_INITIALIZE;
}
}
m_fvaCmExtSendReqMsg = (pvaCmExtSendReqMsg) vaGetLibFunc (m_vaDisplay, "vaCmExtSendReqMsg");
if (m_fvaCmExtSendReqMsg == nullptr) {
fprintf(stderr, "Cannot get function of m_fvaCmExtSendReqMsg!\n");
return CM_INVALID_LIBVA_INITIALIZE;
}
else
{
return CM_SUCCESS;
}
}
CM_RT_API int32_t CmDevice_RT::GetVaDpy(VADisplay* & vaDpy)
{
INSERT_PROFILER_RECORD();
vaDpy = &m_vaDisplay;
return CM_SUCCESS;
}
#ifndef ANDROID
int32_t CmDevice_RT::GetLibvaDisplayDrm(VADisplay & vaDisplay)
{
pfVAGetDisplayDRM vaGetDisplayDRM = nullptr;
char *dlSymErr = nullptr;
void *hLibVaDRM = nullptr;
CLock locker(m_vaReferenceCountCriticalSection);
if(m_vaReferenceCount > 0)
{
vaGetDisplayDRM = m_vaGetDisplayDrm;
m_vaReferenceCount ++;
}
else
{
//Load libva-drm.so
dlerror();
hLibVaDRM = dlopen( "libva-drm.so", RTLD_LAZY );
if (!hLibVaDRM)
{
if ((dlSymErr = dlerror()) != nullptr)
{
fprintf(stderr, "%s\n", dlSymErr);
}
return CM_INVALID_LIBVA_INITIALIZE;
}
//dynamically load function vaGetDisplayDRM from libva-drm.so
dlerror();
vaGetDisplayDRM = (pfVAGetDisplayDRM)dlsym(hLibVaDRM, "vaGetDisplayDRM");
if ((dlSymErr= dlerror()) != nullptr) {
fprintf(stderr, "%s\n", dlSymErr);
return CM_INVALID_LIBVA_INITIALIZE;
}
m_vaReferenceCount ++;
m_vaDrm = hLibVaDRM;
m_vaGetDisplayDrm = vaGetDisplayDRM;
}
// open the GPU device
m_driFileDescriptor = open("/dev/dri/renderD128", O_RDWR);
if (m_driFileDescriptor < 0)
{
fprintf(stderr,"Failed to open GPU device file node\n");
return CM_INVALID_LIBVA_INITIALIZE;
}
if (m_vaGetDisplayDrm == nullptr)
{
fprintf(stderr, "m_vaGetDisplayDrm should not be nullptr.\n");
return CM_INVALID_LIBVA_INITIALIZE;
}
// get the display handle.
if (vaGetDisplayDRM == nullptr)
{
fprintf(stderr, "vaGetDisplayDRM should not be nullptr.\n");
return CM_INVALID_LIBVA_INITIALIZE;
}
vaDisplay = vaGetDisplayDRM(m_driFileDescriptor);
return CM_SUCCESS;
}
int32_t CmDevice_RT::FreeLibvaDrm()
{
CLock locker(m_vaReferenceCountCriticalSection);
if(m_vaReferenceCount > 1)
{
m_vaReferenceCount --;
}
else
{
dlclose(m_vaDrm);
m_vaDrm = nullptr;
m_vaGetDisplayDrm = nullptr;
m_vaReferenceCount --;
}
if ( m_driFileDescriptor != -1)
{
close(m_driFileDescriptor);
m_driFileDescriptor = -1;
}
return CM_SUCCESS;
}
#endif