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