9a277836cb30757d3dc4d8016310bd84210832a6
[platform/adaptation/libtdm-drm.git] / src / libhal-backend-tdm-drm / tdm_drm_pp.c
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #include "tdm_backend_drm.h"
6
7 typedef struct _tdm_drm_pp_buffer {
8         tbm_surface_h src;
9         tbm_surface_h dst;
10
11         struct list_head link;
12 } tdm_drm_pp_buffer;
13
14 typedef struct _tdm_drm_pp_data {
15         tdm_drm_display *display_data;
16
17         hal_tdm_info_pp info;
18
19         struct list_head pending_buffer_list;
20
21         hal_tdm_pp_done_handler done_func;
22         void *done_user_data;
23
24         struct list_head link;
25 } tdm_drm_pp_data;
26
27
28 static tbm_format pp_formats[] = {
29         TBM_FORMAT_ARGB8888,
30         TBM_FORMAT_XRGB8888,
31         TBM_FORMAT_YUV420,
32 };
33
34 #define NUM_PP_FORMAT   (sizeof(pp_formats) / sizeof(pp_formats[0]))
35
36 static int pp_list_init;
37 static struct list_head pp_list;
38
39 static pixman_format_code_t
40 _tdm_drm_pp_pixman_get_format(tbm_format tbmfmt)
41 {
42         switch (tbmfmt) {
43         case TBM_FORMAT_ARGB8888:
44                 return PIXMAN_a8r8g8b8;
45         case TBM_FORMAT_XRGB8888:
46                 return PIXMAN_x8r8g8b8;
47         case TBM_FORMAT_YUV420:
48         case TBM_FORMAT_YVU420:
49                 return PIXMAN_yv12;
50         default:
51                 return 0;
52         }
53 }
54
55 int
56 _tdm_drm_pp_pixman_convert(pixman_op_t op,
57                                                    unsigned char *srcbuf, unsigned char *dstbuf,
58                                                    pixman_format_code_t src_format, pixman_format_code_t dst_format,
59                                                    int sbw, int sbh, int sx, int sy, int sw, int sh,
60                                                    int dbw, int dbh, int dx, int dy, int dw, int dh,
61                                                    int rotate, int hflip, int vflip)
62 {
63         pixman_image_t  *src_img;
64         pixman_image_t  *dst_img;
65         struct pixman_f_transform ft;
66         pixman_transform_t transform;
67         int                             src_stride, dst_stride;
68         int                             src_bpp;
69         int                             dst_bpp;
70         double                   scale_x, scale_y;
71         int                             rotate_step;
72         int                             ret = 0;
73
74         RETURN_VAL_IF_FAIL(srcbuf != NULL, 0);
75         RETURN_VAL_IF_FAIL(dstbuf != NULL, 0);
76
77         TDM_BACKEND_DBG("src(%dx%d: %d,%d %dx%d) dst(%dx%d: %d,%d %dx%d) flip(%d,%d), rot(%d)",
78                         sbw, sbh, sx, sy, sw, sh, dbw, dbh, dx, dy, dw, dh, hflip, vflip, rotate);
79
80         src_bpp = PIXMAN_FORMAT_BPP(src_format) / 8;
81         RETURN_VAL_IF_FAIL(src_bpp > 0, 0);
82
83         dst_bpp = PIXMAN_FORMAT_BPP(dst_format) / 8;
84         RETURN_VAL_IF_FAIL(dst_bpp > 0, 0);
85
86         rotate_step = (rotate + 360) / 90 % 4;
87
88         src_stride = sbw * src_bpp;
89         dst_stride = dbw * dst_bpp;
90
91         src_img = pixman_image_create_bits(src_format, sbw, sbh, (uint32_t *)srcbuf,
92                                                                            src_stride);
93         dst_img = pixman_image_create_bits(dst_format, dbw, dbh, (uint32_t *)dstbuf,
94                                                                            dst_stride);
95
96         GOTO_IF_FAIL(src_img != NULL, CANT_CONVERT);
97         GOTO_IF_FAIL(dst_img != NULL, CANT_CONVERT);
98
99         pixman_f_transform_init_identity(&ft);
100
101         if (hflip) {
102                 pixman_f_transform_scale(&ft, NULL, -1, 1);
103                 pixman_f_transform_translate(&ft, NULL, dw, 0);
104         }
105
106         if (vflip) {
107                 pixman_f_transform_scale(&ft, NULL, 1, -1);
108                 pixman_f_transform_translate(&ft, NULL, 0, dh);
109         }
110
111         if (rotate_step > 0) {
112                 int c = 0, s = 0, tx = 0, ty = 0;
113                 switch (rotate_step) {
114                 case 1: /* 90 degrees */
115                         s = -1, tx = -dw;
116                         break;
117                 case 2: /* 180 degrees */
118                         c = -1, tx = -dw, ty = -dh;
119                         break;
120                 case 3: /* 270 degrees */
121                         s = 1, ty = -dh;
122                         break;
123                 }
124
125                 pixman_f_transform_translate(&ft, NULL, tx, ty);
126                 pixman_f_transform_rotate(&ft, NULL, c, s);
127         }
128
129         if (rotate_step % 2 == 0) {
130                 scale_x = (double)sw / dw;
131                 scale_y = (double)sh / dh;
132         } else {
133                 scale_x = (double)sw / dh;
134                 scale_y = (double)sh / dw;
135         }
136
137         pixman_f_transform_scale(&ft, NULL, scale_x, scale_y);
138         pixman_f_transform_translate(&ft, NULL, sx, sy);
139
140         pixman_transform_from_pixman_f_transform(&transform, &ft);
141         pixman_image_set_transform(src_img, &transform);
142
143         pixman_image_composite(op, src_img, NULL, dst_img, 0, 0, 0, 0, dx, dy, dw, dh);
144
145         ret = 1;
146
147 CANT_CONVERT:
148         if (src_img)
149                 pixman_image_unref(src_img);
150         if (dst_img)
151                 pixman_image_unref(dst_img);
152
153         return ret;
154 }
155
156 static hal_tdm_error
157 _tdm_drm_pp_convert(tdm_drm_pp_buffer *buffer, hal_tdm_info_pp *info)
158 {
159         tbm_surface_info_s src_info, dst_info;
160         pixman_format_code_t src_format, dst_format;
161         int sbw, dbw;
162         int rotate = 0, hflip = 0;
163         tbm_bo bo = NULL;
164         int bo_cnt = 0;
165         int bo_size = 0;
166
167         RETURN_VAL_IF_FAIL(buffer != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
168         RETURN_VAL_IF_FAIL(buffer->src != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
169         RETURN_VAL_IF_FAIL(buffer->dst != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
170         RETURN_VAL_IF_FAIL(info != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
171
172         bo_cnt = tbm_surface_internal_get_num_bos(buffer->src);
173         RETURN_VAL_IF_FAIL(bo_cnt == 1, HAL_TDM_ERROR_INVALID_PARAMETER);
174
175         bo_cnt = tbm_surface_internal_get_num_bos(buffer->dst);
176         RETURN_VAL_IF_FAIL(bo_cnt == 1, HAL_TDM_ERROR_INVALID_PARAMETER);
177
178         bo = tbm_surface_internal_get_bo(buffer->src, 0);
179         RETURN_VAL_IF_FAIL(bo != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
180
181         bo_size = tbm_bo_size(bo);
182
183         /* not handle buffers which have 2 more gem handles */
184
185         memset(&src_info, 0, sizeof(tbm_surface_info_s));
186         tbm_surface_map(buffer->src, TBM_OPTION_READ, &src_info);
187         GOTO_IF_FAIL(src_info.planes[0].ptr != NULL, fail_convert);
188
189         memset(&dst_info, 0, sizeof(tbm_surface_info_s));
190         tbm_surface_map(buffer->dst, TBM_OPTION_WRITE, &dst_info);
191         GOTO_IF_FAIL(dst_info.planes[0].ptr != NULL, fail_convert);
192
193         src_format = _tdm_drm_pp_pixman_get_format(src_info.format);
194         GOTO_IF_FAIL(src_format > 0, fail_convert);
195         dst_format = _tdm_drm_pp_pixman_get_format(dst_info.format);
196         GOTO_IF_FAIL(dst_format > 0, fail_convert);
197
198         GOTO_IF_FAIL(pixman_format_supported_destination(dst_format), fail_convert);
199
200         if (src_info.format == TBM_FORMAT_YUV420) {
201                 if (dst_info.format == TBM_FORMAT_XRGB8888)
202                         dst_format = PIXMAN_x8b8g8r8;
203                 else if (dst_info.format == TBM_FORMAT_ARGB8888)
204                         dst_format = PIXMAN_a8b8g8r8;
205                 else if (dst_info.format == TBM_FORMAT_YVU420) {
206                         TDM_BACKEND_ERR("can't convert %c%c%c%c to %c%c%c%c",
207                                         FOURCC_STR(src_info.format), FOURCC_STR(dst_info.format));
208                         goto fail_convert;
209                 }
210         }
211         /* need checking for other formats also? */
212
213         if (IS_RGB(src_info.format))
214                 sbw = src_info.planes[0].stride >> 2;
215         else
216                 sbw = src_info.planes[0].stride;
217
218         if (IS_RGB(dst_info.format))
219                 dbw = dst_info.planes[0].stride >> 2;
220         else
221                 dbw = dst_info.planes[0].stride;
222
223         rotate = (info->transform % 4) * 90;
224         if (info->transform >= HAL_TDM_TRANSFORM_FLIPPED)
225                 hflip = 1;
226
227         if (bo_size < src_info.planes[0].stride * src_info.height) {
228                 TDM_BACKEND_WRN("bo size(%d) is smaller than the expected size(%d)",
229                                 bo_size, src_info.planes[0].stride * src_info.height);
230                 goto fail_convert;
231         }
232
233         _tdm_drm_pp_pixman_convert(PIXMAN_OP_SRC,
234                                                            src_info.planes[0].ptr, dst_info.planes[0].ptr,
235                                                            src_format, dst_format,
236                                                            sbw, src_info.height,
237                                                            info->src_config.pos.x, info->src_config.pos.y,
238                                                            info->src_config.pos.w, info->src_config.pos.h,
239                                                            dbw, dst_info.height,
240                                                            info->dst_config.pos.x, info->dst_config.pos.y,
241                                                            info->dst_config.pos.w, info->dst_config.pos.h,
242                                                            rotate, hflip, 0);
243         tbm_surface_unmap(buffer->src);
244         tbm_surface_unmap(buffer->dst);
245
246         return HAL_TDM_ERROR_NONE;
247 fail_convert:
248         tbm_surface_unmap(buffer->src);
249         tbm_surface_unmap(buffer->dst);
250         return HAL_TDM_ERROR_OPERATION_FAILED;
251 }
252
253 hal_tdm_error
254 tdm_drm_pp_get_capability(tdm_drm_display *display_data, hal_tdm_caps_pp *caps)
255 {
256         int i;
257
258         if (!caps) {
259                 TDM_BACKEND_ERR("invalid params");
260                 return HAL_TDM_ERROR_INVALID_PARAMETER;
261         }
262
263         caps->capabilities = HAL_TDM_PP_CAPABILITY_SYNC;
264
265         caps->format_count = NUM_PP_FORMAT;
266
267         /* will be freed in frontend */
268         caps->formats = calloc(1, sizeof pp_formats);
269         if (!caps->formats) {
270                 TDM_BACKEND_ERR("alloc failed");
271                 return HAL_TDM_ERROR_OUT_OF_MEMORY;
272         }
273         for (i = 0; i < caps->format_count; i++)
274                 caps->formats[i] = pp_formats[i];
275
276         caps->min_w = 16;
277         caps->min_h = 8;
278         caps->max_w = -1;   /* not defined */
279         caps->max_h = -1;
280         caps->preferred_align = 16;
281
282         return HAL_TDM_ERROR_NONE;
283 }
284
285 hal_tdm_pp *
286 tdm_drm_pp_create(tdm_drm_display *display_data, hal_tdm_error *error)
287 {
288         tdm_drm_pp_data *pp_data = calloc(1, sizeof(tdm_drm_pp_data));
289         if (!pp_data) {
290                 TDM_BACKEND_ERR("alloc failed");
291                 if (error)
292                         *error = HAL_TDM_ERROR_OUT_OF_MEMORY;
293                 return NULL;
294         }
295
296         pp_data->display_data = display_data;
297
298         LIST_INITHEAD(&pp_data->pending_buffer_list);
299
300         if (!pp_list_init) {
301                 pp_list_init = 1;
302                 LIST_INITHEAD(&pp_list);
303         }
304         LIST_ADDTAIL(&pp_data->link, &pp_list);
305
306         return pp_data;
307 }
308
309 void
310 drm_pp_destroy(hal_tdm_pp *pp)
311 {
312         tdm_drm_pp_data *pp_data = pp;
313         tdm_drm_pp_buffer *b = NULL, *bb = NULL;
314
315         if (!pp_data)
316                 return;
317
318         LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, link) {
319                 LIST_DEL(&b->link);
320                 free(b);
321         }
322
323         LIST_DEL(&pp_data->link);
324
325         free(pp_data);
326 }
327
328 hal_tdm_error
329 drm_pp_set_info(hal_tdm_pp *pp, hal_tdm_info_pp *info)
330 {
331         tdm_drm_pp_data *pp_data = pp;
332
333         RETURN_VAL_IF_FAIL(pp_data, HAL_TDM_ERROR_INVALID_PARAMETER);
334         RETURN_VAL_IF_FAIL(info, HAL_TDM_ERROR_INVALID_PARAMETER);
335
336         pp_data->info = *info;
337
338         return HAL_TDM_ERROR_NONE;
339 }
340
341 hal_tdm_error
342 drm_pp_attach(hal_tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst)
343 {
344         tdm_drm_pp_data *pp_data = pp;
345         tdm_drm_pp_buffer *buffer;
346
347         RETURN_VAL_IF_FAIL(pp_data, HAL_TDM_ERROR_INVALID_PARAMETER);
348         RETURN_VAL_IF_FAIL(src, HAL_TDM_ERROR_INVALID_PARAMETER);
349         RETURN_VAL_IF_FAIL(dst, HAL_TDM_ERROR_INVALID_PARAMETER);
350
351         if (tbm_surface_internal_get_num_bos(src) > 1 ||
352                 tbm_surface_internal_get_num_bos(dst) > 1) {
353                 TDM_BACKEND_ERR("can't handle multiple tbm bos");
354                 return HAL_TDM_ERROR_OPERATION_FAILED;
355         }
356
357         buffer = calloc(1, sizeof(tdm_drm_pp_buffer));
358         if (!buffer) {
359                 TDM_BACKEND_ERR("alloc failed");
360                 return HAL_TDM_ERROR_NONE;
361         }
362
363         LIST_ADDTAIL(&buffer->link, &pp_data->pending_buffer_list);
364
365         buffer->src = src;
366         buffer->dst = dst;
367
368         return HAL_TDM_ERROR_NONE;
369 }
370
371 hal_tdm_error
372 drm_pp_commit(hal_tdm_pp *pp)
373 {
374         tdm_drm_pp_data *pp_data = pp;
375         tdm_drm_pp_buffer *b = NULL, *bb = NULL;
376
377         RETURN_VAL_IF_FAIL(pp_data, HAL_TDM_ERROR_INVALID_PARAMETER);
378
379         LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, link) {
380                 LIST_DEL(&b->link);
381
382                 _tdm_drm_pp_convert(b, &pp_data->info);
383
384                 if (pp_data->done_func)
385                         pp_data->done_func(pp_data,
386                                                            b->src,
387                                                            b->dst,
388                                                            pp_data->done_user_data);
389                 free(b);
390         }
391
392         return HAL_TDM_ERROR_NONE;
393 }
394
395 hal_tdm_error
396 drm_pp_set_done_handler(hal_tdm_pp *pp, hal_tdm_pp_done_handler func, void *user_data)
397 {
398         tdm_drm_pp_data *pp_data = pp;
399
400         RETURN_VAL_IF_FAIL(pp_data, HAL_TDM_ERROR_INVALID_PARAMETER);
401         RETURN_VAL_IF_FAIL(func, HAL_TDM_ERROR_INVALID_PARAMETER);
402
403         pp_data->done_func = func;
404         pp_data->done_user_data = user_data;
405
406         return HAL_TDM_ERROR_NONE;
407 }