add timeout logs (1000ms)
[platform/core/uifw/libtdm.git] / src / tdm_output.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_private.h"
41
42 #define COUNT_MAX   10
43
44 #define OUTPUT_FUNC_ENTRY() \
45         tdm_private_display *private_display; \
46         tdm_private_output *private_output; \
47         tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\
48         TDM_RETURN_VAL_IF_FAIL(tdm_output_is_valid(output), TDM_ERROR_INVALID_PARAMETER); \
49         private_output = (tdm_private_output*)output; \
50         private_display = private_output->private_display
51
52 #define OUTPUT_FUNC_ENTRY_ERROR() \
53         tdm_private_display *private_display; \
54         tdm_private_output *private_output; \
55         tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\
56         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(tdm_output_is_valid(output), TDM_ERROR_INVALID_PARAMETER, NULL); \
57         private_output = (tdm_private_output*)output; \
58         private_display = private_output->private_display
59
60 static void
61 _tdm_output_vblank_timeout_update(tdm_private_output *private_output, int ms_delay);
62
63 static tdm_error
64 _tdm_output_vblank_timeout_cb(void *user_data)
65 {
66         tdm_private_output *private_output = user_data;
67         tdm_private_vblank_handler *v = NULL;
68
69         TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_OPERATION_FAILED);
70
71         TDM_ERR("TDM output(%d) vblank TIMEOUT!!", private_output->pipe);
72
73         LIST_FOR_EACH_ENTRY(v, &private_output->vblank_handler_list, link) {
74                 TDM_ERR("vblank_handler(%p) interval(%d) sync(%d) sent_to_frontend(%u) owner_tid(%d)",
75                                 v, v->interval, v->sync, v->sent_to_frontend, v->owner_tid);
76         }
77
78         return TDM_ERROR_NONE;
79 }
80
81 INTERN void
82 tdm_output_vblank_print_wait_information(tdm_private_output *private_output, void *user_data)
83 {
84         tdm_private_vblank_handler *v = NULL;
85
86         TDM_RETURN_IF_FAIL(private_output != NULL);
87         TDM_RETURN_IF_FAIL(user_data != NULL);
88
89         TDM_ERR("TDM output(%d) vblank user_data(%p) info!!", private_output->pipe, user_data);
90
91         LIST_FOR_EACH_ENTRY(v, &private_output->vblank_handler_list, link) {
92                 if (v->user_data != user_data)
93                         continue;
94                 TDM_ERR("vblank_handler(%p) interval(%d) sync(%d) sent_to_frontend(%u) owner_tid(%d)",
95                                 v, v->interval, v->sync, v->sent_to_frontend, v->owner_tid);
96         }
97 }
98
99 static void
100 _tdm_output_vblank_timeout_update(tdm_private_output *private_output, int ms_delay)
101 {
102         tdm_error ret;
103
104         if (!private_output->vblank_timeout_timer) {
105                 private_output->vblank_timeout_timer =
106                         tdm_event_loop_add_timer_handler(private_output->private_display,
107                                                                                          _tdm_output_vblank_timeout_cb,
108                                                                                          private_output,
109                                                                                          &ret);
110                 if (!private_output->vblank_timeout_timer) {
111                         TDM_ERR("output(%d) couldn't add timer", private_output->pipe);
112                         return;
113                 }
114                 TDM_INFO("output(%d) create vblank timeout timer", private_output->pipe);
115         }
116
117         ret = tdm_event_loop_source_timer_update(private_output->vblank_timeout_timer, ms_delay);
118         if (ret != TDM_ERROR_NONE) {
119                 TDM_ERR("output(%d) couldn't update timer", private_output->pipe);
120                 return;
121         }
122 }
123
124 static tdm_private_hwc_window *
125 _tdm_output_find_private_hwc_window(tdm_private_output *private_output,
126                                                                 tdm_hwc_window *hwc_window_backend)
127 {
128         tdm_private_hwc_window *private_hwc_window = NULL;
129
130         LIST_FOR_EACH_ENTRY(private_hwc_window, &private_output->hwc_window_list, link) {
131                 if (private_hwc_window->hwc_window_backend == hwc_window_backend)
132                         return private_hwc_window;
133         }
134
135         return NULL;
136 }
137
138 EXTERN tdm_error
139 tdm_output_get_model_info(tdm_output *output, const char **maker,
140                                                   const char **model, const char **name)
141 {
142         OUTPUT_FUNC_ENTRY();
143
144         _pthread_mutex_lock(&private_display->lock);
145
146         if (maker)
147                 *maker = private_output->caps.maker;
148         if (model)
149                 *model = private_output->caps.model;
150         if (name)
151                 *name = private_output->caps.name;
152
153         _pthread_mutex_unlock(&private_display->lock);
154
155         return ret;
156 }
157
158 EXTERN tdm_error
159 tdm_output_get_capabilities(tdm_output *output, tdm_output_capability *capabilities)
160 {
161         OUTPUT_FUNC_ENTRY();
162
163         TDM_RETURN_VAL_IF_FAIL(capabilities != NULL, TDM_ERROR_INVALID_PARAMETER);
164
165         _pthread_mutex_lock(&private_display->lock);
166
167         *capabilities = private_output->caps.capabilities;
168
169         _pthread_mutex_unlock(&private_display->lock);
170
171         return ret;
172 }
173
174 EXTERN tdm_error
175 tdm_output_get_conn_status(tdm_output *output, tdm_output_conn_status *status)
176 {
177         OUTPUT_FUNC_ENTRY();
178
179         TDM_RETURN_VAL_IF_FAIL(status != NULL, TDM_ERROR_INVALID_PARAMETER);
180
181         _pthread_mutex_lock(&private_display->lock);
182
183         *status = private_output->caps.status;
184
185         _pthread_mutex_unlock(&private_display->lock);
186
187         return ret;
188 }
189
190 /* LCOV_EXCL_START */
191 static void
192 _tdm_output_update(tdm_output *output_backend, void *user_data)
193 {
194         tdm_private_display *private_display;
195         tdm_private_output *private_output = user_data;
196         tdm_error ret;
197
198         TDM_RETURN_IF_FAIL(private_output);
199
200         private_display = private_output->private_display;
201
202         ret = tdm_display_update_output(private_display, output_backend, private_output->pipe);
203         TDM_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
204 }
205
206 INTERN void
207 tdm_output_cb_status(tdm_output *output_backend, tdm_output_conn_status status,
208                                          void *user_data)
209 {
210         tdm_private_display *private_display;
211         tdm_private_output *private_output = user_data;
212         tdm_value value;
213
214         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
215         TDM_RETURN_IF_FAIL(private_output);
216
217         private_display = private_output->private_display;
218
219         if (!tdm_thread_in_display_thread(syscall(SYS_gettid))) {
220                 tdm_thread_cb_output_status output_status;
221                 tdm_error ret;
222
223                 TDM_INFO("output(%d) %s", private_output->pipe, tdm_status_str(status));
224
225                 _tdm_output_update(output_backend, user_data);
226
227                 output_status.base.type = TDM_THREAD_CB_OUTPUT_STATUS;
228                 output_status.base.length = sizeof output_status;
229                 output_status.output_stamp = private_output->stamp;
230                 output_status.status = status;
231                 output_status.user_data = user_data;
232
233                 value.u32 = status;
234                 tdm_output_call_change_handler_internal(private_output,
235                                                                                                 &private_output->change_handler_list_sub,
236                                                                                                 TDM_OUTPUT_CHANGE_CONNECTION,
237                                                                                                 value, 0);
238
239                 ret = tdm_thread_send_cb(private_display->private_loop, &output_status.base);
240                 TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
241
242                 return;
243         }
244
245         TDM_INFO("output(%d) %s", private_output->pipe, tdm_status_str(status));
246
247         if (!tdm_thread_is_running())
248                 _tdm_output_update(output_backend, user_data);
249
250         value.u32 = status;
251         tdm_output_call_change_handler_internal(private_output,
252                                                                                         &private_output->change_handler_list_main,
253                                                                                         TDM_OUTPUT_CHANGE_CONNECTION,
254                                                                                         value, 0);
255 }
256 /* LCOV_EXCL_STOP */
257
258 EXTERN tdm_error
259 tdm_output_add_change_handler(tdm_output *output,
260                                                           tdm_output_change_handler func,
261                                                           void *user_data)
262 {
263         tdm_private_change_handler *change_handler;
264         OUTPUT_FUNC_ENTRY();
265
266         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
267
268         _pthread_mutex_lock(&private_display->lock);
269
270         change_handler = calloc(1, sizeof(tdm_private_change_handler));
271         if (!change_handler) {
272                 /* LCOV_EXCL_START */
273                 TDM_ERR("failed: alloc memory");
274                 _pthread_mutex_unlock(&private_display->lock);
275                 return TDM_ERROR_OUT_OF_MEMORY;
276                 /* LCOV_EXCL_STOP */
277         }
278
279         change_handler->private_output = private_output;
280         change_handler->func = func;
281         change_handler->user_data = user_data;
282         change_handler->owner_tid = syscall(SYS_gettid);
283
284         if (!tdm_thread_in_display_thread(change_handler->owner_tid))
285                 LIST_ADDTAIL(&change_handler->link, &private_output->change_handler_list_sub);
286         else
287                 LIST_ADDTAIL(&change_handler->link, &private_output->change_handler_list_main);
288
289         _pthread_mutex_unlock(&private_display->lock);
290
291         return ret;
292 }
293
294 EXTERN void
295 tdm_output_remove_change_handler(tdm_output *output,
296                                                                  tdm_output_change_handler func,
297                                                                  void *user_data)
298 {
299         tdm_private_display *private_display;
300         tdm_private_output *private_output;
301         tdm_private_change_handler *h = NULL, *hh = NULL;
302
303         TDM_RETURN_IF_FAIL(tdm_output_is_valid(output));
304         TDM_RETURN_IF_FAIL(func != NULL);
305
306         private_output = (tdm_private_output*)output;
307         private_display = private_output->private_display;
308
309         _pthread_mutex_lock(&private_display->lock);
310
311         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_main, link) {
312                 if (h->func != func || h->user_data != user_data)
313                         continue;
314
315                 LIST_DEL(&h->link);
316                 free(h);
317
318                 _pthread_mutex_unlock(&private_display->lock);
319
320                 return;
321         }
322
323         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_sub, link) {
324                 if (h->func != func || h->user_data != user_data)
325                         continue;
326
327                 LIST_DEL(&h->link);
328                 free(h);
329
330                 _pthread_mutex_unlock(&private_display->lock);
331
332                 return;
333         }
334
335         _pthread_mutex_unlock(&private_display->lock);
336 }
337
338 EXTERN tdm_error
339 tdm_output_get_output_type(tdm_output *output, tdm_output_type *type)
340 {
341         OUTPUT_FUNC_ENTRY();
342
343         TDM_RETURN_VAL_IF_FAIL(type != NULL, TDM_ERROR_INVALID_PARAMETER);
344
345         _pthread_mutex_lock(&private_display->lock);
346
347         *type = private_output->caps.type;
348
349         _pthread_mutex_unlock(&private_display->lock);
350
351         return ret;
352 }
353
354 EXTERN tdm_error
355 tdm_output_get_layer_count(tdm_output *output, int *count)
356 {
357         tdm_private_layer *private_layer = NULL;
358
359         OUTPUT_FUNC_ENTRY();
360
361         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
362
363         _pthread_mutex_lock(&private_display->lock);
364
365         if (private_output->caps.capabilities & TDM_OUTPUT_CAPABILITY_HWC) {
366                 TDM_ERR("output(%p) support HWC. Use HWC functions", private_output);
367                 *count = 0;
368                 _pthread_mutex_unlock(&private_display->lock);
369                 return TDM_ERROR_BAD_REQUEST;
370         }
371
372         *count = 0;
373         LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link)
374         (*count)++;
375         if (*count == 0) {
376                 _pthread_mutex_unlock(&private_display->lock);
377                 return TDM_ERROR_NONE;
378         }
379
380         _pthread_mutex_unlock(&private_display->lock);
381
382         return ret;
383 }
384
385
386 EXTERN tdm_layer *
387 tdm_output_get_layer(tdm_output *output, int index, tdm_error *error)
388 {
389         tdm_private_layer *private_layer = NULL;
390
391         OUTPUT_FUNC_ENTRY_ERROR();
392
393         _pthread_mutex_lock(&private_display->lock);
394
395         if (error)
396                 *error = TDM_ERROR_NONE;
397
398         if (private_output->caps.capabilities & TDM_OUTPUT_CAPABILITY_HWC) {
399                 _pthread_mutex_unlock(&private_display->lock);
400                 TDM_ERR("output(%p) support HWC. Use HWC functions", private_output);
401                 if (error)
402                         *error = TDM_ERROR_BAD_REQUEST;
403                 return NULL;
404         }
405
406         LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
407                 if (private_layer->index == index) {
408                         _pthread_mutex_unlock(&private_display->lock);
409                         return private_layer;
410                 }
411         }
412
413         _pthread_mutex_unlock(&private_display->lock);
414
415         return NULL;
416 }
417
418 EXTERN tdm_error
419 tdm_output_get_available_properties(tdm_output *output, const tdm_prop **props,
420                                                                         int *count)
421 {
422         OUTPUT_FUNC_ENTRY();
423
424         TDM_RETURN_VAL_IF_FAIL(props != NULL, TDM_ERROR_INVALID_PARAMETER);
425         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
426
427         _pthread_mutex_lock(&private_display->lock);
428
429         *props = (const tdm_prop *)private_output->caps.props;
430         *count = private_output->caps.prop_count;
431
432         _pthread_mutex_unlock(&private_display->lock);
433
434         return ret;
435 }
436
437 EXTERN tdm_error
438 tdm_output_get_available_modes(tdm_output *output,
439                                                            const tdm_output_mode **modes, int *count)
440 {
441         OUTPUT_FUNC_ENTRY();
442
443         TDM_RETURN_VAL_IF_FAIL(modes != NULL, TDM_ERROR_INVALID_PARAMETER);
444         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
445
446         _pthread_mutex_lock(&private_display->lock);
447
448         *modes = (const tdm_output_mode *)private_output->caps.modes;
449         *count = private_output->caps.mode_count;
450
451         _pthread_mutex_unlock(&private_display->lock);
452
453         return ret;
454 }
455
456 EXTERN tdm_error
457 tdm_output_get_available_size(tdm_output *output, int *min_w, int *min_h,
458                                                           int *max_w, int *max_h, int *preferred_align)
459 {
460         OUTPUT_FUNC_ENTRY();
461
462         _pthread_mutex_lock(&private_display->lock);
463
464         if (min_w)
465                 *min_w = TDM_FRONT_VALUE(private_output->caps.min_w);
466         if (min_h)
467                 *min_h = TDM_FRONT_VALUE(private_output->caps.min_h);
468         if (max_w)
469                 *max_w = TDM_FRONT_VALUE(private_output->caps.max_w);
470         if (max_h)
471                 *max_h = TDM_FRONT_VALUE(private_output->caps.max_h);
472         if (preferred_align)
473                 *preferred_align = TDM_FRONT_VALUE(private_output->caps.preferred_align);
474
475         _pthread_mutex_unlock(&private_display->lock);
476
477         return ret;
478 }
479
480 EXTERN tdm_error
481 tdm_output_get_cursor_available_size(tdm_output *output, int *min_w, int *min_h,
482                                                                          int *max_w, int *max_h, int *preferred_align)
483 {
484         OUTPUT_FUNC_ENTRY();
485
486         _pthread_mutex_lock(&private_display->lock);
487
488         if (!tdm_display_check_module_abi(private_display, 1, 5)) {
489
490                 if (min_w)
491                         *min_w = -1;
492                 if (min_h)
493                         *min_h = -1;
494                 if (max_w)
495                         *max_w = -1;
496                 if (max_h)
497                         *max_h = -1;
498                 if (preferred_align)
499                         *preferred_align = -1;
500
501                 _pthread_mutex_unlock(&private_display->lock);
502
503                 return TDM_ERROR_BAD_MODULE;
504         }
505
506         if (min_w)
507                 *min_w = TDM_FRONT_VALUE(private_output->caps.cursor_min_w);
508         if (min_h)
509                 *min_h = TDM_FRONT_VALUE(private_output->caps.cursor_min_h);
510         if (max_w)
511                 *max_w = TDM_FRONT_VALUE(private_output->caps.cursor_max_w);
512         if (max_h)
513                 *max_h = TDM_FRONT_VALUE(private_output->caps.cursor_max_h);
514         if (preferred_align)
515                 *preferred_align = TDM_FRONT_VALUE(private_output->caps.cursor_preferred_align);
516
517         _pthread_mutex_unlock(&private_display->lock);
518
519         return ret;
520 }
521
522 EXTERN tdm_error
523 tdm_output_get_physical_size(tdm_output *output, unsigned int *mmWidth,
524                                                          unsigned int *mmHeight)
525 {
526         OUTPUT_FUNC_ENTRY();
527
528         _pthread_mutex_lock(&private_display->lock);
529
530         if (mmWidth)
531                 *mmWidth = private_output->caps.mmWidth;
532         if (mmHeight)
533                 *mmHeight = private_output->caps.mmHeight;
534
535         _pthread_mutex_unlock(&private_display->lock);
536
537         return ret;
538 }
539
540 EXTERN tdm_error
541 tdm_output_get_subpixel(tdm_output *output, unsigned int *subpixel)
542 {
543         OUTPUT_FUNC_ENTRY();
544         TDM_RETURN_VAL_IF_FAIL(subpixel != NULL, TDM_ERROR_INVALID_PARAMETER);
545
546         _pthread_mutex_lock(&private_display->lock);
547
548         *subpixel = private_output->caps.subpixel;
549
550         _pthread_mutex_unlock(&private_display->lock);
551
552         return ret;
553 }
554
555 EXTERN tdm_error
556 tdm_output_get_pipe(tdm_output *output, unsigned int *pipe)
557 {
558         OUTPUT_FUNC_ENTRY();
559         TDM_RETURN_VAL_IF_FAIL(pipe != NULL, TDM_ERROR_INVALID_PARAMETER);
560
561         _pthread_mutex_lock(&private_display->lock);
562
563         *pipe = private_output->pipe;
564
565         _pthread_mutex_unlock(&private_display->lock);
566
567         return ret;
568 }
569
570 EXTERN tdm_error
571 tdm_output_get_primary_index(tdm_output *output, int *index)
572 {
573         tdm_private_layer *private_layer = NULL;
574
575         OUTPUT_FUNC_ENTRY();
576         TDM_RETURN_VAL_IF_FAIL(index != NULL, TDM_ERROR_INVALID_PARAMETER);
577
578         _pthread_mutex_lock(&private_display->lock);
579
580         LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
581                 if (private_layer->caps.capabilities & TDM_LAYER_CAPABILITY_PRIMARY) {
582                         *index = private_layer->index;
583                         break;
584                 }
585         }
586
587         _pthread_mutex_unlock(&private_display->lock);
588
589         return ret;
590 }
591
592 EXTERN tdm_error
593 tdm_output_set_property(tdm_output *output, unsigned int id, tdm_value value)
594 {
595         tdm_func_output *func_output;
596         OUTPUT_FUNC_ENTRY();
597
598         _pthread_mutex_lock(&private_display->lock);
599
600         func_output = &private_display->func_output;
601
602         if (!func_output->output_set_property) {
603                 /* LCOV_EXCL_START */
604                 _pthread_mutex_unlock(&private_display->lock);
605                 TDM_ERR("not implemented!!");
606                 return TDM_ERROR_NOT_IMPLEMENTED;
607                 /* LCOV_EXCL_STOP */
608         }
609
610         ret = func_output->output_set_property(private_output->output_backend, id,
611                                                                                    value);
612
613         _pthread_mutex_unlock(&private_display->lock);
614
615         return ret;
616 }
617
618 EXTERN tdm_error
619 tdm_output_get_property(tdm_output *output, unsigned int id, tdm_value *value)
620 {
621         tdm_func_output *func_output;
622         OUTPUT_FUNC_ENTRY();
623
624         TDM_RETURN_VAL_IF_FAIL(value != NULL, TDM_ERROR_INVALID_PARAMETER);
625
626         _pthread_mutex_lock(&private_display->lock);
627
628         func_output = &private_display->func_output;
629
630         if (!func_output->output_get_property) {
631                 /* LCOV_EXCL_START */
632                 _pthread_mutex_unlock(&private_display->lock);
633                 TDM_ERR("not implemented!!");
634                 return TDM_ERROR_NOT_IMPLEMENTED;
635                 /* LCOV_EXCL_STOP */
636         }
637
638         ret = func_output->output_get_property(private_output->output_backend, id,
639                                                                                    value);
640
641         _pthread_mutex_unlock(&private_display->lock);
642
643         return ret;
644 }
645
646 INTERN void
647 tdm_output_cb_vblank(tdm_output *output_backend, unsigned int sequence,
648                                          unsigned int tv_sec, unsigned int tv_usec, void *user_data)
649 {
650         tdm_private_vblank_handler *vblank_handler = user_data;
651         tdm_private_vblank_handler *v = NULL, *vv = NULL;
652         tdm_private_output *private_output;
653         tdm_private_display *private_display;
654         struct list_head clone_list;
655         int interval, sync;
656         pid_t tid = syscall(SYS_gettid);
657
658         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
659         TDM_RETURN_IF_FAIL(vblank_handler);
660
661         private_output = vblank_handler->private_output;
662         private_display = private_output->private_display;
663
664         if (vblank_handler->owner_tid != tid) {
665                 tdm_thread_cb_output_vblank output_vblank;
666                 tdm_error ret;
667
668                 vblank_handler->sent_to_frontend = 1;
669
670                 output_vblank.base.type = TDM_THREAD_CB_OUTPUT_VBLANK;
671                 output_vblank.base.length = sizeof output_vblank;
672                 output_vblank.output_stamp = vblank_handler->private_output->stamp;
673                 output_vblank.sequence = sequence;
674                 output_vblank.tv_sec = tv_sec;
675                 output_vblank.tv_usec = tv_usec;
676                 output_vblank.user_data = user_data;
677
678                 ret = tdm_thread_send_cb(private_display->private_loop, &output_vblank.base);
679                 TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
680
681                 return;
682         }
683
684         vblank_handler->sent_to_frontend = 0;
685
686         _tdm_output_vblank_timeout_update(private_output, 0);
687
688         if (vblank_handler->owner_tid != tid)
689                 TDM_NEVER_GET_HERE();
690
691         interval = vblank_handler->interval;
692         sync = vblank_handler->sync;
693
694         LIST_INITHEAD(&clone_list);
695
696         LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_handler_list, link) {
697                 if (v->interval != interval || v->sync != sync || v->owner_tid != tid)
698                         continue;
699
700                 LIST_DEL(&v->link);
701                 LIST_ADDTAIL(&v->link, &clone_list);
702         }
703
704         if (tdm_debug_module & TDM_DEBUG_COMMIT)
705                 TDM_INFO("----------------------------------------- output(%d) got vblank", private_output->pipe);
706
707         _pthread_mutex_unlock(&private_display->lock);
708         LIST_FOR_EACH_ENTRY_SAFE(v, vv, &clone_list, link) {
709                 if (tdm_debug_module & TDM_DEBUG_COMMIT)
710                         TDM_INFO("handler(%p)", v);
711
712                 LIST_DEL(&v->link);
713
714                 if (v->func)
715                         v->func(v->private_output, sequence, tv_sec, tv_usec, v->user_data);
716
717                 free(v);
718         }
719         _pthread_mutex_lock(&private_display->lock);
720
721         if (tdm_debug_module & TDM_DEBUG_COMMIT)
722                 TDM_INFO("-----------------------------------------...");
723 }
724
725 INTERN void
726 tdm_output_cb_commit(tdm_output *output_backend, unsigned int sequence,
727                                          unsigned int tv_sec, unsigned int tv_usec, void *user_data)
728 {
729         tdm_private_output_commit_handler *output_commit_handler = user_data;
730         tdm_private_display *private_display;
731         tdm_private_output *private_output;
732         tdm_private_layer *private_layer = NULL;
733
734         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
735
736         if (!output_commit_handler)
737                 return;
738
739         private_output = output_commit_handler->private_output;
740         private_display = private_output->private_display;
741
742         if (output_commit_handler->owner_tid != syscall(SYS_gettid)) {
743                 tdm_thread_cb_output_commit output_commit;
744                 tdm_error ret;
745
746                 output_commit.base.type = TDM_THREAD_CB_OUTPUT_COMMIT;
747                 output_commit.base.length = sizeof output_commit;
748                 output_commit.output_stamp = private_output->stamp;
749                 output_commit.sequence = sequence;
750                 output_commit.tv_sec = tv_sec;
751                 output_commit.tv_usec = tv_usec;
752                 output_commit.user_data = user_data;
753
754                 ret = tdm_thread_send_cb(private_display->private_loop, &output_commit.base);
755                 TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
756
757                 return;
758         }
759
760         LIST_DEL(&output_commit_handler->link);
761
762         if (tdm_debug_module & TDM_DEBUG_COMMIT) {
763                 TDM_INFO("----------------------------------------- output(%d) committed", private_output->pipe);
764                 TDM_INFO("handler(%p)", output_commit_handler);
765         }
766
767         if (private_output->commit_type == TDM_COMMIT_TYPE_OUTPUT) {
768                 /* In case of layer commit, the below will be handled in the layer commit callback */
769                 LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
770                         if (private_layer->committed_buffer)
771                                 tdm_layer_committed(private_layer, &private_layer->committed_buffer);
772                 }
773         }
774
775         if (output_commit_handler->func) {
776                 _pthread_mutex_unlock(&private_display->lock);
777                 output_commit_handler->func(private_output, sequence,
778                                                                         tv_sec, tv_usec, output_commit_handler->user_data);
779                 _pthread_mutex_lock(&private_display->lock);
780         }
781
782         free(output_commit_handler);
783
784         if (tdm_debug_module & TDM_DEBUG_COMMIT)
785                 TDM_INFO("-----------------------------------------...");
786 }
787
788 /* add_front: To distinguish between the user vblank handlers and the layer
789  *            commit vblank handlers. The layer commit handlers will be called
790  *            before calling the user vblank handlers.
791  */
792 static tdm_error
793 _tdm_output_wait_vblank(tdm_output *output, int interval, int sync,
794                                                 tdm_output_vblank_handler func, void *user_data,
795                                                 unsigned int add_front)
796 {
797         tdm_func_output *func_output;
798         tdm_private_vblank_handler *vblank_handler = NULL, *v = NULL;
799         unsigned int skip_request = 0;
800         pid_t tid = syscall(SYS_gettid);
801
802         OUTPUT_FUNC_ENTRY();
803
804         func_output = &private_display->func_output;
805
806         /* interval SHOULD be at least 1 */
807         if (interval <= 0)
808                 interval = 1;
809
810         if (!func_output->output_wait_vblank) {
811                 /* LCOV_EXCL_START */
812                 TDM_ERR("not implemented!!");
813                 return TDM_ERROR_NOT_IMPLEMENTED;
814                 /* LCOV_EXCL_STOP */
815         }
816
817         if (!private_output->regist_vblank_cb) {
818                 private_output->regist_vblank_cb = 1;
819                 ret = func_output->output_set_vblank_handler(private_output->output_backend,
820                                 tdm_output_cb_vblank);
821         }
822
823         vblank_handler = calloc(1, sizeof(tdm_private_vblank_handler));
824         if (!vblank_handler) {
825                 /* LCOV_EXCL_START */
826                 TDM_ERR("failed: alloc memory");
827                 return TDM_ERROR_OUT_OF_MEMORY;
828                 /* LCOV_EXCL_STOP */
829         }
830
831         if (tdm_debug_module & TDM_DEBUG_COMMIT)
832                 TDM_INFO("output(%d) wait_vblank: handler(%p)", private_output->pipe, vblank_handler);
833
834         LIST_FOR_EACH_ENTRY(v, &private_output->vblank_handler_list, link) {
835                 if (v->interval == interval && v->sync == sync && v->owner_tid == tid) {
836                         skip_request = 1;
837                         break;
838                 }
839         }
840
841         if (add_front)
842                 LIST_ADD(&vblank_handler->link, &private_output->vblank_handler_list);
843         else
844                 LIST_ADDTAIL(&vblank_handler->link, &private_output->vblank_handler_list);
845
846         vblank_handler->private_output = private_output;
847         vblank_handler->interval = interval;
848         vblank_handler->sync = sync;
849         vblank_handler->func = func;
850         vblank_handler->user_data = user_data;
851         vblank_handler->owner_tid = tid;
852
853         /* If there is the previous request, we can skip to call output_wait_vblank() */
854         if (!skip_request) {
855                 ret = func_output->output_wait_vblank(private_output->output_backend, interval,
856                                                                                           sync, vblank_handler);
857                 TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, wait_failed);
858
859                 _tdm_output_vblank_timeout_update(private_output, 1000);
860
861                 if (tdm_debug_module & TDM_DEBUG_COMMIT)
862                         TDM_INFO("output(%d) backend wait_vblank", private_output->pipe);
863         }
864
865         return ret;
866
867 wait_failed:
868         /* LCOV_EXCL_START */
869         if (vblank_handler) {
870                 LIST_DEL(&vblank_handler->link);
871                 free(vblank_handler);
872         }
873         return ret;
874         /* LCOV_EXCL_STOP */
875 }
876
877 EXTERN tdm_error
878 tdm_output_wait_vblank(tdm_output *output, int interval, int sync,
879                                            tdm_output_vblank_handler func, void *user_data)
880 {
881         OUTPUT_FUNC_ENTRY();
882
883         _pthread_mutex_lock(&private_display->lock);
884
885         if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->current_dpms_value)) {
886                 TDM_WRN("output(%d) dpms: %s", private_output->pipe,
887                                 tdm_dpms_str(private_output->current_dpms_value));
888                 _pthread_mutex_unlock(&private_display->lock);
889                 return TDM_ERROR_DPMS_OFF;
890         }
891
892         ret = _tdm_output_wait_vblank(output, interval, sync, func, user_data, 0);
893
894         _pthread_mutex_unlock(&private_display->lock);
895
896         return ret;
897 }
898
899 /* LCOV_EXCL_START */
900 EXTERN tdm_error
901 tdm_output_wait_vblank_add_front(tdm_output *output, int interval, int sync,
902                                                                  tdm_output_vblank_handler func, void *user_data)
903 {
904         OUTPUT_FUNC_ENTRY();
905
906         _pthread_mutex_lock(&private_display->lock);
907
908         if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->current_dpms_value)) {
909                 TDM_WRN("output(%d) dpms: %s", private_output->pipe,
910                                 tdm_dpms_str(private_output->current_dpms_value));
911                 _pthread_mutex_unlock(&private_display->lock);
912                 return TDM_ERROR_DPMS_OFF;
913         }
914
915         ret = _tdm_output_wait_vblank(output, interval, sync, func, user_data, 1);
916
917         _pthread_mutex_unlock(&private_display->lock);
918
919         return ret;
920 }
921 /* LCOV_EXCL_STOP */
922
923 INTERN void
924 tdm_output_remove_vblank_handler_internal(tdm_output *output, tdm_output_vblank_handler func, void *user_data)
925 {
926         tdm_private_output *private_output = (tdm_private_output*)output;
927         tdm_private_vblank_handler *v = NULL;
928
929         TDM_RETURN_IF_FAIL(private_output != NULL);
930         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
931
932         LIST_FOR_EACH_ENTRY(v, &private_output->vblank_handler_list, link) {
933                 if (v->func == func && v->user_data == user_data) {
934                         /* only set func & user_data to NULL. It will be freed when an event occurs */
935                         v->func = NULL;
936                         v->user_data = NULL;
937                         break;
938                 }
939         }
940 }
941
942 INTERN void
943 tdm_output_remove_commit_handler_internal(tdm_output *output, tdm_output_commit_handler func, void *user_data)
944 {
945         tdm_private_output *private_output = (tdm_private_output*)output;
946         tdm_private_output_commit_handler *c = NULL;
947
948         TDM_RETURN_IF_FAIL(private_output != NULL);
949         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
950
951         LIST_FOR_EACH_ENTRY(c, &private_output->output_commit_handler_list, link) {
952                 if (c->func == func && c->user_data == user_data) {
953                         /* only set func & user_data to NULL. It will be freed when an event occurs */
954                         c->func = NULL;
955                         c->user_data = NULL;
956                         break;
957                 }
958         }
959 }
960
961 EXTERN tdm_error
962 tdm_output_remove_vblank_handler(tdm_output *output, tdm_output_vblank_handler func, void *user_data)
963 {
964         OUTPUT_FUNC_ENTRY();
965
966         _pthread_mutex_lock(&private_display->lock);
967
968         tdm_output_remove_vblank_handler_internal(output, func, user_data);
969
970         _pthread_mutex_unlock(&private_display->lock);
971
972         return ret;
973 }
974
975 EXTERN tdm_error
976 tdm_output_remove_commit_handler(tdm_output *output, tdm_output_commit_handler func, void *user_data)
977 {
978         OUTPUT_FUNC_ENTRY();
979
980         _pthread_mutex_lock(&private_display->lock);
981
982         tdm_output_remove_commit_handler_internal(output, func, user_data);
983
984         _pthread_mutex_unlock(&private_display->lock);
985
986         return ret;
987 }
988
989 INTERN tdm_error
990 tdm_output_commit_internal(tdm_output *output, int sync, tdm_output_commit_handler func, void *user_data)
991 {
992         tdm_func_output *func_output;
993         tdm_private_output_commit_handler *output_commit_handler = NULL;
994         tdm_private_layer *private_layer = NULL;
995         tdm_output_dpms dpms_value = TDM_OUTPUT_DPMS_ON;
996
997         OUTPUT_FUNC_ENTRY();
998
999         func_output = &private_display->func_output;
1000
1001         if (!func_output->output_commit) {
1002                 /* LCOV_EXCL_START */
1003                 TDM_ERR("not implemented!!");
1004                 return TDM_ERROR_NOT_IMPLEMENTED;
1005                 /* LCOV_EXCL_STOP */
1006         }
1007
1008         ret = tdm_output_get_dpms_internal(output, &dpms_value);
1009         TDM_RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
1010
1011         if (!TDM_OUTPUT_DPMS_VSYNC_IS_OFF(dpms_value)) {
1012                 if (func) {
1013                         if (!private_output->regist_commit_cb) {
1014                                 private_output->regist_commit_cb = 1;
1015                                 ret = func_output->output_set_commit_handler(private_output->output_backend,
1016                                                         tdm_output_cb_commit);
1017                                 TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed);
1018                         }
1019
1020                         output_commit_handler = calloc(1, sizeof(tdm_private_output_commit_handler));
1021                         if (!output_commit_handler) {
1022                                 /* LCOV_EXCL_START */
1023                                 TDM_ERR("failed: alloc memory");
1024                                 return TDM_ERROR_OUT_OF_MEMORY;
1025                                 /* LCOV_EXCL_STOP */
1026                         }
1027
1028                         LIST_ADDTAIL(&output_commit_handler->link, &private_output->output_commit_handler_list);
1029                         output_commit_handler->private_output = private_output;
1030                         output_commit_handler->func = func;
1031                         output_commit_handler->user_data = user_data;
1032                         output_commit_handler->owner_tid = syscall(SYS_gettid);
1033                 }
1034
1035                 ret = func_output->output_commit(private_output->output_backend, sync,
1036                                 output_commit_handler);
1037                 TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed);
1038
1039                 if (tdm_debug_module & TDM_DEBUG_COMMIT)
1040                         TDM_INFO("output(%d) backend commit: handle(%p) func(%p) user_data(%p)",
1041                                         private_output->pipe, output_commit_handler, func, user_data);
1042         }
1043
1044         /* Even if DPMS is off, committed_buffer should be changed because it will be referred
1045          * for tdm_layer_committed() function.
1046          */
1047         LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
1048                 if (!private_layer->waiting_buffer)
1049                         continue;
1050
1051                 private_layer->committed_buffer = private_layer->waiting_buffer;
1052                 private_layer->waiting_buffer = NULL;
1053                 if (tdm_debug_module & TDM_DEBUG_BUFFER)
1054                         TDM_INFO("layer(%p) waiting_buffer(%p) committed_buffer(%p)",
1055                                          private_layer, private_layer->waiting_buffer,
1056                                          private_layer->committed_buffer->buffer);
1057         }
1058
1059         if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(dpms_value)) {
1060                 TDM_WRN("dpms %s. Directly call commit handler instead of commit.", tdm_dpms_str(dpms_value));
1061                 if (func)
1062                         func(output, 0, 0, 0, user_data);
1063         }
1064
1065         return ret;
1066
1067 commit_failed:
1068         /* LCOV_EXCL_START */
1069         if (output_commit_handler) {
1070                 LIST_DEL(&output_commit_handler->link);
1071                 free(output_commit_handler);
1072         }
1073         return ret;
1074         /* LCOV_EXCL_STOP */
1075 }
1076
1077 EXTERN tdm_error
1078 tdm_output_commit(tdm_output *output, int sync, tdm_output_commit_handler func,
1079                                   void *user_data)
1080 {
1081         tdm_private_layer *private_layer = NULL;
1082
1083         OUTPUT_FUNC_ENTRY();
1084
1085         _pthread_mutex_lock(&private_display->lock);
1086
1087         if (private_output->commit_type == TDM_COMMIT_TYPE_NONE)
1088                 private_output->commit_type = TDM_COMMIT_TYPE_OUTPUT;
1089         else if (private_output->commit_type == TDM_COMMIT_TYPE_LAYER) {
1090                 TDM_ERR("Can't supported. Use tdm_layer_commit");
1091                 _pthread_mutex_unlock(&private_display->lock);
1092                 return TDM_ERROR_BAD_REQUEST;
1093         }
1094
1095         if (private_output->commit_per_vblank) {
1096                 TDM_ERR("Use tdm_layer_commit");
1097                 _pthread_mutex_unlock(&private_display->lock);
1098                 return TDM_ERROR_BAD_REQUEST;
1099         }
1100
1101         if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->current_dpms_value)) {
1102                 TDM_ERR("output(%d) dpms: %s", private_output->pipe,
1103                                 tdm_dpms_str(private_output->current_dpms_value));
1104                 _pthread_mutex_unlock(&private_display->lock);
1105                 return TDM_ERROR_DPMS_OFF;
1106         }
1107
1108         if (tdm_debug_module & TDM_DEBUG_COMMIT)
1109                 TDM_INFO("output(%d) commit", private_output->pipe);
1110
1111         /* apply the pending data of all layers */
1112         LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
1113                 tdm_layer_commit_pending_data(private_layer);
1114         }
1115
1116         ret = tdm_output_commit_internal(output, sync, func, user_data);
1117
1118         _pthread_mutex_unlock(&private_display->lock);
1119
1120         return ret;
1121 }
1122
1123 EXTERN tdm_error
1124 tdm_output_set_mode(tdm_output *output, const tdm_output_mode *mode)
1125 {
1126         tdm_func_output *func_output;
1127         OUTPUT_FUNC_ENTRY();
1128
1129         TDM_RETURN_VAL_IF_FAIL(mode != NULL, TDM_ERROR_INVALID_PARAMETER);
1130
1131         _pthread_mutex_lock(&private_display->lock);
1132
1133         func_output = &private_display->func_output;
1134
1135         if (!func_output->output_set_mode) {
1136                 /* LCOV_EXCL_START */
1137                 _pthread_mutex_unlock(&private_display->lock);
1138                 TDM_ERR("not implemented!!");
1139                 return TDM_ERROR_NOT_IMPLEMENTED;
1140                 /* LCOV_EXCL_STOP */
1141         }
1142
1143         ret = func_output->output_set_mode(private_output->output_backend, mode);
1144         if (ret == TDM_ERROR_NONE) {
1145                 private_output->current_mode = mode;
1146                 TDM_INFO("mode: %dx%d %dhz", mode->hdisplay, mode->vdisplay, mode->vrefresh);
1147         }
1148
1149         _pthread_mutex_unlock(&private_display->lock);
1150
1151         return ret;
1152 }
1153
1154 EXTERN tdm_error
1155 tdm_output_get_mode(tdm_output *output, const tdm_output_mode **mode)
1156 {
1157         OUTPUT_FUNC_ENTRY();
1158
1159         TDM_RETURN_VAL_IF_FAIL(mode != NULL, TDM_ERROR_INVALID_PARAMETER);
1160
1161         _pthread_mutex_lock(&private_display->lock);
1162
1163         *mode = private_output->current_mode;
1164
1165         _pthread_mutex_unlock(&private_display->lock);
1166
1167         return ret;
1168 }
1169
1170 static tdm_error
1171 _tdm_output_dpms_changed_timeout(void *user_data)
1172 {
1173         tdm_private_output *private_output = user_data;
1174         tdm_value value;
1175
1176         value.u32 = private_output->current_dpms_value;
1177         tdm_output_call_change_handler_internal(private_output,
1178                                                                                         &private_output->change_handler_list_sub,
1179                                                                                         TDM_OUTPUT_CHANGE_DPMS,
1180                                                                                         value, 0);
1181
1182         return TDM_ERROR_NONE;
1183 }
1184
1185 static tdm_error
1186 tdm_output_call_dpms_change_handler(tdm_output *output)
1187 {
1188         tdm_private_output *private_output = (tdm_private_output*)output;
1189         tdm_value value;
1190
1191         /** Use timer to call the output change callback of the sub-thread.
1192          * The output change callback of tdm_server and tdm_vblank was called
1193          * in the main thread. And it made the multi thread issue. If we use
1194          * the timer, we can call the sub-thread's output change callback in
1195          * sub-thread.
1196          */
1197         if (!private_output->dpms_changed_timer) {
1198                 private_output->dpms_changed_timer =
1199                         tdm_event_loop_add_timer_handler(private_output->private_display,
1200                                                                                          _tdm_output_dpms_changed_timeout, private_output, NULL);
1201                 if (!private_output->dpms_changed_timer) {
1202                         /* LCOV_EXCL_START */
1203                         TDM_ERR("can't create dpms timer!!");
1204                         return TDM_ERROR_OUT_OF_MEMORY;
1205                         /* LCOV_EXCL_STOP */
1206                 }
1207         }
1208
1209         value.u32 = private_output->current_dpms_value;
1210         tdm_output_call_change_handler_internal(private_output,
1211                                                                                         &private_output->change_handler_list_main,
1212                                                                                         TDM_OUTPUT_CHANGE_DPMS,
1213                                                                                         value, 0);
1214
1215         if (!LIST_IS_EMPTY(&private_output->change_handler_list_sub)) {
1216                 tdm_error ret = tdm_event_loop_source_timer_update(private_output->dpms_changed_timer, 1);
1217                 if (ret != TDM_ERROR_NONE)
1218                         TDM_NEVER_GET_HERE();
1219         }
1220
1221         return TDM_ERROR_NONE;
1222 }
1223
1224 /* LCOV_EXCL_START */
1225 INTERN void
1226 tdm_output_cb_dpms(tdm_output *output_backend, tdm_output_dpms dpms, void *user_data)
1227 {
1228         tdm_private_display *private_display;
1229         tdm_private_output *private_output = user_data;
1230         tdm_value value;
1231
1232         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
1233         TDM_RETURN_IF_FAIL(private_output);
1234
1235         private_display = private_output->private_display;
1236
1237         if (!tdm_thread_in_display_thread(syscall(SYS_gettid))) {
1238                 tdm_thread_cb_output_dpms output_dpms;
1239                 tdm_error ret;
1240
1241                 _tdm_output_update(output_backend, user_data);
1242
1243                 output_dpms.base.type = TDM_THREAD_CB_OUTPUT_DPMS;
1244                 output_dpms.base.length = sizeof output_dpms;
1245                 output_dpms.output_stamp = private_output->stamp;
1246                 output_dpms.dpms = dpms;
1247                 output_dpms.user_data = user_data;
1248
1249                 value.u32 = dpms;
1250                 tdm_output_call_change_handler_internal(private_output,
1251                                                                                                 &private_output->change_handler_list_sub,
1252                                                                                                 TDM_OUTPUT_CHANGE_DPMS,
1253                                                                                                 value, 0);
1254
1255                 ret = tdm_thread_send_cb(private_display->private_loop, &output_dpms.base);
1256                 TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
1257
1258                 return;
1259         }
1260
1261         private_output->current_dpms_value = dpms;
1262         private_output->waiting_dpms_change = 0;
1263
1264         TDM_INFO("output(%d) dpms async '%s' done", private_output->pipe, tdm_dpms_str(dpms));
1265
1266         value.u32 = dpms;
1267         tdm_output_call_change_handler_internal(private_output,
1268                                                                                         &private_output->change_handler_list_main,
1269                                                                                         TDM_OUTPUT_CHANGE_DPMS,
1270                                                                                         value, 0);
1271 }
1272 /* LCOV_EXCL_STOP */
1273
1274 EXTERN tdm_error
1275 tdm_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value)
1276 {
1277         tdm_func_output *func_output;
1278         OUTPUT_FUNC_ENTRY();
1279
1280         if (dpms_value > TDM_OUTPUT_DPMS_OFF) {
1281                 if (dpms_value & TDM_OUTPUT_DPMS_DEFAULT_MASK) {
1282                         TDM_ERR("Don't use the low-4bit for an extended DPMS mode: dpms_value(%x)", dpms_value);
1283                         return TDM_ERROR_BAD_REQUEST;
1284                 }
1285
1286                 if (!(private_output->caps.capabilities & TDM_OUTPUT_CAPABILITY_EXTENDED_DPMS)) {
1287                         TDM_ERR("output(%d) doesn't support the extended DPMS control: '%s'",
1288                                         private_output->pipe, tdm_dpms_str(dpms_value));
1289                         return TDM_ERROR_BAD_REQUEST;
1290                 }
1291         }
1292
1293         _pthread_mutex_lock(&private_display->lock);
1294
1295         if (private_output->waiting_dpms_change) {
1296                 TDM_ERR("DPMS is not changed yet. Can't be changed twice");
1297                 _pthread_mutex_unlock(&private_display->lock);
1298                 return TDM_ERROR_BAD_REQUEST;
1299         }
1300
1301         func_output = &private_display->func_output;
1302
1303         TDM_INFO("output(%d) dpms '%s'", private_output->pipe, tdm_dpms_str(dpms_value));
1304
1305         if (func_output->output_set_dpms)
1306                 ret = func_output->output_set_dpms(private_output->output_backend, dpms_value);
1307         else {
1308                 /* LCOV_EXCL_START */
1309                 ret = TDM_ERROR_NONE;
1310                 TDM_WRN("not implemented!!");
1311                 goto done;
1312                 /* LCOV_EXCL_STOP */
1313         }
1314
1315 done:
1316         if (ret == TDM_ERROR_NONE) {
1317                 if (private_output->current_dpms_value != dpms_value) {
1318                         private_output->current_dpms_value = dpms_value;
1319                         TDM_INFO("output(%d) dpms '%s' done", private_output->pipe, tdm_dpms_str(dpms_value));
1320                         tdm_output_call_dpms_change_handler(output);
1321                 }
1322         } else {
1323                 tdm_output_dpms temp = TDM_OUTPUT_DPMS_OFF;
1324
1325                 /* update current_dpms_value forcely */
1326                 tdm_output_get_dpms_internal(output, &temp);
1327
1328                 TDM_ERR("output(%d) set_dpms failed: dpms '%s'", private_output->pipe, tdm_dpms_str(temp));
1329         }
1330
1331         _pthread_mutex_unlock(&private_display->lock);
1332
1333         return ret;
1334 }
1335
1336 /* LCOV_EXCL_START */
1337 EXTERN tdm_error
1338 tdm_output_set_dpms_async(tdm_output *output, tdm_output_dpms dpms_value)
1339 {
1340         tdm_func_output *func_output;
1341         OUTPUT_FUNC_ENTRY();
1342
1343         if (!(private_output->caps.capabilities & TDM_OUTPUT_CAPABILITY_ASYNC_DPMS)) {
1344                 TDM_ERR("output doesn't support the asynchronous DPMS control!");
1345                 return TDM_ERROR_BAD_REQUEST;
1346         }
1347
1348         if (dpms_value > TDM_OUTPUT_DPMS_OFF) {
1349                 if (dpms_value & TDM_OUTPUT_DPMS_DEFAULT_MASK) {
1350                         TDM_ERR("Don't use the low-4bit for an extended DPMS mode: dpms_value(%x)", dpms_value);
1351                         return TDM_ERROR_BAD_REQUEST;
1352                 }
1353
1354                 if (!(private_output->caps.capabilities & TDM_OUTPUT_CAPABILITY_EXTENDED_DPMS)) {
1355                         TDM_ERR("output(%d) doesn't support the extended DPMS control: '%s'",
1356                                         private_output->pipe, tdm_dpms_str(dpms_value));
1357                         return TDM_ERROR_BAD_REQUEST;
1358                 }
1359         }
1360
1361         _pthread_mutex_lock(&private_display->lock);
1362
1363         if (private_output->waiting_dpms_change) {
1364                 TDM_ERR("DPMS is not changed yet. Can't be changed twice");
1365                 _pthread_mutex_unlock(&private_display->lock);
1366                 return TDM_ERROR_BAD_REQUEST;
1367         }
1368
1369         func_output = &private_display->func_output;
1370         if (!func_output->output_set_dpms_handler) {
1371                 TDM_ERR("not implemented: output_set_dpms_handler");
1372                 _pthread_mutex_unlock(&private_display->lock);
1373                 return TDM_ERROR_NOT_IMPLEMENTED;
1374         }
1375
1376         if (!func_output->output_set_dpms_async) {
1377                 TDM_ERR("not implemented: output_set_dpms_async");
1378                 _pthread_mutex_unlock(&private_display->lock);
1379                 return TDM_ERROR_NOT_IMPLEMENTED;
1380         }
1381
1382         if (!private_output->regist_dpms_cb) {
1383                 private_output->regist_dpms_cb = 1;
1384                 ret = func_output->output_set_dpms_handler(private_output->output_backend,
1385                                 tdm_output_cb_dpms, private_output);
1386                 if (ret != TDM_ERROR_NONE) {
1387                         _pthread_mutex_unlock(&private_display->lock);
1388                         TDM_ERR("Can't set the dpms handler!!");
1389                         return ret;
1390                 }
1391         }
1392
1393         TDM_INFO("output(%d) dpms async '%s'", private_output->pipe, tdm_dpms_str(dpms_value));
1394
1395         ret = func_output->output_set_dpms_async(private_output->output_backend, dpms_value);
1396
1397         if (ret == TDM_ERROR_NONE) {
1398                 private_output->waiting_dpms_change = 1;
1399                 TDM_INFO("output(%d) dpms async '%s' waiting", private_output->pipe, tdm_dpms_str(dpms_value));
1400         } else {
1401                 tdm_output_dpms temp = TDM_OUTPUT_DPMS_OFF;
1402
1403                 /* update current_dpms_value forcely */
1404                 tdm_output_get_dpms_internal(output, &temp);
1405
1406                 TDM_ERR("output(%d) set_dpms_async failed: dpms '%s'", private_output->pipe, tdm_dpms_str(temp));
1407         }
1408
1409         _pthread_mutex_unlock(&private_display->lock);
1410
1411         return ret;
1412 }
1413 /* LCOV_EXCL_STOP */
1414
1415 INTERN tdm_error
1416 tdm_output_get_dpms_internal(tdm_output *output, tdm_output_dpms *dpms_value)
1417 {
1418         tdm_func_output *func_output;
1419         OUTPUT_FUNC_ENTRY();
1420
1421         TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_INVALID_PARAMETER);
1422
1423         /* TODO: this is ugly. But before calling backend's output_get_dpms(), we have
1424          * to check if all backends's DPMS operation has no problem. In future, we'd
1425          * better use new env instead of using commit_per_vblank variable to distinguish
1426          * whether we use the stored value or backend's output_get_dpms.
1427          */
1428         if (!private_output->commit_per_vblank) {
1429                 *dpms_value = private_output->current_dpms_value;
1430                 return TDM_ERROR_NONE;
1431         }
1432
1433         func_output = &private_display->func_output;
1434
1435         if (!func_output->output_get_dpms) {
1436                 /* LCOV_EXCL_START */
1437                 *dpms_value = private_output->current_dpms_value;
1438                 TDM_WRN("not implemented!!");
1439                 return TDM_ERROR_NONE;
1440                 /* LCOV_EXCL_STOP */
1441         }
1442
1443         ret = func_output->output_get_dpms(private_output->output_backend, dpms_value);
1444         if (ret != TDM_ERROR_NONE) {
1445                 /* LCOV_EXCL_START */
1446                 TDM_ERR("output_get_dpms failed");
1447                 *dpms_value = TDM_OUTPUT_DPMS_OFF;
1448                 /* LCOV_EXCL_STOP */
1449         }
1450
1451         /* checking with backend's value */
1452         if (*dpms_value != private_output->current_dpms_value) {
1453                 TDM_ERR("output(%d) dpms changed suddenly: %s -> %s",
1454                                 private_output->pipe, private_output->current_dpms_value,
1455                                 tdm_dpms_str(*dpms_value));
1456                 private_output->current_dpms_value = *dpms_value;
1457                 tdm_output_call_dpms_change_handler(output);
1458         }
1459
1460         return ret;
1461 }
1462
1463 EXTERN tdm_error
1464 tdm_output_get_dpms(tdm_output *output, tdm_output_dpms *dpms_value)
1465 {
1466         OUTPUT_FUNC_ENTRY();
1467
1468         TDM_RETURN_VAL_IF_FAIL(dpms_value != NULL, TDM_ERROR_INVALID_PARAMETER);
1469
1470         _pthread_mutex_lock(&private_display->lock);
1471
1472         ret = tdm_output_get_dpms_internal(output, dpms_value);
1473
1474         _pthread_mutex_unlock(&private_display->lock);
1475
1476         return ret;
1477 }
1478
1479 EXTERN tdm_capture *
1480 tdm_output_create_capture(tdm_output *output, tdm_error *error)
1481 {
1482         tdm_capture *capture = NULL;
1483
1484         OUTPUT_FUNC_ENTRY_ERROR();
1485
1486         _pthread_mutex_lock(&private_display->lock);
1487
1488         capture = (tdm_capture *)tdm_capture_create_output_internal(private_output, error);
1489
1490         _pthread_mutex_unlock(&private_display->lock);
1491
1492         return capture;
1493 }
1494
1495 EXTERN tdm_hwc_window *
1496 tdm_output_hwc_create_window(tdm_output *output, tdm_error *error)
1497 {
1498         tdm_hwc_window *hwc_window = NULL;
1499
1500         OUTPUT_FUNC_ENTRY_ERROR();
1501
1502         _pthread_mutex_lock(&private_display->lock);
1503
1504         if (private_output->caps.capabilities & TDM_OUTPUT_CAPABILITY_HWC)
1505                 hwc_window = (tdm_hwc_window *)tdm_hwc_window_create_internal(private_output, 0, error);
1506         else {
1507                 /* LCOV_EXCL_START */
1508                 TDM_ERR("output(%p) not support HWC", private_output);
1509                 if (error)
1510                         *error = TDM_ERROR_BAD_REQUEST;
1511                 /* LCOV_EXCL_STOP */
1512         }
1513
1514         _pthread_mutex_unlock(&private_display->lock);
1515
1516         return hwc_window;
1517 }
1518
1519 EXTERN tdm_hwc_window *
1520 tdm_output_hwc_create_video_window(tdm_output *output, tdm_error *error)
1521 {
1522         tdm_hwc_window *hwc_window = NULL;
1523
1524         OUTPUT_FUNC_ENTRY_ERROR();
1525
1526         _pthread_mutex_lock(&private_display->lock);
1527
1528         if (private_output->caps.capabilities & TDM_OUTPUT_CAPABILITY_HWC)
1529                 hwc_window = (tdm_hwc_window *)tdm_hwc_window_create_internal(private_output, 1, error);
1530         else {
1531                 /* LCOV_EXCL_START */
1532                 TDM_ERR("output(%p) not support HWC", private_output);
1533                 if (error)
1534                         *error = TDM_ERROR_BAD_REQUEST;
1535                 /* LCOV_EXCL_STOP */
1536         }
1537
1538         _pthread_mutex_unlock(&private_display->lock);
1539
1540         return hwc_window;
1541 }
1542
1543 EXTERN tdm_error
1544 tdm_output_hwc_destroy_window(tdm_output *output, tdm_hwc_window *hwc_window)
1545 {
1546         OUTPUT_FUNC_ENTRY();
1547
1548         TDM_RETURN_VAL_IF_FAIL(hwc_window != NULL, TDM_ERROR_INVALID_PARAMETER);
1549
1550         _pthread_mutex_lock(&private_display->lock);
1551
1552         ret = tdm_hwc_window_destroy_internal(hwc_window);
1553
1554         _pthread_mutex_unlock(&private_display->lock);
1555
1556         return ret;
1557 }
1558
1559 EXTERN tdm_error
1560 tdm_output_hwc_validate(tdm_output *output, uint32_t *num_types)
1561 {
1562         tdm_func_output *func_output = NULL;
1563
1564         OUTPUT_FUNC_ENTRY();
1565
1566         TDM_RETURN_VAL_IF_FAIL(num_types != NULL, TDM_ERROR_INVALID_PARAMETER);
1567
1568         _pthread_mutex_lock(&private_display->lock);
1569
1570         if (!(private_output->caps.capabilities & TDM_OUTPUT_CAPABILITY_HWC)) {
1571                 TDM_ERR("output(%p) not support HWC", private_output);
1572                 _pthread_mutex_unlock(&private_display->lock);
1573                 return TDM_ERROR_BAD_REQUEST;
1574         }
1575
1576         func_output = &private_display->func_output;
1577
1578         if (!func_output->output_hwc_validate) {
1579                 /* LCOV_EXCL_START */
1580                 _pthread_mutex_unlock(&private_display->lock);
1581                 TDM_ERR("not implemented!!");
1582                 return TDM_ERROR_NOT_IMPLEMENTED;
1583                 /* LCOV_EXCL_STOP */
1584         }
1585
1586         ret = func_output->output_hwc_validate(private_output->output_backend, num_types);
1587
1588         _pthread_mutex_unlock(&private_display->lock);
1589
1590         return ret;
1591 }
1592
1593 EXTERN tdm_error
1594 tdm_output_hwc_set_need_validate_handler(tdm_output *output,
1595                 tdm_output_need_validate_handler hndl)
1596 {
1597         OUTPUT_FUNC_ENTRY();
1598
1599         TDM_RETURN_VAL_IF_FAIL(hndl != NULL, TDM_ERROR_INVALID_PARAMETER);
1600
1601         _pthread_mutex_lock(&private_display->lock);
1602
1603         if (!(private_output->caps.capabilities & TDM_OUTPUT_CAPABILITY_HWC)) {
1604                 TDM_ERR("output(%p) not support HWC", private_output);
1605                 _pthread_mutex_unlock(&private_display->lock);
1606                 return TDM_ERROR_BAD_REQUEST;
1607         }
1608
1609         /* there's no reason to allow this */
1610         if (private_output->need_validate.hndl) {
1611
1612                 _pthread_mutex_unlock(&private_display->lock);
1613                 return TDM_ERROR_OPERATION_FAILED;
1614         }
1615
1616         private_output->need_validate.hndl = hndl;
1617
1618         _pthread_mutex_unlock(&private_display->lock);
1619
1620         return ret;
1621 }
1622
1623 EXTERN tdm_error
1624 tdm_output_hwc_get_changed_composition_types(tdm_output *output,
1625                                                                                  uint32_t *num_elements,
1626                                                                                  tdm_hwc_window **hwc_window,
1627                                                                                  tdm_hwc_window_composition *composition_types)
1628 {
1629         tdm_func_output *func_output = NULL;
1630         tdm_private_hwc_window * private_hwc_window = NULL;
1631         int i = 0;
1632
1633         OUTPUT_FUNC_ENTRY();
1634
1635         TDM_RETURN_VAL_IF_FAIL(num_elements != NULL, TDM_ERROR_INVALID_PARAMETER);
1636
1637         _pthread_mutex_lock(&private_display->lock);
1638
1639         if (!(private_output->caps.capabilities & TDM_OUTPUT_CAPABILITY_HWC)) {
1640                 TDM_ERR("output(%p) not support HWC", private_output);
1641                 _pthread_mutex_unlock(&private_display->lock);
1642                 return TDM_ERROR_BAD_REQUEST;
1643         }
1644
1645         func_output = &private_display->func_output;
1646
1647         if (!func_output->output_hwc_get_changed_composition_types) {
1648                 /* LCOV_EXCL_START */
1649                 _pthread_mutex_unlock(&private_display->lock);
1650                 TDM_ERR("not implemented!!");
1651                 return TDM_ERROR_NOT_IMPLEMENTED;
1652                 /* LCOV_EXCL_STOP */
1653         }
1654
1655         ret = func_output->output_hwc_get_changed_composition_types(private_output->output_backend,
1656                                                         num_elements, hwc_window, composition_types);
1657         if (ret != TDM_ERROR_NONE) {
1658                 /* LCOV_EXCL_START */
1659                 _pthread_mutex_unlock(&private_display->lock);
1660                 return ret;
1661                 /* LCOV_EXCL_STOP */
1662         }
1663
1664         if (hwc_window == NULL || composition_types == NULL) {
1665                 _pthread_mutex_unlock(&private_display->lock);
1666                 return TDM_ERROR_NONE;
1667         }
1668
1669         for (i = 0; i < *num_elements; i++) {
1670
1671                 private_hwc_window = _tdm_output_find_private_hwc_window(private_output, hwc_window[i]);
1672
1673                 if (private_hwc_window == NULL) {
1674                         /* LCOV_EXCL_START */
1675                         TDM_ERR("failed! This should never happen!");
1676                         func_output->output_hwc_destroy_window(private_output->output_backend, hwc_window[i]);
1677                         *num_elements = 0;
1678                         _pthread_mutex_unlock(&private_display->lock);
1679                         return TDM_ERROR_OPERATION_FAILED;
1680                         /* LCOV_EXCL_STOP */
1681                 }
1682
1683                 hwc_window[i] = (tdm_hwc_window*)private_hwc_window;
1684         }
1685
1686         _pthread_mutex_unlock(&private_display->lock);
1687
1688         return ret;
1689 }
1690
1691 tdm_error
1692 tdm_output_hwc_accept_changes(tdm_output *output)
1693 {
1694         tdm_func_output *func_output = NULL;
1695
1696         OUTPUT_FUNC_ENTRY();
1697
1698         _pthread_mutex_lock(&private_display->lock);
1699
1700         if (!(private_output->caps.capabilities & TDM_OUTPUT_CAPABILITY_HWC)) {
1701                 TDM_ERR("output(%p) not support HWC", private_output);
1702                 _pthread_mutex_unlock(&private_display->lock);
1703                 return TDM_ERROR_BAD_REQUEST;
1704         }
1705
1706         func_output = &private_display->func_output;
1707
1708         if (!func_output->output_hwc_validate) {
1709                 /* LCOV_EXCL_START */
1710                 _pthread_mutex_unlock(&private_display->lock);
1711                 TDM_ERR("not implemented!!");
1712                 return TDM_ERROR_NOT_IMPLEMENTED;
1713                 /* LCOV_EXCL_STOP */
1714         }
1715
1716         ret = func_output->output_hwc_accept_changes(private_output->output_backend);
1717
1718         _pthread_mutex_unlock(&private_display->lock);
1719
1720         return ret;
1721 }
1722
1723 tbm_surface_queue_h
1724 tdm_output_hwc_get_target_buffer_queue(tdm_output *output, tdm_error *error)
1725 {
1726         tdm_func_output *func_output = NULL;
1727         tbm_surface_queue_h queue = NULL;
1728
1729         OUTPUT_FUNC_ENTRY_ERROR();
1730
1731         _pthread_mutex_lock(&private_display->lock);
1732
1733         if (!(private_output->caps.capabilities & TDM_OUTPUT_CAPABILITY_HWC)) {
1734                 TDM_ERR("output(%p) not support HWC", private_output);
1735                 if (error)
1736                         *error = TDM_ERROR_BAD_REQUEST;
1737                 _pthread_mutex_unlock(&private_display->lock);
1738                 return NULL;
1739         }
1740
1741         func_output = &private_display->func_output;
1742
1743         if (!func_output->output_hwc_get_target_buffer_queue) {
1744                 /* LCOV_EXCL_START */
1745                 _pthread_mutex_unlock(&private_display->lock);
1746                 TDM_ERR("not implemented!!");
1747                 return NULL;
1748                 /* LCOV_EXCL_STOP */
1749         }
1750
1751         queue = func_output->output_hwc_get_target_buffer_queue(private_output->output_backend, error);
1752
1753         _pthread_mutex_unlock(&private_display->lock);
1754
1755         return queue;
1756 }
1757
1758 /* LCOV_EXCL_START */
1759 static void
1760 _tdm_target_window_dump_buffer(tdm_private_output *private_output, tbm_surface_h buffer)
1761 {
1762         unsigned int pipe;
1763         char fname[TDM_PATH_LEN];
1764
1765         pipe = private_output->pipe;
1766
1767         snprintf(fname, sizeof(fname), "tdm_%d_target_win", pipe);
1768
1769         tbm_surface_internal_dump_buffer(buffer, fname);
1770         TDM_DBG("%s dump excute", fname);
1771
1772         return;
1773 }
1774 /* LCOV_EXCL_STOP */
1775
1776 EXTERN tdm_error
1777 tdm_output_hwc_set_client_target_buffer(tdm_output *output, tbm_surface_h target_buffer,
1778                                                                         tdm_hwc_region damage, tdm_hwc_window **composited_wnds,
1779                                                                         uint32_t num_wnds)
1780 {
1781         tdm_func_output *func_output = NULL;
1782         tdm_private_hwc_window **composited_wnds_frontend = NULL;
1783         tdm_hwc_window **composited_wnds_backend = NULL;
1784         int i;
1785
1786         OUTPUT_FUNC_ENTRY();
1787
1788         _pthread_mutex_lock(&private_display->lock);
1789
1790         if (!(private_output->caps.capabilities & TDM_OUTPUT_CAPABILITY_HWC)) {
1791                 TDM_ERR("output(%p) not support HWC", private_output);
1792                 _pthread_mutex_unlock(&private_display->lock);
1793                 return TDM_ERROR_BAD_REQUEST;
1794         }
1795
1796         if (tdm_debug_dump & TDM_DUMP_FLAG_WINDOW) {
1797                 /* LCOV_EXCL_START */
1798                 char str[TDM_PATH_LEN];
1799                 static int i;
1800                 snprintf(str, TDM_PATH_LEN, "target_window_%d_%03d",
1801                                  private_output->index, i++);
1802                 tdm_helper_dump_buffer_str(target_buffer, tdm_debug_dump_dir, str);
1803                 /* LCOV_EXCL_STOP */
1804         }
1805
1806         func_output = &private_display->func_output;
1807
1808         if (!func_output->output_hwc_set_client_target_buffer) {
1809                 /* LCOV_EXCL_START */
1810                 _pthread_mutex_unlock(&private_display->lock);
1811                 TDM_ERR("not implemented!!");
1812                 return TDM_ERROR_NOT_IMPLEMENTED;
1813                 /* LCOV_EXCL_STOP */
1814         }
1815
1816         /* dump buffer */
1817         if (tdm_dump_enable)
1818         /* LCOV_EXCL_START */
1819                 _tdm_target_window_dump_buffer((tdm_private_output *)output, target_buffer);
1820         /* LCOV_EXCL_STOP */
1821
1822         if (num_wnds == 0) {
1823                 ret = func_output->output_hwc_set_client_target_buffer(private_output->output_backend, target_buffer,
1824                                         damage, NULL, 0);
1825
1826                 _pthread_mutex_unlock(&private_display->lock);
1827
1828                 return ret;
1829         }
1830
1831         composited_wnds_backend = calloc(num_wnds, sizeof(tdm_hwc_window *));
1832         if (!composited_wnds_backend) {
1833                 /* LCOV_EXCL_START */
1834                 _pthread_mutex_unlock(&private_display->lock);
1835                 return TDM_ERROR_OUT_OF_MEMORY;
1836                 /* LCOV_EXCL_STOP */
1837         }
1838
1839         composited_wnds_frontend = (tdm_private_hwc_window **)composited_wnds;
1840
1841         for (i = 0; i < num_wnds; i++)
1842                 composited_wnds_backend[i] = composited_wnds_frontend[i]->hwc_window_backend;
1843
1844         ret = func_output->output_hwc_set_client_target_buffer(private_output->output_backend, target_buffer,
1845                         damage, composited_wnds_backend, num_wnds);
1846
1847         free(composited_wnds_backend);
1848
1849         _pthread_mutex_unlock(&private_display->lock);
1850
1851         return ret;
1852 }
1853
1854 tdm_error
1855 tdm_output_hwc_get_video_supported_formats(tdm_output *output, const tbm_format **formats,
1856                                                                 int *count)
1857 {
1858         tdm_func_output *func_output;
1859         OUTPUT_FUNC_ENTRY();
1860
1861         TDM_RETURN_VAL_IF_FAIL(formats != NULL, TDM_ERROR_INVALID_PARAMETER);
1862         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
1863
1864         _pthread_mutex_lock(&private_display->lock);
1865
1866         func_output = &private_display->func_output;
1867
1868         if (!func_output->output_hwc_get_video_supported_formats) {
1869                 /* LCOV_EXCL_START */
1870                 _pthread_mutex_unlock(&private_display->lock);
1871                 TDM_ERR("not implemented!!");
1872                 return TDM_ERROR_NOT_IMPLEMENTED;
1873                 /* LCOV_EXCL_STOP */
1874         }
1875
1876         ret = func_output->output_hwc_get_video_supported_formats(
1877                                                                 private_output->output_backend, formats, count);
1878
1879         _pthread_mutex_unlock(&private_display->lock);
1880
1881         return ret;
1882 }
1883
1884 INTERN void
1885 tdm_output_call_change_handler_internal(tdm_private_output *private_output,
1886                                                                                 struct list_head *change_handler_list,
1887                                                                                 tdm_output_change_type type,
1888                                                                                 tdm_value value,
1889                                                                                 int no_check_thread_id)
1890 {
1891         tdm_private_display *private_display;
1892         tdm_private_change_handler *change_handler = NULL;
1893
1894         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
1895         TDM_RETURN_IF_FAIL(private_output);
1896
1897         private_display = private_output->private_display;
1898         if (!tdm_thread_in_display_thread(syscall(SYS_gettid))) {
1899                 if (type & TDM_OUTPUT_CHANGE_CONNECTION)
1900                         TDM_INFO("output(%d) changed: %s (%d)",
1901                                          private_output->pipe, tdm_status_str(value.u32), value.u32);
1902                 if (type & TDM_OUTPUT_CHANGE_DPMS)
1903                         TDM_INFO("output(%d) changed: dpms %s (%d)",
1904                                          private_output->pipe, tdm_dpms_str(value.u32), value.u32);
1905         }
1906
1907         if (LIST_IS_EMPTY(change_handler_list))
1908                 return;
1909
1910         LIST_FOR_EACH_ENTRY(change_handler, change_handler_list, link) {
1911                 if (!no_check_thread_id && change_handler->owner_tid != syscall(SYS_gettid))
1912                         TDM_NEVER_GET_HERE();
1913
1914                 _pthread_mutex_unlock(&private_display->lock);
1915                 change_handler->func(private_output, type,
1916                                                          value, change_handler->user_data);
1917                 _pthread_mutex_lock(&private_display->lock);
1918         }
1919 }
1920
1921 static int
1922 _is_hwc_output_still_existed(tdm_private_output *private_output)
1923 {
1924         tdm_private_display *dpy;
1925         tdm_private_output *o = NULL;
1926
1927         dpy = tdm_display_init(NULL);
1928         TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_OPERATION_FAILED);
1929
1930         LIST_FOR_EACH_ENTRY(o, &dpy->output_list, link) {
1931                 if (!(o->caps.capabilities & TDM_OUTPUT_CAPABILITY_HWC))
1932                         continue;
1933
1934                 if (o == private_output)
1935                         goto exist;
1936         }
1937
1938         tdm_display_deinit(dpy);
1939         return 0;
1940
1941 exist:
1942         tdm_display_deinit(dpy);
1943         return 1;
1944 }
1945
1946 /* gets called on behalf of the ecore-main-loop thread */
1947 INTERN tdm_error
1948 tdm_output_cb_need_validate(tdm_private_output *private_output)
1949 {
1950         TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_INVALID_PARAMETER);
1951
1952         /* as we get 'private_output' within an event, an output this 'private_output'
1953          * points to can be destroyed already */
1954         if (!_is_hwc_output_still_existed(private_output))
1955                 return TDM_ERROR_NONE;
1956
1957         TDM_INFO("tdm-backend asks for revalidation for the output:%p.", private_output);
1958
1959         if (private_output->need_validate.hndl)
1960                 private_output->need_validate.hndl((tdm_output*)private_output);
1961
1962         return TDM_ERROR_NONE;
1963 }
1964
1965 /* gets called on behalf of the tdm-thread */
1966 static tdm_error
1967 _need_validate_handler(int fd, tdm_event_loop_mask mask, void *user_data)
1968 {
1969         tdm_thread_cb_need_validate ev;
1970         tdm_private_output *private_output;
1971         tdm_error ret;
1972         uint64_t value;
1973
1974         private_output = (tdm_private_output *)user_data;
1975
1976         if (read(private_output->need_validate.event_fd, &value, sizeof(value)) < 0) {
1977                 TDM_ERR("error while trying to read from a need_validate.event_fd fd.");
1978                 return TDM_ERROR_OPERATION_FAILED;
1979         }
1980
1981         ev.base.type = TDM_THREAD_CB_NEED_VALIDATE;
1982         ev.base.length = sizeof ev;
1983         ev.o = private_output;
1984
1985         ret = tdm_thread_send_cb(private_output->private_display->private_loop, &ev.base);
1986         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
1987
1988         TDM_INFO("tdm-thread: get a 'need to revalidate' event for the ouptut:%p.", private_output);
1989
1990         /* who cares about this? */
1991         return TDM_ERROR_NONE;
1992 }
1993
1994 INTERN tdm_error
1995 tdm_output_need_validate_event_init(tdm_output *output)
1996 {
1997         int fd;
1998
1999         OUTPUT_FUNC_ENTRY();
2000
2001         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED);
2002
2003         if (!(private_output->caps.capabilities & TDM_OUTPUT_CAPABILITY_HWC)) {
2004                 TDM_ERR("output(%p) not support HWC", private_output);
2005                 return TDM_ERROR_BAD_REQUEST;
2006         }
2007
2008         /* build in eventfd fds into event_loop listened & handled by the tdm-thread */
2009         fd = eventfd(0, 0);
2010         TDM_WARNING_IF_FAIL(fd >= 0);
2011
2012         private_output->need_validate.event_source = tdm_event_loop_add_fd_handler(private_display,
2013                         fd,     TDM_EVENT_LOOP_READABLE, _need_validate_handler, private_output, &ret);
2014         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
2015
2016         private_output->need_validate.event_fd = fd;
2017
2018         TDM_INFO("register an output:%p for the revalidation, event_fd:%d.", private_output, fd);
2019
2020         return ret;
2021 }
2022
2023 INTERN tdm_error
2024 tdm_output_choose_commit_per_vblank_mode(tdm_private_output *private_output, int mode)
2025 {
2026         if (!private_output)
2027                 return TDM_ERROR_INVALID_PARAMETER;
2028
2029         if (mode < 0 || mode > 2)
2030                 return TDM_ERROR_INVALID_PARAMETER;
2031
2032         private_output->commit_per_vblank = mode;
2033
2034         if (private_output->commit_per_vblank == 0)
2035                 TDM_INFO("commit per vblank: disable");
2036         else if (private_output->commit_per_vblank == 1)
2037                 TDM_INFO("commit per vblank: enable (1 layer)");
2038         else if (private_output->commit_per_vblank == 2)
2039                 TDM_INFO("commit per vblank: enable (previous commit)");
2040
2041         return TDM_ERROR_NONE;
2042 }