tbm_bufmgr: use tbm_module_bufmgr_get_capabilities
[platform/core/uifw/libtbm.git] / src / tbm_module.c
1 /**************************************************************************
2
3 libtbm
4
5 Copyright 2012-2021 Samsung Electronics co., Ltd. All Rights Reserved.
6
7 Contact: SooChan Lim <sc1.lim@samsung.com>
8          Changyeon Lee <cyeon.lee@samsung.com>
9
10 Permission is hereby granted, free of charge, to any person obtaining a
11 copy of this software and associated documentation files (the
12 "Software"), to deal in the Software without restriction, including
13 without limitation the rights to use, copy, modify, merge, publish,
14 distribute, sub license, and/or sell copies of the Software, and to
15 permit persons to whom the Software is furnished to do so, subject to
16 the following conditions:
17
18 The above copyright notice and this permission notice (including the
19 next paragraph) shall be included in all copies or substantial portions
20 of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
25 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
27 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
28 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
30 **************************************************************************/
31
32 #include "config.h"
33
34 #include "tbm_bufmgr_int.h"
35 #include "tbm_bufmgr_backend.h"
36 #include "tbm_drm_helper.h"
37
38 #define PREFIX_LIB    "libtbm_"
39 #define SUFFIX_LIB    ".so"
40 #define DEFAULT_LIB   PREFIX_LIB"default"SUFFIX_LIB
41
42 /* values to indicate unspecified fields in XF86ModReqInfo. */
43 #define MAJOR_UNSPEC      0xFF
44 #define MINOR_UNSPEC      0xFF
45 #define PATCH_UNSPEC      0xFFFF
46 #define ABI_VERS_UNSPEC   0xFFFFFFFF
47
48 #define MODULE_VERSION_NUMERIC(maj, min, patch) \
49                         ((((maj) & 0xFF) << 24) | (((min) & 0xFF) << 16) | (patch & 0xFFFF))
50 #define GET_MODULE_MAJOR_VERSION(vers)    (((vers) >> 24) & 0xFF)
51 #define GET_MODULE_MINOR_VERSION(vers)    (((vers) >> 16) & 0xFF)
52 #define GET_MODULE_PATCHLEVEL(vers)    ((vers) & 0xFFFF)
53
54 /* LCOV_EXCL_START */
55
56 static void
57 _tbm_module_copy_data_to_bufmgr(tbm_module *module, tbm_bufmgr bufmgr, int reset)
58 {
59         if (!reset) {
60                 bufmgr->module_data = module->module_data;
61                 bufmgr->backend = module->backend;
62
63                 bufmgr->backend_module_data = module->backend_module_data;
64                 bufmgr->bufmgr_data = module->bufmgr_data;
65                 bufmgr->bufmgr_func = module->bufmgr_func;
66                 bufmgr->bo_func = module->bo_func;
67
68                 bufmgr->use_hal_tbm = module->use_hal_tbm;
69                 bufmgr->auth_wl_socket_created = module->auth_wl_socket_created;
70                 bufmgr->auth_fd = module->auth_fd;
71                 bufmgr->hal_backend = module->hal_backend;
72                 bufmgr->hal_bufmgr = module->hal_bufmgr;
73         } else {
74                 bufmgr->module_data = NULL;
75                 bufmgr->backend = NULL;
76
77                 bufmgr->backend_module_data = NULL;
78                 bufmgr->bufmgr_data = NULL;
79                 bufmgr->bufmgr_func = NULL;
80                 bufmgr->bo_func = NULL;
81
82                 bufmgr->use_hal_tbm = 0;
83                 bufmgr->auth_wl_socket_created = 0;
84                 bufmgr->auth_fd = -1;
85                 bufmgr->hal_backend = NULL;
86                 bufmgr->hal_bufmgr = NULL;
87         }
88 }
89
90 static int
91 _tbm_backend_load_hal_tbm(tbm_module *module)
92 {
93         hal_tbm_backend *hal_backend = NULL;
94         hal_tbm_bufmgr *hal_bufmgr;
95         hal_tbm_error ret = HAL_TBM_ERROR_NONE;
96         hal_tbm_fd auth_drm_fd = -1;
97
98         hal_backend = hal_tbm_get_backend(&ret);
99         if (hal_backend == NULL || ret != HAL_TBM_ERROR_NONE) {
100                 TBM_ERR("get backend fail");
101                 return 0;
102         }
103
104         hal_bufmgr = hal_tbm_backend_get_bufmgr(hal_backend, &ret);
105         if (hal_bufmgr == NULL || ret != HAL_TBM_ERROR_NONE) {
106                 TBM_ERR("get hal_bufmgr fail");
107                 goto get_backend_fail;
108         }
109
110         if (hal_tbm_backend_has_drm_device(hal_backend, &ret)) {
111                 auth_drm_fd = hal_tbm_backend_get_master_drm_fd(hal_backend, &ret);
112                 if (auth_drm_fd < 0) {
113                         TBM_INFO("tbm_backend has no master drm_fd.");
114
115                         auth_drm_fd = tbm_drm_helper_get_master_fd();
116                         if (auth_drm_fd < 0) {
117                                 TBM_INFO("libtbm requests an authenticated drm_fd to a process(display server).");
118                                 if (!tbm_drm_helper_get_auth_info(&auth_drm_fd, NULL, NULL)) {
119                                         TBM_ERR("get auth drm_fd fail");
120                                         goto get_backend_fail;
121                                 }
122                         } else {
123                                 TBM_INFO("libtbm gets a master drm_fd from libtdm via tbm_drm_helper.");
124                         }
125
126                         TBM_INFO("libtbm sends a master drm_fd as an authentiated drm_fd to tbm_backend.");
127                         ret = hal_tbm_backend_set_authenticated_drm_fd(hal_backend, auth_drm_fd);
128                         if (ret != HAL_TBM_ERROR_NONE) {
129                                 TBM_ERR("hal_tbm_backend_set_authenticated_drm_fd failed.");
130                                 goto get_backend_fail;
131                         }
132                 } else {
133                         TBM_INFO("tbm_backend has a master drm_fd.");
134
135                         tbm_drm_helper_set_tbm_master_fd(auth_drm_fd);
136                 }
137                 tbm_drm_helper_set_fd(auth_drm_fd);
138         }
139
140         module->hal_backend = hal_backend;
141         module->hal_bufmgr = hal_bufmgr;
142
143         module->use_hal_tbm = 1;
144
145         TBM_INFO("use HAL-TBM_API");
146
147         return 1;
148
149 get_backend_fail:
150         if (auth_drm_fd >= 0)
151                 close(auth_drm_fd);
152         hal_tbm_put_backend(hal_backend);
153         return 0;
154 }
155
156 static int
157 _check_version(TBMModuleVersionInfo *data)
158 {
159         int backend_module_major, backend_module_minor;
160         int tbm_backend_major, tbm_backend_minor;
161
162         backend_module_major = GET_ABI_MAJOR(data->abiversion);
163         backend_module_minor = GET_ABI_MINOR(data->abiversion);
164
165         TBM_DBG("TBM module %s: vendor=\"%s\" ABI=%d,%d\n",
166             data->modname ? data->modname : "UNKNOWN!",
167             data->vendor ? data->vendor : "UNKNOWN!", backend_module_major, backend_module_minor);
168
169         tbm_backend_major = GET_ABI_MAJOR(TBM_ABI_VERSION);
170         tbm_backend_minor = GET_ABI_MINOR(TBM_ABI_VERSION);
171
172         TBM_DBG("TBM ABI version %d.%d\n",
173             tbm_backend_major, tbm_backend_minor);
174
175         if (backend_module_major != tbm_backend_major) {
176                 TBM_ERR("TBM module ABI major ver(%d) doesn't match the TBM's ver(%d)\n",
177                         backend_module_major, tbm_backend_major);
178                 return 0;
179         } else if (backend_module_minor > tbm_backend_minor) {
180                 TBM_ERR("TBM module ABI minor ver(%d) is newer than the TBM's ver(%d)\n",
181                         backend_module_minor, tbm_backend_minor);
182                 return 0;
183         }
184
185         return 1;
186 }
187
188 static int
189 _tbm_backend_check_bufmgr_func(tbm_backend_bufmgr_func *bufmgr_func)
190 {
191         TBM_RETURN_VAL_IF_FAIL(bufmgr_func, 0); /* mandatory symbol */
192         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_get_capabilities, 0); /* mandatory symbol */
193         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_bind_native_display, 0); /* mandatory symbol */
194         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_get_supported_formats, 0); /* mandatory symbol */
195         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_get_plane_data, 0); /* mandatory symbol */
196         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_alloc_bo, 0); /* mandatory symbol */
197         if (!bufmgr_func->bufmgr_alloc_bo_with_format)
198                 TBM_DBG("No bufmgr_func->bufmgr_alloc_bo_with_format.");
199         TBM_RETURN_VAL_IF_FAIL(bufmgr_func->bufmgr_import_fd, 0); /* mandatory symbol */
200         if (!bufmgr_func->bufmgr_import_key)
201                 TBM_DBG("No bufmgr_func->bo_export_key.");
202
203         return 1;
204 }
205
206 static int
207 _tbm_backend_check_bufmgr_bo(tbm_backend_bo_func *bo_func)
208 {
209         TBM_RETURN_VAL_IF_FAIL(bo_func, 0); /* mandatory symbol */
210         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_free, 0); /* mandatory symbol */
211         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_get_size, 0); /* mandatory symbol */
212         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_get_memory_types, 0); /* mandatory symbol */
213         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_get_handle, 0); /* mandatory symbol */
214         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_map, 0); /* mandatory symbol */
215         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_unmap, 0); /* mandatory symbol */
216         if (!bo_func->bo_lock)
217                 TBM_DBG("No bo_func->bo_lock.");
218         if (!bo_func->bo_unlock)
219                 TBM_DBG("No bo_func->bo_unlock.");
220         TBM_RETURN_VAL_IF_FAIL(bo_func->bo_export_fd, 0); /* mandatory symbol */
221         if (!bo_func->bo_export_key)
222                 TBM_INFO("No bo_func->bo_export_key.");
223
224         return 1;
225 }
226
227 static int
228 _tbm_backend_load_module(tbm_module *module, const char *file)
229 {
230         char path[PATH_MAX] = {0, };
231         void *module_data = NULL;
232         tbm_backend_module *backend_module_data = NULL;
233         tbm_backend_bufmgr_data *bufmgr_data = NULL;
234         int backend_module_major, backend_module_minor;
235         int tbm_backend_major, tbm_backend_minor;
236         tbm_error_e error;
237
238         snprintf(path, sizeof(path), BUFMGR_MODULE_DIR "/%s", file);
239
240         module_data = dlopen(path, RTLD_LAZY);
241         if (!module_data) {
242                 TBM_ERR("failed to load module: %s(%s)\n", dlerror(), file);
243                 return 0;
244         }
245
246         backend_module_data = dlsym(module_data, "tbm_backend_module_data");
247         if (!backend_module_data) {
248                 TBM_ERR("Error: module does not have data object.\n");
249                 goto err;
250         }
251
252         tbm_backend_major = GET_ABI_MAJOR(TBM_BACKEND_ABI_LATEST_VERSION);
253         tbm_backend_minor = GET_ABI_MINOR(TBM_BACKEND_ABI_LATEST_VERSION);
254         TBM_INFO("TBM Backend ABI version %d.%d\n", tbm_backend_major, tbm_backend_minor);
255
256         backend_module_major = GET_ABI_MAJOR(backend_module_data->abi_version);
257         backend_module_minor = GET_ABI_MINOR(backend_module_data->abi_version);
258
259         TBM_INFO("TBM module %s: vendor=\"%s\" Backend ABI version=%d.%d\n",
260             backend_module_data->name ? backend_module_data->name : "UNKNOWN!",
261             backend_module_data->vendor ? backend_module_data->vendor : "UNKNOWN!",
262                 backend_module_major, backend_module_minor);
263
264         if (backend_module_major > tbm_backend_major) {
265                 TBM_ERR("TBM module ABI major ver(%d) is newer than the TBM's ver(%d)\n",
266                         backend_module_major, tbm_backend_major);
267                 goto err;
268         } else if (backend_module_minor > tbm_backend_minor) {
269                 TBM_ERR("TBM module ABI minor ver(%d) is newer than the TBM's ver(%d)\n",
270                         backend_module_minor, tbm_backend_minor);
271                 goto err;
272         }
273
274         if (!backend_module_data->init) {
275                 TBM_ERR("Error: module does not supply init symbol.\n");
276                 goto err;
277         }
278
279         if (!backend_module_data->deinit)       {
280                 TBM_ERR("Error: module does not supply deinit symbol.\n");
281                 goto err;
282         }
283
284         bufmgr_data = backend_module_data->init((tbm_bufmgr)module, &error);
285         if (!bufmgr_data) {
286                 TBM_ERR("Fail to init module(%s)\n", file);
287                 goto err;
288         }
289
290         /* check the mandatory symbols of the backend module */
291         if (!_tbm_backend_check_bufmgr_func(module->bufmgr_func)) {
292                 TBM_ERR("Fail to check the bufmgr_func symboles.");
293                 goto err;
294         }
295
296         if (!_tbm_backend_check_bufmgr_bo(module->bo_func)) {
297                 TBM_ERR("Fail to check the bufmgr_bo symboles.");
298                 goto err;
299         }
300
301         module->module_data = module_data;
302         module->backend_module_data = backend_module_data;
303         module->bufmgr_data = bufmgr_data;
304
305         TBM_INFO("Success to load module(%s)\n", file);
306
307         return 1;
308
309 err:
310         if (bufmgr_data)
311                 module->backend_module_data->deinit(bufmgr_data);
312         if (module_data)
313                 dlclose(module_data);
314
315         return 0;
316 }
317
318 static int
319 _tbm_backend_load_bufmgr_module(tbm_module *module, int fd, const char *file)
320 {
321         char path[PATH_MAX] = {0, };
322         TBMModuleVersionInfo *vers;
323         TBMModuleData *initdata;
324         ModuleInitProc init;
325         void *module_data;
326
327         snprintf(path, sizeof(path), BUFMGR_MODULE_DIR "/%s", file);
328
329         module_data = dlopen(path, RTLD_LAZY);
330         if (!module_data) {
331                 TBM_ERR("failed to load module: %s(%s)\n", dlerror(), file);
332                 return 0;
333         }
334
335         initdata = dlsym(module_data, "tbmModuleData");
336         if (!initdata) {
337                 TBM_ERR("Error: module does not have data object.\n");
338                 goto err;
339         }
340
341         vers = initdata->vers;
342         if (!vers) {
343                 TBM_ERR("Error: module does not supply version information.\n");
344                 goto err;
345         }
346
347         init = initdata->init;
348         if (!init) {
349                 TBM_ERR("Error: module does not supply init symbol.\n");
350                 goto err;
351         }
352
353         if (!_check_version(vers)) {
354                 TBM_ERR("Fail to check version.\n");
355                 goto err;
356         }
357
358         if (!init((tbm_bufmgr)module, fd)) {
359                 TBM_ERR("Fail to init module(%s)\n", file);
360                 goto err;
361         }
362
363         if (!module->backend || !module->backend->priv) {
364                 TBM_ERR("Error: module(%s) wrong operation. Check backend or backend's priv.\n", file);
365                 goto err;
366         }
367
368         module->module_data = module_data;
369
370         TBM_DBG("Success to load module(%s)\n", file);
371
372         return 1;
373
374 err:
375         dlclose(module_data);
376         return 0;
377 }
378
379 /* LCOV_EXCL_STOP */
380
381 tbm_module *
382 tbm_module_load(tbm_bufmgr bufmgr, int fd)
383 {
384         tbm_module *module;
385         struct dirent **namelist;
386         int ret = 0, n;
387
388         module = calloc(1, sizeof(struct _tbm_module));
389         if (!module) {
390                 TBM_ERR("fail to allocate the memory");
391                 return NULL;
392         }
393         module->bufmgr = bufmgr;
394
395         /* try to load the hal-tbm backend module */
396         ret = _tbm_backend_load_hal_tbm(module);
397         if (ret) {
398                 module->type = TBM_MODULE_TYPE_HAL_TBM;
399                 goto done;
400         }
401
402         /* try to load the new backend module */
403         ret = _tbm_backend_load_module(module, DEFAULT_LIB);
404         if (ret) {
405                 module->type = TBM_MODULE_TYPE_TBM_BACKEND;
406                 goto done;
407         }
408
409         /* try to load the old(deprecated) backend mdoule */
410         ret = _tbm_backend_load_bufmgr_module(module, fd, DEFAULT_LIB);
411         if (ret) {
412                 module->type = TBM_MODULE_TYPE_BUFMGR_BACKEND;
413                 return module;
414         }
415
416         /* load bufmgr priv from configured path */
417         n = scandir(BUFMGR_MODULE_DIR, &namelist, 0, alphasort);
418         if (n < 0) {
419                 TBM_ERR("no files : %s\n", BUFMGR_MODULE_DIR);
420                 tbm_module_unload(module);
421                 return NULL;
422         }
423
424         while (n--) {
425                 if (!ret && strstr(namelist[n]->d_name, PREFIX_LIB)) {
426                         const char *p = strstr(namelist[n]->d_name, SUFFIX_LIB);
427
428                         if (p && !strcmp(p, SUFFIX_LIB)) {
429                                 ret = _tbm_backend_load_module(module, namelist[n]->d_name);
430                                 if (ret)
431                                         module->type = TBM_MODULE_TYPE_TBM_BACKEND;
432                                 else {
433                                         ret = _tbm_backend_load_bufmgr_module(module, fd, namelist[n]->d_name);
434                                         module->type = TBM_MODULE_TYPE_BUFMGR_BACKEND;
435                                 }
436                         }
437                 }
438
439                 free(namelist[n]);
440         }
441
442         free(namelist);
443
444         if (!ret) {
445                 free(module);
446                 module = NULL;
447         }
448
449 done:
450         if (module)
451                 _tbm_module_copy_data_to_bufmgr(module, module->bufmgr, 0);
452
453         return module;
454 }
455
456 void
457 tbm_module_unload(tbm_module *module)
458 {
459         switch (module->type) {
460         case TBM_MODULE_TYPE_HAL_TBM:
461                 if (module->auth_wl_socket_created) {
462                         tbm_drm_helper_wl_auth_server_deinit();
463                         close(module->auth_fd);
464                 }
465                 tbm_drm_helper_unset_tbm_master_fd();
466                 tbm_drm_helper_unset_fd();
467
468                 hal_tbm_put_backend(module->hal_backend);
469                 module->hal_backend = NULL;
470                 module->hal_bufmgr = NULL;
471                 module->use_hal_tbm = 0;
472                 break;
473         case TBM_MODULE_TYPE_TBM_BACKEND:
474                 module->backend_module_data->deinit(module->bufmgr_data);
475                 module->bo_func = NULL;
476                 module->bufmgr_func = NULL;
477                 module->bufmgr_data = NULL;
478                 module->backend_module_data = NULL;
479
480                 dlclose(module->module_data);
481                 break;
482         case TBM_MODULE_TYPE_BUFMGR_BACKEND:
483                 module->backend->bufmgr_deinit(module->backend->priv);
484                 module->backend->priv = NULL;
485                 tbm_backend_free(module->backend);
486                 module->backend = NULL;
487
488                 dlclose(module->module_data);
489                 break;
490         default:
491                 TBM_ERR("Wrong module type:%d", module->type);
492                 break;
493         }
494
495         _tbm_module_copy_data_to_bufmgr(module, module->bufmgr, 1);
496         module->bufmgr = NULL;
497
498         free(module);
499 }
500
501 int
502 tbm_module_bufmgr_get_capabilities(tbm_module *module)
503 {
504         tbm_error_e error = TBM_ERROR_NOT_SUPPORTED;
505         int capabilities = 0;
506
507         switch (module->type) {
508         case TBM_MODULE_TYPE_HAL_TBM:
509                 capabilities = hal_tbm_bufmgr_get_capabilities(module->hal_bufmgr, (hal_tbm_error *)&error);
510                 break;
511         case TBM_MODULE_TYPE_TBM_BACKEND:
512                 capabilities = module->bufmgr_func->bufmgr_get_capabilities(module->bufmgr_data, &error);
513                 break;
514         case TBM_MODULE_TYPE_BUFMGR_BACKEND:
515                 TBM_ERR("Do not support at tbm_bufmgr_backend.");
516                 break;
517         default:
518                 TBM_ERR("Wrong module type:%d", module->type);
519                 break;
520         }
521
522         if (error != TBM_ERROR_NONE) {
523                 TBM_ERR("fail to get capabilities of bufmgr");
524                 return 0;
525         }
526
527         return capabilities;
528 }