1 /**************************************************************************
5 Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
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>
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:
22 The above copyright notice and this permission notice (including the
23 next paragraph) shall be included in all copies or substantial portions
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.
34 **************************************************************************/
41 #include "tdm_backend.h"
42 #include "tdm_private.h"
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
55 _tdm_pp_check_if_exist(tdm_private_pp *private_pp,
56 tbm_surface_h src, tbm_surface_h dst)
58 tdm_buffer_info *buf_info = NULL;
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;
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;
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;
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;
88 return TDM_ERROR_NONE;
92 tdm_pp_cb_done(tdm_pp *pp_backend, tbm_surface_h src, tbm_surface_h dst,
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;
102 if (private_pp->owner_tid != syscall(SYS_gettid)) {
103 tdm_thread_cb_pp_done pp_done;
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;
111 pp_done.user_data = user_data;
113 ret = tdm_thread_send_cb(private_display->private_loop, &pp_done.base);
114 TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
119 if (private_pp->owner_tid != syscall(SYS_gettid))
120 TDM_NEVER_GET_HERE();
122 if (tdm_debug_buffer)
123 TDM_INFO("pp(%p) done: src(%p) dst(%p)", private_pp, src, dst);
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);
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);
133 if ((buf_info = tdm_buffer_get_info(src)))
134 LIST_DEL(&buf_info->link);
136 if ((buf_info = tdm_buffer_get_info(dst)))
137 LIST_DEL(&buf_info->link);
139 ret = pthread_mutex_trylock(&private_display->lock);
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;
147 tdm_buffer_unref_backend(src);
148 tdm_buffer_unref_backend(dst);
150 if (lock_after_cb_done)
151 _pthread_mutex_lock(&private_display->lock);
154 INTERN tdm_private_pp *
155 tdm_pp_find_stamp(tdm_private_display *private_display, unsigned long stamp)
157 tdm_private_pp *private_pp = NULL;
159 LIST_FOR_EACH_ENTRY(private_pp, &private_display->pp_list, link) {
160 if (private_pp->stamp == stamp)
167 INTERN tdm_private_pp *
168 tdm_pp_create_internal(tdm_private_display *private_display, tdm_error *error)
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;
176 func_display = &private_display->func_display;
177 func_pp = &private_display->func_pp;
179 if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP)) {
180 TDM_ERR("no pp capability");
182 *error = TDM_ERROR_NO_CAPABILITY;
186 pp_backend = func_display->display_create_pp(private_display->bdata, &ret);
187 if (ret != TDM_ERROR_NONE) {
193 private_pp = calloc(1, sizeof(tdm_private_pp));
195 TDM_ERR("failed: alloc memory");
196 func_pp->pp_destroy(pp_backend);
198 *error = TDM_ERROR_OUT_OF_MEMORY;
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);
211 private_pp->stamp = tdm_helper_get_time_in_millis();
212 while (tdm_pp_find_stamp(private_display, private_pp->stamp))
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);
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);
226 *error = TDM_ERROR_NONE;
232 tdm_pp_destroy_internal(tdm_private_pp *private_pp)
234 tdm_private_display *private_display;
235 tdm_func_pp *func_pp;
236 tdm_buffer_info *b = NULL, *bb = NULL;
241 private_display = private_pp->private_display;
242 func_pp = &private_display->func_pp;
244 LIST_DEL(&private_pp->link);
246 func_pp->pp_destroy(private_pp->pp_backend);
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);
252 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_pending_buffer_list, link) {
254 _pthread_mutex_unlock(&private_display->lock);
255 tdm_buffer_unref_backend(b->buffer);
256 _pthread_mutex_lock(&private_display->lock);
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);
264 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_pending_buffer_list, link) {
266 _pthread_mutex_unlock(&private_display->lock);
267 tdm_buffer_unref_backend(b->buffer);
268 _pthread_mutex_lock(&private_display->lock);
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);
276 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_buffer_list, link) {
278 _pthread_mutex_unlock(&private_display->lock);
279 tdm_buffer_unref_backend(b->buffer);
280 _pthread_mutex_lock(&private_display->lock);
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);
288 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_buffer_list, link) {
290 _pthread_mutex_unlock(&private_display->lock);
291 tdm_buffer_unref_backend(b->buffer);
292 _pthread_mutex_lock(&private_display->lock);
296 private_pp->stamp = 0;
301 tdm_pp_destroy(tdm_pp *pp)
303 tdm_private_pp *private_pp = pp;
304 tdm_private_display *private_display;
309 private_display = private_pp->private_display;
311 _pthread_mutex_lock(&private_display->lock);
312 tdm_pp_destroy_internal(private_pp);
313 _pthread_mutex_unlock(&private_display->lock);
317 tdm_pp_set_info(tdm_pp *pp, tdm_info_pp *info)
321 TDM_RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER);
323 _pthread_mutex_lock(&private_display->lock);
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;
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);
342 ret = func_pp->pp_set_info(private_pp->pp_backend, info);
343 TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
345 _pthread_mutex_unlock(&private_display->lock);
351 tdm_pp_attach(tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst)
355 TDM_RETURN_VAL_IF_FAIL(src != NULL, TDM_ERROR_INVALID_PARAMETER);
356 TDM_RETURN_VAL_IF_FAIL(dst != NULL, TDM_ERROR_INVALID_PARAMETER);
358 _pthread_mutex_lock(&private_display->lock);
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;
366 ret = _tdm_pp_check_if_exist(private_pp, src, dst);
367 if (ret != TDM_ERROR_NONE) {
368 _pthread_mutex_unlock(&private_display->lock);
372 ret = func_pp->pp_attach(private_pp->pp_backend, src, dst);
373 TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
375 if (ret == TDM_ERROR_NONE) {
376 tdm_buffer_info *buf_info;
378 if ((buf_info = tdm_buffer_get_info(src)))
379 LIST_ADDTAIL(&buf_info->link, &private_pp->src_pending_buffer_list);
381 if ((buf_info = tdm_buffer_get_info(dst)))
382 LIST_ADDTAIL(&buf_info->link, &private_pp->dst_pending_buffer_list);
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);
391 _pthread_mutex_unlock(&private_display->lock);
397 tdm_pp_commit(tdm_pp *pp)
399 tdm_buffer_info *b = NULL, *bb = NULL;
403 _pthread_mutex_lock(&private_display->lock);
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;
411 ret = func_pp->pp_commit(private_pp->pp_backend);
412 TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
414 if (ret == TDM_ERROR_NONE) {
415 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_pending_buffer_list, link) {
417 tdm_buffer_ref_backend(b->buffer);
418 LIST_ADDTAIL(&b->link, &private_pp->src_buffer_list);
421 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_pending_buffer_list, link) {
423 tdm_buffer_ref_backend(b->buffer);
424 LIST_ADDTAIL(&b->link, &private_pp->dst_buffer_list);
427 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_pending_buffer_list, link)
429 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_pending_buffer_list, link)
433 _pthread_mutex_unlock(&private_display->lock);