a7a44f70fa2b43310554b69e409b824cf25d5ab5
[platform/core/uifw/libtdm.git] / src / tdm_display.c
1 /**************************************************************************
2  *
3  * libtdm
4  *
5  * Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
6  *
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 <boram1288.park@samsung.com>
13  *
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:
21  *
22  * The above copyright notice and this permission notice (including the
23  * next paragraph) shall be included in all copies or substantial portions
24  * of the Software.
25  *
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.
33  *
34 **************************************************************************/
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include "tdm_private.h"
41
42 #define COUNT_MAX   10
43
44 #define DISPLAY_FUNC_ENTRY() \
45         tdm_private_display *private_display; \
46         tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\
47         TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER); \
48         private_display = (tdm_private_display*)dpy;
49
50 #define DISPLAY_FUNC_ENTRY_ERROR() \
51         tdm_private_display *private_display; \
52         tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\
53         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(dpy != NULL, TDM_ERROR_INVALID_PARAMETER, NULL); \
54         private_display = (tdm_private_display*)dpy;
55
56 #define BACKEND_FUNC_ENTRY() \
57         tdm_private_module *private_module; \
58         tdm_private_display *private_display; \
59         tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\
60         TDM_RETURN_VAL_IF_FAIL(module != NULL, TDM_ERROR_INVALID_PARAMETER); \
61         private_module = (tdm_private_module*)module; \
62         private_display = private_module->private_display;
63
64 /* LCOV_EXCL_START */
65 INTERN tdm_error
66 tdm_display_enable_debug_module(const char*modules)
67 {
68         char temp[TDM_PATH_LEN];
69         char *arg;
70         char *end;
71
72         snprintf(temp, TDM_PATH_LEN, "%s", modules);
73
74         tdm_debug_module = 0;
75
76         arg = strtok_r(temp, TDM_CONFIG_DELIM, &end);
77         while (arg) {
78                 if (!strncmp(arg, "none", 4)) {
79                         tdm_debug_module = 0;
80                         return TDM_ERROR_NONE;
81                 }
82                 if (!strncmp(arg, "all", 3)) {
83                         tdm_debug_module = 0xFFFFFFFF;
84                         return TDM_ERROR_NONE;
85                 }
86                 if (!strncmp(arg, "buffer", 6))
87                         tdm_debug_module |= TDM_DEBUG_BUFFER;
88                 else if (!strncmp(arg, "event", 5))
89                         tdm_debug_module |= TDM_DEBUG_EVENT;
90                 else if (!strncmp(arg, "thread", 6))
91                         tdm_debug_module |= TDM_DEBUG_THREAD;
92                 else if (!strncmp(arg, "mutex", 5))
93                         tdm_debug_module |= TDM_DEBUG_MUTEX;
94                 else if (!strncmp(arg, "vblank", 6))
95                         tdm_debug_module |= TDM_DEBUG_VBLANK;
96                 else if (!strncmp(arg, "commit", 6))
97                         tdm_debug_module |= TDM_DEBUG_COMMIT;
98
99                 arg = strtok_r(NULL, TDM_CONFIG_DELIM, &end);
100         }
101
102         TDM_INFO("module debugging... '%s'", modules);
103
104         return TDM_ERROR_NONE;
105 }
106
107 void
108 _tdm_display_enable_dump_current(tdm_private_display *private_display, char *path)
109 {
110         tdm_private_module *b = NULL;
111         tdm_private_output *o = NULL;
112
113         LIST_FOR_EACH_ENTRY(b, &private_display->module_list, link) {
114                 LIST_FOR_EACH_ENTRY(o, &b->output_list, link) {
115                         if (o->caps.capabilities & TDM_OUTPUT_CAPABILITY_HWC) {
116                                 tdm_private_hwc *private_hwc = NULL;
117                                 tdm_private_hwc_window *w = NULL;
118                                 int index = 0;
119                                 private_hwc = o->private_hwc;
120                                 if (private_hwc->display_target_buffer) {
121                                         char str[TDM_PATH_LEN];
122                                         snprintf(str, TDM_PATH_LEN, "window_%d_target", private_hwc->index);
123                                         tdm_helper_dump_buffer_str(private_hwc->display_target_buffer, path, str);
124                                 }
125                                 LIST_FOR_EACH_ENTRY(w, &private_hwc->hwc_window_list, link) {
126                                         char str[TDM_PATH_LEN];
127                                         if (!w->display_buffer)
128                                                 continue;
129                                         if (w->composition_type != TDM_HWC_WIN_COMPOSITION_DEVICE)
130                                                 continue;
131                                         snprintf(str, TDM_PATH_LEN, "window_%d_%d", private_hwc->index, index++);
132                                         tdm_helper_dump_buffer_str(w->display_buffer, path, str);
133                                 }
134                         } else {
135                                 tdm_private_layer *l = NULL;
136                                 LIST_FOR_EACH_ENTRY(l, &o->layer_list, link) {
137                                         char str[TDM_PATH_LEN];
138                                         if (l->usable || l->caps.capabilities & TDM_LAYER_CAPABILITY_VIDEO)
139                                                 continue;
140                                         if (!l->showing_buffer)
141                                                 continue;
142                                         snprintf(str, TDM_PATH_LEN, "layer_%d_%d", o->index, l->index);
143                                         tdm_helper_dump_buffer_str(l->showing_buffer->buffer, path, str);
144                                 }
145                         }
146                 }
147         }
148 }
149
150 INTERN tdm_error
151 tdm_display_enable_dump(tdm_private_display *private_display, const char *dump_str, char *reply, int *len)
152 {
153         char temp[TDM_PATH_LEN] = {0,}, temp2[TDM_PATH_LEN] = {0,};
154         char *path = NULL, *path2;
155         char *arg;
156         char *end;
157
158         snprintf(temp2, TDM_PATH_LEN, "%s", dump_str);
159         path2 = strtostr(temp, TDM_PATH_LEN, temp2, "@");
160         if (!path2 || path2[0] == '\0')
161                 path2 = TDM_DUMP_DIR;
162         else
163                 path2++;
164
165         tdm_debug_dump = 0;
166
167         snprintf(temp, sizeof(temp), "%s", dump_str);
168         arg = strtok_r(temp, ",", &end);
169         TDM_GOTO_IF_FAIL(arg != NULL, done);
170
171         if (!strncmp(arg, "none", 4)) {
172                 tdm_debug_dump = 0;
173                 TDM_SNPRINTF(reply, len, "path: %s\n", (tdm_debug_dump_dir) ? : "unknown");
174                 if (tdm_debug_dump_dir) {
175                         free(tdm_debug_dump_dir);
176                         tdm_debug_dump_dir = NULL;
177                 }
178                 goto done;
179         }
180
181         path = tdm_helper_dump_make_directory(path2, reply, len);
182         TDM_GOTO_IF_FAIL(path != NULL, done);
183
184         if (!strncmp(arg, "current", 7)) {
185                 if (!private_display) {
186                         TDM_WRN("no private_display");
187                         goto done;
188                 }
189
190                 _tdm_display_enable_dump_current(private_display, path);
191                 TDM_SNPRINTF(reply, len, "path: %s\n", path);
192                 goto done;
193         }
194
195         TDM_SNPRINTF(reply, len, "dump: %s\n", arg);
196
197         while (arg) {
198                 if (!strncmp(arg, "all", 3)) {
199                         tdm_debug_dump = 0xFFFFFFFF;
200                         goto done;
201                 } else if (!strncmp(arg, "layer", 5)) {
202                         tdm_debug_dump |= TDM_DUMP_FLAG_LAYER;
203                 } else if (!strncmp(arg, "pp", 2)) {
204                         tdm_debug_dump |= TDM_DUMP_FLAG_PP;
205                 } else if (!strncmp(arg, "capture", 7)) {
206                         tdm_debug_dump |= TDM_DUMP_FLAG_CAPTURE;
207                 } else if (!strncmp(arg, "window", 6)) {
208                         tdm_debug_dump |= TDM_DUMP_FLAG_WINDOW;
209                 } else
210                         goto done;
211
212                 arg = strtok_r(NULL, ",", &end);
213         }
214
215         if (tdm_debug_dump_dir)
216                 free(tdm_debug_dump_dir);
217
218         tdm_debug_dump_dir = strndup(path, TDM_PATH_LEN);
219
220         TDM_INFO("dump... '%s'", dump_str);
221
222 done:
223         if (path)
224                 free(path);
225
226         return TDM_ERROR_NONE;
227 }
228
229 static void
230 _tdm_display_ttrace_vblank_cb(tdm_vblank *vblank, tdm_error error, unsigned int sequence,
231                                                           unsigned int tv_sec, unsigned int tv_usec, void *user_data)
232 {
233         tdm_error ret = TDM_ERROR_NONE;
234
235         TDM_TRACE_MARK("VSYNC");
236
237         ret = tdm_vblank_wait(vblank, 0, 0, 1, _tdm_display_ttrace_vblank_cb, NULL);
238         TDM_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
239 }
240
241 INTERN tdm_error
242 tdm_display_enable_ttrace_vblank(tdm_display *dpy, tdm_output *output, int enable)
243 {
244         tdm_private_display *private_display = dpy;
245         tdm_private_module *private_module = NULL;
246         tdm_private_output *private_output = NULL;
247         const tdm_output_mode *mode = NULL;
248         tdm_vblank *vblank = NULL;
249         tdm_error ret = TDM_ERROR_NONE;
250
251         if (!enable) {
252                 LIST_FOR_EACH_ENTRY(private_module, &private_display->module_list, link) {
253                         LIST_FOR_EACH_ENTRY(private_output, &private_module->output_list, link) {
254                                 if (private_output->ttrace_vblank)
255                                         tdm_vblank_destroy(private_output->ttrace_vblank);
256                                 private_output->ttrace_vblank = NULL;
257                         }
258                 }
259                 return TDM_ERROR_NONE;
260         }
261
262         private_output = output;
263         TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_INVALID_PARAMETER);
264
265         if (private_output->ttrace_vblank)
266                 return TDM_ERROR_NONE;
267
268         vblank = tdm_vblank_create(private_display, output, &ret);
269         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, ret);
270
271         ret = tdm_output_get_mode(output, &mode);
272         TDM_GOTO_IF_FAIL(mode != NULL, enable_fail);
273
274         ret = tdm_vblank_set_fps(vblank, mode->vrefresh);
275         TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, enable_fail);
276
277         ret = tdm_vblank_set_enable_fake(vblank, 1);
278         TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, enable_fail);
279
280         ret = tdm_vblank_wait(vblank, 0, 0, 1, _tdm_display_ttrace_vblank_cb, NULL);
281         TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, enable_fail);
282
283         private_output->ttrace_vblank = vblank;
284
285         return TDM_ERROR_NONE;
286
287 enable_fail:
288         if (vblank)
289                 tdm_vblank_destroy(vblank);
290
291         return ret;
292 }
293
294 INTERN tdm_error
295 tdm_display_enable_ttrace(tdm_private_display *private_display, const char *ttrace, int output_id, char *reply, int *len)
296 {
297         char temp[TDM_PATH_LEN];
298         char *arg;
299         char *end;
300         tdm_output *output;
301         tdm_error ret;
302         tdm_output_type type;
303
304         snprintf(temp, TDM_PATH_LEN, "%s", ttrace);
305
306         tdm_ttrace_output = output_id;
307         tdm_ttrace_module = 0;
308
309         output = tdm_display_get_output(private_display, output_id, &ret);
310         if (!output) {
311                 TDM_SNPRINTF(reply, len, "can't find the output_id(%d)\n", output_id);
312                 return ret;
313         }
314
315         ret = tdm_output_get_output_type(output, &type);
316         if (ret != TDM_ERROR_NONE) {
317                 TDM_SNPRINTF(reply, len, "can't find the type of output_id(%d)\n", output_id);
318                 return ret;
319         }
320
321         arg = strtok_r(temp, TDM_CONFIG_DELIM, &end);
322         while (arg) {
323                 if (!strncmp(arg, "none", 4))
324                         tdm_ttrace_module = 0;
325                 else if (!strncmp(arg, "all", 3))
326                         tdm_ttrace_module = 0xFFFFFFFF;
327                 else if (!strncmp(arg, "vsync", 5))
328                         tdm_ttrace_module |= TDM_TTRACE_VSYNC;
329                 else if (!strncmp(arg, "client_vblank", 13))
330                         tdm_ttrace_module |= TDM_TTRACE_CLIENT_VBLANK;
331                 else if (!strncmp(arg, "server_vblank", 13))
332                         tdm_ttrace_module |= TDM_TTRACE_SERVER_VBLANK;
333                 else if (!strncmp(arg, "vblank", 6))
334                         tdm_ttrace_module |= TDM_TTRACE_VBLANK;
335                 else if (!strncmp(arg, "layer", 5))
336                         tdm_ttrace_module |= TDM_TTRACE_LAYER;
337                 else if (!strncmp(arg, "pp", 2))
338                         tdm_ttrace_module |= TDM_TTRACE_PP;
339                 else if (!strncmp(arg, "capture", 7))
340                         tdm_ttrace_module |= TDM_TTRACE_CAPTURE;
341                 else  {
342                         tdm_ttrace_module = 0;
343                         tdm_display_enable_ttrace_vblank(private_display, NULL, 0);
344                         tdm_server_enable_ttrace_client_vblank(private_display, NULL, 0);
345                         TDM_SNPRINTF(reply, len, "unknown option: '%s'\n", arg);
346                         return TDM_ERROR_NONE;
347                 }
348
349                 arg = strtok_r(NULL, TDM_CONFIG_DELIM, &end);
350         }
351
352         TDM_SNPRINTF(reply, len, "ttrace debugging... '%s' %x\n", ttrace, tdm_ttrace_module);
353
354         if (tdm_ttrace_module & TDM_TTRACE_VSYNC)
355                 tdm_display_enable_ttrace_vblank(private_display, output, 1);
356         else
357                 tdm_display_enable_ttrace_vblank(private_display, NULL, 0);
358
359         if (tdm_ttrace_module & TDM_TTRACE_CLIENT_VBLANK)
360                 tdm_server_enable_ttrace_client_vblank(private_display, output, 1);
361         else
362                 tdm_server_enable_ttrace_client_vblank(private_display, NULL, 0);
363
364         return TDM_ERROR_NONE;
365 }
366
367 INTERN tdm_error
368 tdm_display_enable_fps(tdm_private_display *private_display, int enable)
369 {
370         private_display->print_fps = enable;
371
372         TDM_INFO("print fps: %s", (enable) ? "enable" : "disable");
373
374         return TDM_ERROR_NONE;
375 }
376 /* LCOV_EXCL_STOP */
377
378 INTERN tdm_error
379 tdm_display_call_thread_cb_output_create(tdm_private_display *private_display, tdm_output *output)
380 {
381         tdm_thread_cb_display_output_create output_create;
382         tdm_error ret;
383
384         if (LIST_IS_EMPTY(&private_display->output_create_handler_list)) return TDM_ERROR_NONE;
385
386         memset(&output_create, 0, sizeof output_create);
387         output_create.base.type = TDM_THREAD_CB_DISPLAY_OUTPUT_CREATE;
388         output_create.base.length = sizeof output_create;
389         output_create.base.object_stamp = tdm_helper_get_time();
390         output_create.base.data = NULL;
391         output_create.base.sync = 1;
392         output_create.output = output;
393
394         ret = tdm_thread_cb_call(private_display, &output_create.base, 1);
395         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
396
397         return TDM_ERROR_NONE;
398 }
399
400 /* LCOV_EXCL_START */
401 INTERN void
402 tdm_display_thread_cb_output_create(tdm_private_display *private_display, void *object, tdm_thread_cb_base *cb_base, void *user_data)
403 {
404         tdm_thread_cb_display_output_create *output_create = (tdm_thread_cb_display_output_create*)cb_base;
405         tdm_private_output_create_handler *create_handler = user_data;
406         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
407
408         assert(create_handler->owner_tid == syscall(SYS_gettid));
409
410         _pthread_mutex_unlock(&private_display->lock);
411         create_handler->func(private_display, output_create->output, create_handler->user_data);
412         _pthread_mutex_lock(&private_display->lock);
413 }
414
415 EXTERN tdm_error
416 tdm_display_add_output_create_handler(tdm_display *dpy,
417                                                                           tdm_output_create_handler func,
418                                                                           void *user_data)
419 {
420         tdm_private_output_create_handler *create_handler = NULL;
421
422         DISPLAY_FUNC_ENTRY();
423
424         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
425
426         _pthread_mutex_lock(&private_display->lock);
427
428         LIST_FOR_EACH_ENTRY(create_handler, &private_display->output_create_handler_list, link) {
429                 if (create_handler->func == func && create_handler->user_data == user_data) {
430                         TDM_ERR("can't add twice");
431                         _pthread_mutex_unlock(&private_display->lock);
432                         return TDM_ERROR_BAD_REQUEST;
433                 }
434         }
435
436         create_handler = calloc(1, sizeof(tdm_private_output_create_handler));
437         if (!create_handler) {
438                 TDM_ERR("failed: alloc memory");
439                 _pthread_mutex_unlock(&private_display->lock);
440                 return TDM_ERROR_OUT_OF_MEMORY;
441         }
442
443         ret = tdm_thread_cb_add(private_display, TDM_THREAD_CB_DISPLAY_OUTPUT_CREATE, NULL,
444                                                         tdm_display_thread_cb_output_create, create_handler);
445         if (ret != TDM_ERROR_NONE) {
446                 TDM_ERR("tdm_thread_cb_add failed");
447                 free(create_handler);
448                 _pthread_mutex_unlock(&private_display->lock);
449                 return TDM_ERROR_OPERATION_FAILED;
450         }
451
452         create_handler->private_display = private_display;
453         create_handler->func = func;
454         create_handler->user_data = user_data;
455         create_handler->owner_tid = syscall(SYS_gettid);
456
457         LIST_ADDTAIL(&create_handler->link, &private_display->output_create_handler_list);
458
459         _pthread_mutex_unlock(&private_display->lock);
460
461         return ret;
462 }
463
464 EXTERN void
465 tdm_display_remove_output_create_handler(tdm_display *dpy,
466                                                                                  tdm_output_create_handler func,
467                                                                                  void *user_data)
468 {
469         tdm_private_display *private_display;
470         tdm_private_output_create_handler *create_handler = NULL, *hh = NULL;
471
472         TDM_RETURN_IF_FAIL(dpy != NULL);
473         TDM_RETURN_IF_FAIL(func != NULL);
474
475         private_display = (tdm_private_display*)dpy;
476
477         _pthread_mutex_lock(&private_display->lock);
478
479         LIST_FOR_EACH_ENTRY_SAFE(create_handler, hh, &private_display->output_create_handler_list, link) {
480                 if (create_handler->func != func || create_handler->user_data != user_data)
481                         continue;
482
483                 tdm_thread_cb_remove(private_display, TDM_THREAD_CB_DISPLAY_OUTPUT_CREATE, NULL,
484                                                          tdm_display_thread_cb_output_create, create_handler);
485
486                 LIST_DEL(&create_handler->link);
487                 free(create_handler);
488
489                 _pthread_mutex_unlock(&private_display->lock);
490
491                 return;
492         }
493
494         _pthread_mutex_unlock(&private_display->lock);
495 }
496 /* LCOV_EXCL_STOP */
497
498 EXTERN tdm_error
499 tdm_display_get_capabilities(tdm_display *dpy,
500                                                          tdm_display_capability *capabilities)
501 {
502         tdm_private_module *private_module = NULL;
503
504         DISPLAY_FUNC_ENTRY();
505
506         TDM_RETURN_VAL_IF_FAIL(capabilities != NULL, TDM_ERROR_INVALID_PARAMETER);
507
508         _pthread_mutex_lock(&private_display->lock);
509
510         *capabilities = 0;
511
512         LIST_FOR_EACH_ENTRY(private_module, &private_display->module_list, link) {
513                 *capabilities |= private_module->capabilities;
514         }
515
516         _pthread_mutex_unlock(&private_display->lock);
517
518         return ret;
519 }
520
521 EXTERN tdm_error
522 tdm_display_get_pp_capabilities(tdm_display *dpy,
523                                                                 tdm_pp_capability *capabilities)
524 {
525         tdm_private_module *pp_module;
526
527         DISPLAY_FUNC_ENTRY();
528
529         TDM_RETURN_VAL_IF_FAIL(capabilities != NULL, TDM_ERROR_INVALID_PARAMETER);
530
531         _pthread_mutex_lock(&private_display->lock);
532
533         if (!private_display->pp_module) {
534                 /* LCOV_EXCL_START */
535                 TDM_ERR("no pp capability");
536                 _pthread_mutex_unlock(&private_display->lock);
537                 return TDM_ERROR_NO_CAPABILITY;
538                 /* LCOV_EXCL_STOP */
539         }
540
541         pp_module = private_display->pp_module;
542
543         *capabilities = pp_module->caps_pp.capabilities;
544
545         _pthread_mutex_unlock(&private_display->lock);
546
547         return ret;
548 }
549
550 EXTERN tdm_error
551 tdm_display_get_pp_available_formats(tdm_display *dpy,
552                                                                          const tbm_format **formats, int *count)
553 {
554         tdm_private_module *pp_module;
555
556         DISPLAY_FUNC_ENTRY();
557
558         TDM_RETURN_VAL_IF_FAIL(formats != NULL, TDM_ERROR_INVALID_PARAMETER);
559         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
560
561         _pthread_mutex_lock(&private_display->lock);
562
563         if (!private_display->pp_module) {
564                 /* LCOV_EXCL_START */
565                 TDM_ERR("no pp capability");
566                 _pthread_mutex_unlock(&private_display->lock);
567                 return TDM_ERROR_NO_CAPABILITY;
568                 /* LCOV_EXCL_STOP */
569         }
570
571         pp_module = private_display->pp_module;
572
573         *formats = (const tbm_format *)pp_module->caps_pp.formats;
574         *count = pp_module->caps_pp.format_count;
575
576         _pthread_mutex_unlock(&private_display->lock);
577
578         return ret;
579 }
580
581 EXTERN tdm_error
582 tdm_display_get_pp_available_size(tdm_display *dpy, int *min_w, int *min_h,
583                                                                   int *max_w, int *max_h, int *preferred_align)
584 {
585         tdm_private_module *pp_module;
586
587         DISPLAY_FUNC_ENTRY();
588
589         _pthread_mutex_lock(&private_display->lock);
590
591         if (!private_display->pp_module) {
592                 /* LCOV_EXCL_START */
593                 TDM_ERR("no pp capability");
594                 _pthread_mutex_unlock(&private_display->lock);
595                 return TDM_ERROR_NO_CAPABILITY;
596                 /* LCOV_EXCL_STOP */
597         }
598
599         pp_module = private_display->pp_module;
600
601         if (min_w)
602                 *min_w = TDM_FRONT_VALUE(pp_module->caps_pp.min_w);
603         if (min_h)
604                 *min_h = TDM_FRONT_VALUE(pp_module->caps_pp.min_h);
605         if (max_w)
606                 *max_w = TDM_FRONT_VALUE(pp_module->caps_pp.max_w);
607         if (max_h)
608                 *max_h = TDM_FRONT_VALUE(pp_module->caps_pp.max_h);
609         if (preferred_align)
610                 *preferred_align = TDM_FRONT_VALUE(pp_module->caps_pp.preferred_align);
611
612         _pthread_mutex_unlock(&private_display->lock);
613
614         return ret;
615 }
616
617 EXTERN tdm_error
618 tdm_display_get_pp_preferred_align_vertical(tdm_display *dpy, int *preferred_align_vertical)
619 {
620         tdm_private_module *pp_module;
621
622         DISPLAY_FUNC_ENTRY();
623
624         _pthread_mutex_lock(&private_display->lock);
625
626         if (!private_display->pp_module) {
627                 /* LCOV_EXCL_START */
628                 TDM_ERR("no pp capability");
629                 _pthread_mutex_unlock(&private_display->lock);
630                 return TDM_ERROR_NO_CAPABILITY;
631                 /* LCOV_EXCL_STOP */
632         }
633
634         pp_module = private_display->pp_module;
635
636         if (preferred_align_vertical)
637                 *preferred_align_vertical = TDM_FRONT_VALUE(pp_module->caps_pp.preferred_align_vertical);
638
639         _pthread_mutex_unlock(&private_display->lock);
640
641         return ret;
642 }
643
644 EXTERN tdm_error
645 tdm_display_get_capture_capabilities(tdm_display *dpy,
646                                                                          tdm_capture_capability *capabilities)
647 {
648         tdm_private_module *capture_module;
649
650         DISPLAY_FUNC_ENTRY();
651
652         TDM_RETURN_VAL_IF_FAIL(capabilities != NULL, TDM_ERROR_INVALID_PARAMETER);
653
654         _pthread_mutex_lock(&private_display->lock);
655
656         if (!private_display->capture_module) {
657                 /* LCOV_EXCL_START */
658                 TDM_ERR("no capture capability");
659                 _pthread_mutex_unlock(&private_display->lock);
660                 return TDM_ERROR_NO_CAPABILITY;
661                 /* LCOV_EXCL_STOP */
662         }
663
664         capture_module = private_display->capture_module;
665
666         *capabilities = capture_module->caps_capture.capabilities;
667
668         _pthread_mutex_unlock(&private_display->lock);
669
670         return ret;
671 }
672
673 EXTERN tdm_error
674 tdm_display_get_capture_available_formats(tdm_display *dpy,
675                 const tbm_format **formats, int *count)
676 {
677         tdm_private_module *capture_module;
678
679         DISPLAY_FUNC_ENTRY();
680
681         TDM_RETURN_VAL_IF_FAIL(formats != NULL, TDM_ERROR_INVALID_PARAMETER);
682         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
683
684         _pthread_mutex_lock(&private_display->lock);
685
686         if (!private_display->capture_module) {
687                 /* LCOV_EXCL_START */
688                 TDM_ERR("no capture capability");
689                 _pthread_mutex_unlock(&private_display->lock);
690                 return TDM_ERROR_NO_CAPABILITY;
691                 /* LCOV_EXCL_STOP */
692         }
693
694         capture_module = private_display->capture_module;
695
696         *formats = (const tbm_format *)capture_module->caps_capture.formats;
697         *count = capture_module->caps_capture.format_count;
698
699         _pthread_mutex_unlock(&private_display->lock);
700
701         return ret;
702 }
703
704 EXTERN tdm_error
705 tdm_display_get_capture_available_size(tdm_display *dpy, int *min_w, int *min_h,
706                                                                            int *max_w, int *max_h, int *preferred_align)
707 {
708         tdm_private_module *capture_module;
709
710         DISPLAY_FUNC_ENTRY();
711
712         _pthread_mutex_lock(&private_display->lock);
713
714         if (!private_display->capture_module) {
715                 /* LCOV_EXCL_START */
716                 TDM_ERR("no capture capability");
717                 _pthread_mutex_unlock(&private_display->lock);
718                 return TDM_ERROR_NO_CAPABILITY;
719                 /* LCOV_EXCL_STOP */
720         }
721
722         capture_module = private_display->capture_module;
723
724         if (min_w)
725                 *min_w = TDM_FRONT_VALUE(capture_module->caps_capture.min_w);
726         if (min_h)
727                 *min_h = TDM_FRONT_VALUE(capture_module->caps_capture.min_h);
728         if (max_w)
729                 *max_w = TDM_FRONT_VALUE(capture_module->caps_capture.max_w);
730         if (max_h)
731                 *max_h = TDM_FRONT_VALUE(capture_module->caps_capture.max_h);
732         if (preferred_align)
733                 *preferred_align = TDM_FRONT_VALUE(capture_module->caps_capture.preferred_align);
734
735         _pthread_mutex_unlock(&private_display->lock);
736
737         return ret;
738 }
739
740 EXTERN tdm_error
741 tdm_display_get_max_layer_count(tdm_display *dpy, int *max_count)
742 {
743         TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER);
744         TDM_RETURN_VAL_IF_FAIL(max_count != NULL, TDM_ERROR_INVALID_PARAMETER);
745
746         TDM_DEPRECATED(NULL);
747
748         *max_count = -1;
749
750         return TDM_ERROR_NONE;
751 }
752
753 EXTERN tdm_error
754 tdm_display_get_output_count(tdm_display *dpy, int *count)
755 {
756         tdm_private_module *private_module = NULL;
757         tdm_private_output *private_output = NULL;
758
759         DISPLAY_FUNC_ENTRY();
760
761         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
762
763         _pthread_mutex_lock(&private_display->lock);
764
765         *count = 0;
766         LIST_FOR_EACH_ENTRY(private_module, &private_display->module_list, link) {
767                 LIST_FOR_EACH_ENTRY(private_output, &private_module->output_list, link) {
768                         (*count)++;
769                 }
770         }
771
772         _pthread_mutex_unlock(&private_display->lock);
773
774         return ret;
775 }
776
777
778 EXTERN tdm_output *
779 tdm_display_get_output(tdm_display *dpy, int index, tdm_error *error)
780 {
781         tdm_private_module *private_module = NULL;
782         tdm_private_output *private_output = NULL;
783
784         DISPLAY_FUNC_ENTRY_ERROR();
785
786         _pthread_mutex_lock(&private_display->lock);
787
788         if (error)
789                 *error = TDM_ERROR_NONE;
790
791         LIST_FOR_EACH_ENTRY(private_module, &private_display->module_list, link) {
792                 LIST_FOR_EACH_ENTRY(private_output, &private_module->output_list, link) {
793                         if (private_output->index == index) {
794                                 _pthread_mutex_unlock(&private_display->lock);
795                                 return private_output;
796                         }
797                 }
798         }
799
800         _pthread_mutex_unlock(&private_display->lock);
801
802         return NULL;
803 }
804
805 EXTERN tdm_output *
806 tdm_display_find_output(tdm_display *dpy, const char *name, tdm_error *error)
807 {
808         tdm_private_module *private_module = NULL;
809         tdm_private_output *private_output = NULL;
810         tdm_private_output *mode_setted_output = NULL;
811         tdm_private_output *connected_output = NULL;
812         unsigned int find_primary = 0;
813
814         DISPLAY_FUNC_ENTRY_ERROR();
815
816         if (!strncasecmp(name, "primary", 7) || !strncasecmp(name, "default", 7))
817                 find_primary = 1;
818
819         _pthread_mutex_lock(&private_display->lock);
820
821         if (error)
822                 *error = TDM_ERROR_NONE;
823
824         if (find_primary) {
825                 LIST_FOR_EACH_ENTRY(private_module, &private_display->module_list, link) {
826                         LIST_FOR_EACH_ENTRY(private_output, &private_module->output_list, link) {
827                                 if (private_output->caps.status == TDM_OUTPUT_CONN_STATUS_CONNECTED && !connected_output)
828                                         connected_output = private_output;
829                                 else if (private_output->caps.status == TDM_OUTPUT_CONN_STATUS_MODE_SETTED && !mode_setted_output)
830                                         mode_setted_output = private_output;
831                         }
832                 }
833
834                 if (mode_setted_output) {
835                         _pthread_mutex_unlock(&private_display->lock);
836                         return mode_setted_output;
837                 }
838
839                 if (connected_output) {
840                         _pthread_mutex_unlock(&private_display->lock);
841                         return connected_output;
842                 }
843
844                 LIST_FOR_EACH_ENTRY(private_module, &private_display->module_list, link) {
845                         LIST_FOR_EACH_ENTRY(private_output, &private_module->output_list, link) {
846                                 if (private_output->index == 0) {
847                                         _pthread_mutex_unlock(&private_display->lock);
848                                         return private_output;
849                                 }
850                         }
851                 }
852         }
853
854         LIST_FOR_EACH_ENTRY(private_module, &private_display->module_list, link) {
855                 LIST_FOR_EACH_ENTRY(private_output, &private_module->output_list, link) {
856                         if (strncmp(private_output->caps.model, name, TDM_NAME_LEN))
857                                 continue;
858                         _pthread_mutex_unlock(&private_display->lock);
859                         return private_output;
860                 }
861         }
862
863         if (private_display->virtual_module) {
864                 private_module = private_display->virtual_module;
865                 LIST_FOR_EACH_ENTRY(private_output, &private_module->output_list, link) {
866                         if (strncmp(private_output->name, name, TDM_NAME_LEN))
867                                 continue;
868                         _pthread_mutex_unlock(&private_display->lock);
869                         return private_output;
870                 }
871         }
872         _pthread_mutex_unlock(&private_display->lock);
873
874         return NULL;
875 }
876
877 EXTERN tdm_error
878 tdm_display_get_fd(tdm_display *dpy, int *fd)
879 {
880         DISPLAY_FUNC_ENTRY();
881
882         TDM_RETURN_VAL_IF_FAIL(fd != NULL, TDM_ERROR_INVALID_PARAMETER);
883
884         _pthread_mutex_lock(&private_display->lock);
885
886         if (tdm_thread_is_running())
887                 *fd = tdm_thread_get_fd(private_display->private_loop);
888         else
889                 *fd = tdm_event_loop_get_fd(private_display);
890
891         _pthread_mutex_unlock(&private_display->lock);
892
893         return ret;
894 }
895
896 EXTERN tdm_error
897 tdm_display_handle_events(tdm_display *dpy)
898 {
899         struct pollfd fds;
900         int fd = -1;
901
902         DISPLAY_FUNC_ENTRY();
903
904         ret = tdm_display_get_fd(dpy, &fd);
905         TDM_RETURN_VAL_IF_FAIL(fd >= 0, ret);
906
907         fds.events = POLLIN;
908         fds.fd = fd;
909         fds.revents = 0;
910
911         if (tdm_debug_module & TDM_DEBUG_EVENT)
912                 TDM_INFO("fd(%d) polling in", fd);
913
914         while (poll(&fds, 1, -1) < 0) {
915                 /* LCOV_EXCL_START */
916                 if (errno == EINTR || errno == EAGAIN)  /* normal case */
917                         continue;
918                 else {
919                         TDM_ERR("poll failed: %m");
920                         return TDM_ERROR_OPERATION_FAILED;
921                 }
922                 /* LCOV_EXCL_STOP */
923         }
924
925         if (tdm_debug_module & TDM_DEBUG_EVENT)
926                 TDM_INFO("fd(%d) polling out", fd);
927
928         if (tdm_thread_is_running()) {
929                 _pthread_mutex_lock(&private_display->lock);
930                 ret = tdm_thread_handle_cb(private_display->private_loop);
931                 _pthread_mutex_unlock(&private_display->lock);
932         } else {
933                 ret = tdm_event_loop_dispatch(private_display);
934         }
935
936         return ret;
937 }
938
939 EXTERN void
940 tdm_display_flush(tdm_display *dpy)
941 {
942         tdm_private_display *private_display;
943
944         TDM_RETURN_IF_FAIL(dpy != NULL);
945         private_display = (tdm_private_display*)dpy;
946
947         if (tdm_thread_is_running())
948                 return;
949
950         tdm_event_loop_flush(private_display);
951 }
952
953 EXTERN tdm_error
954 tdm_display_get_backend_info(tdm_display *dpy, const char **name,
955                                                          const char **vendor, int *major, int *minor)
956 {
957         tdm_private_module *private_module = NULL;
958         tdm_backend_module *module_data = NULL;
959
960         DISPLAY_FUNC_ENTRY();
961
962         TDM_DEPRECATED("Use tdm_module_get_info");
963
964         _pthread_mutex_lock(&private_display->lock);
965
966         /* use first backend */
967         LIST_FOR_EACH_ENTRY(private_module, &private_display->module_list, link) {
968                 module_data = private_module->module_data;
969                 break;
970         }
971
972         if (!private_module->use_hal_tdm) {
973                 assert(module_data != NULL);
974
975                 if (name)
976                         *name = module_data->name;
977                 if (vendor)
978                         *vendor = module_data->vendor;
979                 if (major)
980                         *major = TDM_BACKEND_GET_ABI_MAJOR(module_data->abi_version);
981                 if (minor)
982                         *minor = TDM_BACKEND_GET_ABI_MINOR(module_data->abi_version);
983         }
984         _pthread_mutex_unlock(&private_display->lock);
985
986         return ret;
987 }
988
989 EXTERN tdm_pp *
990 tdm_display_create_pp(tdm_display *dpy, tdm_error *error)
991 {
992         tdm_pp *pp;
993
994         DISPLAY_FUNC_ENTRY_ERROR();
995
996         _pthread_mutex_lock(&private_display->lock);
997
998         pp = (tdm_pp *)tdm_pp_create_internal(private_display->pp_module, error);
999
1000         _pthread_mutex_unlock(&private_display->lock);
1001
1002         return pp;
1003 }
1004
1005 EXTERN tdm_error
1006 tdm_module_get_info(tdm_module *module, const char **name,
1007                                         const char **vendor, int *major, int *minor)
1008 {
1009         tdm_backend_module *module_data;
1010
1011         BACKEND_FUNC_ENTRY();
1012
1013         _pthread_mutex_lock(&private_display->lock);
1014
1015         module_data = private_module->module_data;
1016
1017         if (!private_module->use_hal_tdm) {
1018                 if (name)
1019                         *name = module_data->name;
1020                 if (vendor)
1021                         *vendor = module_data->vendor;
1022                 if (major)
1023                         *major = TDM_BACKEND_GET_ABI_MAJOR(module_data->abi_version);
1024                 if (minor)
1025                         *minor = TDM_BACKEND_GET_ABI_MINOR(module_data->abi_version);
1026         }
1027
1028         _pthread_mutex_unlock(&private_display->lock);
1029
1030         return ret;
1031 }
1032
1033 INTERN int
1034 tdm_module_check_abi(tdm_private_module *private_module, int abimaj, int abimin)
1035 {
1036         tdm_backend_module *module = private_module->module_data;
1037
1038         if (!private_module->use_hal_tdm) {
1039                 if (TDM_BACKEND_GET_ABI_MAJOR(module->abi_version) > abimaj)
1040                         return 1;
1041
1042                 if (TDM_BACKEND_GET_ABI_MAJOR(module->abi_version) < abimaj)
1043                         return 0;
1044
1045                 if (TDM_BACKEND_GET_ABI_MINOR(module->abi_version) < abimin)
1046                         return 0;
1047         }
1048
1049         return 1;
1050 }
1051
1052 /* LCOV_EXCL_START */
1053 INTERN tdm_voutput *
1054 tdm_display_voutput_create(tdm_display *dpy, const char *name, tdm_error *error)
1055 {
1056         tdm_private_module *private_module = NULL;
1057         tdm_private_module *current_module = NULL;
1058         tdm_private_voutput *private_voutput = NULL;
1059         tdm_private_output *private_output = NULL;
1060         tdm_func_display *func_display = NULL;
1061         tdm_func_voutput *func_voutput = NULL;
1062         tdm_voutput *voutput_backend = NULL;
1063         tdm_output *output_backend = NULL;
1064         int output_find = 0;
1065         tdm_private_display *private_display;
1066         tdm_error ret = TDM_ERROR_NONE;
1067
1068         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(dpy != NULL, TDM_ERROR_INVALID_PARAMETER, NULL);
1069         private_display = (tdm_private_display*)dpy;
1070         private_module = private_display->virtual_module;
1071         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_module != NULL, TDM_ERROR_BAD_MODULE, NULL);
1072
1073         _pthread_mutex_lock(&private_display->lock);
1074
1075         if (error) *error = TDM_ERROR_NONE;
1076
1077         private_voutput = calloc(1, sizeof(tdm_private_voutput));
1078         if (!private_voutput) {
1079                 if (error) *error = TDM_ERROR_OUT_OF_MEMORY;
1080                 _pthread_mutex_unlock(&private_display->lock);
1081                 return NULL;
1082         }
1083
1084         current_module = private_display->current_module;
1085         private_display->current_module = private_module;
1086
1087         if (private_module->use_hal_tdm) {
1088                 voutput_backend = (tdm_voutput *)hal_tdm_display_voutput_create(private_module->htdm_dpy, name, (hal_tdm_error *)&ret);
1089         } else {
1090                 func_display = &private_module->func_display;
1091                 func_voutput = &private_module->func_voutput;
1092                 voutput_backend = func_display->display_voutput_create(private_module->bdata, name, &ret);
1093         }
1094         if (voutput_backend == NULL || ret != TDM_ERROR_NONE) {
1095                 TDM_ERR("display_voutput_create fail");
1096                 if (error) *error = ret;
1097                 goto voutput_create_fail;
1098         }
1099         private_voutput->voutput_backend = voutput_backend;
1100         private_voutput->private_display = private_display;
1101         private_voutput->private_module = private_module;
1102         LIST_INITHEAD(&private_voutput->voutput_commit_handler_list);
1103
1104         if (private_module->use_hal_tdm)
1105                 output_backend = (tdm_output *)hal_tdm_voutput_get_output((hal_tdm_voutput *)voutput_backend, (hal_tdm_error *)&ret);
1106         else
1107                 output_backend = func_voutput->voutput_get_output(voutput_backend, &ret);
1108         if (output_backend == NULL || ret != TDM_ERROR_NONE) {
1109                 TDM_ERR("voutput_get_output fail");
1110                 if (error) *error = ret;
1111                 goto output_get_fail;
1112         }
1113
1114         if (private_module->use_hal_tdm) {
1115                 if (private_module->use_default_type_bo == 1)
1116                         hal_tdm_voutput_set_target_buffer_queue_flag((hal_tdm_voutput *)voutput_backend, TBM_BO_DEFAULT);
1117                 else
1118                         hal_tdm_voutput_set_target_buffer_queue_flag((hal_tdm_voutput *)voutput_backend, TBM_BO_SCANOUT);
1119         } else {
1120                 if (func_voutput->voutput_set_target_buffer_queue_flag) {
1121                         if (private_module->use_default_type_bo == 1)
1122                                 func_voutput->voutput_set_target_buffer_queue_flag(voutput_backend, TBM_BO_DEFAULT);
1123                         else
1124                                 func_voutput->voutput_set_target_buffer_queue_flag(voutput_backend, TBM_BO_SCANOUT);
1125                 }
1126         }
1127
1128         ret = tdm_display_update_output(private_display->current_module, output_backend);
1129         if (ret != TDM_ERROR_NONE) {
1130                 TDM_ERR("tdm_display_update_output fail");
1131                 if (error) *error = ret;
1132                 goto update_output_fail;
1133         }
1134
1135         LIST_FOR_EACH_ENTRY(private_output, &private_module->output_list, link) {
1136                 if (private_output->output_backend == output_backend) {
1137                         output_find = 1;
1138                         break;
1139                 }
1140         }
1141
1142         if (output_find != 1) {
1143                 private_output = NULL;
1144                 free(private_voutput);
1145                 if (private_module->use_hal_tdm) {
1146                         hal_tdm_voutput_destroy((hal_tdm_voutput *)voutput_backend);
1147                 } else {
1148                         if (func_voutput->voutput_destroy)
1149                                 func_voutput->voutput_destroy(voutput_backend);
1150                         else
1151                                 TDM_ERR("no destroy function");
1152                 }
1153                 private_voutput = NULL;
1154         } else {
1155                 strncpy(private_voutput->name, name, TDM_NAME_LEN - 1);
1156                 private_voutput->name[TDM_NAME_LEN - 1] = '\0';
1157                 strncpy(private_output->name, name, TDM_NAME_LEN - 1);
1158                 private_output->name[TDM_NAME_LEN - 1] = '\0';
1159
1160                 private_voutput->private_output = private_output;
1161                 private_output->private_voutput = private_voutput;
1162
1163                 /* do not use vblank */
1164                 tdm_output_choose_commit_per_vblank_mode(private_output, 0);
1165
1166                 LIST_ADDTAIL(&private_voutput->link, &private_module->voutput_list);
1167         }
1168
1169         private_display->current_module = current_module;
1170
1171         _pthread_mutex_unlock(&private_display->lock);
1172
1173         return private_voutput;
1174
1175 update_output_fail:
1176 output_get_fail:
1177         if (private_module->use_hal_tdm) {
1178                 hal_tdm_voutput_destroy((hal_tdm_voutput *)voutput_backend);
1179         } else {
1180                 if (func_voutput->voutput_destroy)
1181                         func_voutput->voutput_destroy(voutput_backend);
1182                 else
1183                         TDM_ERR("no destroy function");
1184         }
1185 voutput_create_fail:
1186         free(private_voutput);
1187         private_display->current_module = current_module;
1188         _pthread_mutex_unlock(&private_display->lock);
1189
1190         return NULL;
1191 }
1192 /* LCOV_EXCL_STOP */