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)
47 tdm_private_layer *private_layer = NULL;
49 LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link)
51 if (private_layer->layer == layer)
58 static tdm_private_output*
59 _tdm_display_find_private_output(tdm_private_display *private_display, tdm_output *output)
61 tdm_private_output *private_output = NULL;
63 LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link)
65 if (private_output->output == output)
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, tdm_layer *layer, tdm_caps_layer *caps)
250 tdm_func_display *func_display = &private_display->func_display;
252 int bufsize = sizeof(buf);
254 int *len_buf = &bufsize;
258 if (!func_display->layer_get_capability)
260 TDM_ERR("no layer_get_capability()");
261 return TDM_ERROR_BAD_MODULE;
264 ret = func_display->layer_get_capability(layer, caps);
265 if (ret != TDM_ERROR_NONE)
267 TDM_ERR("layer_get_capability() failed");
268 return TDM_ERROR_BAD_MODULE;
271 TDM_DBG("layer capabilities: %x", caps->capabilities);
272 TDM_DBG("layer zpos : %d", caps->zpos);
274 for (i = 0; i < caps->format_count; i++)
275 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
276 TDM_DBG("layer formats: %s", buf);
277 for (i = 0; i < caps->prop_count; i++)
278 TDM_DBG("layer props: %d, %s", caps->props[i].id, caps->props[i].name);
280 return TDM_ERROR_NONE;
284 _tdm_display_update_caps_output(tdm_private_display *private_display, tdm_output *output, tdm_caps_output *caps)
286 tdm_func_display *func_display = &private_display->func_display;
290 if (!func_display->output_get_capability)
292 TDM_ERR("no output_get_capability()");
293 return TDM_ERROR_BAD_MODULE;
296 ret = func_display->output_get_capability(output, caps);
297 if (ret != TDM_ERROR_NONE)
299 TDM_ERR("output_get_capability() failed");
300 return TDM_ERROR_BAD_MODULE;
303 TDM_DBG("output status: %d", caps->status);
304 TDM_DBG("output type : %d", caps->type);
305 for (i = 0; i < caps->prop_count; i++)
306 TDM_DBG("output props: %d, %s", caps->props[i].id, caps->props[i].name);
307 for (i = 0; i < caps->mode_count; i++)
308 TDM_DBG("output modes: name(%s), size(%dx%d), refresh(%d), flags(%d), type(%d)",
309 caps->modes[i]->name, caps->modes[i]->width, caps->modes[i]->height,
310 caps->modes[i]->refresh, caps->modes[i]->flags, caps->modes[i]->type);
311 TDM_DBG("output min : %dx%d", caps->min_w, caps->min_h);
312 TDM_DBG("output max : %dx%d", caps->max_w, caps->max_h);
313 TDM_DBG("output align: %d", caps->preferred_align);
315 return TDM_ERROR_NONE;
319 _tdm_display_update_layer(tdm_private_display *private_display,
320 tdm_private_output *private_output,
323 tdm_private_layer *private_layer;
326 private_layer = _tdm_display_find_private_layer(private_output, layer);
329 private_layer = calloc(1, sizeof(tdm_private_layer));
330 TDM_RETURN_VAL_IF_FAIL(private_layer != NULL, TDM_ERROR_OUT_OF_MEMORY);
332 LIST_ADD(&private_layer->link, &private_output->layer_list);
333 private_layer->func_display = &private_display->func_display;
334 private_layer->private_display = private_display;
335 private_layer->private_output = private_output;
336 private_layer->layer = layer;
338 LIST_INITHEAD(&private_layer->capture_list);
340 private_layer->usable = 1;
343 _tdm_display_destroy_caps_layer(&private_layer->caps);
345 ret = _tdm_display_update_caps_layer(private_display, layer, &private_layer->caps);
346 if (ret != TDM_ERROR_NONE)
349 return TDM_ERROR_NONE;
351 _tdm_display_destroy_private_layer(private_layer);
356 _tdm_display_update_output(tdm_private_display *private_display, tdm_output *output, int pipe)
358 tdm_func_display *func_display = &private_display->func_display;
359 tdm_private_output *private_output = NULL;
360 tdm_layer **layers = NULL;
361 int layer_count = 0, i;
364 private_output = _tdm_display_find_private_output(private_display, output);
367 private_output = calloc(1, sizeof(tdm_private_output));
368 TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_OUT_OF_MEMORY);
370 LIST_ADD(&private_output->link, &private_display->output_list);
371 private_output->func_display = func_display;
372 private_output->private_display = private_display;
373 private_output->output = output;
374 private_output->pipe = pipe;
376 LIST_INITHEAD(&private_output->layer_list);
377 LIST_INITHEAD(&private_output->capture_list);
378 LIST_INITHEAD(&private_output->vblank_handler_list);
379 LIST_INITHEAD(&private_output->commit_handler_list);
382 _tdm_display_destroy_caps_output(&private_output->caps);
384 ret = _tdm_display_update_caps_output(private_display, output, &private_output->caps);
385 if (ret != TDM_ERROR_NONE)
388 layers = func_display->output_get_layers(output, &layer_count, &ret);
389 if (ret != TDM_ERROR_NONE)
392 for (i = 0; i < layer_count; i++)
394 ret = _tdm_display_update_layer(private_display, private_output, layers[i]);
395 if (ret != TDM_ERROR_NONE)
401 return TDM_ERROR_NONE;
403 _tdm_display_destroy_private_output(private_output);
409 _tdm_display_update_internal(tdm_private_display *private_display, int only_display)
411 tdm_func_display *func_display = &private_display->func_display;
412 tdm_output **outputs = NULL;
413 int output_count = 0, i;
416 LIST_INITHEAD(&private_display->output_list);
417 LIST_INITHEAD(&private_display->pp_list);
421 ret = _tdm_display_update_caps_pp(private_display, &private_display->caps_pp);
422 if (ret != TDM_ERROR_NONE)
425 ret = _tdm_display_update_caps_capture(private_display, &private_display->caps_capture);
426 if (ret != TDM_ERROR_NONE)
430 outputs = func_display->display_get_outputs(private_display->bdata, &output_count, &ret);
431 if (ret != TDM_ERROR_NONE)
434 for (i = 0; i < output_count; i++)
436 ret = _tdm_display_update_output(private_display, outputs[i], i);
437 if (ret != TDM_ERROR_NONE)
443 return TDM_ERROR_NONE;
446 _tdm_display_destroy_private_display(private_display);
453 tdm_display_update(tdm_display *dpy)
455 tdm_private_display *private_display;
458 TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER);
460 private_display = dpy;
461 pthread_mutex_lock(&private_display->lock);
463 ret = _tdm_display_update_internal(private_display, 1);
465 pthread_mutex_unlock(&private_display->lock);
470 #define SUFFIX_MODULE ".so"
471 #define DEFAULT_MODULE "libtdm-default"SUFFIX_MODULE
475 static tdm_private_display *g_private_display;
476 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
479 _tdm_display_check_module(tdm_backend_module *module)
486 abimaj = TDM_BACKEND_GET_ABI_MAJOR(TDM_BACKEND_ABI_VERSION);
487 abimin = TDM_BACKEND_GET_ABI_MINOR(TDM_BACKEND_ABI_VERSION);
489 TDM_INFO("TDM module ABI version : %d.%d", abimaj, abimin);
491 name = module->name ? module->name : "unknown";
492 vendor = module->vendor ? module->vendor : "unknown";
493 major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version);
494 minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version);
496 TDM_INFO("TDM module name: %s", name);
497 TDM_INFO("'%s' vendor: %s", name, vendor);
498 TDM_INFO("'%s' version: %d.%d", name, major, minor);
502 TDM_ERR("'%s' major version mismatch, %d != %d", name, major, abimaj);
503 return TDM_ERROR_BAD_MODULE;
508 TDM_ERR("'%s' minor version(%d) is newer than %d", name, minor, abimin);
509 return TDM_ERROR_BAD_MODULE;
514 TDM_ERR("'%s' doesn't have init function", name);
515 return TDM_ERROR_BAD_MODULE;
520 TDM_ERR("'%s' doesn't have deinit function", name);
521 return TDM_ERROR_BAD_MODULE;
524 return TDM_ERROR_NONE;
528 _tdm_display_check_backend_functions(tdm_private_display *private_display)
530 tdm_func_display *func_display = &private_display->func_display;
533 /* below functions should be implemented in backend side */
535 TDM_RETURN_VAL_IF_FAIL(func_display != NULL, TDM_ERROR_BAD_MODULE);
536 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capabilitiy, TDM_ERROR_BAD_MODULE);
537 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_outputs, TDM_ERROR_BAD_MODULE);
538 TDM_RETURN_VAL_IF_FAIL(func_display->output_get_capability, TDM_ERROR_BAD_MODULE);
539 TDM_RETURN_VAL_IF_FAIL(func_display->output_get_layers, TDM_ERROR_BAD_MODULE);
540 TDM_RETURN_VAL_IF_FAIL(func_display->layer_get_capability, TDM_ERROR_BAD_MODULE);
542 ret = func_display->display_get_capabilitiy(private_display->bdata,
543 &private_display->caps_display);
544 if (ret != TDM_ERROR_NONE)
546 TDM_ERR("display_get_capabilitiy() failed");
547 return TDM_ERROR_BAD_MODULE;
550 if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP)
552 tdm_func_pp *func_pp = &private_display->func_pp;
553 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_pp_capability, TDM_ERROR_BAD_MODULE);
554 TDM_RETURN_VAL_IF_FAIL(func_display->display_create_pp, TDM_ERROR_BAD_MODULE);
555 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_destroy, TDM_ERROR_BAD_MODULE);
556 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_commit, TDM_ERROR_BAD_MODULE);
557 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_set_done_handler, TDM_ERROR_BAD_MODULE);
560 if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)
562 tdm_func_capture *func_capture = &private_display->func_capture;
563 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability, TDM_ERROR_BAD_MODULE);
564 TDM_RETURN_VAL_IF_FAIL(func_display->output_create_capture, TDM_ERROR_BAD_MODULE);
565 TDM_RETURN_VAL_IF_FAIL(func_display->layer_create_capture, TDM_ERROR_BAD_MODULE);
566 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE);
567 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE);
568 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler, TDM_ERROR_BAD_MODULE);
571 return TDM_ERROR_NONE;
575 _tdm_display_load_module_with_file(tdm_private_display *private_display, const char *file)
577 char path[PATH_MAX] = {0,};
578 tdm_backend_module *module_data;
582 snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
584 module = dlopen(path, RTLD_LAZY);
587 TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
588 return TDM_ERROR_BAD_MODULE;
591 module_data = dlsym(module, "tdm_backend_module_data");
594 TDM_ERR("'%s' doesn't have data object", file);
595 ret = TDM_ERROR_BAD_MODULE;
599 /* check if version, init() and deinit() are valid or not */
600 ret = _tdm_display_check_module(module_data);
601 if (ret != TDM_ERROR_NONE)
604 /* We don't care if backend_data is NULL or not. It's up to backend. */
605 private_display->bdata = module_data->init((tdm_display*)private_display, &ret);
606 if (ret != TDM_ERROR_NONE)
608 TDM_ERR("'%s' init failed", file);
612 ret = _tdm_display_check_backend_functions(private_display);
613 if (ret != TDM_ERROR_NONE)
615 module_data->deinit(private_display->bdata);
616 private_display->bdata = NULL;
620 private_display->module_data = module_data;
621 private_display->module = module;
623 TDM_INFO("Success to load module(%s)", file);
625 return TDM_ERROR_NONE;
632 _tdm_display_load_module(tdm_private_display *private_display)
634 const char *module_name;
635 struct dirent **namelist;
639 module_name = getenv("TDM_MODULE");
641 module_name = DEFAULT_MODULE;
643 /* load bufmgr priv from default lib */
644 ret = _tdm_display_load_module_with_file(private_display, module_name);
645 if (ret == TDM_ERROR_NONE)
646 return TDM_ERROR_NONE;
648 /* load bufmgr priv from configured path */
649 n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
652 TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
653 return TDM_ERROR_BAD_MODULE;
656 ret = TDM_ERROR_BAD_MODULE;
659 if (ret < 0 && strstr(namelist[n]->d_name, SUFFIX_MODULE))
660 ret = _tdm_display_load_module_with_file(private_display, namelist[n]->d_name);
670 _tdm_display_unload_module(tdm_private_display *private_display)
672 if (private_display->module_data)
673 private_display->module_data->deinit(private_display->bdata);
674 if (private_display->module)
675 dlclose(private_display->module);
677 private_display->bdata = NULL;
678 private_display->module_data = NULL;
679 private_display->module = NULL;
683 tdm_display_init(tdm_error *error)
685 tdm_private_display *private_display = NULL;
689 pthread_mutex_lock(&gLock);
691 if (g_private_display)
693 g_private_display->init_count++;
694 pthread_mutex_unlock(&gLock);
696 *error = TDM_ERROR_NONE;
697 return g_private_display;
700 debug = getenv("TDM_DEBUG");
701 if (debug && (strstr(debug, "1")))
704 private_display = calloc(1, sizeof(tdm_private_display));
705 if (!private_display)
707 ret = TDM_ERROR_OUT_OF_MEMORY;
708 TDM_ERR("'private_display != NULL' failed");
712 if (pthread_mutex_init(&private_display->lock, NULL))
714 ret = TDM_ERROR_OPERATION_FAILED;
715 TDM_ERR("mutex init failed: %m");
716 goto failed_mutex_init;
719 ret = _tdm_display_load_module(private_display);
720 if (ret != TDM_ERROR_NONE)
723 ret = _tdm_display_update_internal(private_display, 0);
724 if (ret != TDM_ERROR_NONE)
727 private_display->init_count = 1;
729 g_private_display = private_display;
732 *error = TDM_ERROR_NONE;
734 pthread_mutex_unlock(&gLock);
736 return (tdm_display*)private_display;
739 _tdm_display_unload_module(private_display);
741 pthread_mutex_destroy(&private_display->lock);
743 free(private_display);
748 pthread_mutex_unlock(&gLock);
753 tdm_display_deinit(tdm_display *dpy)
755 tdm_private_display *private_display = dpy;
757 if (!private_display)
760 pthread_mutex_lock(&gLock);
762 private_display->init_count--;
763 if (private_display->init_count > 0)
765 pthread_mutex_unlock(&gLock);
769 pthread_mutex_lock(&private_display->lock);
771 _tdm_display_destroy_private_display(private_display);
772 _tdm_display_unload_module(private_display);
774 pthread_mutex_unlock(&private_display->lock);
776 pthread_mutex_destroy(&private_display->lock);
777 free(private_display);
780 pthread_mutex_unlock(&gLock);