return TDM_ERROR_NOT_IMPLEMENTED if backend doesn't implenment
[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                 TDM_DBG("failed: not implemented!!");
289                 return TDM_ERROR_NOT_IMPLEMENTED;
290         }
291
292         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)",
293                  private_pp, info->src_config.size.h, info->src_config.size.v,
294                  info->src_config.pos.x, info->src_config.pos.y,
295                  info->src_config.pos.w, info->src_config.pos.h,
296                  FOURCC_STR(info->src_config.format),
297                  info->dst_config.size.h, info->dst_config.size.v,
298                  info->dst_config.pos.x, info->dst_config.pos.y,
299                  info->dst_config.pos.w, info->dst_config.pos.h,
300                  FOURCC_STR(info->dst_config.format),
301                  info->transform, info->sync, info->flags);
302
303         ret = func_pp->pp_set_info(private_pp->pp_backend, info);
304         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
305
306         _pthread_mutex_unlock(&private_display->lock);
307
308         return ret;
309 }
310
311 EXTERN tdm_error
312 tdm_pp_attach(tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst)
313 {
314         PP_FUNC_ENTRY();
315
316         TDM_RETURN_VAL_IF_FAIL(src != NULL, TDM_ERROR_INVALID_PARAMETER);
317         TDM_RETURN_VAL_IF_FAIL(dst != NULL, TDM_ERROR_INVALID_PARAMETER);
318
319         _pthread_mutex_lock(&private_display->lock);
320
321         if (!func_pp->pp_attach) {
322                 _pthread_mutex_unlock(&private_display->lock);
323                 TDM_DBG("failed: not implemented!!");
324                 return TDM_ERROR_NOT_IMPLEMENTED;
325         }
326
327         ret = _tdm_pp_check_if_exist(private_pp, src, dst);
328         if (ret != TDM_ERROR_NONE) {
329                 _pthread_mutex_unlock(&private_display->lock);
330                 return ret;
331         }
332
333         ret = func_pp->pp_attach(private_pp->pp_backend, src, dst);
334         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
335
336         if (ret == TDM_ERROR_NONE) {
337                 tdm_buffer_info *buf_info;
338
339                 if ((buf_info = tdm_buffer_get_info(src)))
340                         LIST_ADDTAIL(&buf_info->link, &private_pp->src_pending_buffer_list);
341
342                 if ((buf_info = tdm_buffer_get_info(dst)))
343                         LIST_ADDTAIL(&buf_info->link, &private_pp->dst_pending_buffer_list);
344
345                 if (tdm_debug_buffer) {
346                         TDM_INFO("pp(%p) attached:", private_pp);
347                         tdm_buffer_list_dump(&private_pp->src_pending_buffer_list);
348                         tdm_buffer_list_dump(&private_pp->dst_pending_buffer_list);
349                 }
350         }
351
352         _pthread_mutex_unlock(&private_display->lock);
353
354         return ret;
355 }
356
357 EXTERN tdm_error
358 tdm_pp_commit(tdm_pp *pp)
359 {
360         tdm_buffer_info *b = NULL, *bb = NULL;
361
362         PP_FUNC_ENTRY();
363
364         _pthread_mutex_lock(&private_display->lock);
365
366         if (!func_pp->pp_commit) {
367                 _pthread_mutex_unlock(&private_display->lock);
368                 TDM_DBG("failed: not implemented!!");
369                 return TDM_ERROR_NOT_IMPLEMENTED;
370         }
371
372         ret = func_pp->pp_commit(private_pp->pp_backend);
373         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
374
375         if (ret == TDM_ERROR_NONE) {
376                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_pending_buffer_list, link) {
377                         LIST_DEL(&b->link);
378                         tdm_buffer_ref_backend(b->buffer);
379                         LIST_ADDTAIL(&b->link, &private_pp->src_buffer_list);
380                 }
381
382                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_pending_buffer_list, link) {
383                         LIST_DEL(&b->link);
384                         tdm_buffer_ref_backend(b->buffer);
385                         LIST_ADDTAIL(&b->link, &private_pp->dst_buffer_list);
386                 }
387         } else {
388                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_pending_buffer_list, link)
389                         LIST_DEL(&b->link);
390                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_pending_buffer_list, link)
391                         LIST_DEL(&b->link);
392         }
393
394         _pthread_mutex_unlock(&private_display->lock);
395
396         return ret;
397 }