summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac2
-rw-r--r--packaging/libtdm-drm.spec1
-rw-r--r--src/Makefile.am1
-rw-r--r--src/tdm_drm.c13
-rw-r--r--src/tdm_drm.h13
-rw-r--r--src/tdm_drm_display.c18
-rw-r--r--src/tdm_drm_pp.c403
-rw-r--r--src/tdm_drm_pp.h13
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_ */