1 /*
2 * Copyright (c) 2017, Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22 
23 #include "cm_device.h"
24 #include <dlfcn.h>
25 #include <cstdio>
26 
27 #include "cm_mem.h"
28 #include "cm_surface_manager.h"
29 #include "cm_queue.h"
30 #include "cm_timer.h"
31 #include "cm_debug.h"
32 #include "cm_extension_creator.h"
33 
34 #if USE_EXTENSION_CODE
35 #include "cm_gtpin_external_interface.h"
36 #endif
37 
38 #include <unistd.h>
39 #include <fcntl.h>
40 
41 #ifndef ANDROID
42 uint32_t CmDevice_RT::m_vaReferenceCount = 0;
43 CSync CmDevice_RT::m_vaReferenceCountCriticalSection;
44 void  *CmDevice_RT::m_vaDrm = nullptr;
45 pfVAGetDisplayDRM CmDevice_RT::m_vaGetDisplayDrm = nullptr;
46 #endif
47 // current binary version, query by command "strings",
48 //       e.g. "strings  -a igfxcmrt64.so | grep current_version "
49 volatile static char cmrtCurrentVersion[] = "cmrt_current_version: " \
50 "6.0.0.9010\0";
51 CSync gDeviceCreationCriticalSection;
52 
Create(CmDevice_RT * & device,uint32_t createOption)53 int32_t CmDevice_RT::Create(CmDevice_RT* &device, uint32_t createOption)
54 {
55     INSERT_PROFILER_RECORD();
56 
57     int32_t result = CM_SUCCESS;
58 
59     device = new CmDevice_RT(nullptr, createOption);
60     if( device )
61     {
62         result = device->Initialize(true);
63         if(result != CM_SUCCESS)
64         {
65             CmAssert(0);
66             Destroy(device);
67         }
68     }
69     else
70     {
71         CmAssert(0);
72         result = CM_OUT_OF_HOST_MEMORY;
73     }
74 
75     return result;
76 }
77 
78 
Create(VADisplay & vaDisplay,CmDevice_RT * & device,uint32_t createOption)79 int32_t CmDevice_RT::Create(VADisplay &vaDisplay, CmDevice_RT* &device, uint32_t createOption)
80 {
81     INSERT_PROFILER_RECORD();
82 
83     int32_t result = CM_FAILURE;
84     device = new (std::nothrow) CmDevice_RT(vaDisplay, createOption);
85     if (device)
86     {
87         result = device->Initialize(false);
88         if (result != CM_SUCCESS)
89         {
90             Destroy(device);
91         }
92     }
93     else
94     {
95         CmAssert(0);
96         result = CM_OUT_OF_HOST_MEMORY;
97     }
98 
99     // leave critical section
100     return result;
101 }
102 
Destroy(CmDevice_RT * & device)103 int32_t CmDevice_RT::Destroy(CmDevice_RT* &device)
104 {
105     if (device == nullptr)
106     {
107         return CM_FAILURE;
108     }
109 
110     // Destroy the cm device object
111     device->FreeResources();
112 
113     //Destroy the Device at CMRT@UMD
114     CM_DESTROYCMDEVICE_PARAM destroyCmDeviceParam;
115     CmSafeMemSet(&destroyCmDeviceParam, 0, sizeof(CM_DESTROYCMDEVICE_PARAM));
116     destroyCmDeviceParam.cmDeviceHandle = device->m_deviceInUmd;
117     uint32_t inputDataLen = sizeof(CM_DESTROYCMDEVICE_PARAM);
118 
119     int32_t result = device->OSALExtensionExecute(CM_FN_DESTROYCMDEVICE,
120         &destroyCmDeviceParam,
121         inputDataLen);
122 
123     CmSafeRelease(device);
124     CHK_FAILURE_RETURN(result);
125 
126     // leave critical section
127     return destroyCmDeviceParam.returnValue;
128 }
129 
CmDevice_RT(VADisplay vaDisplay,uint32_t createOption)130 CmDevice_RT::CmDevice_RT(
131     VADisplay vaDisplay,
132     uint32_t createOption
133     ) :
134     m_cmVersion(0),
135     m_deviceInUmd(nullptr),
136     m_cmCreated(true),
137     m_vaDisplay(vaDisplay),
138 #ifdef ANDROID
139     m_display(nullptr),
140 #endif
141     m_fvaCmExtSendReqMsg(nullptr),
142     m_gtpinEnabled(false),
143     m_gtpinBufferUP0(nullptr),
144     m_gtpinBufferUP1(nullptr),
145     m_gtpinBufferUP2(nullptr),
146     m_createOption(createOption),
147     m_driverStoreEnabled(0),
148     m_driFileDescriptor(0)
149 {
150 
151     // New Surface Manager
152     m_surfaceManager = new CmSurfaceManager(this);
153 
154     // New Kernel Debugger
155     m_kernelDebugger = CmExtensionCreator<CmKernelDebugger>::CreateClass();
156 
157     //Initialize L3 cache config
158     CmSafeMemSet(&m_l3Config, 0, sizeof(L3ConfigRegisterValues));
159 
160 }
161 
~CmDevice_RT(void)162 CmDevice_RT::~CmDevice_RT(void)
163 {
164     if (m_cmCreated)
165     {
166         vaTerminate(m_vaDisplay);
167 #ifndef ANDROID
168         FreeLibvaDrm();
169 #else
170         free(m_display); //Android
171 #endif
172     }
173 
174     if (m_kernelDebugger != nullptr)
175     {
176         delete m_kernelDebugger;
177     }
178 }
179 
FreeResources()180 int32_t CmDevice_RT::FreeResources()
181 {
182     //Destroy Queue
183     m_criticalSectionQueue.Acquire();
184     for (auto iter = m_queue.begin(); iter != m_queue.end();)
185     {
186         if (*iter != nullptr)
187         {
188             CmQueue_RT::Destroy(*iter);
189         }
190         iter = m_queue.erase(iter);
191     }
192     m_criticalSectionQueue.Release();
193 
194     //Destroy GTPin Used BufferUp
195     if (m_gtpinBufferUP0 != nullptr)
196     {
197         DestroyBufferUP(m_gtpinBufferUP0);
198     }
199 
200     if (m_gtpinBufferUP1 != nullptr)
201     {
202         DestroyBufferUP(m_gtpinBufferUP1);
203     }
204 
205     if (m_gtpinBufferUP2 != nullptr)
206     {
207         DestroyBufferUP(m_gtpinBufferUP2);
208     }
209 
210     CmSafeRelease(m_surfaceManager);
211 
212     return CM_SUCCESS;
213 }
214 
CmrtVaSurfaceRelease(void * vaDisplay,void * vaSurface)215 static int32_t CmrtVaSurfaceRelease(void *vaDisplay, void *vaSurface)
216 {
217     VAStatus   vaStatus = VA_STATUS_SUCCESS;
218     VADisplay  *display = (VADisplay *)(vaDisplay);
219 
220     //Destroy VaSurface
221     vaStatus = vaDestroySurfaces(*display, (VASurfaceID *)vaSurface, 1);
222 
223     return vaStatus;
224 }
225 
Initialize(bool isCmCreated)226 int32_t CmDevice_RT::Initialize(bool isCmCreated)
227 {
228     int32_t result = CM_SUCCESS;
229 
230     m_cmCreated = isCmCreated;
231 
232     CLock locker(gDeviceCreationCriticalSection);
233 
234     CHK_RET(InitializeLibvaDisplay());
235 
236     CHK_RET(CreateDeviceInUmd());
237 
238     CHK_RET(CheckDdiVersionSupported(m_cmVersion));
239 
240 #if USE_EXTENSION_CODE
241     if (GTpinVariables.GTPinEnabled)
242     {
243         CHK_RET(EnableGtpin());
244         CHK_RET(RegisterGtpinMarkerFunctions());
245 
246     }
247 #endif
248     if (m_kernelDebugger != nullptr)
249     {
250         m_kernelDebugger->NotifyNewDevice(this, m_deviceInUmd, m_driverStoreEnabled);
251     }
252 
253 finish:
254     return result;
255 }
256 
CreateDeviceInUmd()257 int32_t CmDevice_RT::CreateDeviceInUmd()
258 {
259     CmDeviceCreationParam createCmDeviceParam;
260     CmSafeMemSet(&createCmDeviceParam, 0, sizeof(createCmDeviceParam));
261     createCmDeviceParam.returnValue = CM_FAILURE;
262     createCmDeviceParam.createOption = m_createOption;
263     createCmDeviceParam.releaseSurfaceFunc = &CmrtVaSurfaceRelease;
264     uint32_t inputDataLen = sizeof(createCmDeviceParam);
265 
266     int32_t result = OSALExtensionExecute(CM_FN_CREATECMDEVICE,
267         &createCmDeviceParam, inputDataLen);
268 
269     CHK_FAILURE_RETURN(result);
270     CHK_FAILURE_RETURN(createCmDeviceParam.returnValue);
271 
272     m_cmVersion = createCmDeviceParam.version;
273     m_deviceInUmd = createCmDeviceParam.deviceHandleInUmd;
274     m_driverStoreEnabled = createCmDeviceParam.driverStoreEnabled;
275     return CM_SUCCESS;
276 }
277 
278 //!
279 //! Create Libva Surface and wrap it as a CmSurface
280 //! It is CALLER's responsibility to allocation memory for all pointers to CmSurface2D
281 //! Input :
282 //!     1) Surface's width  [in]
283 //!     2) Surface's height [in]
284 //!     3) Surface's format [in]
285 //!     4) Reference to created VASurfaceID [out]
286 //!     5) Reference to pointer of created Cm Surface [out]
287 //! Output:
288 //!     CM_SUCCESS if all CmSurface2D are successfully created;
289 //!     CM_VA_SURFACE_NOT_SUPPORTED if libva surface creation fail;
290 //!     CM_FAILURE otherwise;
CreateVaSurface2D(uint32_t width,uint32_t height,CM_SURFACE_FORMAT format,VASurfaceID & vaSurface,CmSurface2D * & surface)291 CM_RT_API int32_t CmDevice_RT::CreateVaSurface2D(uint32_t width, uint32_t height, CM_SURFACE_FORMAT format, VASurfaceID &vaSurface, CmSurface2D* &surface)
292 {
293     INSERT_PROFILER_RECORD();
294 
295     return m_surfaceManager->CreateVaSurface2D(width, height, format, vaSurface, surface);
296 }
297 
298 //!
299 //!
300 //! Create a CmSurface2D from an existing LIBVA surface
301 //! Input :
302 //!     Reference to the pointer to the CmSurface2D .
303 //!     VASurfaceID
304 //! Output:
305 //!     CM_SUCCESS if the CmSurface2D are successfully created;
306 //!     CM_OUT_OF_HOST_MEMORY if out of system memory;
307 //!     CM_FAILURE otherwise;
308 //!
CreateSurface2D(VASurfaceID vaSurface,CmSurface2D * & surface)309 CM_RT_API int32_t CmDevice_RT::CreateSurface2D(VASurfaceID vaSurface, CmSurface2D* &surface)
310 {
311     INSERT_PROFILER_RECORD();
312 
313     return m_surfaceManager->CreateSurface2D(vaSurface, surface);
314 }
315 
316 //!
317 //! Create an array of CmSurface2D from an existing array of LIBVA surfaces, which are created by LIBVA's vaCreateSurfaces
318 //! It is CALLER's responsibility to allocation memory for all pointers to CmSurface2D
319 //! Input :
320 //!     1) Pointer to the array of pointers pointing to LIBVA surface
321 //!     2) array size
322 //!     3) Pointer to the array of pointers pointing to CmSurface2D .
323 //! Output:
324 //!     CM_SUCCESS if all CmSurface2D are successfully created;
325 //!     CM_OUT_OF_HOST_MEMORY if out of system memory;
326 //!     CM_FAILURE otherwise;
CreateSurface2D(VASurfaceID * vaSurfaceArray,const uint32_t surfaceCount,CmSurface2D ** surfaceArray)327 CM_RT_API int32_t CmDevice_RT::CreateSurface2D(VASurfaceID* vaSurfaceArray, const uint32_t surfaceCount, CmSurface2D**  surfaceArray)
328 {
329     INSERT_PROFILER_RECORD();
330 
331     return m_surfaceManager->CreateSurface2D(vaSurfaceArray, surfaceCount, surfaceArray);
332 }
333 
OSALExtensionExecute(uint32_t functionId,void * inputData,uint32_t inputDataLength,void ** resourceList,uint32_t resourceCount)334 int32_t CmDevice_RT::OSALExtensionExecute(uint32_t functionId,
335     void *inputData,
336     uint32_t inputDataLength,
337     void **resourceList,
338     uint32_t resourceCount)
339 {
340     CmAssert(inputData);
341 
342     //    uint32_t functionId    = functionId;
343     //    void* inputData    = pInputData;
344     //    uint32_t inputDataLen  = iInputDataLen;
345 
346     void* outputData = m_deviceInUmd; // pass cm device handle to umd
347     uint32_t outputDataLen = sizeof(m_deviceInUmd);
348     uint32_t vaModuleId = VAExtModuleCMRT;
349     VAStatus hr = VA_STATUS_SUCCESS;
350 
351     if (m_fvaCmExtSendReqMsg != nullptr)
352     {
353         hr = m_fvaCmExtSendReqMsg(m_vaDisplay, &vaModuleId, &functionId, inputData, &inputDataLength, 0, outputData, &outputDataLen);
354     }
355     return hr;
356 }
357 
358 //Initalize LibVA's VADisplay
InitializeLibvaDisplay()359 int32_t CmDevice_RT::InitializeLibvaDisplay()
360 {
361     if (m_cmCreated)
362     {
363         VAStatus vaStatus = VA_STATUS_SUCCESS;
364         int vaMajorVersion, vaMinorVersion;
365 
366 #ifndef ANDROID
367         int32_t ret = GetLibvaDisplayDrm(m_vaDisplay);
368         if (ret != CM_SUCCESS)
369         {
370             CmAssert(0);
371             return ret;
372         }
373 #else
374         m_display = (Display*)malloc(sizeof(Display));
375         if (m_display == nullptr)
376         {
377             fprintf(stderr, "Can't connect X server!\n");
378             return CM_INVALID_LIBVA_INITIALIZE;
379         }
380 
381         *(m_display) = ANDROID_DISPLAY;
382         m_vaDisplay = vaGetDisplay(m_display);
383         if (m_vaDisplay == nullptr)
384         {
385             return CM_INVALID_LIBVA_INITIALIZE;
386         }
387 #endif  //ANDROID
388 
389         vaStatus = vaInitialize(m_vaDisplay, &vaMajorVersion, &vaMinorVersion);
390         if (VA_STATUS_SUCCESS != vaStatus) {
391             return CM_INVALID_LIBVA_INITIALIZE;
392         }
393     }
394 
395     m_fvaCmExtSendReqMsg = (pvaCmExtSendReqMsg)vaGetLibFunc(m_vaDisplay, "vaCmExtSendReqMsg");
396 
397     if (m_fvaCmExtSendReqMsg == nullptr) {
398         fprintf(stderr, "Cannot get function of m_fvaCmExtSendReqMsg!\n");
399         return CM_INVALID_LIBVA_INITIALIZE;
400     }
401     else
402     {
403         return CM_SUCCESS;
404     }
405 }
406 
GetVaDpy(VADisplay * & vaDpy)407 CM_RT_API int32_t CmDevice_RT::GetVaDpy(VADisplay* & vaDpy)
408 {
409     INSERT_PROFILER_RECORD();
410 
411     vaDpy = &m_vaDisplay;
412     return CM_SUCCESS;
413 }
414 
415 #ifndef ANDROID
GetLibvaDisplayDrm(VADisplay & vaDisplay)416 int32_t CmDevice_RT::GetLibvaDisplayDrm(VADisplay & vaDisplay)
417 {
418     pfVAGetDisplayDRM vaGetDisplayDRM = nullptr;
419     char *dlSymErr = nullptr;
420     void *hLibVaDRM = nullptr;
421 
422     CLock locker(m_vaReferenceCountCriticalSection);
423 
424     if (m_vaReferenceCount > 0)
425     {
426         vaGetDisplayDRM = m_vaGetDisplayDrm;
427         m_vaReferenceCount++;
428     }
429     else
430     {
431         //Load libva-drm.so
432         dlerror();
433         hLibVaDRM = dlopen("libva-drm.so", RTLD_LAZY);
434 
435         if (!hLibVaDRM)
436         {
437             if ((dlSymErr = dlerror()) != nullptr)
438             {
439                 fprintf(stderr, "%s\n", dlSymErr);
440             }
441             return CM_INVALID_LIBVA_INITIALIZE;
442         }
443 
444         //dynamically load function vaGetDisplayDRM from libva-drm.so
445         dlerror();
446         vaGetDisplayDRM = (pfVAGetDisplayDRM)dlsym(hLibVaDRM, "vaGetDisplayDRM");
447         if ((dlSymErr = dlerror()) != nullptr) {
448             fprintf(stderr, "%s\n", dlSymErr);
449             return CM_INVALID_LIBVA_INITIALIZE;
450         }
451 
452         m_vaReferenceCount++;
453         m_vaDrm = hLibVaDRM;
454         m_vaGetDisplayDrm = vaGetDisplayDRM;
455     }
456 
457     // open the GPU device
458     m_driFileDescriptor = open("/dev/dri/renderD128", O_RDWR);
459     if (m_driFileDescriptor < 0)
460     {
461         fprintf(stderr, "Failed to open GPU device file node\n");
462         return CM_INVALID_LIBVA_INITIALIZE;
463     }
464 
465     if (m_vaGetDisplayDrm == nullptr)
466     {
467         fprintf(stderr, "m_vaGetDisplayDrm should not be nullptr.\n");
468         return CM_INVALID_LIBVA_INITIALIZE;
469     }
470 
471     // get the display handle.
472     if (vaGetDisplayDRM == nullptr)
473     {
474         fprintf(stderr, "vaGetDisplayDRM should not be nullptr.\n");
475         return CM_INVALID_LIBVA_INITIALIZE;
476     }
477     vaDisplay = vaGetDisplayDRM(m_driFileDescriptor);
478 
479     return CM_SUCCESS;
480 }
481 
FreeLibvaDrm()482 int32_t CmDevice_RT::FreeLibvaDrm()
483 {
484     CLock locker(m_vaReferenceCountCriticalSection);
485     if (m_vaReferenceCount > 1)
486     {
487         m_vaReferenceCount--;
488     }
489     else
490     {
491         dlclose(m_vaDrm);
492         m_vaDrm = nullptr;
493         m_vaGetDisplayDrm = nullptr;
494 
495         m_vaReferenceCount--;
496     }
497 
498     if (m_driFileDescriptor != -1)
499     {
500         close(m_driFileDescriptor);
501         m_driFileDescriptor = -1;
502     }
503     return CM_SUCCESS;
504 }
505 #endif
506 
507