Merge branch 'tizen' into sandbox/cyeon/devel
[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                 hwc_commit_handler->use_vblank = 1;
272                 private_output->layer_waiting_vblank = 1;
273
274                 /* tdm_vblank APIs is for server. it should be called in unlock status*/
275                 _pthread_mutex_unlock(&private_display->lock);
276                 ret = tdm_vblank_wait(private_output->vblank, 0, 0, 1, _tdm_hwc_cb_wait_vblank, hwc_commit_handler);
277                 _pthread_mutex_lock(&private_display->lock);
278                 if (ret != TDM_ERROR_NONE) {
279                         if (!TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->current_dpms_value)) {
280                                 hwc_commit_handler->use_vblank = 0;
281                                 private_output->layer_waiting_vblank = 0;
282                         }
283                 }
284         }
285
286 done:
287         return ret;
288 }
289
290 INTERN tdm_error
291 tdm_hwc_init(tdm_private_display *private_display)
292 {
293         tdm_thread_cb_set_find_func(TDM_THREAD_CB_HWC_COMMIT, tdm_display_find_hwc_stamp);
294
295         return TDM_ERROR_NONE;
296 }
297
298 INTERN void
299 tdm_hwc_set_vblank(unsigned int fps)
300 {
301         hwc_use_vblank = 1;
302         hwc_vblank_fps = fps;
303 }
304
305 INTERN void
306 tdm_hwc_unset_vblank(void)
307 {
308         hwc_use_vblank = 0;
309         hwc_vblank_fps = 0;
310 }
311
312 EXTERN tdm_hwc_window *
313 tdm_hwc_create_window(tdm_hwc *hwc, tdm_error *error)
314 {
315         tdm_hwc_window *hwc_window = NULL;
316
317         HWC_FUNC_ENTRY_ERROR();
318
319         _pthread_mutex_lock(&private_display->lock);
320
321         hwc_window = (tdm_hwc_window *)tdm_hwc_window_create_internal(private_hwc, error);
322
323         _pthread_mutex_unlock(&private_display->lock);
324
325         return hwc_window;
326 }
327
328 EXTERN tdm_error
329 tdm_hwc_get_video_supported_formats(tdm_hwc *hwc, const tbm_format **formats, int *count)
330 {
331         tdm_private_module *private_module;
332         tdm_func_hwc *func_hwc;
333
334         HWC_FUNC_ENTRY();
335
336         TDM_RETURN_VAL_IF_FAIL(formats != NULL, TDM_ERROR_INVALID_PARAMETER);
337         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
338
339         _pthread_mutex_lock(&private_display->lock);
340
341         private_module = private_output->private_module;
342         func_hwc = &private_module->func_hwc;
343
344         if (!func_hwc->hwc_get_video_supported_formats) {
345                 /* LCOV_EXCL_START */
346                 _pthread_mutex_unlock(&private_display->lock);
347                 TDM_WRN("not implemented!!");
348                 return TDM_ERROR_NOT_IMPLEMENTED;
349                 /* LCOV_EXCL_STOP */
350         }
351
352         ret = func_hwc->hwc_get_video_supported_formats(private_hwc->hwc_backend, formats, count);
353
354         _pthread_mutex_unlock(&private_display->lock);
355
356         return ret;
357 }
358
359 EXTERN tdm_error
360 tdm_hwc_get_video_available_properties(tdm_hwc *hwc, const tdm_prop **props, int *count)
361 {
362         tdm_private_module *private_module;
363         tdm_func_hwc *func_hwc = NULL;
364
365         HWC_FUNC_ENTRY();
366
367         TDM_RETURN_VAL_IF_FAIL(props != NULL, TDM_ERROR_INVALID_PARAMETER);
368         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
369
370         _pthread_mutex_lock(&private_display->lock);
371
372         private_module = private_output->private_module;
373         func_hwc = &private_module->func_hwc;
374
375         if (!func_hwc->hwc_get_video_available_properties) {
376                 /* LCOV_EXCL_START */
377                 _pthread_mutex_unlock(&private_display->lock);
378                 TDM_WRN("not implemented!!");
379                 return TDM_ERROR_NOT_IMPLEMENTED;
380                 /* LCOV_EXCL_STOP */
381         }
382
383         ret = func_hwc->hwc_get_video_available_properties(private_hwc->hwc_backend, props, count);
384
385         _pthread_mutex_unlock(&private_display->lock);
386
387         return ret;
388 }
389
390 EXTERN tdm_error
391 tdm_hwc_get_capabilities(tdm_hwc *hwc, tdm_hwc_capability *capabilities)
392 {
393         tdm_private_module *private_module;
394         tdm_func_hwc *func_hwc;
395
396         HWC_FUNC_ENTRY();
397
398         _pthread_mutex_lock(&private_display->lock);
399
400         private_module = private_output->private_module;
401         func_hwc = &private_module->func_hwc;
402
403         if (!func_hwc->hwc_get_capabilities) {
404                 _pthread_mutex_unlock(&private_display->lock);
405                 TDM_WRN("not implemented!!");
406                 return TDM_ERROR_NOT_IMPLEMENTED;
407         }
408
409         ret = func_hwc->hwc_get_capabilities(private_hwc->hwc_backend, capabilities);
410
411         _pthread_mutex_unlock(&private_display->lock);
412
413         return ret;
414 }
415
416 EXTERN tdm_error
417 tdm_hwc_get_available_properties(tdm_hwc *hwc, const tdm_prop **props, int *count)
418 {
419         tdm_private_module *private_module;
420         tdm_func_hwc *func_hwc = NULL;
421
422         HWC_FUNC_ENTRY();
423
424         TDM_RETURN_VAL_IF_FAIL(props != NULL, TDM_ERROR_INVALID_PARAMETER);
425         TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
426
427         _pthread_mutex_lock(&private_display->lock);
428
429         private_module = private_output->private_module;
430         func_hwc = &private_module->func_hwc;
431
432         if (!func_hwc->hwc_get_available_properties) {
433                 /* LCOV_EXCL_START */
434                 _pthread_mutex_unlock(&private_display->lock);
435                 TDM_WRN("not implemented!!");
436                 return TDM_ERROR_NOT_IMPLEMENTED;
437                 /* LCOV_EXCL_STOP */
438         }
439
440         ret = func_hwc->hwc_get_available_properties(private_hwc->hwc_backend, props, count);
441
442         _pthread_mutex_unlock(&private_display->lock);
443
444         return ret;
445 }
446
447 EXTERN tbm_surface_queue_h
448 tdm_hwc_get_client_target_buffer_queue(tdm_hwc *hwc, tdm_error *error)
449 {
450         tdm_private_module *private_module;
451         tdm_func_hwc *func_hwc = NULL;
452         tbm_surface_queue_h queue = NULL;
453
454         HWC_FUNC_ENTRY_ERROR();
455
456         _pthread_mutex_lock(&private_display->lock);
457
458         private_module = private_hwc->private_module;
459         func_hwc = &private_module->func_hwc;
460
461         if (!func_hwc->hwc_get_client_target_buffer_queue) {
462                 /* LCOV_EXCL_START */
463                 _pthread_mutex_unlock(&private_display->lock);
464                 TDM_WRN("not implemented!!");
465                 return NULL;
466                 /* LCOV_EXCL_STOP */
467         }
468
469         queue = func_hwc->hwc_get_client_target_buffer_queue(private_hwc->hwc_backend, error);
470
471         _pthread_mutex_unlock(&private_display->lock);
472
473         return queue;
474 }
475
476 EXTERN tdm_error
477 tdm_hwc_set_client_target_buffer(tdm_hwc *hwc, tbm_surface_h target_buffer, tdm_region damage)
478 {
479         tdm_private_module *private_module;
480         tdm_func_hwc *func_hwc = NULL;
481
482         HWC_FUNC_ENTRY();
483
484         _pthread_mutex_lock(&private_display->lock);
485
486         if (tdm_debug_dump & TDM_DUMP_FLAG_WINDOW) {
487                 /* LCOV_EXCL_START */
488                 char str[TDM_PATH_LEN];
489                 static int i;
490                 snprintf(str, TDM_PATH_LEN, "target_window_%03d", i++);
491                 tdm_helper_dump_buffer_str(target_buffer, tdm_debug_dump_dir, str);
492                 /* LCOV_EXCL_STOP */
493         }
494
495         private_module = private_hwc->private_module;
496         func_hwc = &private_module->func_hwc;
497
498         if (!func_hwc->hwc_set_client_target_buffer) {
499                 /* LCOV_EXCL_START */
500                 _pthread_mutex_unlock(&private_display->lock);
501                 TDM_WRN("not implemented!!");
502                 return TDM_ERROR_NOT_IMPLEMENTED;
503                 /* LCOV_EXCL_STOP */
504         }
505
506         ret = func_hwc->hwc_set_client_target_buffer(private_hwc->hwc_backend, target_buffer, damage);
507
508         if (private_hwc->display_target_buffer) {
509                 if (private_hwc->display_target_buffer != target_buffer) {
510                         tbm_surface_internal_unref(private_hwc->display_target_buffer);
511                         private_hwc->display_target_buffer = target_buffer;
512                         if (target_buffer)
513                                 tbm_surface_internal_ref(private_hwc->display_target_buffer);
514                 }
515         } else {
516                 if (target_buffer) {
517                         private_hwc->display_target_buffer = target_buffer;
518                         tbm_surface_internal_ref(private_hwc->display_target_buffer);
519                 }
520         }
521
522         _pthread_mutex_unlock(&private_display->lock);
523
524         return ret;
525 }
526
527 EXTERN tdm_error
528 tdm_hwc_set_client_target_acquire_fence(tdm_hwc *hwc, int acquire_fence)
529 {
530         tdm_private_module *private_module;
531         tdm_func_hwc *func_hwc = NULL;
532
533         HWC_FUNC_ENTRY();
534
535         _pthread_mutex_lock(&private_display->lock);
536
537         private_module = private_hwc->private_module;
538         func_hwc = &private_module->func_hwc;
539
540         if (!func_hwc->hwc_set_client_target_acquire_fence) {
541                 /* LCOV_EXCL_START */
542                 _pthread_mutex_unlock(&private_display->lock);
543                 TDM_WRN("not implemented!!");
544                 return TDM_ERROR_NOT_IMPLEMENTED;
545                 /* LCOV_EXCL_STOP */
546         }
547
548         ret = func_hwc->hwc_set_client_target_acquire_fence(private_hwc->hwc_backend, acquire_fence);
549
550         _pthread_mutex_unlock(&private_display->lock);
551
552         return ret;
553 }
554
555 EXTERN tdm_error
556 tdm_hwc_validate(tdm_hwc *hwc, tdm_hwc_window **composited_wnds, uint32_t num_wnds, uint32_t *num_types)
557 {
558         tdm_private_module *private_module;
559         tdm_func_hwc *func_hwc = NULL;
560         tdm_private_hwc_window **composited_wnds_frontend = NULL;
561         tdm_hwc_window **composited_wnds_backend = NULL;
562         int i;
563
564         HWC_FUNC_ENTRY();
565
566         TDM_RETURN_VAL_IF_FAIL(num_types != NULL, TDM_ERROR_INVALID_PARAMETER);
567
568         _pthread_mutex_lock(&private_display->lock);
569
570         private_module = private_hwc->private_module;
571         func_hwc = &private_module->func_hwc;
572
573         if (!func_hwc->hwc_validate) {
574                 /* LCOV_EXCL_START */
575                 _pthread_mutex_unlock(&private_display->lock);
576                 TDM_WRN("not implemented!!");
577                 return TDM_ERROR_NOT_IMPLEMENTED;
578                 /* LCOV_EXCL_STOP */
579         }
580
581         if (num_wnds == 0) {
582                 ret = func_hwc->hwc_validate(private_hwc->hwc_backend, NULL, 0, num_types);
583
584                 _pthread_mutex_unlock(&private_display->lock);
585                 return ret;
586         }
587
588         composited_wnds_backend = calloc(num_wnds, sizeof(tdm_hwc_window *));
589         if (!composited_wnds_backend) {
590                 /* LCOV_EXCL_START */
591                 _pthread_mutex_unlock(&private_display->lock);
592                 return TDM_ERROR_OUT_OF_MEMORY;
593                 /* LCOV_EXCL_STOP */
594         }
595
596         composited_wnds_frontend = (tdm_private_hwc_window **)composited_wnds;
597
598         for (i = 0; i < num_wnds; i++)
599                 composited_wnds_backend[i] = composited_wnds_frontend[i]->hwc_window_backend;
600
601         ret = func_hwc->hwc_validate(private_hwc->hwc_backend, composited_wnds_backend,
602                                                                 num_wnds, num_types);
603
604         free(composited_wnds_backend);
605
606         _pthread_mutex_unlock(&private_display->lock);
607
608         return ret;
609 }
610
611 EXTERN tdm_error
612 tdm_hwc_get_changed_composition_types(tdm_hwc *hwc, uint32_t *num_elements,
613                                                                 tdm_hwc_window **hwc_window,
614                                                                 tdm_hwc_window_composition *composition_types)
615 {
616         tdm_private_module *private_module;
617         tdm_func_hwc *func_hwc = NULL;
618         tdm_private_hwc_window * private_hwc_window = NULL;
619         int i = 0;
620
621         HWC_FUNC_ENTRY();
622
623         TDM_RETURN_VAL_IF_FAIL(num_elements != NULL, TDM_ERROR_INVALID_PARAMETER);
624
625         _pthread_mutex_lock(&private_display->lock);
626
627         private_module = private_hwc->private_module;
628         func_hwc = &private_module->func_hwc;
629
630         if (!func_hwc->hwc_get_changed_composition_types) {
631                 /* LCOV_EXCL_START */
632                 _pthread_mutex_unlock(&private_display->lock);
633                 TDM_WRN("not implemented!!");
634                 return TDM_ERROR_NOT_IMPLEMENTED;
635                 /* LCOV_EXCL_STOP */
636         }
637
638         ret = func_hwc->hwc_get_changed_composition_types(private_hwc->hwc_backend,
639                                                         num_elements, hwc_window, composition_types);
640         if (ret != TDM_ERROR_NONE) {
641                 /* LCOV_EXCL_START */
642                 _pthread_mutex_unlock(&private_display->lock);
643                 return ret;
644                 /* LCOV_EXCL_STOP */
645         }
646
647         if (hwc_window == NULL || composition_types == NULL) {
648                 _pthread_mutex_unlock(&private_display->lock);
649                 return TDM_ERROR_NONE;
650         }
651
652         for (i = 0; i < *num_elements; i++) {
653                 private_hwc_window = _tdm_hwc_find_private_hwc_window(private_hwc, hwc_window[i]);
654                 if (private_hwc_window == NULL) {
655                         /* LCOV_EXCL_START */
656                         TDM_ERR("failed! This should never happen!");
657                         tdm_hwc_window_destroy_internal(private_hwc_window);
658                         *num_elements = 0;
659                         _pthread_mutex_unlock(&private_display->lock);
660                         return TDM_ERROR_OPERATION_FAILED;
661                         /* LCOV_EXCL_STOP */
662                 }
663
664                 hwc_window[i] = (tdm_hwc_window*)private_hwc_window;
665         }
666
667         _pthread_mutex_unlock(&private_display->lock);
668
669         return ret;
670 }
671
672 EXTERN tdm_error
673 tdm_hwc_accept_validation(tdm_hwc *hwc)
674 {
675         tdm_private_module *private_module;
676         tdm_func_hwc *func_hwc = NULL;
677
678         HWC_FUNC_ENTRY();
679
680         _pthread_mutex_lock(&private_display->lock);
681
682         private_module = private_hwc->private_module;
683         func_hwc = &private_module->func_hwc;
684
685         if (!func_hwc->hwc_validate) {
686                 /* LCOV_EXCL_START */
687                 _pthread_mutex_unlock(&private_display->lock);
688                 TDM_WRN("not implemented!!");
689                 return TDM_ERROR_NOT_IMPLEMENTED;
690                 /* LCOV_EXCL_STOP */
691         }
692
693         ret = func_hwc->hwc_accept_validation(private_hwc->hwc_backend);
694
695         _pthread_mutex_unlock(&private_display->lock);
696
697         return ret;
698 }
699
700 EXTERN tdm_error
701 tdm_hwc_commit(tdm_hwc *hwc, int sync, tdm_hwc_commit_handler func, void *user_data)
702 {
703         tdm_private_module *private_module;
704         tdm_func_hwc *func_hwc = NULL;
705         tdm_private_hwc_commit_handler *hwc_commit_handler = NULL;
706         tdm_private_voutput *private_voutput = NULL;
707         tdm_private_voutput_commit_handler *voutput_commit_handler = NULL;
708
709         HWC_FUNC_ENTRY();
710
711         _pthread_mutex_lock(&private_display->lock);
712
713         private_module = private_hwc->private_module;
714         func_hwc = &private_module->func_hwc;
715
716         if (!func_hwc->hwc_commit) {
717                 /* LCOV_EXCL_START */
718                 TDM_WRN("not implemented!!");
719                 _pthread_mutex_unlock(&private_display->lock);
720                 return TDM_ERROR_NOT_IMPLEMENTED;
721                 /* LCOV_EXCL_STOP */
722         }
723
724 //TODO: I am not sure yet whether we have to check the dpms at hwc_commit.
725 #if 0
726         /* check if the dpms is off */
727         if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->current_dpms_value)) {
728                 TDM_ERR("hwc(%d) dpms: %s", private_hwc->index,
729                                 tdm_dpms_str(private_output->current_dpms_value));
730                 _pthread_mutex_unlock(&private_display->lock);
731                 return TDM_ERROR_DPMS_OFF;
732         }
733 #endif
734
735         if (tdm_debug_module & TDM_DEBUG_COMMIT)
736                 TDM_INFO("hwc(%d) commit", private_hwc->index);
737
738         if (private_module == private_display->virtual_module) {
739                 if (!private_output->private_voutput) {
740                         TDM_ERR("virtual module but don't have voutput");
741                         _pthread_mutex_unlock(&private_display->lock);
742                         return TDM_ERROR_BAD_MODULE;
743                 }
744         }
745
746         if (!private_hwc->regist_commit_cb) {
747                 private_hwc->regist_commit_cb = 1;
748                 ret = func_hwc->hwc_set_commit_handler(private_hwc->hwc_backend, _tdm_hwc_cb_commit);
749                 /* LCOV_EXCL_START */
750                 if (ret != TDM_ERROR_NONE) {
751                         private_hwc->regist_commit_cb = 0;
752                         TDM_ERR("hwc(%d) fail to set hwc_set_commit_handler", private_hwc->index);
753                         _pthread_mutex_unlock(&private_display->lock);
754                         return ret;
755                 /* LCOV_EXCL_STOP */
756                 }
757         }
758
759         hwc_commit_handler = calloc(1, sizeof(tdm_private_hwc_commit_handler));
760         if (!hwc_commit_handler) {
761                 /* LCOV_EXCL_START */
762                 TDM_ERR("failed: alloc memory");
763                 _pthread_mutex_unlock(&private_display->lock);
764                 return TDM_ERROR_OUT_OF_MEMORY;
765                 /* LCOV_EXCL_STOP */
766         }
767
768         ret = tdm_thread_cb_add(private_hwc, TDM_THREAD_CB_HWC_COMMIT, hwc_commit_handler,
769                                         _tdm_hwc_thread_cb_commit, NULL);
770         if (ret != TDM_ERROR_NONE) {
771                 TDM_ERR("tdm_thread_cb_add failed");
772                 free(hwc_commit_handler);
773                 _pthread_mutex_unlock(&private_display->lock);
774                 return ret;
775         }
776
777         LIST_ADDTAIL(&hwc_commit_handler->link, &private_hwc->hwc_commit_handler_list);
778         hwc_commit_handler->private_hwc = private_hwc;
779         hwc_commit_handler->func = func;
780         hwc_commit_handler->user_data = user_data;
781         hwc_commit_handler->owner_tid = syscall(SYS_gettid);
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 tdm_error
857 tdm_hwc_set_property(tdm_hwc *hwc, uint32_t id, tdm_value value)
858 {
859         tdm_private_module *private_module;
860         tdm_func_hwc *func_hwc = NULL;
861
862         HWC_FUNC_ENTRY();
863
864         _pthread_mutex_lock(&private_display->lock);
865
866         private_module = private_hwc->private_module;
867         func_hwc = &private_module->func_hwc;
868
869         if (!func_hwc->hwc_set_property) {
870                 /* LCOV_EXCL_START */
871                 _pthread_mutex_unlock(&private_display->lock);
872                 TDM_WRN("not implemented!!");
873                 return TDM_ERROR_NOT_IMPLEMENTED;
874                 /* LCOV_EXCL_STOP */
875         }
876
877         ret = func_hwc->hwc_set_property(private_hwc->hwc_backend, id, value);
878
879         _pthread_mutex_unlock(&private_display->lock);
880
881         return ret;
882 }
883
884 tdm_error
885 tdm_hwc_get_property(tdm_hwc *hwc, uint32_t id, tdm_value *value)
886 {
887         tdm_private_module *private_module;
888         tdm_func_hwc *func_hwc = NULL;
889
890         HWC_FUNC_ENTRY();
891
892         _pthread_mutex_lock(&private_display->lock);
893
894         private_module = private_hwc->private_module;
895         func_hwc = &private_module->func_hwc;
896
897         if (!func_hwc->hwc_get_property) {
898                 /* LCOV_EXCL_START */
899                 _pthread_mutex_unlock(&private_display->lock);
900                 TDM_WRN("not implemented!!");
901                 return TDM_ERROR_NOT_IMPLEMENTED;
902                 /* LCOV_EXCL_STOP */
903         }
904
905         ret = func_hwc->hwc_get_property(private_hwc->hwc_backend, id, value);
906
907         _pthread_mutex_unlock(&private_display->lock);
908
909         return ret;
910 }