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