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