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);
168 private_display->caps_display.capabilities = 0;
172 _tdm_display_update_caps_pp(tdm_private_display *private_display, tdm_caps_pp *caps)
174 tdm_func_display *func_display = &private_display->func_display;
176 int bufsize = sizeof(buf);
178 int *len_buf = &bufsize;
182 if (!(private_display->caps_display.capabilities & TDM_DISPLAY_CAPABILITY_PP))
183 return TDM_ERROR_NONE;
185 if (!func_display->display_get_pp_capability)
187 TDM_ERR("no display_get_pp_capability()");
188 return TDM_ERROR_BAD_MODULE;
191 ret = func_display->display_get_pp_capability(private_display->bdata, caps);
192 if (ret != TDM_ERROR_NONE)
194 TDM_ERR("display_get_pp_capability() failed");
195 return TDM_ERROR_BAD_MODULE;
198 TDM_DBG("pp capabilities: %x", caps->capabilities);
200 for (i = 0; i < caps->format_count; i++)
201 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
202 TDM_DBG("pp formats: %s", buf);
203 TDM_DBG("pp min : %dx%d", caps->min_w, caps->min_h);
204 TDM_DBG("pp max : %dx%d", caps->max_w, caps->max_h);
205 TDM_DBG("pp align: %d", caps->preferred_align);
207 return TDM_ERROR_NONE;
211 _tdm_display_update_caps_capture(tdm_private_display *private_display, tdm_caps_capture *caps)
213 tdm_func_display *func_display = &private_display->func_display;
215 int bufsize = sizeof(buf);
217 int *len_buf = &bufsize;
221 if (!(private_display->caps_display.capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE))
222 return TDM_ERROR_NONE;
224 if (!func_display->display_get_capture_capability)
226 TDM_ERR("no display_get_capture_capability()");
227 return TDM_ERROR_BAD_MODULE;
230 ret = func_display->display_get_capture_capability(private_display->bdata, caps);
231 if (ret != TDM_ERROR_NONE)
233 TDM_ERR("display_get_capture_capability() failed");
234 return TDM_ERROR_BAD_MODULE;
238 for (i = 0; i < caps->format_count; i++)
239 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
240 TDM_DBG("capture formats: %s", buf);
242 return TDM_ERROR_NONE;
246 _tdm_display_update_caps_layer(tdm_private_display *private_display, tdm_layer *layer, tdm_caps_layer *caps)
248 tdm_func_display *func_display = &private_display->func_display;
250 int bufsize = sizeof(buf);
252 int *len_buf = &bufsize;
256 if (!func_display->layer_get_capability)
258 TDM_ERR("no layer_get_capability()");
259 return TDM_ERROR_BAD_MODULE;
262 ret = func_display->layer_get_capability(layer, caps);
263 if (ret != TDM_ERROR_NONE)
265 TDM_ERR("layer_get_capability() failed");
266 return TDM_ERROR_BAD_MODULE;
269 TDM_DBG("layer capabilities: %x", caps->capabilities);
270 TDM_DBG("layer zpos : %d", caps->zpos);
272 for (i = 0; i < caps->format_count; i++)
273 TDM_SNPRINTF(str_buf, len_buf, "%c%c%c%c ", FOURCC_STR(caps->formats[i]));
274 TDM_DBG("layer formats: %s", buf);
275 for (i = 0; i < caps->prop_count; i++)
276 TDM_DBG("layer props: %d, %s", caps->props[i].id, caps->props[i].name);
278 return TDM_ERROR_NONE;
282 _tdm_display_update_caps_output(tdm_private_display *private_display, tdm_output *output, tdm_caps_output *caps)
284 tdm_func_display *func_display = &private_display->func_display;
288 if (!func_display->output_get_capability)
290 TDM_ERR("no output_get_capability()");
291 return TDM_ERROR_BAD_MODULE;
294 ret = func_display->output_get_capability(output, caps);
295 if (ret != TDM_ERROR_NONE)
297 TDM_ERR("output_get_capability() failed");
298 return TDM_ERROR_BAD_MODULE;
301 TDM_DBG("output status: %d", caps->status);
302 TDM_DBG("output type : %d", caps->type);
303 for (i = 0; i < caps->prop_count; i++)
304 TDM_DBG("output props: %d, %s", caps->props[i].id, caps->props[i].name);
305 for (i = 0; i < caps->mode_count; i++)
306 TDM_DBG("output modes: name(%s), size(%dx%d), refresh(%d), flags(%d), type(%d)",
307 caps->modes[i]->name, caps->modes[i]->width, caps->modes[i]->height,
308 caps->modes[i]->refresh, caps->modes[i]->flags, caps->modes[i]->type);
309 TDM_DBG("output min : %dx%d", caps->min_w, caps->min_h);
310 TDM_DBG("output max : %dx%d", caps->max_w, caps->max_h);
311 TDM_DBG("output align: %d", caps->preferred_align);
313 return TDM_ERROR_NONE;
317 _tdm_display_update_layer(tdm_private_display *private_display,
318 tdm_private_output *private_output,
321 tdm_private_layer *private_layer;
324 private_layer = _tdm_display_find_private_layer(private_output, layer);
327 private_layer = calloc(1, sizeof(tdm_private_layer));
328 TDM_RETURN_VAL_IF_FAIL(private_layer != NULL, TDM_ERROR_OUT_OF_MEMORY);
330 LIST_ADD(&private_layer->link, &private_output->layer_list);
331 private_layer->func_display = &private_display->func_display;
332 private_layer->private_display = private_display;
333 private_layer->private_output = private_output;
334 private_layer->layer = layer;
336 LIST_INITHEAD(&private_layer->capture_list);
339 _tdm_display_destroy_caps_layer(&private_layer->caps);
341 ret = _tdm_display_update_caps_layer(private_display, layer, &private_layer->caps);
342 if (ret != TDM_ERROR_NONE)
345 return TDM_ERROR_NONE;
347 _tdm_display_destroy_private_layer(private_layer);
352 _tdm_display_update_output(tdm_private_display *private_display, tdm_output *output, int pipe)
354 tdm_func_display *func_display = &private_display->func_display;
355 tdm_private_output *private_output = NULL;
356 tdm_layer **layers = NULL;
357 int layer_count = 0, i;
360 private_output = _tdm_display_find_private_output(private_display, output);
363 private_output = calloc(1, sizeof(tdm_private_output));
364 TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_OUT_OF_MEMORY);
366 LIST_ADD(&private_output->link, &private_display->output_list);
367 private_output->func_display = func_display;
368 private_output->private_display = private_display;
369 private_output->output = output;
370 private_output->pipe = pipe;
372 LIST_INITHEAD(&private_output->layer_list);
373 LIST_INITHEAD(&private_output->capture_list);
374 LIST_INITHEAD(&private_output->vblank_handler_list);
375 LIST_INITHEAD(&private_output->commit_handler_list);
378 _tdm_display_destroy_caps_output(&private_output->caps);
380 ret = _tdm_display_update_caps_output(private_display, output, &private_output->caps);
381 if (ret != TDM_ERROR_NONE)
384 layers = func_display->output_get_layers(output, &layer_count, &ret);
385 if (ret != TDM_ERROR_NONE)
388 for (i = 0; i < layer_count; i++)
390 ret = _tdm_display_update_layer(private_display, private_output, layers[i]);
391 if (ret != TDM_ERROR_NONE)
397 return TDM_ERROR_NONE;
399 _tdm_display_destroy_private_output(private_output);
405 _tdm_display_update_internal(tdm_private_display *private_display, int only_display)
407 tdm_func_display *func_display = &private_display->func_display;
408 tdm_output **outputs = NULL;
409 int output_count = 0, i;
412 LIST_INITHEAD(&private_display->output_list);
413 LIST_INITHEAD(&private_display->pp_list);
417 ret = _tdm_display_update_caps_pp(private_display, &private_display->caps_pp);
418 if (ret != TDM_ERROR_NONE)
421 ret = _tdm_display_update_caps_capture(private_display, &private_display->caps_capture);
422 if (ret != TDM_ERROR_NONE)
426 outputs = func_display->display_get_outputs(private_display->bdata, &output_count, &ret);
427 if (ret != TDM_ERROR_NONE)
430 for (i = 0; i < output_count; i++)
432 ret = _tdm_display_update_output(private_display, outputs[i], i);
433 if (ret != TDM_ERROR_NONE)
439 return TDM_ERROR_NONE;
442 _tdm_display_destroy_private_display(private_display);
449 tdm_display_update(tdm_display *dpy)
451 tdm_private_display *private_display;
454 TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER);
456 private_display = dpy;
457 pthread_mutex_lock(&private_display->lock);
459 ret = _tdm_display_update_internal(private_display, 1);
461 pthread_mutex_unlock(&private_display->lock);
466 #define SUFFIX_MODULE ".so"
467 #define DEFAULT_MODULE "libtdm-default"SUFFIX_MODULE
471 static tdm_private_display *g_private_display;
472 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
475 _tdm_display_check_module(tdm_backend_module *module)
482 abimaj = TDM_BACKEND_GET_ABI_MAJOR(TDM_BACKEND_ABI_VERSION);
483 abimin = TDM_BACKEND_GET_ABI_MINOR(TDM_BACKEND_ABI_VERSION);
485 TDM_INFO("TDM module ABI version : %d.%d", abimaj, abimin);
487 name = module->name ? module->name : "unknown";
488 vendor = module->vendor ? module->vendor : "unknown";
489 major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version);
490 minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version);
492 TDM_INFO("TDM module name: %s", name);
493 TDM_INFO("'%s' vendor: %s", name, vendor);
494 TDM_INFO("'%s' version: %d.%d", name, major, minor);
498 TDM_ERR("'%s' major version mismatch, %d != %d", name, major, abimaj);
499 return TDM_ERROR_BAD_MODULE;
504 TDM_ERR("'%s' minor version(%d) is newer than %d", name, minor, abimin);
505 return TDM_ERROR_BAD_MODULE;
510 TDM_ERR("'%s' doesn't have init function", name);
511 return TDM_ERROR_BAD_MODULE;
516 TDM_ERR("'%s' doesn't have deinit function", name);
517 return TDM_ERROR_BAD_MODULE;
520 return TDM_ERROR_NONE;
524 _tdm_display_check_backend_functions(tdm_private_display *private_display)
526 tdm_func_display *func_display = &private_display->func_display;
529 /* below functions should be implemented in backend side */
531 TDM_RETURN_VAL_IF_FAIL(func_display != NULL, TDM_ERROR_BAD_MODULE);
532 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capabilitiy, TDM_ERROR_BAD_MODULE);
533 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_outputs, TDM_ERROR_BAD_MODULE);
534 TDM_RETURN_VAL_IF_FAIL(func_display->output_get_capability, TDM_ERROR_BAD_MODULE);
535 TDM_RETURN_VAL_IF_FAIL(func_display->output_get_layers, TDM_ERROR_BAD_MODULE);
536 TDM_RETURN_VAL_IF_FAIL(func_display->layer_get_capability, TDM_ERROR_BAD_MODULE);
538 ret = func_display->display_get_capabilitiy(private_display->bdata,
539 &private_display->caps_display);
540 if (ret != TDM_ERROR_NONE)
542 TDM_ERR("display_get_capabilitiy() failed");
543 return TDM_ERROR_BAD_MODULE;
546 if (private_display->caps_display.capabilities & TDM_DISPLAY_CAPABILITY_PP)
548 tdm_func_pp *func_pp = &private_display->func_pp;
549 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_pp_capability, TDM_ERROR_BAD_MODULE);
550 TDM_RETURN_VAL_IF_FAIL(func_display->display_create_pp, TDM_ERROR_BAD_MODULE);
551 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_destroy, TDM_ERROR_BAD_MODULE);
552 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_commit, TDM_ERROR_BAD_MODULE);
553 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_set_done_handler, TDM_ERROR_BAD_MODULE);
556 if (private_display->caps_display.capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)
558 tdm_func_capture *func_capture = &private_display->func_capture;
559 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability, TDM_ERROR_BAD_MODULE);
560 TDM_RETURN_VAL_IF_FAIL(func_display->output_create_capture, TDM_ERROR_BAD_MODULE);
561 TDM_RETURN_VAL_IF_FAIL(func_display->layer_create_capture, TDM_ERROR_BAD_MODULE);
562 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE);
563 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE);
564 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler, TDM_ERROR_BAD_MODULE);
567 return TDM_ERROR_NONE;
571 _tdm_display_load_module_with_file(tdm_private_display *private_display, const char *file)
573 char path[PATH_MAX] = {0,};
574 tdm_backend_module *module_data;
578 snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
580 module = dlopen(path, RTLD_LAZY);
583 TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
584 return TDM_ERROR_BAD_MODULE;
587 module_data = dlsym(module, "tdm_backend_module_data");
590 TDM_ERR("'%s' doesn't have data object", file);
591 ret = TDM_ERROR_BAD_MODULE;
595 /* check if version, init() and deinit() are valid or not */
596 ret = _tdm_display_check_module(module_data);
597 if (ret != TDM_ERROR_NONE)
600 /* We don't care if backend_data is NULL or not. It's up to backend. */
601 private_display->bdata = module_data->init((tdm_display*)private_display, &ret);
602 if (ret != TDM_ERROR_NONE)
604 TDM_ERR("'%s' init failed", file);
608 ret = _tdm_display_check_backend_functions(private_display);
609 if (ret != TDM_ERROR_NONE)
611 module_data->deinit(private_display->bdata);
612 private_display->bdata = NULL;
616 private_display->module_data = module_data;
617 private_display->module = module;
619 TDM_INFO("Success to load module(%s)", file);
621 return TDM_ERROR_NONE;
628 _tdm_display_load_module(tdm_private_display *private_display)
630 const char *module_name;
631 struct dirent **namelist;
635 module_name = getenv("TDM_MODULE");
637 module_name = DEFAULT_MODULE;
639 /* load bufmgr priv from default lib */
640 ret = _tdm_display_load_module_with_file(private_display, module_name);
641 if (ret == TDM_ERROR_NONE)
642 return TDM_ERROR_NONE;
644 /* load bufmgr priv from configured path */
645 n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
648 TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
649 return TDM_ERROR_BAD_MODULE;
652 ret = TDM_ERROR_BAD_MODULE;
655 if (ret < 0 && strstr(namelist[n]->d_name, SUFFIX_MODULE))
656 ret = _tdm_display_load_module_with_file(private_display, namelist[n]->d_name);
666 _tdm_display_unload_module(tdm_private_display *private_display)
668 if (private_display->module_data)
669 private_display->module_data->deinit(private_display->bdata);
670 if (private_display->module)
671 dlclose(private_display->module);
673 private_display->bdata = NULL;
674 private_display->module_data = NULL;
675 private_display->module = NULL;
679 tdm_display_init(tdm_error *error)
681 tdm_private_display *private_display = NULL;
685 pthread_mutex_lock(&gLock);
687 if (g_private_display)
689 g_private_display->init_count++;
690 pthread_mutex_unlock(&gLock);
692 *error = TDM_ERROR_NONE;
693 return g_private_display;
696 debug = getenv("TDM_DEBUG");
697 if (debug && (strstr(debug, "1")))
700 private_display = calloc(1, sizeof(tdm_private_display));
701 if (!private_display)
703 ret = TDM_ERROR_OUT_OF_MEMORY;
704 TDM_ERR("'private_display != NULL' failed");
708 if (pthread_mutex_init(&private_display->lock, NULL))
710 ret = TDM_ERROR_OPERATION_FAILED;
711 TDM_ERR("mutex init failed: %m");
712 goto failed_mutex_init;
715 ret = _tdm_display_load_module(private_display);
716 if (ret != TDM_ERROR_NONE)
719 ret = _tdm_display_update_internal(private_display, 0);
720 if (ret != TDM_ERROR_NONE)
723 private_display->init_count = 1;
725 g_private_display = private_display;
728 *error = TDM_ERROR_NONE;
730 pthread_mutex_unlock(&gLock);
732 return (tdm_display*)private_display;
735 _tdm_display_unload_module(private_display);
737 pthread_mutex_destroy(&private_display->lock);
739 free(private_display);
744 pthread_mutex_unlock(&gLock);
749 tdm_display_deinit(tdm_display *dpy)
751 tdm_private_display *private_display = dpy;
753 if (!private_display)
756 pthread_mutex_lock(&gLock);
758 private_display->init_count--;
759 if (private_display->init_count > 0)
761 pthread_mutex_unlock(&gLock);
765 pthread_mutex_lock(&private_display->lock);
767 _tdm_display_destroy_private_display(private_display);
768 _tdm_display_unload_module(private_display);
770 pthread_mutex_unlock(&private_display->lock);
772 pthread_mutex_destroy(&private_display->lock);
773 free(private_display);
776 pthread_mutex_unlock(&gLock);