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 **************************************************************************/
38 #include "tdm_helper.h"
40 typedef struct _tdm_drm_pp_buffer {
44 struct list_head link;
47 typedef struct _tdm_drm_pp_data {
48 tdm_drm_data *drm_data;
52 struct list_head pending_buffer_list;
54 tdm_pp_done_handler done_func;
57 struct list_head link;
61 static tbm_format pp_formats[] = {
67 #define NUM_PP_FORMAT (sizeof(pp_formats) / sizeof(pp_formats[0]))
69 static int pp_list_init;
70 static struct list_head pp_list;
72 static pixman_format_code_t
73 _tdm_drm_pp_pixman_get_format(tbm_format tbmfmt)
76 case TBM_FORMAT_ARGB8888:
77 return PIXMAN_a8r8g8b8;
78 case TBM_FORMAT_XRGB8888:
79 return PIXMAN_x8r8g8b8;
80 case TBM_FORMAT_YUV420:
81 case TBM_FORMAT_YVU420:
89 _tdm_drm_pp_pixman_convert(pixman_op_t op,
90 unsigned char *srcbuf, unsigned char *dstbuf,
91 pixman_format_code_t src_format, pixman_format_code_t dst_format,
92 int sbw, int sbh, int sx, int sy, int sw, int sh,
93 int dbw, int dbh, int dx, int dy, int dw, int dh,
94 int rotate, int hflip, int vflip)
96 pixman_image_t *src_img;
97 pixman_image_t *dst_img;
98 struct pixman_f_transform ft;
99 pixman_transform_t transform;
100 int src_stride, dst_stride;
103 double scale_x, scale_y;
107 RETURN_VAL_IF_FAIL(srcbuf != NULL, 0);
108 RETURN_VAL_IF_FAIL(dstbuf != NULL, 0);
110 TDM_DBG("src(%dx%d: %d,%d %dx%d) dst(%dx%d: %d,%d %dx%d) flip(%d,%d), rot(%d)",
111 sbw, sbh, sx, sy, sw, sh, dbw, dbh, dx, dy, dw, dh, hflip, vflip, rotate);
113 src_bpp = PIXMAN_FORMAT_BPP(src_format) / 8;
114 RETURN_VAL_IF_FAIL(src_bpp > 0, 0);
116 dst_bpp = PIXMAN_FORMAT_BPP(dst_format) / 8;
117 RETURN_VAL_IF_FAIL(dst_bpp > 0, 0);
119 rotate_step = (rotate + 360) / 90 % 4;
121 src_stride = sbw * src_bpp;
122 dst_stride = dbw * dst_bpp;
124 src_img = pixman_image_create_bits(src_format, sbw, sbh, (uint32_t *)srcbuf,
126 dst_img = pixman_image_create_bits(dst_format, dbw, dbh, (uint32_t *)dstbuf,
129 GOTO_IF_FAIL(src_img != NULL, CANT_CONVERT);
130 GOTO_IF_FAIL(dst_img != NULL, CANT_CONVERT);
132 pixman_f_transform_init_identity(&ft);
135 pixman_f_transform_scale(&ft, NULL, -1, 1);
136 pixman_f_transform_translate(&ft, NULL, dw, 0);
140 pixman_f_transform_scale(&ft, NULL, 1, -1);
141 pixman_f_transform_translate(&ft, NULL, 0, dh);
144 if (rotate_step > 0) {
145 int c = 0, s = 0, tx = 0, ty = 0;
146 switch (rotate_step) {
147 case 1: /* 90 degrees */
150 case 2: /* 180 degrees */
151 c = -1, tx = -dw, ty = -dh;
153 case 3: /* 270 degrees */
158 pixman_f_transform_translate(&ft, NULL, tx, ty);
159 pixman_f_transform_rotate(&ft, NULL, c, s);
162 if (rotate_step % 2 == 0) {
163 scale_x = (double)sw / dw;
164 scale_y = (double)sh / dh;
166 scale_x = (double)sw / dh;
167 scale_y = (double)sh / dw;
170 pixman_f_transform_scale(&ft, NULL, scale_x, scale_y);
171 pixman_f_transform_translate(&ft, NULL, sx, sy);
173 pixman_transform_from_pixman_f_transform(&transform, &ft);
174 pixman_image_set_transform(src_img, &transform);
176 pixman_image_composite(op, src_img, NULL, dst_img, 0, 0, 0, 0, dx, dy, dw, dh);
182 pixman_image_unref(src_img);
184 pixman_image_unref(dst_img);
190 _tdm_drm_pp_convert(tdm_drm_pp_buffer *buffer, tdm_info_pp *info)
192 tbm_surface_info_s src_info, dst_info;
193 pixman_format_code_t src_format, dst_format;
195 int rotate = 0, hflip = 0;
200 RETURN_VAL_IF_FAIL(buffer != NULL, TDM_ERROR_INVALID_PARAMETER);
201 RETURN_VAL_IF_FAIL(buffer->src != NULL, TDM_ERROR_INVALID_PARAMETER);
202 RETURN_VAL_IF_FAIL(buffer->dst != NULL, TDM_ERROR_INVALID_PARAMETER);
203 RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER);
205 bo_cnt = tbm_surface_internal_get_num_bos(buffer->src);
206 RETURN_VAL_IF_FAIL(bo_cnt == 1, TDM_ERROR_INVALID_PARAMETER);
208 bo_cnt = tbm_surface_internal_get_num_bos(buffer->dst);
209 RETURN_VAL_IF_FAIL(bo_cnt == 1, TDM_ERROR_INVALID_PARAMETER);
211 bo = tbm_surface_internal_get_bo(buffer->src, 0);
212 RETURN_VAL_IF_FAIL(bo != NULL, TDM_ERROR_INVALID_PARAMETER);
214 bo_size = tbm_bo_size(bo);
216 /* not handle buffers which have 2 more gem handles */
218 memset(&src_info, 0, sizeof(tbm_surface_info_s));
219 tbm_surface_map(buffer->src, TBM_OPTION_READ, &src_info);
220 GOTO_IF_FAIL(src_info.planes[0].ptr != NULL, fail_convert);
222 memset(&dst_info, 0, sizeof(tbm_surface_info_s));
223 tbm_surface_map(buffer->dst, TBM_OPTION_WRITE, &dst_info);
224 GOTO_IF_FAIL(dst_info.planes[0].ptr != NULL, fail_convert);
226 src_format = _tdm_drm_pp_pixman_get_format(src_info.format);
227 GOTO_IF_FAIL(src_format > 0, fail_convert);
228 dst_format = _tdm_drm_pp_pixman_get_format(dst_info.format);
229 GOTO_IF_FAIL(dst_format > 0, fail_convert);
231 GOTO_IF_FAIL(pixman_format_supported_destination(dst_format), fail_convert);
233 if (src_info.format == TBM_FORMAT_YUV420) {
234 if (dst_info.format == TBM_FORMAT_XRGB8888)
235 dst_format = PIXMAN_x8b8g8r8;
236 else if (dst_info.format == TBM_FORMAT_ARGB8888)
237 dst_format = PIXMAN_a8b8g8r8;
238 else if (dst_info.format == TBM_FORMAT_YVU420) {
239 TDM_ERR("can't convert %c%c%c%c to %c%c%c%c",
240 FOURCC_STR(src_info.format), FOURCC_STR(dst_info.format));
244 /* need checking for other formats also? */
246 if (IS_RGB(src_info.format))
247 sbw = src_info.planes[0].stride >> 2;
249 sbw = src_info.planes[0].stride;
251 if (IS_RGB(dst_info.format))
252 dbw = dst_info.planes[0].stride >> 2;
254 dbw = dst_info.planes[0].stride;
256 rotate = (info->transform % 4) * 90;
257 if (info->transform >= TDM_TRANSFORM_FLIPPED)
260 if (bo_size < src_info.planes[0].stride * src_info.height) {
261 TDM_WRN("bo size(%d) is smaller than the expected size(%d)",
262 bo_size, src_info.planes[0].stride * src_info.height);
266 _tdm_drm_pp_pixman_convert(PIXMAN_OP_SRC,
267 src_info.planes[0].ptr, dst_info.planes[0].ptr,
268 src_format, dst_format,
269 sbw, src_info.height,
270 info->src_config.pos.x, info->src_config.pos.y,
271 info->src_config.pos.w, info->src_config.pos.h,
272 dbw, dst_info.height,
273 info->dst_config.pos.x, info->dst_config.pos.y,
274 info->dst_config.pos.w, info->dst_config.pos.h,
276 tbm_surface_unmap(buffer->src);
277 tbm_surface_unmap(buffer->dst);
279 return TDM_ERROR_NONE;
281 tbm_surface_unmap(buffer->src);
282 tbm_surface_unmap(buffer->dst);
283 return TDM_ERROR_OPERATION_FAILED;
287 tdm_drm_pp_get_capability(tdm_drm_data *drm_data, tdm_caps_pp *caps)
292 TDM_ERR("invalid params");
293 return TDM_ERROR_INVALID_PARAMETER;
296 caps->capabilities = TDM_PP_CAPABILITY_SYNC;
298 caps->format_count = NUM_PP_FORMAT;
300 /* will be freed in frontend */
301 caps->formats = calloc(1, sizeof pp_formats);
302 if (!caps->formats) {
303 TDM_ERR("alloc failed");
304 return TDM_ERROR_OUT_OF_MEMORY;
306 for (i = 0; i < caps->format_count; i++)
307 caps->formats[i] = pp_formats[i];
311 caps->max_w = -1; /* not defined */
313 caps->preferred_align = 16;
315 return TDM_ERROR_NONE;
319 tdm_drm_pp_create(tdm_drm_data *drm_data, tdm_error *error)
321 tdm_drm_pp_data *pp_data = calloc(1, sizeof(tdm_drm_pp_data));
323 TDM_ERR("alloc failed");
325 *error = TDM_ERROR_OUT_OF_MEMORY;
329 pp_data->drm_data = drm_data;
331 LIST_INITHEAD(&pp_data->pending_buffer_list);
335 LIST_INITHEAD(&pp_list);
337 LIST_ADDTAIL(&pp_data->link, &pp_list);
343 drm_pp_destroy(tdm_pp *pp)
345 tdm_drm_pp_data *pp_data = pp;
346 tdm_drm_pp_buffer *b = NULL, *bb = NULL;
351 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, link) {
356 LIST_DEL(&pp_data->link);
362 drm_pp_set_info(tdm_pp *pp, tdm_info_pp *info)
364 tdm_drm_pp_data *pp_data = pp;
366 RETURN_VAL_IF_FAIL(pp_data, TDM_ERROR_INVALID_PARAMETER);
367 RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
369 pp_data->info = *info;
371 return TDM_ERROR_NONE;
375 drm_pp_attach(tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst)
377 tdm_drm_pp_data *pp_data = pp;
378 tdm_drm_pp_buffer *buffer;
380 RETURN_VAL_IF_FAIL(pp_data, TDM_ERROR_INVALID_PARAMETER);
381 RETURN_VAL_IF_FAIL(src, TDM_ERROR_INVALID_PARAMETER);
382 RETURN_VAL_IF_FAIL(dst, TDM_ERROR_INVALID_PARAMETER);
384 if (tbm_surface_internal_get_num_bos(src) > 1 ||
385 tbm_surface_internal_get_num_bos(dst) > 1) {
386 TDM_ERR("can't handle multiple tbm bos");
387 return TDM_ERROR_OPERATION_FAILED;
390 buffer = calloc(1, sizeof(tdm_drm_pp_buffer));
392 TDM_ERR("alloc failed");
393 return TDM_ERROR_NONE;
396 LIST_ADDTAIL(&buffer->link, &pp_data->pending_buffer_list);
401 return TDM_ERROR_NONE;
405 drm_pp_commit(tdm_pp *pp)
407 tdm_drm_pp_data *pp_data = pp;
408 tdm_drm_pp_buffer *b = NULL, *bb = NULL;
410 RETURN_VAL_IF_FAIL(pp_data, TDM_ERROR_INVALID_PARAMETER);
412 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, link) {
415 _tdm_drm_pp_convert(b, &pp_data->info);
417 if (pp_data->done_func)
418 pp_data->done_func(pp_data,
421 pp_data->done_user_data);
425 return TDM_ERROR_NONE;
429 drm_pp_set_done_handler(tdm_pp *pp, tdm_pp_done_handler func, void *user_data)
431 tdm_drm_pp_data *pp_data = pp;
433 RETURN_VAL_IF_FAIL(pp_data, TDM_ERROR_INVALID_PARAMETER);
434 RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
436 pp_data->done_func = func;
437 pp_data->done_user_data = user_data;
439 return TDM_ERROR_NONE;