use macro to debug mutex lock
[platform/core/uifw/libtdm.git] / src / tdm_pp.c
1 /**************************************************************************
2
3 libtdm
4
5 Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
6
7 Contact: Eunchul Kim <chulspro.kim@samsung.com>,
8          JinYoung Jeon <jy0.jeon@samsung.com>,
9          Taeheon Kim <th908.kim@samsung.com>,
10          YoungJun Cho <yj44.cho@samsung.com>,
11          SooChan Lim <sc1.lim@samsung.com>,
12          Boram Park <sc1.lim@samsung.com>
13
14 Permission is hereby granted, free of charge, to any person obtaining a
15 copy of this software and associated documentation files (the
16 "Software"), to deal in the Software without restriction, including
17 without limitation the rights to use, copy, modify, merge, publish,
18 distribute, sub license, and/or sell copies of the Software, and to
19 permit persons to whom the Software is furnished to do so, subject to
20 the following conditions:
21
22 The above copyright notice and this permission notice (including the
23 next paragraph) shall be included in all copies or substantial portions
24 of the Software.
25
26 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
29 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
30 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
31 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
32 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33
34 **************************************************************************/
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include "tdm.h"
41 #include "tdm_backend.h"
42 #include "tdm_private.h"
43
44 #define PP_FUNC_ENTRY() \
45     tdm_func_pp *func_pp; \
46     tdm_private_display *private_display; \
47     tdm_private_pp *private_pp; \
48     tdm_error ret = TDM_ERROR_NONE; \
49     TDM_RETURN_VAL_IF_FAIL(pp != NULL, TDM_ERROR_INVALID_PARAMETER); \
50     private_pp = (tdm_private_pp*)pp; \
51     private_display = private_pp->private_display; \
52     func_pp = &private_display->func_pp
53
54 static tdm_error
55 _tdm_pp_check_if_exist(tdm_private_pp *private_pp,
56                        tbm_surface_h src, tbm_surface_h dst)
57 {
58         tdm_buffer_info *buf_info = NULL;
59
60         LIST_FOR_EACH_ENTRY(buf_info, &private_pp->src_buffer_list, link) {
61                 if (buf_info->buffer == src) {
62                         TDM_ERR("%p attached twice", src);
63                         return TDM_ERROR_BAD_REQUEST;
64                 }
65         }
66
67         LIST_FOR_EACH_ENTRY(buf_info, &private_pp->src_pending_buffer_list, link) {
68                 if (buf_info->buffer == src) {
69                         TDM_ERR("%p attached twice", src);
70                         return TDM_ERROR_BAD_REQUEST;
71                 }
72         }
73
74         LIST_FOR_EACH_ENTRY(buf_info, &private_pp->dst_buffer_list, link) {
75                 if (buf_info->buffer == dst) {
76                         TDM_ERR("%p attached twice", dst);
77                         return TDM_ERROR_BAD_REQUEST;
78                 }
79         }
80
81         LIST_FOR_EACH_ENTRY(buf_info, &private_pp->dst_pending_buffer_list, link) {
82                 if (buf_info->buffer == dst) {
83                         TDM_ERR("%p attached twice", dst);
84                         return TDM_ERROR_BAD_REQUEST;
85                 }
86         }
87
88         return TDM_ERROR_NONE;
89 }
90
91 static void
92 _tdm_pp_cb_done(tdm_pp *pp_backend, tbm_surface_h src, tbm_surface_h dst,
93                 void *user_data)
94 {
95         tdm_private_pp *private_pp = user_data;
96         tdm_private_display *private_display = private_pp->private_display;
97         tdm_buffer_info *buf_info;
98         tbm_surface_h first_entry;
99         int lock_after_cb_done = 0;
100         int ret;
101
102         if (tdm_debug_buffer)
103                 TDM_INFO("pp(%p) done: src(%p) dst(%p)", private_pp, src, dst);
104
105         first_entry = tdm_buffer_list_get_first_entry(&private_pp->src_buffer_list);
106         if (first_entry != src)
107                 TDM_ERR("src(%p) is skipped", first_entry);
108
109         first_entry = tdm_buffer_list_get_first_entry(&private_pp->dst_buffer_list);
110         if (first_entry != dst)
111                 TDM_ERR("dst(%p) is skipped", first_entry);
112
113         if ((buf_info = tdm_buffer_get_info(src)))
114                 LIST_DEL(&buf_info->link);
115
116         if ((buf_info = tdm_buffer_get_info(dst)))
117                 LIST_DEL(&buf_info->link);
118
119         ret = pthread_mutex_trylock(&private_display->lock);
120         if (ret == 0)
121                 _pthread_mutex_unlock(&private_display->lock);
122         else  if (ret == EBUSY) {
123                 _pthread_mutex_unlock(&private_display->lock);
124                 lock_after_cb_done = 1;
125         }
126
127         tdm_buffer_unref_backend(src);
128         tdm_buffer_unref_backend(dst);
129
130         if (lock_after_cb_done)
131                 _pthread_mutex_lock(&private_display->lock);
132 }
133
134 INTERN tdm_private_pp *
135 tdm_pp_create_internal(tdm_private_display *private_display, tdm_error *error)
136 {
137         tdm_func_display *func_display;
138         tdm_func_pp *func_pp;
139         tdm_private_pp *private_pp = NULL;
140         tdm_pp *pp_backend = NULL;
141         tdm_error ret = TDM_ERROR_NONE;
142
143         func_display = &private_display->func_display;
144         func_pp = &private_display->func_pp;
145
146         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP)) {
147                 TDM_ERR("no pp capability");
148                 if (error)
149                         *error = TDM_ERROR_NO_CAPABILITY;
150                 return NULL;
151         }
152
153         pp_backend = func_display->display_create_pp(private_display->bdata, &ret);
154         if (ret != TDM_ERROR_NONE) {
155                 if (error)
156                         *error = ret;
157                 return NULL;
158         }
159
160         private_pp = calloc(1, sizeof(tdm_private_pp));
161         if (!private_pp) {
162                 TDM_ERR("failed: alloc memory");
163                 func_pp->pp_destroy(pp_backend);
164                 if (error)
165                         *error = TDM_ERROR_OUT_OF_MEMORY;
166                 return NULL;
167         }
168
169         ret = func_pp->pp_set_done_handler(pp_backend, _tdm_pp_cb_done, private_pp);
170         if (ret != TDM_ERROR_NONE) {
171                 TDM_ERR("spp(%p) et pp_done_handler failed", private_pp);
172                 func_pp->pp_destroy(pp_backend);
173                 if (error)
174                         *error = ret;
175                 return NULL;
176         }
177
178         LIST_ADD(&private_pp->link, &private_display->pp_list);
179         private_pp->private_display = private_display;
180         private_pp->pp_backend = pp_backend;
181
182         LIST_INITHEAD(&private_pp->src_pending_buffer_list);
183         LIST_INITHEAD(&private_pp->dst_pending_buffer_list);
184         LIST_INITHEAD(&private_pp->src_buffer_list);
185         LIST_INITHEAD(&private_pp->dst_buffer_list);
186
187         if (error)
188                 *error = TDM_ERROR_NONE;
189
190         return private_pp;
191 }
192
193 INTERN void
194 tdm_pp_destroy_internal(tdm_private_pp *private_pp)
195 {
196         tdm_private_display *private_display;
197         tdm_func_pp *func_pp;
198         tdm_buffer_info *b = NULL, *bb = NULL;
199
200         if (!private_pp)
201                 return;
202
203         private_display = private_pp->private_display;
204         func_pp = &private_display->func_pp;
205
206         LIST_DEL(&private_pp->link);
207
208         func_pp->pp_destroy(private_pp->pp_backend);
209
210         if (!LIST_IS_EMPTY(&private_pp->src_pending_buffer_list)) {
211                 TDM_ERR("pp(%p) not finished:", private_pp);
212                 tdm_buffer_list_dump(&private_pp->src_pending_buffer_list);
213
214                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_pending_buffer_list, link) {
215                         LIST_DEL(&b->link);
216                         _pthread_mutex_unlock(&private_display->lock);
217                         tdm_buffer_unref_backend(b->buffer);
218                         _pthread_mutex_lock(&private_display->lock);
219                 }
220         }
221
222         if (!LIST_IS_EMPTY(&private_pp->dst_pending_buffer_list)) {
223                 TDM_ERR("pp(%p) not finished:", private_pp);
224                 tdm_buffer_list_dump(&private_pp->dst_pending_buffer_list);
225
226                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_pending_buffer_list, link) {
227                         LIST_DEL(&b->link);
228                         _pthread_mutex_unlock(&private_display->lock);
229                         tdm_buffer_unref_backend(b->buffer);
230                         _pthread_mutex_lock(&private_display->lock);
231                 }
232         }
233
234         if (!LIST_IS_EMPTY(&private_pp->src_buffer_list)) {
235                 TDM_ERR("pp(%p) not finished:", private_pp);
236                 tdm_buffer_list_dump(&private_pp->src_buffer_list);
237
238                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_buffer_list, link) {
239                         LIST_DEL(&b->link);
240                         _pthread_mutex_unlock(&private_display->lock);
241                         tdm_buffer_unref_backend(b->buffer);
242                         _pthread_mutex_lock(&private_display->lock);
243                 }
244         }
245
246         if (!LIST_IS_EMPTY(&private_pp->dst_buffer_list)) {
247                 TDM_ERR("pp(%p) not finished:", private_pp);
248                 tdm_buffer_list_dump(&private_pp->dst_buffer_list);
249
250                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_buffer_list, link) {
251                         LIST_DEL(&b->link);
252                         _pthread_mutex_unlock(&private_display->lock);
253                         tdm_buffer_unref_backend(b->buffer);
254                         _pthread_mutex_lock(&private_display->lock);
255                 }
256         }
257
258         free(private_pp);
259 }
260
261 EXTERN void
262 tdm_pp_destroy(tdm_pp *pp)
263 {
264         tdm_private_pp *private_pp = pp;
265         tdm_private_display *private_display;
266
267         if (!private_pp)
268                 return;
269
270         private_display = private_pp->private_display;
271
272         _pthread_mutex_lock(&private_display->lock);
273         tdm_pp_destroy_internal(private_pp);
274         _pthread_mutex_unlock(&private_display->lock);
275 }
276
277 EXTERN tdm_error
278 tdm_pp_set_info(tdm_pp *pp, tdm_info_pp *info)
279 {
280         PP_FUNC_ENTRY();
281
282         TDM_RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER);
283
284         _pthread_mutex_lock(&private_display->lock);
285
286         if (!func_pp->pp_set_info) {
287                 _pthread_mutex_unlock(&private_display->lock);
288                 return TDM_ERROR_NONE;
289         }
290
291         TDM_INFO("pp(%p) info: src(%dx%d %d,%d %dx%d %c%c%c%c) dst(%dx%d %d,%d %dx%d %c%c%c%c) trans(%d) sync(%d) flags(%x)",
292                  private_pp, info->src_config.size.h, info->src_config.size.v,
293                  info->src_config.pos.x, info->src_config.pos.y,
294                  info->src_config.pos.w, info->src_config.pos.h,
295                  FOURCC_STR(info->src_config.format),
296                  info->dst_config.size.h, info->dst_config.size.v,
297                  info->dst_config.pos.x, info->dst_config.pos.y,
298                  info->dst_config.pos.w, info->dst_config.pos.h,
299                  FOURCC_STR(info->dst_config.format),
300                  info->transform, info->sync, info->flags);
301
302         ret = func_pp->pp_set_info(private_pp->pp_backend, info);
303         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
304
305         _pthread_mutex_unlock(&private_display->lock);
306
307         return ret;
308 }
309
310 EXTERN tdm_error
311 tdm_pp_attach(tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst)
312 {
313         PP_FUNC_ENTRY();
314
315         TDM_RETURN_VAL_IF_FAIL(src != NULL, TDM_ERROR_INVALID_PARAMETER);
316         TDM_RETURN_VAL_IF_FAIL(dst != NULL, TDM_ERROR_INVALID_PARAMETER);
317
318         _pthread_mutex_lock(&private_display->lock);
319
320         if (!func_pp->pp_attach) {
321                 _pthread_mutex_unlock(&private_display->lock);
322                 return TDM_ERROR_NONE;
323         }
324
325         ret = _tdm_pp_check_if_exist(private_pp, src, dst);
326         if (ret != TDM_ERROR_NONE) {
327                 _pthread_mutex_unlock(&private_display->lock);
328                 return ret;
329         }
330
331         ret = func_pp->pp_attach(private_pp->pp_backend, src, dst);
332         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
333
334         if (ret == TDM_ERROR_NONE) {
335                 tdm_buffer_info *buf_info;
336
337                 if ((buf_info = tdm_buffer_get_info(src)))
338                         LIST_ADDTAIL(&buf_info->link, &private_pp->src_pending_buffer_list);
339
340                 if ((buf_info = tdm_buffer_get_info(dst)))
341                         LIST_ADDTAIL(&buf_info->link, &private_pp->dst_pending_buffer_list);
342
343                 if (tdm_debug_buffer) {
344                         TDM_INFO("pp(%p) attached:", private_pp);
345                         tdm_buffer_list_dump(&private_pp->src_pending_buffer_list);
346                         tdm_buffer_list_dump(&private_pp->dst_pending_buffer_list);
347                 }
348         }
349
350         _pthread_mutex_unlock(&private_display->lock);
351
352         return ret;
353 }
354
355 EXTERN tdm_error
356 tdm_pp_commit(tdm_pp *pp)
357 {
358         tdm_buffer_info *b = NULL, *bb = NULL;
359
360         PP_FUNC_ENTRY();
361
362         _pthread_mutex_lock(&private_display->lock);
363
364         if (!func_pp->pp_commit) {
365                 _pthread_mutex_unlock(&private_display->lock);
366                 return TDM_ERROR_NONE;
367         }
368
369         ret = func_pp->pp_commit(private_pp->pp_backend);
370         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
371
372         if (ret == TDM_ERROR_NONE) {
373                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_pending_buffer_list, link) {
374                         LIST_DEL(&b->link);
375                         tdm_buffer_ref_backend(b->buffer);
376                         LIST_ADDTAIL(&b->link, &private_pp->src_buffer_list);
377                 }
378
379                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_pending_buffer_list, link) {
380                         LIST_DEL(&b->link);
381                         tdm_buffer_ref_backend(b->buffer);
382                         LIST_ADDTAIL(&b->link, &private_pp->dst_buffer_list);
383                 }
384         } else {
385                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_pending_buffer_list, link)
386                         LIST_DEL(&b->link);
387                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_pending_buffer_list, link)
388                         LIST_DEL(&b->link);
389         }
390
391         _pthread_mutex_unlock(&private_display->lock);
392
393         return ret;
394 }