1 /**************************************************************************
5 Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
7 Contact: SooChan Lim <sc1.lim@samsung.com>
9 Permission is hereby granted, free of charge, to any person obtaining a
10 copy of this software and associated documentation files (the
11 "Software"), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sub license, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
17 The above copyright notice and this permission notice (including the
18 next paragraph) shall be included in all copies or substantial portions
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
24 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
25 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 **************************************************************************/
35 #include "tdm_backend_drm.h"
37 typedef struct _tdm_drm_pp_buffer {
41 struct list_head link;
44 typedef struct _tdm_drm_pp_data {
45 tdm_drm_display *display_data;
49 struct list_head pending_buffer_list;
51 hal_tdm_pp_done_handler done_func;
54 struct list_head link;
58 static tbm_format pp_formats[] = {
64 #define NUM_PP_FORMAT (sizeof(pp_formats) / sizeof(pp_formats[0]))
66 static int pp_list_init;
67 static struct list_head pp_list;
69 static pixman_format_code_t
70 _tdm_drm_pp_pixman_get_format(tbm_format tbmfmt)
73 case TBM_FORMAT_ARGB8888:
74 return PIXMAN_a8r8g8b8;
75 case TBM_FORMAT_XRGB8888:
76 return PIXMAN_x8r8g8b8;
77 case TBM_FORMAT_YUV420:
78 case TBM_FORMAT_YVU420:
86 _tdm_drm_pp_pixman_convert(pixman_op_t op,
87 unsigned char *srcbuf, unsigned char *dstbuf,
88 pixman_format_code_t src_format, pixman_format_code_t dst_format,
89 int sbw, int sbh, int sx, int sy, int sw, int sh,
90 int dbw, int dbh, int dx, int dy, int dw, int dh,
91 int rotate, int hflip, int vflip)
93 pixman_image_t *src_img;
94 pixman_image_t *dst_img;
95 struct pixman_f_transform ft;
96 pixman_transform_t transform;
97 int src_stride, dst_stride;
100 double scale_x, scale_y;
104 RETURN_VAL_IF_FAIL(srcbuf != NULL, 0);
105 RETURN_VAL_IF_FAIL(dstbuf != NULL, 0);
107 TDM_BACKEND_DBG("src(%dx%d: %d,%d %dx%d) dst(%dx%d: %d,%d %dx%d) flip(%d,%d), rot(%d)",
108 sbw, sbh, sx, sy, sw, sh, dbw, dbh, dx, dy, dw, dh, hflip, vflip, rotate);
110 src_bpp = PIXMAN_FORMAT_BPP(src_format) / 8;
111 RETURN_VAL_IF_FAIL(src_bpp > 0, 0);
113 dst_bpp = PIXMAN_FORMAT_BPP(dst_format) / 8;
114 RETURN_VAL_IF_FAIL(dst_bpp > 0, 0);
116 rotate_step = (rotate + 360) / 90 % 4;
118 src_stride = sbw * src_bpp;
119 dst_stride = dbw * dst_bpp;
121 src_img = pixman_image_create_bits(src_format, sbw, sbh, (uint32_t *)srcbuf,
123 dst_img = pixman_image_create_bits(dst_format, dbw, dbh, (uint32_t *)dstbuf,
126 GOTO_IF_FAIL(src_img != NULL, CANT_CONVERT);
127 GOTO_IF_FAIL(dst_img != NULL, CANT_CONVERT);
129 pixman_f_transform_init_identity(&ft);
132 pixman_f_transform_scale(&ft, NULL, -1, 1);
133 pixman_f_transform_translate(&ft, NULL, dw, 0);
137 pixman_f_transform_scale(&ft, NULL, 1, -1);
138 pixman_f_transform_translate(&ft, NULL, 0, dh);
141 if (rotate_step > 0) {
142 int c = 0, s = 0, tx = 0, ty = 0;
143 switch (rotate_step) {
144 case 1: /* 90 degrees */
147 case 2: /* 180 degrees */
148 c = -1, tx = -dw, ty = -dh;
150 case 3: /* 270 degrees */
155 pixman_f_transform_translate(&ft, NULL, tx, ty);
156 pixman_f_transform_rotate(&ft, NULL, c, s);
159 if (rotate_step % 2 == 0) {
160 scale_x = (double)sw / dw;
161 scale_y = (double)sh / dh;
163 scale_x = (double)sw / dh;
164 scale_y = (double)sh / dw;
167 pixman_f_transform_scale(&ft, NULL, scale_x, scale_y);
168 pixman_f_transform_translate(&ft, NULL, sx, sy);
170 pixman_transform_from_pixman_f_transform(&transform, &ft);
171 pixman_image_set_transform(src_img, &transform);
173 pixman_image_composite(op, src_img, NULL, dst_img, 0, 0, 0, 0, dx, dy, dw, dh);
179 pixman_image_unref(src_img);
181 pixman_image_unref(dst_img);
187 _tdm_drm_pp_convert(tdm_drm_pp_buffer *buffer, hal_tdm_info_pp *info)
189 tbm_surface_info_s src_info, dst_info;
190 pixman_format_code_t src_format, dst_format;
192 int rotate = 0, hflip = 0;
197 RETURN_VAL_IF_FAIL(buffer != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
198 RETURN_VAL_IF_FAIL(buffer->src != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
199 RETURN_VAL_IF_FAIL(buffer->dst != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
200 RETURN_VAL_IF_FAIL(info != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
202 bo_cnt = tbm_surface_internal_get_num_bos(buffer->src);
203 RETURN_VAL_IF_FAIL(bo_cnt == 1, HAL_TDM_ERROR_INVALID_PARAMETER);
205 bo_cnt = tbm_surface_internal_get_num_bos(buffer->dst);
206 RETURN_VAL_IF_FAIL(bo_cnt == 1, HAL_TDM_ERROR_INVALID_PARAMETER);
208 bo = tbm_surface_internal_get_bo(buffer->src, 0);
209 RETURN_VAL_IF_FAIL(bo != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
211 bo_size = tbm_bo_size(bo);
213 /* not handle buffers which have 2 more gem handles */
215 memset(&src_info, 0, sizeof(tbm_surface_info_s));
216 tbm_surface_map(buffer->src, TBM_OPTION_READ, &src_info);
217 GOTO_IF_FAIL(src_info.planes[0].ptr != NULL, fail_convert);
219 memset(&dst_info, 0, sizeof(tbm_surface_info_s));
220 tbm_surface_map(buffer->dst, TBM_OPTION_WRITE, &dst_info);
221 GOTO_IF_FAIL(dst_info.planes[0].ptr != NULL, fail_convert);
223 src_format = _tdm_drm_pp_pixman_get_format(src_info.format);
224 GOTO_IF_FAIL(src_format > 0, fail_convert);
225 dst_format = _tdm_drm_pp_pixman_get_format(dst_info.format);
226 GOTO_IF_FAIL(dst_format > 0, fail_convert);
228 GOTO_IF_FAIL(pixman_format_supported_destination(dst_format), fail_convert);
230 if (src_info.format == TBM_FORMAT_YUV420) {
231 if (dst_info.format == TBM_FORMAT_XRGB8888)
232 dst_format = PIXMAN_x8b8g8r8;
233 else if (dst_info.format == TBM_FORMAT_ARGB8888)
234 dst_format = PIXMAN_a8b8g8r8;
235 else if (dst_info.format == TBM_FORMAT_YVU420) {
236 TDM_BACKEND_ERR("can't convert %c%c%c%c to %c%c%c%c",
237 FOURCC_STR(src_info.format), FOURCC_STR(dst_info.format));
241 /* need checking for other formats also? */
243 if (IS_RGB(src_info.format))
244 sbw = src_info.planes[0].stride >> 2;
246 sbw = src_info.planes[0].stride;
248 if (IS_RGB(dst_info.format))
249 dbw = dst_info.planes[0].stride >> 2;
251 dbw = dst_info.planes[0].stride;
253 rotate = (info->transform % 4) * 90;
254 if (info->transform >= HAL_TDM_TRANSFORM_FLIPPED)
257 if (bo_size < src_info.planes[0].stride * src_info.height) {
258 TDM_BACKEND_WRN("bo size(%d) is smaller than the expected size(%d)",
259 bo_size, src_info.planes[0].stride * src_info.height);
263 _tdm_drm_pp_pixman_convert(PIXMAN_OP_SRC,
264 src_info.planes[0].ptr, dst_info.planes[0].ptr,
265 src_format, dst_format,
266 sbw, src_info.height,
267 info->src_config.pos.x, info->src_config.pos.y,
268 info->src_config.pos.w, info->src_config.pos.h,
269 dbw, dst_info.height,
270 info->dst_config.pos.x, info->dst_config.pos.y,
271 info->dst_config.pos.w, info->dst_config.pos.h,
273 tbm_surface_unmap(buffer->src);
274 tbm_surface_unmap(buffer->dst);
276 return HAL_TDM_ERROR_NONE;
278 tbm_surface_unmap(buffer->src);
279 tbm_surface_unmap(buffer->dst);
280 return HAL_TDM_ERROR_OPERATION_FAILED;
284 tdm_drm_pp_get_capability(tdm_drm_display *display_data, hal_tdm_caps_pp *caps)
289 TDM_BACKEND_ERR("invalid params");
290 return HAL_TDM_ERROR_INVALID_PARAMETER;
293 caps->capabilities = HAL_TDM_PP_CAPABILITY_SYNC;
295 caps->format_count = NUM_PP_FORMAT;
297 /* will be freed in frontend */
298 caps->formats = calloc(1, sizeof pp_formats);
299 if (!caps->formats) {
300 TDM_BACKEND_ERR("alloc failed");
301 return HAL_TDM_ERROR_OUT_OF_MEMORY;
303 for (i = 0; i < caps->format_count; i++)
304 caps->formats[i] = pp_formats[i];
308 caps->max_w = -1; /* not defined */
310 caps->preferred_align = 16;
312 return HAL_TDM_ERROR_NONE;
316 tdm_drm_pp_create(tdm_drm_display *display_data, hal_tdm_error *error)
318 tdm_drm_pp_data *pp_data = calloc(1, sizeof(tdm_drm_pp_data));
320 TDM_BACKEND_ERR("alloc failed");
322 *error = HAL_TDM_ERROR_OUT_OF_MEMORY;
326 pp_data->display_data = display_data;
328 LIST_INITHEAD(&pp_data->pending_buffer_list);
332 LIST_INITHEAD(&pp_list);
334 LIST_ADDTAIL(&pp_data->link, &pp_list);
340 drm_pp_destroy(hal_tdm_pp *pp)
342 tdm_drm_pp_data *pp_data = pp;
343 tdm_drm_pp_buffer *b = NULL, *bb = NULL;
348 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, link) {
353 LIST_DEL(&pp_data->link);
359 drm_pp_set_info(hal_tdm_pp *pp, hal_tdm_info_pp *info)
361 tdm_drm_pp_data *pp_data = pp;
363 RETURN_VAL_IF_FAIL(pp_data, HAL_TDM_ERROR_INVALID_PARAMETER);
364 RETURN_VAL_IF_FAIL(info, HAL_TDM_ERROR_INVALID_PARAMETER);
366 pp_data->info = *info;
368 return HAL_TDM_ERROR_NONE;
372 drm_pp_attach(hal_tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst)
374 tdm_drm_pp_data *pp_data = pp;
375 tdm_drm_pp_buffer *buffer;
377 RETURN_VAL_IF_FAIL(pp_data, HAL_TDM_ERROR_INVALID_PARAMETER);
378 RETURN_VAL_IF_FAIL(src, HAL_TDM_ERROR_INVALID_PARAMETER);
379 RETURN_VAL_IF_FAIL(dst, HAL_TDM_ERROR_INVALID_PARAMETER);
381 if (tbm_surface_internal_get_num_bos(src) > 1 ||
382 tbm_surface_internal_get_num_bos(dst) > 1) {
383 TDM_BACKEND_ERR("can't handle multiple tbm bos");
384 return HAL_TDM_ERROR_OPERATION_FAILED;
387 buffer = calloc(1, sizeof(tdm_drm_pp_buffer));
389 TDM_BACKEND_ERR("alloc failed");
390 return HAL_TDM_ERROR_NONE;
393 LIST_ADDTAIL(&buffer->link, &pp_data->pending_buffer_list);
398 return HAL_TDM_ERROR_NONE;
402 drm_pp_commit(hal_tdm_pp *pp)
404 tdm_drm_pp_data *pp_data = pp;
405 tdm_drm_pp_buffer *b = NULL, *bb = NULL;
407 RETURN_VAL_IF_FAIL(pp_data, HAL_TDM_ERROR_INVALID_PARAMETER);
409 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, link) {
412 _tdm_drm_pp_convert(b, &pp_data->info);
414 if (pp_data->done_func)
415 pp_data->done_func(pp_data,
418 pp_data->done_user_data);
422 return HAL_TDM_ERROR_NONE;
426 drm_pp_set_done_handler(hal_tdm_pp *pp, hal_tdm_pp_done_handler func, void *user_data)
428 tdm_drm_pp_data *pp_data = pp;
430 RETURN_VAL_IF_FAIL(pp_data, HAL_TDM_ERROR_INVALID_PARAMETER);
431 RETURN_VAL_IF_FAIL(func, HAL_TDM_ERROR_INVALID_PARAMETER);
433 pp_data->done_func = func;
434 pp_data->done_user_data = user_data;
436 return HAL_TDM_ERROR_NONE;