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