1 /**************************************************************************
5 Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
7 Contact: Eunchul Kim <chulspro.kim@samsung.com>,
8 JinYoung Jeon <jy0.jeon@samsung.com>,
9 Taeheon Kim <th908.kim@samsung.com>,
10 YoungJun Cho <yj44.cho@samsung.com>,
11 SooChan Lim <sc1.lim@samsung.com>,
12 Boram Park <sc1.lim@samsung.com>
14 Permission is hereby granted, free of charge, to any person obtaining a
15 copy of this software and associated documentation files (the
16 "Software"), to deal in the Software without restriction, including
17 without limitation the rights to use, copy, modify, merge, publish,
18 distribute, sub license, and/or sell copies of the Software, and to
19 permit persons to whom the Software is furnished to do so, subject to
20 the following conditions:
22 The above copyright notice and this permission notice (including the
23 next paragraph) shall be included in all copies or substantial portions
26 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
29 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
30 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
31 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
32 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 **************************************************************************/
41 #include "tdm_backend.h"
42 #include "tdm_private.h"
44 static tdm_private_layer*
45 _tdm_display_find_private_layer(tdm_private_output *private_output, tdm_layer *layer_backend)
47 tdm_private_layer *private_layer = NULL;
49 LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link)
51 if (private_layer->layer_backend == layer_backend)
58 static tdm_private_output*
59 _tdm_display_find_private_output(tdm_private_display *private_display, tdm_output *output_backend)
61 tdm_private_output *private_output = NULL;
63 LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link)
65 if (private_output->output_backend == output_backend)
66 return private_output;
73 _tdm_display_destroy_caps_pp(tdm_caps_pp *caps_pp)
75 free(caps_pp->formats);
76 memset(caps_pp, 0, sizeof(tdm_caps_pp));
80 _tdm_display_destroy_caps_capture(tdm_caps_capture *caps_capture)
82 free(caps_capture->formats);
83 memset(caps_capture, 0, sizeof(tdm_caps_capture));
87 _tdm_display_destroy_caps_layer(tdm_caps_layer *caps_layer)
89 free(caps_layer->formats);
90 free(caps_layer->props);
91 memset(caps_layer, 0, sizeof(tdm_caps_layer));
95 _tdm_display_destroy_caps_output(tdm_caps_output *caps_output)
97 free(caps_output->modes);
98 free(caps_output->props);
99 memset(caps_output, 0, sizeof(tdm_caps_output));
103 _tdm_display_destroy_private_layer(tdm_private_layer *private_layer)
105 tdm_private_capture *c = NULL, *cc = NULL;
107 LIST_DEL(&private_layer->link);
109 LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_layer->capture_list, link)
110 tdm_capture_destroy_internal(c);
112 _tdm_display_destroy_caps_layer(&private_layer->caps);
118 _tdm_display_destroy_private_output(tdm_private_output *private_output)
120 tdm_private_layer *l = NULL, *ll = NULL;
121 tdm_private_capture *c = NULL, *cc = NULL;
122 tdm_private_vblank_handler *v = NULL, *vv = NULL;
123 tdm_private_commit_handler *m = NULL, *mm = NULL;
125 LIST_DEL(&private_output->link);
127 free(private_output->layers_ptr);
129 LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_handler_list, link)
135 LIST_FOR_EACH_ENTRY_SAFE(m, mm, &private_output->commit_handler_list, link)
141 LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_output->capture_list, link)
142 tdm_capture_destroy_internal(c);
144 LIST_FOR_EACH_ENTRY_SAFE(l, ll, &private_output->layer_list, link)
145 _tdm_display_destroy_private_layer(l);
147 _tdm_display_destroy_caps_output(&private_output->caps);
149 free(private_output);
153 _tdm_display_destroy_private_display(tdm_private_display *private_display)
155 tdm_private_output *o = NULL, *oo = NULL;
156 tdm_private_pp *p = NULL, *pp = NULL;
158 free(private_display->outputs_ptr);
160 LIST_FOR_EACH_ENTRY_SAFE(p, pp, &private_display->pp_list, link)
161 tdm_pp_destroy_internal(p);
163 LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_display->output_list, link)
164 _tdm_display_destroy_private_output(o);
166 _tdm_display_destroy_caps_pp(&private_display->caps_pp);
167 _tdm_display_destroy_caps_capture(&private_display->caps_capture);
169 private_display->capabilities = 0;
170 private_display->caps_display.max_layer_count = -1;
174 _tdm_display_update_caps_pp(tdm_private_display *private_display, tdm_caps_pp *caps)
176 tdm_func_display *func_display = &private_display->func_display;
178 int bufsize = sizeof(buf);
180 int *len_buf = &bufsize;
184 if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP))
185 return TDM_ERROR_NONE;
187 if (!func_display->display_get_pp_capability)
189 TDM_ERR("no display_get_pp_capability()");
190 return TDM_ERROR_BAD_MODULE;
193 ret = func_display->display_get_pp_capability(private_display->bdata, caps);
194 if (ret != TDM_ERROR_NONE)
196 TDM_ERR("display_get_pp_capability() failed");
197 return TDM_ERROR_BAD_MODULE;
200 TDM_DBG("pp capabilities: %x", caps->capabilities);
202 for (i = 0; i < caps->format_count; i++)
203 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
204 TDM_DBG("pp formats: %s", buf);
205 TDM_DBG("pp min : %dx%d", caps->min_w, caps->min_h);
206 TDM_DBG("pp max : %dx%d", caps->max_w, caps->max_h);
207 TDM_DBG("pp align: %d", caps->preferred_align);
209 return TDM_ERROR_NONE;
213 _tdm_display_update_caps_capture(tdm_private_display *private_display, tdm_caps_capture *caps)
215 tdm_func_display *func_display = &private_display->func_display;
217 int bufsize = sizeof(buf);
219 int *len_buf = &bufsize;
223 if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE))
224 return TDM_ERROR_NONE;
226 if (!func_display->display_get_capture_capability)
228 TDM_ERR("no display_get_capture_capability()");
229 return TDM_ERROR_BAD_MODULE;
232 ret = func_display->display_get_capture_capability(private_display->bdata, caps);
233 if (ret != TDM_ERROR_NONE)
235 TDM_ERR("display_get_capture_capability() failed");
236 return TDM_ERROR_BAD_MODULE;
240 for (i = 0; i < caps->format_count; i++)
241 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
242 TDM_DBG("capture formats: %s", buf);
244 return TDM_ERROR_NONE;
248 _tdm_display_update_caps_layer(tdm_private_display *private_display,
249 tdm_layer *layer_backend, tdm_caps_layer *caps)
251 tdm_func_layer *func_layer = &private_display->func_layer;
253 int bufsize = sizeof(buf);
255 int *len_buf = &bufsize;
259 if (!func_layer->layer_get_capability)
261 TDM_ERR("no layer_get_capability()");
262 return TDM_ERROR_BAD_MODULE;
265 ret = func_layer->layer_get_capability(layer_backend, caps);
266 if (ret != TDM_ERROR_NONE)
268 TDM_ERR("layer_get_capability() failed");
269 return TDM_ERROR_BAD_MODULE;
272 TDM_DBG("layer capabilities: %x", caps->capabilities);
273 TDM_DBG("layer zpos : %d", caps->zpos);
275 for (i = 0; i < caps->format_count; i++)
276 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
277 TDM_DBG("layer formats: %s", buf);
278 for (i = 0; i < caps->prop_count; i++)
279 TDM_DBG("layer props: %d, %s", caps->props[i].id, caps->props[i].name);
281 return TDM_ERROR_NONE;
285 _tdm_display_update_caps_output(tdm_private_display *private_display,
286 tdm_output *output_backend, tdm_caps_output *caps)
288 tdm_func_output *func_output = &private_display->func_output;
292 if (!func_output->output_get_capability)
294 TDM_ERR("no output_get_capability()");
295 return TDM_ERROR_BAD_MODULE;
298 ret = func_output->output_get_capability(output_backend, caps);
299 if (ret != TDM_ERROR_NONE)
301 TDM_ERR("output_get_capability() failed");
302 return TDM_ERROR_BAD_MODULE;
305 TDM_DBG("output maker: %s", caps->maker);
306 TDM_DBG("output model: %s", caps->model);
307 TDM_DBG("output name: %s", caps->name);
308 TDM_DBG("output status: %d", caps->status);
309 TDM_DBG("output type : %d", caps->type);
310 for (i = 0; i < caps->prop_count; i++)
311 TDM_DBG("output props: %d, %s", caps->props[i].id, caps->props[i].name);
312 for (i = 0; i < caps->mode_count; i++)
313 TDM_DBG("output modes: name(%s), size(%dx%d), refresh(%d), flags(%d), type(%d)",
314 caps->modes[i].name, caps->modes[i].width, caps->modes[i].height,
315 caps->modes[i].refresh, caps->modes[i].flags, caps->modes[i].type);
316 TDM_DBG("output min : %dx%d", caps->min_w, caps->min_h);
317 TDM_DBG("output max : %dx%d", caps->max_w, caps->max_h);
318 TDM_DBG("output align: %d", caps->preferred_align);
320 return TDM_ERROR_NONE;
324 _tdm_display_update_layer(tdm_private_display *private_display,
325 tdm_private_output *private_output,
326 tdm_layer *layer_backend)
328 tdm_private_layer *private_layer;
331 private_layer = _tdm_display_find_private_layer(private_output, layer_backend);
334 private_layer = calloc(1, sizeof(tdm_private_layer));
335 TDM_RETURN_VAL_IF_FAIL(private_layer != NULL, TDM_ERROR_OUT_OF_MEMORY);
337 LIST_ADD(&private_layer->link, &private_output->layer_list);
338 private_layer->private_display = private_display;
339 private_layer->private_output = private_output;
340 private_layer->layer_backend = layer_backend;
342 LIST_INITHEAD(&private_layer->capture_list);
344 private_layer->usable = 1;
347 _tdm_display_destroy_caps_layer(&private_layer->caps);
349 ret = _tdm_display_update_caps_layer(private_display, layer_backend, &private_layer->caps);
350 if (ret != TDM_ERROR_NONE)
353 return TDM_ERROR_NONE;
355 _tdm_display_destroy_private_layer(private_layer);
360 _tdm_display_update_output(tdm_private_display *private_display,
361 tdm_output *output_backend, int pipe)
363 tdm_func_output *func_output = &private_display->func_output;
364 tdm_private_output *private_output = NULL;
365 tdm_layer **layers = NULL;
366 int layer_count = 0, i;
369 private_output = _tdm_display_find_private_output(private_display, output_backend);
372 private_output = calloc(1, sizeof(tdm_private_output));
373 TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_OUT_OF_MEMORY);
375 LIST_ADD(&private_output->link, &private_display->output_list);
376 private_output->private_display = private_display;
377 private_output->output_backend = output_backend;
378 private_output->pipe = pipe;
380 LIST_INITHEAD(&private_output->layer_list);
381 LIST_INITHEAD(&private_output->capture_list);
382 LIST_INITHEAD(&private_output->vblank_handler_list);
383 LIST_INITHEAD(&private_output->commit_handler_list);
386 _tdm_display_destroy_caps_output(&private_output->caps);
388 ret = _tdm_display_update_caps_output(private_display, output_backend, &private_output->caps);
389 if (ret != TDM_ERROR_NONE)
392 layers = func_output->output_get_layers(output_backend, &layer_count, &ret);
393 if (ret != TDM_ERROR_NONE)
396 for (i = 0; i < layer_count; i++)
398 ret = _tdm_display_update_layer(private_display, private_output, layers[i]);
399 if (ret != TDM_ERROR_NONE)
405 return TDM_ERROR_NONE;
407 _tdm_display_destroy_private_output(private_output);
413 _tdm_display_update_internal(tdm_private_display *private_display, int only_display)
415 tdm_func_display *func_display = &private_display->func_display;
416 tdm_output **outputs = NULL;
417 int output_count = 0, i;
420 LIST_INITHEAD(&private_display->output_list);
421 LIST_INITHEAD(&private_display->pp_list);
425 ret = _tdm_display_update_caps_pp(private_display, &private_display->caps_pp);
426 if (ret != TDM_ERROR_NONE)
429 ret = _tdm_display_update_caps_capture(private_display, &private_display->caps_capture);
430 if (ret != TDM_ERROR_NONE)
434 outputs = func_display->display_get_outputs(private_display->bdata, &output_count, &ret);
435 if (ret != TDM_ERROR_NONE)
438 for (i = 0; i < output_count; i++)
440 ret = _tdm_display_update_output(private_display, outputs[i], i);
441 if (ret != TDM_ERROR_NONE)
447 return TDM_ERROR_NONE;
450 _tdm_display_destroy_private_display(private_display);
457 tdm_display_update(tdm_display *dpy)
459 tdm_private_display *private_display;
462 TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER);
464 private_display = dpy;
465 pthread_mutex_lock(&private_display->lock);
467 ret = _tdm_display_update_internal(private_display, 1);
469 pthread_mutex_unlock(&private_display->lock);
474 #define SUFFIX_MODULE ".so"
475 #define DEFAULT_MODULE "libtdm-default"SUFFIX_MODULE
479 static tdm_private_display *g_private_display;
480 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
483 _tdm_display_check_module(tdm_backend_module *module)
490 abimaj = TDM_BACKEND_GET_ABI_MAJOR(TDM_BACKEND_ABI_VERSION);
491 abimin = TDM_BACKEND_GET_ABI_MINOR(TDM_BACKEND_ABI_VERSION);
493 TDM_INFO("TDM module ABI version : %d.%d", abimaj, abimin);
495 name = module->name ? module->name : "unknown";
496 vendor = module->vendor ? module->vendor : "unknown";
497 major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version);
498 minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version);
500 TDM_INFO("TDM module name: %s", name);
501 TDM_INFO("'%s' vendor: %s", name, vendor);
502 TDM_INFO("'%s' version: %d.%d", name, major, minor);
506 TDM_ERR("'%s' major version mismatch, %d != %d", name, major, abimaj);
507 return TDM_ERROR_BAD_MODULE;
512 TDM_ERR("'%s' minor version(%d) is newer than %d", name, minor, abimin);
513 return TDM_ERROR_BAD_MODULE;
518 TDM_ERR("'%s' doesn't have init function", name);
519 return TDM_ERROR_BAD_MODULE;
524 TDM_ERR("'%s' doesn't have deinit function", name);
525 return TDM_ERROR_BAD_MODULE;
528 return TDM_ERROR_NONE;
532 _tdm_display_check_backend_functions(tdm_private_display *private_display)
534 tdm_func_display *func_display = &private_display->func_display;
535 tdm_func_output *func_output = &private_display->func_output;
536 tdm_func_layer *func_layer = &private_display->func_layer;
539 /* below functions should be implemented in backend side */
541 TDM_RETURN_VAL_IF_FAIL(func_display != NULL, TDM_ERROR_BAD_MODULE);
542 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capabilitiy, TDM_ERROR_BAD_MODULE);
543 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_outputs, TDM_ERROR_BAD_MODULE);
544 TDM_RETURN_VAL_IF_FAIL(func_output->output_get_capability, TDM_ERROR_BAD_MODULE);
545 TDM_RETURN_VAL_IF_FAIL(func_output->output_get_layers, TDM_ERROR_BAD_MODULE);
546 TDM_RETURN_VAL_IF_FAIL(func_layer->layer_get_capability, TDM_ERROR_BAD_MODULE);
548 ret = func_display->display_get_capabilitiy(private_display->bdata,
549 &private_display->caps_display);
550 if (ret != TDM_ERROR_NONE)
552 TDM_ERR("display_get_capabilitiy() failed");
553 return TDM_ERROR_BAD_MODULE;
556 if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP)
558 tdm_func_pp *func_pp = &private_display->func_pp;
559 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_pp_capability, TDM_ERROR_BAD_MODULE);
560 TDM_RETURN_VAL_IF_FAIL(func_display->display_create_pp, TDM_ERROR_BAD_MODULE);
561 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_destroy, TDM_ERROR_BAD_MODULE);
562 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_commit, TDM_ERROR_BAD_MODULE);
563 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_set_done_handler, TDM_ERROR_BAD_MODULE);
566 if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)
568 tdm_func_capture *func_capture = &private_display->func_capture;
569 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability, TDM_ERROR_BAD_MODULE);
570 TDM_RETURN_VAL_IF_FAIL(func_output->output_create_capture, TDM_ERROR_BAD_MODULE);
571 TDM_RETURN_VAL_IF_FAIL(func_layer->layer_create_capture, TDM_ERROR_BAD_MODULE);
572 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE);
573 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE);
574 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler, TDM_ERROR_BAD_MODULE);
577 return TDM_ERROR_NONE;
581 _tdm_display_load_module_with_file(tdm_private_display *private_display, const char *file)
583 char path[PATH_MAX] = {0,};
584 tdm_backend_module *module_data;
588 snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
590 module = dlopen(path, RTLD_LAZY);
593 TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
594 return TDM_ERROR_BAD_MODULE;
597 module_data = dlsym(module, "tdm_backend_module_data");
600 TDM_ERR("'%s' doesn't have data object", file);
601 ret = TDM_ERROR_BAD_MODULE;
605 /* check if version, init() and deinit() are valid or not */
606 ret = _tdm_display_check_module(module_data);
607 if (ret != TDM_ERROR_NONE)
610 /* We don't care if backend_data is NULL or not. It's up to backend. */
611 private_display->bdata = module_data->init((tdm_display*)private_display, &ret);
612 if (ret != TDM_ERROR_NONE)
614 TDM_ERR("'%s' init failed", file);
618 ret = _tdm_display_check_backend_functions(private_display);
619 if (ret != TDM_ERROR_NONE)
621 module_data->deinit(private_display->bdata);
622 private_display->bdata = NULL;
626 private_display->module_data = module_data;
627 private_display->module = module;
629 TDM_INFO("Success to load module(%s)", file);
631 return TDM_ERROR_NONE;
638 _tdm_display_load_module(tdm_private_display *private_display)
640 const char *module_name;
641 struct dirent **namelist;
645 module_name = getenv("TDM_MODULE");
647 module_name = DEFAULT_MODULE;
649 /* load bufmgr priv from default lib */
650 ret = _tdm_display_load_module_with_file(private_display, module_name);
651 if (ret == TDM_ERROR_NONE)
652 return TDM_ERROR_NONE;
654 /* load bufmgr priv from configured path */
655 n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
658 TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
659 return TDM_ERROR_BAD_MODULE;
662 ret = TDM_ERROR_BAD_MODULE;
665 if (ret < 0 && strstr(namelist[n]->d_name, SUFFIX_MODULE))
666 ret = _tdm_display_load_module_with_file(private_display, namelist[n]->d_name);
676 _tdm_display_unload_module(tdm_private_display *private_display)
678 if (private_display->module_data)
679 private_display->module_data->deinit(private_display->bdata);
680 if (private_display->module)
681 dlclose(private_display->module);
683 private_display->bdata = NULL;
684 private_display->module_data = NULL;
685 private_display->module = NULL;
689 tdm_display_init(tdm_error *error)
691 tdm_private_display *private_display = NULL;
695 pthread_mutex_lock(&gLock);
697 if (g_private_display)
699 g_private_display->init_count++;
700 pthread_mutex_unlock(&gLock);
702 *error = TDM_ERROR_NONE;
703 return g_private_display;
706 debug = getenv("TDM_DEBUG");
707 if (debug && (strstr(debug, "1")))
710 private_display = calloc(1, sizeof(tdm_private_display));
711 if (!private_display)
713 ret = TDM_ERROR_OUT_OF_MEMORY;
714 TDM_ERR("'private_display != NULL' failed");
718 if (pthread_mutex_init(&private_display->lock, NULL))
720 ret = TDM_ERROR_OPERATION_FAILED;
721 TDM_ERR("mutex init failed: %m");
722 goto failed_mutex_init;
725 ret = _tdm_display_load_module(private_display);
726 if (ret != TDM_ERROR_NONE)
729 ret = _tdm_display_update_internal(private_display, 0);
730 if (ret != TDM_ERROR_NONE)
733 private_display->init_count = 1;
735 g_private_display = private_display;
738 *error = TDM_ERROR_NONE;
740 pthread_mutex_unlock(&gLock);
742 return (tdm_display*)private_display;
745 _tdm_display_unload_module(private_display);
747 pthread_mutex_destroy(&private_display->lock);
749 free(private_display);
754 pthread_mutex_unlock(&gLock);
759 tdm_display_deinit(tdm_display *dpy)
761 tdm_private_display *private_display = dpy;
763 if (!private_display)
766 pthread_mutex_lock(&gLock);
768 private_display->init_count--;
769 if (private_display->init_count > 0)
771 pthread_mutex_unlock(&gLock);
775 pthread_mutex_lock(&private_display->lock);
777 _tdm_display_destroy_private_display(private_display);
778 _tdm_display_unload_module(private_display);
780 pthread_mutex_unlock(&private_display->lock);
782 pthread_mutex_destroy(&private_display->lock);
783 free(private_display);
786 pthread_mutex_unlock(&gLock);