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 status: %d", caps->status);
306 TDM_DBG("output type : %d", caps->type);
307 for (i = 0; i < caps->prop_count; i++)
308 TDM_DBG("output props: %d, %s", caps->props[i].id, caps->props[i].name);
309 for (i = 0; i < caps->mode_count; i++)
310 TDM_DBG("output modes: name(%s), size(%dx%d), refresh(%d), flags(%d), type(%d)",
311 caps->modes[i].name, caps->modes[i].width, caps->modes[i].height,
312 caps->modes[i].refresh, caps->modes[i].flags, caps->modes[i].type);
313 TDM_DBG("output min : %dx%d", caps->min_w, caps->min_h);
314 TDM_DBG("output max : %dx%d", caps->max_w, caps->max_h);
315 TDM_DBG("output align: %d", caps->preferred_align);
317 return TDM_ERROR_NONE;
321 _tdm_display_update_layer(tdm_private_display *private_display,
322 tdm_private_output *private_output,
323 tdm_layer *layer_backend)
325 tdm_private_layer *private_layer;
328 private_layer = _tdm_display_find_private_layer(private_output, layer_backend);
331 private_layer = calloc(1, sizeof(tdm_private_layer));
332 TDM_RETURN_VAL_IF_FAIL(private_layer != NULL, TDM_ERROR_OUT_OF_MEMORY);
334 LIST_ADD(&private_layer->link, &private_output->layer_list);
335 private_layer->private_display = private_display;
336 private_layer->private_output = private_output;
337 private_layer->layer_backend = layer_backend;
339 LIST_INITHEAD(&private_layer->capture_list);
341 private_layer->usable = 1;
344 _tdm_display_destroy_caps_layer(&private_layer->caps);
346 ret = _tdm_display_update_caps_layer(private_display, layer_backend, &private_layer->caps);
347 if (ret != TDM_ERROR_NONE)
350 return TDM_ERROR_NONE;
352 _tdm_display_destroy_private_layer(private_layer);
357 _tdm_display_update_output(tdm_private_display *private_display,
358 tdm_output *output_backend, int pipe)
360 tdm_func_output *func_output = &private_display->func_output;
361 tdm_private_output *private_output = NULL;
362 tdm_layer **layers = NULL;
363 int layer_count = 0, i;
366 private_output = _tdm_display_find_private_output(private_display, output_backend);
369 private_output = calloc(1, sizeof(tdm_private_output));
370 TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_OUT_OF_MEMORY);
372 LIST_ADD(&private_output->link, &private_display->output_list);
373 private_output->private_display = private_display;
374 private_output->output_backend = output_backend;
375 private_output->pipe = pipe;
377 LIST_INITHEAD(&private_output->layer_list);
378 LIST_INITHEAD(&private_output->capture_list);
379 LIST_INITHEAD(&private_output->vblank_handler_list);
380 LIST_INITHEAD(&private_output->commit_handler_list);
383 _tdm_display_destroy_caps_output(&private_output->caps);
385 ret = _tdm_display_update_caps_output(private_display, output_backend, &private_output->caps);
386 if (ret != TDM_ERROR_NONE)
389 layers = func_output->output_get_layers(output_backend, &layer_count, &ret);
390 if (ret != TDM_ERROR_NONE)
393 for (i = 0; i < layer_count; i++)
395 ret = _tdm_display_update_layer(private_display, private_output, layers[i]);
396 if (ret != TDM_ERROR_NONE)
402 return TDM_ERROR_NONE;
404 _tdm_display_destroy_private_output(private_output);
410 _tdm_display_update_internal(tdm_private_display *private_display, int only_display)
412 tdm_func_display *func_display = &private_display->func_display;
413 tdm_output **outputs = NULL;
414 int output_count = 0, i;
417 LIST_INITHEAD(&private_display->output_list);
418 LIST_INITHEAD(&private_display->pp_list);
422 ret = _tdm_display_update_caps_pp(private_display, &private_display->caps_pp);
423 if (ret != TDM_ERROR_NONE)
426 ret = _tdm_display_update_caps_capture(private_display, &private_display->caps_capture);
427 if (ret != TDM_ERROR_NONE)
431 outputs = func_display->display_get_outputs(private_display->bdata, &output_count, &ret);
432 if (ret != TDM_ERROR_NONE)
435 for (i = 0; i < output_count; i++)
437 ret = _tdm_display_update_output(private_display, outputs[i], i);
438 if (ret != TDM_ERROR_NONE)
444 return TDM_ERROR_NONE;
447 _tdm_display_destroy_private_display(private_display);
454 tdm_display_update(tdm_display *dpy)
456 tdm_private_display *private_display;
459 TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER);
461 private_display = dpy;
462 pthread_mutex_lock(&private_display->lock);
464 ret = _tdm_display_update_internal(private_display, 1);
466 pthread_mutex_unlock(&private_display->lock);
471 #define SUFFIX_MODULE ".so"
472 #define DEFAULT_MODULE "libtdm-default"SUFFIX_MODULE
476 static tdm_private_display *g_private_display;
477 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
480 _tdm_display_check_module(tdm_backend_module *module)
487 abimaj = TDM_BACKEND_GET_ABI_MAJOR(TDM_BACKEND_ABI_VERSION);
488 abimin = TDM_BACKEND_GET_ABI_MINOR(TDM_BACKEND_ABI_VERSION);
490 TDM_INFO("TDM module ABI version : %d.%d", abimaj, abimin);
492 name = module->name ? module->name : "unknown";
493 vendor = module->vendor ? module->vendor : "unknown";
494 major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version);
495 minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version);
497 TDM_INFO("TDM module name: %s", name);
498 TDM_INFO("'%s' vendor: %s", name, vendor);
499 TDM_INFO("'%s' version: %d.%d", name, major, minor);
503 TDM_ERR("'%s' major version mismatch, %d != %d", name, major, abimaj);
504 return TDM_ERROR_BAD_MODULE;
509 TDM_ERR("'%s' minor version(%d) is newer than %d", name, minor, abimin);
510 return TDM_ERROR_BAD_MODULE;
515 TDM_ERR("'%s' doesn't have init function", name);
516 return TDM_ERROR_BAD_MODULE;
521 TDM_ERR("'%s' doesn't have deinit function", name);
522 return TDM_ERROR_BAD_MODULE;
525 return TDM_ERROR_NONE;
529 _tdm_display_check_backend_functions(tdm_private_display *private_display)
531 tdm_func_display *func_display = &private_display->func_display;
532 tdm_func_output *func_output = &private_display->func_output;
533 tdm_func_layer *func_layer = &private_display->func_layer;
536 /* below functions should be implemented in backend side */
538 TDM_RETURN_VAL_IF_FAIL(func_display != NULL, TDM_ERROR_BAD_MODULE);
539 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capabilitiy, TDM_ERROR_BAD_MODULE);
540 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_outputs, TDM_ERROR_BAD_MODULE);
541 TDM_RETURN_VAL_IF_FAIL(func_output->output_get_capability, TDM_ERROR_BAD_MODULE);
542 TDM_RETURN_VAL_IF_FAIL(func_output->output_get_layers, TDM_ERROR_BAD_MODULE);
543 TDM_RETURN_VAL_IF_FAIL(func_layer->layer_get_capability, TDM_ERROR_BAD_MODULE);
545 ret = func_display->display_get_capabilitiy(private_display->bdata,
546 &private_display->caps_display);
547 if (ret != TDM_ERROR_NONE)
549 TDM_ERR("display_get_capabilitiy() failed");
550 return TDM_ERROR_BAD_MODULE;
553 if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP)
555 tdm_func_pp *func_pp = &private_display->func_pp;
556 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_pp_capability, TDM_ERROR_BAD_MODULE);
557 TDM_RETURN_VAL_IF_FAIL(func_display->display_create_pp, TDM_ERROR_BAD_MODULE);
558 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_destroy, TDM_ERROR_BAD_MODULE);
559 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_commit, TDM_ERROR_BAD_MODULE);
560 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_set_done_handler, TDM_ERROR_BAD_MODULE);
563 if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)
565 tdm_func_capture *func_capture = &private_display->func_capture;
566 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability, TDM_ERROR_BAD_MODULE);
567 TDM_RETURN_VAL_IF_FAIL(func_output->output_create_capture, TDM_ERROR_BAD_MODULE);
568 TDM_RETURN_VAL_IF_FAIL(func_layer->layer_create_capture, TDM_ERROR_BAD_MODULE);
569 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE);
570 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE);
571 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler, TDM_ERROR_BAD_MODULE);
574 return TDM_ERROR_NONE;
578 _tdm_display_load_module_with_file(tdm_private_display *private_display, const char *file)
580 char path[PATH_MAX] = {0,};
581 tdm_backend_module *module_data;
585 snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
587 module = dlopen(path, RTLD_LAZY);
590 TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
591 return TDM_ERROR_BAD_MODULE;
594 module_data = dlsym(module, "tdm_backend_module_data");
597 TDM_ERR("'%s' doesn't have data object", file);
598 ret = TDM_ERROR_BAD_MODULE;
602 /* check if version, init() and deinit() are valid or not */
603 ret = _tdm_display_check_module(module_data);
604 if (ret != TDM_ERROR_NONE)
607 /* We don't care if backend_data is NULL or not. It's up to backend. */
608 private_display->bdata = module_data->init((tdm_display*)private_display, &ret);
609 if (ret != TDM_ERROR_NONE)
611 TDM_ERR("'%s' init failed", file);
615 ret = _tdm_display_check_backend_functions(private_display);
616 if (ret != TDM_ERROR_NONE)
618 module_data->deinit(private_display->bdata);
619 private_display->bdata = NULL;
623 private_display->module_data = module_data;
624 private_display->module = module;
626 TDM_INFO("Success to load module(%s)", file);
628 return TDM_ERROR_NONE;
635 _tdm_display_load_module(tdm_private_display *private_display)
637 const char *module_name;
638 struct dirent **namelist;
642 module_name = getenv("TDM_MODULE");
644 module_name = DEFAULT_MODULE;
646 /* load bufmgr priv from default lib */
647 ret = _tdm_display_load_module_with_file(private_display, module_name);
648 if (ret == TDM_ERROR_NONE)
649 return TDM_ERROR_NONE;
651 /* load bufmgr priv from configured path */
652 n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
655 TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
656 return TDM_ERROR_BAD_MODULE;
659 ret = TDM_ERROR_BAD_MODULE;
662 if (ret < 0 && strstr(namelist[n]->d_name, SUFFIX_MODULE))
663 ret = _tdm_display_load_module_with_file(private_display, namelist[n]->d_name);
673 _tdm_display_unload_module(tdm_private_display *private_display)
675 if (private_display->module_data)
676 private_display->module_data->deinit(private_display->bdata);
677 if (private_display->module)
678 dlclose(private_display->module);
680 private_display->bdata = NULL;
681 private_display->module_data = NULL;
682 private_display->module = NULL;
686 tdm_display_init(tdm_error *error)
688 tdm_private_display *private_display = NULL;
692 pthread_mutex_lock(&gLock);
694 if (g_private_display)
696 g_private_display->init_count++;
697 pthread_mutex_unlock(&gLock);
699 *error = TDM_ERROR_NONE;
700 return g_private_display;
703 debug = getenv("TDM_DEBUG");
704 if (debug && (strstr(debug, "1")))
707 private_display = calloc(1, sizeof(tdm_private_display));
708 if (!private_display)
710 ret = TDM_ERROR_OUT_OF_MEMORY;
711 TDM_ERR("'private_display != NULL' failed");
715 if (pthread_mutex_init(&private_display->lock, NULL))
717 ret = TDM_ERROR_OPERATION_FAILED;
718 TDM_ERR("mutex init failed: %m");
719 goto failed_mutex_init;
722 ret = _tdm_display_load_module(private_display);
723 if (ret != TDM_ERROR_NONE)
726 ret = _tdm_display_update_internal(private_display, 0);
727 if (ret != TDM_ERROR_NONE)
730 private_display->init_count = 1;
732 g_private_display = private_display;
735 *error = TDM_ERROR_NONE;
737 pthread_mutex_unlock(&gLock);
739 return (tdm_display*)private_display;
742 _tdm_display_unload_module(private_display);
744 pthread_mutex_destroy(&private_display->lock);
746 free(private_display);
751 pthread_mutex_unlock(&gLock);
756 tdm_display_deinit(tdm_display *dpy)
758 tdm_private_display *private_display = dpy;
760 if (!private_display)
763 pthread_mutex_lock(&gLock);
765 private_display->init_count--;
766 if (private_display->init_count > 0)
768 pthread_mutex_unlock(&gLock);
772 pthread_mutex_lock(&private_display->lock);
774 _tdm_display_destroy_private_display(private_display);
775 _tdm_display_unload_module(private_display);
777 pthread_mutex_unlock(&private_display->lock);
779 pthread_mutex_destroy(&private_display->lock);
780 free(private_display);
783 pthread_mutex_unlock(&gLock);