use vblank instead of the output commit handler in case of tdm_layer_commit
[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 <sc1.lim@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.h"
41 #include "tdm_backend.h"
42 #include "tdm_private.h"
43 #include "tdm_helper.h"
44
45 #define COUNT_MAX   10
46
47 #define DISPLAY_FUNC_ENTRY() \
48         tdm_private_display *private_display; \
49         tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\
50         TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER); \
51         private_display = (tdm_private_display*)dpy;
52
53 #define DISPLAY_FUNC_ENTRY_ERROR() \
54         tdm_private_display *private_display; \
55         tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\
56         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(dpy != NULL, TDM_ERROR_INVALID_PARAMETER, NULL); \
57         private_display = (tdm_private_display*)dpy;
58
59 #define OUTPUT_FUNC_ENTRY() \
60         tdm_private_display *private_display; \
61         tdm_private_output *private_output; \
62         tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\
63         TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER); \
64         private_output = (tdm_private_output*)output; \
65         private_display = private_output->private_display
66
67 #define OUTPUT_FUNC_ENTRY_ERROR() \
68         tdm_private_display *private_display; \
69         tdm_private_output *private_output; \
70         tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\
71         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(output != NULL, TDM_ERROR_INVALID_PARAMETER, NULL); \
72         private_output = (tdm_private_output*)output; \
73         private_display = private_output->private_display
74
75 #define LAYER_FUNC_ENTRY() \
76         tdm_private_display *private_display; \
77         tdm_private_output *private_output; \
78         tdm_private_layer *private_layer; \
79         tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\
80         TDM_RETURN_VAL_IF_FAIL(layer != NULL, TDM_ERROR_INVALID_PARAMETER); \
81         private_layer = (tdm_private_layer*)layer; \
82         private_output = private_layer->private_output; \
83         private_display = private_output->private_display
84
85 #define LAYER_FUNC_ENTRY_ERROR() \
86         tdm_private_display *private_display; \
87         tdm_private_output *private_output; \
88         tdm_private_layer *private_layer; \
89         tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\
90         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(layer != NULL, TDM_ERROR_INVALID_PARAMETER, NULL); \
91         private_layer = (tdm_private_layer*)layer; \
92         private_output = private_layer->private_output; \
93         private_display = private_output->private_display
94
95 #define LAYER_FUNC_ENTRY_VOID_RETURN() \
96         tdm_private_display *private_display; \
97         tdm_private_output *private_output; \
98         tdm_private_layer *private_layer; \
99         tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\
100         TDM_RETURN_IF_FAIL(layer != NULL); \
101         private_layer = (tdm_private_layer*)layer; \
102         private_output = private_layer->private_output; \
103         private_display = private_output->private_display
104
105 static void _tdm_layer_committed(tdm_private_layer *private_layer);
106 static void _tdm_layer_cb_wait_vblank(tdm_vblank *vblank, tdm_error error, unsigned int sequence,
107                                                                           unsigned int tv_sec, unsigned int tv_usec, void *user_data);
108
109 EXTERN tdm_error
110 tdm_display_get_capabilities(tdm_display *dpy,
111                                                          tdm_display_capability *capabilities)
112 {
113         DISPLAY_FUNC_ENTRY();
114
115         TDM_RETURN_VAL_IF_FAIL(capabilities != NULL, TDM_ERROR_INVALID_PARAMETER);
116
117         _pthread_mutex_lock(&private_display->lock);
118
119         *capabilities = private_display->capabilities;
120
121         _pthread_mutex_unlock(&private_display->lock);
122
123         return ret;
124 }
125
126 EXTERN tdm_error
127 tdm_display_get_pp_capabilities(tdm_display *dpy,
128                                                                 tdm_pp_capability *capabilities)
129 {
130         DISPLAY_FUNC_ENTRY();
131
132         TDM_RETURN_VAL_IF_FAIL(capabilities != NULL, TDM_ERROR_INVALID_PARAMETER);
133
134         _pthread_mutex_lock(&private_display->lock);
135
136         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP)) {
137                 TDM_ERR("no pp capability");
138                 _pthread_mutex_unlock(&private_display->lock);
139                 return TDM_ERROR_NO_CAPABILITY;
140         }
141
142         *capabilities = private_display->caps_pp.capabilities;
143
144         _pthread_mutex_unlock(&private_display->lock);
145
146         return ret;
147 }
148
149 EXTERN tdm_error
150 tdm_display_get_pp_available_formats(tdm_display *dpy,
151                                                                          const tbm_format **formats, int *count)
152 {
153         DISPLAY_FUNC_ENTRY();
154
155         TDM_RETURN_VAL_IF_FAIL(formats != NULL, TDM_ERROR_INVALID_PARAMETER);
156         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
157
158         _pthread_mutex_lock(&private_display->lock);
159
160         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP)) {
161                 TDM_ERR("no pp capability");
162                 _pthread_mutex_unlock(&private_display->lock);
163                 return TDM_ERROR_NO_CAPABILITY;
164         }
165
166         *formats = (const tbm_format *)private_display->caps_pp.formats;
167         *count = private_display->caps_pp.format_count;
168
169         _pthread_mutex_unlock(&private_display->lock);
170
171         return ret;
172 }
173
174 EXTERN tdm_error
175 tdm_display_get_pp_available_size(tdm_display *dpy, int *min_w, int *min_h,
176                                                                   int *max_w, int *max_h, int *preferred_align)
177 {
178         DISPLAY_FUNC_ENTRY();
179
180         _pthread_mutex_lock(&private_display->lock);
181
182         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP)) {
183                 TDM_ERR("no pp capability");
184                 _pthread_mutex_unlock(&private_display->lock);
185                 return TDM_ERROR_NO_CAPABILITY;
186         }
187
188         if (min_w)
189                 *min_w = TDM_FRONT_VALUE(private_display->caps_pp.min_w);
190         if (min_h)
191                 *min_h = TDM_FRONT_VALUE(private_display->caps_pp.min_h);
192         if (max_w)
193                 *max_w = TDM_FRONT_VALUE(private_display->caps_pp.max_w);
194         if (max_h)
195                 *max_h = TDM_FRONT_VALUE(private_display->caps_pp.max_h);
196         if (preferred_align)
197                 *preferred_align = TDM_FRONT_VALUE(private_display->caps_pp.preferred_align);
198
199         _pthread_mutex_unlock(&private_display->lock);
200
201         return ret;
202 }
203
204 EXTERN tdm_error
205 tdm_display_get_capture_capabilities(tdm_display *dpy,
206                                                                          tdm_capture_capability *capabilities)
207 {
208         DISPLAY_FUNC_ENTRY();
209
210         TDM_RETURN_VAL_IF_FAIL(capabilities != NULL, TDM_ERROR_INVALID_PARAMETER);
211
212         _pthread_mutex_lock(&private_display->lock);
213
214         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)) {
215                 TDM_ERR("no capture capability");
216                 _pthread_mutex_unlock(&private_display->lock);
217                 return TDM_ERROR_NO_CAPABILITY;
218         }
219
220         *capabilities = private_display->caps_capture.capabilities;
221
222         _pthread_mutex_unlock(&private_display->lock);
223
224         return ret;
225 }
226
227 EXTERN tdm_error
228 tdm_display_get_catpure_available_formats(tdm_display *dpy,
229                 const tbm_format **formats, int *count)
230 {
231         DISPLAY_FUNC_ENTRY();
232
233         TDM_RETURN_VAL_IF_FAIL(formats != NULL, TDM_ERROR_INVALID_PARAMETER);
234         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
235
236         _pthread_mutex_lock(&private_display->lock);
237
238         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)) {
239                 TDM_ERR("no capture capability");
240                 _pthread_mutex_unlock(&private_display->lock);
241                 return TDM_ERROR_NO_CAPABILITY;
242         }
243
244         *formats = (const tbm_format *)private_display->caps_capture.formats;
245         *count = private_display->caps_capture.format_count;
246
247         _pthread_mutex_unlock(&private_display->lock);
248
249         return ret;
250 }
251
252 EXTERN tdm_error
253 tdm_display_get_capture_available_size(tdm_display *dpy, int *min_w, int *min_h,
254                                                                            int *max_w, int *max_h, int *preferred_align)
255 {
256         DISPLAY_FUNC_ENTRY();
257
258         _pthread_mutex_lock(&private_display->lock);
259
260         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)) {
261                 TDM_ERR("no capture capability");
262                 _pthread_mutex_unlock(&private_display->lock);
263                 return TDM_ERROR_NO_CAPABILITY;
264         }
265
266         if (min_w)
267                 *min_w = TDM_FRONT_VALUE(private_display->caps_capture.min_w);
268         if (min_h)
269                 *min_h = TDM_FRONT_VALUE(private_display->caps_capture.min_h);
270         if (max_w)
271                 *max_w = TDM_FRONT_VALUE(private_display->caps_capture.max_w);
272         if (max_h)
273                 *max_h = TDM_FRONT_VALUE(private_display->caps_capture.max_h);
274         if (preferred_align)
275                 *preferred_align = TDM_FRONT_VALUE(private_display->caps_capture.preferred_align);
276
277         _pthread_mutex_unlock(&private_display->lock);
278
279         return ret;
280 }
281
282 EXTERN tdm_error
283 tdm_display_get_max_layer_count(tdm_display *dpy, int *max_count)
284 {
285         DISPLAY_FUNC_ENTRY();
286
287         TDM_RETURN_VAL_IF_FAIL(max_count != NULL, TDM_ERROR_INVALID_PARAMETER);
288
289         _pthread_mutex_lock(&private_display->lock);
290
291         *max_count = TDM_FRONT_VALUE(private_display->caps_display.max_layer_count);
292
293         _pthread_mutex_unlock(&private_display->lock);
294
295         return ret;
296 }
297
298 EXTERN tdm_error
299 tdm_display_get_output_count(tdm_display *dpy, int *count)
300 {
301         tdm_private_output *private_output = NULL;
302
303         DISPLAY_FUNC_ENTRY();
304
305         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
306
307         _pthread_mutex_lock(&private_display->lock);
308
309         *count = 0;
310         LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link)
311         (*count)++;
312
313         if (*count == 0) {
314                 _pthread_mutex_unlock(&private_display->lock);
315                 return TDM_ERROR_NONE;
316         }
317
318         _pthread_mutex_unlock(&private_display->lock);
319
320         return ret;
321 }
322
323
324 EXTERN tdm_output *
325 tdm_display_get_output(tdm_display *dpy, int index, tdm_error *error)
326 {
327         tdm_private_output *private_output = NULL;
328
329         DISPLAY_FUNC_ENTRY_ERROR();
330
331         _pthread_mutex_lock(&private_display->lock);
332
333         if (error)
334                 *error = TDM_ERROR_NONE;
335
336         LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link) {
337                 if (private_output->index == index) {
338                         _pthread_mutex_unlock(&private_display->lock);
339                         return private_output;
340                 }
341         }
342
343         _pthread_mutex_unlock(&private_display->lock);
344
345         return NULL;
346 }
347
348 EXTERN tdm_error
349 tdm_display_get_fd(tdm_display *dpy, int *fd)
350 {
351         DISPLAY_FUNC_ENTRY();
352
353         TDM_RETURN_VAL_IF_FAIL(fd != NULL, TDM_ERROR_INVALID_PARAMETER);
354
355         _pthread_mutex_lock(&private_display->lock);
356
357         if (tdm_thread_is_running())
358                 *fd = tdm_thread_get_fd(private_display->private_loop);
359         else
360                 *fd = tdm_event_loop_get_fd(private_display);
361
362         _pthread_mutex_unlock(&private_display->lock);
363
364         return ret;
365 }
366
367 EXTERN tdm_error
368 tdm_display_handle_events(tdm_display *dpy)
369 {
370         struct pollfd fds;
371         int fd = -1;
372
373         DISPLAY_FUNC_ENTRY();
374
375         ret = tdm_display_get_fd(dpy, &fd);
376         TDM_RETURN_VAL_IF_FAIL(fd >= 0, ret);
377
378         fds.events = POLLIN;
379         fds.fd = fd;
380         fds.revents = 0;
381
382         if (tdm_debug_module & TDM_DEBUG_THREAD)
383                 TDM_INFO("fd(%d) polling in", fd);
384
385         while (poll(&fds, 1, -1) < 0) {
386                 if (errno == EINTR || errno == EAGAIN)  /* normal case */
387                         continue;
388                 else {
389                         TDM_ERR("poll failed: %m");
390                         return TDM_ERROR_OPERATION_FAILED;
391                 }
392         }
393
394         if (tdm_debug_module & TDM_DEBUG_THREAD)
395                 TDM_INFO("fd(%d) polling out", fd);
396
397         if (tdm_thread_is_running())
398                 ret = tdm_thread_handle_cb(private_display->private_loop);
399         else
400                 ret = tdm_event_loop_dispatch(private_display);
401
402         return ret;
403 }
404
405 EXTERN tdm_error
406 tdm_display_get_backend_info(tdm_display *dpy, const char **name,
407                                                          const char **vendor, int *major, int *minor)
408 {
409         tdm_backend_module *module_data;
410
411         DISPLAY_FUNC_ENTRY();
412
413         _pthread_mutex_lock(&private_display->lock);
414
415         module_data = private_display->module_data;
416
417         if (name)
418                 *name = module_data->name;
419         if (vendor)
420                 *vendor = module_data->vendor;
421         if (major)
422                 *major = TDM_BACKEND_GET_ABI_MAJOR(module_data->abi_version);
423         if (minor)
424                 *minor = TDM_BACKEND_GET_ABI_MINOR(module_data->abi_version);
425
426         _pthread_mutex_unlock(&private_display->lock);
427
428         return ret;
429 }
430
431 EXTERN tdm_pp *
432 tdm_display_create_pp(tdm_display *dpy, tdm_error *error)
433 {
434         tdm_pp *pp;
435
436         DISPLAY_FUNC_ENTRY_ERROR();
437
438         _pthread_mutex_lock(&private_display->lock);
439
440         pp = (tdm_pp *)tdm_pp_create_internal(private_display, error);
441
442         _pthread_mutex_unlock(&private_display->lock);
443
444         return pp;
445 }
446
447 EXTERN tdm_error
448 tdm_output_get_model_info(tdm_output *output, const char **maker,
449                                                   const char **model, const char **name)
450 {
451         OUTPUT_FUNC_ENTRY();
452
453         _pthread_mutex_lock(&private_display->lock);
454
455         if (maker)
456                 *maker = private_output->caps.maker;
457         if (model)
458                 *model = private_output->caps.model;
459         if (name)
460                 *name = private_output->caps.name;
461
462         _pthread_mutex_unlock(&private_display->lock);
463
464         return ret;
465 }
466
467 EXTERN tdm_error
468 tdm_output_get_capabilities(tdm_output *output, tdm_output_capability *capabilities)
469 {
470         OUTPUT_FUNC_ENTRY();
471
472         TDM_RETURN_VAL_IF_FAIL(capabilities != NULL, TDM_ERROR_INVALID_PARAMETER);
473
474         _pthread_mutex_lock(&private_display->lock);
475
476         *capabilities = private_output->caps.capabilities;
477
478         _pthread_mutex_unlock(&private_display->lock);
479
480         return ret;
481 }
482
483 EXTERN tdm_error
484 tdm_output_get_conn_status(tdm_output *output, tdm_output_conn_status *status)
485 {
486         OUTPUT_FUNC_ENTRY();
487
488         TDM_RETURN_VAL_IF_FAIL(status != NULL, TDM_ERROR_INVALID_PARAMETER);
489
490         _pthread_mutex_lock(&private_display->lock);
491
492         *status = private_output->caps.status;
493
494         _pthread_mutex_unlock(&private_display->lock);
495
496         return ret;
497 }
498
499 static unsigned int
500 _tdm_output_used_layer_count(tdm_private_output *private_output)
501 {
502         tdm_private_layer *private_layer = NULL;
503         unsigned int count = 0;
504
505         LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
506                 if (!private_layer->usable)
507                         count++;
508         }
509
510         return count;
511 }
512
513 static void
514 _tdm_output_update(tdm_output *output_backend, void *user_data)
515 {
516         tdm_private_display *private_display;
517         tdm_private_output *private_output = user_data;
518         tdm_error ret;
519
520         TDM_RETURN_IF_FAIL(private_output);
521
522         private_display = private_output->private_display;
523
524         ret = tdm_display_update_output(private_display, output_backend, private_output->pipe);
525         TDM_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
526 }
527
528 INTERN void
529 tdm_output_cb_status(tdm_output *output_backend, tdm_output_conn_status status,
530                                          void *user_data)
531 {
532         tdm_private_display *private_display;
533         tdm_private_output *private_output = user_data;
534         tdm_value value;
535
536         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
537         TDM_RETURN_IF_FAIL(private_output);
538
539         private_display = private_output->private_display;
540
541         if (!tdm_thread_in_display_thread(syscall(SYS_gettid))) {
542                 tdm_thread_cb_output_status output_status;
543                 tdm_error ret;
544
545                 _tdm_output_update(output_backend, user_data);
546
547                 output_status.base.type = TDM_THREAD_CB_OUTPUT_STATUS;
548                 output_status.base.length = sizeof output_status;
549                 output_status.output_stamp = private_output->stamp;
550                 output_status.status = status;
551                 output_status.user_data = user_data;
552
553                 value.u32 = status;
554                 tdm_output_call_change_handler_internal(private_output,
555                                                                                                 &private_output->change_handler_list_sub,
556                                                                                                 TDM_OUTPUT_CHANGE_CONNECTION,
557                                                                                                 value, 0);
558
559                 ret = tdm_thread_send_cb(private_display->private_loop, &output_status.base);
560                 TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
561
562                 return;
563         }
564
565         if (!tdm_thread_is_running())
566                 _tdm_output_update(output_backend, user_data);
567
568         value.u32 = status;
569         tdm_output_call_change_handler_internal(private_output,
570                                                                                         &private_output->change_handler_list_main,
571                                                                                         TDM_OUTPUT_CHANGE_CONNECTION,
572                                                                                         value, 0);
573 }
574
575 EXTERN tdm_error
576 tdm_output_add_change_handler(tdm_output *output,
577                                                           tdm_output_change_handler func,
578                                                           void *user_data)
579 {
580         tdm_private_change_handler *change_handler;
581         OUTPUT_FUNC_ENTRY();
582
583         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
584
585         pthread_mutex_lock(&private_display->lock);
586
587         change_handler = calloc(1, sizeof(tdm_private_change_handler));
588         if (!change_handler) {
589                 TDM_ERR("failed: alloc memory");
590                 _pthread_mutex_unlock(&private_display->lock);
591                 return TDM_ERROR_OUT_OF_MEMORY;
592         }
593
594         change_handler->private_output = private_output;
595         change_handler->func = func;
596         change_handler->user_data = user_data;
597         change_handler->owner_tid = syscall(SYS_gettid);
598
599         if (!tdm_thread_in_display_thread(change_handler->owner_tid))
600                 LIST_ADD(&change_handler->link, &private_output->change_handler_list_sub);
601         else
602                 LIST_ADD(&change_handler->link, &private_output->change_handler_list_main);
603
604         _pthread_mutex_unlock(&private_display->lock);
605
606         return ret;
607 }
608
609 EXTERN void
610 tdm_output_remove_change_handler(tdm_output *output,
611                                                                  tdm_output_change_handler func,
612                                                                  void *user_data)
613 {
614         tdm_private_display *private_display;
615         tdm_private_output *private_output;
616         tdm_private_change_handler *h = NULL, *hh = NULL;
617
618         TDM_RETURN_IF_FAIL(output != NULL);
619         TDM_RETURN_IF_FAIL(func != NULL);
620
621         private_output = (tdm_private_output*)output;
622         private_display = private_output->private_display;
623
624         _pthread_mutex_lock(&private_display->lock);
625
626         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_main, link) {
627                 if (h->func != func || h->user_data != user_data)
628                         continue;
629
630                 LIST_DEL(&h->link);
631                 free(h);
632
633                 _pthread_mutex_unlock(&private_display->lock);
634
635                 return;
636         }
637
638         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_sub, link) {
639                 if (h->func != func || h->user_data != user_data)
640                         continue;
641
642                 LIST_DEL(&h->link);
643                 free(h);
644
645                 _pthread_mutex_unlock(&private_display->lock);
646
647                 return;
648         }
649
650         _pthread_mutex_unlock(&private_display->lock);
651 }
652
653 EXTERN tdm_error
654 tdm_output_get_output_type(tdm_output *output, tdm_output_type *type)
655 {
656         OUTPUT_FUNC_ENTRY();
657
658         TDM_RETURN_VAL_IF_FAIL(type != NULL, TDM_ERROR_INVALID_PARAMETER);
659
660         _pthread_mutex_lock(&private_display->lock);
661
662         *type = private_output->caps.type;
663
664         _pthread_mutex_unlock(&private_display->lock);
665
666         return ret;
667 }
668
669 EXTERN tdm_error
670 tdm_output_get_layer_count(tdm_output *output, int *count)
671 {
672         tdm_private_layer *private_layer = NULL;
673
674         OUTPUT_FUNC_ENTRY();
675
676         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
677
678         _pthread_mutex_lock(&private_display->lock);
679
680         *count = 0;
681         LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link)
682         (*count)++;
683         if (*count == 0) {
684                 _pthread_mutex_unlock(&private_display->lock);
685                 return TDM_ERROR_NONE;
686         }
687
688         _pthread_mutex_unlock(&private_display->lock);
689
690         return ret;
691 }
692
693
694 EXTERN tdm_layer *
695 tdm_output_get_layer(tdm_output *output, int index, tdm_error *error)
696 {
697         tdm_private_layer *private_layer = NULL;
698
699         OUTPUT_FUNC_ENTRY_ERROR();
700
701         _pthread_mutex_lock(&private_display->lock);
702
703         if (error)
704                 *error = TDM_ERROR_NONE;
705
706         LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
707                 if (private_layer->index == index) {
708                         _pthread_mutex_unlock(&private_display->lock);
709                         return private_layer;
710                 }
711         }
712
713         _pthread_mutex_unlock(&private_display->lock);
714
715         return NULL;
716 }
717
718 EXTERN tdm_error
719 tdm_output_get_available_properties(tdm_output *output, const tdm_prop **props,
720                                                                         int *count)
721 {
722         OUTPUT_FUNC_ENTRY();
723
724         TDM_RETURN_VAL_IF_FAIL(props != NULL, TDM_ERROR_INVALID_PARAMETER);
725         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
726
727         _pthread_mutex_lock(&private_display->lock);
728
729         *props = (const tdm_prop *)private_output->caps.props;
730         *count = private_output->caps.prop_count;
731
732         _pthread_mutex_unlock(&private_display->lock);
733
734         return ret;
735 }
736
737 EXTERN tdm_error
738 tdm_output_get_available_modes(tdm_output *output,
739                                                            const tdm_output_mode **modes, int *count)
740 {
741         OUTPUT_FUNC_ENTRY();
742
743         TDM_RETURN_VAL_IF_FAIL(modes != NULL, TDM_ERROR_INVALID_PARAMETER);
744         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
745
746         _pthread_mutex_lock(&private_display->lock);
747
748         *modes = (const tdm_output_mode *)private_output->caps.modes;
749         *count = private_output->caps.mode_count;
750
751         _pthread_mutex_unlock(&private_display->lock);
752
753         return ret;
754 }
755
756 EXTERN tdm_error
757 tdm_output_get_available_size(tdm_output *output, int *min_w, int *min_h,
758                                                           int *max_w, int *max_h, int *preferred_align)
759 {
760         OUTPUT_FUNC_ENTRY();
761
762         _pthread_mutex_lock(&private_display->lock);
763
764         if (min_w)
765                 *min_w = TDM_FRONT_VALUE(private_output->caps.min_w);
766         if (min_h)
767                 *min_h = TDM_FRONT_VALUE(private_output->caps.min_h);
768         if (max_w)
769                 *max_w = TDM_FRONT_VALUE(private_output->caps.max_w);
770         if (max_h)
771                 *max_h = TDM_FRONT_VALUE(private_output->caps.max_h);
772         if (preferred_align)
773                 *preferred_align = TDM_FRONT_VALUE(private_output->caps.preferred_align);
774
775         _pthread_mutex_unlock(&private_display->lock);
776
777         return ret;
778 }
779
780 EXTERN tdm_error
781 tdm_output_get_cursor_available_size(tdm_output *output, int *min_w, int *min_h,
782                                                                          int *max_w, int *max_h, int *preferred_align)
783 {
784         OUTPUT_FUNC_ENTRY();
785
786         _pthread_mutex_lock(&private_display->lock);
787
788         if (!tdm_display_check_module_abi(private_display, 1, 5)) {
789
790                 if (min_w)
791                         *min_w = -1;
792                 if (min_h)
793                         *min_h = -1;
794                 if (max_w)
795                         *max_w = -1;
796                 if (max_h)
797                         *max_h = -1;
798                 if (preferred_align)
799                         *preferred_align = -1;
800
801                 _pthread_mutex_unlock(&private_display->lock);
802
803                 return TDM_ERROR_BAD_MODULE;
804         }
805
806         if (min_w)
807                 *min_w = TDM_FRONT_VALUE(private_output->caps.cursor_min_w);
808         if (min_h)
809                 *min_h = TDM_FRONT_VALUE(private_output->caps.cursor_min_h);
810         if (max_w)
811                 *max_w = TDM_FRONT_VALUE(private_output->caps.cursor_max_w);
812         if (max_h)
813                 *max_h = TDM_FRONT_VALUE(private_output->caps.cursor_max_h);
814         if (preferred_align)
815                 *preferred_align = TDM_FRONT_VALUE(private_output->caps.cursor_preferred_align);
816
817         _pthread_mutex_unlock(&private_display->lock);
818
819         return ret;
820 }
821
822 EXTERN tdm_error
823 tdm_output_get_physical_size(tdm_output *output, unsigned int *mmWidth,
824                                                          unsigned int *mmHeight)
825 {
826         OUTPUT_FUNC_ENTRY();
827
828         _pthread_mutex_lock(&private_display->lock);
829
830         if (mmWidth)
831                 *mmWidth = private_output->caps.mmWidth;
832         if (mmHeight)
833                 *mmHeight = private_output->caps.mmHeight;
834
835         _pthread_mutex_unlock(&private_display->lock);
836
837         return ret;
838 }
839
840 EXTERN tdm_error
841 tdm_output_get_subpixel(tdm_output *output, unsigned int *subpixel)
842 {
843         OUTPUT_FUNC_ENTRY();
844         TDM_RETURN_VAL_IF_FAIL(subpixel != NULL, TDM_ERROR_INVALID_PARAMETER);
845
846         _pthread_mutex_lock(&private_display->lock);
847
848         *subpixel = private_output->caps.subpixel;
849
850         _pthread_mutex_unlock(&private_display->lock);
851
852         return ret;
853 }
854
855 EXTERN tdm_error
856 tdm_output_get_pipe(tdm_output *output, unsigned int *pipe)
857 {
858         OUTPUT_FUNC_ENTRY();
859         TDM_RETURN_VAL_IF_FAIL(pipe != NULL, TDM_ERROR_INVALID_PARAMETER);
860
861         _pthread_mutex_lock(&private_display->lock);
862
863         *pipe = private_output->pipe;
864
865         _pthread_mutex_unlock(&private_display->lock);
866
867         return ret;
868 }
869
870 EXTERN tdm_error
871 tdm_output_get_primary_index(tdm_output *output, int *index)
872 {
873         tdm_private_layer *private_layer = NULL;
874
875         OUTPUT_FUNC_ENTRY();
876         TDM_RETURN_VAL_IF_FAIL(index != NULL, TDM_ERROR_INVALID_PARAMETER);
877
878         _pthread_mutex_lock(&private_display->lock);
879
880         LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
881                 if (private_layer->caps.capabilities & TDM_LAYER_CAPABILITY_PRIMARY) {
882                         *index = private_layer->index;
883                         break;
884                 }
885         }
886
887         _pthread_mutex_unlock(&private_display->lock);
888
889         return ret;
890 }
891
892 EXTERN tdm_error
893 tdm_output_set_property(tdm_output *output, unsigned int id, tdm_value value)
894 {
895         tdm_func_output *func_output;
896         OUTPUT_FUNC_ENTRY();
897
898         _pthread_mutex_lock(&private_display->lock);
899
900         func_output = &private_display->func_output;
901
902         if (!func_output->output_set_property) {
903                 _pthread_mutex_unlock(&private_display->lock);
904                 TDM_ERR("not implemented!!");
905                 return TDM_ERROR_NOT_IMPLEMENTED;
906         }
907
908         ret = func_output->output_set_property(private_output->output_backend, id,
909                                                                                    value);
910
911         _pthread_mutex_unlock(&private_display->lock);
912
913         return ret;
914 }
915
916 EXTERN tdm_error
917 tdm_output_get_property(tdm_output *output, unsigned int id, tdm_value *value)
918 {
919         tdm_func_output *func_output;
920         OUTPUT_FUNC_ENTRY();
921
922         TDM_RETURN_VAL_IF_FAIL(value != NULL, TDM_ERROR_INVALID_PARAMETER);
923
924         _pthread_mutex_lock(&private_display->lock);
925
926         func_output = &private_display->func_output;
927
928         if (!func_output->output_get_property) {
929                 _pthread_mutex_unlock(&private_display->lock);
930                 TDM_ERR("not implemented!!");
931                 return TDM_ERROR_NOT_IMPLEMENTED;
932         }
933
934         ret = func_output->output_get_property(private_output->output_backend, id,
935                                                                                    value);
936
937         _pthread_mutex_unlock(&private_display->lock);
938
939         return ret;
940 }
941
942 INTERN void
943 tdm_output_cb_vblank(tdm_output *output_backend, unsigned int sequence,
944                                          unsigned int tv_sec, unsigned int tv_usec, void *user_data)
945 {
946         tdm_private_vblank_handler *vblank_handler = user_data;
947         tdm_private_vblank_handler *v = NULL, *vv = NULL;
948         tdm_private_output *private_output;
949         tdm_private_display *private_display;
950         struct list_head clone_list;
951         int interval, sync;
952         pid_t tid = syscall(SYS_gettid);
953
954         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
955         TDM_RETURN_IF_FAIL(vblank_handler);
956
957         private_output = vblank_handler->private_output;
958         private_display = private_output->private_display;
959
960         if (vblank_handler->owner_tid != tid) {
961                 tdm_thread_cb_output_vblank output_vblank;
962                 tdm_error ret;
963
964                 output_vblank.base.type = TDM_THREAD_CB_OUTPUT_VBLANK;
965                 output_vblank.base.length = sizeof output_vblank;
966                 output_vblank.output_stamp = vblank_handler->private_output->stamp;
967                 output_vblank.sequence = sequence;
968                 output_vblank.tv_sec = tv_sec;
969                 output_vblank.tv_usec = tv_usec;
970                 output_vblank.user_data = user_data;
971
972                 ret = tdm_thread_send_cb(private_display->private_loop, &output_vblank.base);
973                 TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
974
975                 return;
976         }
977
978         if (vblank_handler->owner_tid != tid)
979                 TDM_NEVER_GET_HERE();
980
981         interval = vblank_handler->interval;
982         sync = vblank_handler->sync;
983
984         LIST_INITHEAD(&clone_list);
985
986         LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_handler_list, link) {
987                 if (v->interval != interval || v->sync != sync || v->owner_tid != tid)
988                         continue;
989
990                 LIST_DEL(&v->link);
991                 LIST_ADDTAIL(&v->link, &clone_list);
992         }
993
994         _pthread_mutex_unlock(&private_display->lock);
995         LIST_FOR_EACH_ENTRY_SAFE(v, vv, &clone_list, link) {
996                 if (v->func)
997                         v->func(v->private_output, sequence, tv_sec, tv_usec, v->user_data);
998                 LIST_DEL(&v->link);
999                 free(v);
1000         }
1001         _pthread_mutex_lock(&private_display->lock);
1002 }
1003
1004 INTERN void
1005 tdm_output_cb_commit(tdm_output *output_backend, unsigned int sequence,
1006                                          unsigned int tv_sec, unsigned int tv_usec, void *user_data)
1007 {
1008         tdm_private_output_commit_handler *output_commit_handler = user_data;
1009         tdm_private_display *private_display;
1010         tdm_private_output *private_output;
1011         tdm_private_layer *private_layer = NULL;
1012
1013         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
1014
1015         if (!output_commit_handler)
1016                 return;
1017
1018         private_output = output_commit_handler->private_output;
1019         private_display = private_output->private_display;
1020
1021         if (output_commit_handler->owner_tid != syscall(SYS_gettid)) {
1022                 tdm_thread_cb_output_commit output_commit;
1023                 tdm_error ret;
1024
1025                 output_commit.base.type = TDM_THREAD_CB_OUTPUT_COMMIT;
1026                 output_commit.base.length = sizeof output_commit;
1027                 output_commit.output_stamp = private_output->stamp;
1028                 output_commit.sequence = sequence;
1029                 output_commit.tv_sec = tv_sec;
1030                 output_commit.tv_usec = tv_usec;
1031                 output_commit.user_data = user_data;
1032
1033                 ret = tdm_thread_send_cb(private_display->private_loop, &output_commit.base);
1034                 TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
1035
1036                 return;
1037         }
1038
1039         if (private_display->commit_type == TDM_COMMIT_TYPE_OUTPUT) {
1040                 /* In case of layer commit, the below will be handled in the layer commit callback */
1041                 LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
1042                         _tdm_layer_committed(private_layer);
1043                 }
1044         }
1045
1046         if (output_commit_handler->func) {
1047                 _pthread_mutex_unlock(&private_display->lock);
1048                 output_commit_handler->func(private_output, sequence,
1049                                                                         tv_sec, tv_usec, output_commit_handler->user_data);
1050                 _pthread_mutex_lock(&private_display->lock);
1051         }
1052
1053         LIST_DEL(&output_commit_handler->link);
1054         free(output_commit_handler);
1055 }
1056
1057 /* add_front: To distinguish between the user vblank handlers and the layer
1058  *            commit vblank handlers. The layer commit handlers will be called
1059  *            before calling the user vblank handlers.
1060  */
1061 static tdm_error
1062 _tdm_output_wait_vblank(tdm_output *output, int interval, int sync,
1063                                                 tdm_output_vblank_handler func, void *user_data,
1064                                                 unsigned int add_front)
1065 {
1066         tdm_func_output *func_output;
1067         tdm_private_vblank_handler *vblank_handler = NULL, *v = NULL;
1068         unsigned int skip_request = 0;
1069         pid_t tid = syscall(SYS_gettid);
1070
1071         OUTPUT_FUNC_ENTRY();
1072
1073         func_output = &private_display->func_output;
1074
1075         /* interval SHOULD be at least 1 */
1076         if (interval <= 0)
1077                 interval = 1;
1078
1079         if (!func_output->output_wait_vblank) {
1080                 TDM_ERR("not implemented!!");
1081                 return TDM_ERROR_NOT_IMPLEMENTED;
1082         }
1083
1084         if (!private_output->regist_vblank_cb) {
1085                 private_output->regist_vblank_cb = 1;
1086                 ret = func_output->output_set_vblank_handler(private_output->output_backend,
1087                                 tdm_output_cb_vblank);
1088         }
1089
1090         vblank_handler = calloc(1, sizeof(tdm_private_vblank_handler));
1091         if (!vblank_handler) {
1092                 TDM_ERR("failed: alloc memory");
1093                 return TDM_ERROR_OUT_OF_MEMORY;
1094         }
1095
1096         LIST_FOR_EACH_ENTRY(v, &private_output->vblank_handler_list, link) {
1097                 if (v->interval == interval && v->sync == sync && v->owner_tid == tid) {
1098                         skip_request = 1;
1099                         break;
1100                 }
1101         }
1102
1103         if (add_front)
1104                 LIST_ADD(&vblank_handler->link, &private_output->vblank_handler_list);
1105         else
1106                 LIST_ADDTAIL(&vblank_handler->link, &private_output->vblank_handler_list);
1107
1108         vblank_handler->private_output = private_output;
1109         vblank_handler->interval = interval;
1110         vblank_handler->sync = sync;
1111         vblank_handler->func = func;
1112         vblank_handler->user_data = user_data;
1113         vblank_handler->owner_tid = tid;
1114
1115         /* If there is the previous request, we can skip to call output_wait_vblank() */
1116         if (!skip_request) {
1117                 ret = func_output->output_wait_vblank(private_output->output_backend, interval,
1118                                                                                           sync, vblank_handler);
1119                 TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, wait_failed);
1120         }
1121
1122         return ret;
1123
1124 wait_failed:
1125         if (vblank_handler) {
1126                 LIST_DEL(&vblank_handler->link);
1127                 free(vblank_handler);
1128         }
1129         return ret;
1130 }
1131
1132 EXTERN tdm_error
1133 tdm_output_wait_vblank(tdm_output *output, int interval, int sync,
1134                                            tdm_output_vblank_handler func, void *user_data)
1135 {
1136         OUTPUT_FUNC_ENTRY();
1137
1138         _pthread_mutex_lock(&private_display->lock);
1139
1140         if (private_output->current_dpms_value > TDM_OUTPUT_DPMS_ON) {
1141                 TDM_WRN("output(%d) dpms: %s", private_output->pipe,
1142                                 tdm_dpms_str(private_output->current_dpms_value));
1143                 _pthread_mutex_unlock(&private_display->lock);
1144                 return TDM_ERROR_DPMS_OFF;
1145         }
1146
1147         ret = _tdm_output_wait_vblank(output, interval, sync, func, user_data, 0);
1148
1149         _pthread_mutex_unlock(&private_display->lock);
1150
1151         return ret;
1152 }
1153
1154 EXTERN tdm_error
1155 tdm_output_wait_vblank_add_front(tdm_output *output, int interval, int sync,
1156                                                                  tdm_output_vblank_handler func, void *user_data)
1157 {
1158         OUTPUT_FUNC_ENTRY();
1159
1160         _pthread_mutex_lock(&private_display->lock);
1161
1162         if (private_output->current_dpms_value > TDM_OUTPUT_DPMS_ON) {
1163                 TDM_WRN("output(%d) dpms: %s", private_output->pipe,
1164                                 tdm_dpms_str(private_output->current_dpms_value));
1165                 _pthread_mutex_unlock(&private_display->lock);
1166                 return TDM_ERROR_DPMS_OFF;
1167         }
1168
1169         ret = _tdm_output_wait_vblank(output, interval, sync, func, user_data, 1);
1170
1171         _pthread_mutex_unlock(&private_display->lock);
1172
1173         return ret;
1174 }
1175
1176 static tdm_error
1177 _tdm_output_commit(tdm_output *output, int sync, tdm_output_commit_handler func,
1178                                    void *user_data)
1179 {
1180         tdm_func_output *func_output;
1181         tdm_private_output_commit_handler *output_commit_handler = NULL;
1182         OUTPUT_FUNC_ENTRY();
1183
1184         func_output = &private_display->func_output;
1185
1186         if (!func_output->output_commit) {
1187                 TDM_ERR("not implemented!!");
1188                 return TDM_ERROR_NOT_IMPLEMENTED;
1189         }
1190
1191         if (func) {
1192                 if (!private_output->regist_commit_cb) {
1193                         private_output->regist_commit_cb = 1;
1194                         ret = func_output->output_set_commit_handler(private_output->output_backend,
1195                                         tdm_output_cb_commit);
1196                         TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed);
1197                 }
1198
1199                 output_commit_handler = calloc(1, sizeof(tdm_private_output_commit_handler));
1200                 if (!output_commit_handler) {
1201                         TDM_ERR("failed: alloc memory");
1202                         return TDM_ERROR_OUT_OF_MEMORY;
1203                 }
1204
1205                 LIST_ADD(&output_commit_handler->link, &private_output->output_commit_handler_list);
1206                 output_commit_handler->private_output = private_output;
1207                 output_commit_handler->func = func;
1208                 output_commit_handler->user_data = user_data;
1209                 output_commit_handler->owner_tid = syscall(SYS_gettid);
1210         }
1211
1212         ret = func_output->output_commit(private_output->output_backend, sync,
1213                                                                          output_commit_handler);
1214         TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed);
1215
1216         if (tdm_debug_module & TDM_DEBUG_COMMIT)
1217                 TDM_INFO("output(%d) backend commit", private_output->pipe);
1218
1219         return ret;
1220
1221 commit_failed:
1222         if (output_commit_handler) {
1223                 LIST_DEL(&output_commit_handler->link);
1224                 free(output_commit_handler);
1225         }
1226         return ret;
1227 }
1228
1229 EXTERN tdm_error
1230 tdm_output_commit(tdm_output *output, int sync, tdm_output_commit_handler func,
1231                                   void *user_data)
1232 {
1233         OUTPUT_FUNC_ENTRY();
1234
1235         _pthread_mutex_lock(&private_display->lock);
1236
1237         if (private_display->commit_type == TDM_COMMIT_TYPE_NONE)
1238                 private_display->commit_type = TDM_COMMIT_TYPE_OUTPUT;
1239         else if (private_display->commit_type == TDM_COMMIT_TYPE_LAYER) {
1240                 TDM_ERR("Can't supported. Use tdm_layer_commit");
1241                 _pthread_mutex_unlock(&private_display->lock);
1242                 return TDM_ERROR_BAD_REQUEST;
1243         }
1244
1245         if (private_display->commit_per_vblank) {
1246                 TDM_ERR("Use tdm_layer_commit");
1247                 _pthread_mutex_unlock(&private_display->lock);
1248                 return TDM_ERROR_BAD_REQUEST;
1249         }
1250
1251         if (private_output->current_dpms_value > TDM_OUTPUT_DPMS_ON) {
1252                 TDM_ERR("output(%d) dpms: %s", private_output->pipe,
1253                                 tdm_dpms_str(private_output->current_dpms_value));
1254                 _pthread_mutex_unlock(&private_display->lock);
1255                 return TDM_ERROR_DPMS_OFF;
1256         }
1257
1258         if (tdm_debug_module & TDM_DEBUG_COMMIT)
1259                 TDM_INFO("output(%d) commit", private_output->pipe);
1260
1261         ret = _tdm_output_commit(output, sync, func, user_data);
1262
1263         _pthread_mutex_unlock(&private_display->lock);
1264
1265         return ret;
1266 }
1267
1268 EXTERN tdm_error
1269 tdm_output_set_mode(tdm_output *output, const tdm_output_mode *mode)
1270 {
1271         tdm_func_output *func_output;
1272         OUTPUT_FUNC_ENTRY();
1273
1274         TDM_RETURN_VAL_IF_FAIL(mode != NULL, TDM_ERROR_INVALID_PARAMETER);
1275
1276         _pthread_mutex_lock(&private_display->lock);
1277
1278         func_output = &private_display->func_output;
1279
1280         if (!func_output->output_set_mode) {
1281                 _pthread_mutex_unlock(&private_display->lock);
1282                 TDM_ERR("not implemented!!");
1283                 return TDM_ERROR_NOT_IMPLEMENTED;
1284         }
1285
1286         ret = func_output->output_set_mode(private_output->output_backend, mode);
1287         if (ret == TDM_ERROR_NONE)
1288                 private_output->current_mode = mode;
1289         _pthread_mutex_unlock(&private_display->lock);
1290
1291         return ret;
1292 }
1293
1294 EXTERN tdm_error
1295 tdm_output_get_mode(tdm_output *output, const tdm_output_mode **mode)
1296 {
1297         OUTPUT_FUNC_ENTRY();
1298
1299         TDM_RETURN_VAL_IF_FAIL(mode != NULL, TDM_ERROR_INVALID_PARAMETER);
1300
1301         _pthread_mutex_lock(&private_display->lock);
1302
1303         *mode = private_output->current_mode;
1304
1305         _pthread_mutex_unlock(&private_display->lock);
1306
1307         return ret;
1308 }
1309
1310 static tdm_error
1311 _tdm_output_dpms_changed_timeout(void *user_data)
1312 {
1313         tdm_private_output *private_output = user_data;
1314         tdm_value value;
1315
1316         value.u32 = private_output->current_dpms_value;
1317         tdm_output_call_change_handler_internal(private_output,
1318                                                                                         &private_output->change_handler_list_sub,
1319                                                                                         TDM_OUTPUT_CHANGE_DPMS,
1320                                                                                         value, 0);
1321
1322         return TDM_ERROR_NONE;
1323 }
1324
1325 INTERN void
1326 tdm_output_cb_dpms(tdm_output *output_backend, tdm_output_dpms dpms, void *user_data)
1327 {
1328         tdm_private_display *private_display;
1329         tdm_private_output *private_output = user_data;
1330         tdm_value value;
1331
1332         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
1333         TDM_RETURN_IF_FAIL(private_output);
1334
1335         private_display = private_output->private_display;
1336
1337         if (!tdm_thread_in_display_thread(syscall(SYS_gettid))) {
1338                 tdm_thread_cb_output_dpms output_dpms;
1339                 tdm_error ret;
1340
1341                 _tdm_output_update(output_backend, user_data);
1342
1343                 output_dpms.base.type = TDM_THREAD_CB_OUTPUT_DPMS;
1344                 output_dpms.base.length = sizeof output_dpms;
1345                 output_dpms.output_stamp = private_output->stamp;
1346                 output_dpms.dpms = dpms;
1347                 output_dpms.user_data = user_data;
1348
1349                 value.u32 = dpms;
1350                 tdm_output_call_change_handler_internal(private_output,
1351                                                                                                 &private_output->change_handler_list_sub,
1352                                                                                                 TDM_OUTPUT_CHANGE_DPMS,
1353                                                                                                 value, 0);
1354
1355                 ret = tdm_thread_send_cb(private_display->private_loop, &output_dpms.base);
1356                 TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
1357
1358                 return;
1359         }
1360
1361         private_output->current_dpms_value = dpms;
1362
1363         value.u32 = dpms;
1364         tdm_output_call_change_handler_internal(private_output,
1365                                                                                         &private_output->change_handler_list_main,
1366                                                                                         TDM_OUTPUT_CHANGE_DPMS,
1367                                                                                         value, 0);
1368 }
1369
1370 EXTERN tdm_error
1371 tdm_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value)
1372 {
1373         tdm_func_output *func_output;
1374         OUTPUT_FUNC_ENTRY();
1375
1376         if (dpms_value > TDM_OUTPUT_DPMS_OFF)
1377                 dpms_value = TDM_OUTPUT_DPMS_OFF;
1378
1379         _pthread_mutex_lock(&private_display->lock);
1380
1381         if (private_output->current_dpms_value == dpms_value) {
1382                 _pthread_mutex_unlock(&private_display->lock);
1383                 return TDM_ERROR_NONE;
1384         }
1385
1386         /** Use timer to call the output change callback of the sub-thread.
1387          * The output change callback of tdm_server and tdm_vblank was called
1388          * in the main thread. And it made the multi thread issue. If we use
1389          * the timer, we can call the sub-thread's output change callback in
1390          * sub-thread.
1391          */
1392         if (!private_output->dpms_changed_timer) {
1393                 private_output->dpms_changed_timer =
1394                         tdm_event_loop_add_timer_handler(private_output->private_display,
1395                                                                                          _tdm_output_dpms_changed_timeout, private_output, NULL);
1396                 if (!private_output->dpms_changed_timer) {
1397                         TDM_ERR("can't create dpms timer!!");
1398                         _pthread_mutex_unlock(&private_display->lock);
1399                         return TDM_ERROR_OUT_OF_MEMORY;
1400                 }
1401         }
1402
1403         func_output = &private_display->func_output;
1404
1405         if (!func_output->output_set_dpms) {
1406                 _pthread_mutex_unlock(&private_display->lock);
1407                 private_output->current_dpms_value = dpms_value;
1408                 TDM_WRN("not implemented!!");
1409                 return TDM_ERROR_NONE;
1410         }
1411
1412         if (func_output->output_set_dpms_handler) {
1413                 if (!private_output->regist_dpms_cb) {
1414                         private_output->regist_dpms_cb = 1;
1415                         ret = func_output->output_set_dpms_handler(private_output->output_backend,
1416                                         tdm_output_cb_dpms, private_output);
1417                         if (ret != TDM_ERROR_NONE) {
1418                                 _pthread_mutex_unlock(&private_display->lock);
1419                                 TDM_ERR("Can't set the dpms handler!!");
1420                                 return ret;
1421                         }
1422                 }
1423         }
1424
1425         ret = func_output->output_set_dpms(private_output->output_backend, dpms_value);
1426
1427         if (ret == TDM_ERROR_NONE && !func_output->output_set_dpms_handler) {
1428                 tdm_value value;
1429
1430                 private_output->current_dpms_value = dpms_value;
1431
1432                 value.u32 = dpms_value;
1433                 tdm_output_call_change_handler_internal(private_output,
1434                                                                                                 &private_output->change_handler_list_main,
1435                                                                                                 TDM_OUTPUT_CHANGE_DPMS,
1436                                                                                                 value, 0);
1437
1438                 if (!LIST_IS_EMPTY(&private_output->change_handler_list_sub)) {
1439                         ret = tdm_event_loop_source_timer_update(private_output->dpms_changed_timer, 1);
1440                         if (ret != TDM_ERROR_NONE)
1441                                 TDM_NEVER_GET_HERE();
1442                 }
1443         }
1444
1445         _pthread_mutex_unlock(&private_display->lock);
1446
1447         return ret;
1448 }
1449
1450 EXTERN tdm_error
1451 tdm_output_get_dpms(tdm_output *output, tdm_output_dpms *dpms_value)
1452 {
1453         tdm_func_output *func_output;
1454         OUTPUT_FUNC_ENTRY();
1455
1456         TDM_RETURN_VAL_IF_FAIL(dpms_value != NULL, TDM_ERROR_INVALID_PARAMETER);
1457
1458         _pthread_mutex_lock(&private_display->lock);
1459
1460         func_output = &private_display->func_output;
1461
1462         if (!func_output->output_get_dpms) {
1463                 *dpms_value = private_output->current_dpms_value;
1464                 _pthread_mutex_unlock(&private_display->lock);
1465                 TDM_WRN("not implemented!!");
1466                 return TDM_ERROR_NONE;
1467         }
1468
1469         ret = func_output->output_get_dpms(private_output->output_backend, dpms_value);
1470
1471         _pthread_mutex_unlock(&private_display->lock);
1472
1473         return ret;
1474 }
1475
1476 EXTERN tdm_capture *
1477 tdm_output_create_capture(tdm_output *output, tdm_error *error)
1478 {
1479         tdm_capture *capture = NULL;
1480
1481         OUTPUT_FUNC_ENTRY_ERROR();
1482
1483         _pthread_mutex_lock(&private_display->lock);
1484
1485         capture = (tdm_capture *)tdm_capture_create_output_internal(private_output, error);
1486
1487         _pthread_mutex_unlock(&private_display->lock);
1488
1489         return capture;
1490 }
1491
1492 INTERN void
1493 tdm_output_call_change_handler_internal(tdm_private_output *private_output,
1494                                                                                 struct list_head *change_handler_list,
1495                                                                                 tdm_output_change_type type,
1496                                                                                 tdm_value value,
1497                                                                                 int no_check_thread_id)
1498 {
1499         tdm_private_display *private_display;
1500         tdm_private_change_handler *change_handler = NULL;
1501
1502         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
1503         TDM_RETURN_IF_FAIL(private_output);
1504
1505         private_display = private_output->private_display;
1506         if (!tdm_thread_in_display_thread(syscall(SYS_gettid))) {
1507                 if (type & TDM_OUTPUT_CHANGE_CONNECTION)
1508                         TDM_INFO("output(%d) changed: %s (%d)",
1509                                          private_output->pipe, tdm_status_str(value.u32), value.u32);
1510                 if (type & TDM_OUTPUT_CHANGE_DPMS)
1511                         TDM_INFO("output(%d) changed: dpms %s (%d)",
1512                                          private_output->pipe, tdm_dpms_str(value.u32), value.u32);
1513         }
1514
1515         if (LIST_IS_EMPTY(change_handler_list))
1516                 return;
1517
1518         LIST_FOR_EACH_ENTRY(change_handler, change_handler_list, link) {
1519                 if (!no_check_thread_id && change_handler->owner_tid != syscall(SYS_gettid))
1520                         TDM_NEVER_GET_HERE();
1521
1522                 _pthread_mutex_unlock(&private_display->lock);
1523                 change_handler->func(private_output, type,
1524                                                          value, change_handler->user_data);
1525                 _pthread_mutex_lock(&private_display->lock);
1526         }
1527 }
1528
1529 EXTERN tdm_error
1530 tdm_layer_get_capabilities(tdm_layer *layer, tdm_layer_capability *capabilities)
1531 {
1532         LAYER_FUNC_ENTRY();
1533
1534         TDM_RETURN_VAL_IF_FAIL(capabilities != NULL, TDM_ERROR_INVALID_PARAMETER);
1535
1536         _pthread_mutex_lock(&private_display->lock);
1537
1538         *capabilities = private_layer->caps.capabilities;
1539
1540         _pthread_mutex_unlock(&private_display->lock);
1541
1542         return ret;
1543 }
1544
1545 EXTERN tdm_error
1546 tdm_layer_get_available_formats(tdm_layer *layer, const tbm_format **formats, int *count)
1547 {
1548         LAYER_FUNC_ENTRY();
1549
1550         TDM_RETURN_VAL_IF_FAIL(formats != NULL, TDM_ERROR_INVALID_PARAMETER);
1551         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
1552
1553         _pthread_mutex_lock(&private_display->lock);
1554
1555         *formats = (const tbm_format *)private_layer->caps.formats;
1556         *count = private_layer->caps.format_count;
1557
1558         _pthread_mutex_unlock(&private_display->lock);
1559
1560         return ret;
1561 }
1562
1563 EXTERN tdm_error
1564 tdm_layer_get_available_properties(tdm_layer *layer, const tdm_prop **props, int *count)
1565 {
1566         LAYER_FUNC_ENTRY();
1567
1568         TDM_RETURN_VAL_IF_FAIL(props != NULL, TDM_ERROR_INVALID_PARAMETER);
1569         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
1570
1571         _pthread_mutex_lock(&private_display->lock);
1572
1573         *props = (const tdm_prop *)private_layer->caps.props;
1574         *count = private_layer->caps.prop_count;
1575
1576         _pthread_mutex_unlock(&private_display->lock);
1577
1578         return ret;
1579 }
1580
1581 EXTERN tdm_error
1582 tdm_layer_get_zpos(tdm_layer *layer, int *zpos)
1583 {
1584         LAYER_FUNC_ENTRY();
1585
1586         TDM_RETURN_VAL_IF_FAIL(zpos != NULL, TDM_ERROR_INVALID_PARAMETER);
1587
1588         _pthread_mutex_lock(&private_display->lock);
1589
1590         *zpos = private_layer->caps.zpos;
1591
1592         _pthread_mutex_unlock(&private_display->lock);
1593
1594         return ret;
1595 }
1596
1597 EXTERN tdm_error
1598 tdm_layer_set_property(tdm_layer *layer, unsigned int id, tdm_value value)
1599 {
1600         tdm_func_layer *func_layer;
1601         LAYER_FUNC_ENTRY();
1602
1603         _pthread_mutex_lock(&private_display->lock);
1604
1605         func_layer = &private_display->func_layer;
1606
1607         if (private_layer->usable)
1608                 TDM_INFO("layer(%d) not usable", private_layer->index);
1609
1610         private_layer->usable = 0;
1611
1612         if (!func_layer->layer_set_property) {
1613                 _pthread_mutex_unlock(&private_display->lock);
1614                 TDM_ERR("not implemented!!");
1615                 return TDM_ERROR_NOT_IMPLEMENTED;
1616         }
1617
1618         ret = func_layer->layer_set_property(private_layer->layer_backend, id, value);
1619
1620         _pthread_mutex_unlock(&private_display->lock);
1621
1622         return ret;
1623 }
1624
1625 EXTERN tdm_error
1626 tdm_layer_get_property(tdm_layer *layer, unsigned int id, tdm_value *value)
1627 {
1628         tdm_func_layer *func_layer;
1629         LAYER_FUNC_ENTRY();
1630
1631         TDM_RETURN_VAL_IF_FAIL(value != NULL, TDM_ERROR_INVALID_PARAMETER);
1632
1633         _pthread_mutex_lock(&private_display->lock);
1634
1635         func_layer = &private_display->func_layer;
1636
1637         if (!func_layer->layer_get_property) {
1638                 _pthread_mutex_unlock(&private_display->lock);
1639                 TDM_ERR("not implemented!!");
1640                 return TDM_ERROR_NOT_IMPLEMENTED;
1641         }
1642
1643         ret = func_layer->layer_get_property(private_layer->layer_backend, id, value);
1644
1645         _pthread_mutex_unlock(&private_display->lock);
1646
1647         return ret;
1648 }
1649
1650 EXTERN tdm_error
1651 tdm_layer_set_info(tdm_layer *layer, tdm_info_layer *info)
1652 {
1653         tdm_func_layer *func_layer;
1654         char fmtstr[128];
1655
1656         LAYER_FUNC_ENTRY();
1657
1658         TDM_RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER);
1659
1660         _pthread_mutex_lock(&private_display->lock);
1661
1662         func_layer = &private_display->func_layer;
1663
1664         if (private_layer->usable)
1665                 TDM_INFO("layer(%p) not usable", private_layer);
1666
1667         private_layer->usable = 0;
1668
1669         if (!func_layer->layer_set_info) {
1670                 _pthread_mutex_unlock(&private_display->lock);
1671                 TDM_ERR("not implemented!!");
1672                 return TDM_ERROR_NOT_IMPLEMENTED;
1673         }
1674
1675         if (info->src_config.format)
1676                 snprintf(fmtstr, 128, "%c%c%c%c", FOURCC_STR(info->src_config.format));
1677         else
1678                 snprintf(fmtstr, 128, "NONE");
1679
1680         TDM_INFO("layer(%p) info: src(%dx%d %d,%d %dx%d %s) dst(%d,%d %dx%d) trans(%d)",
1681                          private_layer, info->src_config.size.h, info->src_config.size.v,
1682                          info->src_config.pos.x, info->src_config.pos.y,
1683                          info->src_config.pos.w, info->src_config.pos.h,
1684                          fmtstr,
1685                          info->dst_pos.x, info->dst_pos.y,
1686                          info->dst_pos.w, info->dst_pos.h,
1687                          info->transform);
1688
1689         ret = func_layer->layer_set_info(private_layer->layer_backend, info);
1690         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
1691
1692         _pthread_mutex_unlock(&private_display->lock);
1693
1694         return ret;
1695 }
1696
1697 EXTERN tdm_error
1698 tdm_layer_get_info(tdm_layer *layer, tdm_info_layer *info)
1699 {
1700         tdm_func_layer *func_layer;
1701         LAYER_FUNC_ENTRY();
1702
1703         TDM_RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER);
1704
1705         _pthread_mutex_lock(&private_display->lock);
1706
1707         func_layer = &private_display->func_layer;
1708
1709         if (!func_layer->layer_get_info) {
1710                 _pthread_mutex_unlock(&private_display->lock);
1711                 TDM_ERR("not implemented!!");
1712                 return TDM_ERROR_NOT_IMPLEMENTED;
1713         }
1714
1715         ret = func_layer->layer_get_info(private_layer->layer_backend, info);
1716
1717         _pthread_mutex_unlock(&private_display->lock);
1718
1719         return ret;
1720 }
1721
1722 static void
1723 _tdm_layer_dump_buffer(tdm_layer *layer, tbm_surface_h buffer)
1724 {
1725         tdm_private_layer *private_layer = (tdm_private_layer*)layer;
1726         tdm_private_output *private_output = private_layer->private_output;
1727         unsigned int pipe;
1728         int zpos;
1729         char fname[PATH_MAX];
1730
1731         pipe = private_output->pipe;
1732         zpos = private_layer->caps.zpos;
1733
1734         snprintf(fname, sizeof(fname), "tdm_%d_lyr_%d", pipe, zpos);
1735
1736         tbm_surface_internal_dump_buffer(buffer, fname);
1737         TDM_DBG("%s dump excute", fname);
1738
1739         return;
1740 }
1741
1742 EXTERN tdm_error
1743 tdm_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer)
1744 {
1745         tdm_func_layer *func_layer;
1746
1747         LAYER_FUNC_ENTRY();
1748
1749         TDM_RETURN_VAL_IF_FAIL(buffer != NULL, TDM_ERROR_INVALID_PARAMETER);
1750
1751         _pthread_mutex_lock(&private_display->lock);
1752
1753         if (tdm_debug_dump & TDM_DUMP_FLAG_LAYER &&
1754                 !(private_layer->caps.capabilities & TDM_LAYER_CAPABILITY_VIDEO)) {
1755                 char str[TDM_PATH_LEN];
1756                 static int i;
1757                 snprintf(str, TDM_PATH_LEN, "layer_%d_%d_%03d",
1758                                  private_output->index, private_layer->index, i++);
1759                 tdm_helper_dump_buffer_str(buffer, tdm_debug_dump_dir, str);
1760         }
1761
1762         func_layer = &private_display->func_layer;
1763
1764         if (private_layer->usable)
1765                 TDM_INFO("layer(%p) not usable", private_layer);
1766
1767         private_layer->usable = 0;
1768
1769         if (!func_layer->layer_set_buffer) {
1770                 _pthread_mutex_unlock(&private_display->lock);
1771                 TDM_ERR("not implemented!!");
1772                 return TDM_ERROR_NOT_IMPLEMENTED;
1773         }
1774
1775         ret = func_layer->layer_set_buffer(private_layer->layer_backend, buffer);
1776         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
1777
1778         /* dump buffer */
1779         if (tdm_dump_enable && !(private_layer->caps.capabilities & TDM_LAYER_CAPABILITY_VIDEO))
1780                 _tdm_layer_dump_buffer(layer, buffer);
1781
1782         if (ret == TDM_ERROR_NONE) {
1783                 /* FIXME: should save to pending_buffer first. And after committing
1784                  * successfully, need to move to waiting_buffer.
1785                  */
1786                 if (private_layer->waiting_buffer) {
1787                         _pthread_mutex_unlock(&private_display->lock);
1788                         tdm_buffer_unref_backend(private_layer->waiting_buffer);
1789                         _pthread_mutex_lock(&private_display->lock);
1790                 }
1791
1792                 private_layer->waiting_buffer = tdm_buffer_ref_backend(buffer);
1793                 if (tdm_debug_module & TDM_DEBUG_BUFFER)
1794                         TDM_INFO("layer(%p) waiting_buffer(%p)",
1795                                          private_layer, private_layer->waiting_buffer);
1796         }
1797
1798         _pthread_mutex_unlock(&private_display->lock);
1799
1800         return ret;
1801 }
1802
1803 EXTERN tdm_error
1804 tdm_layer_unset_buffer(tdm_layer *layer)
1805 {
1806         tdm_private_layer_commit_handler *lm = NULL, *lmm = NULL;
1807         tdm_func_layer *func_layer;
1808         LAYER_FUNC_ENTRY();
1809
1810         _pthread_mutex_lock(&private_display->lock);
1811
1812         func_layer = &private_display->func_layer;
1813
1814         if (private_layer->waiting_buffer) {
1815                 _pthread_mutex_unlock(&private_display->lock);
1816                 tdm_buffer_unref_backend(private_layer->waiting_buffer);
1817                 _pthread_mutex_lock(&private_display->lock);
1818                 private_layer->waiting_buffer = NULL;
1819
1820                 if (tdm_debug_module & TDM_DEBUG_BUFFER)
1821                         TDM_INFO("layer(%p) waiting_buffer(%p)",
1822                                          private_layer, private_layer->waiting_buffer);
1823         }
1824
1825         if (private_layer->showing_buffer) {
1826                 _pthread_mutex_unlock(&private_display->lock);
1827                 tdm_buffer_unref_backend(private_layer->showing_buffer);
1828                 _pthread_mutex_lock(&private_display->lock);
1829                 private_layer->showing_buffer = NULL;
1830
1831                 if (tdm_debug_module & TDM_DEBUG_BUFFER)
1832                         TDM_INFO("layer(%p) showing_buffer(%p)",
1833                                          private_layer, private_layer->showing_buffer);
1834         }
1835
1836         LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &private_output->layer_commit_handler_list, link) {
1837                 if (lm->private_layer != private_layer)
1838                         continue;
1839                 LIST_DEL(&lm->link);
1840                 free(lm);
1841         }
1842
1843         LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &private_output->pending_commit_handler_list, link) {
1844                 if (lm->private_layer != private_layer)
1845                         continue;
1846                 LIST_DEL(&lm->link);
1847                 free(lm);
1848         }
1849
1850         private_layer->usable = 1;
1851
1852         if (private_layer->usable)
1853                 TDM_INFO("layer(%p) now usable", private_layer);
1854
1855         if (!func_layer->layer_unset_buffer) {
1856                 _pthread_mutex_unlock(&private_display->lock);
1857                 TDM_ERR("not implemented!!");
1858                 return TDM_ERROR_NOT_IMPLEMENTED;
1859         }
1860
1861         ret = func_layer->layer_unset_buffer(private_layer->layer_backend);
1862         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
1863
1864         _pthread_mutex_unlock(&private_display->lock);
1865
1866         return ret;
1867 }
1868
1869 static void
1870 _tdm_layer_committed(tdm_private_layer *private_layer)
1871 {
1872         tdm_private_output *private_output = private_layer->private_output;
1873         tdm_private_display *private_display = private_output->private_display;
1874
1875         private_layer->committing = 0;
1876
1877         if (private_display->print_fps) {
1878                 double curr = tdm_helper_get_time();
1879                 private_layer->fps_count++;
1880                 if (private_layer->fps_stamp == 0) {
1881                         private_layer->fps_stamp = curr;
1882                 } else if ((curr - private_layer->fps_stamp) > 1.0) {
1883                         TDM_INFO("output(%d) layer(%d) fps: %d", private_output->index, private_layer->index, private_layer->fps_count - 1);
1884                         private_layer->fps_count = 1;
1885                         private_layer->fps_stamp = curr;
1886                 }
1887         } else if (private_layer->fps_stamp != 0) {
1888                 private_layer->fps_stamp = 0;
1889                 private_layer->fps_count = 0;
1890         }
1891
1892         if (!private_layer->waiting_buffer)
1893                 return;
1894
1895         if (private_layer->showing_buffer) {
1896                 _pthread_mutex_unlock(&private_display->lock);
1897                 tdm_buffer_unref_backend(private_layer->showing_buffer);
1898                 _pthread_mutex_lock(&private_display->lock);
1899
1900                 if (private_layer->buffer_queue) {
1901                         _pthread_mutex_unlock(&private_display->lock);
1902                         tbm_surface_queue_release(private_layer->buffer_queue,
1903                                                                           private_layer->showing_buffer);
1904                         _pthread_mutex_lock(&private_display->lock);
1905                 }
1906         }
1907
1908         private_layer->showing_buffer = private_layer->waiting_buffer;
1909         private_layer->waiting_buffer = NULL;
1910
1911         if (tdm_debug_module & TDM_DEBUG_BUFFER)
1912                 TDM_INFO("layer(%p) waiting_buffer(%p) showing_buffer(%p)",
1913                                  private_layer, private_layer->waiting_buffer,
1914                                  private_layer->showing_buffer);
1915 }
1916
1917 static void
1918 _tdm_layer_got_output_vblank(tdm_private_output *private_output, unsigned int sequence,
1919                                                          unsigned int tv_sec, unsigned int tv_usec)
1920 {
1921         tdm_private_layer_commit_handler *lm = NULL, *lmm = NULL;
1922         tdm_private_display *private_display;
1923         struct list_head clone_list, pending_clone_list;
1924         tdm_error ret;
1925
1926         private_display = private_output->private_display;
1927
1928         private_output->waiting_vblank = 0;
1929
1930         LIST_INITHEAD(&clone_list);
1931         LIST_INITHEAD(&pending_clone_list);
1932
1933         LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &private_output->layer_commit_handler_list, link) {
1934                 LIST_DEL(&lm->link);
1935                 LIST_ADDTAIL(&lm->link, &clone_list);
1936         }
1937
1938         LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &private_output->pending_commit_handler_list, link) {
1939                 LIST_DEL(&lm->link);
1940                 LIST_ADDTAIL(&lm->link, &pending_clone_list);
1941         }
1942
1943         LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &clone_list, link) {
1944                 _tdm_layer_committed(lm->private_layer);
1945                 _pthread_mutex_unlock(&private_display->lock);
1946                 if (lm->func)
1947                         lm->func(lm->private_layer, sequence, tv_sec, tv_usec, lm->user_data);
1948                 _pthread_mutex_lock(&private_display->lock);
1949                 LIST_DEL(&lm->link);
1950                 free(lm);
1951         }
1952
1953         if (LIST_IS_EMPTY(&pending_clone_list))
1954                 return;
1955
1956         TDM_GOTO_IF_FAIL(private_output->vblank != NULL, wait_failed);
1957
1958         ret = _tdm_output_commit(private_output, 0, NULL, NULL);
1959         TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, wait_failed);
1960
1961         if (tdm_debug_module & TDM_DEBUG_COMMIT)
1962                 TDM_INFO("layer commit: output(%d) commit", private_output->pipe);
1963
1964         /* tdm_vblank APIs is for server. it should be called in unlock status*/
1965         _pthread_mutex_unlock(&private_display->lock);
1966         ret = tdm_vblank_wait(private_output->vblank, 0, 0, 1, _tdm_layer_cb_wait_vblank, private_output);
1967         _pthread_mutex_lock(&private_display->lock);
1968         TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, wait_failed);
1969         private_output->waiting_vblank = 1;
1970
1971         if (tdm_debug_module & TDM_DEBUG_COMMIT)
1972                 TDM_INFO("layer commit: output(%d) wait vblank", private_output->pipe);
1973
1974         LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &pending_clone_list, link) {
1975                 LIST_DEL(&lm->link);
1976                 LIST_ADDTAIL(&lm->link, &private_output->layer_commit_handler_list);
1977         }
1978
1979         return;
1980 wait_failed:
1981         LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &pending_clone_list, link) {
1982                 LIST_DEL(&lm->link);
1983                 free(lm);
1984         }
1985         return;
1986 }
1987
1988 static void
1989 _tdm_layer_cb_wait_vblank(tdm_vblank *vblank, tdm_error error, unsigned int sequence,
1990                                                   unsigned int tv_sec, unsigned int tv_usec, void *user_data)
1991 {
1992         tdm_private_output *private_output = user_data;
1993         tdm_private_display *private_display;
1994
1995         TDM_RETURN_IF_FAIL(private_output != NULL);
1996
1997         private_display = private_output->private_display;
1998
1999         _pthread_mutex_lock(&private_display->lock);
2000
2001         if (tdm_debug_module & TDM_DEBUG_COMMIT)
2002                 TDM_INFO("layer commit: output(%d) got vblank", private_output->pipe);
2003
2004         _tdm_layer_got_output_vblank(private_output, sequence, tv_sec, tv_usec);
2005
2006         _pthread_mutex_unlock(&private_display->lock);
2007 }
2008
2009 static int
2010 _tdm_layer_commit_possible(tdm_private_layer *private_layer)
2011 {
2012         tdm_private_output *private_output = private_layer->private_output;
2013         tdm_private_display *private_display = private_output->private_display;
2014
2015         if (!private_display->commit_per_vblank) {
2016                 if (tdm_debug_module & TDM_DEBUG_COMMIT)
2017                         TDM_INFO("layer(%p) commit: commit_per_vblank false", private_layer);
2018                 return 1;
2019         }
2020
2021         if (private_display->commit_per_vblank == 1 && _tdm_output_used_layer_count(private_output) == 1) {
2022                 if (tdm_debug_module & TDM_DEBUG_COMMIT)
2023                         TDM_INFO("layer(%p) commit: 1 layer", private_layer);
2024                 return 1;
2025         }
2026
2027         if (private_display->commit_per_vblank == 2 && LIST_IS_EMPTY(&private_output->layer_commit_handler_list)) {
2028                 if (tdm_debug_module & TDM_DEBUG_COMMIT)
2029                         TDM_INFO("layer(%p) commit: non previous commit", private_layer);
2030                 return 1;
2031         }
2032
2033         return 0;
2034 }
2035
2036 static tdm_error
2037 _tdm_layer_commit(tdm_layer *layer, tdm_layer_commit_handler func, void *user_data)
2038 {
2039         tdm_private_layer_commit_handler *layer_commit_handler = NULL;
2040         LAYER_FUNC_ENTRY();
2041
2042         if (private_layer->committing)
2043                 TDM_WRN("layer(%d) too many commit", private_layer->index);
2044         else
2045                 private_layer->committing = 1;
2046
2047         layer_commit_handler = calloc(1, sizeof(tdm_private_layer_commit_handler));
2048         if (!layer_commit_handler) {
2049                 TDM_ERR("failed: alloc memory");
2050                 return TDM_ERROR_OUT_OF_MEMORY;
2051         }
2052
2053         LIST_INITHEAD(&layer_commit_handler->link);
2054         layer_commit_handler->private_layer = private_layer;
2055         layer_commit_handler->func = func;
2056         layer_commit_handler->user_data = user_data;
2057
2058         if (_tdm_layer_commit_possible(private_layer)) {
2059                 /* add to layer_commit_handler_list */
2060                 LIST_ADD(&layer_commit_handler->link, &private_output->layer_commit_handler_list);
2061
2062                 ret = _tdm_output_commit(private_layer->private_output, 0, NULL, NULL);
2063                 TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed);
2064
2065                 if (tdm_debug_module & TDM_DEBUG_COMMIT)
2066                         TDM_INFO("layer(%p) commit: output", private_layer);
2067         } else {
2068                 /* add to pending_commit_handler_list. It will be commited when a vblank occurs */
2069                 LIST_ADD(&layer_commit_handler->link, &private_output->pending_commit_handler_list);
2070
2071                 if (tdm_debug_module & TDM_DEBUG_COMMIT)
2072                         TDM_INFO("layer(%p) commit: pending", private_layer);
2073         }
2074
2075         if (!private_output->vblank) {
2076                 /* tdm_vblank APIs is for server. it should be called in unlock status*/
2077                 _pthread_mutex_unlock(&private_display->lock);
2078                 private_output->vblank = tdm_vblank_create(private_display, private_output, NULL);
2079                 _pthread_mutex_lock(&private_display->lock);
2080                 TDM_GOTO_IF_FAIL(private_output->vblank != NULL, commit_failed);
2081
2082                 tdm_vblank_set_add_front(private_output->vblank, 1);
2083         }
2084
2085         if (!private_output->waiting_vblank) {
2086                 /* tdm_vblank APIs is for server. it should be called in unlock status*/
2087                 _pthread_mutex_unlock(&private_display->lock);
2088                 ret = tdm_vblank_wait(private_output->vblank, 0, 0, 1, _tdm_layer_cb_wait_vblank, private_output);
2089                 _pthread_mutex_lock(&private_display->lock);
2090                 TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed);
2091                 private_output->waiting_vblank = 1;
2092
2093                 if (tdm_debug_module & TDM_DEBUG_COMMIT)
2094                         TDM_INFO("layer(%p) commit: wait vblank", private_layer);
2095         }
2096
2097         return ret;
2098
2099 commit_failed:
2100         if (layer_commit_handler) {
2101                 LIST_DEL(&layer_commit_handler->link);
2102                 free(layer_commit_handler);
2103         }
2104         return ret;
2105 }
2106
2107 EXTERN tdm_error
2108 tdm_layer_commit(tdm_layer *layer, tdm_layer_commit_handler func, void *user_data)
2109 {
2110         LAYER_FUNC_ENTRY();
2111
2112         _pthread_mutex_lock(&private_display->lock);
2113
2114         if (private_display->commit_type == TDM_COMMIT_TYPE_NONE)
2115                 private_display->commit_type = TDM_COMMIT_TYPE_LAYER;
2116         else if (private_display->commit_type == TDM_COMMIT_TYPE_OUTPUT) {
2117                 TDM_ERR("Can't supported. Use tdm_output_commit");
2118                 _pthread_mutex_unlock(&private_display->lock);
2119                 return TDM_ERROR_BAD_REQUEST;
2120         }
2121
2122         if (private_output->current_dpms_value > TDM_OUTPUT_DPMS_ON) {
2123                 TDM_ERR("layer(%p)'s output(%d) dpms: %s", layer, private_output->pipe,
2124                                 tdm_dpms_str(private_output->current_dpms_value));
2125                 _pthread_mutex_unlock(&private_display->lock);
2126                 return TDM_ERROR_DPMS_OFF;
2127         }
2128
2129         if (tdm_debug_module & TDM_DEBUG_COMMIT)
2130                 TDM_INFO("layer(%p) commit", private_layer);
2131
2132         ret = _tdm_layer_commit(private_layer, func, user_data);
2133
2134         _pthread_mutex_unlock(&private_display->lock);
2135
2136         return ret;
2137 }
2138
2139 EXTERN tdm_error
2140 tdm_layer_is_committing(tdm_layer *layer, unsigned int *committing)
2141 {
2142         LAYER_FUNC_ENTRY();
2143
2144         TDM_RETURN_VAL_IF_FAIL(committing != NULL, TDM_ERROR_INVALID_PARAMETER);
2145
2146         _pthread_mutex_lock(&private_display->lock);
2147
2148         *committing = private_layer->committing;
2149
2150         _pthread_mutex_unlock(&private_display->lock);
2151
2152         return ret;
2153 }
2154
2155 EXTERN tbm_surface_h
2156 tdm_layer_get_displaying_buffer(tdm_layer *layer, tdm_error *error)
2157 {
2158         tbm_surface_h buffer;
2159         LAYER_FUNC_ENTRY_ERROR();
2160
2161         _pthread_mutex_lock(&private_display->lock);
2162
2163         if (error)
2164                 *error = TDM_ERROR_NONE;
2165
2166         if (private_layer->showing_buffer) {
2167                 buffer = private_layer->showing_buffer;
2168         } else {
2169                 if (error)
2170                         *error = TDM_ERROR_OPERATION_FAILED;
2171                 _pthread_mutex_unlock(&private_display->lock);
2172                 TDM_DBG("layer(%p) showing_buffer is null", private_layer);
2173                 return NULL;
2174         }
2175         _pthread_mutex_unlock(&private_display->lock);
2176
2177         return buffer;
2178 }
2179
2180 static void
2181 _tbm_layer_queue_acquirable_cb(tbm_surface_queue_h surface_queue, void *data)
2182 {
2183         TDM_RETURN_IF_FAIL(data != NULL);
2184         tdm_layer *layer = data;
2185         tdm_func_layer *func_layer;
2186         tbm_surface_h surface = NULL;
2187         LAYER_FUNC_ENTRY_VOID_RETURN();
2188
2189         _pthread_mutex_lock(&private_display->lock);
2190
2191         func_layer = &private_display->func_layer;
2192         if (!func_layer->layer_set_buffer) {
2193                 _pthread_mutex_unlock(&private_display->lock);
2194                 return;
2195         }
2196
2197         if (TBM_SURFACE_QUEUE_ERROR_NONE != tbm_surface_queue_acquire(private_layer->buffer_queue, &surface) ||
2198                 surface == NULL) {
2199                 TDM_ERR("layer(%p) tbm_surface_queue_acquire() failed surface:%p",
2200                                 private_layer, surface);
2201                 _pthread_mutex_unlock(&private_display->lock);
2202                 return;
2203         }
2204
2205         ret = func_layer->layer_set_buffer(private_layer->layer_backend, surface);
2206         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
2207
2208         if (ret == TDM_ERROR_NONE) {
2209                 if (private_layer->waiting_buffer) {
2210                         TDM_DBG("layer(%p) drop waiting_buffer(%p)", private_layer, private_layer->waiting_buffer);
2211                         _pthread_mutex_unlock(&private_display->lock);
2212                         tdm_buffer_unref_backend(private_layer->waiting_buffer);
2213                         tbm_surface_queue_release(private_layer->buffer_queue,
2214                                                                           private_layer->waiting_buffer);
2215                         _pthread_mutex_lock(&private_display->lock);
2216                 }
2217
2218                 private_layer->waiting_buffer = tdm_buffer_ref_backend(surface);
2219
2220                 if (tdm_debug_module & TDM_DEBUG_BUFFER)
2221                         TDM_INFO("layer(%p) waiting_buffer(%p)",
2222                                          private_layer, private_layer->waiting_buffer);
2223
2224                 if (private_display->commit_type == TDM_COMMIT_TYPE_OUTPUT) {
2225                         ret = _tdm_output_commit(private_layer->private_output, 0, NULL, NULL);
2226                         if (ret != TDM_ERROR_NONE)
2227                                 TDM_ERR("_tdm_output_commit() is fail");
2228                 } else if (private_display->commit_type == TDM_COMMIT_TYPE_LAYER) {
2229                         ret = _tdm_layer_commit(private_layer, NULL, NULL);
2230                         if (ret != TDM_ERROR_NONE)
2231                                 TDM_ERR("layer(%p) _tdm_layer_commit() is fail", private_layer);
2232                 } else {
2233                         TDM_NEVER_GET_HERE();
2234                 }
2235         }
2236
2237         _pthread_mutex_unlock(&private_display->lock);
2238 }
2239
2240 static void
2241 _tbm_layer_queue_destroy_cb(tbm_surface_queue_h surface_queue, void *data)
2242 {
2243         TDM_RETURN_IF_FAIL(data != NULL);
2244         tdm_layer *layer = data;
2245         LAYER_FUNC_ENTRY_VOID_RETURN();
2246         TDM_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
2247
2248         _pthread_mutex_lock(&private_display->lock);
2249
2250         if (private_layer->waiting_buffer) {
2251                 _pthread_mutex_unlock(&private_display->lock);
2252                 tdm_buffer_unref_backend(private_layer->waiting_buffer);
2253                 tbm_surface_queue_release(private_layer->buffer_queue,
2254                                                                   private_layer->waiting_buffer);
2255                 _pthread_mutex_lock(&private_display->lock);
2256         }
2257
2258         private_layer->buffer_queue = NULL;
2259
2260         _pthread_mutex_unlock(&private_display->lock);
2261 }
2262
2263 EXTERN tdm_error
2264 tdm_layer_set_buffer_queue(tdm_layer *layer, tbm_surface_queue_h buffer_queue)
2265 {
2266         tdm_func_layer *func_layer;
2267         LAYER_FUNC_ENTRY();
2268
2269         TDM_RETURN_VAL_IF_FAIL(buffer_queue != NULL, TDM_ERROR_INVALID_PARAMETER);
2270
2271         _pthread_mutex_lock(&private_display->lock);
2272
2273         func_layer = &private_display->func_layer;
2274
2275         if (private_layer->usable)
2276                 TDM_INFO("layer(%p) not usable", private_layer);
2277
2278         private_layer->usable = 0;
2279
2280         if (!func_layer->layer_set_buffer) {
2281                 _pthread_mutex_unlock(&private_display->lock);
2282                 TDM_ERR("not implemented!!");
2283                 return TDM_ERROR_NOT_IMPLEMENTED;
2284         }
2285
2286         if (buffer_queue == private_layer->buffer_queue) {
2287                 _pthread_mutex_unlock(&private_display->lock);
2288                 return TDM_ERROR_NONE;
2289         }
2290
2291         if (private_layer->waiting_buffer) {
2292                 _pthread_mutex_unlock(&private_display->lock);
2293                 tdm_buffer_unref_backend(private_layer->waiting_buffer);
2294                 tbm_surface_queue_release(private_layer->buffer_queue,
2295                                                                   private_layer->waiting_buffer);
2296                 private_layer->waiting_buffer = NULL;
2297                 _pthread_mutex_lock(&private_display->lock);
2298
2299                 if (tdm_debug_module & TDM_DEBUG_BUFFER)
2300                         TDM_INFO("layer(%p) waiting_buffer(%p)",
2301                                          private_layer, private_layer->waiting_buffer);
2302         }
2303
2304         private_layer->buffer_queue = buffer_queue;
2305         tbm_surface_queue_add_acquirable_cb(private_layer->buffer_queue,
2306                                                                                 _tbm_layer_queue_acquirable_cb,
2307                                                                                 layer);
2308         tbm_surface_queue_add_destroy_cb(private_layer->buffer_queue,
2309                                                                          _tbm_layer_queue_destroy_cb,
2310                                                                          layer);
2311         _pthread_mutex_unlock(&private_display->lock);
2312
2313         return ret;
2314 }
2315
2316 EXTERN tdm_error
2317 tdm_layer_unset_buffer_queue(tdm_layer *layer)
2318 {
2319         tdm_func_layer *func_layer;
2320         LAYER_FUNC_ENTRY();
2321
2322         _pthread_mutex_lock(&private_display->lock);
2323
2324         func_layer = &private_display->func_layer;
2325
2326         if (private_layer->waiting_buffer) {
2327                 _pthread_mutex_unlock(&private_display->lock);
2328                 tdm_buffer_unref_backend(private_layer->waiting_buffer);
2329                 tbm_surface_queue_release(private_layer->buffer_queue,
2330                                                                   private_layer->waiting_buffer);
2331                 private_layer->waiting_buffer = NULL;
2332                 _pthread_mutex_lock(&private_display->lock);
2333
2334                 if (tdm_debug_module & TDM_DEBUG_BUFFER)
2335                         TDM_INFO("layer(%p) waiting_buffer(%p)",
2336                                          private_layer, private_layer->waiting_buffer);
2337         }
2338
2339         if (private_layer->showing_buffer) {
2340                 _pthread_mutex_unlock(&private_display->lock);
2341                 tdm_buffer_unref_backend(private_layer->showing_buffer);
2342                 tbm_surface_queue_release(private_layer->buffer_queue,
2343                                                                   private_layer->showing_buffer);
2344                 _pthread_mutex_lock(&private_display->lock);
2345                 private_layer->showing_buffer = NULL;
2346
2347                 if (tdm_debug_module & TDM_DEBUG_BUFFER)
2348                         TDM_INFO("layer(%p) showing_buffer(%p)",
2349                                          private_layer, private_layer->showing_buffer);
2350         }
2351
2352         tbm_surface_queue_remove_acquirable_cb(private_layer->buffer_queue, _tbm_layer_queue_acquirable_cb, layer);
2353         tbm_surface_queue_remove_destroy_cb(private_layer->buffer_queue, _tbm_layer_queue_destroy_cb, layer);
2354         private_layer->buffer_queue = NULL;
2355         private_layer->usable = 1;
2356
2357         if (private_layer->usable)
2358                 TDM_INFO("layer(%p) now usable", private_layer);
2359
2360         if (!func_layer->layer_unset_buffer) {
2361                 _pthread_mutex_unlock(&private_display->lock);
2362                 TDM_ERR("not implemented!!");
2363                 return TDM_ERROR_NOT_IMPLEMENTED;
2364         }
2365
2366         ret = func_layer->layer_unset_buffer(private_layer->layer_backend);
2367
2368         _pthread_mutex_unlock(&private_display->lock);
2369
2370         return ret;
2371 }
2372
2373 EXTERN tdm_error
2374 tdm_layer_is_usable(tdm_layer *layer, unsigned int *usable)
2375 {
2376         LAYER_FUNC_ENTRY();
2377
2378         TDM_RETURN_VAL_IF_FAIL(usable != NULL, TDM_ERROR_INVALID_PARAMETER);
2379
2380         _pthread_mutex_lock(&private_display->lock);
2381
2382         *usable = private_layer->usable;
2383
2384         _pthread_mutex_unlock(&private_display->lock);
2385
2386         return ret;
2387 }
2388
2389 EXTERN tdm_error
2390 tdm_layer_set_video_pos(tdm_layer *layer, int zpos)
2391 {
2392         tdm_func_layer *func_layer;
2393         LAYER_FUNC_ENTRY();
2394
2395         _pthread_mutex_lock(&private_display->lock);
2396
2397         func_layer = &private_display->func_layer;
2398
2399         if (!(private_layer->caps.capabilities & TDM_LAYER_CAPABILITY_VIDEO)) {
2400                 TDM_ERR("layer(%p) is not video layer", private_layer);
2401                 _pthread_mutex_unlock(&private_display->lock);
2402                 return TDM_ERROR_INVALID_PARAMETER;
2403         }
2404
2405         if (!func_layer->layer_set_video_pos) {
2406                 _pthread_mutex_unlock(&private_display->lock);
2407                 TDM_ERR("not implemented!!");
2408                 return TDM_ERROR_NOT_IMPLEMENTED;
2409         }
2410
2411         ret = func_layer->layer_set_video_pos(private_layer->layer_backend, zpos);
2412
2413         _pthread_mutex_unlock(&private_display->lock);
2414
2415         return ret;
2416 }
2417
2418 EXTERN tdm_capture *
2419 tdm_layer_create_capture(tdm_layer *layer, tdm_error *error)
2420 {
2421         tdm_capture *capture = NULL;
2422
2423         LAYER_FUNC_ENTRY_ERROR();
2424
2425         _pthread_mutex_lock(&private_display->lock);
2426
2427         capture = (tdm_capture *)tdm_capture_create_layer_internal(private_layer, error);
2428
2429         _pthread_mutex_unlock(&private_display->lock);
2430
2431         return capture;
2432 }
2433
2434 EXTERN tdm_error
2435 tdm_layer_get_buffer_flags(tdm_layer *layer, unsigned int *flags)
2436 {
2437         tdm_func_layer *func_layer;
2438         LAYER_FUNC_ENTRY();
2439
2440         _pthread_mutex_lock(&private_display->lock);
2441
2442         func_layer = &private_display->func_layer;
2443
2444         if (!func_layer->layer_get_buffer_flags) {
2445                 _pthread_mutex_unlock(&private_display->lock);
2446                 TDM_ERR("not implemented!!");
2447                 return TDM_ERROR_NOT_IMPLEMENTED;
2448         }
2449
2450         ret = func_layer->layer_get_buffer_flags(private_layer->layer_backend, flags);
2451
2452         _pthread_mutex_unlock(&private_display->lock);
2453
2454         return ret;
2455 }