tdm_hwc: change use_vblank and layer_waiting_vblank flag setting 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 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         TDM_RETURN_IF_FAIL(hwc_commit_handler->private_hwc != NULL);
216
217         private_output = hwc_commit_handler->private_hwc->private_output;
218         TDM_RETURN_IF_FAIL(private_output != NULL);
219
220         private_display = private_output->private_display;
221
222         _pthread_mutex_lock(&private_display->lock);
223
224         _tdm_hwc_got_wait_vblank(sequence, tv_sec, tv_usec, user_data);
225
226         _pthread_mutex_unlock(&private_display->lock);
227 }
228
229 static tdm_error
230 _tdm_hwc_vblank(tdm_private_hwc *private_hwc, tdm_private_hwc_commit_handler *hwc_commit_handler)
231 {
232         tdm_private_display *private_display;
233         tdm_private_output *private_output;
234         tdm_error ret = TDM_ERROR_NONE;
235
236         private_output = private_hwc->private_output;
237         TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_INVALID_PARAMETER);
238         private_display = private_output->private_display;
239
240         if (!private_output->vblank) {
241                 /* tdm_vblank APIs is for server. it should be called in unlock status*/
242                 _pthread_mutex_unlock(&private_display->lock);
243                 private_output->vblank = tdm_vblank_create(private_display, private_output, NULL);
244                 _pthread_mutex_lock(&private_display->lock);
245                 TDM_RETURN_VAL_IF_FAIL(private_output->vblank != NULL, TDM_ERROR_OPERATION_FAILED);
246         }
247
248         if (!private_output->layer_waiting_vblank) {
249                 ret = tdm_vblank_set_fps(private_output->vblank, hwc_vblank_fps);
250                 if (ret != TDM_ERROR_NONE)
251                         goto done;
252
253                 hwc_commit_handler->use_vblank = 1;
254                 private_output->layer_waiting_vblank = 1;
255
256                 /* tdm_vblank APIs is for server. it should be called in unlock status*/
257                 _pthread_mutex_unlock(&private_display->lock);
258                 ret = tdm_vblank_wait(private_output->vblank, 0, 0, 1, _tdm_hwc_cb_wait_vblank, hwc_commit_handler);
259                 _pthread_mutex_lock(&private_display->lock);
260                 if (ret != TDM_ERROR_NONE) {
261                         if (!TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->current_dpms_value)) {
262                                 hwc_commit_handler->use_vblank = 0;
263                                 private_output->layer_waiting_vblank = 0;
264                         }
265                 }
266         }
267
268 done:
269         return ret;
270 }
271
272 INTERN tdm_error
273 tdm_hwc_init(tdm_private_display *private_display)
274 {
275         tdm_thread_cb_set_find_func(TDM_THREAD_CB_HWC_COMMIT, tdm_display_find_hwc_stamp);
276
277         return TDM_ERROR_NONE;
278 }
279
280 INTERN void
281 tdm_hwc_set_vblank(unsigned int fps)
282 {
283         hwc_use_vblank = 1;
284         hwc_vblank_fps = fps;
285 }
286
287 INTERN void
288 tdm_hwc_unset_vblank(void)
289 {
290         hwc_use_vblank = 0;
291         hwc_vblank_fps = 0;
292 }
293
294 EXTERN tdm_hwc_window *
295 tdm_hwc_create_window(tdm_hwc *hwc, tdm_error *error)
296 {
297         tdm_hwc_window *hwc_window = NULL;
298
299         HWC_FUNC_ENTRY_ERROR();
300
301         _pthread_mutex_lock(&private_display->lock);
302
303         hwc_window = (tdm_hwc_window *)tdm_hwc_window_create_internal(private_hwc, error);
304
305         _pthread_mutex_unlock(&private_display->lock);
306
307         return hwc_window;
308 }
309
310 EXTERN tdm_error
311 tdm_hwc_get_video_supported_formats(tdm_hwc *hwc, const tbm_format **formats, int *count)
312 {
313         tdm_private_module *private_module;
314         tdm_func_hwc *func_hwc;
315
316         HWC_FUNC_ENTRY();
317
318         TDM_RETURN_VAL_IF_FAIL(formats != NULL, TDM_ERROR_INVALID_PARAMETER);
319         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
320
321         _pthread_mutex_lock(&private_display->lock);
322
323         private_module = private_output->private_module;
324         func_hwc = &private_module->func_hwc;
325
326         if (!func_hwc->hwc_get_video_supported_formats) {
327                 /* LCOV_EXCL_START */
328                 _pthread_mutex_unlock(&private_display->lock);
329                 TDM_WRN("not implemented!!");
330                 return TDM_ERROR_NOT_IMPLEMENTED;
331                 /* LCOV_EXCL_STOP */
332         }
333
334         ret = func_hwc->hwc_get_video_supported_formats(private_hwc->hwc_backend, formats, count);
335
336         _pthread_mutex_unlock(&private_display->lock);
337
338         return ret;
339 }
340
341 EXTERN tdm_error
342 tdm_hwc_get_video_available_properties(tdm_hwc *hwc, const tdm_prop **props, int *count)
343 {
344         tdm_private_module *private_module;
345         tdm_func_hwc *func_hwc = NULL;
346
347         HWC_FUNC_ENTRY();
348
349         TDM_RETURN_VAL_IF_FAIL(props != NULL, TDM_ERROR_INVALID_PARAMETER);
350         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
351
352         _pthread_mutex_lock(&private_display->lock);
353
354         private_module = private_output->private_module;
355         func_hwc = &private_module->func_hwc;
356
357         if (!func_hwc->hwc_get_video_available_properties) {
358                 /* LCOV_EXCL_START */
359                 _pthread_mutex_unlock(&private_display->lock);
360                 TDM_WRN("not implemented!!");
361                 return TDM_ERROR_NOT_IMPLEMENTED;
362                 /* LCOV_EXCL_STOP */
363         }
364
365         ret = func_hwc->hwc_get_video_available_properties(private_hwc->hwc_backend, props, count);
366
367         _pthread_mutex_unlock(&private_display->lock);
368
369         return ret;
370 }
371
372 EXTERN tdm_error
373 tdm_hwc_get_capabilities(tdm_hwc *hwc, tdm_hwc_capability *capabilities)
374 {
375         tdm_private_module *private_module;
376         tdm_func_hwc *func_hwc;
377
378         HWC_FUNC_ENTRY();
379
380         _pthread_mutex_lock(&private_display->lock);
381
382         private_module = private_output->private_module;
383         func_hwc = &private_module->func_hwc;
384
385         if (!func_hwc->hwc_get_capabilities) {
386                 _pthread_mutex_unlock(&private_display->lock);
387                 TDM_WRN("not implemented!!");
388                 return TDM_ERROR_NOT_IMPLEMENTED;
389         }
390
391         ret = func_hwc->hwc_get_capabilities(private_hwc->hwc_backend, capabilities);
392
393         _pthread_mutex_unlock(&private_display->lock);
394
395         return ret;
396 }
397
398 EXTERN tdm_error
399 tdm_hwc_get_available_properties(tdm_hwc *hwc, const tdm_prop **props, int *count)
400 {
401         tdm_private_module *private_module;
402         tdm_func_hwc *func_hwc = NULL;
403
404         HWC_FUNC_ENTRY();
405
406         TDM_RETURN_VAL_IF_FAIL(props != NULL, TDM_ERROR_INVALID_PARAMETER);
407         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
408
409         _pthread_mutex_lock(&private_display->lock);
410
411         private_module = private_output->private_module;
412         func_hwc = &private_module->func_hwc;
413
414         if (!func_hwc->hwc_get_available_properties) {
415                 /* LCOV_EXCL_START */
416                 _pthread_mutex_unlock(&private_display->lock);
417                 TDM_WRN("not implemented!!");
418                 return TDM_ERROR_NOT_IMPLEMENTED;
419                 /* LCOV_EXCL_STOP */
420         }
421
422         ret = func_hwc->hwc_get_available_properties(private_hwc->hwc_backend, props, count);
423
424         _pthread_mutex_unlock(&private_display->lock);
425
426         return ret;
427 }
428
429 EXTERN tbm_surface_queue_h
430 tdm_hwc_get_client_target_buffer_queue(tdm_hwc *hwc, tdm_error *error)
431 {
432         tdm_private_module *private_module;
433         tdm_func_hwc *func_hwc = NULL;
434         tbm_surface_queue_h queue = NULL;
435
436         HWC_FUNC_ENTRY_ERROR();
437
438         _pthread_mutex_lock(&private_display->lock);
439
440         private_module = private_hwc->private_module;
441         func_hwc = &private_module->func_hwc;
442
443         if (!func_hwc->hwc_get_client_target_buffer_queue) {
444                 /* LCOV_EXCL_START */
445                 _pthread_mutex_unlock(&private_display->lock);
446                 TDM_WRN("not implemented!!");
447                 return NULL;
448                 /* LCOV_EXCL_STOP */
449         }
450
451         queue = func_hwc->hwc_get_client_target_buffer_queue(private_hwc->hwc_backend, error);
452
453         _pthread_mutex_unlock(&private_display->lock);
454
455         return queue;
456 }
457
458 EXTERN tdm_error
459 tdm_hwc_set_client_target_buffer(tdm_hwc *hwc, tbm_surface_h target_buffer, tdm_region damage)
460 {
461         tdm_private_module *private_module;
462         tdm_func_hwc *func_hwc = NULL;
463
464         HWC_FUNC_ENTRY();
465
466         _pthread_mutex_lock(&private_display->lock);
467
468         if (tdm_debug_dump & TDM_DUMP_FLAG_WINDOW) {
469                 /* LCOV_EXCL_START */
470                 char str[TDM_PATH_LEN];
471                 static int i;
472                 snprintf(str, TDM_PATH_LEN, "target_window_%03d", i++);
473                 tdm_helper_dump_buffer_str(target_buffer, tdm_debug_dump_dir, str);
474                 /* LCOV_EXCL_STOP */
475         }
476
477         private_module = private_hwc->private_module;
478         func_hwc = &private_module->func_hwc;
479
480         if (!func_hwc->hwc_set_client_target_buffer) {
481                 /* LCOV_EXCL_START */
482                 _pthread_mutex_unlock(&private_display->lock);
483                 TDM_WRN("not implemented!!");
484                 return TDM_ERROR_NOT_IMPLEMENTED;
485                 /* LCOV_EXCL_STOP */
486         }
487
488         ret = func_hwc->hwc_set_client_target_buffer(private_hwc->hwc_backend, target_buffer, damage);
489
490         if (private_hwc->display_target_buffer) {
491                 if (private_hwc->display_target_buffer != target_buffer) {
492                         tbm_surface_internal_unref(private_hwc->display_target_buffer);
493                         private_hwc->display_target_buffer = target_buffer;
494                         if (target_buffer)
495                                 tbm_surface_internal_ref(private_hwc->display_target_buffer);
496                 }
497         } else {
498                 if (target_buffer) {
499                         private_hwc->display_target_buffer = target_buffer;
500                         tbm_surface_internal_ref(private_hwc->display_target_buffer);
501                 }
502         }
503
504         _pthread_mutex_unlock(&private_display->lock);
505
506         return ret;
507 }
508
509
510 EXTERN tdm_error
511 tdm_hwc_validate(tdm_hwc *hwc, tdm_hwc_window **composited_wnds, uint32_t num_wnds, uint32_t *num_types)
512 {
513         tdm_private_module *private_module;
514         tdm_func_hwc *func_hwc = NULL;
515         tdm_private_hwc_window **composited_wnds_frontend = NULL;
516         tdm_hwc_window **composited_wnds_backend = NULL;
517         int i;
518
519         HWC_FUNC_ENTRY();
520
521         TDM_RETURN_VAL_IF_FAIL(num_types != NULL, TDM_ERROR_INVALID_PARAMETER);
522
523         _pthread_mutex_lock(&private_display->lock);
524
525         private_module = private_hwc->private_module;
526         func_hwc = &private_module->func_hwc;
527
528         if (!func_hwc->hwc_validate) {
529                 /* LCOV_EXCL_START */
530                 _pthread_mutex_unlock(&private_display->lock);
531                 TDM_WRN("not implemented!!");
532                 return TDM_ERROR_NOT_IMPLEMENTED;
533                 /* LCOV_EXCL_STOP */
534         }
535
536         if (num_wnds == 0) {
537                 ret = func_hwc->hwc_validate(private_hwc->hwc_backend, NULL, 0, num_types);
538
539                 _pthread_mutex_unlock(&private_display->lock);
540                 return ret;
541         }
542
543         composited_wnds_backend = calloc(num_wnds, sizeof(tdm_hwc_window *));
544         if (!composited_wnds_backend) {
545                 /* LCOV_EXCL_START */
546                 _pthread_mutex_unlock(&private_display->lock);
547                 return TDM_ERROR_OUT_OF_MEMORY;
548                 /* LCOV_EXCL_STOP */
549         }
550
551         composited_wnds_frontend = (tdm_private_hwc_window **)composited_wnds;
552
553         for (i = 0; i < num_wnds; i++)
554                 composited_wnds_backend[i] = composited_wnds_frontend[i]->hwc_window_backend;
555
556         ret = func_hwc->hwc_validate(private_hwc->hwc_backend, composited_wnds_backend,
557                                                                 num_wnds, num_types);
558
559         free(composited_wnds_backend);
560
561         _pthread_mutex_unlock(&private_display->lock);
562
563         return ret;
564 }
565
566 EXTERN tdm_error
567 tdm_hwc_get_changed_composition_types(tdm_hwc *hwc, uint32_t *num_elements,
568                                                                 tdm_hwc_window **hwc_window,
569                                                                 tdm_hwc_window_composition *composition_types)
570 {
571         tdm_private_module *private_module;
572         tdm_func_hwc *func_hwc = NULL;
573         tdm_private_hwc_window * private_hwc_window = NULL;
574         int i = 0;
575
576         HWC_FUNC_ENTRY();
577
578         TDM_RETURN_VAL_IF_FAIL(num_elements != NULL, TDM_ERROR_INVALID_PARAMETER);
579
580         _pthread_mutex_lock(&private_display->lock);
581
582         private_module = private_hwc->private_module;
583         func_hwc = &private_module->func_hwc;
584
585         if (!func_hwc->hwc_get_changed_composition_types) {
586                 /* LCOV_EXCL_START */
587                 _pthread_mutex_unlock(&private_display->lock);
588                 TDM_WRN("not implemented!!");
589                 return TDM_ERROR_NOT_IMPLEMENTED;
590                 /* LCOV_EXCL_STOP */
591         }
592
593         ret = func_hwc->hwc_get_changed_composition_types(private_hwc->hwc_backend,
594                                                         num_elements, hwc_window, composition_types);
595         if (ret != TDM_ERROR_NONE) {
596                 /* LCOV_EXCL_START */
597                 _pthread_mutex_unlock(&private_display->lock);
598                 return ret;
599                 /* LCOV_EXCL_STOP */
600         }
601
602         if (hwc_window == NULL || composition_types == NULL) {
603                 _pthread_mutex_unlock(&private_display->lock);
604                 return TDM_ERROR_NONE;
605         }
606
607         for (i = 0; i < *num_elements; i++) {
608                 private_hwc_window = _tdm_hwc_find_private_hwc_window(private_hwc, hwc_window[i]);
609                 if (private_hwc_window == NULL) {
610                         /* LCOV_EXCL_START */
611                         TDM_ERR("failed! This should never happen!");
612                         tdm_hwc_window_destroy_internal(private_hwc_window);
613                         *num_elements = 0;
614                         _pthread_mutex_unlock(&private_display->lock);
615                         return TDM_ERROR_OPERATION_FAILED;
616                         /* LCOV_EXCL_STOP */
617                 }
618
619                 hwc_window[i] = (tdm_hwc_window*)private_hwc_window;
620         }
621
622         _pthread_mutex_unlock(&private_display->lock);
623
624         return ret;
625 }
626
627 EXTERN tdm_error
628 tdm_hwc_accept_validation(tdm_hwc *hwc)
629 {
630         tdm_private_module *private_module;
631         tdm_func_hwc *func_hwc = NULL;
632
633         HWC_FUNC_ENTRY();
634
635         _pthread_mutex_lock(&private_display->lock);
636
637         private_module = private_hwc->private_module;
638         func_hwc = &private_module->func_hwc;
639
640         if (!func_hwc->hwc_validate) {
641                 /* LCOV_EXCL_START */
642                 _pthread_mutex_unlock(&private_display->lock);
643                 TDM_WRN("not implemented!!");
644                 return TDM_ERROR_NOT_IMPLEMENTED;
645                 /* LCOV_EXCL_STOP */
646         }
647
648         ret = func_hwc->hwc_accept_validation(private_hwc->hwc_backend);
649
650         _pthread_mutex_unlock(&private_display->lock);
651
652         return ret;
653 }
654
655 EXTERN tdm_error
656 tdm_hwc_commit(tdm_hwc *hwc, int sync, tdm_hwc_commit_handler func, void *user_data)
657 {
658         tdm_private_module *private_module;
659         tdm_func_hwc *func_hwc = NULL;
660         tdm_private_hwc_commit_handler *hwc_commit_handler = NULL;
661         tdm_private_voutput *private_voutput = NULL;
662         tdm_private_voutput_commit_handler *voutput_commit_handler = NULL;
663
664         HWC_FUNC_ENTRY();
665
666         _pthread_mutex_lock(&private_display->lock);
667
668         private_module = private_hwc->private_module;
669         func_hwc = &private_module->func_hwc;
670
671         if (!func_hwc->hwc_commit) {
672                 /* LCOV_EXCL_START */
673                 TDM_WRN("not implemented!!");
674                 _pthread_mutex_unlock(&private_display->lock);
675                 return TDM_ERROR_NOT_IMPLEMENTED;
676                 /* LCOV_EXCL_STOP */
677         }
678
679 //TODO: I am not sure yet whether we have to check the dpms at hwc_commit.
680 #if 0
681         /* check if the dpms is off */
682         if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->current_dpms_value)) {
683                 TDM_ERR("hwc(%d) dpms: %s", private_hwc->index,
684                                 tdm_dpms_str(private_output->current_dpms_value));
685                 _pthread_mutex_unlock(&private_display->lock);
686                 return TDM_ERROR_DPMS_OFF;
687         }
688 #endif
689
690         if (tdm_debug_module & TDM_DEBUG_COMMIT)
691                 TDM_INFO("hwc(%d) commit", private_hwc->index);
692
693         if (private_module == private_display->virtual_module) {
694                 if (!private_output->private_voutput) {
695                         TDM_ERR("virtual module but don't have voutput");
696                         _pthread_mutex_unlock(&private_display->lock);
697                         return TDM_ERROR_BAD_MODULE;
698                 }
699         }
700
701         if (!private_hwc->regist_commit_cb) {
702                 private_hwc->regist_commit_cb = 1;
703                 ret = func_hwc->hwc_set_commit_handler(private_hwc->hwc_backend, _tdm_hwc_cb_commit);
704                 /* LCOV_EXCL_START */
705                 if (ret != TDM_ERROR_NONE) {
706                         private_hwc->regist_commit_cb = 0;
707                         TDM_ERR("hwc(%d) fail to set hwc_set_commit_handler", private_hwc->index);
708                         _pthread_mutex_unlock(&private_display->lock);
709                         return ret;
710                 /* LCOV_EXCL_STOP */
711                 }
712         }
713
714         hwc_commit_handler = calloc(1, sizeof(tdm_private_hwc_commit_handler));
715         if (!hwc_commit_handler) {
716                 /* LCOV_EXCL_START */
717                 TDM_ERR("failed: alloc memory");
718                 _pthread_mutex_unlock(&private_display->lock);
719                 return TDM_ERROR_OUT_OF_MEMORY;
720                 /* LCOV_EXCL_STOP */
721         }
722
723         ret = tdm_thread_cb_add(private_hwc, TDM_THREAD_CB_HWC_COMMIT, hwc_commit_handler,
724                                         _tdm_hwc_thread_cb_commit, NULL);
725         if (ret != TDM_ERROR_NONE) {
726                 TDM_ERR("tdm_thread_cb_add failed");
727                 free(hwc_commit_handler);
728                 _pthread_mutex_unlock(&private_display->lock);
729                 return ret;
730         }
731
732         LIST_ADDTAIL(&hwc_commit_handler->link, &private_hwc->hwc_commit_handler_list);
733         hwc_commit_handler->private_hwc = private_hwc;
734         hwc_commit_handler->func = func;
735         hwc_commit_handler->user_data = user_data;
736         hwc_commit_handler->owner_tid = syscall(SYS_gettid);
737
738         if (private_module == private_display->virtual_module) {
739                 private_voutput = private_output->private_voutput;
740
741                 if (LIST_LENGTH(&private_voutput->voutput_commit_handler_list) != 0) {
742                         voutput_commit_handler = LIST_FIRST_ENTRY(&private_voutput->voutput_commit_handler_list, tdm_private_voutput_commit_handler, link);
743                         voutput_commit_handler->user_data = private_hwc->display_target_buffer;
744                 }
745         }
746
747         ret = func_hwc->hwc_commit(private_hwc->hwc_backend, sync, hwc_commit_handler);
748         TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, commit_failed);
749
750         if (hwc_use_vblank) {
751                 ret = _tdm_hwc_vblank(private_hwc, hwc_commit_handler);
752                 if (ret == TDM_ERROR_NONE) {
753                         if (tdm_debug_module & TDM_DEBUG_COMMIT)
754                                 TDM_INFO("hwc(%d) backend commit: wait vblank handle(%p) func(%p) user_data(%p)",
755                                         private_hwc->index, hwc_commit_handler, func, user_data);
756                 } else
757                         goto commit_failed;
758         } else {
759                 if (tdm_debug_module & TDM_DEBUG_COMMIT)
760                         TDM_INFO("hwc(%d) backend commit: handle(%p) func(%p) user_data(%p)",
761                                         private_hwc->index, hwc_commit_handler, func, user_data);
762         }
763
764         _pthread_mutex_unlock(&private_display->lock);
765
766         return ret;
767
768 commit_failed:
769         /* LCOV_EXCL_START */
770         if (hwc_commit_handler) {
771                 tdm_thread_cb_remove(private_hwc, TDM_THREAD_CB_HWC_COMMIT, hwc_commit_handler,
772                                                 _tdm_hwc_thread_cb_commit, NULL);
773                 LIST_DEL(&hwc_commit_handler->link);
774                 free(hwc_commit_handler);
775         }
776
777         _pthread_mutex_unlock(&private_display->lock);
778
779         return ret;
780         /* LCOV_EXCL_STOP */
781 }
782
783 tdm_error
784 tdm_hwc_set_property(tdm_hwc *hwc, uint32_t id, tdm_value value)
785 {
786         tdm_private_module *private_module;
787         tdm_func_hwc *func_hwc = NULL;
788
789         HWC_FUNC_ENTRY();
790
791         _pthread_mutex_lock(&private_display->lock);
792
793         private_module = private_hwc->private_module;
794         func_hwc = &private_module->func_hwc;
795
796         if (!func_hwc->hwc_set_property) {
797                 /* LCOV_EXCL_START */
798                 _pthread_mutex_unlock(&private_display->lock);
799                 TDM_WRN("not implemented!!");
800                 return TDM_ERROR_NOT_IMPLEMENTED;
801                 /* LCOV_EXCL_STOP */
802         }
803
804         ret = func_hwc->hwc_set_property(private_hwc->hwc_backend, id, value);
805
806         _pthread_mutex_unlock(&private_display->lock);
807
808         return ret;
809 }
810
811 tdm_error
812 tdm_hwc_get_property(tdm_hwc *hwc, uint32_t id, tdm_value *value)
813 {
814         tdm_private_module *private_module;
815         tdm_func_hwc *func_hwc = NULL;
816
817         HWC_FUNC_ENTRY();
818
819         _pthread_mutex_lock(&private_display->lock);
820
821         private_module = private_hwc->private_module;
822         func_hwc = &private_module->func_hwc;
823
824         if (!func_hwc->hwc_get_property) {
825                 /* LCOV_EXCL_START */
826                 _pthread_mutex_unlock(&private_display->lock);
827                 TDM_WRN("not implemented!!");
828                 return TDM_ERROR_NOT_IMPLEMENTED;
829                 /* LCOV_EXCL_STOP */
830         }
831
832         ret = func_hwc->hwc_get_property(private_hwc->hwc_backend, id, value);
833
834         _pthread_mutex_unlock(&private_display->lock);
835
836         return ret;
837 }