Add missing boilerplate
[platform/adaptation/libtdm-drm.git] / src / libtdm-drm / tdm_drm_pp.c
1 /**************************************************************************
2
3 libtdm_drm
4
5 Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
6
7 Contact: SooChan Lim <sc1.lim@samsung.com>
8
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:
16
17 The above copyright notice and this permission notice (including the
18 next paragraph) shall be included in all copies or substantial portions
19 of the Software.
20
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.
28
29 **************************************************************************/
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include <pixman.h>
36
37 #include "tdm_drm.h"
38 #include "tdm_helper.h"
39
40 typedef struct _tdm_drm_pp_buffer {
41         tbm_surface_h src;
42         tbm_surface_h dst;
43
44         struct list_head link;
45 } tdm_drm_pp_buffer;
46
47 typedef struct _tdm_drm_pp_data {
48         tdm_drm_data *drm_data;
49
50         tdm_info_pp info;
51
52         struct list_head pending_buffer_list;
53
54         tdm_pp_done_handler done_func;
55         void *done_user_data;
56
57         struct list_head link;
58 } tdm_drm_pp_data;
59
60
61 static tbm_format pp_formats[] = {
62         TBM_FORMAT_ARGB8888,
63         TBM_FORMAT_XRGB8888,
64         TBM_FORMAT_YUV420,
65 };
66
67 #define NUM_PP_FORMAT   (sizeof(pp_formats) / sizeof(pp_formats[0]))
68
69 static int pp_list_init;
70 static struct list_head pp_list;
71
72 static pixman_format_code_t
73 _tdm_drm_pp_pixman_get_format(tbm_format tbmfmt)
74 {
75         switch (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:
82                 return PIXMAN_yv12;
83         default:
84                 return 0;
85         }
86 }
87
88 int
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)
95 {
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;
101         int                             src_bpp;
102         int                             dst_bpp;
103         double                   scale_x, scale_y;
104         int                             rotate_step;
105         int                             ret = 0;
106
107         RETURN_VAL_IF_FAIL(srcbuf != NULL, 0);
108         RETURN_VAL_IF_FAIL(dstbuf != NULL, 0);
109
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);
112
113         src_bpp = PIXMAN_FORMAT_BPP(src_format) / 8;
114         RETURN_VAL_IF_FAIL(src_bpp > 0, 0);
115
116         dst_bpp = PIXMAN_FORMAT_BPP(dst_format) / 8;
117         RETURN_VAL_IF_FAIL(dst_bpp > 0, 0);
118
119         rotate_step = (rotate + 360) / 90 % 4;
120
121         src_stride = sbw * src_bpp;
122         dst_stride = dbw * dst_bpp;
123
124         src_img = pixman_image_create_bits(src_format, sbw, sbh, (uint32_t *)srcbuf,
125                                                                            src_stride);
126         dst_img = pixman_image_create_bits(dst_format, dbw, dbh, (uint32_t *)dstbuf,
127                                                                            dst_stride);
128
129         GOTO_IF_FAIL(src_img != NULL, CANT_CONVERT);
130         GOTO_IF_FAIL(dst_img != NULL, CANT_CONVERT);
131
132         pixman_f_transform_init_identity(&ft);
133
134         if (hflip) {
135                 pixman_f_transform_scale(&ft, NULL, -1, 1);
136                 pixman_f_transform_translate(&ft, NULL, dw, 0);
137         }
138
139         if (vflip) {
140                 pixman_f_transform_scale(&ft, NULL, 1, -1);
141                 pixman_f_transform_translate(&ft, NULL, 0, dh);
142         }
143
144         if (rotate_step > 0) {
145                 int c = 0, s = 0, tx = 0, ty = 0;
146                 switch (rotate_step) {
147                 case 1: /* 90 degrees */
148                         s = -1, tx = -dw;
149                         break;
150                 case 2: /* 180 degrees */
151                         c = -1, tx = -dw, ty = -dh;
152                         break;
153                 case 3: /* 270 degrees */
154                         s = 1, ty = -dh;
155                         break;
156                 }
157
158                 pixman_f_transform_translate(&ft, NULL, tx, ty);
159                 pixman_f_transform_rotate(&ft, NULL, c, s);
160         }
161
162         if (rotate_step % 2 == 0) {
163                 scale_x = (double)sw / dw;
164                 scale_y = (double)sh / dh;
165         } else {
166                 scale_x = (double)sw / dh;
167                 scale_y = (double)sh / dw;
168         }
169
170         pixman_f_transform_scale(&ft, NULL, scale_x, scale_y);
171         pixman_f_transform_translate(&ft, NULL, sx, sy);
172
173         pixman_transform_from_pixman_f_transform(&transform, &ft);
174         pixman_image_set_transform(src_img, &transform);
175
176         pixman_image_composite(op, src_img, NULL, dst_img, 0, 0, 0, 0, dx, dy, dw, dh);
177
178         ret = 1;
179
180 CANT_CONVERT:
181         if (src_img)
182                 pixman_image_unref(src_img);
183         if (dst_img)
184                 pixman_image_unref(dst_img);
185
186         return ret;
187 }
188
189 static tdm_error
190 _tdm_drm_pp_convert(tdm_drm_pp_buffer *buffer, tdm_info_pp *info)
191 {
192         tbm_surface_info_s src_info, dst_info;
193         pixman_format_code_t src_format, dst_format;
194         int sbw, dbw;
195         int rotate = 0, hflip = 0;
196         tbm_bo bo = NULL;
197         int bo_cnt = 0;
198         int bo_size = 0;
199
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);
204
205         bo_cnt = tbm_surface_internal_get_num_bos(buffer->src);
206         RETURN_VAL_IF_FAIL(bo_cnt == 1, TDM_ERROR_INVALID_PARAMETER);
207
208         bo_cnt = tbm_surface_internal_get_num_bos(buffer->dst);
209         RETURN_VAL_IF_FAIL(bo_cnt == 1, TDM_ERROR_INVALID_PARAMETER);
210
211         bo = tbm_surface_internal_get_bo(buffer->src, 0);
212         RETURN_VAL_IF_FAIL(bo != NULL, TDM_ERROR_INVALID_PARAMETER);
213
214         bo_size = tbm_bo_size(bo);
215
216         /* not handle buffers which have 2 more gem handles */
217
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);
221
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);
225
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);
230
231         GOTO_IF_FAIL(pixman_format_supported_destination(dst_format), fail_convert);
232
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));
241                         goto fail_convert;
242                 }
243         }
244         /* need checking for other formats also? */
245
246         if (IS_RGB(src_info.format))
247                 sbw = src_info.planes[0].stride >> 2;
248         else
249                 sbw = src_info.planes[0].stride;
250
251         if (IS_RGB(dst_info.format))
252                 dbw = dst_info.planes[0].stride >> 2;
253         else
254                 dbw = dst_info.planes[0].stride;
255
256         rotate = (info->transform % 4) * 90;
257         if (info->transform >= TDM_TRANSFORM_FLIPPED)
258                 hflip = 1;
259
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);
263                 goto fail_convert;
264         }
265
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,
275                                                            rotate, hflip, 0);
276         tbm_surface_unmap(buffer->src);
277         tbm_surface_unmap(buffer->dst);
278
279         return TDM_ERROR_NONE;
280 fail_convert:
281         tbm_surface_unmap(buffer->src);
282         tbm_surface_unmap(buffer->dst);
283         return TDM_ERROR_OPERATION_FAILED;
284 }
285
286 tdm_error
287 tdm_drm_pp_get_capability(tdm_drm_data *drm_data, tdm_caps_pp *caps)
288 {
289         int i;
290
291         if (!caps) {
292                 TDM_ERR("invalid params");
293                 return TDM_ERROR_INVALID_PARAMETER;
294         }
295
296         caps->capabilities = TDM_PP_CAPABILITY_SYNC;
297
298         caps->format_count = NUM_PP_FORMAT;
299
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;
305         }
306         for (i = 0; i < caps->format_count; i++)
307                 caps->formats[i] = pp_formats[i];
308
309         caps->min_w = 16;
310         caps->min_h = 8;
311         caps->max_w = -1;   /* not defined */
312         caps->max_h = -1;
313         caps->preferred_align = 16;
314
315         return TDM_ERROR_NONE;
316 }
317
318 tdm_pp *
319 tdm_drm_pp_create(tdm_drm_data *drm_data, tdm_error *error)
320 {
321         tdm_drm_pp_data *pp_data = calloc(1, sizeof(tdm_drm_pp_data));
322         if (!pp_data) {
323                 TDM_ERR("alloc failed");
324                 if (error)
325                         *error = TDM_ERROR_OUT_OF_MEMORY;
326                 return NULL;
327         }
328
329         pp_data->drm_data = drm_data;
330
331         LIST_INITHEAD(&pp_data->pending_buffer_list);
332
333         if (!pp_list_init) {
334                 pp_list_init = 1;
335                 LIST_INITHEAD(&pp_list);
336         }
337         LIST_ADDTAIL(&pp_data->link, &pp_list);
338
339         return pp_data;
340 }
341
342 void
343 drm_pp_destroy(tdm_pp *pp)
344 {
345         tdm_drm_pp_data *pp_data = pp;
346         tdm_drm_pp_buffer *b = NULL, *bb = NULL;
347
348         if (!pp_data)
349                 return;
350
351         LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, link) {
352                 LIST_DEL(&b->link);
353                 free(b);
354         }
355
356         LIST_DEL(&pp_data->link);
357
358         free(pp_data);
359 }
360
361 tdm_error
362 drm_pp_set_info(tdm_pp *pp, tdm_info_pp *info)
363 {
364         tdm_drm_pp_data *pp_data = pp;
365
366         RETURN_VAL_IF_FAIL(pp_data, TDM_ERROR_INVALID_PARAMETER);
367         RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
368
369         pp_data->info = *info;
370
371         return TDM_ERROR_NONE;
372 }
373
374 tdm_error
375 drm_pp_attach(tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst)
376 {
377         tdm_drm_pp_data *pp_data = pp;
378         tdm_drm_pp_buffer *buffer;
379
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);
383
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;
388         }
389
390         buffer = calloc(1, sizeof(tdm_drm_pp_buffer));
391         if (!buffer) {
392                 TDM_ERR("alloc failed");
393                 return TDM_ERROR_NONE;
394         }
395
396         LIST_ADDTAIL(&buffer->link, &pp_data->pending_buffer_list);
397
398         buffer->src = src;
399         buffer->dst = dst;
400
401         return TDM_ERROR_NONE;
402 }
403
404 tdm_error
405 drm_pp_commit(tdm_pp *pp)
406 {
407         tdm_drm_pp_data *pp_data = pp;
408         tdm_drm_pp_buffer *b = NULL, *bb = NULL;
409
410         RETURN_VAL_IF_FAIL(pp_data, TDM_ERROR_INVALID_PARAMETER);
411
412         LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, link) {
413                 LIST_DEL(&b->link);
414
415                 _tdm_drm_pp_convert(b, &pp_data->info);
416
417                 if (pp_data->done_func)
418                         pp_data->done_func(pp_data,
419                                                            b->src,
420                                                            b->dst,
421                                                            pp_data->done_user_data);
422                 free(b);
423         }
424
425         return TDM_ERROR_NONE;
426 }
427
428 tdm_error
429 drm_pp_set_done_handler(tdm_pp *pp, tdm_pp_done_handler func, void *user_data)
430 {
431         tdm_drm_pp_data *pp_data = pp;
432
433         RETURN_VAL_IF_FAIL(pp_data, TDM_ERROR_INVALID_PARAMETER);
434         RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
435
436         pp_data->done_func = func;
437         pp_data->done_user_data = user_data;
438
439         return TDM_ERROR_NONE;
440 }