tdm_hwc: add fence api and backend interface
[platform/core/uifw/libtdm.git] / src / tdm_hwc.c
1 /**************************************************************************
2  *
3  * libtdm
4  *
5  * Copyright 2018 Samsung Electronics co., Ltd. All Rights Reserved.
6  *
7  * Contact: SooChan Lim <sc1.lim@samsung.com>,
8  *          Boram Park <boram1288.park@samsung.com>,
9  *          Changyeon Lee <cyeon.lee@samsung.com>,
10  *          Sangjin Lee <lsj119@samsung.com>
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a
13  * copy of this software and associated documentation files (the
14  * "Software"), to deal in the Software without restriction, including
15  * without limitation the rights to use, copy, modify, merge, publish,
16  * distribute, sub license, and/or sell copies of the Software, and to
17  * permit persons to whom the Software is furnished to do so, subject to
18  * the following conditions:
19  *
20  * The above copyright notice and this permission notice (including the
21  * next paragraph) shall be included in all copies or substantial portions
22  * of the Software.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
27  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
28  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
29  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
30  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31  *
32 **************************************************************************/
33
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37
38 #include "tdm_private.h"
39
40 #define HWC_FUNC_ENTRY() \
41         tdm_private_display *private_display; \
42         tdm_private_output *private_output; \
43         tdm_private_hwc *private_hwc; \
44         tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\
45         TDM_RETURN_VAL_IF_FAIL(hwc != NULL, TDM_ERROR_INVALID_PARAMETER); \
46         private_hwc = (tdm_private_hwc*)hwc; \
47         private_output = private_hwc->private_output; \
48         TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_INVALID_PARAMETER); \
49         private_display = private_output->private_display
50
51 #define HWC_FUNC_ENTRY_ERROR() \
52         tdm_private_display *private_display; \
53         tdm_private_output *private_output; \
54         tdm_private_hwc *private_hwc; \
55         tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\
56         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(hwc != NULL, TDM_ERROR_INVALID_PARAMETER, NULL); \
57         private_hwc = (tdm_private_hwc*)hwc; \
58         private_output = private_hwc->private_output; \
59         TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_output != NULL, TDM_ERROR_INVALID_PARAMETER, NULL); \
60         private_display = private_output->private_display
61
62 #define HWC_FUNC_ENTRY_VOID_RETURN() \
63         tdm_private_display *private_display; \
64         tdm_private_output *private_output; \
65         tdm_private_hwc *private_hwc; \
66         tdm_error ret = TDM_ERROR_NONE; /* default TDM_ERROR_NONE */\
67         TDM_RETURN_IF_FAIL(hwc != NULL); \
68         private_hwc = (tdm_private_hwc*)hwc; \
69         private_output = private_hwc->private_output; \
70         TDM_RETURN_IF_FAIL(private_output != NULL); \
71         private_display = private_output->private_display
72
73 static int hwc_use_vblank;
74 static unsigned int hwc_vblank_fps;
75
76 static tdm_private_hwc_window *
77 _tdm_hwc_find_private_hwc_window(tdm_private_hwc *private_hwc, tdm_hwc_window *hwc_window_backend)
78 {
79         tdm_private_hwc_window *private_hwc_window = NULL;
80
81         LIST_FOR_EACH_ENTRY(private_hwc_window, &private_hwc->hwc_window_list, link) {
82                 if (private_hwc_window->hwc_window_backend == hwc_window_backend)
83                         return private_hwc_window;
84         }
85
86         return NULL;
87 }
88
89 static void
90 _tdm_hwc_thread_cb_commit(tdm_private_display *private_display, void *object,
91                                 tdm_thread_cb_base *cb_base, void *user_data)
92 {
93         tdm_thread_cb_hwc_commit *hwc_commit = (tdm_thread_cb_hwc_commit *)cb_base;
94         tdm_private_hwc_commit_handler *hwc_commit_handler = hwc_commit->base.data;
95         tdm_private_hwc *private_hwc = object;
96
97         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
98
99         if (!hwc_commit_handler)
100                 return;
101
102         assert(hwc_commit_handler->owner_tid == syscall(SYS_gettid));
103
104         tdm_thread_cb_remove(private_hwc, TDM_THREAD_CB_HWC_COMMIT, hwc_commit_handler,
105                                         _tdm_hwc_thread_cb_commit, NULL);
106
107         LIST_DEL(&hwc_commit_handler->link);
108
109         if (tdm_debug_module & TDM_DEBUG_COMMIT) {
110                 TDM_INFO("----------------------------------------- hwc(%d) committed", private_hwc->index);
111                 TDM_INFO("handler(%p)", hwc_commit_handler);
112         }
113
114         /* LCOV_EXCL_START */
115         if (private_display->print_fps) {
116                 double curr = tdm_helper_get_time();
117                 if (private_hwc->fps_stamp == 0) {
118                         private_hwc->fps_stamp = curr;
119                 } else if ((curr - private_hwc->fps_stamp) > 1.0) {
120                         TDM_INFO("hwc(%p,%d) fps: %d",
121                                          private_hwc, private_hwc->index, private_hwc->fps_count);
122                         private_hwc->fps_count = 0;
123                         private_hwc->fps_stamp = curr;
124                 } else
125                         private_hwc->fps_count++;
126         } else if (private_hwc->fps_stamp != 0) {
127                 private_hwc->fps_stamp = 0;
128                 private_hwc->fps_count = 0;
129         }
130         /* LCOV_EXCL_STOP */
131
132         if (hwc_commit_handler->func) {
133                 _pthread_mutex_unlock(&private_display->lock);
134                 hwc_commit_handler->func(private_hwc,
135                                                                         hwc_commit->sequence,
136                                                                         hwc_commit->tv_sec,
137                                                                         hwc_commit->tv_usec,
138                                                                         hwc_commit_handler->user_data);
139                 _pthread_mutex_lock(&private_display->lock);
140         }
141
142         free(hwc_commit_handler);
143
144         if (tdm_debug_module & TDM_DEBUG_COMMIT)
145                 TDM_INFO("-----------------------------------------...");
146 }
147
148 static void
149 _tdm_hwc_cb_commit(tdm_hwc *hwc_backend, unsigned int sequence,
150                                           unsigned int tv_sec, unsigned int tv_usec, void *user_data)
151 {
152         tdm_private_hwc_commit_handler *hwc_commit_handler = user_data;
153         tdm_private_hwc *private_hwc;
154         tdm_thread_cb_hwc_commit hwc_commit;
155         tdm_error ret;
156
157         if (hwc_commit_handler && hwc_commit_handler->use_vblank)
158                 return;
159
160         if (hwc_commit_handler)
161                 private_hwc = hwc_commit_handler->private_hwc;
162         else
163                 private_hwc = tdm_display_find_private_hwc(tdm_display_get(), hwc_backend);
164
165         memset(&hwc_commit, 0, sizeof hwc_commit);
166         hwc_commit.base.type = TDM_THREAD_CB_HWC_COMMIT;
167         hwc_commit.base.length = sizeof hwc_commit;
168         hwc_commit.base.object_stamp = private_hwc->stamp;
169         hwc_commit.base.data = hwc_commit_handler;
170         hwc_commit.base.sync = 0;
171         hwc_commit.sequence = sequence;
172         hwc_commit.tv_sec = tv_sec;
173         hwc_commit.tv_usec = tv_usec;
174
175         ret = tdm_thread_cb_call(private_hwc, &hwc_commit.base, 1);
176         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
177 }
178
179 static void
180 _tdm_hwc_got_wait_vblank(unsigned int sequence,
181                                                  unsigned int tv_sec, unsigned int tv_usec, void *user_data)
182 {
183         tdm_private_hwc_commit_handler *hwc_commit_handler = user_data;
184         tdm_private_hwc *private_hwc;
185         tdm_thread_cb_hwc_commit hwc_commit;
186
187         private_hwc = hwc_commit_handler->private_hwc;
188         private_hwc->private_output->layer_waiting_vblank = 0;
189
190         memset(&hwc_commit, 0, sizeof hwc_commit);
191         hwc_commit.base.type = TDM_THREAD_CB_HWC_COMMIT;
192         hwc_commit.base.length = sizeof hwc_commit;
193         hwc_commit.base.object_stamp = private_hwc->stamp;
194         hwc_commit.base.data = hwc_commit_handler;
195         hwc_commit.base.sync = 0;
196         hwc_commit.sequence = sequence;
197         hwc_commit.tv_sec = tv_sec;
198         hwc_commit.tv_usec = tv_usec;
199
200         _tdm_hwc_thread_cb_commit(private_hwc->private_output->private_display, private_hwc, &hwc_commit.base, user_data);
201 }
202
203 static void
204 _tdm_hwc_cb_wait_vblank(tdm_vblank *vblank, tdm_error error, unsigned int sequence,
205                                                 unsigned int tv_sec, unsigned int tv_usec, void *user_data)
206 {
207         tdm_private_hwc_commit_handler *hwc_commit_handler = user_data;
208         tdm_private_output *private_output = NULL;
209         tdm_private_display *private_display;
210
211         if (!hwc_commit_handler->use_vblank)
212                 return;
213
214         TDM_RETURN_IF_FAIL(hwc_commit_handler != NULL);
215
216         private_output = hwc_commit_handler->private_hwc->private_output;
217         TDM_RETURN_IF_FAIL(private_output != NULL);
218
219         private_display = private_output->private_display;
220
221         _pthread_mutex_lock(&private_display->lock);
222
223         _tdm_hwc_got_wait_vblank(sequence, tv_sec, tv_usec, user_data);
224
225         _pthread_mutex_unlock(&private_display->lock);
226 }
227
228 static tdm_error
229 _tdm_hwc_vblank(tdm_private_hwc *private_hwc, tdm_private_hwc_commit_handler *hwc_commit_handler)
230 {
231         tdm_private_display *private_display;
232         tdm_private_output *private_output;
233         tdm_error ret = TDM_ERROR_NONE;
234
235         private_output = private_hwc->private_output;
236         TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_INVALID_PARAMETER);
237         private_display = private_output->private_display;
238
239         if (!private_output->vblank) {
240                 /* tdm_vblank APIs is for server. it should be called in unlock status*/
241                 _pthread_mutex_unlock(&private_display->lock);
242                 private_output->vblank = tdm_vblank_create(private_display, private_output, NULL);
243                 _pthread_mutex_lock(&private_display->lock);
244                 TDM_RETURN_VAL_IF_FAIL(private_output->vblank != NULL, TDM_ERROR_OPERATION_FAILED);
245         }
246
247         if (!private_output->layer_waiting_vblank) {
248                 ret = tdm_vblank_set_fps(private_output->vblank, hwc_vblank_fps);
249                 if (ret != TDM_ERROR_NONE)
250                         goto done;
251
252                 /* tdm_vblank APIs is for server. it should be called in unlock status*/
253                 _pthread_mutex_unlock(&private_display->lock);
254                 ret = tdm_vblank_wait(private_output->vblank, 0, 0, 1, _tdm_hwc_cb_wait_vblank, hwc_commit_handler);
255                 _pthread_mutex_lock(&private_display->lock);
256                 if (ret != TDM_ERROR_NONE) {
257                         if (!TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->current_dpms_value))
258                                 goto done;
259                 }
260
261                 hwc_commit_handler->use_vblank = 1;
262                 private_output->layer_waiting_vblank = 1;
263         }
264
265 done:
266         return ret;
267 }
268
269 INTERN tdm_error
270 tdm_hwc_init(tdm_private_display *private_display)
271 {
272         tdm_thread_cb_set_find_func(TDM_THREAD_CB_HWC_COMMIT, tdm_display_find_hwc_stamp);
273
274         return TDM_ERROR_NONE;
275 }
276
277 INTERN void
278 tdm_hwc_set_vblank(unsigned int fps)
279 {
280         hwc_use_vblank = 1;
281         hwc_vblank_fps = fps;
282 }
283
284 INTERN void
285 tdm_hwc_unset_vblank(void)
286 {
287         hwc_use_vblank = 0;
288         hwc_vblank_fps = 0;
289 }
290
291 EXTERN tdm_hwc_window *
292 tdm_hwc_create_window(tdm_hwc *hwc, tdm_error *error)
293 {
294         tdm_hwc_window *hwc_window = NULL;
295
296         HWC_FUNC_ENTRY_ERROR();
297
298         _pthread_mutex_lock(&private_display->lock);
299
300         hwc_window = (tdm_hwc_window *)tdm_hwc_window_create_internal(private_hwc, error);
301
302         _pthread_mutex_unlock(&private_display->lock);
303
304         return hwc_window;
305 }
306
307 EXTERN tdm_error
308 tdm_hwc_get_video_supported_formats(tdm_hwc *hwc, const tbm_format **formats, int *count)
309 {
310         tdm_private_module *private_module;
311         tdm_func_hwc *func_hwc;
312
313         HWC_FUNC_ENTRY();
314
315         TDM_RETURN_VAL_IF_FAIL(formats != NULL, TDM_ERROR_INVALID_PARAMETER);
316         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
317
318         _pthread_mutex_lock(&private_display->lock);
319
320         private_module = private_output->private_module;
321         func_hwc = &private_module->func_hwc;
322
323         if (!func_hwc->hwc_get_video_supported_formats) {
324                 /* LCOV_EXCL_START */
325                 _pthread_mutex_unlock(&private_display->lock);
326                 TDM_WRN("not implemented!!");
327                 return TDM_ERROR_NOT_IMPLEMENTED;
328                 /* LCOV_EXCL_STOP */
329         }
330
331         ret = func_hwc->hwc_get_video_supported_formats(private_hwc->hwc_backend, formats, count);
332
333         _pthread_mutex_unlock(&private_display->lock);
334
335         return ret;
336 }
337
338 EXTERN tdm_error
339 tdm_hwc_get_video_available_properties(tdm_hwc *hwc, const tdm_prop **props, int *count)
340 {
341         tdm_private_module *private_module;
342         tdm_func_hwc *func_hwc = NULL;
343
344         HWC_FUNC_ENTRY();
345
346         TDM_RETURN_VAL_IF_FAIL(props != NULL, TDM_ERROR_INVALID_PARAMETER);
347         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
348
349         _pthread_mutex_lock(&private_display->lock);
350
351         private_module = private_output->private_module;
352         func_hwc = &private_module->func_hwc;
353
354         if (!func_hwc->hwc_get_video_available_properties) {
355                 /* LCOV_EXCL_START */
356                 _pthread_mutex_unlock(&private_display->lock);
357                 TDM_WRN("not implemented!!");
358                 return TDM_ERROR_NOT_IMPLEMENTED;
359                 /* LCOV_EXCL_STOP */
360         }
361
362         ret = func_hwc->hwc_get_video_available_properties(private_hwc->hwc_backend, props, count);
363
364         _pthread_mutex_unlock(&private_display->lock);
365
366         return ret;
367 }
368
369 EXTERN tdm_error
370 tdm_hwc_get_capabilities(tdm_hwc *hwc, tdm_hwc_capability *capabilities)
371 {
372         tdm_private_module *private_module;
373         tdm_func_hwc *func_hwc;
374
375         HWC_FUNC_ENTRY();
376
377         _pthread_mutex_lock(&private_display->lock);
378
379         private_module = private_output->private_module;
380         func_hwc = &private_module->func_hwc;
381
382         if (!func_hwc->hwc_get_capabilities) {
383                 _pthread_mutex_unlock(&private_display->lock);
384                 TDM_WRN("not implemented!!");
385                 return TDM_ERROR_NOT_IMPLEMENTED;
386         }
387
388         ret = func_hwc->hwc_get_capabilities(private_hwc->hwc_backend, capabilities);
389
390         _pthread_mutex_unlock(&private_display->lock);
391
392         return ret;
393 }
394
395 EXTERN tdm_error
396 tdm_hwc_get_available_properties(tdm_hwc *hwc, const tdm_prop **props, int *count)
397 {
398         tdm_private_module *private_module;
399         tdm_func_hwc *func_hwc = NULL;
400
401         HWC_FUNC_ENTRY();
402
403         TDM_RETURN_VAL_IF_FAIL(props != NULL, TDM_ERROR_INVALID_PARAMETER);
404         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
405
406         _pthread_mutex_lock(&private_display->lock);
407
408         private_module = private_output->private_module;
409         func_hwc = &private_module->func_hwc;
410
411         if (!func_hwc->hwc_get_available_properties) {
412                 /* LCOV_EXCL_START */
413                 _pthread_mutex_unlock(&private_display->lock);
414                 TDM_WRN("not implemented!!");
415                 return TDM_ERROR_NOT_IMPLEMENTED;
416                 /* LCOV_EXCL_STOP */
417         }
418
419         ret = func_hwc->hwc_get_available_properties(private_hwc->hwc_backend, props, count);
420
421         _pthread_mutex_unlock(&private_display->lock);
422
423         return ret;
424 }
425
426 EXTERN tbm_surface_queue_h
427 tdm_hwc_get_client_target_buffer_queue(tdm_hwc *hwc, tdm_error *error)
428 {
429         tdm_private_module *private_module;
430         tdm_func_hwc *func_hwc = NULL;
431         tbm_surface_queue_h queue = NULL;
432
433         HWC_FUNC_ENTRY_ERROR();
434
435         _pthread_mutex_lock(&private_display->lock);
436
437         private_module = private_hwc->private_module;
438         func_hwc = &private_module->func_hwc;
439
440         if (!func_hwc->hwc_get_client_target_buffer_queue) {
441                 /* LCOV_EXCL_START */
442                 _pthread_mutex_unlock(&private_display->lock);
443                 TDM_WRN("not implemented!!");
444                 return NULL;
445                 /* LCOV_EXCL_STOP */
446         }
447
448         queue = func_hwc->hwc_get_client_target_buffer_queue(private_hwc->hwc_backend, error);
449
450         _pthread_mutex_unlock(&private_display->lock);
451
452         return queue;
453 }
454
455 EXTERN tdm_error
456 tdm_hwc_set_client_target_buffer(tdm_hwc *hwc, tbm_surface_h target_buffer, tdm_region damage)
457 {
458         tdm_private_module *private_module;
459         tdm_func_hwc *func_hwc = NULL;
460
461         HWC_FUNC_ENTRY();
462
463         _pthread_mutex_lock(&private_display->lock);
464
465         if (tdm_debug_dump & TDM_DUMP_FLAG_WINDOW) {
466                 /* LCOV_EXCL_START */
467                 char str[TDM_PATH_LEN];
468                 static int i;
469                 snprintf(str, TDM_PATH_LEN, "target_window_%03d", i++);
470                 tdm_helper_dump_buffer_str(target_buffer, tdm_debug_dump_dir, str);
471                 /* LCOV_EXCL_STOP */
472         }
473
474         private_module = private_hwc->private_module;
475         func_hwc = &private_module->func_hwc;
476
477         if (!func_hwc->hwc_set_client_target_buffer) {
478                 /* LCOV_EXCL_START */
479                 _pthread_mutex_unlock(&private_display->lock);
480                 TDM_WRN("not implemented!!");
481                 return TDM_ERROR_NOT_IMPLEMENTED;
482                 /* LCOV_EXCL_STOP */
483         }
484
485         ret = func_hwc->hwc_set_client_target_buffer(private_hwc->hwc_backend, target_buffer, damage);
486
487         if (private_hwc->display_target_buffer) {
488                 if (private_hwc->display_target_buffer != target_buffer) {
489                         tbm_surface_internal_unref(private_hwc->display_target_buffer);
490                         private_hwc->display_target_buffer = target_buffer;
491                         if (target_buffer)
492                                 tbm_surface_internal_ref(private_hwc->display_target_buffer);
493                 }
494         } else {
495                 if (target_buffer) {
496                         private_hwc->display_target_buffer = target_buffer;
497                         tbm_surface_internal_ref(private_hwc->display_target_buffer);
498                 }
499         }
500
501         _pthread_mutex_unlock(&private_display->lock);
502
503         return ret;
504 }
505
506 EXTERN tdm_error
507 tdm_hwc_set_client_target_acquire_fence(tdm_hwc *hwc, int acquire_fence)
508 {
509         tdm_private_module *private_module;
510         tdm_func_hwc *func_hwc = NULL;
511
512         HWC_FUNC_ENTRY();
513
514         _pthread_mutex_lock(&private_display->lock);
515
516         private_module = private_hwc->private_module;
517         func_hwc = &private_module->func_hwc;
518
519         if (!func_hwc->hwc_set_client_target_acquire_fence) {
520                 /* LCOV_EXCL_START */
521                 _pthread_mutex_unlock(&private_display->lock);
522                 TDM_WRN("not implemented!!");
523                 return TDM_ERROR_NOT_IMPLEMENTED;
524                 /* LCOV_EXCL_STOP */
525         }
526
527         ret = func_hwc->hwc_set_client_target_acquire_fence(private_hwc->hwc_backend, acquire_fence);
528
529         _pthread_mutex_unlock(&private_display->lock);
530
531         return ret;
532 }
533
534 EXTERN tdm_error
535 tdm_hwc_validate(tdm_hwc *hwc, tdm_hwc_window **composited_wnds, uint32_t num_wnds, uint32_t *num_types)
536 {
537         tdm_private_module *private_module;
538         tdm_func_hwc *func_hwc = NULL;
539         tdm_private_hwc_window **composited_wnds_frontend = NULL;
540         tdm_hwc_window **composited_wnds_backend = NULL;
541         int i;
542
543         HWC_FUNC_ENTRY();
544
545         TDM_RETURN_VAL_IF_FAIL(num_types != NULL, TDM_ERROR_INVALID_PARAMETER);
546
547         _pthread_mutex_lock(&private_display->lock);
548
549         private_module = private_hwc->private_module;
550         func_hwc = &private_module->func_hwc;
551
552         if (!func_hwc->hwc_validate) {
553                 /* LCOV_EXCL_START */
554                 _pthread_mutex_unlock(&private_display->lock);
555                 TDM_WRN("not implemented!!");
556                 return TDM_ERROR_NOT_IMPLEMENTED;
557                 /* LCOV_EXCL_STOP */
558         }
559
560         if (num_wnds == 0) {
561                 ret = func_hwc->hwc_validate(private_hwc->hwc_backend, NULL, 0, num_types);
562
563                 _pthread_mutex_unlock(&private_display->lock);
564                 return ret;
565         }
566
567         composited_wnds_backend = calloc(num_wnds, sizeof(tdm_hwc_window *));
568         if (!composited_wnds_backend) {
569                 /* LCOV_EXCL_START */
570                 _pthread_mutex_unlock(&private_display->lock);
571                 return TDM_ERROR_OUT_OF_MEMORY;
572                 /* LCOV_EXCL_STOP */
573         }
574
575         composited_wnds_frontend = (tdm_private_hwc_window **)composited_wnds;
576
577         for (i = 0; i < num_wnds; i++)
578                 composited_wnds_backend[i] = composited_wnds_frontend[i]->hwc_window_backend;
579
580         ret = func_hwc->hwc_validate(private_hwc->hwc_backend, composited_wnds_backend,
581                                                                 num_wnds, num_types);
582
583         free(composited_wnds_backend);
584
585         _pthread_mutex_unlock(&private_display->lock);
586
587         return ret;
588 }
589
590 EXTERN tdm_error
591 tdm_hwc_get_changed_composition_types(tdm_hwc *hwc, uint32_t *num_elements,
592                                                                 tdm_hwc_window **hwc_window,
593                                                                 tdm_hwc_window_composition *composition_types)
594 {
595         tdm_private_module *private_module;
596         tdm_func_hwc *func_hwc = NULL;
597         tdm_private_hwc_window * private_hwc_window = NULL;
598         int i = 0;
599
600         HWC_FUNC_ENTRY();
601
602         TDM_RETURN_VAL_IF_FAIL(num_elements != NULL, TDM_ERROR_INVALID_PARAMETER);
603
604         _pthread_mutex_lock(&private_display->lock);
605
606         private_module = private_hwc->private_module;
607         func_hwc = &private_module->func_hwc;
608
609         if (!func_hwc->hwc_get_changed_composition_types) {
610                 /* LCOV_EXCL_START */
611                 _pthread_mutex_unlock(&private_display->lock);
612                 TDM_WRN("not implemented!!");
613                 return TDM_ERROR_NOT_IMPLEMENTED;
614                 /* LCOV_EXCL_STOP */
615         }
616
617         ret = func_hwc->hwc_get_changed_composition_types(private_hwc->hwc_backend,
618                                                         num_elements, hwc_window, composition_types);
619         if (ret != TDM_ERROR_NONE) {
620                 /* LCOV_EXCL_START */
621                 _pthread_mutex_unlock(&private_display->lock);
622                 return ret;
623                 /* LCOV_EXCL_STOP */
624         }
625
626         if (hwc_window == NULL || composition_types == NULL) {
627                 _pthread_mutex_unlock(&private_display->lock);
628                 return TDM_ERROR_NONE;
629         }
630
631         for (i = 0; i < *num_elements; i++) {
632                 private_hwc_window = _tdm_hwc_find_private_hwc_window(private_hwc, hwc_window[i]);
633                 if (private_hwc_window == NULL) {
634                         /* LCOV_EXCL_START */
635                         TDM_ERR("failed! This should never happen!");
636                         tdm_hwc_window_destroy_internal(private_hwc_window);
637                         *num_elements = 0;
638                         _pthread_mutex_unlock(&private_display->lock);
639                         return TDM_ERROR_OPERATION_FAILED;
640                         /* LCOV_EXCL_STOP */
641                 }
642
643                 hwc_window[i] = (tdm_hwc_window*)private_hwc_window;
644         }
645
646         _pthread_mutex_unlock(&private_display->lock);
647
648         return ret;
649 }
650
651 EXTERN tdm_error
652 tdm_hwc_accept_validation(tdm_hwc *hwc)
653 {
654         tdm_private_module *private_module;
655         tdm_func_hwc *func_hwc = NULL;
656
657         HWC_FUNC_ENTRY();
658
659         _pthread_mutex_lock(&private_display->lock);
660
661         private_module = private_hwc->private_module;
662         func_hwc = &private_module->func_hwc;
663
664         if (!func_hwc->hwc_validate) {
665                 /* LCOV_EXCL_START */
666                 _pthread_mutex_unlock(&private_display->lock);
667                 TDM_WRN("not implemented!!");
668                 return TDM_ERROR_NOT_IMPLEMENTED;
669                 /* LCOV_EXCL_STOP */
670         }
671
672         ret = func_hwc->hwc_accept_validation(private_hwc->hwc_backend);
673
674         _pthread_mutex_unlock(&private_display->lock);
675
676         return ret;
677 }
678
679 EXTERN tdm_error
680 tdm_hwc_commit(tdm_hwc *hwc, int sync, tdm_hwc_commit_handler func, void *user_data)
681 {
682         tdm_private_module *private_module;
683         tdm_func_hwc *func_hwc = NULL;
684         tdm_private_hwc_commit_handler *hwc_commit_handler = NULL;
685         tdm_private_voutput *private_voutput = NULL;
686         tdm_private_voutput_commit_handler *voutput_commit_handler = NULL;
687
688         HWC_FUNC_ENTRY();
689
690         _pthread_mutex_lock(&private_display->lock);
691
692         private_module = private_hwc->private_module;
693         func_hwc = &private_module->func_hwc;
694
695         if (!func_hwc->hwc_commit) {
696                 /* LCOV_EXCL_START */
697                 TDM_WRN("not implemented!!");
698                 _pthread_mutex_unlock(&private_display->lock);
699                 return TDM_ERROR_NOT_IMPLEMENTED;
700                 /* LCOV_EXCL_STOP */
701         }
702
703 //TODO: I am not sure yet whether we have to check the dpms at hwc_commit.
704 #if 0
705         /* check if the dpms is off */
706         if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->current_dpms_value)) {
707                 TDM_ERR("hwc(%d) dpms: %s", private_hwc->index,
708                                 tdm_dpms_str(private_output->current_dpms_value));
709                 _pthread_mutex_unlock(&private_display->lock);
710                 return TDM_ERROR_DPMS_OFF;
711         }
712 #endif
713
714         if (tdm_debug_module & TDM_DEBUG_COMMIT)
715                 TDM_INFO("hwc(%d) commit", private_hwc->index);
716
717         if (private_module == private_display->virtual_module) {
718                 if (!private_output->private_voutput) {
719                         TDM_ERR("virtual module but don't have voutput");
720                         _pthread_mutex_unlock(&private_display->lock);
721                         return TDM_ERROR_BAD_MODULE;
722                 }
723         }
724
725         if (!private_hwc->regist_commit_cb) {
726                 private_hwc->regist_commit_cb = 1;
727                 ret = func_hwc->hwc_set_commit_handler(private_hwc->hwc_backend, _tdm_hwc_cb_commit);
728                 /* LCOV_EXCL_START */
729                 if (ret != TDM_ERROR_NONE) {
730                         private_hwc->regist_commit_cb = 0;
731                         TDM_ERR("hwc(%d) fail to set hwc_set_commit_handler", private_hwc->index);
732                         _pthread_mutex_unlock(&private_display->lock);
733                         return ret;
734                 /* LCOV_EXCL_STOP */
735                 }
736         }
737
738         hwc_commit_handler = calloc(1, sizeof(tdm_private_hwc_commit_handler));
739         if (!hwc_commit_handler) {
740                 /* LCOV_EXCL_START */
741                 TDM_ERR("failed: alloc memory");
742                 _pthread_mutex_unlock(&private_display->lock);
743                 return TDM_ERROR_OUT_OF_MEMORY;
744                 /* LCOV_EXCL_STOP */
745         }
746
747         ret = tdm_thread_cb_add(private_hwc, TDM_THREAD_CB_HWC_COMMIT, hwc_commit_handler,
748                                         _tdm_hwc_thread_cb_commit, NULL);
749         if (ret != TDM_ERROR_NONE) {
750                 TDM_ERR("tdm_thread_cb_add failed");
751                 free(hwc_commit_handler);
752                 _pthread_mutex_unlock(&private_display->lock);
753                 return ret;
754         }
755
756         LIST_ADDTAIL(&hwc_commit_handler->link, &private_hwc->hwc_commit_handler_list);
757         hwc_commit_handler->private_hwc = private_hwc;
758         hwc_commit_handler->func = func;
759         hwc_commit_handler->user_data = user_data;
760         hwc_commit_handler->owner_tid = syscall(SYS_gettid);
761
762         if (private_module == private_display->virtual_module) {
763                 private_voutput = private_output->private_voutput;
764
765                 if (LIST_LENGTH(&private_voutput->voutput_commit_handler_list) != 0) {
766                         voutput_commit_handler = LIST_FIRST_ENTRY(&private_voutput->voutput_commit_handler_list, tdm_private_voutput_commit_handler, link);
767                         voutput_commit_handler->user_data = private_hwc->display_target_buffer;
768                 }
769         }
770
771         ret = func_hwc->hwc_commit(private_hwc->hwc_backend, sync, hwc_commit_handler);
772         TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed);
773
774         if (hwc_use_vblank) {
775                 ret = _tdm_hwc_vblank(private_hwc, hwc_commit_handler);
776                 if (ret == TDM_ERROR_NONE) {
777                         if (tdm_debug_module & TDM_DEBUG_COMMIT)
778                                 TDM_INFO("hwc(%d) backend commit: wait vblank handle(%p) func(%p) user_data(%p)",
779                                         private_hwc->index, hwc_commit_handler, func, user_data);
780                 } else
781                         goto commit_failed;
782         } else {
783                 if (tdm_debug_module & TDM_DEBUG_COMMIT)
784                         TDM_INFO("hwc(%d) backend commit: handle(%p) func(%p) user_data(%p)",
785                                         private_hwc->index, hwc_commit_handler, func, user_data);
786         }
787
788         _pthread_mutex_unlock(&private_display->lock);
789
790         return ret;
791
792 commit_failed:
793         /* LCOV_EXCL_START */
794         if (hwc_commit_handler) {
795                 tdm_thread_cb_remove(private_hwc, TDM_THREAD_CB_HWC_COMMIT, hwc_commit_handler,
796                                                 _tdm_hwc_thread_cb_commit, NULL);
797                 LIST_DEL(&hwc_commit_handler->link);
798                 free(hwc_commit_handler);
799         }
800
801         _pthread_mutex_unlock(&private_display->lock);
802
803         return ret;
804         /* LCOV_EXCL_STOP */
805 }
806
807 EXTERN tdm_error
808 tdm_hwc_get_commit_fence(tdm_hwc *hwc, int *commit_fence)
809 {
810         tdm_private_module *private_module;
811         tdm_func_hwc *func_hwc = NULL;
812
813         HWC_FUNC_ENTRY();
814
815         _pthread_mutex_lock(&private_display->lock);
816
817         private_module = private_hwc->private_module;
818         func_hwc = &private_module->func_hwc;
819
820         if (!func_hwc->hwc_get_commit_fence) {
821                 /* LCOV_EXCL_START */
822                 _pthread_mutex_unlock(&private_display->lock);
823                 TDM_WRN("not implemented!!");
824                 return TDM_ERROR_NOT_IMPLEMENTED;
825                 /* LCOV_EXCL_STOP */
826         }
827
828         ret = func_hwc->hwc_get_commit_fence(private_hwc->hwc_backend, commit_fence);
829
830         _pthread_mutex_unlock(&private_display->lock);
831
832         return ret;
833 }
834
835 tdm_error
836 tdm_hwc_set_property(tdm_hwc *hwc, uint32_t id, tdm_value value)
837 {
838         tdm_private_module *private_module;
839         tdm_func_hwc *func_hwc = NULL;
840
841         HWC_FUNC_ENTRY();
842
843         _pthread_mutex_lock(&private_display->lock);
844
845         private_module = private_hwc->private_module;
846         func_hwc = &private_module->func_hwc;
847
848         if (!func_hwc->hwc_set_property) {
849                 /* LCOV_EXCL_START */
850                 _pthread_mutex_unlock(&private_display->lock);
851                 TDM_WRN("not implemented!!");
852                 return TDM_ERROR_NOT_IMPLEMENTED;
853                 /* LCOV_EXCL_STOP */
854         }
855
856         ret = func_hwc->hwc_set_property(private_hwc->hwc_backend, id, value);
857
858         _pthread_mutex_unlock(&private_display->lock);
859
860         return ret;
861 }
862
863 tdm_error
864 tdm_hwc_get_property(tdm_hwc *hwc, uint32_t id, tdm_value *value)
865 {
866         tdm_private_module *private_module;
867         tdm_func_hwc *func_hwc = NULL;
868
869         HWC_FUNC_ENTRY();
870
871         _pthread_mutex_lock(&private_display->lock);
872
873         private_module = private_hwc->private_module;
874         func_hwc = &private_module->func_hwc;
875
876         if (!func_hwc->hwc_get_property) {
877                 /* LCOV_EXCL_START */
878                 _pthread_mutex_unlock(&private_display->lock);
879                 TDM_WRN("not implemented!!");
880                 return TDM_ERROR_NOT_IMPLEMENTED;
881                 /* LCOV_EXCL_STOP */
882         }
883
884         ret = func_hwc->hwc_get_property(private_hwc->hwc_backend, id, value);
885
886         _pthread_mutex_unlock(&private_display->lock);
887
888         return ret;
889 }