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