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