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