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