Add missing boilerplate
[platform/adaptation/libtdm-drm.git] / src / libhal-backend-tdm-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 "tdm_backend_drm.h"
36
37 typedef struct _tdm_drm_pp_buffer {
38         tbm_surface_h src;
39         tbm_surface_h dst;
40
41         struct list_head link;
42 } tdm_drm_pp_buffer;
43
44 typedef struct _tdm_drm_pp_data {
45         tdm_drm_display *display_data;
46
47         hal_tdm_info_pp info;
48
49         struct list_head pending_buffer_list;
50
51         hal_tdm_pp_done_handler done_func;
52         void *done_user_data;
53
54         struct list_head link;
55 } tdm_drm_pp_data;
56
57
58 static tbm_format pp_formats[] = {
59         TBM_FORMAT_ARGB8888,
60         TBM_FORMAT_XRGB8888,
61         TBM_FORMAT_YUV420,
62 };
63
64 #define NUM_PP_FORMAT   (sizeof(pp_formats) / sizeof(pp_formats[0]))
65
66 static int pp_list_init;
67 static struct list_head pp_list;
68
69 static pixman_format_code_t
70 _tdm_drm_pp_pixman_get_format(tbm_format tbmfmt)
71 {
72         switch (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:
79                 return PIXMAN_yv12;
80         default:
81                 return 0;
82         }
83 }
84
85 int
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)
92 {
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;
98         int                             src_bpp;
99         int                             dst_bpp;
100         double                   scale_x, scale_y;
101         int                             rotate_step;
102         int                             ret = 0;
103
104         RETURN_VAL_IF_FAIL(srcbuf != NULL, 0);
105         RETURN_VAL_IF_FAIL(dstbuf != NULL, 0);
106
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);
109
110         src_bpp = PIXMAN_FORMAT_BPP(src_format) / 8;
111         RETURN_VAL_IF_FAIL(src_bpp > 0, 0);
112
113         dst_bpp = PIXMAN_FORMAT_BPP(dst_format) / 8;
114         RETURN_VAL_IF_FAIL(dst_bpp > 0, 0);
115
116         rotate_step = (rotate + 360) / 90 % 4;
117
118         src_stride = sbw * src_bpp;
119         dst_stride = dbw * dst_bpp;
120
121         src_img = pixman_image_create_bits(src_format, sbw, sbh, (uint32_t *)srcbuf,
122                                                                            src_stride);
123         dst_img = pixman_image_create_bits(dst_format, dbw, dbh, (uint32_t *)dstbuf,
124                                                                            dst_stride);
125
126         GOTO_IF_FAIL(src_img != NULL, CANT_CONVERT);
127         GOTO_IF_FAIL(dst_img != NULL, CANT_CONVERT);
128
129         pixman_f_transform_init_identity(&ft);
130
131         if (hflip) {
132                 pixman_f_transform_scale(&ft, NULL, -1, 1);
133                 pixman_f_transform_translate(&ft, NULL, dw, 0);
134         }
135
136         if (vflip) {
137                 pixman_f_transform_scale(&ft, NULL, 1, -1);
138                 pixman_f_transform_translate(&ft, NULL, 0, dh);
139         }
140
141         if (rotate_step > 0) {
142                 int c = 0, s = 0, tx = 0, ty = 0;
143                 switch (rotate_step) {
144                 case 1: /* 90 degrees */
145                         s = -1, tx = -dw;
146                         break;
147                 case 2: /* 180 degrees */
148                         c = -1, tx = -dw, ty = -dh;
149                         break;
150                 case 3: /* 270 degrees */
151                         s = 1, ty = -dh;
152                         break;
153                 }
154
155                 pixman_f_transform_translate(&ft, NULL, tx, ty);
156                 pixman_f_transform_rotate(&ft, NULL, c, s);
157         }
158
159         if (rotate_step % 2 == 0) {
160                 scale_x = (double)sw / dw;
161                 scale_y = (double)sh / dh;
162         } else {
163                 scale_x = (double)sw / dh;
164                 scale_y = (double)sh / dw;
165         }
166
167         pixman_f_transform_scale(&ft, NULL, scale_x, scale_y);
168         pixman_f_transform_translate(&ft, NULL, sx, sy);
169
170         pixman_transform_from_pixman_f_transform(&transform, &ft);
171         pixman_image_set_transform(src_img, &transform);
172
173         pixman_image_composite(op, src_img, NULL, dst_img, 0, 0, 0, 0, dx, dy, dw, dh);
174
175         ret = 1;
176
177 CANT_CONVERT:
178         if (src_img)
179                 pixman_image_unref(src_img);
180         if (dst_img)
181                 pixman_image_unref(dst_img);
182
183         return ret;
184 }
185
186 static hal_tdm_error
187 _tdm_drm_pp_convert(tdm_drm_pp_buffer *buffer, hal_tdm_info_pp *info)
188 {
189         tbm_surface_info_s src_info, dst_info;
190         pixman_format_code_t src_format, dst_format;
191         int sbw, dbw;
192         int rotate = 0, hflip = 0;
193         tbm_bo bo = NULL;
194         int bo_cnt = 0;
195         int bo_size = 0;
196
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);
201
202         bo_cnt = tbm_surface_internal_get_num_bos(buffer->src);
203         RETURN_VAL_IF_FAIL(bo_cnt == 1, HAL_TDM_ERROR_INVALID_PARAMETER);
204
205         bo_cnt = tbm_surface_internal_get_num_bos(buffer->dst);
206         RETURN_VAL_IF_FAIL(bo_cnt == 1, HAL_TDM_ERROR_INVALID_PARAMETER);
207
208         bo = tbm_surface_internal_get_bo(buffer->src, 0);
209         RETURN_VAL_IF_FAIL(bo != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
210
211         bo_size = tbm_bo_size(bo);
212
213         /* not handle buffers which have 2 more gem handles */
214
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);
218
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);
222
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);
227
228         GOTO_IF_FAIL(pixman_format_supported_destination(dst_format), fail_convert);
229
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));
238                         goto fail_convert;
239                 }
240         }
241         /* need checking for other formats also? */
242
243         if (IS_RGB(src_info.format))
244                 sbw = src_info.planes[0].stride >> 2;
245         else
246                 sbw = src_info.planes[0].stride;
247
248         if (IS_RGB(dst_info.format))
249                 dbw = dst_info.planes[0].stride >> 2;
250         else
251                 dbw = dst_info.planes[0].stride;
252
253         rotate = (info->transform % 4) * 90;
254         if (info->transform >= HAL_TDM_TRANSFORM_FLIPPED)
255                 hflip = 1;
256
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);
260                 goto fail_convert;
261         }
262
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,
272                                                            rotate, hflip, 0);
273         tbm_surface_unmap(buffer->src);
274         tbm_surface_unmap(buffer->dst);
275
276         return HAL_TDM_ERROR_NONE;
277 fail_convert:
278         tbm_surface_unmap(buffer->src);
279         tbm_surface_unmap(buffer->dst);
280         return HAL_TDM_ERROR_OPERATION_FAILED;
281 }
282
283 hal_tdm_error
284 tdm_drm_pp_get_capability(tdm_drm_display *display_data, hal_tdm_caps_pp *caps)
285 {
286         int i;
287
288         if (!caps) {
289                 TDM_BACKEND_ERR("invalid params");
290                 return HAL_TDM_ERROR_INVALID_PARAMETER;
291         }
292
293         caps->capabilities = HAL_TDM_PP_CAPABILITY_SYNC;
294
295         caps->format_count = NUM_PP_FORMAT;
296
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;
302         }
303         for (i = 0; i < caps->format_count; i++)
304                 caps->formats[i] = pp_formats[i];
305
306         caps->min_w = 16;
307         caps->min_h = 8;
308         caps->max_w = -1;   /* not defined */
309         caps->max_h = -1;
310         caps->preferred_align = 16;
311
312         return HAL_TDM_ERROR_NONE;
313 }
314
315 hal_tdm_pp *
316 tdm_drm_pp_create(tdm_drm_display *display_data, hal_tdm_error *error)
317 {
318         tdm_drm_pp_data *pp_data = calloc(1, sizeof(tdm_drm_pp_data));
319         if (!pp_data) {
320                 TDM_BACKEND_ERR("alloc failed");
321                 if (error)
322                         *error = HAL_TDM_ERROR_OUT_OF_MEMORY;
323                 return NULL;
324         }
325
326         pp_data->display_data = display_data;
327
328         LIST_INITHEAD(&pp_data->pending_buffer_list);
329
330         if (!pp_list_init) {
331                 pp_list_init = 1;
332                 LIST_INITHEAD(&pp_list);
333         }
334         LIST_ADDTAIL(&pp_data->link, &pp_list);
335
336         return pp_data;
337 }
338
339 void
340 drm_pp_destroy(hal_tdm_pp *pp)
341 {
342         tdm_drm_pp_data *pp_data = pp;
343         tdm_drm_pp_buffer *b = NULL, *bb = NULL;
344
345         if (!pp_data)
346                 return;
347
348         LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, link) {
349                 LIST_DEL(&b->link);
350                 free(b);
351         }
352
353         LIST_DEL(&pp_data->link);
354
355         free(pp_data);
356 }
357
358 hal_tdm_error
359 drm_pp_set_info(hal_tdm_pp *pp, hal_tdm_info_pp *info)
360 {
361         tdm_drm_pp_data *pp_data = pp;
362
363         RETURN_VAL_IF_FAIL(pp_data, HAL_TDM_ERROR_INVALID_PARAMETER);
364         RETURN_VAL_IF_FAIL(info, HAL_TDM_ERROR_INVALID_PARAMETER);
365
366         pp_data->info = *info;
367
368         return HAL_TDM_ERROR_NONE;
369 }
370
371 hal_tdm_error
372 drm_pp_attach(hal_tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst)
373 {
374         tdm_drm_pp_data *pp_data = pp;
375         tdm_drm_pp_buffer *buffer;
376
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);
380
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;
385         }
386
387         buffer = calloc(1, sizeof(tdm_drm_pp_buffer));
388         if (!buffer) {
389                 TDM_BACKEND_ERR("alloc failed");
390                 return HAL_TDM_ERROR_NONE;
391         }
392
393         LIST_ADDTAIL(&buffer->link, &pp_data->pending_buffer_list);
394
395         buffer->src = src;
396         buffer->dst = dst;
397
398         return HAL_TDM_ERROR_NONE;
399 }
400
401 hal_tdm_error
402 drm_pp_commit(hal_tdm_pp *pp)
403 {
404         tdm_drm_pp_data *pp_data = pp;
405         tdm_drm_pp_buffer *b = NULL, *bb = NULL;
406
407         RETURN_VAL_IF_FAIL(pp_data, HAL_TDM_ERROR_INVALID_PARAMETER);
408
409         LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, link) {
410                 LIST_DEL(&b->link);
411
412                 _tdm_drm_pp_convert(b, &pp_data->info);
413
414                 if (pp_data->done_func)
415                         pp_data->done_func(pp_data,
416                                                            b->src,
417                                                            b->dst,
418                                                            pp_data->done_user_data);
419                 free(b);
420         }
421
422         return HAL_TDM_ERROR_NONE;
423 }
424
425 hal_tdm_error
426 drm_pp_set_done_handler(hal_tdm_pp *pp, hal_tdm_pp_done_handler func, void *user_data)
427 {
428         tdm_drm_pp_data *pp_data = pp;
429
430         RETURN_VAL_IF_FAIL(pp_data, HAL_TDM_ERROR_INVALID_PARAMETER);
431         RETURN_VAL_IF_FAIL(func, HAL_TDM_ERROR_INVALID_PARAMETER);
432
433         pp_data->done_func = func;
434         pp_data->done_user_data = user_data;
435
436         return HAL_TDM_ERROR_NONE;
437 }