hwc_window: add the buffer dump
[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                 return TDM_ERROR_NONE;
304         }
305
306         *count = 0;
307         LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link)
308         (*count)++;
309         if (*count == 0) {
310                 _pthread_mutex_unlock(&private_display->lock);
311                 return TDM_ERROR_NONE;
312         }
313
314         _pthread_mutex_unlock(&private_display->lock);
315
316         return ret;
317 }
318
319
320 EXTERN tdm_layer *
321 tdm_output_get_layer(tdm_output *output, int index, tdm_error *error)
322 {
323         tdm_private_layer *private_layer = NULL;
324
325         OUTPUT_FUNC_ENTRY_ERROR();
326
327         _pthread_mutex_lock(&private_display->lock);
328
329         if (error)
330                 *error = TDM_ERROR_NONE;
331
332         if (private_display->hwc_enable) {
333                 *error = TDM_ERROR_INVALID_PARAMETER;
334                 return NULL;
335         }
336
337         LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
338                 if (private_layer->index == index) {
339                         _pthread_mutex_unlock(&private_display->lock);
340                         return private_layer;
341                 }
342         }
343
344         _pthread_mutex_unlock(&private_display->lock);
345
346         return NULL;
347 }
348
349 EXTERN tdm_error
350 tdm_output_get_available_properties(tdm_output *output, const tdm_prop **props,
351                                                                         int *count)
352 {
353         OUTPUT_FUNC_ENTRY();
354
355         TDM_RETURN_VAL_IF_FAIL(props != NULL, TDM_ERROR_INVALID_PARAMETER);
356         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
357
358         _pthread_mutex_lock(&private_display->lock);
359
360         *props = (const tdm_prop *)private_output->caps.props;
361         *count = private_output->caps.prop_count;
362
363         _pthread_mutex_unlock(&private_display->lock);
364
365         return ret;
366 }
367
368 EXTERN tdm_error
369 tdm_output_get_available_modes(tdm_output *output,
370                                                            const tdm_output_mode **modes, int *count)
371 {
372         OUTPUT_FUNC_ENTRY();
373
374         TDM_RETURN_VAL_IF_FAIL(modes != NULL, TDM_ERROR_INVALID_PARAMETER);
375         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
376
377         _pthread_mutex_lock(&private_display->lock);
378
379         *modes = (const tdm_output_mode *)private_output->caps.modes;
380         *count = private_output->caps.mode_count;
381
382         _pthread_mutex_unlock(&private_display->lock);
383
384         return ret;
385 }
386
387 EXTERN tdm_error
388 tdm_output_get_available_size(tdm_output *output, int *min_w, int *min_h,
389                                                           int *max_w, int *max_h, int *preferred_align)
390 {
391         OUTPUT_FUNC_ENTRY();
392
393         _pthread_mutex_lock(&private_display->lock);
394
395         if (min_w)
396                 *min_w = TDM_FRONT_VALUE(private_output->caps.min_w);
397         if (min_h)
398                 *min_h = TDM_FRONT_VALUE(private_output->caps.min_h);
399         if (max_w)
400                 *max_w = TDM_FRONT_VALUE(private_output->caps.max_w);
401         if (max_h)
402                 *max_h = TDM_FRONT_VALUE(private_output->caps.max_h);
403         if (preferred_align)
404                 *preferred_align = TDM_FRONT_VALUE(private_output->caps.preferred_align);
405
406         _pthread_mutex_unlock(&private_display->lock);
407
408         return ret;
409 }
410
411 EXTERN tdm_error
412 tdm_output_get_cursor_available_size(tdm_output *output, int *min_w, int *min_h,
413                                                                          int *max_w, int *max_h, int *preferred_align)
414 {
415         OUTPUT_FUNC_ENTRY();
416
417         _pthread_mutex_lock(&private_display->lock);
418
419         if (!tdm_display_check_module_abi(private_display, 1, 5)) {
420
421                 if (min_w)
422                         *min_w = -1;
423                 if (min_h)
424                         *min_h = -1;
425                 if (max_w)
426                         *max_w = -1;
427                 if (max_h)
428                         *max_h = -1;
429                 if (preferred_align)
430                         *preferred_align = -1;
431
432                 _pthread_mutex_unlock(&private_display->lock);
433
434                 return TDM_ERROR_BAD_MODULE;
435         }
436
437         if (min_w)
438                 *min_w = TDM_FRONT_VALUE(private_output->caps.cursor_min_w);
439         if (min_h)
440                 *min_h = TDM_FRONT_VALUE(private_output->caps.cursor_min_h);
441         if (max_w)
442                 *max_w = TDM_FRONT_VALUE(private_output->caps.cursor_max_w);
443         if (max_h)
444                 *max_h = TDM_FRONT_VALUE(private_output->caps.cursor_max_h);
445         if (preferred_align)
446                 *preferred_align = TDM_FRONT_VALUE(private_output->caps.cursor_preferred_align);
447
448         _pthread_mutex_unlock(&private_display->lock);
449
450         return ret;
451 }
452
453 EXTERN tdm_error
454 tdm_output_get_physical_size(tdm_output *output, unsigned int *mmWidth,
455                                                          unsigned int *mmHeight)
456 {
457         OUTPUT_FUNC_ENTRY();
458
459         _pthread_mutex_lock(&private_display->lock);
460
461         if (mmWidth)
462                 *mmWidth = private_output->caps.mmWidth;
463         if (mmHeight)
464                 *mmHeight = private_output->caps.mmHeight;
465
466         _pthread_mutex_unlock(&private_display->lock);
467
468         return ret;
469 }
470
471 EXTERN tdm_error
472 tdm_output_get_subpixel(tdm_output *output, unsigned int *subpixel)
473 {
474         OUTPUT_FUNC_ENTRY();
475         TDM_RETURN_VAL_IF_FAIL(subpixel != NULL, TDM_ERROR_INVALID_PARAMETER);
476
477         _pthread_mutex_lock(&private_display->lock);
478
479         *subpixel = private_output->caps.subpixel;
480
481         _pthread_mutex_unlock(&private_display->lock);
482
483         return ret;
484 }
485
486 EXTERN tdm_error
487 tdm_output_get_pipe(tdm_output *output, unsigned int *pipe)
488 {
489         OUTPUT_FUNC_ENTRY();
490         TDM_RETURN_VAL_IF_FAIL(pipe != NULL, TDM_ERROR_INVALID_PARAMETER);
491
492         _pthread_mutex_lock(&private_display->lock);
493
494         *pipe = private_output->pipe;
495
496         _pthread_mutex_unlock(&private_display->lock);
497
498         return ret;
499 }
500
501 EXTERN tdm_error
502 tdm_output_get_primary_index(tdm_output *output, int *index)
503 {
504         tdm_private_layer *private_layer = NULL;
505
506         OUTPUT_FUNC_ENTRY();
507         TDM_RETURN_VAL_IF_FAIL(index != NULL, TDM_ERROR_INVALID_PARAMETER);
508
509         _pthread_mutex_lock(&private_display->lock);
510
511         LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
512                 if (private_layer->caps.capabilities & TDM_LAYER_CAPABILITY_PRIMARY) {
513                         *index = private_layer->index;
514                         break;
515                 }
516         }
517
518         _pthread_mutex_unlock(&private_display->lock);
519
520         return ret;
521 }
522
523 EXTERN tdm_error
524 tdm_output_set_property(tdm_output *output, unsigned int id, tdm_value value)
525 {
526         tdm_func_output *func_output;
527         OUTPUT_FUNC_ENTRY();
528
529         _pthread_mutex_lock(&private_display->lock);
530
531         func_output = &private_display->func_output;
532
533         if (!func_output->output_set_property) {
534                 _pthread_mutex_unlock(&private_display->lock);
535                 TDM_ERR("not implemented!!");
536                 return TDM_ERROR_NOT_IMPLEMENTED;
537         }
538
539         ret = func_output->output_set_property(private_output->output_backend, id,
540                                                                                    value);
541
542         _pthread_mutex_unlock(&private_display->lock);
543
544         return ret;
545 }
546
547 EXTERN tdm_error
548 tdm_output_get_property(tdm_output *output, unsigned int id, tdm_value *value)
549 {
550         tdm_func_output *func_output;
551         OUTPUT_FUNC_ENTRY();
552
553         TDM_RETURN_VAL_IF_FAIL(value != NULL, TDM_ERROR_INVALID_PARAMETER);
554
555         _pthread_mutex_lock(&private_display->lock);
556
557         func_output = &private_display->func_output;
558
559         if (!func_output->output_get_property) {
560                 _pthread_mutex_unlock(&private_display->lock);
561                 TDM_ERR("not implemented!!");
562                 return TDM_ERROR_NOT_IMPLEMENTED;
563         }
564
565         ret = func_output->output_get_property(private_output->output_backend, id,
566                                                                                    value);
567
568         _pthread_mutex_unlock(&private_display->lock);
569
570         return ret;
571 }
572
573 INTERN void
574 tdm_output_cb_vblank(tdm_output *output_backend, unsigned int sequence,
575                                          unsigned int tv_sec, unsigned int tv_usec, void *user_data)
576 {
577         tdm_private_vblank_handler *vblank_handler = user_data;
578         tdm_private_vblank_handler *v = NULL, *vv = NULL;
579         tdm_private_output *private_output;
580         tdm_private_display *private_display;
581         struct list_head clone_list;
582         int interval, sync;
583         pid_t tid = syscall(SYS_gettid);
584
585         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
586         TDM_RETURN_IF_FAIL(vblank_handler);
587
588         private_output = vblank_handler->private_output;
589         private_display = private_output->private_display;
590
591         if (vblank_handler->owner_tid != tid) {
592                 tdm_thread_cb_output_vblank output_vblank;
593                 tdm_error ret;
594
595                 output_vblank.base.type = TDM_THREAD_CB_OUTPUT_VBLANK;
596                 output_vblank.base.length = sizeof output_vblank;
597                 output_vblank.output_stamp = vblank_handler->private_output->stamp;
598                 output_vblank.sequence = sequence;
599                 output_vblank.tv_sec = tv_sec;
600                 output_vblank.tv_usec = tv_usec;
601                 output_vblank.user_data = user_data;
602
603                 ret = tdm_thread_send_cb(private_display->private_loop, &output_vblank.base);
604                 TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
605
606                 return;
607         }
608
609         if (vblank_handler->owner_tid != tid)
610                 TDM_NEVER_GET_HERE();
611
612         interval = vblank_handler->interval;
613         sync = vblank_handler->sync;
614
615         LIST_INITHEAD(&clone_list);
616
617         LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_handler_list, link) {
618                 if (v->interval != interval || v->sync != sync || v->owner_tid != tid)
619                         continue;
620
621                 LIST_DEL(&v->link);
622                 LIST_ADDTAIL(&v->link, &clone_list);
623         }
624
625         if (tdm_debug_module & TDM_DEBUG_COMMIT)
626                 TDM_INFO("----------------------------------------- output(%d) got vblank", private_output->pipe);
627
628         _pthread_mutex_unlock(&private_display->lock);
629         LIST_FOR_EACH_ENTRY_SAFE(v, vv, &clone_list, link) {
630                 if (tdm_debug_module & TDM_DEBUG_COMMIT)
631                         TDM_INFO("handler(%p)", v);
632
633                 if (v->func)
634                         v->func(v->private_output, sequence, tv_sec, tv_usec, v->user_data);
635                 LIST_DEL(&v->link);
636                 free(v);
637         }
638         _pthread_mutex_lock(&private_display->lock);
639
640         if (tdm_debug_module & TDM_DEBUG_COMMIT)
641                 TDM_INFO("-----------------------------------------...");
642 }
643
644 INTERN void
645 tdm_output_cb_commit(tdm_output *output_backend, unsigned int sequence,
646                                          unsigned int tv_sec, unsigned int tv_usec, void *user_data)
647 {
648         tdm_private_output_commit_handler *output_commit_handler = user_data;
649         tdm_private_display *private_display;
650         tdm_private_output *private_output;
651         tdm_private_layer *private_layer = NULL;
652
653         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
654
655         if (!output_commit_handler)
656                 return;
657
658         private_output = output_commit_handler->private_output;
659         private_display = private_output->private_display;
660
661         if (output_commit_handler->owner_tid != syscall(SYS_gettid)) {
662                 tdm_thread_cb_output_commit output_commit;
663                 tdm_error ret;
664
665                 output_commit.base.type = TDM_THREAD_CB_OUTPUT_COMMIT;
666                 output_commit.base.length = sizeof output_commit;
667                 output_commit.output_stamp = private_output->stamp;
668                 output_commit.sequence = sequence;
669                 output_commit.tv_sec = tv_sec;
670                 output_commit.tv_usec = tv_usec;
671                 output_commit.user_data = user_data;
672
673                 ret = tdm_thread_send_cb(private_display->private_loop, &output_commit.base);
674                 TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
675
676                 return;
677         }
678
679         if (tdm_debug_module & TDM_DEBUG_COMMIT) {
680                 TDM_INFO("----------------------------------------- output(%d) committed", private_output->pipe);
681                 TDM_INFO("handler(%p)", output_commit_handler);
682         }
683
684         if (private_display->commit_type == TDM_COMMIT_TYPE_OUTPUT) {
685                 /* In case of layer commit, the below will be handled in the layer commit callback */
686                 LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
687                         if (private_layer->committed_buffer)
688                                 tdm_layer_committed(private_layer, &private_layer->committed_buffer);
689                 }
690         }
691
692         if (output_commit_handler->func) {
693                 _pthread_mutex_unlock(&private_display->lock);
694                 output_commit_handler->func(private_output, sequence,
695                                                                         tv_sec, tv_usec, output_commit_handler->user_data);
696                 _pthread_mutex_lock(&private_display->lock);
697         }
698
699         LIST_DEL(&output_commit_handler->link);
700         free(output_commit_handler);
701
702         if (tdm_debug_module & TDM_DEBUG_COMMIT)
703                 TDM_INFO("-----------------------------------------...");
704 }
705
706 /* add_front: To distinguish between the user vblank handlers and the layer
707  *            commit vblank handlers. The layer commit handlers will be called
708  *            before calling the user vblank handlers.
709  */
710 static tdm_error
711 _tdm_output_wait_vblank(tdm_output *output, int interval, int sync,
712                                                 tdm_output_vblank_handler func, void *user_data,
713                                                 unsigned int add_front)
714 {
715         tdm_func_output *func_output;
716         tdm_private_vblank_handler *vblank_handler = NULL, *v = NULL;
717         unsigned int skip_request = 0;
718         pid_t tid = syscall(SYS_gettid);
719
720         OUTPUT_FUNC_ENTRY();
721
722         func_output = &private_display->func_output;
723
724         /* interval SHOULD be at least 1 */
725         if (interval <= 0)
726                 interval = 1;
727
728         if (!func_output->output_wait_vblank) {
729                 TDM_ERR("not implemented!!");
730                 return TDM_ERROR_NOT_IMPLEMENTED;
731         }
732
733         if (!private_output->regist_vblank_cb) {
734                 private_output->regist_vblank_cb = 1;
735                 ret = func_output->output_set_vblank_handler(private_output->output_backend,
736                                 tdm_output_cb_vblank);
737         }
738
739         vblank_handler = calloc(1, sizeof(tdm_private_vblank_handler));
740         if (!vblank_handler) {
741                 TDM_ERR("failed: alloc memory");
742                 return TDM_ERROR_OUT_OF_MEMORY;
743         }
744
745         if (tdm_debug_module & TDM_DEBUG_COMMIT)
746                 TDM_INFO("output(%d) wait_vblank: handler(%p)", private_output->pipe, vblank_handler);
747
748         LIST_FOR_EACH_ENTRY(v, &private_output->vblank_handler_list, link) {
749                 if (v->interval == interval && v->sync == sync && v->owner_tid == tid) {
750                         skip_request = 1;
751                         break;
752                 }
753         }
754
755         if (add_front)
756                 LIST_ADD(&vblank_handler->link, &private_output->vblank_handler_list);
757         else
758                 LIST_ADDTAIL(&vblank_handler->link, &private_output->vblank_handler_list);
759
760         vblank_handler->private_output = private_output;
761         vblank_handler->interval = interval;
762         vblank_handler->sync = sync;
763         vblank_handler->func = func;
764         vblank_handler->user_data = user_data;
765         vblank_handler->owner_tid = tid;
766
767         /* If there is the previous request, we can skip to call output_wait_vblank() */
768         if (!skip_request) {
769                 ret = func_output->output_wait_vblank(private_output->output_backend, interval,
770                                                                                           sync, vblank_handler);
771                 TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, wait_failed);
772
773                 if (tdm_debug_module & TDM_DEBUG_COMMIT)
774                         TDM_INFO("output(%d) backend wait_vblank", private_output->pipe);
775         }
776
777         return ret;
778
779 wait_failed:
780         if (vblank_handler) {
781                 LIST_DEL(&vblank_handler->link);
782                 free(vblank_handler);
783         }
784         return ret;
785 }
786
787 EXTERN tdm_error
788 tdm_output_wait_vblank(tdm_output *output, int interval, int sync,
789                                            tdm_output_vblank_handler func, void *user_data)
790 {
791         OUTPUT_FUNC_ENTRY();
792
793         _pthread_mutex_lock(&private_display->lock);
794
795         if (private_output->current_dpms_value > TDM_OUTPUT_DPMS_ON) {
796                 TDM_WRN("output(%d) dpms: %s", private_output->pipe,
797                                 tdm_dpms_str(private_output->current_dpms_value));
798                 _pthread_mutex_unlock(&private_display->lock);
799                 return TDM_ERROR_DPMS_OFF;
800         }
801
802         ret = _tdm_output_wait_vblank(output, interval, sync, func, user_data, 0);
803
804         _pthread_mutex_unlock(&private_display->lock);
805
806         return ret;
807 }
808
809 EXTERN tdm_error
810 tdm_output_wait_vblank_add_front(tdm_output *output, int interval, int sync,
811                                                                  tdm_output_vblank_handler func, void *user_data)
812 {
813         OUTPUT_FUNC_ENTRY();
814
815         _pthread_mutex_lock(&private_display->lock);
816
817         if (private_output->current_dpms_value > TDM_OUTPUT_DPMS_ON) {
818                 TDM_WRN("output(%d) dpms: %s", private_output->pipe,
819                                 tdm_dpms_str(private_output->current_dpms_value));
820                 _pthread_mutex_unlock(&private_display->lock);
821                 return TDM_ERROR_DPMS_OFF;
822         }
823
824         ret = _tdm_output_wait_vblank(output, interval, sync, func, user_data, 1);
825
826         _pthread_mutex_unlock(&private_display->lock);
827
828         return ret;
829 }
830
831 INTERN void
832 tdm_output_remove_vblank_handler_internal(tdm_output *output, tdm_output_vblank_handler func, void *user_data)
833 {
834         tdm_private_output *private_output = (tdm_private_output*)output;
835         tdm_private_vblank_handler *v = NULL;
836
837         TDM_RETURN_IF_FAIL(private_output != NULL);
838
839         LIST_FOR_EACH_ENTRY(v, &private_output->vblank_handler_list, link) {
840                 if (v->func == func && v->user_data == user_data) {
841                         /* only set func & user_data to NULL. It will be freed when an event occurs */
842                         v->func = NULL;
843                         v->user_data = NULL;
844                         break;
845                 }
846         }
847 }
848
849 INTERN void
850 tdm_output_remove_commit_handler_internal(tdm_output *output, tdm_output_commit_handler func, void *user_data)
851 {
852         tdm_private_output *private_output = (tdm_private_output*)output;
853         tdm_private_output_commit_handler *c = NULL;
854
855         TDM_RETURN_IF_FAIL(private_output != NULL);
856
857         LIST_FOR_EACH_ENTRY(c, &private_output->output_commit_handler_list, link) {
858                 if (c->func == func && c->user_data == user_data) {
859                         /* only set func & user_data to NULL. It will be freed when an event occurs */
860                         c->func = NULL;
861                         c->user_data = NULL;
862                         break;
863                 }
864         }
865 }
866
867 EXTERN tdm_error
868 tdm_output_remove_vblank_handler(tdm_output *output, tdm_output_vblank_handler func, void *user_data)
869 {
870         OUTPUT_FUNC_ENTRY();
871
872         _pthread_mutex_lock(&private_display->lock);
873
874         tdm_output_remove_vblank_handler_internal(output, func, user_data);
875
876         _pthread_mutex_unlock(&private_display->lock);
877
878         return ret;
879 }
880
881 EXTERN tdm_error
882 tdm_output_remove_commit_handler(tdm_output *output, tdm_output_commit_handler func, void *user_data)
883 {
884         OUTPUT_FUNC_ENTRY();
885
886         _pthread_mutex_lock(&private_display->lock);
887
888         tdm_output_remove_commit_handler_internal(output, func, user_data);
889
890         _pthread_mutex_unlock(&private_display->lock);
891
892         return ret;
893 }
894
895 INTERN tdm_error
896 tdm_output_commit_internal(tdm_output *output, int sync, tdm_output_commit_handler func, void *user_data)
897 {
898         tdm_func_output *func_output;
899         tdm_private_output_commit_handler *output_commit_handler = NULL;
900         tdm_private_layer *private_layer = NULL;
901         tdm_output_dpms dpms_value = TDM_OUTPUT_DPMS_ON;
902
903         OUTPUT_FUNC_ENTRY();
904
905         func_output = &private_display->func_output;
906
907         if (!func_output->output_commit) {
908                 TDM_ERR("not implemented!!");
909                 return TDM_ERROR_NOT_IMPLEMENTED;
910         }
911
912         /* TODO: this is ugly. But before using tdm_output_get_dpms_internal, we have
913          * to check if all backends's DPMS operation has no problem.
914          */
915         if (private_display->commit_per_vblank)
916                 tdm_output_get_dpms_internal(output, &dpms_value);
917         else
918                 dpms_value = private_output->current_dpms_value;
919
920         if (dpms_value == TDM_OUTPUT_DPMS_ON) {
921                 if (func) {
922                         if (!private_output->regist_commit_cb) {
923                                 private_output->regist_commit_cb = 1;
924                                 ret = func_output->output_set_commit_handler(private_output->output_backend,
925                                                         tdm_output_cb_commit);
926                                 TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed);
927                         }
928
929                         output_commit_handler = calloc(1, sizeof(tdm_private_output_commit_handler));
930                         if (!output_commit_handler) {
931                                 TDM_ERR("failed: alloc memory");
932                                 return TDM_ERROR_OUT_OF_MEMORY;
933                         }
934
935                         LIST_ADDTAIL(&output_commit_handler->link, &private_output->output_commit_handler_list);
936                         output_commit_handler->private_output = private_output;
937                         output_commit_handler->func = func;
938                         output_commit_handler->user_data = user_data;
939                         output_commit_handler->owner_tid = syscall(SYS_gettid);
940                 }
941
942                 ret = func_output->output_commit(private_output->output_backend, sync,
943                                 output_commit_handler);
944                 TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed);
945
946                 if (tdm_debug_module & TDM_DEBUG_COMMIT)
947                         TDM_INFO("output(%d) backend commit: handle(%p) func(%p) user_data(%p)",
948                                         private_output->pipe, output_commit_handler, func, user_data);
949         }
950
951         /* Even if DPMS is off, committed_buffer should be changed because it will be referred
952          * for tdm_layer_committed() function.
953          */
954         LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
955                 if (!private_layer->waiting_buffer)
956                         continue;
957
958                 private_layer->committed_buffer = private_layer->waiting_buffer;
959                 private_layer->waiting_buffer = NULL;
960                 if (tdm_debug_module & TDM_DEBUG_BUFFER)
961                         TDM_INFO("layer(%p) waiting_buffer(%p) committed_buffer(%p)",
962                                          private_layer, private_layer->waiting_buffer,
963                                          private_layer->committed_buffer->buffer);
964         }
965
966         if (dpms_value != TDM_OUTPUT_DPMS_ON) {
967                 TDM_WRN("TDM_OUTPUT_DPMS_OFF. Directly call commit handler instead of commit.");
968                 if (func)
969                         func(output, 0, 0, 0, user_data);
970         }
971
972         return ret;
973
974 commit_failed:
975         if (output_commit_handler) {
976                 LIST_DEL(&output_commit_handler->link);
977                 free(output_commit_handler);
978         }
979         return ret;
980 }
981
982 EXTERN tdm_error
983 tdm_output_commit(tdm_output *output, int sync, tdm_output_commit_handler func,
984                                   void *user_data)
985 {
986         OUTPUT_FUNC_ENTRY();
987
988         _pthread_mutex_lock(&private_display->lock);
989
990         if (private_display->commit_type == TDM_COMMIT_TYPE_NONE)
991                 private_display->commit_type = TDM_COMMIT_TYPE_OUTPUT;
992         else if (private_display->commit_type == TDM_COMMIT_TYPE_LAYER) {
993                 TDM_ERR("Can't supported. Use tdm_layer_commit");
994                 _pthread_mutex_unlock(&private_display->lock);
995                 return TDM_ERROR_BAD_REQUEST;
996         }
997
998         if (private_display->commit_per_vblank) {
999                 TDM_ERR("Use tdm_layer_commit");
1000                 _pthread_mutex_unlock(&private_display->lock);
1001                 return TDM_ERROR_BAD_REQUEST;
1002         }
1003
1004         if (private_output->current_dpms_value > TDM_OUTPUT_DPMS_ON) {
1005                 TDM_ERR("output(%d) dpms: %s", private_output->pipe,
1006                                 tdm_dpms_str(private_output->current_dpms_value));
1007                 _pthread_mutex_unlock(&private_display->lock);
1008                 return TDM_ERROR_DPMS_OFF;
1009         }
1010
1011         if (tdm_debug_module & TDM_DEBUG_COMMIT)
1012                 TDM_INFO("output(%d) commit", private_output->pipe);
1013
1014         ret = tdm_output_commit_internal(output, sync, func, user_data);
1015
1016         _pthread_mutex_unlock(&private_display->lock);
1017
1018         return ret;
1019 }
1020
1021 EXTERN tdm_error
1022 tdm_output_set_mode(tdm_output *output, const tdm_output_mode *mode)
1023 {
1024         tdm_func_output *func_output;
1025         OUTPUT_FUNC_ENTRY();
1026
1027         TDM_RETURN_VAL_IF_FAIL(mode != NULL, TDM_ERROR_INVALID_PARAMETER);
1028
1029         _pthread_mutex_lock(&private_display->lock);
1030
1031         func_output = &private_display->func_output;
1032
1033         if (!func_output->output_set_mode) {
1034                 _pthread_mutex_unlock(&private_display->lock);
1035                 TDM_ERR("not implemented!!");
1036                 return TDM_ERROR_NOT_IMPLEMENTED;
1037         }
1038
1039         ret = func_output->output_set_mode(private_output->output_backend, mode);
1040         if (ret == TDM_ERROR_NONE)
1041                 private_output->current_mode = mode;
1042         _pthread_mutex_unlock(&private_display->lock);
1043
1044         return ret;
1045 }
1046
1047 EXTERN tdm_error
1048 tdm_output_get_mode(tdm_output *output, const tdm_output_mode **mode)
1049 {
1050         OUTPUT_FUNC_ENTRY();
1051
1052         TDM_RETURN_VAL_IF_FAIL(mode != NULL, TDM_ERROR_INVALID_PARAMETER);
1053
1054         _pthread_mutex_lock(&private_display->lock);
1055
1056         *mode = private_output->current_mode;
1057
1058         _pthread_mutex_unlock(&private_display->lock);
1059
1060         return ret;
1061 }
1062
1063 static tdm_error
1064 _tdm_output_dpms_changed_timeout(void *user_data)
1065 {
1066         tdm_private_output *private_output = user_data;
1067         tdm_value value;
1068
1069         value.u32 = private_output->current_dpms_value;
1070         tdm_output_call_change_handler_internal(private_output,
1071                                                                                         &private_output->change_handler_list_sub,
1072                                                                                         TDM_OUTPUT_CHANGE_DPMS,
1073                                                                                         value, 0);
1074
1075         return TDM_ERROR_NONE;
1076 }
1077
1078 INTERN void
1079 tdm_output_cb_dpms(tdm_output *output_backend, tdm_output_dpms dpms, void *user_data)
1080 {
1081         tdm_private_display *private_display;
1082         tdm_private_output *private_output = user_data;
1083         tdm_value value;
1084
1085         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
1086         TDM_RETURN_IF_FAIL(private_output);
1087
1088         private_display = private_output->private_display;
1089
1090         if (!tdm_thread_in_display_thread(syscall(SYS_gettid))) {
1091                 tdm_thread_cb_output_dpms output_dpms;
1092                 tdm_error ret;
1093
1094                 _tdm_output_update(output_backend, user_data);
1095
1096                 output_dpms.base.type = TDM_THREAD_CB_OUTPUT_DPMS;
1097                 output_dpms.base.length = sizeof output_dpms;
1098                 output_dpms.output_stamp = private_output->stamp;
1099                 output_dpms.dpms = dpms;
1100                 output_dpms.user_data = user_data;
1101
1102                 value.u32 = dpms;
1103                 tdm_output_call_change_handler_internal(private_output,
1104                                                                                                 &private_output->change_handler_list_sub,
1105                                                                                                 TDM_OUTPUT_CHANGE_DPMS,
1106                                                                                                 value, 0);
1107
1108                 ret = tdm_thread_send_cb(private_display->private_loop, &output_dpms.base);
1109                 TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
1110
1111                 return;
1112         }
1113
1114         private_output->current_dpms_value = dpms;
1115
1116         TDM_INFO("output(%d) dpms %s", private_output->pipe, tdm_dpms_str(dpms));
1117
1118         value.u32 = dpms;
1119         tdm_output_call_change_handler_internal(private_output,
1120                                                                                         &private_output->change_handler_list_main,
1121                                                                                         TDM_OUTPUT_CHANGE_DPMS,
1122                                                                                         value, 0);
1123 }
1124
1125 EXTERN tdm_error
1126 tdm_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value)
1127 {
1128         tdm_func_output *func_output;
1129         OUTPUT_FUNC_ENTRY();
1130
1131         if (dpms_value > TDM_OUTPUT_DPMS_OFF)
1132                 dpms_value = TDM_OUTPUT_DPMS_OFF;
1133
1134         _pthread_mutex_lock(&private_display->lock);
1135
1136         if (private_output->current_dpms_value == dpms_value) {
1137                 _pthread_mutex_unlock(&private_display->lock);
1138                 return TDM_ERROR_NONE;
1139         }
1140
1141         /** Use timer to call the output change callback of the sub-thread.
1142          * The output change callback of tdm_server and tdm_vblank was called
1143          * in the main thread. And it made the multi thread issue. If we use
1144          * the timer, we can call the sub-thread's output change callback in
1145          * sub-thread.
1146          */
1147         if (!private_output->dpms_changed_timer) {
1148                 private_output->dpms_changed_timer =
1149                         tdm_event_loop_add_timer_handler(private_output->private_display,
1150                                                                                          _tdm_output_dpms_changed_timeout, private_output, NULL);
1151                 if (!private_output->dpms_changed_timer) {
1152                         TDM_ERR("can't create dpms timer!!");
1153                         _pthread_mutex_unlock(&private_display->lock);
1154                         return TDM_ERROR_OUT_OF_MEMORY;
1155                 }
1156         }
1157
1158         func_output = &private_display->func_output;
1159
1160         if (!func_output->output_set_dpms) {
1161                 _pthread_mutex_unlock(&private_display->lock);
1162                 private_output->current_dpms_value = dpms_value;
1163                 TDM_INFO("output(%d) dpms %s", private_output->pipe, tdm_dpms_str(dpms_value));
1164                 TDM_WRN("not implemented!!");
1165                 return TDM_ERROR_NONE;
1166         }
1167
1168         if (func_output->output_set_dpms_handler) {
1169                 if (!private_output->regist_dpms_cb) {
1170                         private_output->regist_dpms_cb = 1;
1171                         ret = func_output->output_set_dpms_handler(private_output->output_backend,
1172                                         tdm_output_cb_dpms, private_output);
1173                         if (ret != TDM_ERROR_NONE) {
1174                                 _pthread_mutex_unlock(&private_display->lock);
1175                                 TDM_ERR("Can't set the dpms handler!!");
1176                                 return ret;
1177                         }
1178                 }
1179         }
1180
1181         ret = func_output->output_set_dpms(private_output->output_backend, dpms_value);
1182
1183         if (ret == TDM_ERROR_NONE && !func_output->output_set_dpms_handler) {
1184                 tdm_value value;
1185
1186                 private_output->current_dpms_value = dpms_value;
1187                 TDM_INFO("output(%d) dpms %s", private_output->pipe, tdm_dpms_str(dpms_value));
1188
1189                 value.u32 = dpms_value;
1190                 tdm_output_call_change_handler_internal(private_output,
1191                                                                                                 &private_output->change_handler_list_main,
1192                                                                                                 TDM_OUTPUT_CHANGE_DPMS,
1193                                                                                                 value, 0);
1194
1195                 if (!LIST_IS_EMPTY(&private_output->change_handler_list_sub)) {
1196                         ret = tdm_event_loop_source_timer_update(private_output->dpms_changed_timer, 1);
1197                         if (ret != TDM_ERROR_NONE)
1198                                 TDM_NEVER_GET_HERE();
1199                 }
1200         }
1201
1202         _pthread_mutex_unlock(&private_display->lock);
1203
1204         return ret;
1205 }
1206
1207 INTERN tdm_error
1208 tdm_output_get_dpms_internal(tdm_output *output, tdm_output_dpms *dpms_value)
1209 {
1210         tdm_func_output *func_output;
1211         OUTPUT_FUNC_ENTRY();
1212
1213         TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_INVALID_PARAMETER);
1214
1215         func_output = &private_display->func_output;
1216
1217         if (!func_output->output_get_dpms) {
1218                 *dpms_value = private_output->current_dpms_value;
1219                 TDM_WRN("not implemented!!");
1220                 return TDM_ERROR_NONE;
1221         }
1222
1223         ret = func_output->output_get_dpms(private_output->output_backend, dpms_value);
1224         if (ret != TDM_ERROR_NONE) {
1225                 TDM_ERR("output_get_dpms failed");
1226                 *dpms_value = TDM_OUTPUT_DPMS_OFF;
1227         }
1228
1229         /* TODO: this is ugly. But we have to check if all backends's DPMS operation has no problem. */
1230         if (private_display->commit_per_vblank)
1231                 if (*dpms_value != private_output->current_dpms_value) {
1232                         private_output->current_dpms_value = *dpms_value;
1233                         TDM_ERR("output(%d) dpms changed suddenly: %s",
1234                                         private_output->pipe, tdm_dpms_str(*dpms_value));
1235                 }
1236
1237         return ret;
1238 }
1239
1240 EXTERN tdm_error
1241 tdm_output_get_dpms(tdm_output *output, tdm_output_dpms *dpms_value)
1242 {
1243         OUTPUT_FUNC_ENTRY();
1244
1245         TDM_RETURN_VAL_IF_FAIL(dpms_value != NULL, TDM_ERROR_INVALID_PARAMETER);
1246
1247         _pthread_mutex_lock(&private_display->lock);
1248
1249         ret = tdm_output_get_dpms_internal(output, dpms_value);
1250
1251         _pthread_mutex_unlock(&private_display->lock);
1252
1253         return ret;
1254 }
1255
1256 EXTERN tdm_capture *
1257 tdm_output_create_capture(tdm_output *output, tdm_error *error)
1258 {
1259         tdm_capture *capture = NULL;
1260
1261         OUTPUT_FUNC_ENTRY_ERROR();
1262
1263         _pthread_mutex_lock(&private_display->lock);
1264
1265         capture = (tdm_capture *)tdm_capture_create_output_internal(private_output, error);
1266
1267         _pthread_mutex_unlock(&private_display->lock);
1268
1269         return capture;
1270 }
1271
1272 EXTERN tdm_hwc_window *
1273 tdm_output_create_hwc_window(tdm_output *output, tdm_error *error)
1274 {
1275         tdm_hwc_window *hwc_window = NULL;
1276
1277         OUTPUT_FUNC_ENTRY_ERROR();
1278
1279         _pthread_mutex_lock(&private_display->lock);
1280
1281         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_display->hwc_enable, TDM_ERROR_BAD_REQUEST, NULL);
1282
1283         hwc_window = (tdm_hwc_window *)tdm_hwc_window_create_internal(private_output, error);
1284
1285         _pthread_mutex_unlock(&private_display->lock);
1286
1287         return hwc_window;
1288 }
1289
1290 EXTERN tdm_error
1291 tdm_output_destroy_hwc_window(tdm_output *output, tdm_hwc_window *hwc_window)
1292 {
1293         OUTPUT_FUNC_ENTRY();
1294
1295         _pthread_mutex_lock(&private_display->lock);
1296
1297         ret = tdm_hwc_window_destroy_internal(hwc_window);
1298
1299         _pthread_mutex_unlock(&private_display->lock);
1300
1301         return ret;
1302 }
1303
1304 EXTERN tdm_error
1305 tdm_output_validate(tdm_output *output, uint32_t *num_types)
1306 {
1307         tdm_func_output *func_output = NULL;
1308
1309         OUTPUT_FUNC_ENTRY();
1310
1311         TDM_RETURN_VAL_IF_FAIL(num_types != NULL, TDM_ERROR_INVALID_PARAMETER);
1312
1313         _pthread_mutex_lock(&private_display->lock);
1314
1315         func_output = &private_display->func_output;
1316
1317         if (!func_output->output_validate) {
1318                 _pthread_mutex_unlock(&private_display->lock);
1319                 TDM_ERR("not implemented!!");
1320                 return TDM_ERROR_NOT_IMPLEMENTED;
1321         }
1322
1323         ret = func_output->output_validate(private_output->output_backend, num_types);
1324
1325         _pthread_mutex_unlock(&private_display->lock);
1326
1327         return ret;
1328 }
1329
1330 EXTERN tdm_error
1331 tdm_output_get_changed_composition_types(tdm_output *output,
1332                                                                                  uint32_t *num_elements,
1333                                                                                  tdm_hwc_window **hwc_window,
1334                                                                                  tdm_hwc_window_composition_t *composition_types)
1335 {
1336         tdm_func_output *func_output = NULL;
1337         tdm_private_hwc_window * private_hwc_window = NULL;
1338         int i = 0;
1339
1340         OUTPUT_FUNC_ENTRY();
1341
1342         TDM_RETURN_VAL_IF_FAIL(num_elements != NULL, TDM_ERROR_INVALID_PARAMETER);
1343
1344         _pthread_mutex_lock(&private_display->lock);
1345
1346         func_output = &private_display->func_output;
1347
1348         if (!func_output->output_get_changed_composition_types) {
1349                 _pthread_mutex_unlock(&private_display->lock);
1350                 TDM_ERR("not implemented!!");
1351                 return TDM_ERROR_NOT_IMPLEMENTED;
1352         }
1353
1354         ret = func_output->output_get_changed_composition_types(private_output->output_backend,
1355                                                          num_elements, hwc_window, composition_types);
1356         TDM_RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
1357
1358         if (hwc_window == NULL || composition_types == NULL)
1359                 return TDM_ERROR_NONE;
1360
1361         for (i = 0; i < *num_elements; i++) {
1362
1363                 private_hwc_window = _tdm_output_find_private_hwc_window(private_output, hwc_window[i]);
1364
1365                 if (private_hwc_window == NULL) {
1366                         TDM_ERR("failed! This should never happen!");
1367                         func_output->output_destroy_hwc_window(private_output->output_backend, hwc_window[i]);
1368                         free(hwc_window);
1369                         free(composition_types);
1370                         num_elements = 0;
1371                         hwc_window = NULL;
1372                         composition_types = NULL;
1373                         _pthread_mutex_unlock(&private_display->lock);
1374                         return TDM_ERROR_OPERATION_FAILED;
1375                 }
1376
1377                 hwc_window[i] = (tdm_hwc_window*)private_hwc_window;
1378         }
1379
1380         _pthread_mutex_unlock(&private_display->lock);
1381
1382         return ret;
1383 }
1384
1385 tdm_error
1386 tdm_output_accept_changes(tdm_output *output)
1387 {
1388         tdm_func_output *func_output = NULL;
1389
1390         OUTPUT_FUNC_ENTRY();
1391
1392         _pthread_mutex_lock(&private_display->lock);
1393
1394         func_output = &private_display->func_output;
1395
1396         if (!func_output->output_validate) {
1397                 _pthread_mutex_unlock(&private_display->lock);
1398                 TDM_ERR("not implemented!!");
1399                 return TDM_ERROR_NOT_IMPLEMENTED;
1400         }
1401
1402         ret = func_output->output_accept_changes(private_output->output_backend);
1403
1404         _pthread_mutex_unlock(&private_display->lock);
1405
1406         return ret;
1407 }
1408
1409 tbm_surface_queue_h
1410 tdm_output_get_target_surface_queue(tdm_output *output, tdm_error *error)
1411 {
1412         tdm_func_output *func_output = NULL;
1413         tbm_surface_queue_h queue = NULL;
1414
1415         OUTPUT_FUNC_ENTRY_ERROR();
1416
1417         _pthread_mutex_lock(&private_display->lock);
1418
1419         func_output = &private_display->func_output;
1420
1421         if (!func_output->output_get_target_surface_queue) {
1422                 _pthread_mutex_unlock(&private_display->lock);
1423                 TDM_ERR("not implemented!!");
1424                 return NULL;
1425         }
1426
1427         queue = func_output->output_get_target_surface_queue(private_output->output_backend, error);
1428
1429         _pthread_mutex_unlock(&private_display->lock);
1430
1431         return queue;
1432 }
1433
1434 static void
1435 _tdm_target_window_dump_buffer(tdm_private_output *private_output, tbm_surface_h buffer)
1436 {
1437         unsigned int pipe;
1438         char fname[PATH_MAX];
1439
1440         pipe = private_output->pipe;
1441
1442         snprintf(fname, sizeof(fname), "tdm_%d_target_win", pipe);
1443
1444         tbm_surface_internal_dump_buffer(buffer, fname);
1445         TDM_DBG("%s dump excute", fname);
1446
1447         return;
1448 }
1449
1450 EXTERN tdm_error
1451 tdm_output_set_client_target_buffer(tdm_output *output, tbm_surface_h buffer,
1452                                                                         tdm_hwc_region damage)
1453 {
1454         tdm_func_output *func_output = NULL;
1455
1456         OUTPUT_FUNC_ENTRY();
1457
1458         _pthread_mutex_lock(&private_display->lock);
1459
1460         if (tdm_debug_dump & TDM_DUMP_FLAG_WINDOW) {
1461                 char str[TDM_PATH_LEN];
1462                 static int i;
1463                 snprintf(str, TDM_PATH_LEN, "target_window_%d_%03d",
1464                                  private_output->index, i++);
1465                 tdm_helper_dump_buffer_str(buffer, tdm_debug_dump_dir, str);
1466         }
1467
1468         func_output = &private_display->func_output;
1469
1470         if (!func_output->output_set_client_target_buffer) {
1471                 _pthread_mutex_unlock(&private_display->lock);
1472                 TDM_ERR("not implemented!!");
1473                 return TDM_ERROR_NOT_IMPLEMENTED;
1474         }
1475
1476         /* dump buffer */
1477         if (tdm_dump_enable)
1478                 _tdm_target_window_dump_buffer((tdm_private_output *)output, buffer);
1479
1480         ret = func_output->output_set_client_target_buffer(private_output->output_backend, buffer, damage);
1481
1482         _pthread_mutex_unlock(&private_display->lock);
1483
1484         return ret;
1485 }
1486
1487 INTERN void
1488 tdm_output_call_change_handler_internal(tdm_private_output *private_output,
1489                                                                                 struct list_head *change_handler_list,
1490                                                                                 tdm_output_change_type type,
1491                                                                                 tdm_value value,
1492                                                                                 int no_check_thread_id)
1493 {
1494         tdm_private_display *private_display;
1495         tdm_private_change_handler *change_handler = NULL;
1496
1497         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
1498         TDM_RETURN_IF_FAIL(private_output);
1499
1500         private_display = private_output->private_display;
1501         if (!tdm_thread_in_display_thread(syscall(SYS_gettid))) {
1502                 if (type & TDM_OUTPUT_CHANGE_CONNECTION)
1503                         TDM_INFO("output(%d) changed: %s (%d)",
1504                                          private_output->pipe, tdm_status_str(value.u32), value.u32);
1505                 if (type & TDM_OUTPUT_CHANGE_DPMS)
1506                         TDM_INFO("output(%d) changed: dpms %s (%d)",
1507                                          private_output->pipe, tdm_dpms_str(value.u32), value.u32);
1508         }
1509
1510         if (LIST_IS_EMPTY(change_handler_list))
1511                 return;
1512
1513         LIST_FOR_EACH_ENTRY(change_handler, change_handler_list, link) {
1514                 if (!no_check_thread_id && change_handler->owner_tid != syscall(SYS_gettid))
1515                         TDM_NEVER_GET_HERE();
1516
1517                 _pthread_mutex_unlock(&private_display->lock);
1518                 change_handler->func(private_output, type,
1519                                                          value, change_handler->user_data);
1520                 _pthread_mutex_lock(&private_display->lock);
1521         }
1522 }