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