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 (!tdm_thread_in_display_thread(private_display)) {
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, &pp_done.base);
114 TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
119 if (tdm_debug_buffer)
120 TDM_INFO("pp(%p) done: src(%p) dst(%p)", private_pp, src, dst);
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);
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);
130 if ((buf_info = tdm_buffer_get_info(src)))
131 LIST_DEL(&buf_info->link);
133 if ((buf_info = tdm_buffer_get_info(dst)))
134 LIST_DEL(&buf_info->link);
136 ret = pthread_mutex_trylock(&private_display->lock);
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;
144 tdm_buffer_unref_backend(src);
145 tdm_buffer_unref_backend(dst);
147 if (lock_after_cb_done)
148 _pthread_mutex_lock(&private_display->lock);
151 INTERN tdm_private_pp *
152 tdm_pp_find_stamp(tdm_private_display *private_display, unsigned long stamp)
154 tdm_private_pp *private_pp = NULL;
156 LIST_FOR_EACH_ENTRY(private_pp, &private_display->pp_list, link) {
157 if (private_pp->stamp == stamp)
164 INTERN tdm_private_pp *
165 tdm_pp_create_internal(tdm_private_display *private_display, tdm_error *error)
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;
173 func_display = &private_display->func_display;
174 func_pp = &private_display->func_pp;
176 if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP)) {
177 TDM_ERR("no pp capability");
179 *error = TDM_ERROR_NO_CAPABILITY;
183 pp_backend = func_display->display_create_pp(private_display->bdata, &ret);
184 if (ret != TDM_ERROR_NONE) {
190 private_pp = calloc(1, sizeof(tdm_private_pp));
192 TDM_ERR("failed: alloc memory");
193 func_pp->pp_destroy(pp_backend);
195 *error = TDM_ERROR_OUT_OF_MEMORY;
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);
208 private_pp->stamp = tdm_helper_get_time_in_millis();
209 while (tdm_pp_find_stamp(private_display, private_pp->stamp))
212 LIST_ADD(&private_pp->link, &private_display->pp_list);
213 private_pp->private_display = private_display;
214 private_pp->pp_backend = pp_backend;
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);
222 *error = TDM_ERROR_NONE;
228 tdm_pp_destroy_internal(tdm_private_pp *private_pp)
230 tdm_private_display *private_display;
231 tdm_func_pp *func_pp;
232 tdm_buffer_info *b = NULL, *bb = NULL;
237 private_display = private_pp->private_display;
238 func_pp = &private_display->func_pp;
240 LIST_DEL(&private_pp->link);
242 func_pp->pp_destroy(private_pp->pp_backend);
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);
248 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_pending_buffer_list, link) {
250 _pthread_mutex_unlock(&private_display->lock);
251 tdm_buffer_unref_backend(b->buffer);
252 _pthread_mutex_lock(&private_display->lock);
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);
260 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_pending_buffer_list, link) {
262 _pthread_mutex_unlock(&private_display->lock);
263 tdm_buffer_unref_backend(b->buffer);
264 _pthread_mutex_lock(&private_display->lock);
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);
272 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_buffer_list, link) {
274 _pthread_mutex_unlock(&private_display->lock);
275 tdm_buffer_unref_backend(b->buffer);
276 _pthread_mutex_lock(&private_display->lock);
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);
284 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_buffer_list, link) {
286 _pthread_mutex_unlock(&private_display->lock);
287 tdm_buffer_unref_backend(b->buffer);
288 _pthread_mutex_lock(&private_display->lock);
292 private_pp->stamp = 0;
297 tdm_pp_destroy(tdm_pp *pp)
299 tdm_private_pp *private_pp = pp;
300 tdm_private_display *private_display;
305 private_display = private_pp->private_display;
307 _pthread_mutex_lock(&private_display->lock);
308 tdm_pp_destroy_internal(private_pp);
309 _pthread_mutex_unlock(&private_display->lock);
313 tdm_pp_set_info(tdm_pp *pp, tdm_info_pp *info)
317 TDM_RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER);
319 _pthread_mutex_lock(&private_display->lock);
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;
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);
338 ret = func_pp->pp_set_info(private_pp->pp_backend, info);
339 TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
341 _pthread_mutex_unlock(&private_display->lock);
347 tdm_pp_attach(tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst)
351 TDM_RETURN_VAL_IF_FAIL(src != NULL, TDM_ERROR_INVALID_PARAMETER);
352 TDM_RETURN_VAL_IF_FAIL(dst != NULL, TDM_ERROR_INVALID_PARAMETER);
354 _pthread_mutex_lock(&private_display->lock);
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;
362 ret = _tdm_pp_check_if_exist(private_pp, src, dst);
363 if (ret != TDM_ERROR_NONE) {
364 _pthread_mutex_unlock(&private_display->lock);
368 ret = func_pp->pp_attach(private_pp->pp_backend, src, dst);
369 TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
371 if (ret == TDM_ERROR_NONE) {
372 tdm_buffer_info *buf_info;
374 if ((buf_info = tdm_buffer_get_info(src)))
375 LIST_ADDTAIL(&buf_info->link, &private_pp->src_pending_buffer_list);
377 if ((buf_info = tdm_buffer_get_info(dst)))
378 LIST_ADDTAIL(&buf_info->link, &private_pp->dst_pending_buffer_list);
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);
387 _pthread_mutex_unlock(&private_display->lock);
393 tdm_pp_commit(tdm_pp *pp)
395 tdm_buffer_info *b = NULL, *bb = NULL;
399 _pthread_mutex_lock(&private_display->lock);
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;
407 ret = func_pp->pp_commit(private_pp->pp_backend);
408 TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
410 if (ret == TDM_ERROR_NONE) {
411 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_pending_buffer_list, link) {
413 tdm_buffer_ref_backend(b->buffer);
414 LIST_ADDTAIL(&b->link, &private_pp->src_buffer_list);
417 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_pending_buffer_list, link) {
419 tdm_buffer_ref_backend(b->buffer);
420 LIST_ADDTAIL(&b->link, &private_pp->dst_buffer_list);
423 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->src_pending_buffer_list, link)
425 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_pp->dst_pending_buffer_list, link)
429 _pthread_mutex_unlock(&private_display->lock);