return error if a buffer is attached twice
[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         }
217
218         if (!LIST_IS_EMPTY(&private_pp->dst_pending_buffer_list)) {
219                 TDM_ERR("pp(%p) not finished:", private_pp);
220                 tdm_buffer_list_dump(&private_pp->dst_pending_buffer_list);
221
222                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_pending_buffer_list, link)
223                         LIST_DEL(&b->link);
224         }
225
226         if (!LIST_IS_EMPTY(&private_pp->src_buffer_list)) {
227                 TDM_ERR("pp(%p) not finished:", private_pp);
228                 tdm_buffer_list_dump(&private_pp->src_buffer_list);
229
230                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_buffer_list, link)
231                         LIST_DEL(&b->link);
232         }
233
234         if (!LIST_IS_EMPTY(&private_pp->dst_buffer_list)) {
235                 TDM_ERR("pp(%p) not finished:", private_pp);
236                 tdm_buffer_list_dump(&private_pp->dst_buffer_list);
237
238                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_buffer_list, link)
239                         LIST_DEL(&b->link);
240         }
241
242         free(private_pp);
243 }
244
245 EXTERN void
246 tdm_pp_destroy(tdm_pp *pp)
247 {
248         tdm_private_pp *private_pp = pp;
249         tdm_private_display *private_display;
250
251         if (!private_pp)
252                 return;
253
254         private_display = private_pp->private_display;
255
256         pthread_mutex_lock(&private_display->lock);
257         tdm_pp_destroy_internal(private_pp);
258         pthread_mutex_unlock(&private_display->lock);
259 }
260
261 EXTERN tdm_error
262 tdm_pp_set_info(tdm_pp *pp, tdm_info_pp *info)
263 {
264         PP_FUNC_ENTRY();
265
266         TDM_RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER);
267
268         pthread_mutex_lock(&private_display->lock);
269
270         if (!func_pp->pp_set_info) {
271                 pthread_mutex_unlock(&private_display->lock);
272                 return TDM_ERROR_NONE;
273         }
274
275         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)",
276                  private_pp, info->src_config.size.h, info->src_config.size.v,
277                  info->src_config.pos.x, info->src_config.pos.y,
278                  info->src_config.pos.w, info->src_config.pos.h,
279                  FOURCC_STR(info->src_config.format),
280                  info->dst_config.size.h, info->dst_config.size.v,
281                  info->dst_config.pos.x, info->dst_config.pos.y,
282                  info->dst_config.pos.w, info->dst_config.pos.h,
283                  FOURCC_STR(info->dst_config.format),
284                  info->transform, info->sync, info->flags);
285
286         ret = func_pp->pp_set_info(private_pp->pp_backend, info);
287         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
288
289         pthread_mutex_unlock(&private_display->lock);
290
291         return ret;
292 }
293
294 EXTERN tdm_error
295 tdm_pp_attach(tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst)
296 {
297         PP_FUNC_ENTRY();
298
299         TDM_RETURN_VAL_IF_FAIL(src != NULL, TDM_ERROR_INVALID_PARAMETER);
300         TDM_RETURN_VAL_IF_FAIL(dst != NULL, TDM_ERROR_INVALID_PARAMETER);
301
302         pthread_mutex_lock(&private_display->lock);
303
304         if (!func_pp->pp_attach) {
305                 pthread_mutex_unlock(&private_display->lock);
306                 return TDM_ERROR_NONE;
307         }
308
309         ret = _tdm_pp_check_if_exist(private_pp, src, dst);
310         if (ret != TDM_ERROR_NONE) {
311                 pthread_mutex_unlock(&private_display->lock);
312                 return ret;
313         }
314
315         ret = func_pp->pp_attach(private_pp->pp_backend, src, dst);
316         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
317
318         if (ret == TDM_ERROR_NONE) {
319                 tdm_buffer_info *buf_info;
320
321                 if ((buf_info = tdm_buffer_get_info(src)))
322                         LIST_ADDTAIL(&buf_info->link, &private_pp->src_pending_buffer_list);
323
324                 if ((buf_info = tdm_buffer_get_info(dst)))
325                         LIST_ADDTAIL(&buf_info->link, &private_pp->dst_pending_buffer_list);
326
327                 if (tdm_debug_buffer) {
328                         TDM_INFO("pp(%p) attached:", private_pp);
329                         tdm_buffer_list_dump(&private_pp->src_pending_buffer_list);
330                         tdm_buffer_list_dump(&private_pp->dst_pending_buffer_list);
331                 }
332         }
333
334         pthread_mutex_unlock(&private_display->lock);
335
336         return ret;
337 }
338
339 EXTERN tdm_error
340 tdm_pp_commit(tdm_pp *pp)
341 {
342         tdm_buffer_info *b = NULL, *bb = NULL;
343
344         PP_FUNC_ENTRY();
345
346         pthread_mutex_lock(&private_display->lock);
347
348         if (!func_pp->pp_commit) {
349                 pthread_mutex_unlock(&private_display->lock);
350                 return TDM_ERROR_NONE;
351         }
352
353         ret = func_pp->pp_commit(private_pp->pp_backend);
354         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
355
356         if (ret == TDM_ERROR_NONE) {
357                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_pending_buffer_list, link) {
358                         LIST_DEL(&b->link);
359                         tdm_buffer_ref_backend(b->buffer);
360                         LIST_ADDTAIL(&b->link, &private_pp->src_buffer_list);
361                 }
362
363                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_pending_buffer_list, link) {
364                         LIST_DEL(&b->link);
365                         tdm_buffer_ref_backend(b->buffer);
366                         LIST_ADDTAIL(&b->link, &private_pp->dst_buffer_list);
367                 }
368         } else {
369                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_pending_buffer_list, link)
370                         LIST_DEL(&b->link);
371                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_pending_buffer_list, link)
372                         LIST_DEL(&b->link);
373         }
374
375         pthread_mutex_unlock(&private_display->lock);
376
377         return ret;
378 }