hwc: change use_vblank flag set position
[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 tdm_error
90 _tdm_hwc_check_hwc_commit_handler_validation(tdm_private_hwc *private_hwc, tdm_private_hwc_commit_handler *hwc_commit_handler)
91 {
92         tdm_private_hwc_commit_handler *commit_handler = NULL;
93
94         if (LIST_IS_EMPTY(&private_hwc->hwc_commit_handler_list))
95                 return TDM_ERROR_INVALID_PARAMETER;
96
97         LIST_FOR_EACH_ENTRY(commit_handler, &private_hwc->hwc_commit_handler_list, link) {
98                 if (commit_handler == hwc_commit_handler)
99                         return TDM_ERROR_NONE;
100         }
101
102         return TDM_ERROR_INVALID_PARAMETER;
103 }
104
105 static void
106 _tdm_hwc_thread_cb_commit(tdm_private_display *private_display, void *object,
107                                 tdm_thread_cb_base *cb_base, void *user_data)
108 {
109         tdm_thread_cb_hwc_commit *hwc_commit = (tdm_thread_cb_hwc_commit *)cb_base;
110         tdm_private_hwc_commit_handler *hwc_commit_handler = hwc_commit->base.data;
111         tdm_private_hwc *private_hwc = object;
112
113         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
114
115         if (!hwc_commit_handler)
116                 return;
117
118         assert(hwc_commit_handler->owner_tid == syscall(SYS_gettid));
119
120         tdm_thread_cb_remove(private_hwc, TDM_THREAD_CB_HWC_COMMIT, hwc_commit_handler,
121                                         _tdm_hwc_thread_cb_commit, NULL);
122
123         TDM_RETURN_IF_FAIL(_tdm_hwc_check_hwc_commit_handler_validation(private_hwc, hwc_commit_handler) == TDM_ERROR_NONE)
124
125         LIST_DEL(&hwc_commit_handler->link);
126
127         if (tdm_debug_module & TDM_DEBUG_COMMIT) {
128                 TDM_INFO("----------------------------------------- hwc(%d) committed", private_hwc->index);
129                 TDM_INFO("handler(%p)", hwc_commit_handler);
130         }
131
132         /* LCOV_EXCL_START */
133         if (private_display->print_fps) {
134                 double curr = tdm_helper_get_time();
135                 if (private_hwc->fps_stamp == 0) {
136                         private_hwc->fps_stamp = curr;
137                 } else if ((curr - private_hwc->fps_stamp) > 1.0) {
138                         TDM_INFO("hwc(%p,%d) fps: %d",
139                                          private_hwc, private_hwc->index, private_hwc->fps_count);
140                         private_hwc->fps_count = 0;
141                         private_hwc->fps_stamp = curr;
142                 } else
143                         private_hwc->fps_count++;
144         } else if (private_hwc->fps_stamp != 0) {
145                 private_hwc->fps_stamp = 0;
146                 private_hwc->fps_count = 0;
147         }
148         /* LCOV_EXCL_STOP */
149
150         if (hwc_commit_handler->func) {
151                 _pthread_mutex_unlock(&private_display->lock);
152                 hwc_commit_handler->func(private_hwc,
153                                                                         hwc_commit->sequence,
154                                                                         hwc_commit->tv_sec,
155                                                                         hwc_commit->tv_usec,
156                                                                         hwc_commit_handler->user_data);
157                 _pthread_mutex_lock(&private_display->lock);
158         }
159
160         free(hwc_commit_handler);
161
162         if (tdm_debug_module & TDM_DEBUG_COMMIT)
163                 TDM_INFO("-----------------------------------------...");
164 }
165
166 static void
167 _tdm_hwc_cb_commit(tdm_hwc *hwc_backend, unsigned int sequence,
168                                           unsigned int tv_sec, unsigned int tv_usec, void *user_data)
169 {
170         tdm_private_hwc_commit_handler *hwc_commit_handler = user_data;
171         tdm_private_hwc *private_hwc;
172         tdm_thread_cb_hwc_commit hwc_commit;
173         tdm_error ret;
174
175         if (hwc_commit_handler && hwc_commit_handler->use_vblank)
176                 return;
177
178         if (hwc_commit_handler)
179                 private_hwc = hwc_commit_handler->private_hwc;
180         else
181                 private_hwc = tdm_display_find_private_hwc(tdm_display_get(), hwc_backend);
182
183         memset(&hwc_commit, 0, sizeof hwc_commit);
184         hwc_commit.base.type = TDM_THREAD_CB_HWC_COMMIT;
185         hwc_commit.base.length = sizeof hwc_commit;
186         hwc_commit.base.object_stamp = private_hwc->stamp;
187         hwc_commit.base.data = hwc_commit_handler;
188         hwc_commit.base.sync = 0;
189         hwc_commit.sequence = sequence;
190         hwc_commit.tv_sec = tv_sec;
191         hwc_commit.tv_usec = tv_usec;
192
193         ret = tdm_thread_cb_call(private_hwc, &hwc_commit.base, 1);
194         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
195 }
196
197 static void
198 _tdm_hwc_got_wait_vblank(unsigned int sequence,
199                                                  unsigned int tv_sec, unsigned int tv_usec, void *user_data)
200 {
201         tdm_private_hwc_commit_handler *hwc_commit_handler = user_data;
202         tdm_private_hwc *private_hwc;
203         tdm_thread_cb_hwc_commit hwc_commit;
204
205         private_hwc = hwc_commit_handler->private_hwc;
206         private_hwc->private_output->layer_waiting_vblank = 0;
207
208         memset(&hwc_commit, 0, sizeof hwc_commit);
209         hwc_commit.base.type = TDM_THREAD_CB_HWC_COMMIT;
210         hwc_commit.base.length = sizeof hwc_commit;
211         hwc_commit.base.object_stamp = private_hwc->stamp;
212         hwc_commit.base.data = hwc_commit_handler;
213         hwc_commit.base.sync = 0;
214         hwc_commit.sequence = sequence;
215         hwc_commit.tv_sec = tv_sec;
216         hwc_commit.tv_usec = tv_usec;
217
218         _tdm_hwc_thread_cb_commit(private_hwc->private_output->private_display, private_hwc, &hwc_commit.base, user_data);
219 }
220
221 static void
222 _tdm_hwc_cb_wait_vblank(tdm_vblank *vblank, tdm_error error, unsigned int sequence,
223                                                 unsigned int tv_sec, unsigned int tv_usec, void *user_data)
224 {
225         tdm_private_hwc_commit_handler *hwc_commit_handler = user_data;
226         tdm_private_output *private_output = NULL;
227         tdm_private_display *private_display;
228
229         if (!hwc_commit_handler->use_vblank)
230                 return;
231
232         TDM_RETURN_IF_FAIL(hwc_commit_handler != NULL);
233         TDM_RETURN_IF_FAIL(hwc_commit_handler->private_hwc != NULL);
234
235         private_output = hwc_commit_handler->private_hwc->private_output;
236         TDM_RETURN_IF_FAIL(private_output != NULL);
237
238         private_display = private_output->private_display;
239
240         _pthread_mutex_lock(&private_display->lock);
241
242         _tdm_hwc_got_wait_vblank(sequence, tv_sec, tv_usec, user_data);
243
244         _pthread_mutex_unlock(&private_display->lock);
245 }
246
247 static tdm_error
248 _tdm_hwc_vblank(tdm_private_hwc *private_hwc, tdm_private_hwc_commit_handler *hwc_commit_handler)
249 {
250         tdm_private_display *private_display;
251         tdm_private_output *private_output;
252         tdm_error ret = TDM_ERROR_NONE;
253
254         private_output = private_hwc->private_output;
255         TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_INVALID_PARAMETER);
256         private_display = private_output->private_display;
257
258         if (!private_output->vblank) {
259                 /* tdm_vblank APIs is for server. it should be called in unlock status*/
260                 _pthread_mutex_unlock(&private_display->lock);
261                 private_output->vblank = tdm_vblank_create(private_display, private_output, NULL);
262                 _pthread_mutex_lock(&private_display->lock);
263                 TDM_RETURN_VAL_IF_FAIL(private_output->vblank != NULL, TDM_ERROR_OPERATION_FAILED);
264         }
265
266         if (!private_output->layer_waiting_vblank) {
267                 ret = tdm_vblank_set_fps(private_output->vblank, hwc_vblank_fps);
268                 if (ret != TDM_ERROR_NONE)
269                         goto done;
270
271                 private_output->layer_waiting_vblank = 1;
272
273                 /* tdm_vblank APIs is for server. it should be called in unlock status*/
274                 _pthread_mutex_unlock(&private_display->lock);
275                 ret = tdm_vblank_wait(private_output->vblank, 0, 0, 1, _tdm_hwc_cb_wait_vblank, hwc_commit_handler);
276                 _pthread_mutex_lock(&private_display->lock);
277                 if (ret != TDM_ERROR_NONE) {
278                         if (!TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->current_dpms_value)) {
279                                 private_output->layer_waiting_vblank = 0;
280                         }
281                 }
282         }
283
284 done:
285         return ret;
286 }
287
288 INTERN tdm_error
289 tdm_hwc_init(tdm_private_display *private_display)
290 {
291         tdm_thread_cb_set_find_func(TDM_THREAD_CB_HWC_COMMIT, tdm_display_find_hwc_stamp);
292
293         return TDM_ERROR_NONE;
294 }
295
296 INTERN void
297 tdm_hwc_set_vblank(unsigned int fps)
298 {
299         hwc_use_vblank = 1;
300         hwc_vblank_fps = fps;
301 }
302
303 INTERN void
304 tdm_hwc_unset_vblank(void)
305 {
306         hwc_use_vblank = 0;
307         hwc_vblank_fps = 0;
308 }
309
310 EXTERN tdm_hwc_window *
311 tdm_hwc_create_window(tdm_hwc *hwc, tdm_error *error)
312 {
313         tdm_hwc_window *hwc_window = NULL;
314
315         HWC_FUNC_ENTRY_ERROR();
316
317         _pthread_mutex_lock(&private_display->lock);
318
319         hwc_window = (tdm_hwc_window *)tdm_hwc_window_create_internal(private_hwc, error);
320
321         _pthread_mutex_unlock(&private_display->lock);
322
323         return hwc_window;
324 }
325
326 EXTERN tdm_error
327 tdm_hwc_get_video_supported_formats(tdm_hwc *hwc, const tbm_format **formats, int *count)
328 {
329         tdm_private_module *private_module;
330         tdm_func_hwc *func_hwc;
331
332         HWC_FUNC_ENTRY();
333
334         TDM_RETURN_VAL_IF_FAIL(formats != NULL, TDM_ERROR_INVALID_PARAMETER);
335         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
336
337         _pthread_mutex_lock(&private_display->lock);
338
339         private_module = private_output->private_module;
340         func_hwc = &private_module->func_hwc;
341
342         if (!func_hwc->hwc_get_video_supported_formats) {
343                 /* LCOV_EXCL_START */
344                 _pthread_mutex_unlock(&private_display->lock);
345                 TDM_WRN("not implemented!!");
346                 return TDM_ERROR_NOT_IMPLEMENTED;
347                 /* LCOV_EXCL_STOP */
348         }
349
350         ret = func_hwc->hwc_get_video_supported_formats(private_hwc->hwc_backend, formats, count);
351
352         _pthread_mutex_unlock(&private_display->lock);
353
354         return ret;
355 }
356
357 EXTERN tdm_error
358 tdm_hwc_get_video_available_properties(tdm_hwc *hwc, const tdm_prop **props, int *count)
359 {
360         tdm_private_module *private_module;
361         tdm_func_hwc *func_hwc = NULL;
362
363         HWC_FUNC_ENTRY();
364
365         TDM_RETURN_VAL_IF_FAIL(props != NULL, TDM_ERROR_INVALID_PARAMETER);
366         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
367
368         _pthread_mutex_lock(&private_display->lock);
369
370         private_module = private_output->private_module;
371         func_hwc = &private_module->func_hwc;
372
373         if (!func_hwc->hwc_get_video_available_properties) {
374                 /* LCOV_EXCL_START */
375                 _pthread_mutex_unlock(&private_display->lock);
376                 TDM_WRN("not implemented!!");
377                 return TDM_ERROR_NOT_IMPLEMENTED;
378                 /* LCOV_EXCL_STOP */
379         }
380
381         ret = func_hwc->hwc_get_video_available_properties(private_hwc->hwc_backend, props, count);
382
383         _pthread_mutex_unlock(&private_display->lock);
384
385         return ret;
386 }
387
388 EXTERN tdm_error
389 tdm_hwc_get_capabilities(tdm_hwc *hwc, tdm_hwc_capability *capabilities)
390 {
391         tdm_private_module *private_module;
392         tdm_func_hwc *func_hwc;
393
394         HWC_FUNC_ENTRY();
395
396         _pthread_mutex_lock(&private_display->lock);
397
398         private_module = private_output->private_module;
399         func_hwc = &private_module->func_hwc;
400
401         if (!func_hwc->hwc_get_capabilities) {
402                 _pthread_mutex_unlock(&private_display->lock);
403                 TDM_WRN("not implemented!!");
404                 return TDM_ERROR_NOT_IMPLEMENTED;
405         }
406
407         ret = func_hwc->hwc_get_capabilities(private_hwc->hwc_backend, capabilities);
408
409         _pthread_mutex_unlock(&private_display->lock);
410
411         return ret;
412 }
413
414 EXTERN tdm_error
415 tdm_hwc_get_available_properties(tdm_hwc *hwc, const tdm_prop **props, int *count)
416 {
417         tdm_private_module *private_module;
418         tdm_func_hwc *func_hwc = NULL;
419
420         HWC_FUNC_ENTRY();
421
422         TDM_RETURN_VAL_IF_FAIL(props != NULL, TDM_ERROR_INVALID_PARAMETER);
423         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
424
425         _pthread_mutex_lock(&private_display->lock);
426
427         private_module = private_output->private_module;
428         func_hwc = &private_module->func_hwc;
429
430         if (!func_hwc->hwc_get_available_properties) {
431                 /* LCOV_EXCL_START */
432                 _pthread_mutex_unlock(&private_display->lock);
433                 TDM_WRN("not implemented!!");
434                 return TDM_ERROR_NOT_IMPLEMENTED;
435                 /* LCOV_EXCL_STOP */
436         }
437
438         ret = func_hwc->hwc_get_available_properties(private_hwc->hwc_backend, props, count);
439
440         _pthread_mutex_unlock(&private_display->lock);
441
442         return ret;
443 }
444
445 EXTERN tbm_surface_queue_h
446 tdm_hwc_get_client_target_buffer_queue(tdm_hwc *hwc, tdm_error *error)
447 {
448         tdm_private_module *private_module;
449         tdm_func_hwc *func_hwc = NULL;
450         tbm_surface_queue_h queue = NULL;
451
452         HWC_FUNC_ENTRY_ERROR();
453
454         _pthread_mutex_lock(&private_display->lock);
455
456         private_module = private_hwc->private_module;
457         func_hwc = &private_module->func_hwc;
458
459         if (!func_hwc->hwc_get_client_target_buffer_queue) {
460                 /* LCOV_EXCL_START */
461                 _pthread_mutex_unlock(&private_display->lock);
462                 TDM_WRN("not implemented!!");
463                 return NULL;
464                 /* LCOV_EXCL_STOP */
465         }
466
467         queue = func_hwc->hwc_get_client_target_buffer_queue(private_hwc->hwc_backend, error);
468
469         _pthread_mutex_unlock(&private_display->lock);
470
471         return queue;
472 }
473
474 EXTERN tdm_error
475 tdm_hwc_set_client_target_buffer(tdm_hwc *hwc, tbm_surface_h target_buffer, tdm_region damage)
476 {
477         tdm_private_module *private_module;
478         tdm_func_hwc *func_hwc = NULL;
479
480         HWC_FUNC_ENTRY();
481
482         _pthread_mutex_lock(&private_display->lock);
483
484         if (tdm_debug_dump & TDM_DUMP_FLAG_WINDOW) {
485                 /* LCOV_EXCL_START */
486                 char str[TDM_PATH_LEN];
487                 static int i;
488                 snprintf(str, TDM_PATH_LEN, "target_window_%03d", i++);
489                 tdm_helper_dump_buffer_str(target_buffer, tdm_debug_dump_dir, str);
490                 /* LCOV_EXCL_STOP */
491         }
492
493         private_module = private_hwc->private_module;
494         func_hwc = &private_module->func_hwc;
495
496         if (!func_hwc->hwc_set_client_target_buffer) {
497                 /* LCOV_EXCL_START */
498                 _pthread_mutex_unlock(&private_display->lock);
499                 TDM_WRN("not implemented!!");
500                 return TDM_ERROR_NOT_IMPLEMENTED;
501                 /* LCOV_EXCL_STOP */
502         }
503
504         ret = func_hwc->hwc_set_client_target_buffer(private_hwc->hwc_backend, target_buffer, damage);
505
506         if (private_hwc->display_target_buffer) {
507                 if (private_hwc->display_target_buffer != target_buffer) {
508                         tbm_surface_internal_unref(private_hwc->display_target_buffer);
509                         private_hwc->display_target_buffer = target_buffer;
510                         if (target_buffer)
511                                 tbm_surface_internal_ref(private_hwc->display_target_buffer);
512                 }
513         } else {
514                 if (target_buffer) {
515                         private_hwc->display_target_buffer = target_buffer;
516                         tbm_surface_internal_ref(private_hwc->display_target_buffer);
517                 }
518         }
519
520         _pthread_mutex_unlock(&private_display->lock);
521
522         return ret;
523 }
524
525 EXTERN tdm_error
526 tdm_hwc_set_client_target_acquire_fence(tdm_hwc *hwc, int acquire_fence)
527 {
528         tdm_private_module *private_module;
529         tdm_func_hwc *func_hwc = NULL;
530
531         HWC_FUNC_ENTRY();
532
533         _pthread_mutex_lock(&private_display->lock);
534
535         private_module = private_hwc->private_module;
536         func_hwc = &private_module->func_hwc;
537
538         if (!func_hwc->hwc_set_client_target_acquire_fence) {
539                 /* LCOV_EXCL_START */
540                 _pthread_mutex_unlock(&private_display->lock);
541                 TDM_WRN("not implemented!!");
542                 return TDM_ERROR_NOT_IMPLEMENTED;
543                 /* LCOV_EXCL_STOP */
544         }
545
546         ret = func_hwc->hwc_set_client_target_acquire_fence(private_hwc->hwc_backend, acquire_fence);
547
548         _pthread_mutex_unlock(&private_display->lock);
549
550         return ret;
551 }
552
553 EXTERN tdm_error
554 tdm_hwc_validate(tdm_hwc *hwc, tdm_hwc_window **composited_wnds, uint32_t num_wnds, uint32_t *num_types)
555 {
556         tdm_private_module *private_module;
557         tdm_func_hwc *func_hwc = NULL;
558         tdm_private_hwc_window **composited_wnds_frontend = NULL;
559         tdm_hwc_window **composited_wnds_backend = NULL;
560         int i;
561
562         HWC_FUNC_ENTRY();
563
564         TDM_RETURN_VAL_IF_FAIL(num_types != NULL, TDM_ERROR_INVALID_PARAMETER);
565
566         _pthread_mutex_lock(&private_display->lock);
567
568         private_module = private_hwc->private_module;
569         func_hwc = &private_module->func_hwc;
570
571         if (!func_hwc->hwc_validate) {
572                 /* LCOV_EXCL_START */
573                 _pthread_mutex_unlock(&private_display->lock);
574                 TDM_WRN("not implemented!!");
575                 return TDM_ERROR_NOT_IMPLEMENTED;
576                 /* LCOV_EXCL_STOP */
577         }
578
579         if (num_wnds == 0) {
580                 ret = func_hwc->hwc_validate(private_hwc->hwc_backend, NULL, 0, num_types);
581
582                 _pthread_mutex_unlock(&private_display->lock);
583                 return ret;
584         }
585
586         composited_wnds_backend = calloc(num_wnds, sizeof(tdm_hwc_window *));
587         if (!composited_wnds_backend) {
588                 /* LCOV_EXCL_START */
589                 _pthread_mutex_unlock(&private_display->lock);
590                 return TDM_ERROR_OUT_OF_MEMORY;
591                 /* LCOV_EXCL_STOP */
592         }
593
594         composited_wnds_frontend = (tdm_private_hwc_window **)composited_wnds;
595
596         for (i = 0; i < num_wnds; i++)
597                 composited_wnds_backend[i] = composited_wnds_frontend[i]->hwc_window_backend;
598
599         ret = func_hwc->hwc_validate(private_hwc->hwc_backend, composited_wnds_backend,
600                                                                 num_wnds, num_types);
601
602         free(composited_wnds_backend);
603
604         _pthread_mutex_unlock(&private_display->lock);
605
606         return ret;
607 }
608
609 EXTERN tdm_error
610 tdm_hwc_get_changed_composition_types(tdm_hwc *hwc, uint32_t *num_elements,
611                                                                 tdm_hwc_window **hwc_window,
612                                                                 tdm_hwc_window_composition *composition_types)
613 {
614         tdm_private_module *private_module;
615         tdm_func_hwc *func_hwc = NULL;
616         tdm_private_hwc_window * private_hwc_window = NULL;
617         int i = 0;
618
619         HWC_FUNC_ENTRY();
620
621         TDM_RETURN_VAL_IF_FAIL(num_elements != NULL, TDM_ERROR_INVALID_PARAMETER);
622
623         _pthread_mutex_lock(&private_display->lock);
624
625         private_module = private_hwc->private_module;
626         func_hwc = &private_module->func_hwc;
627
628         if (!func_hwc->hwc_get_changed_composition_types) {
629                 /* LCOV_EXCL_START */
630                 _pthread_mutex_unlock(&private_display->lock);
631                 TDM_WRN("not implemented!!");
632                 return TDM_ERROR_NOT_IMPLEMENTED;
633                 /* LCOV_EXCL_STOP */
634         }
635
636         ret = func_hwc->hwc_get_changed_composition_types(private_hwc->hwc_backend,
637                                                         num_elements, hwc_window, composition_types);
638         if (ret != TDM_ERROR_NONE) {
639                 /* LCOV_EXCL_START */
640                 _pthread_mutex_unlock(&private_display->lock);
641                 return ret;
642                 /* LCOV_EXCL_STOP */
643         }
644
645         if (hwc_window == NULL || composition_types == NULL) {
646                 _pthread_mutex_unlock(&private_display->lock);
647                 return TDM_ERROR_NONE;
648         }
649
650         for (i = 0; i < *num_elements; i++) {
651                 private_hwc_window = _tdm_hwc_find_private_hwc_window(private_hwc, hwc_window[i]);
652                 if (private_hwc_window == NULL) {
653                         /* LCOV_EXCL_START */
654                         TDM_ERR("failed! This should never happen!");
655                         tdm_hwc_window_destroy_internal(private_hwc_window);
656                         *num_elements = 0;
657                         _pthread_mutex_unlock(&private_display->lock);
658                         return TDM_ERROR_OPERATION_FAILED;
659                         /* LCOV_EXCL_STOP */
660                 }
661
662                 hwc_window[i] = (tdm_hwc_window*)private_hwc_window;
663         }
664
665         _pthread_mutex_unlock(&private_display->lock);
666
667         return ret;
668 }
669
670 EXTERN tdm_error
671 tdm_hwc_accept_validation(tdm_hwc *hwc)
672 {
673         tdm_private_module *private_module;
674         tdm_func_hwc *func_hwc = NULL;
675
676         HWC_FUNC_ENTRY();
677
678         _pthread_mutex_lock(&private_display->lock);
679
680         private_module = private_hwc->private_module;
681         func_hwc = &private_module->func_hwc;
682
683         if (!func_hwc->hwc_validate) {
684                 /* LCOV_EXCL_START */
685                 _pthread_mutex_unlock(&private_display->lock);
686                 TDM_WRN("not implemented!!");
687                 return TDM_ERROR_NOT_IMPLEMENTED;
688                 /* LCOV_EXCL_STOP */
689         }
690
691         ret = func_hwc->hwc_accept_validation(private_hwc->hwc_backend);
692
693         _pthread_mutex_unlock(&private_display->lock);
694
695         return ret;
696 }
697
698 EXTERN tdm_error
699 tdm_hwc_commit(tdm_hwc *hwc, int sync, tdm_hwc_commit_handler func, void *user_data)
700 {
701         tdm_private_module *private_module;
702         tdm_func_hwc *func_hwc = NULL;
703         tdm_private_hwc_commit_handler *hwc_commit_handler = NULL;
704         tdm_private_voutput *private_voutput = NULL;
705         tdm_private_voutput_commit_handler *voutput_commit_handler = NULL;
706
707         HWC_FUNC_ENTRY();
708
709         _pthread_mutex_lock(&private_display->lock);
710
711         private_module = private_hwc->private_module;
712         func_hwc = &private_module->func_hwc;
713
714         if (!func_hwc->hwc_commit) {
715                 /* LCOV_EXCL_START */
716                 TDM_WRN("not implemented!!");
717                 _pthread_mutex_unlock(&private_display->lock);
718                 return TDM_ERROR_NOT_IMPLEMENTED;
719                 /* LCOV_EXCL_STOP */
720         }
721
722 //TODO: I am not sure yet whether we have to check the dpms at hwc_commit.
723 #if 0
724         /* check if the dpms is off */
725         if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->current_dpms_value)) {
726                 TDM_ERR("hwc(%d) dpms: %s", private_hwc->index,
727                                 tdm_dpms_str(private_output->current_dpms_value));
728                 _pthread_mutex_unlock(&private_display->lock);
729                 return TDM_ERROR_DPMS_OFF;
730         }
731 #endif
732
733         if (tdm_debug_module & TDM_DEBUG_COMMIT)
734                 TDM_INFO("hwc(%d) commit", private_hwc->index);
735
736         if (private_module == private_display->virtual_module) {
737                 if (!private_output->private_voutput) {
738                         TDM_ERR("virtual module but don't have voutput");
739                         _pthread_mutex_unlock(&private_display->lock);
740                         return TDM_ERROR_BAD_MODULE;
741                 }
742         }
743
744         if (!private_hwc->regist_commit_cb) {
745                 private_hwc->regist_commit_cb = 1;
746                 ret = func_hwc->hwc_set_commit_handler(private_hwc->hwc_backend, _tdm_hwc_cb_commit);
747                 /* LCOV_EXCL_START */
748                 if (ret != TDM_ERROR_NONE) {
749                         private_hwc->regist_commit_cb = 0;
750                         TDM_ERR("hwc(%d) fail to set hwc_set_commit_handler", private_hwc->index);
751                         _pthread_mutex_unlock(&private_display->lock);
752                         return ret;
753                 /* LCOV_EXCL_STOP */
754                 }
755         }
756
757         hwc_commit_handler = calloc(1, sizeof(tdm_private_hwc_commit_handler));
758         if (!hwc_commit_handler) {
759                 /* LCOV_EXCL_START */
760                 TDM_ERR("failed: alloc memory");
761                 _pthread_mutex_unlock(&private_display->lock);
762                 return TDM_ERROR_OUT_OF_MEMORY;
763                 /* LCOV_EXCL_STOP */
764         }
765
766         ret = tdm_thread_cb_add(private_hwc, TDM_THREAD_CB_HWC_COMMIT, hwc_commit_handler,
767                                         _tdm_hwc_thread_cb_commit, NULL);
768         if (ret != TDM_ERROR_NONE) {
769                 TDM_ERR("tdm_thread_cb_add failed");
770                 free(hwc_commit_handler);
771                 _pthread_mutex_unlock(&private_display->lock);
772                 return ret;
773         }
774
775         LIST_ADDTAIL(&hwc_commit_handler->link, &private_hwc->hwc_commit_handler_list);
776         hwc_commit_handler->private_hwc = private_hwc;
777         hwc_commit_handler->func = func;
778         hwc_commit_handler->user_data = user_data;
779         hwc_commit_handler->owner_tid = syscall(SYS_gettid);
780         if (hwc_use_vblank)
781                 hwc_commit_handler->use_vblank = 1;
782
783         if (private_module == private_display->virtual_module) {
784                 private_voutput = private_output->private_voutput;
785
786                 if (LIST_LENGTH(&private_voutput->voutput_commit_handler_list) != 0) {
787                         voutput_commit_handler = LIST_FIRST_ENTRY(&private_voutput->voutput_commit_handler_list, tdm_private_voutput_commit_handler, link);
788                         voutput_commit_handler->user_data = private_hwc->display_target_buffer;
789                 }
790         }
791
792         ret = func_hwc->hwc_commit(private_hwc->hwc_backend, sync, hwc_commit_handler);
793         TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed);
794
795         if (hwc_use_vblank) {
796                 ret = _tdm_hwc_vblank(private_hwc, hwc_commit_handler);
797                 if (ret == TDM_ERROR_NONE) {
798                         if (tdm_debug_module & TDM_DEBUG_COMMIT)
799                                 TDM_INFO("hwc(%d) backend commit: wait vblank handle(%p) func(%p) user_data(%p)",
800                                         private_hwc->index, hwc_commit_handler, func, user_data);
801                 } else
802                         goto commit_failed;
803         } else {
804                 if (tdm_debug_module & TDM_DEBUG_COMMIT)
805                         TDM_INFO("hwc(%d) backend commit: handle(%p) func(%p) user_data(%p)",
806                                         private_hwc->index, hwc_commit_handler, func, user_data);
807         }
808
809         _pthread_mutex_unlock(&private_display->lock);
810
811         return ret;
812
813 commit_failed:
814         /* LCOV_EXCL_START */
815         if (hwc_commit_handler) {
816                 tdm_thread_cb_remove(private_hwc, TDM_THREAD_CB_HWC_COMMIT, hwc_commit_handler,
817                                                 _tdm_hwc_thread_cb_commit, NULL);
818                 LIST_DEL(&hwc_commit_handler->link);
819                 free(hwc_commit_handler);
820         }
821
822         _pthread_mutex_unlock(&private_display->lock);
823
824         return ret;
825         /* LCOV_EXCL_STOP */
826 }
827
828 EXTERN tdm_error
829 tdm_hwc_get_commit_fence(tdm_hwc *hwc, int *commit_fence)
830 {
831         tdm_private_module *private_module;
832         tdm_func_hwc *func_hwc = NULL;
833
834         HWC_FUNC_ENTRY();
835
836         _pthread_mutex_lock(&private_display->lock);
837
838         private_module = private_hwc->private_module;
839         func_hwc = &private_module->func_hwc;
840
841         if (!func_hwc->hwc_get_commit_fence) {
842                 /* LCOV_EXCL_START */
843                 _pthread_mutex_unlock(&private_display->lock);
844                 TDM_WRN("not implemented!!");
845                 return TDM_ERROR_NOT_IMPLEMENTED;
846                 /* LCOV_EXCL_STOP */
847         }
848
849         ret = func_hwc->hwc_get_commit_fence(private_hwc->hwc_backend, commit_fence);
850
851         _pthread_mutex_unlock(&private_display->lock);
852
853         return ret;
854 }
855
856 EXTERN tdm_error
857 tdm_hwc_get_release_fences(tdm_hwc *hwc, uint32_t *num_elements,
858                                                 tdm_hwc_window **hwc_windows, int *fences)
859 {
860         tdm_private_module *private_module;
861         tdm_func_hwc *func_hwc = NULL;
862         tdm_private_hwc_window *private_hwc_window = NULL;
863         int i;
864
865         HWC_FUNC_ENTRY();
866
867         _pthread_mutex_lock(&private_display->lock);
868
869         private_module = private_hwc->private_module;
870         func_hwc = &private_module->func_hwc;
871
872         if (!func_hwc->hwc_get_release_fences) {
873                 /* LCOV_EXCL_START */
874                 _pthread_mutex_unlock(&private_display->lock);
875                 TDM_WRN("not implemented!!");
876                 return TDM_ERROR_NOT_IMPLEMENTED;
877                 /* LCOV_EXCL_STOP */
878         }
879
880         ret = func_hwc->hwc_get_release_fences(private_hwc->hwc_backend, num_elements,
881                                                                                 hwc_windows, fences);
882
883         if (hwc_windows == NULL || fences == NULL) {
884                 _pthread_mutex_unlock(&private_display->lock);
885                 return TDM_ERROR_NONE;
886         }
887
888         for (i = 0; i < *num_elements; i++) {
889                 private_hwc_window = _tdm_hwc_find_private_hwc_window(private_hwc, hwc_windows[i]);
890                 if (private_hwc_window == NULL) {
891                         /* LCOV_EXCL_START */
892                         TDM_ERR("failed! This should never happen!");
893                         tdm_hwc_window_destroy_internal(private_hwc_window);
894                         *num_elements = 0;
895                         _pthread_mutex_unlock(&private_display->lock);
896                         return TDM_ERROR_OPERATION_FAILED;
897                         /* LCOV_EXCL_STOP */
898                 }
899
900                 hwc_windows[i] = (tdm_hwc_window*)private_hwc_window;
901         }
902
903         _pthread_mutex_unlock(&private_display->lock);
904
905         return ret;
906 }
907
908 tdm_error
909 tdm_hwc_set_property(tdm_hwc *hwc, uint32_t id, tdm_value value)
910 {
911         tdm_private_module *private_module;
912         tdm_func_hwc *func_hwc = NULL;
913
914         HWC_FUNC_ENTRY();
915
916         _pthread_mutex_lock(&private_display->lock);
917
918         private_module = private_hwc->private_module;
919         func_hwc = &private_module->func_hwc;
920
921         if (!func_hwc->hwc_set_property) {
922                 /* LCOV_EXCL_START */
923                 _pthread_mutex_unlock(&private_display->lock);
924                 TDM_WRN("not implemented!!");
925                 return TDM_ERROR_NOT_IMPLEMENTED;
926                 /* LCOV_EXCL_STOP */
927         }
928
929         ret = func_hwc->hwc_set_property(private_hwc->hwc_backend, id, value);
930
931         _pthread_mutex_unlock(&private_display->lock);
932
933         return ret;
934 }
935
936 tdm_error
937 tdm_hwc_get_property(tdm_hwc *hwc, uint32_t id, tdm_value *value)
938 {
939         tdm_private_module *private_module;
940         tdm_func_hwc *func_hwc = NULL;
941
942         HWC_FUNC_ENTRY();
943
944         _pthread_mutex_lock(&private_display->lock);
945
946         private_module = private_hwc->private_module;
947         func_hwc = &private_module->func_hwc;
948
949         if (!func_hwc->hwc_get_property) {
950                 /* LCOV_EXCL_START */
951                 _pthread_mutex_unlock(&private_display->lock);
952                 TDM_WRN("not implemented!!");
953                 return TDM_ERROR_NOT_IMPLEMENTED;
954                 /* LCOV_EXCL_STOP */
955         }
956
957         ret = func_hwc->hwc_get_property(private_hwc->hwc_backend, id, value);
958
959         _pthread_mutex_unlock(&private_display->lock);
960
961         return ret;
962 }