1 /*############################################################################
2   # Copyright (C) 2005 Intel Corporation
3   #
4   # SPDX-License-Identifier: MIT
5   ############################################################################*/
6 
7 #ifdef LIBVA_SUPPORT
8 
9     #include "vaapi_utils.h"
10     #include <dlfcn.h>
11     #include <stdexcept>
12 
13     //#if defined(LIBVA_DRM_SUPPORT)
14     #include "vaapi_utils_drm.h"
15     //#elif defined(LIBVA_X11_SUPPORT)
16     #include "vaapi_utils_x11.h"
17 //#endif
18 
19     #if defined(LIBVA_WAYLAND_SUPPORT)
20         #include "class_wayland.h"
21     #endif
22 
23 namespace MfxLoader {
24 
SimpleLoader(const char * name)25 SimpleLoader::SimpleLoader(const char* name) {
26     dlerror();
27     so_handle = dlopen(name, RTLD_GLOBAL | RTLD_NOW);
28     if (NULL == so_handle) {
29         std::cerr << dlerror() << std::endl;
30         throw std::runtime_error("Can't load library");
31     }
32 }
33 
GetFunction(const char * name)34 void* SimpleLoader::GetFunction(const char* name) {
35     void* fn_ptr = dlsym(so_handle, name);
36     if (!fn_ptr)
37         throw std::runtime_error("Can't find function");
38     return fn_ptr;
39 }
40 
~SimpleLoader()41 SimpleLoader::~SimpleLoader() {
42     dlclose(so_handle);
43 }
44 
45     #define SIMPLE_LOADER_STRINGIFY1(x)           #x
46     #define SIMPLE_LOADER_STRINGIFY(x)            SIMPLE_LOADER_STRINGIFY1(x)
47     #define SIMPLE_LOADER_DECORATOR1(fun, suffix) fun##_##suffix
48     #define SIMPLE_LOADER_DECORATOR(fun, suffix)  SIMPLE_LOADER_DECORATOR1(fun, suffix)
49 
50     // Following macro applied on vaInitialize will give:  vaInitialize((vaInitialize_type)lib.GetFunction("vaInitialize"))
51     #define SIMPLE_LOADER_FUNCTION(name) \
52         name((SIMPLE_LOADER_DECORATOR(name, type))lib.GetFunction(SIMPLE_LOADER_STRINGIFY(name)))
53 
54     #if defined(LIBVA_SUPPORT)
VA_Proxy()55 VA_Proxy::VA_Proxy()
56         #ifdef ANDROID
57         : lib("libva-android.so")
58         #else
59         : lib("libva.so.2")
60         #endif
61           ,
62           SIMPLE_LOADER_FUNCTION(vaInitialize),
63           SIMPLE_LOADER_FUNCTION(vaTerminate),
64           SIMPLE_LOADER_FUNCTION(vaCreateSurfaces),
65           SIMPLE_LOADER_FUNCTION(vaDestroySurfaces),
66           SIMPLE_LOADER_FUNCTION(vaCreateBuffer),
67           SIMPLE_LOADER_FUNCTION(vaDestroyBuffer),
68           SIMPLE_LOADER_FUNCTION(vaMapBuffer),
69           SIMPLE_LOADER_FUNCTION(vaUnmapBuffer),
70           SIMPLE_LOADER_FUNCTION(vaSyncSurface),
71           SIMPLE_LOADER_FUNCTION(vaDeriveImage),
72           SIMPLE_LOADER_FUNCTION(vaDestroyImage),
73           SIMPLE_LOADER_FUNCTION(vaGetLibFunc),
74           SIMPLE_LOADER_FUNCTION(vaAcquireBufferHandle),
75           SIMPLE_LOADER_FUNCTION(vaReleaseBufferHandle),
76           SIMPLE_LOADER_FUNCTION(vaMaxNumEntrypoints),
77           SIMPLE_LOADER_FUNCTION(vaQueryConfigEntrypoints),
78           SIMPLE_LOADER_FUNCTION(vaGetConfigAttributes),
79           SIMPLE_LOADER_FUNCTION(vaCreateConfig),
80           SIMPLE_LOADER_FUNCTION(vaCreateContext),
81           SIMPLE_LOADER_FUNCTION(vaDestroyConfig),
82           SIMPLE_LOADER_FUNCTION(vaDestroyContext) {
83 }
84 
~VA_Proxy()85 VA_Proxy::~VA_Proxy() {}
86 
87     #endif
88 
89     #if defined(LIBVA_DRM_SUPPORT)
DRM_Proxy()90 DRM_Proxy::DRM_Proxy()
91         : lib("libdrm.so.2"),
92           SIMPLE_LOADER_FUNCTION(drmIoctl),
93           SIMPLE_LOADER_FUNCTION(drmModeAddFB),
94           SIMPLE_LOADER_FUNCTION(drmModeAddFB2WithModifiers),
95           SIMPLE_LOADER_FUNCTION(drmModeFreeConnector),
96           SIMPLE_LOADER_FUNCTION(drmModeFreeCrtc),
97           SIMPLE_LOADER_FUNCTION(drmModeFreeEncoder),
98           SIMPLE_LOADER_FUNCTION(drmModeFreePlane),
99           SIMPLE_LOADER_FUNCTION(drmModeFreePlaneResources),
100           SIMPLE_LOADER_FUNCTION(drmModeFreeResources),
101           SIMPLE_LOADER_FUNCTION(drmModeGetConnector),
102           SIMPLE_LOADER_FUNCTION(drmModeGetCrtc),
103           SIMPLE_LOADER_FUNCTION(drmModeGetEncoder),
104           SIMPLE_LOADER_FUNCTION(drmModeGetPlane),
105           SIMPLE_LOADER_FUNCTION(drmModeGetPlaneResources),
106           SIMPLE_LOADER_FUNCTION(drmModeGetResources),
107           SIMPLE_LOADER_FUNCTION(drmModeRmFB),
108           SIMPLE_LOADER_FUNCTION(drmModeSetCrtc),
109           SIMPLE_LOADER_FUNCTION(drmSetMaster),
110           SIMPLE_LOADER_FUNCTION(drmDropMaster),
111           SIMPLE_LOADER_FUNCTION(drmModeSetPlane) {}
112 
~DrmIntel_Proxy()113 DrmIntel_Proxy::~DrmIntel_Proxy() {}
114 
DrmIntel_Proxy()115 DrmIntel_Proxy::DrmIntel_Proxy()
116         : lib("libdrm_intel.so.1"),
117           SIMPLE_LOADER_FUNCTION(drm_intel_bo_gem_create_from_prime),
118           SIMPLE_LOADER_FUNCTION(drm_intel_bo_unreference),
119           SIMPLE_LOADER_FUNCTION(drm_intel_bufmgr_gem_init),
120           SIMPLE_LOADER_FUNCTION(drm_intel_bufmgr_destroy)
121         #if defined(X11_DRI3_SUPPORT)
122           ,
123           SIMPLE_LOADER_FUNCTION(drm_intel_bo_gem_export_to_prime)
124         #endif
125 {
126 }
127 
~DRM_Proxy()128 DRM_Proxy::~DRM_Proxy() {}
129 
VA_DRMProxy()130 VA_DRMProxy::VA_DRMProxy() : lib("libva-drm.so.2"), SIMPLE_LOADER_FUNCTION(vaGetDisplayDRM) {}
131 
~VA_DRMProxy()132 VA_DRMProxy::~VA_DRMProxy() {}
133 
134         #if defined(X11_DRI3_SUPPORT)
XCB_Dri3_Proxy()135 XCB_Dri3_Proxy::XCB_Dri3_Proxy()
136         : lib("libxcb-dri3.so.0"),
137           SIMPLE_LOADER_FUNCTION(xcb_dri3_pixmap_from_buffer_checked) {}
138 
~XCB_Dri3_Proxy()139 XCB_Dri3_Proxy::~XCB_Dri3_Proxy() {}
140 
Xcb_Proxy()141 Xcb_Proxy::Xcb_Proxy()
142         : lib("libxcb.so.1"),
143           SIMPLE_LOADER_FUNCTION(xcb_generate_id),
144           SIMPLE_LOADER_FUNCTION(xcb_free_pixmap),
145           SIMPLE_LOADER_FUNCTION(xcb_flush),
146           SIMPLE_LOADER_FUNCTION(xcb_request_check) {}
147 
~Xcb_Proxy()148 Xcb_Proxy::~Xcb_Proxy() {}
149 
X11_Xcb_Proxy()150 X11_Xcb_Proxy::X11_Xcb_Proxy()
151         : lib("libX11-xcb.so.1"),
152           SIMPLE_LOADER_FUNCTION(XGetXCBConnection) {}
153 
~X11_Xcb_Proxy()154 X11_Xcb_Proxy::~X11_Xcb_Proxy() {}
155 
Xcbpresent_Proxy()156 Xcbpresent_Proxy::Xcbpresent_Proxy()
157         : lib("libxcb-present.so.0"),
158           SIMPLE_LOADER_FUNCTION(xcb_present_pixmap_checked) {}
159 
~Xcbpresent_Proxy()160 Xcbpresent_Proxy::~Xcbpresent_Proxy() {}
161         #endif // X11_DRI3_SUPPORT
162     #endif
163 
164     #if defined(LIBVA_WAYLAND_SUPPORT)
165 
166         #define WAYLAND_LIB SIMPLE_LOADER_STRINGIFY(_TOOLS_LIB_PATH) "/libvpl_wayland.so"
167 
VA_WaylandClientProxy()168 VA_WaylandClientProxy::VA_WaylandClientProxy()
169         : lib(WAYLAND_LIB),
170           SIMPLE_LOADER_FUNCTION(WaylandCreate) {}
171 
~VA_WaylandClientProxy()172 VA_WaylandClientProxy::~VA_WaylandClientProxy() {}
173 
174     #endif // LIBVA_WAYLAND_SUPPORT
175 
176     #if defined(LIBVA_X11_SUPPORT)
VA_X11Proxy()177 VA_X11Proxy::VA_X11Proxy()
178         : lib("libva-x11.so.2"),
179           SIMPLE_LOADER_FUNCTION(vaGetDisplay),
180           SIMPLE_LOADER_FUNCTION(vaPutSurface) {}
181 
~VA_X11Proxy()182 VA_X11Proxy::~VA_X11Proxy() {}
183 
XLib_Proxy()184 XLib_Proxy::XLib_Proxy()
185         : lib("libX11.so.6"),
186           SIMPLE_LOADER_FUNCTION(XOpenDisplay),
187           SIMPLE_LOADER_FUNCTION(XCloseDisplay),
188           SIMPLE_LOADER_FUNCTION(XCreateSimpleWindow),
189           SIMPLE_LOADER_FUNCTION(XMapWindow),
190           SIMPLE_LOADER_FUNCTION(XSync),
191           SIMPLE_LOADER_FUNCTION(XDestroyWindow),
192           SIMPLE_LOADER_FUNCTION(XResizeWindow)
193         #if defined(X11_DRI3_SUPPORT)
194           ,
195           SIMPLE_LOADER_FUNCTION(XGetGeometry)
196         #endif // X11_DRI3_SUPPORT
197 {
198 }
199 
~XLib_Proxy()200 XLib_Proxy::~XLib_Proxy() {}
201 
202     #endif
203 
204     #undef SIMPLE_LOADER_FUNCTION
205 
206 } // namespace MfxLoader
207 
va_to_mfx_status(VAStatus va_res)208 mfxStatus va_to_mfx_status(VAStatus va_res) {
209     mfxStatus mfxRes = MFX_ERR_NONE;
210 
211     switch (va_res) {
212         case VA_STATUS_SUCCESS:
213             mfxRes = MFX_ERR_NONE;
214             break;
215         case VA_STATUS_ERROR_ALLOCATION_FAILED:
216             mfxRes = MFX_ERR_MEMORY_ALLOC;
217             break;
218         case VA_STATUS_ERROR_ATTR_NOT_SUPPORTED:
219         case VA_STATUS_ERROR_UNSUPPORTED_PROFILE:
220         case VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT:
221         case VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT:
222         case VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE:
223         case VA_STATUS_ERROR_FLAG_NOT_SUPPORTED:
224         case VA_STATUS_ERROR_RESOLUTION_NOT_SUPPORTED:
225             mfxRes = MFX_ERR_UNSUPPORTED;
226             break;
227         case VA_STATUS_ERROR_INVALID_DISPLAY:
228         case VA_STATUS_ERROR_INVALID_CONFIG:
229         case VA_STATUS_ERROR_INVALID_CONTEXT:
230         case VA_STATUS_ERROR_INVALID_SURFACE:
231         case VA_STATUS_ERROR_INVALID_BUFFER:
232         case VA_STATUS_ERROR_INVALID_IMAGE:
233         case VA_STATUS_ERROR_INVALID_SUBPICTURE:
234             mfxRes = MFX_ERR_NOT_INITIALIZED;
235             break;
236         case VA_STATUS_ERROR_INVALID_PARAMETER:
237             mfxRes = MFX_ERR_INVALID_VIDEO_PARAM;
238         default:
239             mfxRes = MFX_ERR_UNKNOWN;
240             break;
241     }
242     return mfxRes;
243 }
244 
245     #if defined(LIBVA_DRM_SUPPORT) || defined(LIBVA_X11_SUPPORT)
246 
247 // temp compatibility with some old tools/val-tools
CreateLibVA(int type)248 CLibVA* CreateLibVA(int type) {
249     return CreateLibVA("", type);
250 }
251 
CreateLibVA(const std::string & devicePath,int type)252 CLibVA* CreateLibVA(const std::string& devicePath, int type) {
253     CLibVA* libva = NULL;
254     switch (type) {
255         case MFX_LIBVA_DRM:
256         #if defined(LIBVA_DRM_SUPPORT)
257             try {
258                 libva = new DRMLibVA(devicePath, type);
259             }
260             catch (std::exception&) {
261             }
262         #endif
263             break;
264 
265         case MFX_LIBVA_X11:
266         #if defined(LIBVA_X11_SUPPORT)
267             try {
268                 libva = new X11LibVA;
269             }
270             catch (std::exception&) {
271             }
272         #endif
273             break;
274 
275         case MFX_LIBVA_AUTO:
276         #if defined(LIBVA_X11_SUPPORT)
277             try {
278                 libva = new X11LibVA;
279             }
280             catch (std::exception&) {
281             }
282         #endif
283         #if defined(LIBVA_DRM_SUPPORT)
284             if (!libva) {
285                 try {
286                     libva = new DRMLibVA(devicePath, type);
287                 }
288                 catch (std::exception&) {
289                 }
290             }
291         #endif
292             break;
293     } // switch(type)
294 
295     return libva;
296 }
297     #endif // #if defined(LIBVA_DRM_SUPPORT) || defined(LIBVA_X11_SUPPORT)
298 
299     #if defined(LIBVA_X11_SUPPORT)
300 
301 struct AcquireCtx {
302     int fd;
303     VAImage image;
304 };
305 
AcquireVASurface(void ** pctx,VADisplay dpy1,VASurfaceID srf1,VADisplay dpy2,VASurfaceID * srf2)306 VAStatus CLibVA::AcquireVASurface(void** pctx,
307                                   VADisplay dpy1,
308                                   VASurfaceID srf1,
309                                   VADisplay dpy2,
310                                   VASurfaceID* srf2) {
311     if (!pctx || !srf2)
312         return VA_STATUS_ERROR_OPERATION_FAILED;
313 
314     if (dpy1 == dpy2) {
315         *srf2 = srf1;
316         return VA_STATUS_SUCCESS;
317     }
318 
319     AcquireCtx* ctx;
320     unsigned long handle = 0;
321     VAStatus va_res;
322     VASurfaceAttrib attribs[2];
323     VASurfaceAttribExternalBuffers extsrf;
324     VABufferInfo bufferInfo;
325     uint32_t memtype = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
326 
327     MSDK_ZERO_MEMORY(attribs);
328     MSDK_ZERO_MEMORY(extsrf);
329     MSDK_ZERO_MEMORY(bufferInfo);
330     extsrf.num_buffers = 1;
331     extsrf.buffers     = &handle;
332 
333     attribs[0].type          = (VASurfaceAttribType)VASurfaceAttribMemoryType;
334     attribs[0].flags         = VA_SURFACE_ATTRIB_SETTABLE;
335     attribs[0].value.type    = VAGenericValueTypeInteger;
336     attribs[0].value.value.i = memtype;
337 
338     attribs[1].type          = (VASurfaceAttribType)VASurfaceAttribExternalBufferDescriptor;
339     attribs[1].flags         = VA_SURFACE_ATTRIB_SETTABLE;
340     attribs[1].value.type    = VAGenericValueTypePointer;
341     attribs[1].value.value.p = &extsrf;
342 
343     ctx = (AcquireCtx*)calloc(1, sizeof(AcquireCtx));
344     if (!ctx)
345         return VA_STATUS_ERROR_OPERATION_FAILED;
346 
347     va_res = m_libva.vaDeriveImage(dpy1, srf1, &ctx->image);
348     if (VA_STATUS_SUCCESS != va_res) {
349         free(ctx);
350         return va_res;
351     }
352 
353     va_res = m_libva.vaAcquireBufferHandle(dpy1, ctx->image.buf, &bufferInfo);
354     if (VA_STATUS_SUCCESS != va_res) {
355         m_libva.vaDestroyImage(dpy1, ctx->image.image_id);
356         free(ctx);
357         return va_res;
358     }
359 
360     extsrf.width        = ctx->image.width;
361     extsrf.height       = ctx->image.height;
362     extsrf.num_planes   = ctx->image.num_planes;
363     extsrf.pixel_format = ctx->image.format.fourcc;
364     for (int i = 0; i < 3; ++i) {
365         extsrf.pitches[i] = ctx->image.pitches[i];
366         extsrf.offsets[i] = ctx->image.offsets[i];
367     }
368     extsrf.data_size  = ctx->image.data_size;
369     extsrf.flags      = memtype;
370     extsrf.buffers[0] = bufferInfo.handle;
371 
372     va_res = m_libva.vaCreateSurfaces(dpy2,
373                                       VA_RT_FORMAT_YUV420,
374                                       extsrf.width,
375                                       extsrf.height,
376                                       srf2,
377                                       1,
378                                       attribs,
379                                       2);
380     if (VA_STATUS_SUCCESS != va_res) {
381         m_libva.vaDestroyImage(dpy1, ctx->image.image_id);
382         free(ctx);
383         return va_res;
384     }
385 
386     *pctx = ctx;
387 
388     return VA_STATUS_SUCCESS;
389 }
390 
ReleaseVASurface(void * actx,VADisplay dpy1,VASurfaceID,VADisplay dpy2,VASurfaceID srf2)391 void CLibVA::ReleaseVASurface(void* actx,
392                               VADisplay dpy1,
393                               VASurfaceID /*srf1*/,
394                               VADisplay dpy2,
395                               VASurfaceID srf2) {
396     if (dpy1 != dpy2) {
397         AcquireCtx* ctx = (AcquireCtx*)actx;
398         if (ctx) {
399             m_libva.vaDestroySurfaces(dpy2, &srf2, 1);
400             close(ctx->fd);
401             m_libva.vaReleaseBufferHandle(dpy1, ctx->image.buf);
402             m_libva.vaDestroyImage(dpy1, ctx->image.image_id);
403             free(ctx);
404         }
405     }
406 }
407 
408     #endif //LIBVA_X11_SUPPORT
409 
410 #endif // #ifdef LIBVA_SUPPORT
411