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