summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunkyeong Kim <jk0430.kim@samsung.com>2015-12-17 11:40:07 +0900
committerBoram Park <boram1288.park@samsung.com>2015-12-21 21:34:38 +0900
commitfcc98bd4aedf49f5eecca577bdd57f6336af9673 (patch)
treeb74f2a0ec7b00f33985f89f0d34972dee31b333c
parent18d08e277a25cbeb5c2a49bb74ab0324261fd1cf (diff)
downloadlibtdm-drm-fcc98bd4aedf49f5eecca577bdd57f6336af9673.tar.gz
libtdm-drm-fcc98bd4aedf49f5eecca577bdd57f6336af9673.tar.bz2
libtdm-drm-fcc98bd4aedf49f5eecca577bdd57f6336af9673.zip
Change-Id: I461763439b1cb1ac397d98755f029d71d92365a5
-rw-r--r--COPYING21
-rw-r--r--Makefile.am1
-rwxr-xr-xautogen.sh6
-rw-r--r--configure.ac55
-rw-r--r--packaging/libtdm-drm.manifest5
-rw-r--r--packaging/libtdm-drm.spec41
-rw-r--r--src/Makefile.am13
-rw-r--r--src/tdm_drm.c270
-rw-r--r--src/tdm_drm.h101
-rw-r--r--src/tdm_drm_display.c1496
-rw-r--r--src/tdm_drm_format.c106
11 files changed, 2115 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..817cb95
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,21 @@
+Copyright 2013 Samsung Electronics co., Ltd. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sub license, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..af437a6
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = src
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..30d679f
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,6 @@
+#! /bin/sh
+
+test -n "$srcdir" || srcdir=`dirname "$0"`
+test -n "$srcdir" || srcdir=.
+autoreconf --force --install --verbose "$srcdir"
+test -n "$NOCONFIGURE" || "$srcdir/configure" "$@"
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..642db2e
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,55 @@
+AC_PREREQ([2.60])
+AC_INIT([libtdm-drm],
+ [1.0.0],
+ [https://www.tizen.org],
+ [libtdm-drm])
+
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_SRCDIR([Makefile.am])
+AM_INIT_AUTOMAKE([1.10 foreign dist-bzip2])
+AM_MAINTAINER_MODE([enable])
+
+# Check for programs
+AC_PROG_CC
+
+AC_USE_SYSTEM_EXTENSIONS
+AC_SYS_LARGEFILE
+AC_FUNC_ALLOCA
+
+# Initialize libtool
+LT_PREREQ([2.2])
+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(UDEV, libudev, [udev=yes], [udev=no])
+if test x"$udev" = xyes; then
+ AC_DEFINE(HAVE_UDEV,1,[Enable udev-based monitor hotplug detection])
+ TDM_DRM_CFLAGS="$TDM_DRM_CFLAGS $UDEV_CFLAGS"
+ TDM_DRM_LIBS="$TDM_DRM_LIBS $UDEV_LIBS"
+fi
+
+AC_SUBST(TDM_DRM_CFLAGS)
+AC_SUBST(TDM_DRM_LIBS)
+
+# set the dir for the tbm module
+DEFAULT_TDM_MODULE_PATH="${libdir}/tdm"
+AC_ARG_WITH(tdm-module-path, AS_HELP_STRING([--with-tdm-module-path=PATH], [tdm module dir]),
+ [ TDM_MODULE_PATH="$withval" ],
+ [ TDM_MODULE_PATH="${DEFAULT_TDM_MODULE_PATH}" ])
+AC_SUBST(TDM_MODULE_PATH)
+
+# For enumerating devices in test case
+AC_OUTPUT([
+ Makefile
+ src/Makefile])
+
+echo ""
+echo "$PACKAGE_STRING will be compiled with:"
+echo ""
+echo "TDM_DRM_CFLAGS : $TDM_DRM_CFLAGS"
+echo "TDM_DRM_LIBS : $TDM_DRM_LIBS"
+echo "TDM_MODULE_DIR : $TDM_MODULE_PATH"
+echo ""
diff --git a/packaging/libtdm-drm.manifest b/packaging/libtdm-drm.manifest
new file mode 100644
index 0000000..75b0fa5
--- /dev/null
+++ b/packaging/libtdm-drm.manifest
@@ -0,0 +1,5 @@
+<manifest>
+ <request>
+ <domain name="_"/>
+ </request>
+</manifest>
diff --git a/packaging/libtdm-drm.spec b/packaging/libtdm-drm.spec
new file mode 100644
index 0000000..52dc4a7
--- /dev/null
+++ b/packaging/libtdm-drm.spec
@@ -0,0 +1,41 @@
+Name: libtdm-drm
+Version: 1.0.0
+Release: 0
+Summary: Tizen Display Manager DRM Back-End Library
+Group: Development/Libraries
+License: MIT
+Source0: %{name}-%{version}.tar.gz
+Source1001: %{name}.manifest
+BuildRequires: pkgconfig(libdrm)
+BuildRequires: pkgconfig(libudev)
+BuildRequires: pkgconfig(libtdm)
+
+%description
+Back-End library of Tizen Display Manager DRM : libtdm-mgr DRM library
+
+%prep
+%setup -q
+cp %{SOURCE1001} .
+
+%build
+%reconfigure --prefix=%{_prefix} --libdir=%{_libdir} --disable-static \
+ CFLAGS="${CFLAGS} -Wall -Werror" \
+ LDFLAGS="${LDFLAGS} -Wl,--hash-style=both -Wl,--as-needed"
+make %{?_smp_mflags}
+
+%install
+%make_install
+
+%post
+if [ -f %{_libdir}/tdm/libtdm-default.so ]; then
+ rm -rf %{_libdir}/tdm/libtdm-default.so
+fi
+ln -s libtdm-drm.so %{_libdir}/tdm/libtdm-default.so
+
+%postun -p /sbin/ldconfig
+
+%files
+%manifest %{name}.manifest
+%license COPYING
+%defattr(-,root,root,-)
+%{_libdir}/tdm/libtdm-drm.so
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..6e6d8c3
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,13 @@
+AM_CFLAGS = \
+ $(TDM_DRM_CFLAGS) \
+ -I$(top_srcdir)/src
+
+libtdm_drm_la_LTLIBRARIES = libtdm-drm.la
+libtdm_drm_ladir = $(TDM_MODULE_PATH)
+libtdm_drm_la_LDFLAGS = -module -avoid-version
+libtdm_drm_la_LIBADD = $(TDM_DRM_LIBS) -ldl
+
+libtdm_drm_la_SOURCES = \
+ tdm_drm_format.c \
+ tdm_drm_display.c \
+ tdm_drm.c
diff --git a/src/tdm_drm.c b/src/tdm_drm.c
new file mode 100644
index 0000000..3200569
--- /dev/null
+++ b/src/tdm_drm.c
@@ -0,0 +1,270 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if HAVE_UDEV
+#include <libudev.h>
+#endif
+
+#include "tdm_drm.h"
+#include <tdm_helper.h>
+
+#define TDM_DRM_NAME "vigs"
+
+static tdm_func_display drm_func_display =
+{
+ drm_display_get_capabilitiy,
+ NULL, //display_get_pp_capability,
+ NULL, //display_get_capture_capability
+ drm_display_get_outputs,
+ drm_display_get_fd,
+ drm_display_handle_events,
+ NULL, //display_create_pp,
+ drm_output_get_capability,
+ drm_output_get_layers,
+ drm_output_set_property,
+ drm_output_get_property,
+ drm_output_wait_vblank,
+ drm_output_set_vblank_handler,
+ drm_output_commit,
+ drm_output_set_commit_handler,
+ drm_output_set_dpms,
+ drm_output_get_dpms,
+ drm_output_set_mode,
+ drm_output_get_mode,
+ NULL, //output_create_capture
+ drm_layer_get_capability,
+ drm_layer_set_property,
+ drm_layer_get_property,
+ drm_layer_set_info,
+ drm_layer_get_info,
+ drm_layer_set_buffer,
+ drm_layer_unset_buffer,
+ NULL, //layer_create_capture
+};
+
+static tdm_drm_data *drm_data;
+
+#ifdef HAVE_UDEV
+static struct udev_device*
+_tdm_find_primary_gpu(void)
+{
+ struct udev *udev;
+ struct udev_enumerate *e;
+ struct udev_list_entry *entry;
+ const char *path, *id;
+ struct udev_device *device, *drm_device, *pci;
+
+ udev = udev_new();
+ if (!udev)
+ {
+ TDM_ERR("fail to initialize udev context\n");
+ return NULL;
+ }
+
+ e = udev_enumerate_new(udev);
+ udev_enumerate_add_match_subsystem(e, "drm");
+ udev_enumerate_add_match_sysname(e, "card[0-9]*");
+
+ udev_enumerate_scan_devices(e);
+ drm_device = NULL;
+ udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
+ path = udev_list_entry_get_name(entry);
+ device = udev_device_new_from_syspath(udev, path);
+ if (!device)
+ continue;
+
+ pci = udev_device_get_parent_with_subsystem_devtype(device,
+ "pci", NULL);
+ if (pci) {
+ id = udev_device_get_sysattr_value(pci, "boot_vga");
+ if (id && !strcmp(id, "1")) {
+ if (drm_device)
+ udev_device_unref(drm_device);
+ drm_device = device;
+ break;
+ }
+ }
+
+ if (!drm_device)
+ drm_device = device;
+ else
+ udev_device_unref(device);
+ }
+
+ udev_enumerate_unref(e);
+ return drm_device;
+}
+#endif
+
+static int
+_tdm_drm_open_drm(void)
+{
+ int fd = -1;
+
+ fd = drmOpen(TDM_DRM_NAME, NULL);
+ if (fd < 0)
+ {
+ TDM_ERR("Cannot open '%s' drm", TDM_DRM_NAME);
+ }
+
+#ifdef HAVE_UDEV
+ if (fd < 0)
+ {
+ struct udev_device *drm_device = NULL;
+ const char *filename;
+ TDM_WRN("Cannot open drm device.. search by udev");
+
+ drm_device = _tdm_find_primary_gpu();
+ if (drm_device == NULL)
+ {
+ TDM_ERR("fail to find drm device\n");
+ goto close_l;
+ }
+
+ filename = udev_device_get_devnode(drm_device);
+
+ fd = open(filename, O_RDWR | O_CLOEXEC);
+ if (fd < 0)
+ TDM_ERR("Cannot open drm device(%s)\n", filename);
+
+ TDM_DBG("open drm device (name:%s, fd:%d)", filename, fd);
+
+ udev_device_unref(drm_device);
+ }
+close_l:
+#endif
+ return fd;
+}
+
+void
+tdm_drm_deinit(tdm_backend_data *bdata)
+{
+ if (drm_data != bdata)
+ return;
+
+ TDM_INFO("deinit");
+
+ tdm_drm_display_destroy_output_list(drm_data);
+
+ if (drm_data->plane_res)
+ drmModeFreePlaneResources(drm_data->plane_res);
+ if (drm_data->mode_res)
+ drmModeFreeResources(drm_data->mode_res);
+ if (drm_data->drm_fd >= 0)
+ close(drm_data->drm_fd);
+
+ free(drm_data);
+ drm_data = NULL;
+}
+
+tdm_backend_data*
+tdm_drm_init(tdm_display *dpy, tdm_error *error)
+{
+ tdm_error ret;
+
+ if (!dpy)
+ {
+ TDM_ERR("display is null");
+ if (error)
+ *error = TDM_ERROR_INVALID_PARAMETER;
+ return NULL;
+ }
+
+ if (drm_data)
+ {
+ TDM_ERR("failed: init twice");
+ if (error)
+ *error = TDM_ERROR_BAD_REQUEST;
+ return NULL;
+ }
+
+ drm_data = calloc(1, sizeof(tdm_drm_data));
+ if (!drm_data)
+ {
+ TDM_ERR("alloc failed");
+ if (error)
+ *error = TDM_ERROR_OUT_OF_MEMORY;
+ return NULL;
+ }
+
+ LIST_INITHEAD(&drm_data->output_list);
+ LIST_INITHEAD(&drm_data->buffer_list);
+
+ ret = tdm_backend_register_func_display(dpy, &drm_func_display);
+ if (ret != TDM_ERROR_NONE)
+ goto failed;
+
+ drm_data->dpy = dpy;
+
+ drm_data->drm_fd = -1;
+ if (tdm_helper_drm_fd >= 0)
+ drm_data->drm_fd = tdm_helper_drm_fd;
+
+ if (drm_data->drm_fd < 0)
+ drm_data->drm_fd = _tdm_drm_open_drm();
+
+ if (drm_data->drm_fd < 0)
+ {
+ ret = TDM_ERROR_OPERATION_FAILED;
+ goto failed;
+ }
+
+ if (drmSetClientCap(drm_data->drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) < 0)
+ TDM_WRN("Set DRM_CLIENT_CAP_UNIVERSAL_PLANES failed");
+
+ drm_data->mode_res = drmModeGetResources(drm_data->drm_fd);
+ if (!drm_data->mode_res)
+ {
+ TDM_ERR("no drm resource: %m");
+ ret = TDM_ERROR_OPERATION_FAILED;
+ goto failed;
+ }
+
+ drm_data->plane_res = drmModeGetPlaneResources(drm_data->drm_fd);
+ if (!drm_data->plane_res)
+ {
+ TDM_ERR("no drm plane resource: %m");
+ ret = TDM_ERROR_OPERATION_FAILED;
+ goto failed;
+ }
+
+ if (drm_data->plane_res->count_planes <= 0)
+ {
+ TDM_ERR("no drm plane resource");
+ ret = TDM_ERROR_OPERATION_FAILED;
+ goto failed;
+ }
+
+ ret = tdm_drm_display_create_output_list(drm_data);
+ if (ret != TDM_ERROR_NONE)
+ goto failed;
+
+ ret = tdm_drm_display_create_layer_list(drm_data);
+ if (ret != TDM_ERROR_NONE)
+ goto failed;
+
+ if (error)
+ *error = TDM_ERROR_NONE;
+
+ TDM_INFO("init success!");
+
+ return (tdm_backend_data*)drm_data;
+failed:
+ if (error)
+ *error = ret;
+
+ tdm_drm_deinit(drm_data);
+
+ TDM_ERR("init failed!");
+ return NULL;
+}
+
+tdm_backend_module tdm_backend_module_data =
+{
+ "vigs",
+ "Samsung",
+ TDM_BACKEND_ABI_VERSION,
+ tdm_drm_init,
+ tdm_drm_deinit
+};
diff --git a/src/tdm_drm.h b/src/tdm_drm.h
new file mode 100644
index 0000000..5fc9153
--- /dev/null
+++ b/src/tdm_drm.h
@@ -0,0 +1,101 @@
+#ifndef _TDM_DRM_H_
+#define _TDM_DRM_H_
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <tbm_surface.h>
+#include <tbm_surface_internal.h>
+#include <tdm_backend.h>
+#include <tdm_log.h>
+#include <tdm_list.h>
+
+/* drm backend functions (display) */
+tdm_error drm_display_get_capabilitiy(tdm_backend_data *bdata, tdm_caps_display *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);
+tdm_pp* drm_display_create_pp(tdm_backend_data *bdata, tdm_error *error);
+tdm_error drm_output_get_capability(tdm_output *output, tdm_caps_output *caps);
+tdm_layer** drm_output_get_layers(tdm_output *output, int *count, tdm_error *error);
+tdm_error drm_output_set_property(tdm_output *output, unsigned int id, tdm_value value);
+tdm_error drm_output_get_property(tdm_output *output, unsigned int id, tdm_value *value);
+tdm_error drm_output_wait_vblank(tdm_output *output, int interval, int sync, void *user_data);
+tdm_error drm_output_set_vblank_handler(tdm_output *output, tdm_output_vblank_handler func);
+tdm_error drm_output_commit(tdm_output *output, int sync, void *user_data);
+tdm_error drm_output_set_commit_handler(tdm_output *output, tdm_output_commit_handler func);
+tdm_error drm_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value);
+tdm_error drm_output_get_dpms(tdm_output *output, tdm_output_dpms *dpms_value);
+tdm_error drm_output_set_mode(tdm_output *output, tdm_output_mode *mode);
+tdm_error drm_output_get_mode(tdm_output *output, const tdm_output_mode **mode);
+tdm_error drm_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps);
+tdm_error drm_layer_set_property(tdm_layer *layer, unsigned int id, tdm_value value);
+tdm_error drm_layer_get_property(tdm_layer *layer, unsigned int id, tdm_value *value);
+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, tdm_buffer *buffer);
+tdm_error drm_layer_unset_buffer(tdm_layer *layer);
+
+/* drm module internal macros, structures, functions */
+#define NEVER_GET_HERE() TDM_ERR("** NEVER GET HERE **")
+
+#define C(b,m) (((b) >> (m)) & 0xFF)
+#define B(c,s) ((((unsigned int)(c)) & 0xff) << (s))
+#define FOURCC(a,b,c,d) (B(d,24) | B(c,16) | B(b,8) | B(a,0))
+#define FOURCC_STR(id) C(id,0), C(id,8), C(id,16), C(id,24)
+
+#define IS_RGB(format) (format == TBM_FORMAT_XRGB8888 || format == TBM_FORMAT_ARGB8888 || \
+ format == TBM_FORMAT_XBGR8888 || format == TBM_FORMAT_ABGR8888)
+
+#define CLEAR(x) memset(&(x), 0, sizeof(x))
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#define SWAP(a, b) ({int t; t = a; a = b; b = t;})
+#define ROUNDUP(x) (ceil (floor ((float)(height) / 4)))
+
+#define ALIGN_TO_16B(x) ((((x) + (1 << 4) - 1) >> 4) << 4)
+#define ALIGN_TO_32B(x) ((((x) + (1 << 5) - 1) >> 5) << 5)
+#define ALIGN_TO_128B(x) ((((x) + (1 << 7) - 1) >> 7) << 7)
+#define ALIGN_TO_2KB(x) ((((x) + (1 << 11) - 1) >> 11) << 11)
+#define ALIGN_TO_8KB(x) ((((x) + (1 << 13) - 1) >> 13) << 13)
+#define ALIGN_TO_64KB(x) ((((x) + (1 << 16) - 1) >> 16) << 16)
+
+#define RETURN_VAL_IF_FAIL(cond, val) {\
+ if (!(cond)) {\
+ TDM_ERR("'%s' failed", #cond);\
+ return val;\
+ }\
+}
+
+typedef struct _tdm_drm_data
+{
+ tdm_display *dpy;
+
+ int drm_fd;
+
+ drmModeResPtr mode_res;
+ drmModePlaneResPtr plane_res;
+
+ struct list_head output_list;
+ struct list_head buffer_list;
+} tdm_drm_data;
+
+uint32_t tdm_drm_format_to_drm_format(tbm_format format);
+tbm_format tdm_drm_format_to_tbm_format(uint32_t format);
+
+tdm_error tdm_drm_display_create_output_list(tdm_drm_data *drm_data);
+void tdm_drm_display_destroy_output_list(tdm_drm_data *drm_data);
+tdm_error tdm_drm_display_create_layer_list(tdm_drm_data *drm_data);
+
+#endif /* _TDM_DRM_H_ */
diff --git a/src/tdm_drm_display.c b/src/tdm_drm_display.c
new file mode 100644
index 0000000..645a086
--- /dev/null
+++ b/src/tdm_drm_display.c
@@ -0,0 +1,1496 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <drm_fourcc.h>
+#include <tdm_helper.h>
+#include "tdm_drm.h"
+
+#define MIN_WIDTH 32
+
+typedef struct _tdm_drm_output_data tdm_drm_output_data;
+typedef struct _tdm_drm_layer_data tdm_drm_layer_data;
+typedef struct _tdm_drm_vblank_data tdm_drm_vblank_data;
+
+typedef enum
+{
+ VBLANK_TYPE_WAIT,
+ VBLANK_TYPE_COMMIT,
+} vblank_type;
+
+typedef struct _tdm_drm_display_buffer
+{
+ struct list_head link;
+
+ unsigned int fb_id;
+ tdm_buffer *buffer;
+ int width;
+} tdm_drm_display_buffer;
+
+struct _tdm_drm_vblank_data
+{
+ vblank_type type;
+ tdm_drm_output_data *output_data;
+ void *user_data;
+};
+
+struct _tdm_drm_output_data
+{
+ struct list_head link;
+
+ /* data which are fixed at initializing */
+ tdm_drm_data *drm_data;
+ uint32_t connector_id;
+ uint32_t encoder_id;
+ uint32_t crtc_id;
+ uint32_t pipe;
+ uint32_t dpms_prop_id;
+ int count_modes;
+ drmModeModeInfoPtr drm_modes;
+ tdm_output_mode *output_modes;
+ tdm_output_type connector_type;
+ unsigned int connector_type_id;
+ struct list_head layer_list;
+ tdm_drm_layer_data *primary_layer;
+
+ /* not fixed data below */
+ tdm_output_vblank_handler vblank_func;
+ tdm_output_commit_handler commit_func;
+
+ tdm_output_conn_status status;
+
+ int mode_changed;
+ tdm_output_mode *current_mode;
+
+ int waiting_vblank_event;
+};
+
+struct _tdm_drm_layer_data
+{
+ struct list_head link;
+
+ /* data which are fixed at initializing */
+ tdm_drm_data *drm_data;
+ tdm_drm_output_data *output_data;
+ uint32_t plane_id;
+ tdm_layer_capability capabilities;
+ int zpos;
+
+ /* not fixed data below */
+ tdm_info_layer info;
+ int info_changed;
+
+ tdm_drm_display_buffer *display_buffer;
+ int display_buffer_changed;
+};
+
+typedef struct _Drm_Event_Context
+{
+ void (*vblank_handler)(int fd, unsigned int sequence, unsigned int tv_sec,
+ unsigned int tv_usec, void *user_data);
+} Drm_Event_Context;
+
+static drmModeModeInfoPtr
+_tdm_drm_display_get_mode(tdm_drm_output_data *output_data)
+{
+ int i;
+
+ if (!output_data->current_mode)
+ {
+ TDM_ERR("no output_data->current_mode");
+ return NULL;
+ }
+
+ for (i = 0; i < output_data->count_modes; i++)
+ {
+ drmModeModeInfoPtr drm_mode = &output_data->drm_modes[i];
+ if ((drm_mode->hdisplay == output_data->current_mode->width) &&
+ (drm_mode->vdisplay == output_data->current_mode->height) &&
+ (drm_mode->vrefresh == output_data->current_mode->refresh) &&
+ (drm_mode->flags == output_data->current_mode->flags) &&
+ (drm_mode->type == output_data->current_mode->type) &&
+ !(strncmp(drm_mode->name, output_data->current_mode->name, TDM_NAME_LEN)))
+ return drm_mode;
+ }
+
+ return NULL;
+}
+
+static tdm_drm_display_buffer*
+_tdm_drm_display_find_buffer(tdm_drm_data *drm_data, tdm_buffer *buffer)
+{
+ tdm_drm_display_buffer *display_buffer;
+
+ LIST_FOR_EACH_ENTRY(display_buffer, &drm_data->buffer_list, link)
+ {
+ if (display_buffer->buffer == buffer)
+ return display_buffer;
+ }
+
+ return NULL;
+}
+
+static void
+_tdm_drm_display_to_tdm_mode(drmModeModeInfoPtr drm_mode, tdm_output_mode *tdm_mode)
+{
+ tdm_mode->width = drm_mode->hdisplay;
+ tdm_mode->height = drm_mode->vdisplay;
+ tdm_mode->refresh = drm_mode->vrefresh;
+ tdm_mode->flags = drm_mode->flags;
+ tdm_mode->type = drm_mode->type;
+ snprintf(tdm_mode->name, TDM_NAME_LEN, "%s", drm_mode->name);
+}
+
+static tdm_error
+_tdm_drm_display_get_cur_msc (int fd, int pipe, uint *msc)
+{
+ drmVBlank vbl;
+
+ vbl.request.type = DRM_VBLANK_RELATIVE;
+ if (pipe > 0)
+ vbl.request.type |= DRM_VBLANK_SECONDARY;
+
+ vbl.request.sequence = 0;
+ if (drmWaitVBlank(fd, &vbl))
+ {
+ TDM_ERR("get vblank counter failed: %m");
+ *msc = 0;
+ return TDM_ERROR_OPERATION_FAILED;
+ }
+
+ *msc = vbl.reply.sequence;
+
+ return TDM_ERROR_NONE;
+}
+
+static tdm_error
+_tdm_drm_display_wait_vblank(int fd, int pipe, uint *target_msc, void *data)
+{
+ drmVBlank vbl;
+
+ vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
+ if (pipe > 0)
+ vbl.request.type |= DRM_VBLANK_SECONDARY;
+
+ vbl.request.sequence = *target_msc;
+ vbl.request.signal = (unsigned long)(uintptr_t)data;
+
+ if (drmWaitVBlank(fd, &vbl))
+ {
+ *target_msc = 0;
+ TDM_ERR("wait vblank failed: %m");
+ return TDM_ERROR_OPERATION_FAILED;
+ }
+
+ *target_msc = vbl.reply.sequence;
+
+ return TDM_ERROR_NONE;
+}
+
+static tdm_error
+_tdm_drm_display_commit_primary_layer(tdm_drm_layer_data *layer_data)
+{
+ tdm_drm_data *drm_data = layer_data->drm_data;
+ tdm_drm_output_data *output_data = layer_data->output_data;
+
+ if (output_data->mode_changed && layer_data->display_buffer_changed)
+ {
+ drmModeModeInfoPtr mode;
+
+ if (!layer_data->display_buffer)
+ {
+ TDM_ERR("primary layer should have a buffer for modestting");
+ return TDM_ERROR_BAD_REQUEST;
+ }
+
+ output_data->mode_changed = 0;
+ layer_data->display_buffer_changed = 0;
+ layer_data->info_changed = 0;
+
+ mode = _tdm_drm_display_get_mode(output_data);
+ if (!mode)
+ {
+ TDM_ERR("couldn't find proper mode");
+ return TDM_ERROR_BAD_REQUEST;
+ }
+
+ if (drmModeSetCrtc(drm_data->drm_fd, output_data->crtc_id,
+ layer_data->display_buffer->fb_id, 0, 0,
+ &output_data->connector_id, 1, mode))
+ {
+ TDM_ERR("set crtc failed: %m");
+ return TDM_ERROR_OPERATION_FAILED;
+ }
+
+ return TDM_ERROR_NONE;
+ }
+ else if (layer_data->display_buffer_changed)
+ {
+ layer_data->display_buffer_changed = 0;
+
+ if (!layer_data->display_buffer)
+ {
+ if (drmModeSetCrtc(drm_data->drm_fd, output_data->crtc_id,
+ 0, 0, 0, NULL, 0, NULL))
+ {
+ TDM_ERR("unset crtc failed: %m");
+ return TDM_ERROR_OPERATION_FAILED;
+ }
+ }
+ else
+ {
+ if (drmModePageFlip(drm_data->drm_fd, output_data->crtc_id,
+ layer_data->display_buffer->fb_id, DRM_MODE_PAGE_FLIP_EVENT, layer_data->display_buffer))
+ {
+ TDM_ERR("pageflip failed: %m");
+ return TDM_ERROR_OPERATION_FAILED;
+ }
+ }
+ }
+
+ return TDM_ERROR_NONE;
+}
+
+static tdm_error
+_tdm_drm_display_commit_layer(tdm_drm_layer_data *layer_data)
+{
+ tdm_drm_data *drm_data = layer_data->drm_data;
+ tdm_drm_output_data *output_data = layer_data->output_data;
+ uint32_t fx, fy, fw, fh;
+ int crtc_w;
+
+ if (!layer_data->display_buffer_changed && !layer_data->info_changed)
+ return TDM_ERROR_NONE;
+
+ if (output_data->current_mode)
+ crtc_w = output_data->current_mode->width;
+ else
+ {
+ drmModeCrtcPtr crtc = drmModeGetCrtc(drm_data->drm_fd, output_data->crtc_id);
+ if (!crtc)
+ {
+ TDM_ERR("getting crtc failed");
+ return TDM_ERROR_OPERATION_FAILED;
+ }
+ crtc_w = crtc->width;
+ if (crtc_w == 0)
+ {
+ TDM_ERR("getting crtc width failed");
+ return TDM_ERROR_OPERATION_FAILED;
+ }
+ }
+
+ layer_data->display_buffer_changed = 0;
+ layer_data->info_changed = 0;
+
+ if (!layer_data->display_buffer)
+ {
+ if (drmModeSetPlane(drm_data->drm_fd, layer_data->plane_id,
+ output_data->crtc_id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
+ TDM_ERR("unset plane(%d) filed: %m", layer_data->plane_id);
+
+ return TDM_ERROR_NONE;
+ }
+
+ /* Source values are 16.16 fixed point */
+ fx = ((unsigned int)layer_data->info.src_config.pos.x) << 16;
+ fy = ((unsigned int)layer_data->info.src_config.pos.y) << 16;
+ fw = ((unsigned int)layer_data->info.src_config.pos.w) << 16;
+ fh = ((unsigned int)layer_data->info.src_config.pos.h) << 16;
+
+ if (drmModeSetPlane(drm_data->drm_fd, layer_data->plane_id,
+ output_data->crtc_id, layer_data->display_buffer->fb_id, 0,
+ layer_data->info.dst_pos.x, layer_data->info.dst_pos.y,
+ layer_data->info.dst_pos.w, layer_data->info.dst_pos.h,
+ fx, fy, fw, fh) < 0)
+ {
+ TDM_ERR("set plane(%d) failed: %m", layer_data->plane_id);
+ return TDM_ERROR_OPERATION_FAILED;
+ }
+
+ return TDM_ERROR_NONE;
+}
+
+static void
+_tdm_drm_display_cb_vblank(int fd, unsigned int sequence,
+ unsigned int tv_sec, unsigned int tv_usec,
+ void *user_data)
+{
+ tdm_drm_vblank_data *vblank_data = user_data;
+ tdm_drm_output_data *output_data;
+
+ if (!vblank_data)
+ {
+ TDM_ERR("no vblank data");
+ return;
+ }
+
+ output_data = vblank_data->output_data;
+
+ switch(vblank_data->type)
+ {
+ case VBLANK_TYPE_WAIT:
+ if (output_data->vblank_func)
+ output_data->vblank_func(output_data, sequence, tv_sec, tv_usec, vblank_data->user_data);
+ break;
+ case VBLANK_TYPE_COMMIT:
+ if (output_data->commit_func)
+ output_data->commit_func(output_data, sequence, tv_sec, tv_usec, vblank_data->user_data);
+ break;
+ default:
+ return;
+ }
+}
+
+static int
+_tdm_drm_display_events_handle(int fd, Drm_Event_Context *evctx)
+{
+#define MAX_BUF_SIZE 1024
+
+ char buffer[MAX_BUF_SIZE];
+ unsigned int len, i;
+ struct drm_event *e;
+
+ /* The DRM read semantics guarantees that we always get only
+ * complete events. */
+ len = read(fd, buffer, sizeof buffer);
+ if (len == 0)
+ {
+ TDM_WRN("warning: the size of the drm_event is 0.");
+ return 0;
+ }
+ if (len < sizeof *e)
+ {
+ TDM_WRN("warning: the size of the drm_event is less than drm_event structure.");
+ return -1;
+ }
+ if (len > MAX_BUF_SIZE)
+ {
+ TDM_WRN("warning: the size of the drm_event can be over the maximum size.");
+ return -1;
+ }
+
+ i = 0;
+ while (i < len)
+ {
+ e = (struct drm_event *) &buffer[i];
+ switch (e->type)
+ {
+ case DRM_EVENT_VBLANK:
+ {
+ struct drm_event_vblank *vblank;
+
+ if (evctx->vblank_handler == NULL)
+ break;
+
+ vblank = (struct drm_event_vblank *)e;
+ TDM_DBG("******* VBLANK *******");
+ evctx->vblank_handler (fd, vblank->sequence,
+ vblank->tv_sec, vblank->tv_usec,
+ (void *)((unsigned long)vblank->user_data));
+ TDM_DBG("******* VBLANK *******...");
+ }
+ break;
+ case DRM_EVENT_FLIP_COMPLETE:
+ /* do nothing for flip complete */
+ break;
+ default:
+ break;
+ }
+ i += e->length;
+ }
+
+ return 0;
+}
+
+static tdm_error
+_tdm_drm_display_create_layer_list(tdm_drm_data *drm_data)
+{
+ int i;
+
+ if (drm_data->plane_res->count_planes == 0)
+ {
+ TDM_ERR("no layer error");
+ return TDM_ERROR_OPERATION_FAILED;
+ }
+
+ for (i = 0; i < drm_data->plane_res->count_planes; i++)
+ {
+ tdm_drm_output_data *output_data;
+ tdm_drm_layer_data *layer_data;
+ drmModePlanePtr plane;
+
+ if (i == 3)
+ {
+ TDM_DBG("doesn't need more layer set");
+ break;
+ }
+
+ LIST_FOR_EACH_ENTRY(output_data, &drm_data->output_list, link)
+ {
+ if (output_data->pipe == 0)
+ break;
+ }
+
+ plane = drmModeGetPlane(drm_data->drm_fd, drm_data->plane_res->planes[i]);
+ if (!plane)
+ {
+ TDM_ERR("no plane");
+ continue;
+ }
+
+ layer_data = calloc(1, sizeof(tdm_drm_layer_data));
+ if (!layer_data)
+ {
+ TDM_ERR("alloc failed");
+ drmModeFreePlane(plane);
+ continue;
+ }
+
+ layer_data->drm_data = drm_data;
+ layer_data->output_data = output_data;
+ layer_data->plane_id = drm_data->plane_res->planes[i];
+
+ if (drm_data->plane_res->count_planes == 1)
+ {
+ layer_data->capabilities = TDM_LAYER_CAPABILITY_PRIMARY | TDM_LAYER_CAPABILITY_GRAPHIC;
+ output_data->primary_layer = layer_data;
+ }
+ else if (drm_data->plane_res->count_planes == 2)
+ {
+ if (i == 0)
+ {
+ layer_data->capabilities = TDM_LAYER_CAPABILITY_PRIMARY | TDM_LAYER_CAPABILITY_GRAPHIC;
+ output_data->primary_layer = layer_data;
+ }
+ else
+ {
+ layer_data->capabilities = TDM_LAYER_CAPABILITY_OVERLAY | TDM_LAYER_CAPABILITY_GRAPHIC;
+ }
+ }
+ else
+ {
+ if (i == 0)
+ {
+ layer_data->capabilities = TDM_LAYER_CAPABILITY_CURSOR | TDM_LAYER_CAPABILITY_GRAPHIC;
+ }
+ else if (i == 1)
+ {
+ layer_data->capabilities = TDM_LAYER_CAPABILITY_PRIMARY | TDM_LAYER_CAPABILITY_GRAPHIC;
+ output_data->primary_layer = layer_data;
+ }
+ else
+ {
+ layer_data->capabilities = TDM_LAYER_CAPABILITY_OVERLAY | TDM_LAYER_CAPABILITY_GRAPHIC;
+ }
+ }
+
+ TDM_DBG("layer_data(%p) plane_id(%d) crtc_id(%d) capabilities(%x)",
+ layer_data, layer_data->plane_id, layer_data->output_data->crtc_id,
+ layer_data->capabilities);
+
+ LIST_ADDTAIL(&layer_data->link, &output_data->layer_list);
+
+ drmModeFreePlane(plane);
+ }
+
+ return TDM_ERROR_NONE;
+}
+
+static void
+_tdm_drm_display_cb_destroy_buffer(tdm_buffer *buffer, void *user_data)
+{
+ tdm_drm_data *drm_data;
+ tdm_drm_display_buffer *display_buffer;
+ int ret;
+
+ if (!user_data)
+ {
+ TDM_ERR("no user_data");
+ return;
+ }
+ if (!buffer)
+ {
+ TDM_ERR("no buffer");
+ return;
+ }
+
+ drm_data = (tdm_drm_data *)user_data;
+
+ display_buffer = _tdm_drm_display_find_buffer(drm_data, buffer);
+ if (!display_buffer)
+ {
+ TDM_ERR("no display_buffer");
+ return;
+ }
+ LIST_DEL(&display_buffer->link);
+
+ if (display_buffer->fb_id > 0)
+ {
+ ret = drmModeRmFB(drm_data->drm_fd, display_buffer->fb_id);
+ if (ret < 0)
+ {
+ TDM_ERR("rm fb failed");
+ return;
+ }
+ TDM_DBG("drmModeRmFB success!!! fb_id:%d", display_buffer->fb_id);
+ }
+ else
+ TDM_DBG("drmModeRmFB not called fb_id:%d", display_buffer->fb_id);
+
+ free(display_buffer);
+}
+
+tdm_error
+tdm_drm_display_create_layer_list(tdm_drm_data *drm_data)
+{
+ tdm_drm_output_data *output_data;
+ tdm_error ret;
+
+ ret = _tdm_drm_display_create_layer_list(drm_data);
+ if (ret != TDM_ERROR_NONE)
+ return ret;
+
+ LIST_FOR_EACH_ENTRY(output_data, &drm_data->output_list, link)
+ {
+ if (!output_data->primary_layer)
+ {
+ TDM_ERR("output(%d) no primary layer", output_data->pipe);
+ return TDM_ERROR_OPERATION_FAILED;
+ }
+ }
+
+ return TDM_ERROR_NONE;
+}
+
+void
+tdm_drm_display_destroy_output_list(tdm_drm_data *drm_data)
+{
+ tdm_drm_output_data *o = NULL, *oo = NULL;
+
+ if (LIST_IS_EMPTY(&drm_data->output_list))
+ return;
+
+ LIST_FOR_EACH_ENTRY_SAFE(o, oo, &drm_data->output_list, link)
+ {
+ LIST_DEL(&o->link);
+ if (!LIST_IS_EMPTY(&o->layer_list))
+ {
+ tdm_drm_layer_data *l = NULL, *ll = NULL;
+ LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->layer_list, link)
+ {
+ LIST_DEL(&l->link);
+ free(l);
+ }
+ }
+ free(o->drm_modes);
+ free(o->output_modes);
+ free(o);
+ }
+}
+
+tdm_error
+tdm_drm_display_create_output_list(tdm_drm_data *drm_data)
+{
+ tdm_drm_output_data *output_data;
+ int i;
+ tdm_error ret;
+ int allocated = 0;
+
+ RETURN_VAL_IF_FAIL(LIST_IS_EMPTY(&drm_data->output_list), TDM_ERROR_OPERATION_FAILED);
+
+ for (i = 0; i < drm_data->mode_res->count_connectors; i++)
+ {
+ drmModeConnectorPtr connector;
+ drmModeEncoderPtr encoder;
+ int crtc_id = 0, c, j;
+
+ connector = drmModeGetConnector(drm_data->drm_fd, drm_data->mode_res->connectors[i]);
+ if (!connector)
+ {
+ TDM_ERR("no connector");
+ ret = TDM_ERROR_OPERATION_FAILED;
+ goto failed_create;
+ }
+
+ if (connector->count_encoders != 1)
+ {
+ TDM_ERR("too many encoders: %d", connector->count_encoders);
+ drmModeFreeConnector(connector);
+ ret = TDM_ERROR_OPERATION_FAILED;
+ goto failed_create;
+ }
+
+ encoder = drmModeGetEncoder(drm_data->drm_fd, connector->encoders[0]);
+ if (!encoder)
+ {
+ TDM_ERR("no encoder");
+ drmModeFreeConnector(connector);
+ ret = TDM_ERROR_OPERATION_FAILED;
+ goto failed_create;
+ }
+
+ for (c = 0; c < drm_data->mode_res->count_crtcs; c++)
+ {
+ if (allocated & (1 << c))
+ continue;
+
+ if ((encoder->possible_crtcs & (1 << c)) == 0)
+ continue;
+
+ crtc_id = drm_data->mode_res->crtcs[c];
+ allocated |= (1 << c);
+ break;
+ }
+
+ if (crtc_id == 0)
+ {
+ TDM_ERR("no possible crtc");
+ drmModeFreeConnector(connector);
+ ret = TDM_ERROR_OPERATION_FAILED;
+ goto failed_create;
+ }
+
+ output_data = calloc(1, sizeof(tdm_drm_output_data));
+ if (!output_data)
+ {
+ TDM_ERR("alloc failed");
+ drmModeFreeConnector(connector);
+ drmModeFreeEncoder(encoder);
+ ret = TDM_ERROR_OUT_OF_MEMORY;
+ goto failed_create;
+ }
+
+ LIST_INITHEAD(&output_data->layer_list);
+
+ output_data->drm_data = drm_data;
+ output_data->connector_id = drm_data->mode_res->connectors[i];
+ output_data->encoder_id = encoder->encoder_id;
+ output_data->crtc_id = crtc_id;
+ output_data->pipe = c;
+ output_data->connector_type = connector->connector_type;
+ output_data->connector_type_id = connector->connector_type_id;
+
+ if (connector->connection == DRM_MODE_CONNECTED)
+ output_data->status = TDM_OUTPUT_CONN_STATUS_CONNECTED;
+ else
+ output_data->status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
+
+ for (j = 0; j < connector->count_props; j++)
+ {
+ drmModePropertyPtr prop = drmModeGetProperty(drm_data->drm_fd, connector->props[i]);
+ if (!prop)
+ continue;
+ if (!strcmp(prop->name, "DPMS"))
+ {
+ output_data->dpms_prop_id = connector->props[i];
+ drmModeFreeProperty(prop);
+ break;
+ }
+ drmModeFreeProperty(prop);
+ }
+
+ output_data->count_modes = connector->count_modes;
+ output_data->drm_modes = calloc(connector->count_modes, sizeof(drmModeModeInfo));
+ if (!output_data->drm_modes)
+ {
+ TDM_ERR("alloc failed");
+ free(output_data);
+ drmModeFreeConnector(connector);
+ drmModeFreeEncoder(encoder);
+ ret = TDM_ERROR_OUT_OF_MEMORY;
+ goto failed_create;
+ }
+ output_data->output_modes = calloc(connector->count_modes, sizeof(tdm_output_mode));
+ if (!output_data->output_modes)
+ {
+ TDM_ERR("alloc failed");
+ free(output_data);
+ free(output_data->drm_modes);
+ drmModeFreeConnector(connector);
+ drmModeFreeEncoder(encoder);
+ ret = TDM_ERROR_OUT_OF_MEMORY;
+ goto failed_create;
+ }
+ for (j = 0; j < connector->count_modes; j++)
+ {
+ output_data->drm_modes[j] = connector->modes[j];
+ _tdm_drm_display_to_tdm_mode(&output_data->drm_modes[j], &output_data->output_modes[j]);
+ }
+
+ LIST_ADDTAIL(&output_data->link, &drm_data->output_list);
+
+ TDM_DBG("output_data(%p) connector_id(%d:%d:%d-%d) encoder_id(%d) crtc_id(%d) pipe(%d) dpms_id(%d)",
+ output_data, output_data->connector_id, output_data->status, output_data->connector_type,
+ output_data->connector_type_id, output_data->encoder_id, output_data->crtc_id,
+ output_data->pipe, output_data->dpms_prop_id);
+
+ drmModeFreeEncoder(encoder);
+ drmModeFreeConnector(connector);
+ }
+
+ TDM_DBG("output count: %d", drm_data->mode_res->count_connectors);
+
+ return TDM_ERROR_NONE;
+failed_create:
+ tdm_drm_display_destroy_output_list(drm_data);
+ return ret;
+}
+
+tdm_error
+drm_display_get_capabilitiy(tdm_backend_data *bdata, tdm_caps_display *caps)
+{
+ RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
+
+ caps->max_layer_count = -1; /* not defined */
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_output**
+drm_display_get_outputs(tdm_backend_data *bdata, int *count, tdm_error *error)
+{
+ tdm_drm_data *drm_data = bdata;
+ tdm_drm_output_data *output_data;
+ tdm_output **outputs;
+ tdm_error ret;
+ int i;
+
+ RETURN_VAL_IF_FAIL(drm_data, NULL);
+ RETURN_VAL_IF_FAIL(count, NULL);
+
+ *count = 0;
+ LIST_FOR_EACH_ENTRY(output_data, &drm_data->output_list, link)
+ (*count)++;
+
+ if (*count == 0)
+ {
+ ret = TDM_ERROR_NONE;
+ goto failed_get;
+ }
+
+ /* will be freed in frontend */
+ outputs = calloc(*count, sizeof(tdm_drm_output_data*));
+ if (!outputs)
+ {
+ TDM_ERR("failed: alloc memory");
+ *count = 0;
+ ret = TDM_ERROR_OUT_OF_MEMORY;
+ goto failed_get;
+ }
+
+ i = 0;
+ LIST_FOR_EACH_ENTRY(output_data, &drm_data->output_list, link)
+ outputs[i++] = output_data;
+
+ if (error)
+ *error = TDM_ERROR_NONE;
+
+ return outputs;
+failed_get:
+ if (error)
+ *error = ret;
+ return NULL;
+}
+
+tdm_error
+drm_display_get_fd(tdm_backend_data *bdata, int *fd)
+{
+ tdm_drm_data *drm_data = bdata;
+
+ RETURN_VAL_IF_FAIL(drm_data, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(fd, TDM_ERROR_INVALID_PARAMETER);
+
+ *fd = drm_data->drm_fd;
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+drm_display_handle_events(tdm_backend_data *bdata)
+{
+ tdm_drm_data *drm_data = bdata;
+ Drm_Event_Context ctx;
+
+ RETURN_VAL_IF_FAIL(drm_data, TDM_ERROR_INVALID_PARAMETER);
+
+ memset(&ctx, 0, sizeof(Drm_Event_Context));
+
+ ctx.vblank_handler = _tdm_drm_display_cb_vblank;
+
+ _tdm_drm_display_events_handle(drm_data->drm_fd, &ctx);
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+drm_output_get_capability(tdm_output *output, tdm_caps_output *caps)
+{
+ tdm_drm_output_data *output_data = output;
+ tdm_drm_data *drm_data;
+ drmModeConnectorPtr connector = NULL;
+ drmModeCrtcPtr crtc = NULL;
+ drmModeObjectPropertiesPtr props = NULL;
+ int i;
+ tdm_error ret;
+
+ RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
+
+ memset(caps, 0, sizeof(tdm_caps_output));
+
+ drm_data = output_data->drm_data;
+
+ caps->status = output_data->status;
+ caps->type = output_data->connector_type;
+ caps->type_id = output_data->connector_type_id;
+
+ connector = drmModeGetConnector(drm_data->drm_fd, output_data->connector_id);
+ RETURN_VAL_IF_FAIL(connector, TDM_ERROR_OPERATION_FAILED);
+
+ caps->mode_count = connector->count_modes;
+ caps->modes = calloc(1, sizeof(tdm_output_mode) * caps->mode_count);
+ if (!caps->modes)
+ {
+ ret = TDM_ERROR_OUT_OF_MEMORY;
+ TDM_ERR("alloc failed\n");
+ goto failed_get;
+ }
+ for (i = 0; i < caps->mode_count; i++)
+ caps->modes[i] = output_data->output_modes[i];
+
+ caps->mmWidth = connector->mmWidth;
+ caps->mmHeight = connector->mmHeight;
+ caps->subpixel = connector->subpixel;
+
+ caps->min_w = drm_data->mode_res->min_width;
+ caps->min_h = drm_data->mode_res->min_height;
+ caps->max_w = drm_data->mode_res->max_width;
+ caps->max_h = drm_data->mode_res->max_height;
+ caps->preferred_align = -1;
+
+ crtc = drmModeGetCrtc(drm_data->drm_fd, output_data->crtc_id);
+ if (!crtc)
+ {
+ ret = TDM_ERROR_OPERATION_FAILED;
+ TDM_ERR("get crtc failed: %m\n");
+ goto failed_get;
+ }
+
+ props = drmModeObjectGetProperties(drm_data->drm_fd, output_data->crtc_id, DRM_MODE_OBJECT_CRTC);
+ if (!props)
+ {
+ ret = TDM_ERROR_OPERATION_FAILED;
+ TDM_ERR("get crtc properties failed: %m\n");
+ goto failed_get;
+ }
+
+ caps->prop_count = props->count_props;
+ caps->props = calloc(1, sizeof(tdm_prop) * caps->prop_count);
+ if (!caps->props)
+ {
+ ret = TDM_ERROR_OUT_OF_MEMORY;
+ TDM_ERR("alloc failed\n");
+ goto failed_get;
+ }
+
+ for (i = 0; i < caps->prop_count; i++)
+ {
+ drmModePropertyPtr prop = drmModeGetProperty(drm_data->drm_fd, props->props[i]);
+ if (!prop)
+ continue;
+ snprintf(caps->props[i].name, TDM_NAME_LEN, "%s", prop->name);
+ caps->props[i].id = props->props[i];
+ drmModeFreeProperty(prop);
+ }
+
+ drmModeFreeObjectProperties(props);
+ drmModeFreeCrtc(crtc);
+ drmModeFreeConnector(connector);
+
+ return TDM_ERROR_NONE;
+failed_get:
+ drmModeFreeCrtc(crtc);
+ drmModeFreeObjectProperties(props);
+ drmModeFreeConnector(connector);
+ free(caps->modes);
+ free(caps->props);
+ memset(caps, 0, sizeof(tdm_caps_output));
+ return ret;
+}
+
+tdm_layer**
+drm_output_get_layers(tdm_output *output, int *count, tdm_error *error)
+{
+ tdm_drm_output_data *output_data = output;
+ tdm_drm_layer_data *layer_data;
+ tdm_layer **layers;
+ tdm_error ret;
+ int i;
+
+ RETURN_VAL_IF_FAIL(output_data, NULL);
+ RETURN_VAL_IF_FAIL(count, NULL);
+
+ *count = 0;
+ LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link)
+ (*count)++;
+
+ if (*count == 0)
+ {
+ ret = TDM_ERROR_NONE;
+ goto failed_get;
+ }
+
+ /* will be freed in frontend */
+ layers = calloc(*count, sizeof(tdm_drm_layer_data*));
+ if (!layers)
+ {
+ TDM_ERR("failed: alloc memory");
+ *count = 0;
+ ret = TDM_ERROR_OUT_OF_MEMORY;
+ goto failed_get;
+ }
+
+ i = 0;
+ LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link)
+ layers[i++] = layer_data;
+
+ if (error)
+ *error = TDM_ERROR_NONE;
+
+ return layers;
+failed_get:
+ if (error)
+ *error = ret;
+ return NULL;
+}
+
+tdm_error
+drm_output_set_property(tdm_output *output, unsigned int id, tdm_value value)
+{
+ tdm_drm_output_data *output_data = output;
+ tdm_drm_data *drm_data;
+ int ret;
+
+ RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(output_data->crtc_id > 0, TDM_ERROR_INVALID_PARAMETER);
+
+ drm_data = output_data->drm_data;
+ ret = drmModeObjectSetProperty(drm_data->drm_fd,
+ output_data->crtc_id, DRM_MODE_OBJECT_CRTC,
+ id, value.u32);
+ if (ret < 0)
+ {
+ TDM_ERR("set property failed: %m");
+ return TDM_ERROR_OPERATION_FAILED;
+ }
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+drm_output_get_property(tdm_output *output, unsigned int id, tdm_value *value)
+{
+ tdm_drm_output_data *output_data = output;
+ tdm_drm_data *drm_data;
+ drmModeObjectPropertiesPtr props;
+ int i;
+
+ RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(output_data->crtc_id > 0, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(value, TDM_ERROR_INVALID_PARAMETER);
+
+ drm_data = output_data->drm_data;
+ props = drmModeObjectGetProperties(drm_data->drm_fd, output_data->crtc_id, DRM_MODE_OBJECT_CRTC);
+ if (props == NULL)
+ {
+ TDM_ERR("get property failed: %m");
+ return TDM_ERROR_OPERATION_FAILED;
+ }
+
+ for (i = 0; i < props->count_props; i++)
+ if (props->props[i] == id)
+ {
+ (*value).u32 = (uint)props->prop_values[i];
+ break;
+ }
+
+ drmModeFreeObjectProperties(props);
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+drm_output_wait_vblank(tdm_output *output, int interval, int sync, void *user_data)
+{
+ tdm_drm_output_data *output_data = output;
+ tdm_drm_data *drm_data;
+ tdm_drm_vblank_data *vblank_data;
+ uint target_msc;
+ tdm_error ret;
+
+ RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
+
+ vblank_data = calloc(1, sizeof(tdm_drm_vblank_data));
+ if (!vblank_data)
+ {
+ TDM_ERR("alloc failed");
+ return TDM_ERROR_OUT_OF_MEMORY;
+ }
+
+ drm_data = output_data->drm_data;
+
+ ret = _tdm_drm_display_get_cur_msc(drm_data->drm_fd, output_data->pipe, &target_msc);
+ if (ret != TDM_ERROR_NONE)
+ goto failed_vblank;
+
+ target_msc++;
+
+ vblank_data->type = VBLANK_TYPE_WAIT;
+ vblank_data->output_data = output_data;
+ vblank_data->user_data = user_data;
+
+ ret = _tdm_drm_display_wait_vblank(drm_data->drm_fd, output_data->pipe, &target_msc, vblank_data);
+ if (ret != TDM_ERROR_NONE)
+ goto failed_vblank;
+
+ return TDM_ERROR_NONE;
+failed_vblank:
+ free(vblank_data);
+ return ret;
+}
+
+tdm_error
+drm_output_set_vblank_handler(tdm_output *output, tdm_output_vblank_handler func)
+{
+ tdm_drm_output_data *output_data = output;
+
+ RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
+
+ output_data->vblank_func = func;
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+drm_output_commit(tdm_output *output, int sync, void *user_data)
+{
+ tdm_drm_output_data *output_data = output;
+ tdm_drm_data *drm_data;
+ tdm_drm_layer_data *layer_data;
+ tdm_error ret;
+
+ RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
+
+ drm_data = output_data->drm_data;
+
+ LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link)
+ {
+ if (layer_data == output_data->primary_layer)
+ {
+ ret = _tdm_drm_display_commit_primary_layer(layer_data);
+ if (ret != TDM_ERROR_NONE)
+ return ret;
+ }
+ else
+ {
+ ret = _tdm_drm_display_commit_layer(layer_data);
+ if (ret != TDM_ERROR_NONE)
+ return ret;
+ }
+ }
+
+ if (tdm_helper_drm_fd == -1)
+ {
+ tdm_drm_vblank_data *vblank_data = calloc(1, sizeof(tdm_drm_vblank_data));
+ uint target_msc;
+
+ if (!vblank_data)
+ {
+ TDM_ERR("alloc failed");
+ return TDM_ERROR_OUT_OF_MEMORY;
+ }
+
+ ret = _tdm_drm_display_get_cur_msc(drm_data->drm_fd, output_data->pipe, &target_msc);
+ if (ret != TDM_ERROR_NONE)
+ {
+ free(vblank_data);
+ return ret;
+ }
+
+ target_msc++;
+
+ vblank_data->type = VBLANK_TYPE_COMMIT;
+ vblank_data->output_data = output_data;
+ vblank_data->user_data = user_data;
+
+ ret = _tdm_drm_display_wait_vblank(drm_data->drm_fd, output_data->pipe, &target_msc, vblank_data);
+ if (ret != TDM_ERROR_NONE)
+ {
+ free(vblank_data);
+ return ret;
+ }
+ }
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+drm_output_set_commit_handler(tdm_output *output, tdm_output_commit_handler func)
+{
+ tdm_drm_output_data *output_data = output;
+
+ RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
+
+ output_data->commit_func = func;
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+drm_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value)
+{
+ tdm_drm_output_data *output_data = output;
+ tdm_drm_data *drm_data;
+ int ret;
+
+ RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
+
+ drm_data = output_data->drm_data;
+ ret = drmModeObjectSetProperty(drm_data->drm_fd,
+ output_data->connector_id, DRM_MODE_OBJECT_CONNECTOR,
+ output_data->dpms_prop_id, dpms_value);
+ if (ret < 0)
+ {
+ TDM_ERR("set dpms failed: %m");
+ return TDM_ERROR_OPERATION_FAILED;
+ }
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+drm_output_get_dpms(tdm_output *output, tdm_output_dpms *dpms_value)
+{
+ tdm_drm_output_data *output_data = output;
+ tdm_drm_data *drm_data;
+ drmModeObjectPropertiesPtr props;
+ int i;
+
+ RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(dpms_value, TDM_ERROR_INVALID_PARAMETER);
+
+ drm_data = output_data->drm_data;
+ props = drmModeObjectGetProperties(drm_data->drm_fd, output_data->connector_id, DRM_MODE_OBJECT_CONNECTOR);
+ if (props == NULL)
+ {
+ TDM_ERR("get property failed: %m");
+ return TDM_ERROR_OPERATION_FAILED;
+ }
+
+ for (i = 0; i < props->count_props; i++)
+ if (props->props[i] == output_data->dpms_prop_id)
+ {
+ *dpms_value = (uint)props->prop_values[i];
+ break;
+ }
+
+ drmModeFreeObjectProperties(props);
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+drm_output_set_mode(tdm_output *output, tdm_output_mode *mode)
+{
+ tdm_drm_output_data *output_data = output;
+
+ RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
+
+ output_data->current_mode = mode;
+ output_data->mode_changed = 1;
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+drm_output_get_mode(tdm_output *output, const tdm_output_mode **mode)
+{
+ tdm_drm_output_data *output_data = output;
+
+ RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
+
+ *mode = output_data->current_mode;
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+drm_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps)
+{
+ tdm_drm_layer_data *layer_data = layer;
+ tdm_drm_data *drm_data;
+ drmModePlanePtr plane = NULL;
+ drmModeObjectPropertiesPtr props = NULL;
+ int i;
+ tdm_error ret;
+
+ RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
+
+ memset(caps, 0, sizeof(tdm_caps_layer));
+
+ drm_data = layer_data->drm_data;
+ plane = drmModeGetPlane(drm_data->drm_fd, layer_data->plane_id);
+ if (!plane)
+ {
+ TDM_ERR("get plane failed: %m");
+ ret = TDM_ERROR_OPERATION_FAILED;
+ goto failed_get;
+ }
+
+ caps->capabilities = layer_data->capabilities;
+ caps->zpos = layer_data->zpos; /* if VIDEO layer, zpos is -1 */
+
+ caps->format_count = plane->count_formats;
+ caps->formats = calloc(1, sizeof(tbm_format) * caps->format_count);
+ if (!caps->formats)
+ {
+ ret = TDM_ERROR_OUT_OF_MEMORY;
+ TDM_ERR("alloc failed\n");
+ goto failed_get;
+ }
+
+ for (i = 0; i < caps->format_count; i++)
+ {
+ /* TODO: kernel reports wrong formats */
+ if (plane->formats[i] != DRM_FORMAT_XRGB8888 && plane->formats[i] != DRM_FORMAT_ARGB8888)
+ continue;
+ caps->formats[i] = tdm_drm_format_to_tbm_format(plane->formats[i]);
+ }
+
+ props = drmModeObjectGetProperties(drm_data->drm_fd, layer_data->plane_id, DRM_MODE_OBJECT_PLANE);
+ if (!props)
+ {
+ ret = TDM_ERROR_OPERATION_FAILED;
+ TDM_ERR("get plane properties failed: %m\n");
+ goto failed_get;
+ }
+
+ caps->props = calloc(1, sizeof(tdm_prop) * props->count_props);
+ if (!caps->props)
+ {
+ ret = TDM_ERROR_OUT_OF_MEMORY;
+ TDM_ERR("alloc failed\n");
+ goto failed_get;
+ }
+
+ caps->prop_count = 0;
+ for (i = 0; i < props->count_props; i++)
+ {
+ drmModePropertyPtr prop = drmModeGetProperty(drm_data->drm_fd, props->props[i]);
+ if (!prop)
+ continue;
+ if (!strncmp(prop->name, "type", TDM_NAME_LEN))
+ continue;
+ if (!strncmp(prop->name, "zpos", TDM_NAME_LEN))
+ continue;
+ snprintf(caps->props[i].name, TDM_NAME_LEN, "%s", prop->name);
+ caps->props[i].id = props->props[i];
+ caps->prop_count++;
+ drmModeFreeProperty(prop);
+ }
+
+ drmModeFreeObjectProperties(props);
+ drmModeFreePlane(plane);
+
+ return TDM_ERROR_NONE;
+failed_get:
+ drmModeFreeObjectProperties(props);
+ drmModeFreePlane(plane);
+ free(caps->formats);
+ free(caps->props);
+ memset(caps, 0, sizeof(tdm_caps_layer));
+ return ret;
+}
+
+tdm_error
+drm_layer_set_property(tdm_layer *layer, unsigned int id, tdm_value value)
+{
+ tdm_drm_layer_data *layer_data = layer;
+ tdm_drm_data *drm_data;
+ int ret;
+
+ RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(layer_data->plane_id > 0, TDM_ERROR_INVALID_PARAMETER);
+
+ drm_data = layer_data->drm_data;
+ ret = drmModeObjectSetProperty(drm_data->drm_fd,
+ layer_data->plane_id, DRM_MODE_OBJECT_PLANE,
+ id, value.u32);
+ if (ret < 0)
+ {
+ TDM_ERR("set property failed: %m");
+ return TDM_ERROR_OPERATION_FAILED;
+ }
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+drm_layer_get_property(tdm_layer *layer, unsigned int id, tdm_value *value)
+{
+ tdm_drm_layer_data *layer_data = layer;
+ tdm_drm_data *drm_data;
+ drmModeObjectPropertiesPtr props;
+ int i;
+
+ RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(layer_data->plane_id > 0, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(value, TDM_ERROR_INVALID_PARAMETER);
+
+ drm_data = layer_data->drm_data;
+ props = drmModeObjectGetProperties(drm_data->drm_fd, layer_data->plane_id,
+ DRM_MODE_OBJECT_PLANE);
+ if (props == NULL)
+ {
+ TDM_ERR("get property failed: %m");
+ return TDM_ERROR_OPERATION_FAILED;
+ }
+
+ for (i = 0; i < props->count_props; i++)
+ if (props->props[i] == id)
+ {
+ (*value).u32 = (uint)props->prop_values[i];
+ break;
+ }
+
+ drmModeFreeObjectProperties(props);
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+drm_layer_set_info(tdm_layer *layer, tdm_info_layer *info)
+{
+ tdm_drm_layer_data *layer_data = layer;
+
+ RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
+
+ layer_data->info = *info;
+ layer_data->info_changed = 1;
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+drm_layer_get_info(tdm_layer *layer, tdm_info_layer *info)
+{
+ tdm_drm_layer_data *layer_data = layer;
+
+ RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
+
+ *info = layer_data->info;
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+drm_layer_set_buffer(tdm_layer *layer, tdm_buffer *buffer)
+{
+ tdm_drm_layer_data *layer_data = layer;
+ tdm_drm_data *drm_data;
+ tdm_drm_display_buffer *display_buffer;
+ tdm_error err = TDM_ERROR_NONE;
+ tbm_surface_h surface;
+ int ret, i, count;
+
+ RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
+ RETURN_VAL_IF_FAIL(buffer, TDM_ERROR_INVALID_PARAMETER);
+
+ drm_data = layer_data->drm_data;
+ surface = tdm_buffer_get_surface(buffer);
+
+ display_buffer = _tdm_drm_display_find_buffer(drm_data, buffer);
+ if (!display_buffer)
+ {
+ display_buffer = calloc(1, sizeof(tdm_drm_display_buffer));
+ if (!display_buffer)
+ {
+ TDM_ERR("alloc failed");
+ return TDM_ERROR_OUT_OF_MEMORY;
+ }
+ display_buffer->buffer = buffer;
+
+ err = tdm_buffer_add_destroy_handler(buffer, _tdm_drm_display_cb_destroy_buffer, drm_data);
+ if (err != TDM_ERROR_NONE)
+ {
+ TDM_ERR("add destroy handler fail");
+ return TDM_ERROR_OPERATION_FAILED;
+ }
+
+ LIST_ADDTAIL(&display_buffer->link, &drm_data->buffer_list);
+ }
+
+ if (display_buffer->fb_id == 0)
+ {
+ unsigned int width;
+ unsigned int height;
+ unsigned int format;
+ unsigned int handles[4] = {0,};
+ unsigned int pitches[4] = {0,};
+ unsigned int offsets[4] = {0,};
+ unsigned int size;
+
+ width = tbm_surface_get_width(surface);
+ height = tbm_surface_get_height(surface);
+ format = tbm_surface_get_format(surface);
+ count = tbm_surface_internal_get_num_bos(surface);
+ for (i = 0; i < count; i++)
+ {
+ tbm_bo bo = tbm_surface_internal_get_bo(surface, i);
+ handles[i] = tbm_bo_get_handle(bo, TBM_DEVICE_DEFAULT).u32;
+ }
+ count = tbm_surface_internal_get_num_planes(format);
+ for (i = 0; i < count; i++)
+ tbm_surface_internal_get_plane_data(surface, i, &size, &offsets[i], &pitches[i]);
+
+ ret = drmModeAddFB2(drm_data->drm_fd, width, height, format,
+ handles, pitches, offsets, &display_buffer->fb_id, 0);
+ if (ret < 0)
+ {
+ TDM_ERR("add fb failed: %m");
+ return TDM_ERROR_OPERATION_FAILED;
+ }
+ TDM_DBG("drm_data->drm_fd : %d, display_buffer->fb_id:%u", drm_data->drm_fd, display_buffer->fb_id);
+
+ if (IS_RGB(format))
+ display_buffer->width = pitches[0] >> 2;
+ else
+ display_buffer->width = pitches[0];
+ }
+
+ layer_data->display_buffer = display_buffer;
+ layer_data->display_buffer_changed = 1;
+
+ return TDM_ERROR_NONE;
+}
+
+tdm_error
+drm_layer_unset_buffer(tdm_layer *layer)
+{
+ tdm_drm_layer_data *layer_data = layer;
+
+ RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
+
+ layer_data->display_buffer = NULL;
+ layer_data->display_buffer_changed = 1;
+
+ return TDM_ERROR_NONE;
+}
diff --git a/src/tdm_drm_format.c b/src/tdm_drm_format.c
new file mode 100644
index 0000000..c85b1de
--- /dev/null
+++ b/src/tdm_drm_format.c
@@ -0,0 +1,106 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <drm_fourcc.h>
+#include <tbm_surface.h>
+
+#include "tdm_drm.h"
+
+typedef struct
+{
+ tbm_format tbm_format;
+ uint32_t drm_format;
+} tbm_drm_format_data;
+
+static const tbm_drm_format_data formats[] =
+{
+ {TBM_FORMAT_C8, DRM_FORMAT_C8},
+ {TBM_FORMAT_RGB332, DRM_FORMAT_RGB332},
+ {TBM_FORMAT_BGR233, DRM_FORMAT_BGR233},
+ {TBM_FORMAT_XRGB4444, DRM_FORMAT_XRGB4444},
+ {TBM_FORMAT_XBGR4444, DRM_FORMAT_XBGR4444},
+ {TBM_FORMAT_RGBX4444, DRM_FORMAT_RGBX4444},
+ {TBM_FORMAT_BGRX4444, DRM_FORMAT_BGRX4444},
+ {TBM_FORMAT_ARGB4444, DRM_FORMAT_ARGB4444},
+ {TBM_FORMAT_ABGR4444, DRM_FORMAT_ABGR4444},
+ {TBM_FORMAT_RGBA4444, DRM_FORMAT_RGBA4444},
+ {TBM_FORMAT_BGRA4444, DRM_FORMAT_BGRA4444},
+ {TBM_FORMAT_XRGB1555, DRM_FORMAT_XRGB1555},
+ {TBM_FORMAT_XBGR1555, DRM_FORMAT_XBGR1555},
+ {TBM_FORMAT_RGBX5551, DRM_FORMAT_RGBX5551},
+ {TBM_FORMAT_BGRX5551, DRM_FORMAT_BGRX5551},
+ {TBM_FORMAT_ARGB1555, DRM_FORMAT_ARGB1555},
+ {TBM_FORMAT_ABGR1555, DRM_FORMAT_ABGR1555},
+ {TBM_FORMAT_RGBA5551, DRM_FORMAT_RGBA5551},
+ {TBM_FORMAT_BGRA5551, DRM_FORMAT_BGRA5551},
+ {TBM_FORMAT_RGB565, DRM_FORMAT_RGB565},
+ {TBM_FORMAT_BGR565, DRM_FORMAT_BGR565},
+ {TBM_FORMAT_RGB888, DRM_FORMAT_RGB888},
+ {TBM_FORMAT_BGR888, DRM_FORMAT_BGR888},
+ {TBM_FORMAT_XRGB8888, DRM_FORMAT_XRGB8888},
+ {TBM_FORMAT_XBGR8888, DRM_FORMAT_XBGR8888},
+ {TBM_FORMAT_RGBX8888, DRM_FORMAT_RGBX8888},
+ {TBM_FORMAT_BGRX8888, DRM_FORMAT_BGRX8888},
+ {TBM_FORMAT_ARGB8888, DRM_FORMAT_ARGB8888},
+ {TBM_FORMAT_ABGR8888, DRM_FORMAT_ABGR8888},
+ {TBM_FORMAT_RGBA8888, DRM_FORMAT_RGBA8888},
+ {TBM_FORMAT_BGRA8888, DRM_FORMAT_BGRA8888},
+ {TBM_FORMAT_XRGB2101010, DRM_FORMAT_XRGB2101010},
+ {TBM_FORMAT_XBGR2101010, DRM_FORMAT_XBGR2101010},
+ {TBM_FORMAT_RGBX1010102, DRM_FORMAT_RGBX1010102},
+ {TBM_FORMAT_BGRX1010102, DRM_FORMAT_BGRX1010102},
+ {TBM_FORMAT_ARGB2101010, DRM_FORMAT_ARGB2101010},
+ {TBM_FORMAT_ABGR2101010, DRM_FORMAT_ABGR2101010},
+ {TBM_FORMAT_RGBA1010102, DRM_FORMAT_RGBA1010102},
+ {TBM_FORMAT_BGRA1010102, DRM_FORMAT_BGRA1010102},
+ {TBM_FORMAT_YUYV, DRM_FORMAT_YUYV},
+ {TBM_FORMAT_YVYU, DRM_FORMAT_YVYU},
+ {TBM_FORMAT_UYVY, DRM_FORMAT_UYVY},
+ {TBM_FORMAT_VYUY, DRM_FORMAT_VYUY},
+ {TBM_FORMAT_AYUV, DRM_FORMAT_AYUV},
+ {TBM_FORMAT_NV12, DRM_FORMAT_NV12},
+ {TBM_FORMAT_NV21, DRM_FORMAT_NV21},
+ {TBM_FORMAT_NV16, DRM_FORMAT_NV16},
+ {TBM_FORMAT_NV61, DRM_FORMAT_NV61},
+ {TBM_FORMAT_YUV410, DRM_FORMAT_YUV410},
+ {TBM_FORMAT_YVU410, DRM_FORMAT_YVU410},
+ {TBM_FORMAT_YUV411, DRM_FORMAT_YUV411},
+ {TBM_FORMAT_YVU411, DRM_FORMAT_YVU411},
+ {TBM_FORMAT_YUV420, DRM_FORMAT_YUV420},
+ {TBM_FORMAT_YVU420, DRM_FORMAT_YVU420},
+ {TBM_FORMAT_YUV422, DRM_FORMAT_YUV422},
+ {TBM_FORMAT_YVU422, DRM_FORMAT_YVU422},
+ {TBM_FORMAT_YUV444, DRM_FORMAT_YUV444},
+ {TBM_FORMAT_YVU444, DRM_FORMAT_YVU444},
+};
+
+#define NUM_FORMATS (sizeof(formats) / sizeof(formats[0]))
+
+uint32_t
+tdm_drm_format_to_drm_format(tbm_format format)
+{
+ int i;
+
+ for (i = 0; i < NUM_FORMATS; i++)
+ if (formats[i].tbm_format == format)
+ return formats[i].drm_format;
+
+ TDM_ERR("tbm format '%c%c%c%c' not found", FOURCC_STR(format));
+
+ return 0;
+}
+
+tbm_format
+tdm_drm_format_to_tbm_format(uint32_t format)
+{
+ int i;
+
+ for (i = 0; i < NUM_FORMATS; i++)
+ if (formats[i].drm_format == format)
+ return formats[i].tbm_format;
+
+ TDM_ERR("drm format '%c%c%c%c' not found", FOURCC_STR(format));
+
+ return 0;
+}