fix TDM buffer management
[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 void
55 _tdm_pp_cb_done(tdm_pp *pp_backend, tbm_surface_h src, tbm_surface_h dst,
56                 void *user_data)
57 {
58         tdm_private_pp *private_pp = user_data;
59         tdm_private_display *private_display = private_pp->private_display;
60         tdm_buffer_info *buf_info;
61         tbm_surface_h first_entry;
62         int lock_after_cb_done = 0;
63         int ret;
64
65         if (tdm_debug_buffer)
66                 TDM_INFO("pp(%p) done: src(%p) dst(%p)", private_pp, src, dst);
67
68         first_entry = tdm_buffer_list_get_first_entry(&private_pp->src_buffer_list);
69         if (first_entry != src)
70                 TDM_ERR("src(%p) is skipped", first_entry);
71
72         first_entry = tdm_buffer_list_get_first_entry(&private_pp->dst_buffer_list);
73         if (first_entry != dst)
74                 TDM_ERR("dst(%p) is skipped", first_entry);
75
76         if ((buf_info = tdm_buffer_get_info(src)))
77                 LIST_DEL(&buf_info->link);
78
79         if ((buf_info = tdm_buffer_get_info(dst)))
80                 LIST_DEL(&buf_info->link);
81
82         ret = pthread_mutex_trylock(&private_display->lock);
83         if (ret == 0)
84                 pthread_mutex_unlock(&private_display->lock);
85         else  if (ret == EBUSY) {
86                 pthread_mutex_unlock(&private_display->lock);
87                 lock_after_cb_done = 1;
88         }
89
90         tdm_buffer_unref_backend(src);
91         tdm_buffer_unref_backend(dst);
92
93         if (lock_after_cb_done)
94                 pthread_mutex_lock(&private_display->lock);
95 }
96
97 INTERN tdm_private_pp *
98 tdm_pp_create_internal(tdm_private_display *private_display, tdm_error *error)
99 {
100         tdm_func_display *func_display;
101         tdm_func_pp *func_pp;
102         tdm_private_pp *private_pp = NULL;
103         tdm_pp *pp_backend = NULL;
104         tdm_error ret = TDM_ERROR_NONE;
105
106         func_display = &private_display->func_display;
107         func_pp = &private_display->func_pp;
108
109         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP)) {
110                 TDM_ERR("no pp capability");
111                 if (error)
112                         *error = TDM_ERROR_NO_CAPABILITY;
113                 return NULL;
114         }
115
116         pp_backend = func_display->display_create_pp(private_display->bdata, &ret);
117         if (ret != TDM_ERROR_NONE) {
118                 if (error)
119                         *error = ret;
120                 return NULL;
121         }
122
123         private_pp = calloc(1, sizeof(tdm_private_pp));
124         if (!private_pp) {
125                 TDM_ERR("failed: alloc memory");
126                 func_pp->pp_destroy(pp_backend);
127                 if (error)
128                         *error = TDM_ERROR_OUT_OF_MEMORY;
129                 return NULL;
130         }
131
132         ret = func_pp->pp_set_done_handler(pp_backend, _tdm_pp_cb_done, private_pp);
133         if (ret != TDM_ERROR_NONE) {
134                 TDM_ERR("spp(%p) et pp_done_handler failed", private_pp);
135                 func_pp->pp_destroy(pp_backend);
136                 if (error)
137                         *error = ret;
138                 return NULL;
139         }
140
141         LIST_ADD(&private_pp->link, &private_display->pp_list);
142         private_pp->private_display = private_display;
143         private_pp->pp_backend = pp_backend;
144
145         LIST_INITHEAD(&private_pp->src_pending_buffer_list);
146         LIST_INITHEAD(&private_pp->dst_pending_buffer_list);
147         LIST_INITHEAD(&private_pp->src_buffer_list);
148         LIST_INITHEAD(&private_pp->dst_buffer_list);
149
150         if (error)
151                 *error = TDM_ERROR_NONE;
152
153         return private_pp;
154 }
155
156 INTERN void
157 tdm_pp_destroy_internal(tdm_private_pp *private_pp)
158 {
159         tdm_private_display *private_display;
160         tdm_func_pp *func_pp;
161         tdm_buffer_info *b = NULL, *bb = NULL;
162
163         if (!private_pp)
164                 return;
165
166         private_display = private_pp->private_display;
167         func_pp = &private_display->func_pp;
168
169         LIST_DEL(&private_pp->link);
170
171         func_pp->pp_destroy(private_pp->pp_backend);
172
173         if (!LIST_IS_EMPTY(&private_pp->src_pending_buffer_list)) {
174                 TDM_ERR("pp(%p) not finished:", private_pp);
175                 tdm_buffer_list_dump(&private_pp->src_pending_buffer_list);
176
177                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_pending_buffer_list, link)
178                         LIST_DEL(&b->link);
179         }
180
181         if (!LIST_IS_EMPTY(&private_pp->dst_pending_buffer_list)) {
182                 TDM_ERR("pp(%p) not finished:", private_pp);
183                 tdm_buffer_list_dump(&private_pp->dst_pending_buffer_list);
184
185                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_pending_buffer_list, link)
186                         LIST_DEL(&b->link);
187         }
188
189         if (!LIST_IS_EMPTY(&private_pp->src_buffer_list)) {
190                 TDM_ERR("pp(%p) not finished:", private_pp);
191                 tdm_buffer_list_dump(&private_pp->src_buffer_list);
192
193                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_buffer_list, link)
194                         LIST_DEL(&b->link);
195         }
196
197         if (!LIST_IS_EMPTY(&private_pp->dst_buffer_list)) {
198                 TDM_ERR("pp(%p) not finished:", private_pp);
199                 tdm_buffer_list_dump(&private_pp->dst_buffer_list);
200
201                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_buffer_list, link)
202                         LIST_DEL(&b->link);
203         }
204
205         free(private_pp);
206 }
207
208 EXTERN void
209 tdm_pp_destroy(tdm_pp *pp)
210 {
211         tdm_private_pp *private_pp = pp;
212         tdm_private_display *private_display;
213
214         if (!private_pp)
215                 return;
216
217         private_display = private_pp->private_display;
218
219         pthread_mutex_lock(&private_display->lock);
220         tdm_pp_destroy_internal(private_pp);
221         pthread_mutex_unlock(&private_display->lock);
222 }
223
224 EXTERN tdm_error
225 tdm_pp_set_info(tdm_pp *pp, tdm_info_pp *info)
226 {
227         PP_FUNC_ENTRY();
228
229         TDM_RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER);
230
231         pthread_mutex_lock(&private_display->lock);
232
233         if (!func_pp->pp_set_info) {
234                 pthread_mutex_unlock(&private_display->lock);
235                 return TDM_ERROR_NONE;
236         }
237
238         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)",
239                  private_pp, info->src_config.size.h, info->src_config.size.v,
240                  info->src_config.pos.x, info->src_config.pos.y,
241                  info->src_config.pos.w, info->src_config.pos.h,
242                  FOURCC_STR(info->src_config.format),
243                  info->dst_config.size.h, info->dst_config.size.v,
244                  info->dst_config.pos.x, info->dst_config.pos.y,
245                  info->dst_config.pos.w, info->dst_config.pos.h,
246                  FOURCC_STR(info->dst_config.format),
247                  info->transform, info->sync, info->flags);
248
249         ret = func_pp->pp_set_info(private_pp->pp_backend, info);
250         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
251
252         pthread_mutex_unlock(&private_display->lock);
253
254         return ret;
255 }
256
257 EXTERN tdm_error
258 tdm_pp_attach(tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst)
259 {
260         PP_FUNC_ENTRY();
261
262         TDM_RETURN_VAL_IF_FAIL(src != NULL, TDM_ERROR_INVALID_PARAMETER);
263         TDM_RETURN_VAL_IF_FAIL(dst != NULL, TDM_ERROR_INVALID_PARAMETER);
264
265         pthread_mutex_lock(&private_display->lock);
266
267         if (!func_pp->pp_attach) {
268                 pthread_mutex_unlock(&private_display->lock);
269                 return TDM_ERROR_NONE;
270         }
271
272         ret = func_pp->pp_attach(private_pp->pp_backend, src, dst);
273         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
274
275         if (ret == TDM_ERROR_NONE) {
276                 tdm_buffer_info *buf_info;
277
278                 if ((buf_info = tdm_buffer_get_info(src)))
279                         LIST_ADDTAIL(&buf_info->link, &private_pp->src_pending_buffer_list);
280
281                 if ((buf_info = tdm_buffer_get_info(dst)))
282                         LIST_ADDTAIL(&buf_info->link, &private_pp->dst_pending_buffer_list);
283
284                 if (tdm_debug_buffer) {
285                         TDM_INFO("pp(%p) attached:", private_pp);
286                         tdm_buffer_list_dump(&private_pp->src_pending_buffer_list);
287                         tdm_buffer_list_dump(&private_pp->dst_pending_buffer_list);
288                 }
289         }
290
291         pthread_mutex_unlock(&private_display->lock);
292
293         return ret;
294 }
295
296 EXTERN tdm_error
297 tdm_pp_commit(tdm_pp *pp)
298 {
299         tdm_buffer_info *b = NULL, *bb = NULL;
300
301         PP_FUNC_ENTRY();
302
303         pthread_mutex_lock(&private_display->lock);
304
305         if (!func_pp->pp_commit) {
306                 pthread_mutex_unlock(&private_display->lock);
307                 return TDM_ERROR_NONE;
308         }
309
310         ret = func_pp->pp_commit(private_pp->pp_backend);
311         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
312
313         if (ret == TDM_ERROR_NONE) {
314                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_pending_buffer_list, link) {
315                         LIST_DEL(&b->link);
316                         tdm_buffer_ref_backend(b->buffer);
317                         LIST_ADDTAIL(&b->link, &private_pp->src_buffer_list);
318                 }
319
320                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_pending_buffer_list, link) {
321                         LIST_DEL(&b->link);
322                         tdm_buffer_ref_backend(b->buffer);
323                         LIST_ADDTAIL(&b->link, &private_pp->dst_buffer_list);
324                 }
325         } else {
326                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_pending_buffer_list, link)
327                         LIST_DEL(&b->link);
328                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_pending_buffer_list, link)
329                         LIST_DEL(&b->link);
330         }
331
332         pthread_mutex_unlock(&private_display->lock);
333
334         return ret;
335 }