support thread
[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 INTERN 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_thread_in_display_thread(private_display)) {
103                 tdm_thread_cb_pp_done pp_done;
104                 tdm_error ret;
105
106                 pp_done.base.type = TDM_THREAD_CB_PP_DONE;
107                 pp_done.base.length = sizeof pp_done;
108                 pp_done.pp_stamp = private_pp->stamp;
109                 pp_done.src = src;
110                 pp_done.dst = dst;
111                 pp_done.user_data = user_data;
112
113                 ret = tdm_thread_send_cb(private_display, &pp_done.base);
114                 TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
115
116                 return;
117         }
118
119         if (tdm_debug_buffer)
120                 TDM_INFO("pp(%p) done: src(%p) dst(%p)", private_pp, src, dst);
121
122         first_entry = tdm_buffer_list_get_first_entry(&private_pp->src_buffer_list);
123         if (first_entry != src)
124                 TDM_ERR("src(%p) is skipped", first_entry);
125
126         first_entry = tdm_buffer_list_get_first_entry(&private_pp->dst_buffer_list);
127         if (first_entry != dst)
128                 TDM_ERR("dst(%p) is skipped", first_entry);
129
130         if ((buf_info = tdm_buffer_get_info(src)))
131                 LIST_DEL(&buf_info->link);
132
133         if ((buf_info = tdm_buffer_get_info(dst)))
134                 LIST_DEL(&buf_info->link);
135
136         ret = pthread_mutex_trylock(&private_display->lock);
137         if (ret == 0)
138                 _pthread_mutex_unlock(&private_display->lock);
139         else  if (ret == EBUSY) {
140                 _pthread_mutex_unlock(&private_display->lock);
141                 lock_after_cb_done = 1;
142         }
143
144         tdm_buffer_unref_backend(src);
145         tdm_buffer_unref_backend(dst);
146
147         if (lock_after_cb_done)
148                 _pthread_mutex_lock(&private_display->lock);
149 }
150
151 INTERN tdm_private_pp *
152 tdm_pp_find_stamp(tdm_private_display *private_display, unsigned long stamp)
153 {
154         tdm_private_pp *private_pp = NULL;
155
156         LIST_FOR_EACH_ENTRY(private_pp, &private_display->pp_list, link) {
157                 if (private_pp->stamp == stamp)
158                         return private_pp;
159         }
160
161         return NULL;
162 }
163
164 INTERN tdm_private_pp *
165 tdm_pp_create_internal(tdm_private_display *private_display, tdm_error *error)
166 {
167         tdm_func_display *func_display;
168         tdm_func_pp *func_pp;
169         tdm_private_pp *private_pp = NULL;
170         tdm_pp *pp_backend = NULL;
171         tdm_error ret = TDM_ERROR_NONE;
172
173         func_display = &private_display->func_display;
174         func_pp = &private_display->func_pp;
175
176         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP)) {
177                 TDM_ERR("no pp capability");
178                 if (error)
179                         *error = TDM_ERROR_NO_CAPABILITY;
180                 return NULL;
181         }
182
183         pp_backend = func_display->display_create_pp(private_display->bdata, &ret);
184         if (ret != TDM_ERROR_NONE) {
185                 if (error)
186                         *error = ret;
187                 return NULL;
188         }
189
190         private_pp = calloc(1, sizeof(tdm_private_pp));
191         if (!private_pp) {
192                 TDM_ERR("failed: alloc memory");
193                 func_pp->pp_destroy(pp_backend);
194                 if (error)
195                         *error = TDM_ERROR_OUT_OF_MEMORY;
196                 return NULL;
197         }
198
199         ret = func_pp->pp_set_done_handler(pp_backend, tdm_pp_cb_done, private_pp);
200         if (ret != TDM_ERROR_NONE) {
201                 TDM_ERR("spp(%p) et pp_done_handler failed", private_pp);
202                 func_pp->pp_destroy(pp_backend);
203                 if (error)
204                         *error = ret;
205                 return NULL;
206         }
207
208         private_pp->stamp = tdm_helper_get_time_in_millis();
209         while (tdm_pp_find_stamp(private_display, private_pp->stamp))
210                 private_pp->stamp++;
211
212         LIST_ADD(&private_pp->link, &private_display->pp_list);
213         private_pp->private_display = private_display;
214         private_pp->pp_backend = pp_backend;
215
216         LIST_INITHEAD(&private_pp->src_pending_buffer_list);
217         LIST_INITHEAD(&private_pp->dst_pending_buffer_list);
218         LIST_INITHEAD(&private_pp->src_buffer_list);
219         LIST_INITHEAD(&private_pp->dst_buffer_list);
220
221         if (error)
222                 *error = TDM_ERROR_NONE;
223
224         return private_pp;
225 }
226
227 INTERN void
228 tdm_pp_destroy_internal(tdm_private_pp *private_pp)
229 {
230         tdm_private_display *private_display;
231         tdm_func_pp *func_pp;
232         tdm_buffer_info *b = NULL, *bb = NULL;
233
234         if (!private_pp)
235                 return;
236
237         private_display = private_pp->private_display;
238         func_pp = &private_display->func_pp;
239
240         LIST_DEL(&private_pp->link);
241
242         func_pp->pp_destroy(private_pp->pp_backend);
243
244         if (!LIST_IS_EMPTY(&private_pp->src_pending_buffer_list)) {
245                 TDM_ERR("pp(%p) not finished:", private_pp);
246                 tdm_buffer_list_dump(&private_pp->src_pending_buffer_list);
247
248                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_pending_buffer_list, link) {
249                         LIST_DEL(&b->link);
250                         _pthread_mutex_unlock(&private_display->lock);
251                         tdm_buffer_unref_backend(b->buffer);
252                         _pthread_mutex_lock(&private_display->lock);
253                 }
254         }
255
256         if (!LIST_IS_EMPTY(&private_pp->dst_pending_buffer_list)) {
257                 TDM_ERR("pp(%p) not finished:", private_pp);
258                 tdm_buffer_list_dump(&private_pp->dst_pending_buffer_list);
259
260                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_pending_buffer_list, link) {
261                         LIST_DEL(&b->link);
262                         _pthread_mutex_unlock(&private_display->lock);
263                         tdm_buffer_unref_backend(b->buffer);
264                         _pthread_mutex_lock(&private_display->lock);
265                 }
266         }
267
268         if (!LIST_IS_EMPTY(&private_pp->src_buffer_list)) {
269                 TDM_ERR("pp(%p) not finished:", private_pp);
270                 tdm_buffer_list_dump(&private_pp->src_buffer_list);
271
272                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_buffer_list, link) {
273                         LIST_DEL(&b->link);
274                         _pthread_mutex_unlock(&private_display->lock);
275                         tdm_buffer_unref_backend(b->buffer);
276                         _pthread_mutex_lock(&private_display->lock);
277                 }
278         }
279
280         if (!LIST_IS_EMPTY(&private_pp->dst_buffer_list)) {
281                 TDM_ERR("pp(%p) not finished:", private_pp);
282                 tdm_buffer_list_dump(&private_pp->dst_buffer_list);
283
284                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_buffer_list, link) {
285                         LIST_DEL(&b->link);
286                         _pthread_mutex_unlock(&private_display->lock);
287                         tdm_buffer_unref_backend(b->buffer);
288                         _pthread_mutex_lock(&private_display->lock);
289                 }
290         }
291
292         private_pp->stamp = 0;
293         free(private_pp);
294 }
295
296 EXTERN void
297 tdm_pp_destroy(tdm_pp *pp)
298 {
299         tdm_private_pp *private_pp = pp;
300         tdm_private_display *private_display;
301
302         if (!private_pp)
303                 return;
304
305         private_display = private_pp->private_display;
306
307         _pthread_mutex_lock(&private_display->lock);
308         tdm_pp_destroy_internal(private_pp);
309         _pthread_mutex_unlock(&private_display->lock);
310 }
311
312 EXTERN tdm_error
313 tdm_pp_set_info(tdm_pp *pp, tdm_info_pp *info)
314 {
315         PP_FUNC_ENTRY();
316
317         TDM_RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER);
318
319         _pthread_mutex_lock(&private_display->lock);
320
321         if (!func_pp->pp_set_info) {
322                 _pthread_mutex_unlock(&private_display->lock);
323                 TDM_DBG("failed: not implemented!!");
324                 return TDM_ERROR_NOT_IMPLEMENTED;
325         }
326
327         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)",
328                  private_pp, info->src_config.size.h, info->src_config.size.v,
329                  info->src_config.pos.x, info->src_config.pos.y,
330                  info->src_config.pos.w, info->src_config.pos.h,
331                  FOURCC_STR(info->src_config.format),
332                  info->dst_config.size.h, info->dst_config.size.v,
333                  info->dst_config.pos.x, info->dst_config.pos.y,
334                  info->dst_config.pos.w, info->dst_config.pos.h,
335                  FOURCC_STR(info->dst_config.format),
336                  info->transform, info->sync, info->flags);
337
338         ret = func_pp->pp_set_info(private_pp->pp_backend, info);
339         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
340
341         _pthread_mutex_unlock(&private_display->lock);
342
343         return ret;
344 }
345
346 EXTERN tdm_error
347 tdm_pp_attach(tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst)
348 {
349         PP_FUNC_ENTRY();
350
351         TDM_RETURN_VAL_IF_FAIL(src != NULL, TDM_ERROR_INVALID_PARAMETER);
352         TDM_RETURN_VAL_IF_FAIL(dst != NULL, TDM_ERROR_INVALID_PARAMETER);
353
354         _pthread_mutex_lock(&private_display->lock);
355
356         if (!func_pp->pp_attach) {
357                 _pthread_mutex_unlock(&private_display->lock);
358                 TDM_DBG("failed: not implemented!!");
359                 return TDM_ERROR_NOT_IMPLEMENTED;
360         }
361
362         ret = _tdm_pp_check_if_exist(private_pp, src, dst);
363         if (ret != TDM_ERROR_NONE) {
364                 _pthread_mutex_unlock(&private_display->lock);
365                 return ret;
366         }
367
368         ret = func_pp->pp_attach(private_pp->pp_backend, src, dst);
369         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
370
371         if (ret == TDM_ERROR_NONE) {
372                 tdm_buffer_info *buf_info;
373
374                 if ((buf_info = tdm_buffer_get_info(src)))
375                         LIST_ADDTAIL(&buf_info->link, &private_pp->src_pending_buffer_list);
376
377                 if ((buf_info = tdm_buffer_get_info(dst)))
378                         LIST_ADDTAIL(&buf_info->link, &private_pp->dst_pending_buffer_list);
379
380                 if (tdm_debug_buffer) {
381                         TDM_INFO("pp(%p) attached:", private_pp);
382                         tdm_buffer_list_dump(&private_pp->src_pending_buffer_list);
383                         tdm_buffer_list_dump(&private_pp->dst_pending_buffer_list);
384                 }
385         }
386
387         _pthread_mutex_unlock(&private_display->lock);
388
389         return ret;
390 }
391
392 EXTERN tdm_error
393 tdm_pp_commit(tdm_pp *pp)
394 {
395         tdm_buffer_info *b = NULL, *bb = NULL;
396
397         PP_FUNC_ENTRY();
398
399         _pthread_mutex_lock(&private_display->lock);
400
401         if (!func_pp->pp_commit) {
402                 _pthread_mutex_unlock(&private_display->lock);
403                 TDM_DBG("failed: not implemented!!");
404                 return TDM_ERROR_NOT_IMPLEMENTED;
405         }
406
407         ret = func_pp->pp_commit(private_pp->pp_backend);
408         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
409
410         if (ret == TDM_ERROR_NONE) {
411                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_pending_buffer_list, link) {
412                         LIST_DEL(&b->link);
413                         tdm_buffer_ref_backend(b->buffer);
414                         LIST_ADDTAIL(&b->link, &private_pp->src_buffer_list);
415                 }
416
417                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_pending_buffer_list, link) {
418                         LIST_DEL(&b->link);
419                         tdm_buffer_ref_backend(b->buffer);
420                         LIST_ADDTAIL(&b->link, &private_pp->dst_buffer_list);
421                 }
422         } else {
423                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_pending_buffer_list, link)
424                         LIST_DEL(&b->link);
425                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_pending_buffer_list, link)
426                         LIST_DEL(&b->link);
427         }
428
429         _pthread_mutex_unlock(&private_display->lock);
430
431         return ret;
432 }