diff options
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | packaging/libtdm-drm.spec | 1 | ||||
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/tdm_drm.c | 13 | ||||
-rw-r--r-- | src/tdm_drm.h | 13 | ||||
-rw-r--r-- | src/tdm_drm_display.c | 18 | ||||
-rw-r--r-- | src/tdm_drm_pp.c | 403 | ||||
-rw-r--r-- | src/tdm_drm_pp.h | 13 |
8 files changed, 463 insertions, 1 deletions
diff --git a/configure.ac b/configure.ac index f9c2bbd..be9a88a 100644 --- a/configure.ac +++ b/configure.ac @@ -23,7 +23,7 @@ LT_INIT([disable-static]) # Enable quiet compiles on automake 1.11. m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) -PKG_CHECK_MODULES(TDM_DRM, libtdm libtbm libdrm) +PKG_CHECK_MODULES(TDM_DRM, libtdm libtbm libdrm pixman-1) PKG_CHECK_MODULES(UDEV, libudev, [udev=yes], [udev=no]) if test x"$udev" = xyes; then AC_DEFINE(HAVE_UDEV,1,[Enable udev-based monitor hotplug detection]) diff --git a/packaging/libtdm-drm.spec b/packaging/libtdm-drm.spec index 9de51ea..c06bcff 100644 --- a/packaging/libtdm-drm.spec +++ b/packaging/libtdm-drm.spec @@ -9,6 +9,7 @@ Source1001: %{name}.manifest BuildRequires: pkgconfig(libdrm) BuildRequires: pkgconfig(libudev) BuildRequires: pkgconfig(libtdm) +BuildRequires: pkgconfig(pixman-1) %description Back-End library of Tizen Display Manager DRM : libtdm-mgr DRM library diff --git a/src/Makefile.am b/src/Makefile.am index 6e6d8c3..09338b8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,5 +9,6 @@ libtdm_drm_la_LIBADD = $(TDM_DRM_LIBS) -ldl libtdm_drm_la_SOURCES = \ tdm_drm_format.c \ + tdm_drm_pp.c \ tdm_drm_display.c \ tdm_drm.c diff --git a/src/tdm_drm.c b/src/tdm_drm.c index d848f1f..5dffd15 100644 --- a/src/tdm_drm.c +++ b/src/tdm_drm.c @@ -53,6 +53,15 @@ static tdm_func_layer drm_func_layer = NULL, //layer_create_capture }; +static tdm_func_pp drm_func_pp = +{ + drm_pp_destroy, + drm_pp_set_info, + drm_pp_attach, + drm_pp_commit, + drm_pp_set_done_handler, +}; + static tdm_drm_data *drm_data; #ifdef HAVE_UDEV @@ -213,6 +222,10 @@ tdm_drm_init(tdm_display *dpy, tdm_error *error) if (ret != TDM_ERROR_NONE) goto failed; + ret = tdm_backend_register_func_pp(dpy, &drm_func_pp); + if (ret != TDM_ERROR_NONE) + goto failed; + drm_data->dpy = dpy; drm_data->drm_fd = _tdm_drm_open_drm(); diff --git a/src/tdm_drm.h b/src/tdm_drm.h index a354417..3aa86a7 100644 --- a/src/tdm_drm.h +++ b/src/tdm_drm.h @@ -23,6 +23,7 @@ /* drm backend functions (display) */ tdm_error drm_display_get_capabilitiy(tdm_backend_data *bdata, tdm_caps_display *caps); +tdm_error drm_display_get_pp_capability(tdm_backend_data *bdata, tdm_caps_pp *caps); tdm_output** drm_display_get_outputs(tdm_backend_data *bdata, int *count, tdm_error *error); tdm_error drm_display_get_fd(tdm_backend_data *bdata, int *fd); tdm_error drm_display_handle_events(tdm_backend_data *bdata); @@ -46,6 +47,11 @@ tdm_error drm_layer_set_info(tdm_layer *layer, tdm_info_layer *info); tdm_error drm_layer_get_info(tdm_layer *layer, tdm_info_layer *info); tdm_error drm_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer); tdm_error drm_layer_unset_buffer(tdm_layer *layer); +void drm_pp_destroy(tdm_pp *pp); +tdm_error drm_pp_set_info(tdm_pp *pp, tdm_info_pp *info); +tdm_error drm_pp_attach(tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst); +tdm_error drm_pp_commit(tdm_pp *pp); +tdm_error drm_pp_set_done_handler(tdm_pp *pp, tdm_pp_done_handler func, void *user_data); /* drm module internal macros, structures, functions */ #define NEVER_GET_HERE() TDM_ERR("** NEVER GET HERE **") @@ -78,6 +84,13 @@ tdm_error drm_layer_unset_buffer(tdm_layer *layer); }\ } +#define GOTO_IF_FAIL(cond, val) {\ + if (!(cond)) {\ + TDM_ERR("'%s' failed", #cond);\ + goto val;\ + }\ +} + typedef struct _tdm_drm_data { tdm_display *dpy; diff --git a/src/tdm_drm_display.c b/src/tdm_drm_display.c index face731..315ec5a 100644 --- a/src/tdm_drm_display.c +++ b/src/tdm_drm_display.c @@ -4,7 +4,9 @@ #include <drm_fourcc.h> #include <tdm_helper.h> + #include "tdm_drm.h" +#include "tdm_drm_pp.h" #define MIN_WIDTH 32 @@ -707,6 +709,12 @@ drm_display_get_capabilitiy(tdm_backend_data *bdata, tdm_caps_display *caps) return TDM_ERROR_NONE; } +tdm_error +drm_display_get_pp_capability(tdm_backend_data *bdata, tdm_caps_pp *caps) +{ + return tdm_drm_pp_get_capability(bdata, caps); +} + tdm_output** drm_display_get_outputs(tdm_backend_data *bdata, int *count, tdm_error *error) { @@ -785,6 +793,16 @@ drm_display_handle_events(tdm_backend_data *bdata) return TDM_ERROR_NONE; } +tdm_pp* +drm_display_create_pp(tdm_backend_data *bdata, tdm_error *error) +{ + tdm_drm_data *drm_data = bdata; + + RETURN_VAL_IF_FAIL(drm_data, NULL); + + return tdm_drm_pp_create(drm_data, error); +} + tdm_error drm_output_get_capability(tdm_output *output, tdm_caps_output *caps) { diff --git a/src/tdm_drm_pp.c b/src/tdm_drm_pp.c new file mode 100644 index 0000000..9720eb2 --- /dev/null +++ b/src/tdm_drm_pp.c @@ -0,0 +1,403 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pixman.h> + +#include "tdm_drm.h" + +typedef struct _tdm_drm_pp_buffer +{ + tbm_surface_h src; + tbm_surface_h dst; + + struct list_head link; +} tdm_drm_pp_buffer; + +typedef struct _tdm_drm_pp_data +{ + tdm_drm_data *drm_data; + + tdm_info_pp info; + + struct list_head pending_buffer_list; + + tdm_pp_done_handler done_func; + void *done_user_data; + + struct list_head link; +} tdm_drm_pp_data; + + +static tbm_format pp_formats[] = +{ + TBM_FORMAT_ARGB8888, + TBM_FORMAT_XRGB8888, + TBM_FORMAT_YUV420, + TBM_FORMAT_YVU420 +}; + +#define NUM_PP_FORMAT (sizeof(pp_formats) / sizeof(pp_formats[0])) + +static int pp_list_init; +static struct list_head pp_list; + +static pixman_format_code_t +_tdm_drm_pp_pixman_get_format(tbm_format tbmfmt) +{ + switch (tbmfmt) + { + case TBM_FORMAT_ARGB8888: + return PIXMAN_a8r8g8b8; + case TBM_FORMAT_XRGB8888: + return PIXMAN_x8r8g8b8; + case TBM_FORMAT_YUV420: + case TBM_FORMAT_YVU420: + return PIXMAN_yv12; + default: + return 0; + } +} + +int +_tdm_drm_pp_pixman_convert(pixman_op_t op, + unsigned char *srcbuf, unsigned char *dstbuf, + pixman_format_code_t src_format, pixman_format_code_t dst_format, + int sbw, int sbh, int sx, int sy, int sw, int sh, + int dbw, int dbh, int dx, int dy, int dw, int dh, + int rotate, int hflip, int vflip) +{ + pixman_image_t *src_img; + pixman_image_t *dst_img; + struct pixman_f_transform ft; + pixman_transform_t transform; + int src_stride, dst_stride; + int src_bpp; + int dst_bpp; + double scale_x, scale_y; + int rotate_step; + int ret = 0; + + RETURN_VAL_IF_FAIL(srcbuf != NULL, 0); + RETURN_VAL_IF_FAIL(dstbuf != NULL, 0); + + TDM_DBG("src(%dx%d: %d,%d %dx%d) dst(%dx%d: %d,%d %dx%d) flip(%d,%d), rot(%d)", + sbw, sbh, sx, sy, sw, sh, dbw, dbh, dx, dy, dw, dh, hflip, vflip, rotate); + + src_bpp = PIXMAN_FORMAT_BPP(src_format) / 8; + RETURN_VAL_IF_FAIL(src_bpp > 0, 0); + + dst_bpp = PIXMAN_FORMAT_BPP(dst_format) / 8; + RETURN_VAL_IF_FAIL(dst_bpp > 0, 0); + + rotate_step = (rotate + 360) / 90 % 4; + + src_stride = sbw * src_bpp; + dst_stride = dbw * dst_bpp; + + src_img = pixman_image_create_bits(src_format, sbw, sbh, (uint32_t*)srcbuf, src_stride); + dst_img = pixman_image_create_bits(dst_format, dbw, dbh, (uint32_t*)dstbuf, dst_stride); + + GOTO_IF_FAIL(src_img != NULL, CANT_CONVERT); + GOTO_IF_FAIL(dst_img != NULL, CANT_CONVERT); + + pixman_f_transform_init_identity(&ft); + + if (hflip) + { + pixman_f_transform_scale(&ft, NULL, -1, 1); + pixman_f_transform_translate(&ft, NULL, dw, 0); + } + + if (vflip) + { + pixman_f_transform_scale(&ft, NULL, 1, -1); + pixman_f_transform_translate(&ft, NULL, 0, dh); + } + + if (rotate_step > 0) + { + int c = 0, s = 0, tx = 0, ty = 0; + switch (rotate_step) + { + case 1: /* 90 degrees */ + s = -1, tx = -dw; + break; + case 2: /* 180 degrees */ + c = -1, tx = -dw, ty = -dh; + break; + case 3: /* 270 degrees */ + s = 1, ty = -dh; + break; + default: + break; + } + + pixman_f_transform_translate(&ft, NULL, tx, ty); + pixman_f_transform_rotate(&ft, NULL, c, s); + } + + if (rotate_step % 2 == 0) + { + scale_x = (double)sw / dw; + scale_y = (double)sh / dh; + } + else + { + scale_x = (double)sw / dh; + scale_y = (double)sh / dw; + } + + pixman_f_transform_scale(&ft, NULL, scale_x, scale_y); + pixman_f_transform_translate(&ft, NULL, sx, sy); + + pixman_transform_from_pixman_f_transform(&transform, &ft); + pixman_image_set_transform(src_img, &transform); + + pixman_image_composite(op, src_img, NULL, dst_img, 0, 0, 0, 0, dx, dy, dw, dh); + + ret = 1; + +CANT_CONVERT: + if (src_img) + pixman_image_unref(src_img); + if (dst_img) + pixman_image_unref(dst_img); + + return ret; +} + +static tdm_error +_tdm_drm_pp_convert(tdm_drm_pp_buffer *buffer, tdm_info_pp *info) +{ + tbm_surface_info_s src_info, dst_info; + pixman_format_code_t src_format, dst_format; + int sbw, dbw; + int rotate = 0, hflip = 0; + + RETURN_VAL_IF_FAIL(buffer != NULL, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(buffer->src != NULL, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(buffer->dst != NULL, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER); + + /* not handle buffers which have 2 more gem handles */ + + memset(&src_info, 0, sizeof(tbm_surface_info_s)); + tbm_surface_get_info(buffer->src, &src_info); + RETURN_VAL_IF_FAIL(src_info.planes[0].ptr != NULL, TDM_ERROR_INVALID_PARAMETER); + + memset(&dst_info, 0, sizeof(tbm_surface_info_s)); + tbm_surface_get_info(buffer->dst, &dst_info); + RETURN_VAL_IF_FAIL(dst_info.planes[0].ptr != NULL, TDM_ERROR_INVALID_PARAMETER); + + src_format = _tdm_drm_pp_pixman_get_format(src_info.format); + RETURN_VAL_IF_FAIL(src_format > 0, TDM_ERROR_INVALID_PARAMETER); + dst_format = _tdm_drm_pp_pixman_get_format(dst_info.format); + RETURN_VAL_IF_FAIL(dst_format > 0, TDM_ERROR_INVALID_PARAMETER); + + if (src_info.format == TBM_FORMAT_YUV420) + { + if (dst_info.format == TBM_FORMAT_XRGB8888) + dst_format = PIXMAN_x8b8g8r8; + else if (dst_info.format == TBM_FORMAT_ARGB8888) + dst_format = PIXMAN_a8b8g8r8; + else if (dst_info.format == TBM_FORMAT_YVU420) + { + TDM_ERR("can't convert %c%c%c%c to %c%c%c%c", + FOURCC_STR(src_info.format), FOURCC_STR(dst_info.format)); + return TDM_ERROR_OPERATION_FAILED; + } + } + /* need checking for other formats also? */ + + if (IS_RGB(src_info.format)) + sbw = src_info.planes[0].stride >> 2; + else + sbw = src_info.planes[0].stride; + + if (IS_RGB(src_info.format)) + dbw = dst_info.planes[0].stride >> 2; + else + dbw = dst_info.planes[0].stride; + + rotate = (info->transform % 4) * 90; + if (info->transform >= TDM_TRANSFORM_FLIPPED) + hflip = 1; + + _tdm_drm_pp_pixman_convert(PIXMAN_OP_SRC, + src_info.planes[0].ptr, dst_info.planes[0].ptr, + src_format, dst_format, + sbw, src_info.height, + info->src_config.pos.x, info->src_config.pos.y, + info->src_config.pos.w, info->src_config.pos.h, + dbw, dst_info.height, + info->dst_config.pos.x, info->dst_config.pos.y, + info->dst_config.pos.w, info->dst_config.pos.h, + rotate, hflip, 0); + + return TDM_ERROR_NONE; +} + +tdm_error +tdm_drm_pp_get_capability(tdm_drm_data *drm_data, tdm_caps_pp *caps) +{ + int i; + + if (!caps) + { + TDM_ERR("invalid params"); + return TDM_ERROR_INVALID_PARAMETER; + } + + caps->capabilities = TDM_PP_CAPABILITY_ASYNC; + + caps->format_count = NUM_PP_FORMAT; + + /* will be freed in frontend */ + caps->formats = calloc(1, sizeof pp_formats); + if (!caps->formats) + { + TDM_ERR("alloc failed"); + return TDM_ERROR_OUT_OF_MEMORY; + } + for (i = 0; i < caps->format_count; i++) + caps->formats[i] = pp_formats[i]; + + caps->min_w = 16; + caps->min_h = 8; + caps->max_w = -1; /* not defined */ + caps->max_h = -1; + caps->preferred_align = 16; + + return TDM_ERROR_NONE; +} + +tdm_pp* +tdm_drm_pp_create(tdm_drm_data *drm_data, tdm_error *error) +{ + tdm_drm_pp_data *pp_data = calloc(1, sizeof(tdm_drm_pp_data)); + if (!pp_data) + { + TDM_ERR("alloc failed"); + if (error) + *error = TDM_ERROR_OUT_OF_MEMORY; + return NULL; + } + + pp_data->drm_data = drm_data; + + LIST_INITHEAD(&pp_data->pending_buffer_list); + + if (!pp_list_init) + { + pp_list_init = 1; + LIST_INITHEAD(&pp_list); + } + LIST_ADDTAIL(&pp_data->link, &pp_list); + + return pp_data; +} + +void +drm_pp_destroy(tdm_pp *pp) +{ + tdm_drm_pp_data *pp_data = pp; + tdm_drm_pp_buffer *b = NULL, *bb = NULL; + + if (!pp_data) + return; + + LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, link) + { + LIST_DEL(&b->link); + free(b); + } + + LIST_DEL(&pp_data->link); + + free(pp_data); +} + +tdm_error +drm_pp_set_info(tdm_pp *pp, tdm_info_pp *info) +{ + tdm_drm_pp_data *pp_data = pp; + + RETURN_VAL_IF_FAIL(pp_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER); + + pp_data->info = *info; + + return TDM_ERROR_NONE; +} + +tdm_error +drm_pp_attach(tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst) +{ + tdm_drm_pp_data *pp_data = pp; + tdm_drm_pp_buffer *buffer; + + RETURN_VAL_IF_FAIL(pp_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(src, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(dst, TDM_ERROR_INVALID_PARAMETER); + + if (tbm_surface_internal_get_num_bos(src) > 1 || + tbm_surface_internal_get_num_bos(dst) > 1) + { + TDM_ERR("can't handle multiple tbm bos"); + return TDM_ERROR_OPERATION_FAILED; + } + + buffer = calloc(1, sizeof(tdm_drm_pp_buffer)); + if (!buffer) + { + TDM_ERR("alloc failed"); + return TDM_ERROR_NONE; + } + + LIST_ADDTAIL(&buffer->link, &pp_data->pending_buffer_list); + + buffer->src = src; + buffer->dst = dst; + + return TDM_ERROR_NONE; +} + +tdm_error +drm_pp_commit(tdm_pp *pp) +{ + tdm_drm_pp_data *pp_data = pp; + tdm_drm_pp_buffer *b = NULL, *bb = NULL; + + RETURN_VAL_IF_FAIL(pp_data, TDM_ERROR_INVALID_PARAMETER); + + LIST_FOR_EACH_ENTRY_SAFE(b, bb, &pp_data->pending_buffer_list, link) + { + LIST_DEL(&b->link); + + _tdm_drm_pp_convert(b, &pp_data->info); + + if (pp_data->done_func) + pp_data->done_func(pp_data, + b->src, + b->dst, + pp_data->done_user_data); + free(b); + } + + return TDM_ERROR_NONE; +} + +tdm_error +drm_pp_set_done_handler(tdm_pp *pp, tdm_pp_done_handler func, void *user_data) +{ + tdm_drm_pp_data *pp_data = pp; + + RETURN_VAL_IF_FAIL(pp_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER); + + pp_data->done_func = func; + pp_data->done_user_data = user_data; + + return TDM_ERROR_NONE; +} diff --git a/src/tdm_drm_pp.h b/src/tdm_drm_pp.h new file mode 100644 index 0000000..acbb425 --- /dev/null +++ b/src/tdm_drm_pp.h @@ -0,0 +1,13 @@ +#ifndef _TDM_DRM_PP_H_ +#define _TDM_DRM_PP_H_ + +#include "tdm_drm.h" + +tdm_error tdm_drm_pp_get_capability(tdm_drm_data *drm_data, tdm_caps_pp *caps); +tdm_pp* tdm_drm_pp_create(tdm_drm_data *drm_data, tdm_error *error); +void tdm_drm_pp_handler(unsigned int prop_id, unsigned int *buf_idx, + unsigned int tv_sec, unsigned int tv_usec, void *data); +void tdm_drm_pp_cb(int fd, unsigned int prop_id, unsigned int *buf_idx, + unsigned int tv_sec, unsigned int tv_usec, + void *user_data); +#endif /* _TDM_DRM_PP_H_ */ |