summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Michael <cpmichael@osg.samsung.com>2016-05-27 11:58:51 -0400
committerChris Michael <cpmichael@osg.samsung.com>2016-05-27 11:58:51 -0400
commit3c50101f73d0f53e6947eea4294f3b03fb2ad919 (patch)
treeaddf704c83a83cb032b4cb0f13fdde9d9ffd70e4
parent072674dbe2118a26d8616b56b4169a6e543805ef (diff)
parent09805d2b15a71a361ec4bf3154f797fe3314775d (diff)
downloadefl-3c50101f73d0f53e6947eea4294f3b03fb2ad919.tar.gz
Merge branch 'devs/devilhorns/ecore_drm2'
This new Ecore_Drm2 library is going to replace the existing Ecore_Drm. This will refactor a lot of the code, bring improvements over the existing API, and provide additional support for missing features such as atomic modeset, nuclear pageflip, and hardware planes support. @feature
-rw-r--r--Makefile.am4
-rw-r--r--configure.ac82
-rw-r--r--m4/efl.m43
-rw-r--r--m4/evas_check_engine.m413
-rw-r--r--pc/.gitignore1
-rw-r--r--pc/ecore-drm2.pc.in12
-rw-r--r--src/Makefile.am3
-rw-r--r--src/Makefile_Ecore_Drm2.am28
-rw-r--r--src/Makefile_Ecore_Evas.am14
-rw-r--r--src/Makefile_Evas.am14
-rw-r--r--src/lib/ecore_drm2/Ecore_Drm2.h771
-rw-r--r--src/lib/ecore_drm2/ecore_drm2.c83
-rw-r--r--src/lib/ecore_drm2/ecore_drm2_device.c315
-rw-r--r--src/lib/ecore_drm2/ecore_drm2_fb.c265
-rw-r--r--src/lib/ecore_drm2/ecore_drm2_outputs.c1155
-rw-r--r--src/lib/ecore_drm2/ecore_drm2_private.h185
-rw-r--r--src/lib/elementary/elm_priv.h2
-rw-r--r--src/modules/ecore_evas/engines/drm/ecore_evas_drm.c1258
-rw-r--r--src/modules/evas/engines/drm/Evas_Engine_Drm.h21
-rw-r--r--src/modules/evas/engines/drm/evas_engine.c102
-rw-r--r--src/modules/evas/engines/drm/evas_engine.h56
-rw-r--r--src/modules/evas/engines/drm/evas_outbuf.c501
-rw-r--r--src/modules/evas/engines/gl_drm/Evas_Engine_GL_Drm.h6
-rw-r--r--src/modules/evas/engines/gl_drm/evas_engine.c70
-rw-r--r--src/modules/evas/engines/gl_drm/evas_engine.h24
-rw-r--r--src/modules/evas/engines/gl_drm/evas_outbuf.c197
26 files changed, 4118 insertions, 1067 deletions
diff --git a/Makefile.am b/Makefile.am
index 564f332993..1efae6ed10 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -290,6 +290,10 @@ if HAVE_ELPUT
pkgconfig_DATA += pc/elput.pc
endif
+if HAVE_ECORE_DRM2
+pkgconfig_DATA += pc/ecore-drm2.pc
+endif
+
# Cmake configs:
efl_cmakeconfigdir = $(libdir)/cmake/Efl/
efl_cmakeconfig_DATA = \
diff --git a/configure.ac b/configure.ac
index cae4e39594..ff5c2ad188 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2085,19 +2085,32 @@ if test "x${have_cocoa}" = "xyes"; then
fi
AC_SUBST(cocoa_coreservices_ldflags)
+AC_ARG_ENABLE([elput],
+ [AS_HELP_STRING([--enable-elput],[enable elput library. @<:@default=disabled@:>@])],
+ [
+ if test "x${enableval}" = "xyes" ; then
+ want_elput="yes"
+ else
+ want_elput="no"
+ fi
+ ],
+ [want_elput="no"])
+
# Drm
AC_ARG_ENABLE([drm],
[AS_HELP_STRING([--enable-drm],[enable drm engine. @<:@default=disabled@:>@])],
[
if test "x${enableval}" = "xyes" ; then
- want_drm="yes"
+ if test "x${want_elput}" != "xyes" ; then
+ AC_MSG_ERROR([elput is required to build drm support])
+ fi
+ want_drm="yes"
else
want_drm="no"
fi
],
[want_drm="no"])
-
AC_ARG_ENABLE([gl-drm],
[AC_HELP_STRING([--enable-gl-drm],
[enable gl drm engine. @<:@default=disabled@:>@])],
@@ -2296,17 +2309,6 @@ AC_ARG_ENABLE([ecore-buffer],
],
[want_ecore_buffer="no"])
-AC_ARG_ENABLE([elput],
- [AS_HELP_STRING([--enable-elput],[enable elput library. @<:@default=disabled@:>@])],
- [
- if test "x${enableval}" = "xyes" ; then
- want_elput="yes"
- else
- want_elput="no"
- fi
- ],
- [want_elput="no"])
-
# Image Loaders
ARG_ENABLE_EVAS_IMAGE_LOADER(BMP, static)
@@ -3633,7 +3635,52 @@ EFL_EVAL_PKGS([ELPUT])
### Checks for library functions
EFL_LIB_END_OPTIONAL([Elput])
-#### End of Ecore_Drm
+#### End of Elput
+
+#### Ecore_Drm2
+have_libinput_new="no"
+EFL_LIB_START_OPTIONAL([Ecore_Drm2], [test "${want_drm}" = "yes"])
+
+### Additional options to configure
+SUID_CFLAGS=-fPIE
+SUID_LDFLAGS=-pie
+AC_SUBST([SUID_CFLAGS])
+AC_SUBST([SUID_LDFLAGS])
+
+### Default values
+
+### Checks for programs
+
+### Checks for libraries
+EFL_INTERNAL_DEPEND_PKG([ECORE_DRM2], [eo])
+EFL_INTERNAL_DEPEND_PKG([ECORE_DRM2], [efl])
+EFL_INTERNAL_DEPEND_PKG([ECORE_DRM2], [eina])
+EFL_INTERNAL_DEPEND_PKG([ECORE_DRM2], [ecore])
+EFL_INTERNAL_DEPEND_PKG([ECORE_DRM2], [elput])
+EFL_INTERNAL_DEPEND_PKG([ECORE_DRM2], [eeze])
+
+EFL_DEPEND_PKG([ECORE_DRM2], [DRM], [libdrm >= 2.4 gbm])
+
+EFL_ADD_LIBS([ECORE_DRM2], [-lm])
+
+AC_CHECK_LIB(drm, drmModeAtomicCommit, AC_DEFINE(HAVE_ATOMIC_DRM, [], [Atomic modeset supported]))
+
+EFL_EVAL_PKGS([ECORE_DRM2])
+
+### Checks for header files
+
+### Checks for types
+
+### Checks for structures
+
+### Checks for compiler characteristics
+
+### Checks for linker characteristics
+
+### Checks for library functions
+
+EFL_LIB_END_OPTIONAL([Ecore_Drm2])
+#### End of Ecore_Drm2
#### Ecore_Audio
@@ -4357,9 +4404,9 @@ ECORE_EVAS_MODULE([extn], [${want_ecore_evas_extn}])
ECORE_EVAS_MODULE([ews], [yes])
ECORE_EVAS_MODULE([fb], [${want_fb}])
ECORE_EVAS_MODULE([drm], [${want_drm}],
- [EFL_OPTIONAL_INTERNAL_DEPEND_PKG([ECORE_EVAS], [${want_drm}], [ecore-drm])])
+ [EFL_OPTIONAL_INTERNAL_DEPEND_PKG([ECORE_EVAS], [${want_drm}], [ecore-drm2])])
ECORE_EVAS_MODULE([gl-drm], [${want_gl_drm}],
- [EFL_OPTIONAL_INTERNAL_DEPEND_PKG([ECORE_EVAS], [${want_gl_drm}], [ecore-drm])])
+ [EFL_OPTIONAL_INTERNAL_DEPEND_PKG([ECORE_EVAS], [${want_gl_drm}], [ecore-drm2])])
ECORE_EVAS_MODULE([psl1ght], [${have_ps3}])
ECORE_EVAS_MODULE([opengl-cocoa], [${want_ecore_evas_gl_cocoa}])
@@ -5260,7 +5307,7 @@ EFL_OPTIONAL_INTERNAL_DEPEND_PKG([ELEMENTARY], [${have_ps3}], [ecore_psl1ght])
EFL_OPTIONAL_INTERNAL_DEPEND_PKG([ELEMENTARY], [${want_sdl}], [ecore_sdl])
EFL_OPTIONAL_INTERNAL_DEPEND_PKG([ELEMENTARY], [${want_ecore_evas_gl_cocoa}], [ecore_cocoa])
EFL_OPTIONAL_INTERNAL_DEPEND_PKG([ELEMENTARY], [${build_ecore_evas_win32}], [ecore_win32])
-EFL_OPTIONAL_INTERNAL_DEPEND_PKG([ELEMENTARY], [${want_drm}], [ecore_drm])
+EFL_OPTIONAL_INTERNAL_DEPEND_PKG([ELEMENTARY], [${want_drm}], [ecore_drm2])
EFL_OPTIONAL_INTERNAL_DEPEND_PKG([ELEMENTARY], [${build_ecore_evas_wayland}], [ecore_wl2])
dnl Special case deps for ecore_drm
@@ -5605,6 +5652,7 @@ pc/elua.pc
pc/elementary.pc
pc/elementary-cxx.pc
pc/elput.pc
+pc/ecore-drm2.pc
dbus-services/org.enlightenment.Ethumb.service
systemd-services/ethumb.service
$po_makefile_in
diff --git a/m4/efl.m4 b/m4/efl.m4
index c9e15f3537..f1694c58d5 100644
--- a/m4/efl.m4
+++ b/m4/efl.m4
@@ -174,6 +174,9 @@ case "m4_defn([DOWNOTHER])" in
ecore_win32)
depname="ecore-win32"
;;
+ ecore_drm2)
+ depname="ecore-drm2"
+ ;;
esac
requirements_pc_[]m4_defn([DOWNEFL])="${depname} >= ${PACKAGE_VERSION} ${requirements_pc_[][]m4_defn([DOWNEFL])}"
requirements_cflags_[]m4_defn([DOWNEFL])="-I\$(top_srcdir)/src/lib/${libdirname} -I\$(top_builddir)/src/lib/${libdirname} ${requirements_cflags_[][]m4_defn([DOWNEFL])}"
diff --git a/m4/evas_check_engine.m4 b/m4/evas_check_engine.m4
index 448a210592..4789d4b9f0 100644
--- a/m4/evas_check_engine.m4
+++ b/m4/evas_check_engine.m4
@@ -597,16 +597,23 @@ AC_DEFUN([EVAS_CHECK_ENGINE_DEP_DRM],
[
requirement=""
-have_dep="yes"
+have_dep="no"
have_hw_dep="no"
evas_engine_[]$1[]_cflags=""
evas_engine_[]$1[]_libs=""
+PKG_CHECK_EXISTS([libdrm],
+ [
+ have_dep="yes"
+ requirement="libdrm"
+ ], [have_dep="no"])
+
if test "x${have_dep}" = "xyes" ; then
if test "x$3" = "xstatic" ; then
requirements_pc_evas="${requirement} ${requirements_pc_evas}"
requirements_pc_deps_evas="${requirement} ${requirements_pc_deps_evas}"
else
+ PKG_CHECK_MODULES([DRM], [${requirement}])
evas_engine_[]$1[]_cflags="${DRM_CFLAGS}"
evas_engine_[]$1[]_libs="${DRM_LIBS}"
fi
@@ -636,10 +643,10 @@ else
AC_MSG_ERROR([We currently do not support GL DRM without OpenGL ES. Please consider OpenGL ES if you want to use it.])
fi
-PKG_CHECK_EXISTS([egl ${gl_library} gbm wayland-client >= REQUIRED_WAYLAND_VERSION],
+PKG_CHECK_EXISTS([egl ${gl_library} libdrm gbm wayland-client >= REQUIRED_WAYLAND_VERSION],
[
have_dep="yes"
- requirement="egl ${gl_library} gbm wayland-client >= REQUIRED_WAYLAND_VERSION"
+ requirement="egl ${gl_library} libdrm gbm wayland-client >= REQUIRED_WAYLAND_VERSION"
],
[have_dep="no"])
diff --git a/pc/.gitignore b/pc/.gitignore
index f66395b99d..893e9373c9 100644
--- a/pc/.gitignore
+++ b/pc/.gitignore
@@ -74,3 +74,4 @@
/efl-js.pc
/elementary-cxx.pc
/elput.pc
+/ecore-drm2.pc
diff --git a/pc/ecore-drm2.pc.in b/pc/ecore-drm2.pc.in
new file mode 100644
index 0000000000..4530eacab4
--- /dev/null
+++ b/pc/ecore-drm2.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: ecore-drm2
+Description: E core library, DRM module
+Requires.private: @requirements_pc_ecore_drm2@
+Version: @VERSION@
+Libs: -L${libdir} -lecore_drm2
+Libs.private: @requirements_libs_ecore_drm2@
+Cflags: -I${includedir}/efl-@VMAJ@ -I${includedir}/ecore-drm2-@VMAJ@
diff --git a/src/Makefile.am b/src/Makefile.am
index af019a7bc1..523f411037 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -54,7 +54,9 @@ include Makefile_Ecore_IMF.am
include Makefile_Ecore_IMF_Evas.am
include Makefile_Eldbus.am
include Makefile_Eeze.am
+include Makefile_Elput.am
include Makefile_Ecore_Drm.am
+include Makefile_Ecore_Drm2.am
include Makefile_Ecore_Evas.am
include Makefile_Ecore_Audio.am
include Makefile_Ecore_Avahi.am
@@ -69,7 +71,6 @@ include Makefile_Ethumb.am
include Makefile_Ethumb_Client.am
include Makefile_Elocation.am
include Makefile_Elementary.am
-include Makefile_Elput.am
include Makefile_Cxx.am
include Makefile_Eolian_Cxx.am
diff --git a/src/Makefile_Ecore_Drm2.am b/src/Makefile_Ecore_Drm2.am
new file mode 100644
index 0000000000..1c328e33de
--- /dev/null
+++ b/src/Makefile_Ecore_Drm2.am
@@ -0,0 +1,28 @@
+if HAVE_ECORE_DRM2
+
+### Library
+
+lib_LTLIBRARIES += lib/ecore_drm2/libecore_drm2.la
+
+installed_ecoredrm2mainheadersdir = $(includedir)/ecore-drm2-@VMAJ@
+dist_installed_ecoredrm2mainheaders_DATA = \
+ lib/ecore_drm2/Ecore_Drm2.h
+
+lib_ecore_drm2_libecore_drm2_la_SOURCES = \
+lib/ecore_drm2/ecore_drm2_fb.c \
+lib/ecore_drm2/ecore_drm2_outputs.c \
+lib/ecore_drm2/ecore_drm2_device.c \
+lib/ecore_drm2/ecore_drm2.c \
+lib/ecore_drm2/ecore_drm2_private.h
+
+lib_ecore_drm2_libecore_drm2_la_CPPFLAGS = \
+ -I$(top_builddir)/src/lib/efl \
+ @ECORE_DRM2_CFLAGS@ @EFL_CFLAGS@ \
+ -DPACKAGE_LIB_DIR=\"$(libdir)\" \
+ -DMODULE_ARCH=\"$(MODULE_ARCH)\"
+
+lib_ecore_drm2_libecore_drm2_la_LIBADD = @ECORE_DRM2_LIBS@
+lib_ecore_drm2_libecore_drm2_la_DEPENDENCIES = @ECORE_DRM2_INTERNAL_LIBS@
+lib_ecore_drm2_libecore_drm2_la_LDFLAGS = @EFL_LTLIBRARY_FLAGS@
+
+endif
diff --git a/src/Makefile_Ecore_Evas.am b/src/Makefile_Ecore_Evas.am
index 12efc0b135..747a426b8a 100644
--- a/src/Makefile_Ecore_Evas.am
+++ b/src/Makefile_Ecore_Evas.am
@@ -269,13 +269,15 @@ $(install_ecoreevasenginedrmpkgLTLIBRARIES): install-libLTLIBRARIES
modules_ecore_evas_engines_drm_module_la_SOURCES = $(DRMSOURCES)
modules_ecore_evas_engines_drm_module_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
@ECORE_EVAS_CFLAGS@ \
-@ECORE_DRM_CFLAGS@ \
+@ECORE_DRM2_CFLAGS@ \
-I$(top_srcdir)/src/modules/evas/engines/drm \
--I$(top_srcdir)/src/modules/evas/engines/gl_drm \
-@ecore_evas_engines_gl_drm_cflags@
-modules_ecore_evas_engines_drm_module_la_LIBADD = @USE_ECORE_EVAS_LIBS@ \
-@ecore_evas_engines_gl_drm_libs@
-modules_ecore_evas_engines_drm_module_la_DEPENDENCIES = @USE_ECORE_EVAS_INTERNAL_LIBS@
+-I$(top_srcdir)/src/modules/evas/engines/gl_drm
+modules_ecore_evas_engines_drm_module_la_LIBADD = \
+@USE_ECORE_EVAS_LIBS@ \
+@USE_ECORE_DRM2_LIBS@
+modules_ecore_evas_engines_drm_module_la_DEPENDENCIES = \
+@USE_ECORE_EVAS_INTERNAL_LIBS@ \
+@USE_ECORE_DRM2_INTERNAL_LIBS@
modules_ecore_evas_engines_drm_module_la_LDFLAGS = -module @EFL_LTMODULE_FLAGS@
modules_ecore_evas_engines_drm_module_la_LIBTOOLFLAGS = --tag=disable-static
endif
diff --git a/src/Makefile_Evas.am b/src/Makefile_Evas.am
index daa11b8a86..19fea04991 100644
--- a/src/Makefile_Evas.am
+++ b/src/Makefile_Evas.am
@@ -1276,7 +1276,6 @@ endif
endif
if BUILD_ENGINE_DRM
-dist_installed_evasmainheaders_DATA += modules/evas/engines/drm/Evas_Engine_Drm.h
DRM_SOURCES = \
modules/evas/engines/drm/evas_outbuf.c \
modules/evas/engines/drm/evas_engine.c \
@@ -1301,20 +1300,19 @@ modules_evas_engines_drm_module_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
-I$(top_srcdir)/src/lib/evas/cserve2 \
-I$(top_srcdir)/src/modules/evas/engines/drm \
@EVAS_CFLAGS@ \
-@ECORE_DRM_CFLAGS@ \
+@ECORE_DRM2_CFLAGS@ \
@evas_engine_drm_cflags@
modules_evas_engines_drm_module_la_LIBADD = \
@USE_EVAS_LIBS@ \
-@USE_ECORE_DRM_LIBS@ \
+@USE_ECORE_DRM2_LIBS@ \
@evas_engine_drm_libs@
-modules_evas_engines_drm_module_la_DEPENDENCIES = @USE_EVAS_INTERNAL_LIBS@ @USE_ECORE_DRM_INTERNAL_LIBS@
+modules_evas_engines_drm_module_la_DEPENDENCIES = @USE_EVAS_INTERNAL_LIBS@ @USE_ECORE_DRM2_INTERNAL_LIBS@
modules_evas_engines_drm_module_la_LDFLAGS = -module @EFL_LTMODULE_FLAGS@
modules_evas_engines_drm_module_la_LIBTOOLFLAGS = --tag=disable-static
endif
endif
if BUILD_ENGINE_GL_DRM
-dist_installed_evasmainheaders_DATA += modules/evas/engines/gl_drm/Evas_Engine_GL_Drm.h
GL_DRM_SOURCES = \
modules/evas/engines/gl_drm/evas_outbuf.c \
modules/evas/engines/gl_drm/evas_engine.c \
@@ -1339,13 +1337,13 @@ modules_evas_engines_gl_drm_module_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
-I$(top_srcdir)/src/lib/evas/cserve2 \
-I$(top_srcdir)/src/modules/evas/engines/gl_drm \
@EVAS_CFLAGS@ \
-@ECORE_DRM_CFLAGS@ \
+@ECORE_DRM2_CFLAGS@ \
@evas_engine_gl_drm_cflags@
modules_evas_engines_gl_drm_module_la_LIBADD = \
@USE_EVAS_LIBS@ \
-@USE_ECORE_DRM_LIBS@ \
+@USE_ECORE_DRM2_LIBS@ \
@evas_engine_gl_drm_libs@
-modules_evas_engines_gl_drm_module_la_DEPENDENCIES = @USE_EVAS_INTERNAL_LIBS@ @USE_ECORE_DRM_INTERNAL_LIBS@
+modules_evas_engines_gl_drm_module_la_DEPENDENCIES = @USE_EVAS_INTERNAL_LIBS@ @USE_ECORE_DRM2_INTERNAL_LIBS@
modules_evas_engines_gl_drm_module_la_LDFLAGS = -module @EFL_LTMODULE_FLAGS@
modules_evas_engines_gl_drm_module_la_LIBTOOLFLAGS = --tag=disable-static
endif
diff --git a/src/lib/ecore_drm2/Ecore_Drm2.h b/src/lib/ecore_drm2/Ecore_Drm2.h
new file mode 100644
index 0000000000..fa2e916c76
--- /dev/null
+++ b/src/lib/ecore_drm2/Ecore_Drm2.h
@@ -0,0 +1,771 @@
+#ifndef _ECORE_DRM2_H
+# define _ECORE_DRM2_H
+
+# include <Ecore.h>
+
+# ifdef EAPI
+# undef EAPI
+# endif
+
+# ifdef _MSC_VER
+# ifdef BUILDING_DLL
+# define EAPI __declspec(dllexport)
+# else // ifdef BUILDING_DLL
+# define EAPI __declspec(dllimport)
+# endif // ifdef BUILDING_DLL
+# else // ifdef _MSC_VER
+# ifdef __GNUC__
+# if __GNUC__ >= 4
+# define EAPI __attribute__ ((visibility("default")))
+# else // if __GNUC__ >= 4
+# define EAPI
+# endif // if __GNUC__ >= 4
+# else // ifdef __GNUC__
+# define EAPI
+# endif // ifdef __GNUC__
+# endif // ifdef _MSC_VER
+
+# ifdef EFL_BETA_API_SUPPORT
+
+/* opaque structure to represent a drm device */
+typedef struct _Ecore_Drm2_Device Ecore_Drm2_Device;
+
+/* opaque structure to represent a framebuffer object */
+typedef struct _Ecore_Drm2_Fb Ecore_Drm2_Fb;
+
+/* opaque structure to represent an output device */
+typedef struct _Ecore_Drm2_Output Ecore_Drm2_Output;
+
+/* opaque structure to represent an output mode */
+typedef struct _Ecore_Drm2_Output_Mode Ecore_Drm2_Output_Mode;
+
+/* structure to represent event for output changes */
+typedef struct _Ecore_Drm2_Event_Output_Changed
+{
+ unsigned int id;
+ int x, y, w, h;
+ int phys_width, phys_height;
+ unsigned int refresh, scale;
+ int subpixel, transform;
+ const char *make, *model, *name;
+ Eina_Bool connected : 1;
+ Eina_Bool enabled : 1;
+} Ecore_Drm2_Event_Output_Changed;
+
+/* structure to represent event for session state changes */
+typedef struct _Ecore_Drm2_Event_Activate
+{
+ Eina_Bool active : 1;
+} Ecore_Drm2_Event_Activate;
+
+EAPI extern int ECORE_DRM2_EVENT_OUTPUT_CHANGED;
+EAPI extern int ECORE_DRM2_EVENT_ACTIVATE;
+
+/**
+ * @file
+ * @brief Ecore functions for dealing with drm, virtual terminals
+ *
+ * @defgroup Ecore_Drm2_Group Ecore_Drm2 - Drm Integration
+ * @ingroup Ecore
+ *
+ * Ecore_Drm2 provides a wrapper and functions for using libdrm
+ *
+ * @li @ref Ecore_Drm2_Init_Group
+ * @li @ref Ecore_Drm2_Device_Group
+ * @li @ref Ecore_Drm2_Output_Group
+ * @li @ref Ecore_Drm2_Fb_Group
+ */
+
+/**
+ * @defgroup Ecore_Drm2_Init_Group Drm library Init and Shutdown functions
+ *
+ * Functions that start and shutdown the Ecore_Drm2 library
+ */
+
+/**
+ * Initialize the Ecore_Drm2 library
+ *
+ * @return The number of times the library has been initialized without
+ * being shut down. 0 is returned if an error occurs.
+ *
+ * @ingroup Ecore_Drm2_Init_Group
+ * @since 1.18
+ */
+EAPI int ecore_drm2_init(void);
+
+/**
+ * Shutdown the Ecore_Drm2 library
+ *
+ * @return The number of times the library has been initialized without
+ * being shutdown. 0 is returned if an error occurs.
+ *
+ * @ingroup Ecore_Drm2_Init_Group
+ * @since 1.18
+ */
+EAPI int ecore_drm2_shutdown(void);
+
+/**
+ * @defgroup Ecore_Drm2_Device_Group Drm device functions
+ *
+ * Functions that deal with finding, opening, closing, or obtaining various
+ * information about a drm device
+ */
+
+/**
+ * Try to find a drm device on a given seat
+ *
+ * @param seat
+ * @param tty
+ * @param sync
+ *
+ * @return A newly allocated Ecore_Drm2_Device on success, NULL otherwise
+ *
+ * @ingroup Ecore_Drm2_Device_Group
+ * @since 1.18
+ */
+EAPI Ecore_Drm2_Device *ecore_drm2_device_find(const char *seat, unsigned int tty);
+
+/**
+ * Try to open a given Ecore_Drm2_Device
+ *
+ * @param device
+ *
+ * @return A valid file descriptor if open succeeds, -1 otherwise.
+ *
+ * @ingroup Ecore_Drm2_Device_Group
+ * @since 1.18
+ */
+EAPI int ecore_drm2_device_open(Ecore_Drm2_Device *device);
+
+/**
+ * Close an open Ecore_Drm2_Device
+ *
+ * @param device
+ *
+ * @ingroup Ecore_Drm2_Device_Group
+ * @since 1.18
+ */
+EAPI void ecore_drm2_device_close(Ecore_Drm2_Device *device);
+
+/**
+ * Free a given Ecore_Drm2_Device
+ *
+ * @param device
+ *
+ * @ingroup Ecore_Drm2_Device_Group
+ * @since 1.18
+ */
+EAPI void ecore_drm2_device_free(Ecore_Drm2_Device *device);
+
+/**
+ * Get the type of clock used by a given Ecore_Drm2_Device
+ *
+ * @param device
+ *
+ * @return The clockid_t used by this drm device
+ *
+ * @ingroup Ecore_Drm2_Device_Group
+ * @since 1.18
+ */
+EAPI int ecore_drm2_device_clock_id_get(Ecore_Drm2_Device *device);
+
+/**
+ * Get the size of the cursor supported by a given Ecore_Drm2_Device
+ *
+ * @param device
+ * @param width
+ * @param height
+ *
+ * @ingroup Ecore_Drm2_Device_Group
+ * @since 1.18
+ */
+EAPI void ecore_drm2_device_cursor_size_get(Ecore_Drm2_Device *device, int *width, int *height);
+
+/**
+ * Get the current pointer position
+ *
+ * @param device
+ * @param x
+ * @param y
+ *
+ * @ingroup Ecore_Drm2_Device_Group
+ * @since 1.18
+ */
+EAPI void ecore_drm2_device_pointer_xy_get(Ecore_Drm2_Device *device, int *x, int *y);
+
+/**
+ * Warp the pointer position to given coordinates
+ *
+ * @param dev
+ * @param x
+ * @param y
+ *
+ * @ingroup Ecore_Drm2_Device_Group
+ * @since 1.18
+ */
+EAPI void ecore_drm2_device_pointer_warp(Ecore_Drm2_Device *device, int x, int y);
+
+/**
+ * Set a left handed mode for the given device
+ *
+ * @param device
+ * @param left
+ *
+ * @return EINA_TRUE on success, EINA_FALSE otherwise
+ *
+ * @ingroup Ecore_Drm2_Device_Group
+ * @since 1.18
+ */
+EAPI Eina_Bool ecore_drm2_device_pointer_left_handed_set(Ecore_Drm2_Device *device, Eina_Bool left);
+
+/**
+ * Set which window is to be used for input events
+ *
+ * @param device
+ * @param window
+ *
+ * @ingroup Ecore_Drm2_Device_Group
+ * @since 1.18
+ */
+EAPI void ecore_drm2_device_window_set(Ecore_Drm2_Device *device, unsigned int window);
+
+/**
+ * Set maximium position that pointer device is allowed to move
+ *
+ * @param device
+ * @param w
+ * @param h
+ *
+ * @ingroup Ecore_Drm2_Device_Group
+ * @since 1.18
+ */
+EAPI void ecore_drm2_device_pointer_max_set(Ecore_Drm2_Device *device, int w, int h);
+
+/**
+ * Set a cached context to be used on keyboards
+ *
+ * @param device
+ * @param context
+ *
+ * @ingroup Ecore_Drm2_Device_Group
+ * @since 1.18
+ */
+EAPI void ecore_drm2_device_keyboard_cached_context_set(Ecore_Drm2_Device *device, void *context);
+
+/**
+ * Set a cached keymap to be used on keyboards
+ *
+ * @param device
+ * @param keymap
+ *
+ * @ingroup Ecore_Drm2_Device_Group
+ * @since 1.18
+ */
+EAPI void ecore_drm2_device_keyboard_cached_keymap_set(Ecore_Drm2_Device *device, void *keymap);
+
+/**
+ * Get the crtcs of a given device
+ *
+ * @param device
+ * @param num
+ *
+ * @return The crtcs of this given device or NULL on failure
+ *
+ * @ingroup Ecore_Drm2_Device_Group
+ * @since 1.18
+ */
+EAPI unsigned int *ecore_drm2_device_crtcs_get(Ecore_Drm2_Device *device, int *num);
+
+/**
+ * Get the minimum and maximum screen size range
+ *
+ * @param device
+ * @param *minw
+ * @param *minh
+ * @param *maxw
+ * @param *maxh
+ *
+ * @ingroup Ecore_Drm2_Device_Group
+ * @since 1.18
+ */
+EAPI void ecore_drm2_device_screen_size_range_get(Ecore_Drm2_Device *device, int *minw, int *minh, int *maxw, int *maxh);
+
+/**
+ * Calibrate any input devices for given screen size
+ *
+ * @param device
+ * @param w
+ * @param h
+ *
+ * @ingroup Ecore_Drm2_Device_Group
+ * @since 1.18
+ */
+EAPI void ecore_drm2_device_calibrate(Ecore_Drm2_Device *device, int w, int h);
+
+/**
+ * @defgroup Ecore_Drm2_Output_Group Drm output functions
+ *
+ * Functions that deal with setup of outputs
+ */
+
+/**
+ * Iterate drm resources and create outputs
+ *
+ * @param device
+ *
+ * @return EINA_TRUE on success, EINA_FALSE otherwise
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI Eina_Bool ecore_drm2_outputs_create(Ecore_Drm2_Device *device);
+
+/**
+ * Destroy any created outputs
+ *
+ * @param device
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI void ecore_drm2_outputs_destroy(Ecore_Drm2_Device *device);
+
+/**
+ * Get the list of outputs from a drm device
+ *
+ * @param device
+ *
+ * @return
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI const Eina_List *ecore_drm2_outputs_get(Ecore_Drm2_Device *device);
+
+/**
+ * Get the dpms level of a given output
+ *
+ * @param output
+ *
+ * @return Integer value representing the state of DPMS on a given output
+ * or -1 on error
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI int ecore_drm2_output_dpms_get(Ecore_Drm2_Output *output);
+
+/**
+ * Set the dpms level of a given output
+ *
+ * @param output
+ * @param level
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI void ecore_drm2_output_dpms_set(Ecore_Drm2_Output *output, int level);
+
+/**
+ * Get the edid of a given output
+ *
+ * @param output
+ *
+ * @return A string representing the edid
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI char *ecore_drm2_output_edid_get(Ecore_Drm2_Output *output);
+
+/**
+ * Get if a given output has a backlight
+ *
+ * @param output
+ *
+ * @return EINA_TRUE if this output has a backlight, EINA_FALSE otherwise
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI Eina_Bool ecore_drm2_output_backlight_get(Ecore_Drm2_Output *output);
+
+/**
+ * Find an output at the given position
+ *
+ * @param device
+ * @param x
+ * @param y
+ *
+ * @return An Ecore_Drm2_Output which exists at the given coordinates, or NULL on failure
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI Ecore_Drm2_Output *ecore_drm2_output_find(Ecore_Drm2_Device *device, int x, int y);
+
+/**
+ * Get the geometry of a given output
+ *
+ * @param output
+ * @param x
+ * @param y
+ * @param w
+ * @param h
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI void ecore_drm2_output_geometry_get(Ecore_Drm2_Output *output, int *x, int *y, int *w, int *h);
+
+/**
+ * Get the id of the crtc that an output is using
+ *
+ * @param output
+ *
+ * @return A valid crtc id or 0 on failure
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI unsigned int ecore_drm2_output_crtc_get(Ecore_Drm2_Output *output);
+
+/**
+ * Return the next Ecore_Drm2_Fb to be used on a given output
+ *
+ * @param output
+ *
+ * @return The next Ecore_Drm2_Fb which is scheduled to to be flipped, or NULL otherwise
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI Ecore_Drm2_Fb *ecore_drm2_output_next_fb_get(Ecore_Drm2_Output *output);
+
+/**
+ * Return the current Ecore_Drm2_Fb used on a given output
+ *
+ * @param output
+ *
+ * @return The current Ecore_Drm2_Fb used on this output, or NULL otherwise
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI Ecore_Drm2_Fb *ecore_drm2_output_current_fb_get(Ecore_Drm2_Output *output);
+
+/**
+ * Set the next Ecore_Drm2_Fb to be used on a given output
+ *
+ * @param output
+ * @param fb
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI void ecore_drm2_output_next_fb_set(Ecore_Drm2_Output *output, Ecore_Drm2_Fb *fb);
+
+/**
+ * Get the size of the crtc for a given output
+ *
+ * @param output
+ * @param *w
+ * @param *h
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI void ecore_drm2_output_crtc_size_get(Ecore_Drm2_Output *output, int *w, int *h);
+
+/**
+ * Get if a given output is marked as the primary output
+ *
+ * @param output
+ *
+ * @return EINA_TRUE if output is primary, EINA_FALSE otherwise
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI Eina_Bool ecore_drm2_output_primary_get(Ecore_Drm2_Output *output);
+
+/**
+ * Set a given output to be primary
+ *
+ * @param output
+ * @param primary
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI void ecore_drm2_output_primary_set(Ecore_Drm2_Output *output, Eina_Bool primary);
+
+/**
+ * Get if a given output is enabled
+ *
+ * @param output
+ *
+ * @return EINA_TRUE if enabled, EINA_FALSE otherwise.
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI Eina_Bool ecore_drm2_output_enabled_get(Ecore_Drm2_Output *output);
+
+/**
+ * Set if a given output is enabled
+ *
+ * @param output
+ * @param enabled
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI void ecore_drm2_output_enabled_set(Ecore_Drm2_Output *output, Eina_Bool enabled);
+
+/**
+ * Get the physical size of a given output
+ *
+ * This function will give the physical size (in mm) of an output
+ *
+ * @param output
+ * @param *w
+ * @param *h
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI void ecore_drm2_output_physical_size_get(Ecore_Drm2_Output *output, int *w, int *h);
+
+/**
+ * Get a list of the modes supported on a given output
+ *
+ * @param output
+ *
+ * @return An Eina_List of the modes supported for this output
+ *
+ * @note The returned list should not be freed
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI const Eina_List *ecore_drm2_output_modes_get(Ecore_Drm2_Output *output);
+
+/**
+ * Get information from an existing output mode
+ *
+ * @param mode
+ * @param w
+ * @param h
+ * @param refresh
+ * @param flags
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI void ecore_drm2_output_mode_info_get(Ecore_Drm2_Output_Mode *mode, int *w, int *h, unsigned int *refresh, unsigned int *flags);
+
+/**
+ * Set a given mode to be used on a given output
+ *
+ * @param output
+ * @param mode
+ * @param x
+ * @param y
+ *
+ * @return EINA_TRUE on success, EINA_FALSE otherwise
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI Eina_Bool ecore_drm2_output_mode_set(Ecore_Drm2_Output *output, Ecore_Drm2_Output_Mode *mode, int x, int y);
+
+/**
+ * Get the name of a given output
+ *
+ * @param output
+ *
+ * @return A string representing the output's name. Caller should free this return.
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI char *ecore_drm2_output_name_get(Ecore_Drm2_Output *output);
+
+/**
+ * Get the model of a given output
+ *
+ * @param output
+ *
+ * @return A string representing the output's model. Caller should free this return.
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI char *ecore_drm2_output_model_get(Ecore_Drm2_Output *output);
+
+/**
+ * Get if a given output is connected
+ *
+ * @param output
+ *
+ * @return EINA_TRUE if connected, EINA_FALSE otherwise
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI Eina_Bool ecore_drm2_output_connected_get(Ecore_Drm2_Output *output);
+
+/**
+ * Get if a given output is cloned
+ *
+ * @param output
+ *
+ * @return EINA_TRUE if cloned, EINA_FALSE otherwise.
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI Eina_Bool ecore_drm2_output_cloned_get(Ecore_Drm2_Output *output);
+
+/**
+ * Get the connector type of a given output
+ *
+ * @param output
+ *
+ * @return An unsigned integer representing the type of connector for this output
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI unsigned int ecore_drm2_output_connector_type_get(Ecore_Drm2_Output *output);
+
+/**
+ * Get the current resolution of a given output
+ *
+ * @param output
+ * @param *w
+ * @param *h
+ * @param *refresh
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI void ecore_drm2_output_resolution_get(Ecore_Drm2_Output *output, int *w, int *h, unsigned int *refresh);
+
+/**
+ * Get if an output can be used on a given crtc
+ *
+ * This function will loop the possible crtcs of an encoder to determine if
+ * a given output can be assigned to a given crtc
+ *
+ * @param output
+ * @param crtc
+ *
+ * @return EINA_TRUE if the output can be assigned to given crtc, EINA_FALSE otherwise
+ *
+ * @ingroup Ecore_Drm2_Output_Group
+ * @since 1.18
+ */
+EAPI Eina_Bool ecore_drm2_output_possible_crtc_get(Ecore_Drm2_Output *output, unsigned int crtc);
+
+/**
+ * @defgroup Ecore_Drm2_Fb_Group Drm framebuffer functions
+ *
+ * Functions that deal with setup of framebuffers
+ */
+
+/**
+ * Create a new framebuffer object
+ *
+ * @param fd
+ * @param width
+ * @param height
+ * @param depth
+ * @param bpp
+ * @param format
+ *
+ * @return A newly create framebuffer object, or NULL on failure
+ *
+ * @ingroup Ecore_Drm2_Fb_Group
+ * @since 1.18
+ */
+EAPI Ecore_Drm2_Fb *ecore_drm2_fb_create(int fd, int width, int height, int depth, int bpp, unsigned int format);
+
+EAPI Ecore_Drm2_Fb *ecore_drm2_fb_gbm_create(int fd, int width, int height, int depth, int bpp, unsigned int format, unsigned int handle, unsigned int stride);
+
+/**
+ * Destroy a framebuffer object
+ *
+ * @param fb
+ *
+ * @ingroup Ecore_Drm2_Fb_Group
+ * @since 1.18
+ */
+EAPI void ecore_drm2_fb_destroy(Ecore_Drm2_Fb *fb);
+
+/**
+ * Get a framebuffer's mmap'd data
+ *
+ * @param fb
+ *
+ * @return The mmap'd area of the framebuffer or NULL on failure
+ *
+ * @ingroup Ecore_Drm2_Fb_Group
+ * @since 1.18
+ */
+EAPI void *ecore_drm2_fb_data_get(Ecore_Drm2_Fb *fb);
+
+/**
+ * Get a framebuffer's size
+ *
+ * @param fb
+ *
+ * @return size of the framebuffers' mmap'd data or 0 on failure
+ *
+ * @ingroup Ecore_Drm2_Fb_Group
+ * @since 1.18
+ */
+EAPI unsigned int ecore_drm2_fb_size_get(Ecore_Drm2_Fb *fb);
+
+/**
+ * Get a framebuffer's stride
+ *
+ * @param fb
+ *
+ * @return stride of the framebuffer or 0 on failure
+ *
+ * @ingroup Ecore_Drm2_Fb_Group
+ * @since 1.18
+ */
+EAPI unsigned int ecore_drm2_fb_stride_get(Ecore_Drm2_Fb *fb);
+
+/**
+ * Mark regions of a framebuffer as dirty
+ *
+ * @param fb
+ * @param rects
+ * @param count
+ *
+ * @ingroup Ecore_Drm2_Fb_Group
+ * @since 1.18
+ */
+EAPI void ecore_drm2_fb_dirty(Ecore_Drm2_Fb *fb, Eina_Rectangle *rects, unsigned int count);
+
+/**
+ * Schedule a pageflip to the given Ecore_Drm2_Fb
+ *
+ * @param fb
+ * @param output
+ * @param data
+ *
+ * @return The result of drmModePageFlip function call
+ *
+ * @ingroup Ecore_Drm2_Fb_Group
+ * @since 1.18
+ */
+EAPI int ecore_drm2_fb_flip(Ecore_Drm2_Fb *fb, Ecore_Drm2_Output *output, void *data);
+
+# endif
+
+#endif
diff --git a/src/lib/ecore_drm2/ecore_drm2.c b/src/lib/ecore_drm2/ecore_drm2.c
new file mode 100644
index 0000000000..339362a9c2
--- /dev/null
+++ b/src/lib/ecore_drm2/ecore_drm2.c
@@ -0,0 +1,83 @@
+#include "ecore_drm2_private.h"
+
+static int _ecore_drm2_init_count = 0;
+
+int _ecore_drm2_log_dom = -1;
+
+EAPI int ECORE_DRM2_EVENT_OUTPUT_CHANGED = -1;
+EAPI int ECORE_DRM2_EVENT_ACTIVATE = -1;
+
+EAPI int
+ecore_drm2_init(void)
+{
+ if (++_ecore_drm2_init_count != 1) return _ecore_drm2_init_count;
+
+ if (!eina_init()) goto eina_err;
+
+ if (!ecore_init())
+ {
+ EINA_LOG_ERR("Could not initialize Ecore library");
+ goto ecore_err;
+ }
+
+ if (!eeze_init())
+ {
+ EINA_LOG_ERR("Could not initialize Eeze library");
+ goto eeze_err;
+ }
+
+ if (!elput_init())
+ {
+ EINA_LOG_ERR("Could not initialize Elput library");
+ goto elput_err;
+ }
+
+ _ecore_drm2_log_dom =
+ eina_log_domain_register("ecore_drm2", ECORE_DRM2_DEFAULT_LOG_COLOR);
+ if (!_ecore_drm2_log_dom)
+ {
+ EINA_LOG_ERR("Could not create logging domain for Ecore_Drm2");
+ goto log_err;
+ }
+
+ ECORE_DRM2_EVENT_OUTPUT_CHANGED = ecore_event_type_new();
+ ECORE_DRM2_EVENT_ACTIVATE = ecore_event_type_new();
+
+ return _ecore_drm2_init_count;
+
+log_err:
+ elput_shutdown();
+elput_err:
+ eeze_shutdown();
+eeze_err:
+ ecore_shutdown();
+ecore_err:
+ eina_shutdown();
+eina_err:
+ return --_ecore_drm2_init_count;
+}
+
+EAPI int
+ecore_drm2_shutdown(void)
+{
+ if (_ecore_drm2_init_count < 1)
+ {
+ ERR("Ecore_Drm2 shutdown called without init");
+ return 0;
+ }
+
+ if (--_ecore_drm2_init_count != 0) return _ecore_drm2_init_count;
+
+ ECORE_DRM2_EVENT_OUTPUT_CHANGED = -1;
+ ECORE_DRM2_EVENT_ACTIVATE = -1;
+
+ eina_log_domain_unregister(_ecore_drm2_log_dom);
+ _ecore_drm2_log_dom = -1;
+
+ elput_shutdown();
+ eeze_shutdown();
+ ecore_shutdown();
+ eina_shutdown();
+
+ return _ecore_drm2_init_count;
+}
diff --git a/src/lib/ecore_drm2/ecore_drm2_device.c b/src/lib/ecore_drm2/ecore_drm2_device.c
new file mode 100644
index 0000000000..95b7315935
--- /dev/null
+++ b/src/lib/ecore_drm2/ecore_drm2_device.c
@@ -0,0 +1,315 @@
+#include "ecore_drm2_private.h"
+
+#ifndef DRM_CAP_CURSOR_WIDTH
+# define DRM_CAP_CURSOR_WIDTH 0x8
+#endif
+
+#ifndef DRM_CAP_CURSOR_HEIGHT
+# define DRM_CAP_CURSOR_HEIGHT 0x9
+#endif
+
+static Eina_Bool
+_cb_session_active(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Elput_Event_Session_Active *ev;
+ Ecore_Drm2_Event_Activate *ea;
+
+ ev = event;
+
+ ea = calloc(1, sizeof(Ecore_Drm2_Event_Activate));
+ if (!ea) return ECORE_CALLBACK_RENEW;
+
+ ea->active = ev->active;
+
+ ecore_event_add(ECORE_DRM2_EVENT_ACTIVATE, ea, NULL, NULL);
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+static const char *
+_drm2_device_find(const char *seat)
+{
+ Eina_List *devs, *l;
+ const char *dev, *ret = NULL;
+ Eina_Bool found = EINA_FALSE;
+ Eina_Bool platform = EINA_FALSE;
+
+ devs = eeze_udev_find_by_subsystem_sysname("drm", "card[0-9]*");
+ if (!devs) return NULL;
+
+ EINA_LIST_FOREACH(devs, l, dev)
+ {
+ const char *dpath, *dseat, *dparent;
+
+ dpath = eeze_udev_syspath_get_devpath(dev);
+ if (!dpath) continue;
+
+ dseat = eeze_udev_syspath_get_property(dev, "ID_SEAT");
+ if (!dseat) dseat = eina_stringshare_add("seat0");
+
+ if ((seat) && (strcmp(seat, dseat)))
+ goto cont;
+ else if (strcmp(dseat, "seat0"))
+ goto cont;
+
+ dparent = eeze_udev_syspath_get_parent_filtered(dev, "pci", NULL);
+ if (!dparent)
+ {
+ dparent =
+ eeze_udev_syspath_get_parent_filtered(dev, "platform", NULL);
+ platform = EINA_TRUE;
+ }
+
+ if (dparent)
+ {
+ if (!platform)
+ {
+ const char *id;
+
+ id = eeze_udev_syspath_get_sysattr(dparent, "boot_vga");
+ if (id)
+ {
+ if (!strcmp(id, "1")) found = EINA_TRUE;
+ eina_stringshare_del(id);
+ }
+ }
+ else
+ found = EINA_TRUE;
+
+ eina_stringshare_del(dparent);
+ }
+
+cont:
+ eina_stringshare_del(dpath);
+ eina_stringshare_del(dseat);
+ if (found) break;
+ }
+
+ if (!found) goto out;
+
+ ret = eeze_udev_syspath_get_devpath(dev);
+
+out:
+ EINA_LIST_FREE(devs, dev)
+ eina_stringshare_del(dev);
+
+ return ret;
+}
+
+EAPI Ecore_Drm2_Device *
+ecore_drm2_device_find(const char *seat, unsigned int tty)
+{
+ Ecore_Drm2_Device *dev;
+
+ dev = calloc(1, sizeof(Ecore_Drm2_Device));
+ if (!dev) return NULL;
+
+ dev->path = _drm2_device_find(seat);
+ if (!dev->path)
+ {
+ ERR("Could not find drm device on seat %s", seat);
+ goto path_err;
+ }
+
+ dev->em = elput_manager_connect(seat, tty);
+ if (!dev->em)
+ {
+ ERR("Could not connect to input manager");
+ goto man_err;
+ }
+
+ return dev;
+
+man_err:
+ eina_stringshare_del(dev->path);
+path_err:
+ free(dev);
+ return NULL;
+}
+
+EAPI int
+ecore_drm2_device_open(Ecore_Drm2_Device *device)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(device, -1);
+
+ device->fd = elput_manager_open(device->em, device->path, -1);
+ if (device->fd < 0) goto open_err;
+
+ if (!elput_input_init(device->em))
+ {
+ ERR("Could not initialize Elput Input");
+ goto input_err;
+ }
+
+ DBG("Device Path: %s", device->path);
+ DBG("Device Fd: %d", device->fd);
+
+ device->active_hdlr =
+ ecore_event_handler_add(ELPUT_EVENT_SESSION_ACTIVE,
+ _cb_session_active, device);
+
+ /* NB: Not going to enable planes if we don't support atomic */
+ /* if (drmSetClientCap(device->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) < 0) */
+ /* ERR("Could not set Universal Plane support: %m"); */
+
+ return device->fd;
+
+input_err:
+ elput_manager_close(device->em, device->fd);
+open_err:
+ return -1;
+}
+
+EAPI void
+ecore_drm2_device_close(Ecore_Drm2_Device *device)
+{
+ EINA_SAFETY_ON_NULL_RETURN(device);
+ EINA_SAFETY_ON_TRUE_RETURN(device->fd < 0);
+
+ elput_input_shutdown(device->em);
+ elput_manager_close(device->em, device->fd);
+}
+
+EAPI void
+ecore_drm2_device_free(Ecore_Drm2_Device *device)
+{
+ EINA_SAFETY_ON_NULL_RETURN(device);
+
+ if (device->active_hdlr) ecore_event_handler_del(device->active_hdlr);
+ device->active_hdlr = NULL;
+
+ eina_stringshare_del(device->path);
+ free(device);
+}
+
+EAPI int
+ecore_drm2_device_clock_id_get(Ecore_Drm2_Device *device)
+{
+ uint64_t caps;
+ int ret;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(device, -1);
+ EINA_SAFETY_ON_TRUE_RETURN_VAL((device->fd < 0), -1);
+
+ ret = drmGetCap(device->fd, DRM_CAP_TIMESTAMP_MONOTONIC, &caps);
+ if ((ret == 0) && (caps == 1))
+ return CLOCK_MONOTONIC;
+ else
+ return CLOCK_REALTIME;
+}
+
+EAPI void
+ecore_drm2_device_cursor_size_get(Ecore_Drm2_Device *device, int *width, int *height)
+{
+ uint64_t caps;
+ int ret;
+
+ EINA_SAFETY_ON_NULL_RETURN(device);
+ EINA_SAFETY_ON_TRUE_RETURN((device->fd < 0));
+
+ if (width)
+ {
+ *width = 64;
+ ret = drmGetCap(device->fd, DRM_CAP_CURSOR_WIDTH, &caps);
+ if (ret == 0) *width = caps;
+ }
+ if (height)
+ {
+ *height = 64;
+ ret = drmGetCap(device->fd, DRM_CAP_CURSOR_HEIGHT, &caps);
+ if (ret == 0) *height = caps;
+ }
+}
+
+EAPI void
+ecore_drm2_device_pointer_xy_get(Ecore_Drm2_Device *device, int *x, int *y)
+{
+ if (x) *x = 0;
+ if (y) *y = 0;
+
+ EINA_SAFETY_ON_NULL_RETURN(device);
+
+ elput_input_pointer_xy_get(device->em, NULL, x, y);
+}
+
+EAPI void
+ecore_drm2_device_pointer_warp(Ecore_Drm2_Device *device, int x, int y)
+{
+ EINA_SAFETY_ON_NULL_RETURN(device);
+
+ elput_input_pointer_xy_set(device->em, NULL, x, y);
+}
+
+EAPI Eina_Bool
+ecore_drm2_device_pointer_left_handed_set(Ecore_Drm2_Device *device, Eina_Bool left)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(device, EINA_FALSE);
+
+ return elput_input_pointer_left_handed_set(device->em, NULL, left);
+}
+
+EAPI void
+ecore_drm2_device_window_set(Ecore_Drm2_Device *device, unsigned int window)
+{
+ EINA_SAFETY_ON_NULL_RETURN(device);
+ EINA_SAFETY_ON_NULL_RETURN(device->em);
+ elput_manager_window_set(device->em, window);
+}
+
+EAPI void
+ecore_drm2_device_pointer_max_set(Ecore_Drm2_Device *device, int w, int h)
+{
+ EINA_SAFETY_ON_NULL_RETURN(device);
+ EINA_SAFETY_ON_NULL_RETURN(device->em);
+
+ elput_input_pointer_max_set(device->em, w, h);
+}
+
+EAPI void
+ecore_drm2_device_keyboard_cached_context_set(Ecore_Drm2_Device *device, void *context)
+{
+ EINA_SAFETY_ON_NULL_RETURN(device);
+
+ elput_input_keyboard_cached_context_set(device->em, context);
+}
+
+EAPI void
+ecore_drm2_device_keyboard_cached_keymap_set(Ecore_Drm2_Device *device, void *keymap)
+{
+ EINA_SAFETY_ON_NULL_RETURN(device);
+
+ elput_input_keyboard_cached_keymap_set(device->em, keymap);
+}
+
+EAPI unsigned int *
+ecore_drm2_device_crtcs_get(Ecore_Drm2_Device *device, int *num)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(device, NULL);
+
+ if (num) *num = device->num_crtcs;
+ return device->crtcs;
+}
+
+EAPI void
+ecore_drm2_device_screen_size_range_get(Ecore_Drm2_Device *device, int *minw, int *minh, int *maxw, int *maxh)
+{
+ if (minw) *minw = 0;
+ if (minh) *minh = 0;
+ if (maxw) *maxw = 0;
+ if (maxh) *maxh = 0;
+
+ EINA_SAFETY_ON_NULL_RETURN(device);
+
+ if (minw) *minw = device->min.width;
+ if (minh) *minh = device->min.height;
+ if (maxw) *maxw = device->max.width;
+ if (maxh) *maxh = device->max.height;
+}
+
+EAPI void
+ecore_drm2_device_calibrate(Ecore_Drm2_Device *device, int w, int h)
+{
+ EINA_SAFETY_ON_NULL_RETURN(device);
+
+ elput_input_devices_calibrate(device->em, w, h);
+}
diff --git a/src/lib/ecore_drm2/ecore_drm2_fb.c b/src/lib/ecore_drm2/ecore_drm2_fb.c
new file mode 100644
index 0000000000..9032c122be
--- /dev/null
+++ b/src/lib/ecore_drm2/ecore_drm2_fb.c
@@ -0,0 +1,265 @@
+#include "ecore_drm2_private.h"
+
+static Eina_Bool
+_fb2_create(Ecore_Drm2_Fb *fb)
+{
+ struct drm_mode_fb_cmd2 cmd;
+ uint32_t hdls[4], pitches[4], offsets[4];
+ uint64_t modifiers[4];
+
+ hdls[0] = fb->hdl;
+ pitches[0] = fb->stride;
+ offsets[0] = 0;
+ modifiers[0] = 0;
+
+ memset(&cmd, 0, sizeof(struct drm_mode_fb_cmd2));
+ cmd.fb_id = 0;
+ cmd.width = fb->w;
+ cmd.height = fb->h;
+ cmd.pixel_format = fb->format;
+ cmd.flags = 0;
+ memcpy(cmd.handles, hdls, 4 * sizeof(hdls[0]));
+ memcpy(cmd.pitches, pitches, 4 * sizeof(pitches[0]));
+ memcpy(cmd.offsets, offsets, 4 * sizeof(offsets[0]));
+ memcpy(cmd.modifier, modifiers, 4 * sizeof(modifiers[0]));
+
+ if (drmIoctl(fb->fd, DRM_IOCTL_MODE_ADDFB2, &cmd))
+ return EINA_FALSE;
+
+ fb->id = cmd.fb_id;
+
+ return EINA_TRUE;
+}
+
+EAPI Ecore_Drm2_Fb *
+ecore_drm2_fb_create(int fd, int width, int height, int depth, int bpp, unsigned int format)
+{
+ Ecore_Drm2_Fb *fb;
+ struct drm_mode_create_dumb carg;
+ struct drm_mode_destroy_dumb darg;
+ struct drm_mode_map_dumb marg;
+ int ret;
+
+ EINA_SAFETY_ON_TRUE_RETURN_VAL((fd < 0), NULL);
+
+ fb = calloc(1, sizeof(Ecore_Drm2_Fb));
+ if (!fb) return NULL;
+
+ fb->fd = fd;
+ fb->w = width;
+ fb->h = height;
+ fb->bpp = bpp;
+ fb->depth = depth;
+ fb->format = format;
+
+ memset(&carg, 0, sizeof(struct drm_mode_create_dumb));
+ carg.bpp = bpp;
+ carg.width = width;
+ carg.height = height;
+
+ ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &carg);
+ if (ret) goto err;
+
+ fb->hdl = carg.handle;
+ fb->size = carg.size;
+ fb->stride = carg.pitch;
+
+ if (!_fb2_create(fb))
+ {
+ ret =
+ drmModeAddFB(fd, width, height, depth, bpp,
+ fb->stride, fb->hdl, &fb->id);
+ if (ret)
+ {
+ ERR("Could not add framebuffer: %m");
+ goto add_err;
+ }
+ }
+
+ memset(&marg, 0, sizeof(struct drm_mode_map_dumb));
+ marg.handle = fb->hdl;
+ ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &marg);
+ if (ret)
+ {
+ ERR("Could not map framebuffer: %m");
+ goto map_err;
+ }
+
+ fb->mmap = mmap(NULL, fb->size, PROT_WRITE, MAP_SHARED, fd, marg.offset);
+ if (fb->mmap == MAP_FAILED)
+ {
+ ERR("Could not mmap framebuffer memory: %m");
+ goto map_err;
+ }
+
+ return fb;
+
+map_err:
+ drmModeRmFB(fd, fb->id);
+add_err:
+ memset(&darg, 0, sizeof(struct drm_mode_destroy_dumb));
+ darg.handle = fb->hdl;
+ drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &darg);
+err:
+ free(fb);
+ return NULL;
+}
+
+EAPI Ecore_Drm2_Fb *
+ecore_drm2_fb_gbm_create(int fd, int width, int height, int depth, int bpp, unsigned int format, unsigned int handle, unsigned int stride)
+{
+ Ecore_Drm2_Fb *fb;
+
+ EINA_SAFETY_ON_TRUE_RETURN_VAL((fd < 0), NULL);
+
+ fb = calloc(1, sizeof(Ecore_Drm2_Fb));
+ if (!fb) return NULL;
+
+ fb->gbm = EINA_TRUE;
+
+ fb->fd = fd;
+ fb->w = width;
+ fb->h = height;
+ fb->bpp = bpp;
+ fb->depth = depth;
+ fb->format = format;
+ fb->stride = stride;
+ fb->size = fb->stride * fb->h;
+ fb->hdl = handle;
+
+ if (!_fb2_create(fb))
+ {
+ int ret;
+
+ ret =
+ drmModeAddFB(fd, width, height, depth, bpp,
+ fb->stride, fb->hdl, &fb->id);
+ if (ret)
+ {
+ ERR("Could not add framebuffer: %m");
+ goto err;
+ }
+ }
+
+ return fb;
+
+err:
+ free(fb);
+ return NULL;
+}
+
+EAPI void
+ecore_drm2_fb_destroy(Ecore_Drm2_Fb *fb)
+{
+ EINA_SAFETY_ON_NULL_RETURN(fb);
+
+ if (fb->id) drmModeRmFB(fb->fd, fb->id);
+
+ if (!fb->gbm)
+ {
+ struct drm_mode_destroy_dumb darg;
+
+ if (fb->mmap) munmap(fb->mmap, fb->size);
+
+ memset(&darg, 0, sizeof(struct drm_mode_destroy_dumb));
+ darg.handle = fb->hdl;
+ drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &darg);
+ }
+
+ free(fb);
+}
+
+EAPI void *
+ecore_drm2_fb_data_get(Ecore_Drm2_Fb *fb)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(fb, NULL);
+ return fb->mmap;
+}
+
+EAPI unsigned int
+ecore_drm2_fb_size_get(Ecore_Drm2_Fb *fb)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(fb, 0);
+ return fb->size;
+}
+
+EAPI unsigned int
+ecore_drm2_fb_stride_get(Ecore_Drm2_Fb *fb)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(fb, 0);
+ return fb->stride;
+}
+
+EAPI void
+ecore_drm2_fb_dirty(Ecore_Drm2_Fb *fb, Eina_Rectangle *rects, unsigned int count)
+{
+ EINA_SAFETY_ON_NULL_RETURN(fb);
+ EINA_SAFETY_ON_NULL_RETURN(rects);
+
+#ifdef DRM_MODE_FEATURE_DIRTYFB
+ drmModeClip *clip;
+ unsigned int i = 0;
+ int ret;
+
+ clip = alloca(count * sizeof(drmModeClip));
+ for (i = 0; i < count; i++)
+ {
+ clip[i].x1 = rects[i].x;
+ clip[i].y1 = rects[i].y;
+ clip[i].x2 = rects[i].w;
+ clip[i].y2 = rects[i].h;
+ }
+
+ ret = drmModeDirtyFB(fb->fd, fb->id, clip, count);
+ if ((ret) && (ret == -EINVAL))
+ WRN("Could not mark framebuffer as dirty: %m");
+#endif
+}
+
+EAPI int
+ecore_drm2_fb_flip(Ecore_Drm2_Fb *fb, Ecore_Drm2_Output *output, void *data)
+{
+ int ret = 0;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(fb, -1);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, -1);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output->current_mode, -1);
+
+ if (output->next)
+ WRN("Fb reused too soon, tearing may be visible");
+
+ if ((!output->current) ||
+ (output->current->stride != fb->stride))
+ {
+ ret =
+ drmModeSetCrtc(fb->fd, output->crtc_id, fb->id,
+ output->x, output->y, &output->conn_id, 1,
+ &output->current_mode->info);
+ if (ret)
+ {
+ ERR("Failed to set Mode %dx%d for Output %s: %m",
+ output->current_mode->width, output->current_mode->height,
+ output->name);
+ return ret;
+ }
+
+ output->current = fb;
+ output->next = NULL;
+
+ return 0;
+ }
+
+ ret =
+ drmModePageFlip(fb->fd, output->crtc_id, fb->id,
+ DRM_MODE_PAGE_FLIP_EVENT, data);
+ if (ret < 0)
+ {
+ DBG("Pageflip Failed for Crtc %u on Connector %u: %m",
+ output->crtc_id, output->conn_id);
+ output->next = fb;
+ return ret;
+ }
+
+ output->current = fb;
+ return 0;
+}
diff --git a/src/lib/ecore_drm2/ecore_drm2_outputs.c b/src/lib/ecore_drm2/ecore_drm2_outputs.c
new file mode 100644
index 0000000000..7596164f73
--- /dev/null
+++ b/src/lib/ecore_drm2/ecore_drm2_outputs.c
@@ -0,0 +1,1155 @@
+#include "ecore_drm2_private.h"
+
+#define INSIDE(x, y, xx, yy, ww, hh) \
+ (((x) < ((xx) + (ww))) && ((y) < ((yy) + (hh))) && \
+ ((x) >= (xx)) && ((y) >= (yy)))
+
+#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
+#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
+#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
+#define EDID_OFFSET_DATA_BLOCKS 0x36
+#define EDID_OFFSET_LAST_BLOCK 0x6c
+#define EDID_OFFSET_PNPID 0x08
+#define EDID_OFFSET_SERIAL 0x0c
+
+static const char *conn_types[] =
+{
+ "None", "VGA", "DVI-I", "DVI-D", "DVI-A",
+ "Composite", "S-Video", "LVDS", "Component", "DIN",
+ "DisplayPort", "HDMI-A", "HDMI-B", "TV", "eDP", "Virtual", "DSI",
+};
+
+static void
+_output_debug(Ecore_Drm2_Output *output, const drmModeConnector *conn)
+{
+ Eina_List *l;
+ Ecore_Drm2_Output_Mode *omode;
+
+ DBG("Created New Output At %d,%d", output->x, output->y);
+ DBG("\tCrtc Pos: %d %d", output->ocrtc->x, output->ocrtc->y);
+ DBG("\tCrtc: %d", output->crtc_id);
+ DBG("\tConn: %d", output->conn_id);
+ DBG("\tName: %s", output->name);
+ DBG("\tMake: %s", output->make);
+ DBG("\tModel: %s", output->model);
+ DBG("\tSerial: %s", output->serial);
+ DBG("\tCloned: %d", output->cloned);
+ DBG("\tPrimary: %d", output->primary);
+ DBG("\tConnected: %d", output->connected);
+ DBG("\tEnabled: %d", output->enabled);
+
+ if (output->backlight.path)
+ {
+ DBG("\tBacklight");
+ switch (output->backlight.type)
+ {
+ case ECORE_DRM2_BACKLIGHT_RAW:
+ DBG("\t\tType: Raw");
+ break;
+ case ECORE_DRM2_BACKLIGHT_PLATFORM:
+ DBG("\t\tType: Platform");
+ break;
+ case ECORE_DRM2_BACKLIGHT_FIRMWARE:
+ DBG("\t\tType: Firmware");
+ break;
+ }
+ DBG("\t\tPath: %s", output->backlight.path);
+ }
+
+ EINA_LIST_FOREACH(output->modes, l, omode)
+ {
+ DBG("\tAdded Mode: %dx%d@%d%s%s%s",
+ omode->width, omode->height, omode->refresh,
+ (omode->flags & DRM_MODE_TYPE_PREFERRED) ? ", preferred" : "",
+ (omode->flags & DRM_MODE_TYPE_DEFAULT) ? ", current" : "",
+ (conn->count_modes == 0) ? ", built-in" : "");
+ }
+}
+
+static void
+_cb_output_event_free(void *data EINA_UNUSED, void *event)
+{
+ Ecore_Drm2_Event_Output_Changed *ev;
+
+ ev = event;
+ eina_stringshare_del(ev->make);
+ eina_stringshare_del(ev->model);
+ eina_stringshare_del(ev->name);
+ free(ev);
+}
+
+static void
+_output_event_send(Ecore_Drm2_Output *output)
+{
+ Ecore_Drm2_Event_Output_Changed *ev;
+
+ ev = calloc(1, sizeof(Ecore_Drm2_Event_Output_Changed));
+ if (!ev) return;
+
+ ev->id = output->crtc_id;
+
+ ev->x = output->x;
+ ev->y = output->y;
+ if (output->current_mode)
+ {
+ ev->w = output->current_mode->width;
+ ev->h = output->current_mode->height;
+ ev->refresh = output->current_mode->refresh;
+ }
+ else
+ {
+ ev->w = output->ocrtc->width;
+ ev->h = output->ocrtc->height;
+ ev->refresh = 0;
+ }
+
+ ev->phys_width = output->pw;
+ ev->phys_height = output->ph;
+
+ ev->scale = output->scale;
+ ev->subpixel = output->subpixel;
+ ev->transform = output->transform;
+ ev->connected = output->connected;
+ ev->enabled = output->enabled;
+
+ ev->name = eina_stringshare_ref(output->name);
+ ev->make = eina_stringshare_ref(output->make);
+ ev->model = eina_stringshare_ref(output->model);
+
+ ecore_event_add(ECORE_DRM2_EVENT_OUTPUT_CHANGED, ev,
+ _cb_output_event_free, NULL);
+}
+
+static void
+_output_edid_parse_string(const uint8_t *data, char text[])
+{
+ int i = 0, rep = 0;
+
+ strncpy(text, (const char *)data, 12);
+
+ for (; text[i] != '\0'; i++)
+ {
+ if ((text[i] == '\n') || (text[i] == '\r'))
+ {
+ text[i] = '\0';
+ break;
+ }
+ }
+
+ for (i = 0; text[i] != '\0'; i++)
+ {
+ if (!isprint(text[i]))
+ {
+ text[i] = '-';
+ rep++;
+ }
+ }
+
+ if (rep > 4) text[0] = '\0';
+}
+
+static int
+_output_edid_parse(Ecore_Drm2_Output *output, const uint8_t *data, size_t len)
+{
+ int i = 0;
+ uint32_t serial;
+
+ if (len < 128) return -1;
+ if ((data[0] != 0x00) || (data[1] != 0xff)) return -1;
+
+ output->edid.pnp[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
+ output->edid.pnp[1] =
+ 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) +
+ ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
+ output->edid.pnp[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
+ output->edid.pnp[3] = '\0';
+
+ serial = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
+ serial += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
+ serial += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
+ serial += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
+ if (serial > 0)
+ sprintf(output->edid.serial, "%lu", (unsigned long)serial);
+
+ for (i = EDID_OFFSET_DATA_BLOCKS; i <= EDID_OFFSET_LAST_BLOCK; i += 18)
+ {
+ if (data[i] != 0) continue;
+ if (data[i + 2] != 0) continue;
+
+ if (data[i + 3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME)
+ _output_edid_parse_string(&data[i + 5], output->edid.monitor);
+ else if (data[i + 3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER)
+ _output_edid_parse_string(&data[i + 5], output->edid.serial);
+ else if (data[i + 3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING)
+ _output_edid_parse_string(&data[i + 5], output->edid.eisa);
+ }
+
+ return 0;
+}
+
+static void
+_output_edid_find(Ecore_Drm2_Output *output, const drmModeConnector *conn)
+{
+ drmModePropertyBlobPtr blob = NULL;
+ drmModePropertyPtr prop;
+ int i = 0, ret = 0;
+
+ for (; i < conn->count_props && !blob; i++)
+ {
+ if (!(prop = drmModeGetProperty(output->fd, conn->props[i])))
+ continue;
+ if ((prop->flags & DRM_MODE_PROP_BLOB) &&
+ (!strcmp(prop->name, "EDID")))
+ {
+ blob = drmModeGetPropertyBlob(output->fd, conn->prop_values[i]);
+ }
+ drmModeFreeProperty(prop);
+ if (blob) break;
+ }
+
+ if (!blob) return;
+
+ output->edid.blob = eina_memdup(blob->data, blob->length, 1);
+
+ ret = _output_edid_parse(output, blob->data, blob->length);
+ if (!ret)
+ {
+ if (output->edid.pnp[0] != '\0')
+ eina_stringshare_replace(&output->make, output->edid.pnp);
+ if (output->edid.monitor[0] != '\0')
+ eina_stringshare_replace(&output->model, output->edid.monitor);
+ if (output->edid.serial[0] != '\0')
+ eina_stringshare_replace(&output->serial, output->edid.serial);
+ }
+
+ drmModeFreePropertyBlob(blob);
+}
+
+static int
+_output_crtc_find(const drmModeRes *res, const drmModeConnector *conn, Ecore_Drm2_Device *dev)
+{
+ drmModeEncoder *enc;
+ uint32_t crtc;
+ int i = 0, j = 0;
+
+ for (j = 0; j < conn->count_encoders; j++)
+ {
+ enc = drmModeGetEncoder(dev->fd, conn->encoders[j]);
+ if (!enc) continue;
+
+ crtc = enc->crtc_id;
+ drmModeFreeEncoder(enc);
+
+ for (i = 0; i < res->count_crtcs; i++)
+ if (crtc == res->crtcs[i])
+ return i;
+ }
+
+ return -1;
+}
+
+static char *
+_output_name_get(const drmModeConnector *conn)
+{
+ char name[DRM_CONNECTOR_NAME_LEN];
+ const char *type = NULL;
+
+ if (conn->connector_type < EINA_C_ARRAY_LENGTH(conn_types))
+ type = conn_types[conn->connector_type];
+ else
+ type = "UNKNOWN";
+
+ snprintf(name, sizeof(name), "%s-%d", type, conn->connector_type_id);
+ return strdup(name);
+}
+
+static Ecore_Drm2_Output_Mode *
+_output_mode_add(Ecore_Drm2_Output *output, const drmModeModeInfo *info)
+{
+ Ecore_Drm2_Output_Mode *mode;
+ uint64_t refresh;
+
+ mode = calloc(1, sizeof(Ecore_Drm2_Output_Mode));
+ if (!mode) return NULL;
+
+ mode->flags = 0;
+ mode->width = info->hdisplay;
+ mode->height = info->vdisplay;
+
+ refresh = (info->clock * 1000LL / info->htotal + info->vtotal / 2) /
+ info->vtotal;
+
+ if (info->flags & DRM_MODE_FLAG_INTERLACE)
+ refresh *= 2;
+ if (info->flags & DRM_MODE_FLAG_DBLSCAN)
+ refresh /= 2;
+ if (info->vscan > 1)
+ refresh /= info->vscan;
+
+ mode->refresh = refresh;
+ mode->info = *info;
+
+ if (info->type & DRM_MODE_TYPE_PREFERRED)
+ mode->flags |= DRM_MODE_TYPE_PREFERRED;
+
+ output->modes = eina_list_append(output->modes, mode);
+
+ return mode;
+}
+
+static void
+_output_modes_create(Ecore_Drm2_Device *dev, Ecore_Drm2_Output *output, const drmModeConnector *conn)
+{
+ int i = 0;
+ drmModeCrtc *crtc;
+ drmModeEncoder *enc;
+ drmModeModeInfo crtc_mode;
+ Ecore_Drm2_Output_Mode *omode;
+ Ecore_Drm2_Output_Mode *current = NULL, *preferred = NULL, *best = NULL;
+ Eina_List *l = NULL;
+
+ memset(&crtc_mode, 0, sizeof(crtc_mode));
+
+ enc = drmModeGetEncoder(dev->fd, conn->encoder_id);
+ if (enc)
+ {
+ crtc = drmModeGetCrtc(dev->fd, enc->crtc_id);
+ drmModeFreeEncoder(enc);
+ if (!crtc) return;
+ if (crtc->mode_valid) crtc_mode = crtc->mode;
+ drmModeFreeCrtc(crtc);
+ }
+
+ for (i = 0; i < conn->count_modes; i++)
+ {
+ omode = _output_mode_add(output, &conn->modes[i]);
+ if (!omode) continue;
+ }
+
+ EINA_LIST_REVERSE_FOREACH(output->modes, l, omode)
+ {
+ if (!memcmp(&crtc_mode, &omode->info, sizeof(crtc_mode)))
+ current = omode;
+ if (omode->flags & DRM_MODE_TYPE_PREFERRED)
+ preferred = omode;
+ best = omode;
+ }
+
+ if ((!current) && (crtc_mode.clock != 0))
+ {
+ current = _output_mode_add(output, &crtc_mode);
+ if (!current) goto err;
+ }
+
+ if (current) output->current_mode = current;
+ else if (preferred) output->current_mode = preferred;
+ else if (best) output->current_mode = best;
+
+ if (!output->current_mode) goto err;
+
+ output->current_mode->flags |= DRM_MODE_TYPE_DEFAULT;
+
+ return;
+
+err:
+ EINA_LIST_FREE(output->modes, omode)
+ free(omode);
+}
+
+static drmModePropertyPtr
+_output_dpms_property_get(int fd, const drmModeConnector *conn)
+{
+ drmModePropertyPtr prop;
+ int i = 0;
+
+ for (; i < conn->count_props; i++)
+ {
+ prop = drmModeGetProperty(fd, conn->props[i]);
+ if (!prop) continue;
+
+ if (!strcmp(prop->name, "DPMS")) return prop;
+
+ drmModeFreeProperty(prop);
+ }
+
+ return NULL;
+}
+
+static void
+_output_backlight_init(Ecore_Drm2_Output *output, unsigned int conn_type)
+{
+ Eina_List *devs, *l;
+ const char *dev, *t;
+ Eina_Bool found = EINA_FALSE;
+ Ecore_Drm2_Backlight_Type type = 0;
+
+ devs = eeze_udev_find_by_filter("backlight", NULL, NULL);
+
+ EINA_LIST_FOREACH(devs, l, dev)
+ {
+ t = eeze_udev_syspath_get_sysattr(dev, "type");
+ if (!t) continue;
+
+ if (!strcmp(t, "raw"))
+ type = ECORE_DRM2_BACKLIGHT_RAW;
+ else if (!strcmp(t, "platform"))
+ type = ECORE_DRM2_BACKLIGHT_PLATFORM;
+ else if (!strcmp(t, "firmware"))
+ type = ECORE_DRM2_BACKLIGHT_FIRMWARE;
+
+ if ((conn_type == DRM_MODE_CONNECTOR_LVDS) ||
+ (conn_type == DRM_MODE_CONNECTOR_eDP) ||
+ (type == ECORE_DRM2_BACKLIGHT_RAW))
+ found = EINA_TRUE;
+
+ eina_stringshare_del(t);
+ if (found) break;
+ }
+
+ if (found)
+ {
+ output->backlight.type = type;
+ output->backlight.path = eina_stringshare_add(dev);
+ }
+
+ EINA_LIST_FREE(devs, dev)
+ eina_stringshare_del(dev);
+}
+
+static void
+_output_scale_init(Ecore_Drm2_Output *output, Ecore_Drm2_Transform transform, unsigned int scale)
+{
+ output->transform = transform;
+
+ if ((output->enabled) && (output->current_mode))
+ {
+ switch (transform)
+ {
+ case ECORE_DRM2_TRANSFORM_90:
+ case ECORE_DRM2_TRANSFORM_270:
+ case ECORE_DRM2_TRANSFORM_FLIPPED_90:
+ case ECORE_DRM2_TRANSFORM_FLIPPED_270:
+ output->w = output->current_mode->height;
+ output->h = output->current_mode->width;
+ break;
+ case ECORE_DRM2_TRANSFORM_NORMAL:
+ case ECORE_DRM2_TRANSFORM_180:
+ case ECORE_DRM2_TRANSFORM_FLIPPED:
+ case ECORE_DRM2_TRANSFORM_FLIPPED_180:
+ output->w = output->current_mode->width;
+ output->h = output->current_mode->height;
+ break;
+ default:
+ break;
+ }
+ }
+
+ output->scale = scale;
+ output->w /= scale;
+ output->h /= scale;
+}
+
+static void
+_output_matrix_rotate_xy(Eina_Matrix3 *matrix, double x, double y)
+{
+ Eina_Matrix4 tmp, m;
+
+ eina_matrix4_identity(&tmp);
+ eina_matrix4_values_set(&tmp, x, y, 0, 0, -y, x, 0, 0,
+ 0, 0, 1, 0, 0, 0, 0, 1);
+
+ eina_matrix3_matrix4_to(&m, matrix);
+ eina_matrix4_multiply(&m, &m, &tmp);
+ eina_matrix4_matrix3_to(matrix, &m);
+}
+
+static void
+_output_matrix_update(Ecore_Drm2_Output *output)
+{
+ Eina_Matrix3 m3;
+
+ eina_matrix4_identity(&output->matrix);
+ eina_matrix4_matrix3_to(&m3, &output->matrix);
+ eina_matrix3_translate(&m3, -output->x, -output->y);
+
+ switch (output->transform)
+ {
+ case ECORE_DRM2_TRANSFORM_FLIPPED:
+ case ECORE_DRM2_TRANSFORM_FLIPPED_90:
+ case ECORE_DRM2_TRANSFORM_FLIPPED_180:
+ case ECORE_DRM2_TRANSFORM_FLIPPED_270:
+ eina_matrix3_translate(&m3, -output->w, 0);
+ break;
+ default:
+ break;
+ }
+
+ switch (output->transform)
+ {
+ case ECORE_DRM2_TRANSFORM_NORMAL:
+ case ECORE_DRM2_TRANSFORM_FLIPPED:
+ default:
+ break;
+ case ECORE_DRM2_TRANSFORM_90:
+ case ECORE_DRM2_TRANSFORM_FLIPPED_90:
+ eina_matrix3_translate(&m3, 0, -output->h);
+ _output_matrix_rotate_xy(&m3, 0, 1);
+ break;
+ case ECORE_DRM2_TRANSFORM_180:
+ case ECORE_DRM2_TRANSFORM_FLIPPED_180:
+ eina_matrix3_translate(&m3, -output->w, -output->h);
+ _output_matrix_rotate_xy(&m3, -1, 0);
+ break;
+ case ECORE_DRM2_TRANSFORM_270:
+ case ECORE_DRM2_TRANSFORM_FLIPPED_270:
+ eina_matrix3_translate(&m3, -output->w, 0);
+ _output_matrix_rotate_xy(&m3, 0, -1);
+ break;
+ }
+
+ if (output->scale != 1)
+ eina_matrix3_scale(&m3, output->scale, output->scale);
+
+ eina_matrix3_matrix4_to(&output->matrix, &m3);
+ eina_matrix4_inverse(&output->inverse, &output->matrix);
+}
+
+static Eina_Bool
+_output_create(Ecore_Drm2_Device *dev, const drmModeRes *res, const drmModeConnector *conn, int x, int y, int *w, Eina_Bool cloned)
+{
+ Ecore_Drm2_Output *output;
+ int i = 0;
+
+ if (w) *w = 0;
+
+ i = _output_crtc_find(res, conn, dev);
+ if (i < 0) return EINA_FALSE;
+
+ output = calloc(1, sizeof(Ecore_Drm2_Output));
+ if (!output) return EINA_FALSE;
+
+ output->fd = dev->fd;
+ output->x = x;
+ output->y = y;
+ output->cloned = cloned;
+ output->pw = conn->mmWidth;
+ output->ph = conn->mmHeight;
+
+ switch (conn->subpixel)
+ {
+ case DRM_MODE_SUBPIXEL_UNKNOWN:
+ output->subpixel = 0; // WL_OUTPUT_SUBPIXEL_UNKNOWN
+ break;
+ case DRM_MODE_SUBPIXEL_NONE:
+ output->subpixel = 1; // WL_OUTPUT_SUBPIXEL_NONE
+ break;
+ case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
+ output->subpixel = 2; // WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB
+ break;
+ case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
+ output->subpixel = 3; // WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR
+ break;
+ case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
+ output->subpixel = 4; // WL_OUTPUT_SUBPIXEL_VERTICAL_RGB
+ break;
+ case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
+ output->subpixel = 5; // WL_OUTPUT_SUBPIXEL_VERTICAL_BGR
+ break;
+ default:
+ output->subpixel = 0;
+ break;
+ }
+
+ output->name = eina_stringshare_add(_output_name_get(conn));
+ output->make = eina_stringshare_add("unknown");
+ output->model = eina_stringshare_add("unknown");
+ output->serial = eina_stringshare_add("unknown");
+
+ output->pipe = i;
+ output->crtc_id = res->crtcs[i];
+ output->conn_id = conn->connector_id;
+ output->conn_type = conn->connector_type;
+
+ output->connected = (conn->connection == DRM_MODE_CONNECTED);
+
+ output->ocrtc = drmModeGetCrtc(dev->fd, output->crtc_id);
+
+ output->dpms = _output_dpms_property_get(dev->fd, conn);
+
+ _output_backlight_init(output, conn->connector_type);
+
+ /* TODO: gamma */
+
+ _output_modes_create(dev, output, conn);
+
+ _output_edid_find(output, conn);
+
+ if (output->connected) output->enabled = EINA_TRUE;
+
+ _output_scale_init(output, ECORE_DRM2_TRANSFORM_NORMAL, 1);
+ _output_matrix_update(output);
+
+ if (!eina_list_count(dev->outputs))
+ output->primary = EINA_TRUE;
+
+ dev->alloc.crtc |= (1 << output->crtc_id);
+ dev->alloc.conn |= (1 << output->conn_id);
+ dev->outputs = eina_list_append(dev->outputs, output);
+
+ _output_debug(output, conn);
+
+ if ((output->enabled) && (output->current_mode))
+ {
+ if (w) *w = output->current_mode->width;
+ }
+
+ return EINA_TRUE;
+}
+
+static void
+_outputs_update(Ecore_Drm2_Device *dev)
+{
+ drmModeRes *res;
+ drmModeConnector *conn;
+ uint32_t connected = 0, disconnected = 0;
+ int i = 0, x = 0, y = 0;
+
+ res = drmModeGetResources(dev->fd);
+ if (!res) return;
+
+ for (i = 0; i < res->count_connectors; i++)
+ {
+ conn = drmModeGetConnector(dev->fd, res->connectors[i]);
+ if (!conn) continue;
+
+ if (conn->connection != DRM_MODE_CONNECTED) goto next;
+
+ connected |= (1 << res->connectors[i]);
+
+ if (!(dev->alloc.conn & (1 << res->connectors[i])))
+ {
+ if (dev->outputs)
+ {
+ Ecore_Drm2_Output *last;
+
+ last = eina_list_last_data_get(dev->outputs);
+ if (last) x = last->x + last->current_mode->width;
+ else x = 0;
+ }
+ else
+ x = 0;
+
+ if (!_output_create(dev, res, conn, x, y, NULL, EINA_TRUE))
+ goto next;
+ }
+
+next:
+ drmModeFreeConnector(conn);
+ }
+
+ drmModeFreeResources(res);
+
+ disconnected = (dev->alloc.conn & ~connected);
+ if (disconnected)
+ {
+ Ecore_Drm2_Output *output;
+ Eina_List *l;
+
+ EINA_LIST_FOREACH(dev->outputs, l, output)
+ {
+ if (disconnected & (1 << output->conn_id))
+ {
+ disconnected &= ~(1 << output->conn_id);
+ output->connected = EINA_FALSE;
+ output->enabled = EINA_FALSE;
+ _output_event_send(output);
+ }
+ }
+ }
+}
+
+static void
+_cb_output_event(const char *device EINA_UNUSED, Eeze_Udev_Event event EINA_UNUSED, void *data, Eeze_Udev_Watch *watch EINA_UNUSED)
+{
+ Ecore_Drm2_Device *dev;
+
+ dev = data;
+ _outputs_update(dev);
+}
+
+static void
+_output_destroy(Ecore_Drm2_Device *dev, Ecore_Drm2_Output *output)
+{
+ dev->alloc.crtc &= ~(1 << output->crtc_id);
+ dev->alloc.conn &= ~(1 << output->conn_id);
+
+ eina_stringshare_del(output->backlight.path);
+ eina_stringshare_del(output->name);
+ eina_stringshare_del(output->make);
+ eina_stringshare_del(output->model);
+ eina_stringshare_del(output->serial);
+
+ drmModeFreeProperty(output->dpms);
+ free(output->edid.blob);
+
+ free(output);
+}
+
+EAPI Eina_Bool
+ecore_drm2_outputs_create(Ecore_Drm2_Device *device)
+{
+ drmModeConnector *conn;
+ drmModeRes *res;
+ int i = 0, x = 0, y = 0, w = 0;
+ int events = 0;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(device, EINA_FALSE);
+ EINA_SAFETY_ON_TRUE_RETURN_VAL((device->fd < 0), EINA_FALSE);
+
+ res = drmModeGetResources(device->fd);
+ if (!res) return EINA_FALSE;
+
+ device->crtcs = calloc(res->count_crtcs, sizeof(uint32_t));
+ if (!device->crtcs) goto err;
+
+ device->min.width = res->min_width;
+ device->min.height = res->min_height;
+ device->max.width = res->max_width;
+ device->max.height = res->max_height;
+
+ device->num_crtcs = res->count_crtcs;
+ memcpy(device->crtcs, res->crtcs, sizeof(uint32_t) * res->count_crtcs);
+
+ for (i = 0; i < res->count_connectors; i++)
+ {
+ conn = drmModeGetConnector(device->fd, res->connectors[i]);
+ if (!conn) continue;
+
+ if (!_output_create(device, res, conn, x, y, &w, EINA_FALSE))
+ goto next;
+
+ x += w;
+
+next:
+ drmModeFreeConnector(conn);
+ }
+
+ if (eina_list_count(device->outputs) < 1) goto err;
+
+ drmModeFreeResources(res);
+
+ events = (EEZE_UDEV_EVENT_ADD | EEZE_UDEV_EVENT_REMOVE |
+ EEZE_UDEV_EVENT_CHANGE);
+
+ device->watch =
+ eeze_udev_watch_add(EEZE_UDEV_TYPE_DRM, events,
+ _cb_output_event, device);
+
+ return EINA_TRUE;
+
+err:
+ drmModeFreeResources(res);
+ return EINA_FALSE;
+}
+
+EAPI void
+ecore_drm2_outputs_destroy(Ecore_Drm2_Device *device)
+{
+ Ecore_Drm2_Output *output;
+
+ EINA_SAFETY_ON_NULL_RETURN(device);
+
+ EINA_LIST_FREE(device->outputs, output)
+ _output_destroy(device, output);
+}
+
+EAPI const Eina_List *
+ecore_drm2_outputs_get(Ecore_Drm2_Device *device)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(device, NULL);
+ return device->outputs;
+}
+
+EAPI int
+ecore_drm2_output_dpms_get(Ecore_Drm2_Output *output)
+{
+ drmModeObjectProperties *props;
+ drmModePropertyRes *prop;
+ int val = -1;
+ unsigned int i;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, -1);
+
+ props =
+ drmModeObjectGetProperties(output->fd, output->conn_id,
+ DRM_MODE_OBJECT_CONNECTOR);
+ if (!props) return -1;
+
+ for (i = 0; i < props->count_props; i++)
+ {
+ prop = drmModeGetProperty(output->fd, props->props[i]);
+ if (!prop) continue;
+
+ if (!strcmp(prop->name, "DPMS"))
+ val = props->prop_values[i];
+
+ drmModeFreeProperty(prop);
+ }
+
+ drmModeFreeObjectProperties(props);
+
+ return val;
+}
+
+EAPI void
+ecore_drm2_output_dpms_set(Ecore_Drm2_Output *output, int level)
+{
+ EINA_SAFETY_ON_NULL_RETURN(output);
+ EINA_SAFETY_ON_TRUE_RETURN(!output->enabled);
+
+ drmModeConnectorSetProperty(output->fd, output->conn_id,
+ output->dpms->prop_id, level);
+}
+
+EAPI char *
+ecore_drm2_output_edid_get(Ecore_Drm2_Output *output)
+{
+ char *edid_str = NULL;
+ unsigned char *blob;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output->edid.blob, NULL);
+
+ blob = output->edid.blob;
+
+ edid_str = malloc((128 * 2) + 1);
+ if (edid_str)
+ {
+ unsigned int k, kk;
+ const char *hexch = "0123456789abcdef";
+
+ for (kk = 0, k = 0; k < 128; k++)
+ {
+ edid_str[kk] = hexch[(blob[k] >> 4) & 0xf];
+ edid_str[kk + 1] = hexch[blob[k] & 0xf];
+ kk += 2;
+ }
+ edid_str[kk] = 0;
+ }
+
+ return edid_str;
+}
+
+EAPI Eina_Bool
+ecore_drm2_output_backlight_get(Ecore_Drm2_Output *output)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
+ return (output->backlight.path != NULL);
+}
+
+EAPI Ecore_Drm2_Output *
+ecore_drm2_output_find(Ecore_Drm2_Device *device, int x, int y)
+{
+ Eina_List *l;
+ Ecore_Drm2_Output *output;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(device, NULL);
+
+ EINA_LIST_FOREACH(device->outputs, l, output)
+ {
+ int ox, oy, ow, oh;
+
+ if (!output->enabled) continue;
+
+ ox = output->x;
+ oy = output->y;
+ ow = output->current_mode->width;
+ oh = output->current_mode->height;
+
+ if (INSIDE(x, y, ox, oy, ow, oh))
+ return output;
+ }
+
+ return NULL;
+}
+
+EAPI void
+ecore_drm2_output_geometry_get(Ecore_Drm2_Output *output, int *x, int *y, int *w, int *h)
+{
+ EINA_SAFETY_ON_NULL_RETURN(output);
+ EINA_SAFETY_ON_TRUE_RETURN(!output->enabled);
+
+ if (x) *x = output->x;
+ if (y) *y = output->y;
+ if (w) *w = output->current_mode->width;
+ if (h) *h = output->current_mode->height;
+}
+
+EAPI unsigned int
+ecore_drm2_output_crtc_get(Ecore_Drm2_Output *output)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, 0);
+ return output->crtc_id;
+}
+
+EAPI Ecore_Drm2_Fb *
+ecore_drm2_output_next_fb_get(Ecore_Drm2_Output *output)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
+ return output->next;
+}
+
+EAPI void
+ecore_drm2_output_next_fb_set(Ecore_Drm2_Output *output, Ecore_Drm2_Fb *fb)
+{
+ EINA_SAFETY_ON_NULL_RETURN(output);
+ output->next = fb;
+}
+
+EAPI Ecore_Drm2_Fb *
+ecore_drm2_output_current_fb_get(Ecore_Drm2_Output *output)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
+ return output->current;
+}
+
+EAPI void
+ecore_drm2_output_crtc_size_get(Ecore_Drm2_Output *output, int *w, int *h)
+{
+ drmModeCrtcPtr crtc;
+
+ if (w) *w = 0;
+ if (h) *h = 0;
+
+ EINA_SAFETY_ON_NULL_RETURN(output);
+
+ crtc = drmModeGetCrtc(output->fd, output->crtc_id);
+ if (!crtc) return;
+
+ if (w) *w = crtc->width;
+ if (h) *h = crtc->height;
+
+ drmModeFreeCrtc(crtc);
+}
+
+EAPI Eina_Bool
+ecore_drm2_output_primary_get(Ecore_Drm2_Output *output)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
+ return output->primary;
+}
+
+EAPI void
+ecore_drm2_output_primary_set(Ecore_Drm2_Output *output, Eina_Bool primary)
+{
+ EINA_SAFETY_ON_NULL_RETURN(output);
+ output->primary = primary;
+}
+
+EAPI Eina_Bool
+ecore_drm2_output_enabled_get(Ecore_Drm2_Output *output)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
+ return output->enabled;
+}
+
+EAPI void
+ecore_drm2_output_enabled_set(Ecore_Drm2_Output *output, Eina_Bool enabled)
+{
+ EINA_SAFETY_ON_NULL_RETURN(output);
+
+ if (output->enabled == enabled) return;
+ output->enabled = enabled;
+
+ if (output->enabled)
+ ecore_drm2_output_dpms_set(output, DRM_MODE_DPMS_ON);
+ else
+ ecore_drm2_output_dpms_set(output, DRM_MODE_DPMS_OFF);
+
+ _output_event_send(output);
+}
+
+EAPI void
+ecore_drm2_output_physical_size_get(Ecore_Drm2_Output *output, int *w, int *h)
+{
+ if (w) *w = 0;
+ if (h) *h = 0;
+
+ EINA_SAFETY_ON_NULL_RETURN(output);
+
+ if (w) *w = output->pw;
+ if (h) *h = output->ph;
+}
+
+EAPI const Eina_List *
+ecore_drm2_output_modes_get(Ecore_Drm2_Output *output)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
+ return output->modes;
+}
+
+EAPI void
+ecore_drm2_output_mode_info_get(Ecore_Drm2_Output_Mode *mode, int *w, int *h, unsigned int *refresh, unsigned int *flags)
+{
+ if (w) *w = 0;
+ if (h) *h = 0;
+ if (refresh) *refresh = 0;
+ if (flags) *flags = 0;
+
+ EINA_SAFETY_ON_NULL_RETURN(mode);
+
+ if (w) *w = mode->width;
+ if (h) *h = mode->height;
+ if (refresh) *refresh = mode->refresh;
+ if (flags) *flags = mode->flags;
+}
+
+EAPI Eina_Bool
+ecore_drm2_output_mode_set(Ecore_Drm2_Output *output, Ecore_Drm2_Output_Mode *mode, int x, int y)
+{
+ Eina_Bool ret = EINA_TRUE;
+ unsigned int buffer = 0;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
+ EINA_SAFETY_ON_TRUE_RETURN_VAL((output->fd < 0), EINA_FALSE);
+
+ output->x = x;
+ output->y = y;
+ output->current_mode = mode;
+
+ if (mode)
+ {
+ if (output->current)
+ buffer = output->current->id;
+ else if (output->next)
+ buffer = output->next->id;
+ else
+ buffer = output->ocrtc->buffer_id;
+
+ if (drmModeSetCrtc(output->fd, output->crtc_id, buffer,
+ x, y, &output->conn_id, 1, &mode->info) < 0)
+ {
+ ERR("Failed to set Mode %dx%d for Output %s: %m",
+ mode->width, mode->height, output->name);
+ ret = EINA_FALSE;
+ }
+ }
+ else
+ {
+ if (drmModeSetCrtc(output->fd, output->crtc_id, 0,
+ 0, 0, 0, 0, NULL) < 0)
+ {
+ ERR("Failed to turn off Output %s: %m", output->name);
+ ret = EINA_FALSE;
+ }
+ }
+
+ return ret;
+}
+
+EAPI char *
+ecore_drm2_output_name_get(Ecore_Drm2_Output *output)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output->name, NULL);
+ return strdup(output->name);
+}
+
+EAPI char *
+ecore_drm2_output_model_get(Ecore_Drm2_Output *output)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output->model, NULL);
+ return strdup(output->model);
+}
+
+EAPI Eina_Bool
+ecore_drm2_output_connected_get(Ecore_Drm2_Output *output)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
+ return output->connected;
+}
+
+EAPI Eina_Bool
+ecore_drm2_output_cloned_get(Ecore_Drm2_Output *output)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
+ return output->cloned;
+}
+
+EAPI unsigned int
+ecore_drm2_output_connector_type_get(Ecore_Drm2_Output *output)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, 0);
+ return output->conn_type;
+}
+
+EAPI void
+ecore_drm2_output_resolution_get(Ecore_Drm2_Output *output, int *w, int *h, unsigned int *refresh)
+{
+ if (w) *w = 0;
+ if (h) *h = 0;
+ if (refresh) *refresh = 0;
+
+ EINA_SAFETY_ON_NULL_RETURN(output);
+ EINA_SAFETY_ON_TRUE_RETURN(!output->current_mode);
+
+ if (w) *w = output->current_mode->width;
+ if (h) *h = output->current_mode->height;
+ if (refresh) *refresh = output->current_mode->refresh;
+}
+
+EAPI Eina_Bool
+ecore_drm2_output_possible_crtc_get(Ecore_Drm2_Output *output, unsigned int crtc)
+{
+ drmModeRes *res;
+ drmModeConnector *conn;
+ drmModeEncoder *enc;
+ int i = 0, j = 0, k = 0;
+ unsigned int p = 0;
+ Eina_Bool ret = EINA_FALSE;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
+ EINA_SAFETY_ON_TRUE_RETURN_VAL((output->fd < 0), EINA_FALSE);
+
+ res = drmModeGetResources(output->fd);
+ if (!res) return EINA_FALSE;
+
+ for (; i < res->count_connectors; i++)
+ {
+ conn = drmModeGetConnector(output->fd, res->connectors[i]);
+ if (!conn) continue;
+
+ for (j = 0; j < conn->count_encoders; j++)
+ {
+ enc = drmModeGetEncoder(output->fd, conn->encoders[j]);
+ if (!enc) continue;
+
+ if (enc->crtc_id != crtc) goto next;
+
+ p = enc->possible_crtcs;
+
+ for (k = 0; k < res->count_crtcs; k++)
+ {
+ if (res->crtcs[k] != output->crtc_id) continue;
+
+ if (p & (1 << k))
+ {
+ ret = EINA_TRUE;
+ break;
+ }
+ }
+
+next:
+ drmModeFreeEncoder(enc);
+ if (ret) break;
+ }
+
+ drmModeFreeConnector(conn);
+ if (ret) break;
+ }
+
+ drmModeFreeResources(res);
+
+ return ret;
+}
diff --git a/src/lib/ecore_drm2/ecore_drm2_private.h b/src/lib/ecore_drm2/ecore_drm2_private.h
new file mode 100644
index 0000000000..23c9c77016
--- /dev/null
+++ b/src/lib/ecore_drm2/ecore_drm2_private.h
@@ -0,0 +1,185 @@
+#ifndef _ECORE_DRM2_PRIVATE_H
+# define _ECORE_DRM2_PRIVATE_H
+
+# ifdef HAVE_CONFIG_H
+# include "config.h"
+# endif
+
+# include "Ecore.h"
+# include "ecore_private.h"
+# include "Eeze.h"
+# include "Elput.h"
+# include <Ecore_Drm2.h>
+
+# include <unistd.h>
+# include <strings.h>
+# include <sys/mman.h>
+# include <fcntl.h>
+# include <ctype.h>
+
+# include <sys/ioctl.h>
+# include <xf86drm.h>
+# include <xf86drmMode.h>
+# include <drm_mode.h>
+# include <drm_fourcc.h>
+
+extern int _ecore_drm2_log_dom;
+
+# ifdef ECORE_DRM2_DEFAULT_LOG_COLOR
+# undef ECORE_DRM2_DEFAULT_LOG_COLOR
+# endif
+# define ECORE_DRM2_DEFAULT_LOG_COLOR EINA_COLOR_BLUE
+
+# ifdef ERR
+# undef ERR
+# endif
+# define ERR(...) EINA_LOG_DOM_ERR(_ecore_drm2_log_dom, __VA_ARGS__)
+
+# ifdef DBG
+# undef DBG
+# endif
+# define DBG(...) EINA_LOG_DOM_DBG(_ecore_drm2_log_dom, __VA_ARGS__)
+
+# ifdef INF
+# undef INF
+# endif
+# define INF(...) EINA_LOG_DOM_INFO(_ecore_drm2_log_dom, __VA_ARGS__)
+
+# ifdef WRN
+# undef WRN
+# endif
+# define WRN(...) EINA_LOG_DOM_WARN(_ecore_drm2_log_dom, __VA_ARGS__)
+
+# ifdef CRIT
+# undef CRIT
+# endif
+# define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_drm2_log_dom, __VA_ARGS__)
+
+typedef enum _Ecore_Drm2_Backlight_Type
+{
+ ECORE_DRM2_BACKLIGHT_RAW,
+ ECORE_DRM2_BACKLIGHT_PLATFORM,
+ ECORE_DRM2_BACKLIGHT_FIRMWARE
+} Ecore_Drm2_Backlight_Type;
+
+typedef enum _Ecore_Drm2_Transform
+{
+ ECORE_DRM2_TRANSFORM_NORMAL,
+ ECORE_DRM2_TRANSFORM_90,
+ ECORE_DRM2_TRANSFORM_180,
+ ECORE_DRM2_TRANSFORM_270,
+ ECORE_DRM2_TRANSFORM_FLIPPED,
+ ECORE_DRM2_TRANSFORM_FLIPPED_90,
+ ECORE_DRM2_TRANSFORM_FLIPPED_180,
+ ECORE_DRM2_TRANSFORM_FLIPPED_270
+} Ecore_Drm2_Transform;
+
+typedef enum _Ecore_Drm2_Rotation
+{
+ ECORE_DRM2_ROTATION_NORMAL = 1,
+ ECORE_DRM2_ROTATION_90 = 2,
+ ECORE_DRM2_ROTATION_180 = 4,
+ ECORE_DRM2_ROTATION_270 = 8,
+ ECORE_DRM2_ROTATION_REFLECT_X = 16,
+ ECORE_DRM2_ROTATION_REFLECT_Y = 32
+} Ecore_Drm2_Rotation;
+
+struct _Ecore_Drm2_Fb
+{
+ int fd;
+ int w, h;
+ int depth, bpp;
+ uint32_t id, hdl;
+ uint32_t stride, size;
+ uint32_t format;
+
+ Eina_Bool gbm : 1;
+
+ void *mmap;
+};
+
+struct _Ecore_Drm2_Output_Mode
+{
+ uint32_t flags;
+ int32_t width, height;
+ uint32_t refresh;
+ drmModeModeInfo info;
+};
+
+struct _Ecore_Drm2_Output
+{
+ Eina_Stringshare *name;
+ Eina_Stringshare *make, *model, *serial;
+
+ int fd;
+ int pipe;
+ int x, y, w, h, pw, ph;
+
+ uint32_t subpixel;
+ uint32_t crtc_id, conn_id, conn_type;
+ uint32_t scale;
+
+ struct
+ {
+ char eisa[13];
+ char monitor[13];
+ char pnp[5];
+ char serial[13];
+ unsigned char *blob; // unused when doing atomic
+ } edid;
+
+ struct
+ {
+ const char *path;
+ int value, max;
+ Ecore_Drm2_Backlight_Type type;
+ } backlight;
+
+ drmModeCrtcPtr ocrtc;
+
+ Ecore_Drm2_Fb *current, *next;
+
+ Eina_Matrix4 matrix, inverse;
+ Ecore_Drm2_Transform transform;
+
+ /* unused when doing atomic */
+ drmModePropertyPtr dpms;
+
+ Ecore_Drm2_Output_Mode *current_mode;
+ Eina_List *modes;
+
+ Eina_List *planes;
+
+ Eina_Bool connected : 1;
+ Eina_Bool primary : 1;
+ Eina_Bool cloned : 1;
+ Eina_Bool enabled : 1;
+};
+
+struct _Ecore_Drm2_Device
+{
+ Elput_Manager *em;
+
+ int fd;
+ const char *path;
+
+ int num_crtcs;
+ uint32_t *crtcs;
+
+ struct
+ {
+ uint32_t crtc, conn;
+ } alloc;
+
+ struct
+ {
+ uint32_t width, height;
+ } min, max;
+
+ Eeze_Udev_Watch *watch;
+ Ecore_Event_Handler *active_hdlr;
+
+ Eina_List *outputs;
+};
+
+#endif
diff --git a/src/lib/elementary/elm_priv.h b/src/lib/elementary/elm_priv.h
index 162915a1ce..4ba5917efc 100644
--- a/src/lib/elementary/elm_priv.h
+++ b/src/lib/elementary/elm_priv.h
@@ -10,7 +10,7 @@
#include <Ecore_Wl2.h>
#endif
#ifdef HAVE_ELEMENTARY_DRM
-#include <Ecore_Drm.h>
+#include <Ecore_Drm2.h>
#endif
#ifdef HAVE_ELEMENTARY_COCOA
/* Ecore_Cocoa is still in Beta. In Elementary, we know what we are
diff --git a/src/modules/ecore_evas/engines/drm/ecore_evas_drm.c b/src/modules/ecore_evas/engines/drm/ecore_evas_drm.c
index 8b5e4047cc..e14254b381 100644
--- a/src/modules/ecore_evas/engines/drm/ecore_evas_drm.c
+++ b/src/modules/ecore_evas/engines/drm/ecore_evas_drm.c
@@ -2,8 +2,6 @@
# include <config.h>
#endif
-#include <stdlib.h>
-#include <string.h>
#include <Eina.h>
#include <Ecore.h>
#include "ecore_private.h"
@@ -12,12 +10,12 @@
#include <Ecore_Evas.h>
#include "ecore_evas_private.h"
#include "ecore_evas_drm.h"
-#include <Ecore_Drm.h>
+#include <Ecore_Drm2.h>
#include <Evas_Engine_Drm.h>
+#include <drm_fourcc.h>
#ifdef BUILD_ECORE_EVAS_GL_DRM
# include <Evas_Engine_GL_Drm.h>
-# include <gbm.h>
# include <dlfcn.h>
#endif
@@ -43,662 +41,252 @@
# endif
#endif /* ! _WIN32 */
-typedef struct _Ecore_Evas_Engine_Drm_Data Ecore_Evas_Engine_Drm_Data;
-
-struct _Ecore_Evas_Engine_Drm_Data
-{
- int w, h;
-};
-
-/* local function prototypes */
-static int _ecore_evas_drm_init(const char *device);
-static int _ecore_evas_drm_shutdown(void);
-static Ecore_Evas_Interface_Drm *_ecore_evas_drm_interface_new(void);
-static void _ecore_evas_drm_free(Ecore_Evas *ee);
-static void _ecore_evas_drm_callback_resize_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
-static void _ecore_evas_drm_callback_move_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
-static void _ecore_evas_drm_callback_focus_in_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
-static void _ecore_evas_drm_callback_focus_out_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
-static void _ecore_evas_drm_callback_mouse_in_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
-static void _ecore_evas_drm_callback_mouse_out_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
-static void _ecore_evas_drm_delete_request_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
-static void _ecore_evas_drm_move(Ecore_Evas *ee, int x, int y);
-static void _ecore_evas_drm_resize(Ecore_Evas *ee, int w, int h);
-static void _ecore_evas_drm_move_resize(Ecore_Evas *ee, int x, int y, int w, int h);
-static void _ecore_evas_drm_rotation_set(Ecore_Evas *ee, int rotation, int resize);
-static void _ecore_evas_drm_show(Ecore_Evas *ee);
-static void _ecore_evas_drm_hide(Ecore_Evas *ee);
-static void _ecore_evas_drm_title_set(Ecore_Evas *ee, const char *title);
-static void _ecore_evas_drm_name_class_set(Ecore_Evas *ee, const char *n, const char *c);
-static void _ecore_evas_drm_size_min_set(Ecore_Evas *ee, int w, int h);
-static void _ecore_evas_drm_size_max_set(Ecore_Evas *ee, int w, int h);
-static void _ecore_evas_drm_size_base_set(Ecore_Evas *ee, int w, int h);
-static void _ecore_evas_drm_size_step_set(Ecore_Evas *ee, int w, int h);
-static void _ecore_evas_drm_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y);
-static void _ecore_evas_drm_object_cursor_unset(Ecore_Evas *ee);
-static void _ecore_evas_drm_layer_set(Ecore_Evas *ee, int layer);
-static void _ecore_evas_drm_iconified_set(Ecore_Evas *ee, Eina_Bool on);
-static void _ecore_evas_drm_borderless_set(Ecore_Evas *ee, Eina_Bool on);
-static void _ecore_evas_drm_maximized_set(Ecore_Evas *ee, Eina_Bool on);
-static void _ecore_evas_drm_fullscreen_set(Ecore_Evas *ee, Eina_Bool on);
-static void _ecore_evas_drm_withdrawn_set(Ecore_Evas *ee, Eina_Bool on);
-static void _ecore_evas_drm_ignore_events_set(Ecore_Evas *ee, int ignore);
-static void _ecore_evas_drm_alpha_set(Ecore_Evas *ee, int alpha);
-static void _ecore_evas_drm_transparent_set(Ecore_Evas *ee, int transparent);
-static void _ecore_evas_drm_aspect_set(Ecore_Evas *ee, double aspect);
-
-static int _ecore_evas_drm_render(Ecore_Evas *ee);
-static void _ecore_evas_drm_render_updates(void *data, Evas *evas EINA_UNUSED, void *event);
-static int _ecore_evas_drm_render_updates_process(Ecore_Evas *ee, Eina_List *updates);
-
-static void _ecore_evas_drm_screen_geometry_get(const Ecore_Evas *ee EINA_UNUSED, int *x, int *y, int *w, int *h);
-static void _ecore_evas_drm_pointer_xy_get(const Ecore_Evas *ee, Evas_Coord *x, Evas_Coord *y);
-Eina_Bool _ecore_evas_drm_pointer_warp(const Ecore_Evas *ee EINA_UNUSED, Evas_Coord x, Evas_Coord y);
-
-/* local variables */
-static int _ecore_evas_init_count = 0;
-static Ecore_Drm_Device *dev = NULL;
-
-static Ecore_Evas_Engine_Func _ecore_evas_drm_engine_func =
+typedef struct _Ecore_Evas_Engine_Drm_Data
{
- _ecore_evas_drm_free,
- _ecore_evas_drm_callback_resize_set,
- _ecore_evas_drm_callback_move_set,
- NULL, //void (*fn_callback_show_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
- NULL, //void (*fn_callback_hide_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
- _ecore_evas_drm_delete_request_set,
- NULL, //void (*fn_callback_destroy_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
- _ecore_evas_drm_callback_focus_in_set,
- _ecore_evas_drm_callback_focus_out_set,
- _ecore_evas_drm_callback_mouse_in_set,
- _ecore_evas_drm_callback_mouse_out_set,
- NULL, //void (*fn_callback_sticky_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
- NULL, //void (*fn_callback_unsticky_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
- NULL, //void (*fn_callback_pre_render_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
- NULL, //void (*fn_callback_post_render_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
- _ecore_evas_drm_move,
- NULL, //void (*fn_managed_move) (Ecore_Evas *ee, int x, int y);
- _ecore_evas_drm_resize,
- _ecore_evas_drm_move_resize,
- _ecore_evas_drm_rotation_set,
- NULL, //void (*fn_shaped_set) (Ecore_Evas *ee, int shaped);
- _ecore_evas_drm_show,
- _ecore_evas_drm_hide,
- NULL, //void (*fn_raise) (Ecore_Evas *ee);
- NULL, //void (*fn_lower) (Ecore_Evas *ee);
- NULL, //void (*fn_activate) (Ecore_Evas *ee);
- _ecore_evas_drm_title_set,
- _ecore_evas_drm_name_class_set,
- _ecore_evas_drm_size_min_set,
- _ecore_evas_drm_size_max_set,
- _ecore_evas_drm_size_base_set,
- _ecore_evas_drm_size_step_set,
- _ecore_evas_drm_object_cursor_set,
- _ecore_evas_drm_object_cursor_unset,
- _ecore_evas_drm_layer_set,
- NULL, //void (*fn_focus_set) (Ecore_Evas *ee, Eina_Bool on);
- _ecore_evas_drm_iconified_set,
- _ecore_evas_drm_borderless_set,
- NULL, //void (*fn_override_set) (Ecore_Evas *ee, Eina_Bool on);
- _ecore_evas_drm_maximized_set,
- _ecore_evas_drm_fullscreen_set,
- NULL, //void (*fn_avoid_damage_set) (Ecore_Evas *ee, int on);
- _ecore_evas_drm_withdrawn_set,
- NULL, //void (*fn_sticky_set) (Ecore_Evas *ee, Eina_Bool on);
- _ecore_evas_drm_ignore_events_set,
- _ecore_evas_drm_alpha_set,
- _ecore_evas_drm_transparent_set,
- NULL, //void (*fn_profiles_set) (Ecore_Evas *ee, const char **profiles, int count);
- NULL, //void (*fn_profile_set) (Ecore_Evas *ee, const char *profile);
+ int fd;
+ int cw, ch;
+ int clockid;
+ int x, y, w, h;
+ int depth, bpp;
+ unsigned int format;
+ Ecore_Drm2_Device *dev;
+ Ecore_Drm2_Output *output;
+} Ecore_Evas_Engine_Drm_Data;
- NULL, //void (*fn_window_group_set) (Ecore_Evas *ee, const Ecore_Evas *ee_group);
- _ecore_evas_drm_aspect_set,
- NULL, //void (*fn_urgent_set) (Ecore_Evas *ee, Eina_Bool on);
- NULL, //void (*fn_modal_set) (Ecore_Evas *ee, Eina_Bool on);
- NULL, //void (*fn_demands_attention_set) (Ecore_Evas *ee, Eina_Bool on);
- NULL, //void (*fn_focus_skip_set) (Ecore_Evas *ee, Eina_Bool on);
-
- _ecore_evas_drm_render,
-
- _ecore_evas_drm_screen_geometry_get,
- NULL, //void (*fn_screen_dpi_get) (const Ecore_Evas *ee, int *xdpi, int *ydpi);
- NULL, //void (*fn_msg_parent_send) (Ecore_Evas *ee, int maj, int min, void *data, int size);
- NULL, //void (*fn_msg_send) (Ecore_Evas *ee, int maj, int min, void *data, int size);
-
- _ecore_evas_drm_pointer_xy_get,
- _ecore_evas_drm_pointer_warp,
-
- NULL, // wm_rot_preferred_rotation_set
- NULL, // wm_rot_available_rotations_set
- NULL, // wm_rot_manual_rotation_done_set
- NULL, // wm_rot_manual_rotation_done
-
- NULL, // aux_hints_set
+static int _drm_init_count = 0;
- NULL, // fn_animator_register
- NULL // fn_animator_unregister
-};
-
-EAPI Ecore_Evas *
-ecore_evas_drm_new_internal(const char *device, unsigned int parent EINA_UNUSED, int x, int y, int w, int h)
+static int
+_ecore_evas_drm_init(Ecore_Evas_Engine_Drm_Data *edata, const char *device)
{
- Ecore_Evas *ee;
- Evas_Engine_Info_Drm *einfo;
- Ecore_Evas_Interface_Drm *iface;
- Ecore_Evas_Engine_Drm_Data *edata;
- int method;
+ if (++_drm_init_count != 1) return _drm_init_count;
- /* try to find the evas drm engine */
- if (!(method = evas_render_method_lookup("drm")))
+ if (!ecore_drm2_init())
{
- ERR("Render method lookup failed for Drm");
- return NULL;
+ ERR("Failed to init Ecore_Drm2 library");
+ goto init_err;
}
- /* try to init drm */
- if (_ecore_evas_drm_init(device) < 1) return NULL;
+ if (!device) device = "seat0";
- if (!ecore_drm_device_software_setup(dev))
+ edata->dev = ecore_drm2_device_find(device, 0);
+ if (!edata->dev)
{
- ERR("Could not setup device for software");
- goto soft_err;
+ ERR("Failed to create device");
+ goto dev_err;
}
- /* try to allocate space for new ecore_evas */
- if (!(ee = calloc(1, sizeof(Ecore_Evas))))
+ edata->fd = ecore_drm2_device_open(edata->dev);
+ if (edata->fd < 0)
{
- ERR("Failed to allocate space for new Ecore_Evas");
- goto ee_err;
+ ERR("Failed to open device");
+ goto open_err;
}
- if (!(edata = calloc(1, sizeof(Ecore_Evas_Engine_Drm_Data))))
- {
- ERR("Failed to allocate space for new Ecore_Evas_Engine_Data");
- free(ee);
- goto ee_err;
- }
-
- ee->engine.data = edata;
-
- ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS);
-
- ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_evas_drm_engine_func;
+ edata->clockid = ecore_drm2_device_clock_id_get(edata->dev);
+ ecore_drm2_device_cursor_size_get(edata->dev, &edata->cw, &edata->ch);
- iface = _ecore_evas_drm_interface_new();
- ee->engine.ifaces = eina_list_append(ee->engine.ifaces, iface);
-
- /* set some engine properties */
- ee->driver = "drm";
- if (device) ee->name = strdup(device);
- else
- ee->name = strdup(ecore_drm_device_name_get(dev));
-
- if (w < 1) w = 1;
- if (h < 1) h = 1;
-
- ee->x = ee->req.x = x;
- ee->y = ee->req.y = y;
- ee->w = ee->req.w = w;
- ee->h = ee->req.h = h;
-
- ee->prop.max.w = 32767;
- ee->prop.max.h = 32767;
- ee->prop.layer = 4;
- ee->prop.request_pos = 0;
- ee->prop.sticky = 0;
- ee->prop.withdrawn = EINA_TRUE;
- ee->alpha = EINA_FALSE;
-
- ee->can_async_render = 1;
- if (getenv("ECORE_EVAS_FORCE_SYNC_RENDER"))
- ee->can_async_render = 0;
-
- /* try to initialize evas */
- ee->evas = evas_new();
- evas_data_attach_set(ee->evas, ee);
- evas_output_method_set(ee->evas, method);
-
- if ((ee->rotation == 90) || (ee->rotation == 270))
+ if (!ecore_drm2_outputs_create(edata->dev))
{
- evas_output_size_set(ee->evas, h, w);
- evas_output_viewport_set(ee->evas, 0, 0, h, w);
- }
- else
- {
- evas_output_size_set(ee->evas, w, h);
- evas_output_viewport_set(ee->evas, 0, 0, w, h);
- }
-
- if (ee->can_async_render)
- evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_POST,
- _ecore_evas_drm_render_updates, ee);
-
- if ((einfo = (Evas_Engine_Info_Drm *)evas_engine_info_get(ee->evas)))
- {
- Ecore_Drm_Output *output;
- char *num;
-
- einfo->info.depth = 32; // FIXME
- einfo->info.destination_alpha = ee->alpha;
- einfo->info.rotation = ee->rotation;
-
- if ((num = getenv("EVAS_DRM_VSYNC")))
- {
- if (!atoi(num))
- einfo->info.vsync = EINA_FALSE;
- else
- einfo->info.vsync = EINA_TRUE;
- }
- else
- einfo->info.vsync = EINA_TRUE;
-
- einfo->info.use_hw_accel = EINA_FALSE;
- einfo->info.dev = dev;
-
- if ((output = ecore_drm_device_output_find(dev, x, y)))
- {
- einfo->info.conn_id = ecore_drm_output_connector_id_get(output);
- einfo->info.crtc_id = ecore_drm_output_crtc_id_get(output);
- einfo->info.buffer_id = ecore_drm_output_crtc_buffer_get(output);
- }
-
- if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
- {
- ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
- goto eng_err;
- }
- }
- else
- {
- ERR("Failed to get Evas Engine Info for '%s'", ee->driver);
- goto eng_err;
+ ERR("Could not create outputs");
+ goto output_err;
}
- ee->prop.window = einfo->info.buffer_id;
-
- _ecore_evas_register(ee);
- ecore_evas_input_event_register(ee);
-
- ecore_drm_device_window_set(dev, ee->prop.window);
- ecore_event_window_register(ee->prop.window, ee, ee->evas,
- (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process,
- (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process,
- (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process,
- (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process);
-
- /* NB: Send a fake mouse move event so that E-Wl gets an updated
- * pointer position, else we end up with buggers (ref: T2854) */
- {
- Ecore_Event_Mouse_Move *ev;
+ edata->output = ecore_drm2_output_find(edata->dev, edata->x, edata->y);
+ if (!edata->output)
+ WRN("Could not find output at %d %d", edata->x, edata->y);
- ev = calloc(1, sizeof(Ecore_Event_Mouse_Move));
- ev->window = ee->prop.window;
- ev->event_window = ee->prop.window;
- ev->root_window = ee->prop.window;
- ev->same_screen = 1;
+ ecore_event_evas_init();
- ecore_drm_device_pointer_xy_get(dev, &ev->x, &ev->y);
+ return _drm_init_count;
- ev->root.x = ev->x;
- ev->root.y = ev->y;
+output_err:
+ ecore_drm2_device_close(edata->dev);
+open_err:
+ ecore_drm2_device_free(edata->dev);
+dev_err:
+ ecore_drm2_shutdown();
+init_err:
+ return --_drm_init_count;
+}
- ecore_event_evas_mouse_move(NULL, ECORE_EVENT_MOUSE_MOVE, ev);
- }
+static int
+_ecore_evas_drm_shutdown(Ecore_Evas_Engine_Drm_Data *edata)
+{
+ if (--_drm_init_count != 0) return _drm_init_count;
- return ee;
+ ecore_drm2_outputs_destroy(edata->dev);
+ ecore_drm2_device_close(edata->dev);
+ ecore_drm2_device_free(edata->dev);
+ ecore_drm2_shutdown();
+ ecore_event_evas_shutdown();
-eng_err:
- ecore_evas_free(ee);
-soft_err:
-ee_err:
- _ecore_evas_drm_shutdown();
- return NULL;
+ return _drm_init_count;
}
-#ifdef BUILD_ECORE_EVAS_GL_DRM
-EAPI Ecore_Evas *
-ecore_evas_gl_drm_new_internal(const char *device, unsigned int parent EINA_UNUSED, int x, int y, int w, int h)
+static void
+_drm_free(Ecore_Evas *ee)
{
- Ecore_Evas *ee;
- Evas_Engine_Info_GL_Drm *einfo;
- Ecore_Evas_Interface_Drm *iface;
Ecore_Evas_Engine_Drm_Data *edata;
- int method;
- uint32_t format = GBM_FORMAT_XRGB8888;
- uint32_t flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
- char *num;
-
- /* try to find the evas drm engine */
- if (!(method = evas_render_method_lookup("gl_drm")))
- {
- ERR("Render method lookup failed for GL Drm");
- return NULL;
- }
-
- /* try to init drm */
- if (_ecore_evas_drm_init(device) < 1) return NULL;
-
- /* try to load gl libary, gbm libary */
- /* Typically, gbm loads the dri driver However some versions of Mesa
- * do not have libglapi symbols linked in the driver. Because of this,
- * using hardware accel for our drm code Could fail with a
- * message that the driver could not load. Let's be proactive and
- * work around this for the user by preloading the glapi library */
- dlopen("libglapi.so.0", (RTLD_LAZY | RTLD_GLOBAL));
- if (dlerror())
- {
- _ecore_evas_drm_shutdown();
- return NULL;
- }
-
- /* try to allocate space for new ecore_evas */
- if (!(ee = calloc(1, sizeof(Ecore_Evas))))
- {
- ERR("Failed to allocate space for new Ecore_Evas");
- goto ee_err;
- }
-
- if (!(edata = calloc(1, sizeof(Ecore_Evas_Engine_Drm_Data))))
- {
- ERR("Failed to allocate space for new Ecore_Evas_Engine_Data");
- free(ee);
- goto ee_err;
- }
- ee->engine.data = edata;
-
- ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS);
-
- ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_evas_drm_engine_func;
-
- iface = _ecore_evas_drm_interface_new();
- ee->engine.ifaces = eina_list_append(ee->engine.ifaces, iface);
-
- /* set some engine properties */
- ee->driver = "gl_drm";
- if (device) ee->name = strdup(device);
- else
- ee->name = strdup(ecore_drm_device_name_get(dev));
-
- if (w < 1) w = 1;
- if (h < 1) h = 1;
-
- ee->x = ee->req.x = x;
- ee->y = ee->req.y = y;
- ee->w = ee->req.w = w;
- ee->h = ee->req.h = h;
-
- ee->prop.max.w = 32767;
- ee->prop.max.h = 32767;
- ee->prop.layer = 4;
- ee->prop.request_pos = 0;
- ee->prop.sticky = 0;
- ee->prop.withdrawn = EINA_TRUE;
- ee->alpha = EINA_FALSE;
+ ecore_evas_input_event_unregister(ee);
- /* NB: Disable async rendering for egl. Not Applicable as EGL is sync only */
- ee->can_async_render = 0;
- /* if (getenv("ECORE_EVAS_FORCE_SYNC_RENDER")) */
- /* ee->can_async_render = 0; */
+ edata = ee->engine.data;
+ _ecore_evas_drm_shutdown(edata);
+ free(edata);
+}
- /* try to initialize evas */
- ee->evas = evas_new();
- evas_data_attach_set(ee->evas, ee);
- evas_output_method_set(ee->evas, method);
+static int
+_drm_render_updates_process(Ecore_Evas *ee, Eina_List *updates)
+{
+ int rend = 0;
- if ((ee->rotation == 90) || (ee->rotation == 270))
+ if ((ee->visible) && (updates))
{
- evas_output_size_set(ee->evas, h, w);
- evas_output_viewport_set(ee->evas, 0, 0, h, w);
+ _ecore_evas_idle_timeout_update(ee);
+ rend = 1;
}
else
- {
- evas_output_size_set(ee->evas, w, h);
- evas_output_viewport_set(ee->evas, 0, 0, w, h);
- }
-
- if (ee->can_async_render)
- evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_POST,
- _ecore_evas_drm_render_updates, ee);
-
- if ((einfo = (Evas_Engine_Info_GL_Drm *)evas_engine_info_get(ee->evas)))
- {
- Ecore_Drm_Output *output;
-
- einfo->info.depth = 32;
- einfo->info.destination_alpha = ee->alpha;
- einfo->info.rotation = ee->rotation;
-
- if ((num = getenv("EVAS_DRM_VSYNC")))
- {
- if (!atoi(num))
- einfo->info.vsync = EINA_FALSE;
- else
- einfo->info.vsync = EINA_TRUE;
- }
- else
- einfo->info.vsync = EINA_TRUE;
-
- einfo->info.dev = dev;
- einfo->info.format = format;
- einfo->info.flags = flags;
-
- if ((output = ecore_drm_device_output_find(dev, x, y)))
- {
- einfo->info.conn_id = ecore_drm_output_connector_id_get(output);
- einfo->info.crtc_id = ecore_drm_output_crtc_id_get(output);
- einfo->info.buffer_id = ecore_drm_output_crtc_buffer_get(output);
- }
+ evas_norender(ee->evas);
- if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
- {
- ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
- goto eng_err;
- }
- }
- else
- {
- ERR("Failed to get Evas Engine Info for '%s'", ee->driver);
- goto eng_err;
- }
+ if (ee->func.fn_post_render) ee->func.fn_post_render(ee);
- ee->prop.window = einfo->info.buffer_id;
+ return rend;
+}
- _ecore_evas_register(ee);
- ecore_evas_input_event_register(ee);
+static void
+_drm_render_updates(void *data, Evas *evas EINA_UNUSED, void *event)
+{
+ Evas_Event_Render_Post *ev;
+ Ecore_Evas *ee;
- ecore_drm_device_window_set(dev, ee->prop.window);
- ecore_event_window_register(ee->prop.window, ee, ee->evas,
- (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process,
- (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process,
- (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process,
- (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process);
+ ev = event;
+ if (!ev) return;
- return ee;
+ ee = data;
+ if (!ee) return;
-eng_err:
- ecore_evas_free(ee);
-ee_err:
- _ecore_evas_drm_shutdown();
- return NULL;
+ ee->in_async_render = EINA_FALSE;
+ _drm_render_updates_process(ee, ev->updated_area);
}
-#endif
-/* local functions */
static int
-_ecore_evas_drm_init(const char *device)
+_drm_render(Ecore_Evas *ee)
{
- if (++_ecore_evas_init_count != 1) return _ecore_evas_init_count;
+ int rend = 0;
+ Eina_List *l;
+ Ecore_Evas *ee2;
- /* try to init ecore_drm */
- if (!ecore_drm_init())
- {
- ERR("Could not initialize Ecore_Drm");
- return --_ecore_evas_init_count;
- }
+ if (ee->in_async_render) return 0;
- /* try to find the device */
- if (!(dev = ecore_drm_device_find(device, NULL)))
+ if (!ee->visible)
{
- ERR("Could not find drm device with name: %s. Falling back to default device.", device);
-
- /* if we already passed in NULL as device name, then no point in
- * calling the find function below with no name either */
- if (!device) goto dev_err;
-
- /* try getting the default drm device */
- if (!(dev = ecore_drm_device_find(NULL, NULL)))
- goto dev_err;
+ evas_norender(ee->evas);
+ return 0;
}
- if (!ecore_drm_launcher_connect(dev))
+ EINA_LIST_FOREACH(ee->sub_ecore_evas, l, ee2)
{
- ERR("Could not connect DRM launcher");
- goto launcher_err;
+ if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2);
+ if (ee2->engine.func->fn_render)
+ rend |= ee2->engine.func->fn_render(ee2);
+ if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2);
}
- /* try to open the graphics card */
- if (!ecore_drm_device_open(dev))
- {
- ERR("Could not open drm device");
- goto dev_open_err;
- }
+ if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee);
- /* try to create sprites */
- if (!ecore_drm_sprites_create(dev))
+ if (!ee->can_async_render)
{
- ERR("Could not create sprites");
- goto sprite_err;
- }
+ Eina_List *updates;
- /* try to create outputs */
- if (!ecore_drm_outputs_create(dev))
- {
- ERR("Could not create outputs");
- goto output_err;
+ updates = evas_render_updates(ee->evas);
+ rend = _drm_render_updates_process(ee, updates);
+ evas_render_updates_free(updates);
}
-
- /* try to create inputs */
- if (!ecore_drm_inputs_create(dev))
+ else if (evas_render_async(ee->evas))
{
- ERR("Could not create inputs");
- goto input_err;
+ ee->in_async_render = EINA_TRUE;
+ rend = 1;
}
- ecore_event_evas_init();
-
- return _ecore_evas_init_count;
-
-output_err:
- ecore_drm_inputs_destroy(dev);
-input_err:
- ecore_drm_sprites_destroy(dev);
-sprite_err:
- ecore_drm_device_close(dev);
-dev_open_err:
- ecore_drm_launcher_disconnect(dev);
- ecore_drm_device_free(dev);
- dev = NULL;
-launcher_err:
-dev_err:
- ecore_drm_shutdown();
- return --_ecore_evas_init_count;
+ return rend;
}
-static int
-_ecore_evas_drm_shutdown(void)
+static void
+_drm_screen_geometry_get(const Ecore_Evas *ee, int *x, int *y, int *w, int *h)
{
- Ecore_Drm_Output *output;
-
- if (--_ecore_evas_init_count != 0) return _ecore_evas_init_count;
-
- ecore_drm_inputs_destroy(dev);
-
- EINA_LIST_FREE(dev->outputs, output)
- ecore_drm_output_free(output);
-
- ecore_drm_sprites_destroy(dev);
- ecore_drm_device_close(dev);
- ecore_drm_launcher_disconnect(dev);
- ecore_drm_device_free(dev);
- ecore_drm_shutdown();
- dev = NULL;
-
- ecore_event_evas_shutdown();
+ Ecore_Evas_Engine_Drm_Data *edata;
- return _ecore_evas_init_count;
+ edata = ee->engine.data;
+ ecore_drm2_output_geometry_get(edata->output, x, y, w, h);
}
-static Ecore_Evas_Interface_Drm *
-_ecore_evas_drm_interface_new(void)
+static void
+_drm_pointer_xy_get(const Ecore_Evas *ee, Evas_Coord *x, Evas_Coord *y)
{
- Ecore_Evas_Interface_Drm *iface;
-
- if (!(iface = calloc(1, sizeof(Ecore_Evas_Interface_Drm))))
- return NULL;
-
- iface->base.name = "drm";
- iface->base.version = 1;
+ Ecore_Evas_Engine_Drm_Data *edata;
- return iface;
+ edata = ee->engine.data;
+ ecore_drm2_device_pointer_xy_get(edata->dev, x, y);
}
-/* local ecore_evas functions */
-static void
-_ecore_evas_drm_free(Ecore_Evas *ee)
+static Eina_Bool
+_drm_pointer_warp(const Ecore_Evas *ee, Evas_Coord x, Evas_Coord y)
{
- Ecore_Evas_Engine_Drm_Data *data;
+ Ecore_Evas_Engine_Drm_Data *edata;
- data = ee->engine.data;
- ecore_evas_input_event_unregister(ee);
- free(data);
- _ecore_evas_drm_shutdown();
+ edata = ee->engine.data;
+ ecore_drm2_device_pointer_warp(edata->dev, x, y);
+ return EINA_TRUE;
}
static void
-_ecore_evas_drm_callback_resize_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
+_drm_show(Ecore_Evas *ee)
{
- ee->func.fn_resize = func;
-}
+ if ((!ee) || (ee->visible)) return;
-static void
-_ecore_evas_drm_callback_move_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
-{
- ee->func.fn_move = func;
-}
+ ee->should_be_visible = 1;
-static void
-_ecore_evas_drm_callback_focus_in_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
-{
- ee->func.fn_focus_in = func;
-}
+ if (ee->prop.avoid_damage)
+ _drm_render(ee);
-static void
-_ecore_evas_drm_callback_focus_out_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
-{
- ee->func.fn_focus_out = func;
-}
+ if (ee->prop.override)
+ {
+ ee->prop.withdrawn = EINA_FALSE;
+ if (ee->func.fn_state_change) ee->func.fn_state_change(ee);
+ }
-static void
-_ecore_evas_drm_callback_mouse_in_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
-{
- ee->func.fn_mouse_in = func;
-}
+ if (ee->visible) return;
-static void
-_ecore_evas_drm_callback_mouse_out_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
-{
- ee->func.fn_mouse_out = func;
+ ee->visible = 1;
+ if (ee->prop.fullscreen)
+ {
+ evas_focus_in(ee->evas);
+ if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee);
+ }
+ if (ee->func.fn_show) ee->func.fn_show(ee);
}
static void
-_ecore_evas_drm_delete_request_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
+_drm_hide(Ecore_Evas *ee)
{
- ee->func.fn_delete_request = func;
+ if ((!ee) || (!ee->visible)) return;
+
+ if (ee->prop.override)
+ {
+ ee->prop.withdrawn = EINA_TRUE;
+ if (ee->func.fn_state_change) ee->func.fn_state_change(ee);
+ }
+
+ if (!ee->visible) return;
+
+ ee->visible = 0;
+ ee->should_be_visible = 0;
+ evas_sync(ee->evas);
+ if (ee->func.fn_hide) ee->func.fn_hide(ee);
}
static void
-_ecore_evas_drm_move(Ecore_Evas *ee, int x, int y)
+_drm_move(Ecore_Evas *ee, int x, int y)
{
ee->req.x = x;
ee->req.y = y;
@@ -709,7 +297,7 @@ _ecore_evas_drm_move(Ecore_Evas *ee, int x, int y)
}
static void
-_ecore_evas_drm_resize(Ecore_Evas *ee, int w, int h)
+_drm_resize(Ecore_Evas *ee, int w, int h)
{
ee->req.w = w;
ee->req.h = h;
@@ -722,16 +310,16 @@ _ecore_evas_drm_resize(Ecore_Evas *ee, int w, int h)
}
static void
-_ecore_evas_drm_move_resize(Ecore_Evas *ee, int x, int y, int w, int h)
+_drm_move_resize(Ecore_Evas *ee, int x, int y, int w, int h)
{
if ((ee->x != x) || (ee->y != y))
- _ecore_evas_drm_move(ee, x, y);
+ _drm_move(ee, x, y);
if ((ee->w != w) || (ee->h != h))
- _ecore_evas_drm_resize(ee, w, h);
+ _drm_resize(ee, w, h);
}
static void
-_ecore_evas_drm_rotation_set(Ecore_Evas *ee, int rotation, int resize EINA_UNUSED)
+_drm_rotation_set(Ecore_Evas *ee, int rotation, int resize EINA_UNUSED)
{
Evas_Engine_Info_Drm *einfo;
@@ -740,57 +328,11 @@ _ecore_evas_drm_rotation_set(Ecore_Evas *ee, int rotation, int resize EINA_UNUSE
if (!einfo) return;
einfo->info.rotation = rotation;
if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
- ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+ ERR("evas_engine_info_set() for engine '%s' failed", ee->driver);
}
static void
-_ecore_evas_drm_show(Ecore_Evas *ee)
-{
- if ((!ee) || (ee->visible)) return;
-
- ee->should_be_visible = 1;
-
- if (ee->prop.avoid_damage)
- _ecore_evas_drm_render(ee);
-
- if (ee->prop.override)
- {
- ee->prop.withdrawn = EINA_FALSE;
- if (ee->func.fn_state_change) ee->func.fn_state_change(ee);
- }
-
- if (ee->visible) return;
-
- ee->visible = 1;
- if (ee->prop.fullscreen)
- {
- evas_focus_in(ee->evas);
- if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee);
- }
- if (ee->func.fn_show) ee->func.fn_show(ee);
-}
-
-static void
-_ecore_evas_drm_hide(Ecore_Evas *ee)
-{
- if ((!ee) || (!ee->visible)) return;
-
- if (ee->prop.override)
- {
- ee->prop.withdrawn = EINA_TRUE;
- if (ee->func.fn_state_change) ee->func.fn_state_change(ee);
- }
-
- if (!ee->visible) return;
-
- ee->visible = 0;
- ee->should_be_visible = 0;
- evas_sync(ee->evas);
- if (ee->func.fn_hide) ee->func.fn_hide(ee);
-}
-
-static void
-_ecore_evas_drm_title_set(Ecore_Evas *ee, const char *title)
+_drm_title_set(Ecore_Evas *ee, const char *title)
{
if (eina_streq(ee->prop.title, title)) return;
if (ee->prop.title) free(ee->prop.title);
@@ -799,7 +341,7 @@ _ecore_evas_drm_title_set(Ecore_Evas *ee, const char *title)
}
static void
-_ecore_evas_drm_name_class_set(Ecore_Evas *ee, const char *n, const char *c)
+_drm_name_class_set(Ecore_Evas *ee, const char *n, const char *c)
{
if (!eina_streq(ee->prop.name, n))
{
@@ -807,6 +349,7 @@ _ecore_evas_drm_name_class_set(Ecore_Evas *ee, const char *n, const char *c)
ee->prop.name = NULL;
if (n) ee->prop.name = strdup(n);
}
+
if (!eina_streq(ee->prop.clas, c))
{
if (ee->prop.clas) free(ee->prop.clas);
@@ -816,67 +359,54 @@ _ecore_evas_drm_name_class_set(Ecore_Evas *ee, const char *n, const char *c)
}
static void
-_ecore_evas_drm_size_min_set(Ecore_Evas *ee, int w, int h)
+_drm_size_min_set(Ecore_Evas *ee, int w, int h)
{
- if (w < 0) w = 0;
- if (h < 0) h = 0;
if ((ee->prop.min.w == w) && (ee->prop.min.h == h)) return;
ee->prop.min.w = w;
ee->prop.min.h = h;
}
static void
-_ecore_evas_drm_size_max_set(Ecore_Evas *ee, int w, int h)
+_drm_size_max_set(Ecore_Evas *ee, int w, int h)
{
- if (w < 0) w = 0;
- if (h < 0) h = 0;
if ((ee->prop.max.w == w) && (ee->prop.max.h == h)) return;
ee->prop.max.w = w;
ee->prop.max.h = h;
}
static void
-_ecore_evas_drm_size_base_set(Ecore_Evas *ee, int w, int h)
+_drm_size_base_set(Ecore_Evas *ee, int w, int h)
{
- if (w < 0) w = 0;
- if (h < 0) h = 0;
if ((ee->prop.base.w == w) && (ee->prop.base.h == h)) return;
ee->prop.base.w = w;
ee->prop.base.h = h;
}
static void
-_ecore_evas_drm_size_step_set(Ecore_Evas *ee, int w, int h)
+_drm_size_step_set(Ecore_Evas *ee, int w, int h)
{
- if (w < 0) w = 0;
- if (h < 0) h = 0;
if ((ee->prop.step.w == w) && (ee->prop.step.h == h)) return;
ee->prop.step.w = w;
ee->prop.step.h = h;
}
static void
-_ecore_evas_drm_object_cursor_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+_drm_object_cursor_del(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
{
Ecore_Evas *ee;
- if ((ee = data)) ee->prop.cursor.object = NULL;
-}
-
-static void
-_ecore_evas_drm_object_cursor_unset(Ecore_Evas *ee)
-{
- evas_object_event_callback_del_full(ee->prop.cursor.object, EVAS_CALLBACK_DEL, _ecore_evas_drm_object_cursor_del, ee);
+ ee = data;
+ if (ee) ee->prop.cursor.object = NULL;
}
static void
-_ecore_evas_drm_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y)
+_drm_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y)
{
- int x, y;
Evas_Object *old;
+ int x, y;
old = ee->prop.cursor.object;
- if (obj == NULL)
+ if (!obj)
{
ee->prop.cursor.object = NULL;
ee->prop.cursor.layer = 0;
@@ -899,7 +429,7 @@ _ecore_evas_drm_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, i
if (evas_pointer_inside_get(ee->evas))
evas_object_show(ee->prop.cursor.object);
evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
- _ecore_evas_drm_object_cursor_del, ee);
+ _drm_object_cursor_del, ee);
}
evas_object_move(ee->prop.cursor.object, x - ee->prop.cursor.hot.x,
@@ -909,13 +439,21 @@ end:
if ((old) && (obj != old))
{
evas_object_event_callback_del_full
- (old, EVAS_CALLBACK_DEL, _ecore_evas_drm_object_cursor_del, ee);
+ (old, EVAS_CALLBACK_DEL, _drm_object_cursor_del, ee);
evas_object_del(old);
}
}
static void
-_ecore_evas_drm_layer_set(Ecore_Evas *ee, int layer)
+_drm_object_cursor_unset(Ecore_Evas *ee)
+{
+ evas_object_event_callback_del_full(ee->prop.cursor.object,
+ EVAS_CALLBACK_DEL,
+ _drm_object_cursor_del, ee);
+}
+
+static void
+_drm_layer_set(Ecore_Evas *ee, int layer)
{
if (layer < 1) layer = 1;
else if (layer > 255) layer = 255;
@@ -924,44 +462,44 @@ _ecore_evas_drm_layer_set(Ecore_Evas *ee, int layer)
}
static void
-_ecore_evas_drm_iconified_set(Ecore_Evas *ee, Eina_Bool on)
+_drm_iconified_set(Ecore_Evas *ee, Eina_Bool on)
{
if (ee->prop.iconified == on) return;
ee->prop.iconified = on;
}
static void
-_ecore_evas_drm_borderless_set(Ecore_Evas *ee, Eina_Bool on)
+_drm_borderless_set(Ecore_Evas *ee, Eina_Bool on)
{
if (ee->prop.borderless == on) return;
ee->prop.borderless = on;
}
static void
-_ecore_evas_drm_maximized_set(Ecore_Evas *ee, Eina_Bool on)
+_drm_maximized_set(Ecore_Evas *ee, Eina_Bool on)
{
if (ee->prop.maximized == on) return;
ee->prop.maximized = on;
}
static void
-_ecore_evas_drm_fullscreen_set(Ecore_Evas *ee, Eina_Bool on)
+_drm_fullscreen_set(Ecore_Evas *ee, Eina_Bool on)
{
Eina_Bool resized = EINA_FALSE;
Ecore_Evas_Engine_Drm_Data *edata;
edata = ee->engine.data;
if (ee->prop.fullscreen == on) return;
+ ee->prop.fullscreen = on;
+
if (on)
{
- Evas_Engine_Info_Drm *einfo;
int ow = 0, oh = 0;
edata->w = ee->w;
edata->h = ee->h;
- if ((einfo = (Evas_Engine_Info_Drm *)evas_engine_info_get(ee->evas)))
- ecore_drm_output_size_get(dev, einfo->info.buffer_id, &ow, &oh);
+ ecore_drm2_output_geometry_get(edata->output, NULL, NULL, &ow, &oh);
if ((ow == 0) || (oh == 0))
{
ow = ee->w;
@@ -992,7 +530,7 @@ _ecore_evas_drm_fullscreen_set(Ecore_Evas *ee, Eina_Bool on)
}
static void
-_ecore_evas_drm_withdrawn_set(Ecore_Evas *ee, Eina_Bool on)
+_drm_withdrawn_set(Ecore_Evas *ee, Eina_Bool on)
{
if (ee->prop.withdrawn == on) return;
ee->prop.withdrawn = on;
@@ -1001,145 +539,383 @@ _ecore_evas_drm_withdrawn_set(Ecore_Evas *ee, Eina_Bool on)
}
static void
-_ecore_evas_drm_ignore_events_set(Ecore_Evas *ee, int ignore)
+_drm_ignore_events_set(Ecore_Evas *ee, int on)
{
- if (ee->ignore_events == ignore) return;
- ee->ignore_events = ignore;
+ if (ee->ignore_events == on) return;
+ ee->ignore_events = on;
}
static void
-_ecore_evas_drm_alpha_set(Ecore_Evas *ee, int alpha)
+_drm_alpha_set(Ecore_Evas *ee, int alpha)
{
if (ee->in_async_render)
{
ee->delayed.alpha = alpha;
ee->delayed.alpha_changed = EINA_TRUE;
- return;
}
-
- /* FIXME: TODO: Finish */
}
static void
-_ecore_evas_drm_transparent_set(Ecore_Evas *ee, int transparent)
+_drm_transparent_set(Ecore_Evas *ee, int transparent)
{
if (ee->in_async_render)
{
ee->delayed.transparent = transparent;
ee->delayed.transparent_changed = EINA_TRUE;
- return;
}
-
- /* FIXME: TODO: Finish */
}
static void
-_ecore_evas_drm_aspect_set(Ecore_Evas *ee, double aspect)
+_drm_aspect_set(Ecore_Evas *ee, double aspect)
{
if (ee->prop.aspect == aspect) return;
ee->prop.aspect = aspect;
}
-static int
-_ecore_evas_drm_render(Ecore_Evas *ee)
+static Ecore_Evas_Interface_Drm *
+_ecore_evas_drm_interface_new(void)
{
- int rend = 0;
- Eina_List *l;
- Ecore_Evas *ee2;
+ Ecore_Evas_Interface_Drm *iface;
- if (ee->in_async_render) return 0;
+ iface = calloc(1, sizeof(Ecore_Evas_Interface_Drm));
+ if (!iface) return NULL;
- if (!ee->visible)
+ iface->base.name = "drm";
+ iface->base.version = 1;
+
+ return iface;
+}
+
+static Ecore_Evas_Engine_Func _ecore_evas_drm_engine_func =
+{
+ _drm_free,
+ NULL, //void (*fn_callback_resize_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+ NULL, //void (*fn_callback_move_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+ NULL, //void (*fn_callback_show_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+ NULL, //void (*fn_callback_hide_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+ NULL, //_ecore_evas_drm_delete_request_set,
+ NULL, //void (*fn_callback_destroy_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+ NULL, //_ecore_evas_drm_callback_focus_in_set,
+ NULL, //_ecore_evas_drm_callback_focus_out_set,
+ NULL, //_ecore_evas_drm_callback_mouse_in_set,
+ NULL, //_ecore_evas_drm_callback_mouse_out_set,
+ NULL, //void (*fn_callback_sticky_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+ NULL, //void (*fn_callback_unsticky_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+ NULL, //void (*fn_callback_pre_render_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+ NULL, //void (*fn_callback_post_render_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+ _drm_move,
+ NULL, //void (*fn_managed_move) (Ecore_Evas *ee, int x, int y);
+ _drm_resize,
+ _drm_move_resize,
+ _drm_rotation_set,
+ NULL, //void (*fn_shaped_set) (Ecore_Evas *ee, int shaped);
+ _drm_show,
+ _drm_hide,
+ NULL, //void (*fn_raise) (Ecore_Evas *ee);
+ NULL, //void (*fn_lower) (Ecore_Evas *ee);
+ NULL, //void (*fn_activate) (Ecore_Evas *ee);
+ _drm_title_set,
+ _drm_name_class_set,
+ _drm_size_min_set,
+ _drm_size_max_set,
+ _drm_size_base_set,
+ _drm_size_step_set,
+ _drm_object_cursor_set,
+ _drm_object_cursor_unset,
+ _drm_layer_set,
+ NULL, //void (*fn_focus_set) (Ecore_Evas *ee, Eina_Bool on);
+ _drm_iconified_set,
+ _drm_borderless_set,
+ NULL, //void (*fn_override_set) (Ecore_Evas *ee, Eina_Bool on);
+ _drm_maximized_set,
+ _drm_fullscreen_set,
+ NULL, //void (*fn_avoid_damage_set) (Ecore_Evas *ee, int on);
+ _drm_withdrawn_set,
+ NULL, //void (*fn_sticky_set) (Ecore_Evas *ee, Eina_Bool on);
+ _drm_ignore_events_set,
+ _drm_alpha_set,
+ _drm_transparent_set,
+ NULL, //void (*fn_profiles_set) (Ecore_Evas *ee, const char **profiles, int count);
+ NULL, //void (*fn_profile_set) (Ecore_Evas *ee, const char *profile);
+
+ NULL, //void (*fn_window_group_set) (Ecore_Evas *ee, const Ecore_Evas *ee_group);
+ _drm_aspect_set,
+ NULL, //void (*fn_urgent_set) (Ecore_Evas *ee, Eina_Bool on);
+ NULL, //void (*fn_modal_set) (Ecore_Evas *ee, Eina_Bool on);
+ NULL, //void (*fn_demands_attention_set) (Ecore_Evas *ee, Eina_Bool on);
+ NULL, //void (*fn_focus_skip_set) (Ecore_Evas *ee, Eina_Bool on);
+
+ _drm_render,
+
+ _drm_screen_geometry_get,
+ NULL, //void (*fn_screen_dpi_get) (const Ecore_Evas *ee, int *xdpi, int *ydpi);
+ NULL, //void (*fn_msg_parent_send) (Ecore_Evas *ee, int maj, int min, void *data, int size);
+ NULL, //void (*fn_msg_send) (Ecore_Evas *ee, int maj, int min, void *data, int size);
+
+ _drm_pointer_xy_get,
+ _drm_pointer_warp,
+
+ NULL, // wm_rot_preferred_rotation_set
+ NULL, // wm_rot_available_rotations_set
+ NULL, // wm_rot_manual_rotation_done_set
+ NULL, // wm_rot_manual_rotation_done
+
+ NULL, // aux_hints_set
+
+ NULL, // animator_register
+ NULL // animator_unregister
+};
+
+EAPI Ecore_Evas *
+ecore_evas_drm_new_internal(const char *device, unsigned int parent EINA_UNUSED, int x, int y, int w, int h)
+{
+ Ecore_Evas *ee;
+ Evas_Engine_Info_Drm *einfo;
+ Ecore_Evas_Interface_Drm *iface;
+ Ecore_Evas_Engine_Drm_Data *edata;
+ int method, mw, mh;
+
+ method = evas_render_method_lookup("drm");
+ if (!method) return NULL;
+
+ ee = calloc(1, sizeof(Ecore_Evas));
+ if (!ee) return NULL;
+
+ edata = calloc(1, sizeof(Ecore_Evas_Engine_Drm_Data));
+ if (!edata)
{
- evas_norender(ee->evas);
- return 0;
+ free(ee);
+ return NULL;
}
- EINA_LIST_FOREACH(ee->sub_ecore_evas, l, ee2)
+ edata->x = x;
+ edata->y = y;
+ edata->w = w;
+ edata->h = h;
+ edata->depth = 24; // FIXME: Remove hardcode
+ edata->bpp = 32; // FIXME: Remove hardcode
+ edata->format = DRM_FORMAT_XRGB8888;
+
+ if (_ecore_evas_drm_init(edata, device) < 1)
{
- if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2);
- if (ee2->engine.func->fn_render)
- rend |= ee2->engine.func->fn_render(ee2);
- if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2);
+ free(edata);
+ free(ee);
+ return NULL;
}
- if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee);
+ ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS);
- if (!ee->can_async_render)
- {
- Eina_List *updates;
+ ee->driver = "drm";
+ ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_evas_drm_engine_func;
+ ee->engine.data = edata;
- updates = evas_render_updates(ee->evas);
- rend = _ecore_evas_drm_render_updates_process(ee, updates);
- evas_render_updates_free(updates);
- }
- else if (evas_render_async(ee->evas))
+ /* FIXME */
+ /* if (edata->device) ee->name = strdup(edata->device); */
+
+ iface = _ecore_evas_drm_interface_new();
+ ee->engine.ifaces = eina_list_append(ee->engine.ifaces, iface);
+
+ ee->x = ee->req.x = x;
+ ee->y = ee->req.y = y;
+ ee->w = ee->req.w = w;
+ ee->h = ee->req.h = h;
+
+ ee->prop.max.w = 32767;
+ ee->prop.max.h = 32767;
+ ee->prop.layer = 4;
+ ee->prop.request_pos = 0;
+ ee->prop.sticky = 0;
+ ee->prop.withdrawn = EINA_TRUE;
+ ee->alpha = EINA_FALSE;
+
+ ee->can_async_render = 1;
+ if (getenv("ECORE_EVAS_FORCE_SYNC_RENDER"))
+ ee->can_async_render = 0;
+
+ ee->evas = evas_new();
+ evas_data_attach_set(ee->evas, ee);
+ evas_output_method_set(ee->evas, method);
+ evas_output_size_set(ee->evas, w, h);
+ evas_output_viewport_set(ee->evas, 0, 0, w, h);
+
+ if (ee->can_async_render)
+ evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_POST,
+ _drm_render_updates, ee);
+
+ einfo = (Evas_Engine_Info_Drm *)evas_engine_info_get(ee->evas);
+ if (einfo)
{
- ee->in_async_render = EINA_TRUE;
- rend = 1;
+ einfo->info.fd = edata->fd;
+ einfo->info.bpp = edata->bpp;
+ einfo->info.depth = edata->depth;
+ einfo->info.format = edata->format;
+ einfo->info.rotation = ee->rotation;
+ einfo->info.output = edata->output;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed", ee->driver);
+ goto eng_err;
+ }
}
- return rend;
+ ee->prop.window = ecore_drm2_output_crtc_get(edata->output);
+ ecore_drm2_device_window_set(edata->dev, ee->prop.window);
+
+ ecore_evas_data_set(ee, "device", edata->dev);
+
+ _ecore_evas_register(ee);
+ ecore_evas_input_event_register(ee);
+ ecore_event_window_register(ee->prop.window, ee, ee->evas,
+ (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process,
+ (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process,
+ (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process,
+ (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process);
+
+ ecore_drm2_output_crtc_size_get(edata->output, &mw, &mh);
+
+ ecore_drm2_device_calibrate(edata->dev, mw, mh);
+ ecore_drm2_device_pointer_max_set(edata->dev, mw, mh);
+ ecore_drm2_device_pointer_warp(edata->dev, mw / 2, mh / 2);
+
+ return ee;
+
+eng_err:
+ ecore_evas_free(ee);
+ return NULL;
}
-static void
-_ecore_evas_drm_render_updates(void *data, Evas *evas EINA_UNUSED, void *event)
+#ifdef BUILD_ECORE_EVAS_GL_DRM
+EAPI Ecore_Evas *
+ecore_evas_gl_drm_new_internal(const char *device, unsigned int parent EINA_UNUSED, int x, int y, int w, int h)
{
- Evas_Event_Render_Post *ev;
Ecore_Evas *ee;
+ Evas_Engine_Info_GL_Drm *einfo;
+ Ecore_Evas_Interface_Drm *iface;
+ Ecore_Evas_Engine_Drm_Data *edata;
+ int method, mw, mh;
- if (!(ev = event)) return;
- if (!(ee = data)) return;
+ method = evas_render_method_lookup("gl_drm");
+ if (!method) return NULL;
- ee->in_async_render = EINA_FALSE;
+ ee = calloc(1, sizeof(Ecore_Evas));
+ if (!ee) return NULL;
- _ecore_evas_drm_render_updates_process(ee, ev->updated_area);
+ edata = calloc(1, sizeof(Ecore_Evas_Engine_Drm_Data));
+ if (!edata)
+ {
+ free(ee);
+ return NULL;
+ }
- /* TODO: handle delayed changes */
-}
+ edata->x = x;
+ edata->y = y;
+ edata->w = w;
+ edata->h = h;
+ edata->depth = 24; // FIXME: Remove hardcode
+ edata->bpp = 32; // FIXME: Remove hardcode
+ edata->format = DRM_FORMAT_XRGB8888;
-static int
-_ecore_evas_drm_render_updates_process(Ecore_Evas *ee, Eina_List *updates)
-{
- int rend = 0;
+ dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
+ if (dlerror())
+ {
+ free(edata);
+ free(ee);
+ return NULL;
+ }
- if ((ee->visible) && (updates))
+ if (_ecore_evas_drm_init(edata, device) < 1)
{
-// Eina_List *l = NULL;
-// Eina_Rectangle *r;
-//
-// EINA_LIST_FOREACH(updates, l, r)
-// {
-// /* TODO */
-// }
+ free(edata);
+ free(ee);
+ return NULL;
+ }
- _ecore_evas_idle_timeout_update(ee);
- rend = 1;
+ ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS);
+
+ ee->driver = "gl_drm";
+ ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_evas_drm_engine_func;
+ ee->engine.data = edata;
+
+ /* FIXME */
+ /* if (edata->device) ee->name = strdup(edata->device); */
+
+ iface = _ecore_evas_drm_interface_new();
+ ee->engine.ifaces = eina_list_append(ee->engine.ifaces, iface);
+
+ ee->x = ee->req.x = x;
+ ee->y = ee->req.y = y;
+ ee->w = ee->req.w = w;
+ ee->h = ee->req.h = h;
+
+ ee->prop.max.w = 32767;
+ ee->prop.max.h = 32767;
+ ee->prop.layer = 4;
+ ee->prop.request_pos = 0;
+ ee->prop.sticky = 0;
+ ee->prop.withdrawn = EINA_TRUE;
+ ee->alpha = EINA_FALSE;
+
+ ee->can_async_render = 0; // FIXME ??
+ if (getenv("ECORE_EVAS_FORCE_SYNC_RENDER"))
+ ee->can_async_render = 0;
+
+ ee->evas = evas_new();
+ evas_data_attach_set(ee->evas, ee);
+ evas_output_method_set(ee->evas, method);
+ evas_output_size_set(ee->evas, w, h);
+ evas_output_viewport_set(ee->evas, 0, 0, w, h);
+
+ if (ee->can_async_render)
+ evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_POST,
+ _drm_render_updates, ee);
+
+ einfo = (Evas_Engine_Info_GL_Drm *)evas_engine_info_get(ee->evas);
+ if (einfo)
+ {
+ char *num;
+
+ einfo->info.vsync = EINA_TRUE;
+
+ num = getenv("EVAS_DRM_VSYNC");
+ if ((num) && (!atoi(num)))
+ einfo->info.vsync = EINA_FALSE;
+
+ einfo->info.fd = edata->fd;
+ einfo->info.bpp = edata->bpp;
+ einfo->info.depth = edata->depth;
+ einfo->info.format = edata->format;
+ einfo->info.rotation = ee->rotation;
+ einfo->info.output = edata->output;
+ if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+ {
+ ERR("evas_engine_info_set() for engine '%s' failed", ee->driver);
+ goto eng_err;
+ }
}
- else
- evas_norender(ee->evas);
- if (ee->func.fn_post_render) ee->func.fn_post_render(ee);
+ ee->prop.window = ecore_drm2_output_crtc_get(edata->output);
+ ecore_drm2_device_window_set(edata->dev, ee->prop.window);
- return rend;
-}
+ ecore_evas_data_set(ee, "device", edata->dev);
-static void
-_ecore_evas_drm_screen_geometry_get(const Ecore_Evas *ee EINA_UNUSED, int *x, int *y, int *w, int *h)
-{
- ecore_drm_outputs_geometry_get(dev, x, y, w, h);
-}
+ _ecore_evas_register(ee);
+ ecore_evas_input_event_register(ee);
+ ecore_event_window_register(ee->prop.window, ee, ee->evas,
+ (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process,
+ (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process,
+ (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process,
+ (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process);
-static void
-_ecore_evas_drm_pointer_xy_get(const Ecore_Evas *ee EINA_UNUSED, Evas_Coord *x, Evas_Coord *y)
-{
- /* get pointer position from input */
- ecore_drm_device_pointer_xy_get(dev, x, y);
-}
+ ecore_drm2_output_crtc_size_get(edata->output, &mw, &mh);
-Eina_Bool
-_ecore_evas_drm_pointer_warp(const Ecore_Evas *ee EINA_UNUSED, Evas_Coord x, Evas_Coord y)
-{
- ecore_drm_device_pointer_warp(dev, x, y);
- return EINA_TRUE;
+ ecore_drm2_device_calibrate(edata->dev, mw, mh);
+ ecore_drm2_device_pointer_max_set(edata->dev, mw, mh);
+ ecore_drm2_device_pointer_warp(edata->dev, mw / 2, mh / 2);
+
+ return ee;
+
+eng_err:
+ ecore_evas_free(ee);
+ return NULL;
}
+#endif
diff --git a/src/modules/evas/engines/drm/Evas_Engine_Drm.h b/src/modules/evas/engines/drm/Evas_Engine_Drm.h
index 136eb919db..457db625e7 100644
--- a/src/modules/evas/engines/drm/Evas_Engine_Drm.h
+++ b/src/modules/evas/engines/drm/Evas_Engine_Drm.h
@@ -1,11 +1,7 @@
#ifndef _EVAS_ENGINE_DRM_H
# define _EVAS_ENGINE_DRM_H
-# include <Ecore_Drm.h>
-
-typedef struct _Evas_Engine_Info_Drm Evas_Engine_Info_Drm;
-
-struct _Evas_Engine_Info_Drm
+typedef struct _Evas_Engine_Info_Drm
{
/* PRIVATE - don't mess with this baby or evas will poke its tongue out */
/* at you and make nasty noises */
@@ -13,18 +9,17 @@ struct _Evas_Engine_Info_Drm
struct
{
- unsigned int rotation, depth;
- Eina_Bool destination_alpha : 1;
- Eina_Bool vsync : 1;
+ int fd;
+ int depth, bpp;
+ unsigned int format, rotation;
- unsigned int crtc_id, conn_id, buffer_id;
-
- Eina_Bool use_hw_accel : 1;
- Ecore_Drm_Device *dev;
+ void *output;
+ Eina_Bool alpha : 1;
+ Eina_Bool vsync : 1;
} info;
/* non-blocking or blocking mode */
Evas_Engine_Render_Mode render_mode;
-};
+} Evas_Engine_Info_Drm;
#endif
diff --git a/src/modules/evas/engines/drm/evas_engine.c b/src/modules/evas/engines/drm/evas_engine.c
index 40365a99f1..e3cd01e576 100644
--- a/src/modules/evas/engines/drm/evas_engine.c
+++ b/src/modules/evas/engines/drm/evas_engine.c
@@ -1,65 +1,57 @@
#include "evas_engine.h"
-/* local structures */
-typedef struct _Render_Engine Render_Engine;
-
-struct _Render_Engine
+typedef struct _Render_Engine
{
Render_Engine_Software_Generic generic;
-};
+} Render_Engine;
-/* function tables - filled in later (func and parent func) */
static Evas_Func func, pfunc;
-/* external variables */
int _evas_engine_drm_log_dom;
-/* local functions */
-static void *
-_output_setup(Evas_Engine_Info_Drm *info, int w, int h)
+static Render_Engine *
+_render_engine_setup(Evas_Engine_Info_Drm *info, int w, int h)
{
- Render_Engine *re = NULL;
+ Render_Engine *re;
Outbuf *ob;
- /* try to allocate space for our render engine structure */
- if (!(re = calloc(1, sizeof(Render_Engine))))
- goto on_error;
+ re = calloc(1, sizeof(Render_Engine));
+ if (!re) return NULL;
- /* try to create new outbuf */
- if (!(ob = evas_outbuf_setup(info, w, h)))
- goto on_error;
+ ob = _outbuf_setup(info, w, h);
+ if (!ob) goto err;
if (!evas_render_engine_software_generic_init(&re->generic, ob,
- evas_outbuf_buffer_state_get,
- evas_outbuf_rot_get,
- evas_outbuf_reconfigure, NULL,
- evas_outbuf_update_region_new,
- evas_outbuf_update_region_push,
- evas_outbuf_update_region_free,
- NULL, evas_outbuf_flush,
- evas_outbuf_free,
+ _outbuf_state_get,
+ _outbuf_rotation_get,
+ _outbuf_reconfigure,
+ NULL,
+ _outbuf_update_region_new,
+ _outbuf_update_region_push,
+ _outbuf_update_region_free,
+ NULL,
+ _outbuf_flush,
+ _outbuf_free,
ob->w, ob->h))
- goto on_error;
+ goto init_err;
- /* return the allocated render_engine structure */
return re;
- on_error:
- if (re) evas_render_engine_software_generic_clean(&re->generic);
-
+init_err:
+ evas_render_engine_software_generic_clean(&re->generic);
+err:
free(re);
return NULL;
}
-/* engine api functions */
static void *
eng_info(Evas *evas EINA_UNUSED)
{
Evas_Engine_Info_Drm *info;
/* try to allocate space for our engine info structure */
- if (!(info = calloc(1, sizeof(Evas_Engine_Info_Drm))))
- return NULL;
+ info = calloc(1, sizeof(Evas_Engine_Info_Drm));
+ if (!info) return NULL;
/* set some engine default properties */
info->magic.magic = rand();
@@ -74,55 +66,47 @@ eng_info_free(Evas *evas EINA_UNUSED, void *einfo)
Evas_Engine_Info_Drm *info;
/* free the engine info */
- if ((info = (Evas_Engine_Info_Drm *)einfo))
- free(info);
+ info = (Evas_Engine_Info_Drm *)einfo;
+ free(info);
}
static int
eng_setup(Evas *evas, void *einfo)
{
- Evas_Engine_Info_Drm *info;
- Evas_Public_Data *epd;
Render_Engine *re;
+ Evas_Public_Data *epd;
+ Evas_Engine_Info_Drm *info;
- /* try to cast to our engine info structure */
- if (!(info = (Evas_Engine_Info_Drm *)einfo)) return 0;
+ info = (Evas_Engine_Info_Drm *)einfo;
+ if (!info) return 0;
- /* try to get the evas public data */
- if (!(epd = eo_data_scope_get(evas, EVAS_CANVAS_CLASS))) return 0;
+ epd = eo_data_scope_get(evas, EVAS_CANVAS_CLASS);
+ if (!epd) return 0;
- /* check for valid engine output */
- if (!(re = epd->engine.data.output))
+ re = epd->engine.data.output;
+ if (!re)
{
- /* NB: If we have no valid output then assume we have not been
- * initialized yet and call any needed common init routines */
evas_common_init();
- /* try to create a new render_engine */
- if (!(re = _output_setup(info, epd->output.w, epd->output.h)))
- return 0;
+ re = _render_engine_setup(info, epd->output.w, epd->output.h);
+ if (!re) return 0;
}
else
{
Outbuf *ob;
- /* try to create a new outbuf */
- ob = evas_outbuf_setup(info, epd->output.w, epd->output.h);
+ ob = _outbuf_setup(info, epd->output.w, epd->output.h);
if (!ob) return 0;
- /* if we have an existing outbuf, free it */
- evas_render_engine_software_generic_update(&re->generic, ob,
+ evas_render_engine_software_generic_update(&re->generic, ob,
ob->w, ob->h);
}
- /* reassign engine output */
epd->engine.data.output = re;
if (!epd->engine.data.output) return 0;
- /* check for valid engine context */
if (!epd->engine.data.context)
{
- /* create a context if needed */
epd->engine.data.context =
epd->engine.func->context_new(epd->engine.data.output);
}
@@ -135,7 +119,8 @@ eng_output_free(void *data)
{
Render_Engine *re;
- if ((re = data))
+ re = data;
+ if (re)
{
evas_render_engine_software_generic_clean(&re->generic);
free(re);
@@ -144,7 +129,6 @@ eng_output_free(void *data)
evas_common_shutdown();
}
-/* module api functions */
static int
module_open(Evas_Module *em)
{
@@ -165,6 +149,8 @@ module_open(Evas_Module *em)
return 0;
}
+ ecore_init();
+
/* store parent functions */
func = pfunc;
@@ -185,6 +171,8 @@ module_close(Evas_Module *em EINA_UNUSED)
{
/* unregister the eina log domain for this engine */
eina_log_domain_unregister(_evas_engine_drm_log_dom);
+
+ ecore_shutdown();
}
static Evas_Module_Api evas_modapi =
diff --git a/src/modules/evas/engines/drm/evas_engine.h b/src/modules/evas/engines/drm/evas_engine.h
index d5139117ee..a1925b939e 100644
--- a/src/modules/evas/engines/drm/evas_engine.h
+++ b/src/modules/evas/engines/drm/evas_engine.h
@@ -6,8 +6,13 @@
# include "evas_private.h"
# include "Evas.h"
# include "Evas_Engine_Drm.h"
+# include <Ecore.h>
+# include <Ecore_Drm2.h>
+# include <drm_fourcc.h>
+# include <xf86drm.h>
+# include <xf86drmMode.h>
-#include "../software_generic/Evas_Engine_Software_Generic.h"
+# include "../software_generic/Evas_Engine_Software_Generic.h"
extern int _evas_engine_drm_log_dom;
@@ -36,35 +41,44 @@ extern int _evas_engine_drm_log_dom;
# endif
# define CRI(...) EINA_LOG_DOM_CRIT(_evas_engine_drm_log_dom, __VA_ARGS__)
-struct _Outbuf
+typedef struct _Outbuf_Fb
{
- Evas_Engine_Info_Drm *info;
+ int age;
+ Ecore_Drm2_Fb *fb;
+
+ Eina_Bool valid : 1;
+ Eina_Bool drawn : 1;
+ Eina_Bool busy : 1;
+} Outbuf_Fb;
- int w, h;
- int rotation;
- unsigned int depth;
+struct _Outbuf
+{
+ int fd, w, h, bpp, rotation;
+ unsigned int depth, format;
struct
{
- Ecore_Drm_Fb *buffer[4];
-
- Eina_List *pending_writes;
-
- int curr, last, num;
+ int num;
+ Outbuf_Fb ofb[4], *current;
+ Ecore_Drm2_Output *output;
+ Eina_List *pending;
} priv;
- Eina_Bool destination_alpha : 1;
+ drmEventContext ctx;
+ Ecore_Fd_Handler *hdlr;
+
+ Eina_Bool alpha : 1;
Eina_Bool vsync : 1;
};
-Outbuf *evas_outbuf_setup(Evas_Engine_Info_Drm *info, int w, int h);
-void evas_outbuf_free(Outbuf *ob);
-void evas_outbuf_reconfigure(Outbuf *ob, int w, int h, int rot, Outbuf_Depth depth);
-Render_Engine_Swap_Mode evas_outbuf_buffer_state_get(Outbuf *ob);
-int evas_outbuf_rot_get(Outbuf *ob);
-void *evas_outbuf_update_region_new(Outbuf *ob, int x, int y, int w, int h, int *cx, int *cy, int *cw, int *ch);
-void evas_outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int w, int h);
-void evas_outbuf_update_region_free(Outbuf *ob, RGBA_Image *update);
-void evas_outbuf_flush(Outbuf *ob, Tilebuf_Rect *rects, Evas_Render_Mode render_mode);
+Outbuf *_outbuf_setup(Evas_Engine_Info_Drm *info, int w, int h);
+void _outbuf_free(Outbuf *ob);
+int _outbuf_rotation_get(Outbuf *ob);
+void _outbuf_reconfigure(Outbuf *ob, int w, int h, int rotation, Outbuf_Depth depth);
+Render_Engine_Swap_Mode _outbuf_state_get(Outbuf *ob);
+void *_outbuf_update_region_new(Outbuf *ob, int x, int y, int w, int h, int *cx, int *cy, int *cw, int *ch);
+void _outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int w, int h);
+void _outbuf_update_region_free(Outbuf *ob, RGBA_Image *update);
+void _outbuf_flush(Outbuf *ob, Tilebuf_Rect *rects, Evas_Render_Mode render_mode);
#endif
diff --git a/src/modules/evas/engines/drm/evas_outbuf.c b/src/modules/evas/engines/drm/evas_outbuf.c
index 64b3ba9a52..ce7be06462 100644
--- a/src/modules/evas/engines/drm/evas_outbuf.c
+++ b/src/modules/evas/engines/drm/evas_outbuf.c
@@ -8,183 +8,425 @@
#define GREEN_MASK 0x00ff00
#define BLUE_MASK 0x0000ff
-static void
-_evas_outbuf_buffer_swap(Outbuf *ob, Eina_Rectangle *rects, unsigned int count)
+static void _outbuf_tick_schedule(int fd, void *data);
+
+static Eina_Bool ticking = EINA_FALSE;
+
+static void
+_outbuf_tick_begin(void *data)
+{
+ Outbuf *ob;
+
+ ob = data;
+ ticking = EINA_TRUE;
+ if (ob) _outbuf_tick_schedule(ob->fd, ob);
+}
+
+static void
+_outbuf_tick_end(void *data EINA_UNUSED)
+{
+ ticking = EINA_FALSE;
+}
+
+static void
+_outbuf_tick_source_set(Outbuf *ob)
+{
+ if (ob)
+ {
+ ecore_animator_custom_source_tick_begin_callback_set
+ (_outbuf_tick_begin, ob);
+ ecore_animator_custom_source_tick_end_callback_set
+ (_outbuf_tick_end, ob);
+ ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_CUSTOM);
+ }
+ else
+ {
+ ecore_animator_custom_source_tick_begin_callback_set(NULL, NULL);
+ ecore_animator_custom_source_tick_end_callback_set(NULL, NULL);
+ ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER);
+ }
+}
+
+static void
+_outbuf_tick_schedule(int fd EINA_UNUSED, void *data)
{
- Ecore_Drm_Fb *buff;
+ if (!ticking) return;
- buff = ob->priv.buffer[ob->priv.curr];
+ drmVBlank vbl =
+ {
+ .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
+ .request.sequence = 1,
+ .request.signal = (unsigned long)data,
+ };
- /* mark the fb as dirty */
- ecore_drm_fb_dirty(buff, rects, count);
+ if (drmWaitVBlank(fd, &vbl) < 0)
+ _outbuf_tick_source_set(NULL);
+}
- /* send this buffer to the crtc */
- ecore_drm_fb_send(ob->info->info.dev, buff, NULL, NULL);
+static void
+_cb_vblank(int fd, unsigned int frame EINA_UNUSED, unsigned int sec EINA_UNUSED, unsigned int usec EINA_UNUSED, void *data)
+{
+ ecore_animator_custom_tick();
+ if (ticking) _outbuf_tick_schedule(fd, data);
+}
- ob->priv.last = ob->priv.curr;
- ob->priv.curr = (ob->priv.curr + 1) % ob->priv.num;
+static void
+_cb_pageflip(int fd EINA_UNUSED, unsigned int frame EINA_UNUSED, unsigned int sec EINA_UNUSED, unsigned int usec EINA_UNUSED, void *data)
+{
+ Outbuf *ob;
+ Outbuf_Fb *ofb;
+ Ecore_Drm2_Fb *next;
+
+ ob = data;
+
+ ofb = ob->priv.current;
+ if (ofb) ofb->busy = EINA_FALSE;
+
+ next = ecore_drm2_output_next_fb_get(ob->priv.output);
+ if (next)
+ {
+ ecore_drm2_output_next_fb_set(ob->priv.output, NULL);
+ if (ecore_drm2_fb_flip(next, ob->priv.output, ob) < 0)
+ _outbuf_tick_source_set(NULL);
+ }
+}
+
+static Eina_Bool
+_cb_drm_event(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED)
+{
+ Outbuf *ob;
+ int ret;
+
+ ob = data;
+ ret = drmHandleEvent(ob->fd, &ob->ctx);
+ if (ret)
+ {
+ WRN("drmHandleEvent failed to read an event");
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+static void
+_outbuf_buffer_swap(Outbuf *ob, Eina_Rectangle *rects, unsigned int count)
+{
+ /* Ecore_Drm2_Plane *plane; */
+ Outbuf_Fb *ofb;
+
+ ofb = ob->priv.current;
+ if (!ofb) return;
+
+ ecore_drm2_fb_dirty(ofb->fb, rects, count);
+ if (ecore_drm2_fb_flip(ofb->fb, ob->priv.output, ob) < 0)
+ {
+ _outbuf_tick_source_set(NULL);
+ return;
+ }
+
+ ofb->busy = EINA_TRUE;
+ ofb->drawn = EINA_TRUE;
+ ofb->age = 0;
+
+ /* plane = ecore_drm2_plane_find(ob->priv.output, ofb->fb, ob->format); */
+ /* if (plane) */
+ /* { */
+ /* drmVBlank vbl = */
+ /* { */
+ /* .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT, */
+ /* .request.sequence = 1, */
+ /* }; */
+
+ /* vbl.request.type |= ecore_drm2_output_vblank_get(ob->priv.output); */
+ /* vbl.request.signal = (unsigned long)ofb; */
+
+ /* ecore_drm2_fb_dirty(ofb->fb, rects, count); */
+
+ /* if (!ecore_drm2_plane_fb_set(plane, ofb->fb)) */
+ /* { */
+ /* ERR("Failed to set FB on Plane"); */
+ /* return; */
+ /* } */
+
+ /* if (drmWaitVBlank(ob->fd, &vbl) < 0) */
+ /* { */
+ /* _outbuf_tick_source_set(NULL); */
+ /* return; */
+ /* } */
+
+ /* ofb->busy = EINA_TRUE; */
+ /* ofb->drawn = EINA_TRUE; */
+ /* ofb->age = 0; */
+
+ /* ob->priv.current = NULL; */
+ /* } */
+ /* else */
+ /* WRN("Could not find a plane for this framebuffer"); */
+}
+
+static Eina_Bool
+_outbuf_fb_create(Outbuf *ob, Outbuf_Fb *ofb)
+{
+ ofb->fb =
+ ecore_drm2_fb_create(ob->fd, ob->w, ob->h,
+ ob->depth, ob->bpp, ob->format);
+ if (!ofb->fb) return EINA_FALSE;
+
+ ofb->age = 0;
+ ofb->busy = EINA_FALSE;
+ ofb->drawn = EINA_FALSE;
+ ofb->valid = EINA_TRUE;
+
+ return EINA_TRUE;
+}
+
+static void
+_outbuf_fb_destroy(Outbuf_Fb *ofb)
+{
+ ecore_drm2_fb_destroy(ofb->fb);
+
+ memset(ofb, 0, sizeof(*ofb));
+ ofb->valid = EINA_FALSE;
+ ofb->busy = EINA_FALSE;
+ ofb->drawn = EINA_FALSE;
+ ofb->age = 0;
}
Outbuf *
-evas_outbuf_setup(Evas_Engine_Info_Drm *info, int w, int h)
+_outbuf_setup(Evas_Engine_Info_Drm *info, int w, int h)
{
Outbuf *ob;
char *num;
int i = 0;
- /* try to allocate space for outbuf */
- if (!(ob = calloc(1, sizeof(Outbuf)))) return NULL;
+ ob = calloc(1, sizeof(Outbuf));
+ if (!ob) return NULL;
- /* set properties of outbuf */
ob->w = w;
ob->h = h;
+ ob->fd = info->info.fd;
+ ob->alpha = info->info.alpha;
+ ob->rotation = info->info.rotation;
- ob->info = info;
+ ob->bpp = info->info.bpp;
ob->depth = info->info.depth;
- ob->rotation = info->info.rotation;
- ob->destination_alpha = info->info.destination_alpha;
- ob->vsync = info->info.vsync;
+ ob->format = info->info.format;
+
+ ob->priv.output = info->info.output;
- /* we must triple-buffer to prevent problems with the page flip handler */
ob->priv.num = 3;
- /* check for buffer override */
- if ((num = getenv("EVAS_DRM_BUFFERS")))
+ num = getenv("EVAS_DRM_BUFFERS");
+ if (num)
{
ob->priv.num = atoi(num);
- if (ob->priv.num <= 0) ob->priv.num = 1;
+ if (ob->priv.num <= 0) ob->priv.num = 3;
else if (ob->priv.num > 4) ob->priv.num = 4;
}
- /* check for vsync override */
- if ((num = getenv("EVAS_DRM_VSYNC")))
- ob->vsync = atoi(num);
-
- /* try to create buffers */
- for (; i < ob->priv.num; i++)
+ for (i = 0; i < ob->priv.num; i++)
{
- ob->priv.buffer[i] =
- ecore_drm_fb_create(ob->info->info.dev, ob->w, ob->h);
- if (!ob->priv.buffer[i])
+ if (!_outbuf_fb_create(ob, &(ob->priv.ofb[i])))
{
- ERR("Failed to create buffer %d", i);
- break;
+ WRN("Failed to create framebuffer %d", i);
+ continue;
}
-
- DBG("Evas Engine Created Dumb Buffer");
- DBG("\tFb: %d", ob->priv.buffer[i]->id);
- DBG("\tHandle: %d", ob->priv.buffer[i]->hdl);
- DBG("\tStride: %d", ob->priv.buffer[i]->stride);
- DBG("\tSize: %d", ob->priv.buffer[i]->size);
- DBG("\tW: %d\tH: %d",
- ob->priv.buffer[i]->w, ob->priv.buffer[i]->h);
}
- /* set the front buffer to be the one on the crtc */
- ecore_drm_fb_send(info->info.dev, ob->priv.buffer[0], NULL, NULL);
+ /* setup vblank handler */
+ memset(&ob->ctx, 0, sizeof(ob->ctx));
+ ob->ctx.version = DRM_EVENT_CONTEXT_VERSION;
+ ob->ctx.vblank_handler = _cb_vblank;
+ ob->ctx.page_flip_handler = _cb_pageflip;
+
+ ob->hdlr =
+ ecore_main_fd_handler_add(ob->fd, ECORE_FD_READ, _cb_drm_event, ob,
+ NULL, NULL);
+
+ _outbuf_tick_source_set(ob);
return ob;
}
void
-evas_outbuf_free(Outbuf *ob)
+_outbuf_free(Outbuf *ob)
{
int i = 0;
- /* destroy the old buffers */
- for (; i < ob->priv.num; i++)
- ecore_drm_fb_destroy(ob->priv.buffer[i]);
+ for (i = 0; i < ob->priv.num; i++)
+ _outbuf_fb_destroy(&ob->priv.ofb[i]);
+
+ ecore_main_fd_handler_del(ob->hdlr);
- /* free allocate space for outbuf */
free(ob);
}
+int
+_outbuf_rotation_get(Outbuf *ob)
+{
+ return ob->rotation;
+}
+
void
-evas_outbuf_reconfigure(Outbuf *ob, int w, int h, int rot, Outbuf_Depth depth)
+_outbuf_reconfigure(Outbuf *ob, int w, int h, int rotation, Outbuf_Depth depth)
{
int i = 0;
+ unsigned int format = DRM_FORMAT_ARGB8888;
- /* check if we are inheriting the old buffer depth */
- if (depth == OUTBUF_DEPTH_INHERIT) depth = ob->depth;
+ switch (depth)
+ {
+ case OUTBUF_DEPTH_RGB_16BPP_565_565_DITHERED:
+ format = DRM_FORMAT_RGB565;
+ break;
+ case OUTBUF_DEPTH_RGB_16BPP_555_555_DITHERED:
+ format = DRM_FORMAT_RGBX5551;
+ break;
+ case OUTBUF_DEPTH_RGB_16BPP_444_444_DITHERED:
+ format = DRM_FORMAT_RGBX4444;
+ break;
+ case OUTBUF_DEPTH_RGB_16BPP_565_444_DITHERED:
+ format = DRM_FORMAT_RGB565;
+ break;
+ case OUTBUF_DEPTH_RGB_32BPP_888_8888:
+ format = DRM_FORMAT_RGBX8888;
+ break;
+ case OUTBUF_DEPTH_ARGB_32BPP_8888_8888:
+ format = DRM_FORMAT_ARGB8888;
+ break;
+ case OUTBUF_DEPTH_BGRA_32BPP_8888_8888:
+ format = DRM_FORMAT_BGRA8888;
+ break;
+ case OUTBUF_DEPTH_BGR_32BPP_888_8888:
+ format = DRM_FORMAT_BGRX8888;
+ break;
+ case OUTBUF_DEPTH_RGB_24BPP_888_888:
+ format = DRM_FORMAT_RGB888;
+ break;
+ case OUTBUF_DEPTH_BGR_24BPP_888_888:
+ format = DRM_FORMAT_BGR888;
+ break;
+ case OUTBUF_DEPTH_INHERIT:
+ default:
+ depth = ob->depth;
+ format = ob->format;
+ break;
+ }
- /* check for changes */
- if ((ob->w == w) && (ob->h == h) &&
- (ob->destination_alpha == ob->info->info.destination_alpha) &&
- (ob->rotation == rot) &&
- (ob->depth == depth))
+ if ((ob->w == w) && (ob->h == h) && (ob->rotation == rotation) &&
+ (ob->depth == depth) && (ob->format == format))
return;
- /* set new outbuf properties */
- ob->rotation = rot;
ob->depth = depth;
- ob->destination_alpha = ob->info->info.destination_alpha;
+ ob->format = format;
+ ob->rotation = rotation;
- /* handle rotation */
- if ((ob->rotation == 0) || (ob->rotation == 180))
- {
- ob->w = w;
- ob->h = h;
- }
- else
+ ob->w = w;
+ ob->h = h;
+ if ((ob->rotation == 90) || (ob->rotation == 270))
{
ob->w = h;
ob->h = w;
}
- /* destroy the old buffers */
- for (; i < ob->priv.num; i++)
- ecore_drm_fb_destroy(ob->priv.buffer[i]);
+ for (i = 0; i < ob->priv.num; i++)
+ _outbuf_fb_destroy(&ob->priv.ofb[i]);
for (i = 0; i < ob->priv.num; i++)
{
- ob->priv.buffer[i] =
- ecore_drm_fb_create(ob->info->info.dev, ob->w, ob->h);
- if (!ob->priv.buffer[i])
+ if (!_outbuf_fb_create(ob, &(ob->priv.ofb[i])))
{
- ERR("Failed to create buffer %d", i);
- break;
+ WRN("Failed to create framebuffer %d", i);
+ continue;
}
}
}
-Render_Engine_Swap_Mode
-evas_outbuf_buffer_state_get(Outbuf *ob)
+static Outbuf_Fb *
+_outbuf_fb_wait(Outbuf *ob)
{
- int delta;
+ int iter = 0, i = 0;
- /* check for valid output buffer */
- if (!ob) return MODE_FULL;
+ while (iter++ < 10)
+ {
+ for (i = 0; i < ob->priv.num; i++)
+ {
+ if (&ob->priv.ofb[i] == ob->priv.current) continue;
+ if (ob->priv.ofb[i].busy) continue;
+ if (ob->priv.ofb[i].valid) return &(ob->priv.ofb[i]);
+ }
+
+ drmHandleEvent(ob->fd, &ob->ctx);
+ }
+
+ return NULL;
+}
- delta = (ob->priv.last - ob->priv.curr + ob->priv.num) % ob->priv.num;
+static Eina_Bool
+_outbuf_fb_assign(Outbuf *ob)
+{
+ int i;
+
+ ob->priv.current = _outbuf_fb_wait(ob);
- /* This is the number of frame since last frame */
- switch (delta)
+ if (!ob->priv.current)
{
- case 0:
- return MODE_COPY;
- case 1:
- return MODE_DOUBLE;
- case 2:
- return MODE_TRIPLE;
- case 3:
- return MODE_QUADRUPLE;
- default:
- return MODE_FULL;
+ WRN("No Free Buffers. Dropping a frame");
+ for (i = 0; i < ob->priv.num; i++)
+ {
+ if (ob->priv.ofb[i].valid)
+ {
+ ob->priv.ofb[i].busy = 0;
+ ob->priv.ofb[i].age = 0;
+ ob->priv.ofb[i].drawn = EINA_FALSE;
+ }
+ }
+
+ return EINA_FALSE;
}
+
+ for (i = 0; i < ob->priv.num; i++)
+ {
+ if ((ob->priv.ofb[i].valid) && (ob->priv.ofb[i].drawn))
+ {
+ ob->priv.ofb[i].age++;
+ if (ob->priv.ofb[i].age > ob->priv.num)
+ {
+ ob->priv.ofb[i].age = 0;
+ ob->priv.ofb[i].drawn = EINA_FALSE;
+ }
+ }
+ }
+
+ return EINA_TRUE;
+}
+
+Render_Engine_Swap_Mode
+_outbuf_state_get(Outbuf *ob)
+{
+ int age;
+
+ if (!_outbuf_fb_assign(ob)) return MODE_FULL;
+
+ age = ob->priv.current->age;
+ if (age > ob->priv.num) return MODE_FULL;
+ else if (age == 1) return MODE_COPY;
+ else if (age == 2) return MODE_DOUBLE;
+ else if (age == 3) return MODE_TRIPLE;
+ else if (age == 4) return MODE_QUADRUPLE;
+
+ return MODE_FULL;
}
void *
-evas_outbuf_update_region_new(Outbuf *ob, int x, int y, int w, int h, int *cx, int *cy, int *cw, int *ch)
+_outbuf_update_region_new(Outbuf *ob, int x, int y, int w, int h, int *cx, int *cy, int *cw, int *ch)
{
RGBA_Image *img = NULL;
if ((w <= 0) || (h <= 0)) return NULL;
- /* DBG("Outbuf Region New: %d %d %d %d", x, y, w, h); */
-
RECTS_CLIP_TO_RECT(x, y, w, h, 0, 0, ob->w, ob->h);
- if ((ob->rotation == 0) && (ob->depth == 32))
+ if ((ob->rotation == 0))// && (ob->depth == 32))
{
Eina_Rectangle *rect;
@@ -204,7 +446,7 @@ evas_outbuf_update_region_new(Outbuf *ob, int x, int y, int w, int h, int *cx, i
return NULL;
}
- img->cache_entry.flags.alpha = ob->destination_alpha;
+ img->cache_entry.flags.alpha = ob->alpha;
#ifdef EVAS_CSERVE2
if (evas_cserve2_use_get())
@@ -221,48 +463,52 @@ evas_outbuf_update_region_new(Outbuf *ob, int x, int y, int w, int h, int *cx, i
if (ch) *ch = h;
/* add this cached image data to pending writes */
- ob->priv.pending_writes =
- eina_list_append(ob->priv.pending_writes, img);
+ ob->priv.pending =
+ eina_list_append(ob->priv.pending, img);
}
return img;
}
-void
-evas_outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int w, int h)
+void
+_outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int w, int h)
{
Gfx_Func_Convert func = NULL;
Eina_Rectangle rect = {0, 0, 0, 0}, pr;
DATA32 *src;
DATA8 *dst;
- Ecore_Drm_Fb *buff;
+ Ecore_Drm2_Fb *buff;
int bpp = 0, bpl = 0;
int rx = 0, ry = 0;
+ int bw = 0, bh = 0;
/* check for valid output buffer */
if (!ob) return;
/* check for pending writes */
- if (!ob->priv.pending_writes) return;
+ if (!ob->priv.pending) return;
/* check for valid source data */
if (!(src = update->image.data)) return;
/* check for valid desination data */
- buff = ob->priv.buffer[ob->priv.curr];
- if (!(dst = buff->mmap)) return;
+ if (!ob->priv.current) return;
+ buff = ob->priv.current->fb;
+
+ dst = ecore_drm2_fb_data_get(buff);
+ if (!dst) return;
if ((ob->rotation == 0) || (ob->rotation == 180))
{
func =
- evas_common_convert_func_get(0, w, h, ob->depth,
+ evas_common_convert_func_get(0, w, h, ob->bpp,
RED_MASK, GREEN_MASK, BLUE_MASK,
PAL_MODE_NONE, ob->rotation);
}
else if ((ob->rotation == 90) || (ob->rotation == 270))
{
func =
- evas_common_convert_func_get(0, h, w, ob->depth,
+ evas_common_convert_func_get(0, h, w, ob->bpp,
RED_MASK, GREEN_MASK, BLUE_MASK,
PAL_MODE_NONE, ob->rotation);
}
@@ -304,15 +550,18 @@ evas_outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int
rect.h = w;
}
- bpp = (ob->depth / 8);
- if (bpp <= 0) return;
+ bpp = ob->bpp / 8;
+ bw = ob->w;
+ bh = ob->h;
+ /* bpp = (ob->depth / 8); */
+ /* if (bpp <= 0) return; */
- bpl = buff->stride;
+ bpl = ecore_drm2_fb_stride_get(buff);
if (ob->rotation == 0)
{
RECTS_CLIP_TO_RECT(rect.x, rect.y, rect.w, rect.h,
- 0, 0, buff->w, buff->h);
+ 0, 0, bw, bh);
dst += (bpl * rect.y) + (rect.x * bpp);
w -= rx;
}
@@ -320,7 +569,7 @@ evas_outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int
{
pr = rect;
RECTS_CLIP_TO_RECT(rect.x, rect.y, rect.w, rect.h,
- 0, 0, buff->w, buff->h);
+ 0, 0, bw, bh);
rx = pr.w - rect.w;
ry = pr.h - rect.h;
src += (update->cache_entry.w * ry) + rx;
@@ -330,7 +579,7 @@ evas_outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int
{
pr = rect;
RECTS_CLIP_TO_RECT(rect.x, rect.y, rect.w, rect.h,
- 0, 0, buff->w, buff->h);
+ 0, 0, bw, bh);
rx = pr.w - rect.w; ry = pr.h - rect.h;
src += ry;
w -= ry;
@@ -339,7 +588,7 @@ evas_outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int
{
pr = rect;
RECTS_CLIP_TO_RECT(rect.x, rect.y, rect.w, rect.h,
- 0, 0, buff->w, buff->h);
+ 0, 0, bw, bh);
rx = pr.w - rect.w; ry = pr.h - rect.h;
src += (update->cache_entry.w * rx);
w -= ry;
@@ -352,13 +601,13 @@ evas_outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int
}
void
-evas_outbuf_update_region_free(Outbuf *ob EINA_UNUSED, RGBA_Image *update EINA_UNUSED)
+_outbuf_update_region_free(Outbuf *ob EINA_UNUSED, RGBA_Image *update EINA_UNUSED)
{
- /* evas_cache_image_drop(&update->cache_entry); */
+
}
void
-evas_outbuf_flush(Outbuf *ob, Tilebuf_Rect *rects EINA_UNUSED, Evas_Render_Mode render_mode)
+_outbuf_flush(Outbuf *ob, Tilebuf_Rect *rects EINA_UNUSED, Evas_Render_Mode render_mode)
{
Eina_Rectangle *r;
RGBA_Image *img;
@@ -367,19 +616,21 @@ evas_outbuf_flush(Outbuf *ob, Tilebuf_Rect *rects EINA_UNUSED, Evas_Render_Mode
if (render_mode == EVAS_RENDER_MODE_ASYNC_INIT) return;
/* get number of pending writes */
- n = eina_list_count(ob->priv.pending_writes);
+ n = eina_list_count(ob->priv.pending);
if (n == 0) return;
/* allocate rectangles */
- if (!(r = alloca(n * sizeof(Eina_Rectangle)))) return;
+ r = alloca(n * sizeof(Eina_Rectangle));
+ if (!r) return;
/* loop the pending writes */
- EINA_LIST_FREE(ob->priv.pending_writes, img)
+ EINA_LIST_FREE(ob->priv.pending, img)
{
Eina_Rectangle *rect;
int x = 0, y = 0, w = 0, h = 0;
- if (!(rect = img->extended_info)) continue;
+ rect = img->extended_info;
+ if (!rect) continue;
x = rect->x; y = rect->y; w = rect->w; h = rect->h;
@@ -430,11 +681,5 @@ evas_outbuf_flush(Outbuf *ob, Tilebuf_Rect *rects EINA_UNUSED, Evas_Render_Mode
}
/* force a buffer swap */
- _evas_outbuf_buffer_swap(ob, r, n);
-}
-
-int
-evas_outbuf_rot_get(Outbuf *ob)
-{
- return ob->rotation;
+ _outbuf_buffer_swap(ob, r, n);
}
diff --git a/src/modules/evas/engines/gl_drm/Evas_Engine_GL_Drm.h b/src/modules/evas/engines/gl_drm/Evas_Engine_GL_Drm.h
index 71ab60cefc..514aa80c09 100644
--- a/src/modules/evas/engines/gl_drm/Evas_Engine_GL_Drm.h
+++ b/src/modules/evas/engines/gl_drm/Evas_Engine_GL_Drm.h
@@ -1,7 +1,7 @@
#ifndef _EVAS_ENGINE_GL_DRM_H
# define _EVAS_ENGINE_GL_DRM_H
-# include <Ecore_Drm.h>
+# include <Ecore_Drm2.h>
# include <gbm.h>
typedef enum _Evas_Engine_Info_GL_Drm_Swap_Mode
@@ -26,11 +26,11 @@ struct _Evas_Engine_Info_GL_Drm
{
struct gbm_device *gbm;
+ int fd, bpp;
unsigned int rotation, depth;
- unsigned int crtc_id, conn_id, buffer_id;
unsigned int format, flags;
- Ecore_Drm_Device *dev;
+ void *output;
Eina_Bool destination_alpha : 1;
Eina_Bool vsync : 1;
diff --git a/src/modules/evas/engines/gl_drm/evas_engine.c b/src/modules/evas/engines/gl_drm/evas_engine.c
index d8d4312aee..29f2e0c533 100644
--- a/src/modules/evas/engines/gl_drm/evas_engine.c
+++ b/src/modules/evas/engines/gl_drm/evas_engine.c
@@ -118,12 +118,9 @@ static const EVGL_Interface evgl_funcs =
Eina_Bool
eng_gbm_init(Evas_Engine_Info_GL_Drm *info)
{
- Ecore_Drm_Device *dev;
-
if (!info) return EINA_FALSE;
- if (!(dev = info->info.dev)) return EINA_FALSE;
- if (!(info->info.gbm = gbm_create_device(dev->drm.fd)))
+ if (!(info->info.gbm = gbm_create_device(info->info.fd)))
{
ERR("Coult not create gbm device");
return EINA_FALSE;
@@ -146,13 +143,6 @@ eng_gbm_shutdown(Evas_Engine_Info_GL_Drm *info)
return EINA_TRUE;
}
-/* local inline functions */
-static inline Outbuf *
-eng_get_ob(Render_Engine *re)
-{
- return re->generic.software.ob;
-}
-
/* local functions */
static void
gl_symbols(void)
@@ -362,6 +352,8 @@ evgl_eng_native_window_create(void *data)
Render_Engine *re;
struct gbm_surface *surface;
Evas_Engine_Info_GL_Drm *info;
+ unsigned int format = GBM_FORMAT_XRGB8888;
+ unsigned int flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
re = (Render_Engine *)data;
if (!re)
@@ -377,9 +369,9 @@ evgl_eng_native_window_create(void *data)
return NULL;
}
- surface = gbm_surface_create(info->info.gbm,
- eng_get_ob(re)->w, eng_get_ob(re)->h,
- info->info.format, info->info.flags);
+ surface =
+ gbm_surface_create(info->info.gbm,
+ eng_get_ob(re)->w, eng_get_ob(re)->h, format, flags);
if (!surface)
{
ERR("Could not create gl drm window");
@@ -786,6 +778,37 @@ _native_cb_free(void *image)
free(n);
}
+static void
+_cb_vblank(int fd, unsigned int frame EINA_UNUSED, unsigned int sec EINA_UNUSED, unsigned int usec EINA_UNUSED, void *data)
+{
+ evas_outbuf_vblank(data, fd);
+}
+
+static void
+_cb_page_flip(int fd, unsigned int frame EINA_UNUSED, unsigned int sec EINA_UNUSED, unsigned int usec EINA_UNUSED, void *data)
+{
+ evas_outbuf_page_flip(data, fd);
+}
+
+static Eina_Bool
+_cb_drm_event(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED)
+{
+ Render_Engine *re;
+ int ret;
+
+ re = data;
+ if (!re) return EINA_TRUE;
+
+ ret = drmHandleEvent(re->fd, &re->ctx);
+ if (ret)
+ {
+ ERR("drmHandleEvent failed to read an event: %m");
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
/* engine specific override functions */
static void *
eng_info(Evas *eo_e EINA_UNUSED)
@@ -899,6 +922,17 @@ eng_setup(Evas *evas, void *in)
return 0;
}
+ re->fd = info->info.fd;
+
+ memset(&re->ctx, 0, sizeof(re->ctx));
+ re->ctx.version = DRM_EVENT_CONTEXT_VERSION;
+ re->ctx.vblank_handler = _cb_vblank;
+ re->ctx.page_flip_handler = _cb_page_flip;
+
+ re->hdlr =
+ ecore_main_fd_handler_add(info->info.fd, ECORE_FD_READ,
+ _cb_drm_event, re, NULL, NULL);
+
/* try to create new outbuf */
ob = evas_outbuf_new(info, epd->output.w, epd->output.h, swap_mode);
if (!ob)
@@ -970,16 +1004,16 @@ eng_setup(Evas *evas, void *in)
re->generic.software.ob = NULL;
gl_wins--;
+ if (ob_old) evas_outbuf_free(ob_old);
+
ob = evas_outbuf_new(info, epd->output.w, epd->output.h, swap_mode);
if (!ob)
{
- if (ob_old) evas_outbuf_free(ob_old);
free(re);
return 0;
}
evas_outbuf_use(ob);
- if (ob_old) evas_outbuf_free(ob_old);
ob->evas = evas;
@@ -1439,6 +1473,8 @@ module_open(Evas_Module *em)
return 0;
}
+ ecore_init();
+
/* store it for later use */
func = pfunc;
@@ -1471,6 +1507,8 @@ module_close(Evas_Module *em EINA_UNUSED)
/* unregister the eina log domain for this engine */
eina_log_domain_unregister(_evas_engine_gl_drm_log_dom);
_evas_engine_gl_drm_log_dom = -1;
+
+ ecore_shutdown();
}
static Evas_Module_Api evas_modapi =
diff --git a/src/modules/evas/engines/gl_drm/evas_engine.h b/src/modules/evas/engines/gl_drm/evas_engine.h
index f45a1995e6..8a51d59c93 100644
--- a/src/modules/evas/engines/gl_drm/evas_engine.h
+++ b/src/modules/evas/engines/gl_drm/evas_engine.h
@@ -7,6 +7,11 @@
# include "Evas.h"
# include "Evas_Engine_GL_Drm.h"
+# include <Ecore.h>
+# include <drm_fourcc.h>
+# include <xf86drm.h>
+# include <xf86drmMode.h>
+
# define EGL_EGLEXT_PROTOTYPES
# define GL_GLEXT_PROTOTYPES
@@ -64,6 +69,10 @@ typedef struct _Render_Engine Render_Engine;
struct _Render_Engine
{
Render_Engine_GL_Generic generic;
+
+ int fd;
+ drmEventContext ctx;
+ Ecore_Fd_Handler *hdlr;
};
struct _Context_3D
@@ -80,11 +89,10 @@ struct _Outbuf
Evas *evas; // used for pre_swap, post_swap
- int w, h;
- unsigned int rotation, depth;
+ int fd, w, h, bpp;
+ unsigned int rotation, depth, format;
Render_Engine_Swap_Mode swap_mode;
- /* struct gbm_device *gbm; */
struct gbm_surface *surface;
struct
@@ -98,6 +106,7 @@ struct _Outbuf
struct
{
struct gbm_bo *bo[2];
+ Ecore_Drm2_Output *output;
} priv;
Eina_Bool destination_alpha : 1;
@@ -123,6 +132,9 @@ void *evas_outbuf_update_region_new(Outbuf *ob, int x, int y, int w, int h, int
void evas_outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int w, int h);
void evas_outbuf_update_region_free(Outbuf *ob, RGBA_Image *update);
void evas_outbuf_flush(Outbuf *ob, Tilebuf_Rect *rects, Evas_Render_Mode render_mode);
+void evas_outbuf_vblank(void *data, int fd);
+void evas_outbuf_page_flip(void *data, int fd);
+
Evas_Engine_GL_Context* evas_outbuf_gl_context_get(Outbuf *ob);
void *evas_outbuf_egl_display_get(Outbuf *ob);
Context_3D *evas_outbuf_gl_context_new(Outbuf *ob);
@@ -138,6 +150,12 @@ _re_wincheck(Outbuf *ob)
return EINA_FALSE;
}
+static inline Outbuf *
+eng_get_ob(Render_Engine *re)
+{
+ return re->generic.software.ob;
+}
+
extern unsigned int (*glsym_eglSwapBuffersWithDamage)(EGLDisplay a, void *b, const EGLint *d, EGLint c);
extern unsigned int (*glsym_eglSetDamageRegionKHR)(EGLDisplay a, EGLSurface b, EGLint *c, EGLint d);
diff --git a/src/modules/evas/engines/gl_drm/evas_outbuf.c b/src/modules/evas/engines/gl_drm/evas_outbuf.c
index b120216608..ad3f2a0414 100644
--- a/src/modules/evas/engines/gl_drm/evas_outbuf.c
+++ b/src/modules/evas/engines/gl_drm/evas_outbuf.c
@@ -5,6 +5,7 @@
static Outbuf *_evas_gl_drm_window = NULL;
static EGLContext context = EGL_NO_CONTEXT;
static int win_count = 0;
+static Eina_Bool ticking = EINA_FALSE;
#ifdef EGL_MESA_platform_gbm
static PFNEGLGETPLATFORMDISPLAYEXTPROC dlsym_eglGetPlatformDisplayEXT = NULL;
@@ -12,6 +13,79 @@ static PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC dlsym_eglCreatePlatformWindowSur
#endif
static void
+_outbuf_tick_schedule(int fd, void *data)
+{
+ if (!ticking) return;
+
+ drmVBlank vbl =
+ {
+ .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
+ .request.sequence = 1,
+ .request.signal = (unsigned long)data,
+ };
+
+ drmWaitVBlank(fd, &vbl);
+}
+
+static void
+_outbuf_tick_begin(void *data)
+{
+ Outbuf *ob;
+
+ ob = data;
+ ticking = EINA_TRUE;
+ if (ob) _outbuf_tick_schedule(ob->fd, ob);
+}
+
+static void
+_outbuf_tick_end(void *data EINA_UNUSED)
+{
+ ticking = EINA_FALSE;
+}
+
+static void
+_outbuf_tick_source_set(Outbuf *ob)
+{
+ if (ob)
+ {
+ ecore_animator_custom_source_tick_begin_callback_set
+ (_outbuf_tick_begin, ob);
+ ecore_animator_custom_source_tick_end_callback_set
+ (_outbuf_tick_end, ob);
+ ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_CUSTOM);
+ }
+ else
+ {
+ ecore_animator_custom_source_tick_begin_callback_set(NULL, NULL);
+ ecore_animator_custom_source_tick_end_callback_set(NULL, NULL);
+ ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER);
+ }
+}
+
+void
+evas_outbuf_vblank(void *data, int fd)
+{
+ ecore_animator_custom_tick();
+ if (ticking) _outbuf_tick_schedule(fd, data);
+}
+
+void
+evas_outbuf_page_flip(void *data, int fd EINA_UNUSED)
+{
+ Outbuf *ob;
+ Ecore_Drm2_Fb *next;
+
+ ob = data;
+ next = ecore_drm2_output_next_fb_get(ob->priv.output);
+ if (next)
+ {
+ ecore_drm2_output_next_fb_set(ob->priv.output, NULL);
+ if (ecore_drm2_fb_flip(next, ob->priv.output, ob) < 0)
+ _outbuf_tick_source_set(NULL);
+ }
+}
+
+static void
_evas_outbuf_gbm_surface_destroy(Outbuf *ob)
{
if (!ob) return;
@@ -25,63 +99,51 @@ _evas_outbuf_gbm_surface_destroy(Outbuf *ob)
static void
_evas_outbuf_gbm_surface_create(Outbuf *ob, int w, int h)
{
+ unsigned int format = GBM_FORMAT_XRGB8888;
+ unsigned int flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
+
if (!ob) return;
ob->surface =
- gbm_surface_create(ob->info->info.gbm, w, h,
- ob->info->info.format, ob->info->info.flags);
+ gbm_surface_create(ob->info->info.gbm, w, h, format, flags);
if (!ob->surface) ERR("Failed to create gbm surface");
}
static void
-_evas_outbuf_fb_cb_destroy(struct gbm_bo *bo, void *data)
+_evas_outbuf_fb_cb_destroy(struct gbm_bo *bo EINA_UNUSED, void *data)
{
- Ecore_Drm_Fb *fb;
+ Ecore_Drm2_Fb *fb;
fb = data;
- if (fb)
- {
- struct gbm_device *gbm;
-
- gbm = gbm_bo_get_device(bo);
- drmModeRmFB(gbm_device_get_fd(gbm), fb->id);
- free(fb);
- }
+ if (fb) ecore_drm2_fb_destroy(fb);
}
-static Ecore_Drm_Fb *
-_evas_outbuf_fb_get(Ecore_Drm_Device *dev, struct gbm_bo *bo)
+static Ecore_Drm2_Fb *
+_evas_outbuf_fb_get(Outbuf *ob, struct gbm_bo *bo)
{
- int ret;
- Ecore_Drm_Fb *fb;
- uint32_t format;
- uint32_t handles[4], pitches[4], offsets[4];
+ Ecore_Drm2_Fb *fb;
+ uint32_t format, hdl, stride;
+ int w, h;
fb = gbm_bo_get_user_data(bo);
if (fb) return fb;
- if (!(fb = calloc(1, sizeof(Ecore_Drm_Fb)))) return NULL;
-
format = gbm_bo_get_format(bo);
-
- fb->w = gbm_bo_get_width(bo);
- fb->h = gbm_bo_get_height(bo);
- fb->hdl = gbm_bo_get_handle(bo).u32;
- fb->stride = gbm_bo_get_stride(bo);
- fb->size = fb->stride * fb->h;
-
- handles[0] = fb->hdl;
- pitches[0] = fb->stride;
- offsets[0] = 0;
-
- ret = drmModeAddFB2(dev->drm.fd, fb->w, fb->h, format,
- handles, pitches, offsets, &(fb->id), 0);
- if (ret)
- ret = drmModeAddFB(dev->drm.fd, fb->w, fb->h, 24, 32,
- fb->stride, fb->hdl, &(fb->id));
-
- if (ret) ERR("FAILED TO ADD FB: %m");
+ w = gbm_bo_get_width(bo);
+ h = gbm_bo_get_height(bo);
+ hdl = gbm_bo_get_handle(bo).u32;
+ stride = gbm_bo_get_stride(bo);
+ /* fb->size = fb->stride * fb->h; */
+
+ fb =
+ ecore_drm2_fb_gbm_create(ob->fd, w, h, ob->depth, ob->bpp,
+ format, hdl, stride);
+ if (!fb)
+ {
+ ERR("Failed to create FBO");
+ return NULL;
+ }
gbm_bo_set_user_data(bo, fb, _evas_outbuf_fb_cb_destroy);
@@ -91,7 +153,9 @@ _evas_outbuf_fb_get(Ecore_Drm_Device *dev, struct gbm_bo *bo)
static void
_evas_outbuf_buffer_swap(Outbuf *ob, Eina_Rectangle *rects, unsigned int count)
{
- Ecore_Drm_Fb *fb;
+ Ecore_Drm2_Fb *fb;
+
+ if (ob->priv.bo[1]) gbm_surface_release_buffer(ob->surface, ob->priv.bo[1]);
/* Repulsive hack: Right now we don't actually have a proper way to retire
* buffers because the ticker and the flip handler are out of sync, the
@@ -106,15 +170,48 @@ _evas_outbuf_buffer_swap(Outbuf *ob, Eina_Rectangle *rects, unsigned int count)
ob->priv.bo[0] = gbm_surface_lock_front_buffer(ob->surface);
if (!ob->priv.bo[0])
{
- WRN("Could not lock front buffer");
+ WRN("Could not lock front buffer: %m");
return;
}
- fb = _evas_outbuf_fb_get(ob->info->info.dev, ob->priv.bo[0]);
+
+ fb = _evas_outbuf_fb_get(ob, ob->priv.bo[0]);
if (fb)
{
- ecore_drm_fb_dirty(fb, rects, count);
- ecore_drm_fb_send(ob->info->info.dev, fb, NULL, NULL);
+ ecore_drm2_fb_dirty(fb, rects, count);
+ if (ecore_drm2_fb_flip(fb, ob->priv.output, ob) < 0)
+ _outbuf_tick_source_set(NULL);
+
+ /* Ecore_Drm2_Plane *plane; */
+
+ /* plane = ecore_drm2_plane_find(ob->priv.output, fb, ob->format); */
+ /* if (plane) */
+ /* { */
+ /* int ret; */
+ /* drmVBlank vbl = */
+ /* { */
+ /* .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT, */
+ /* .request.sequence = 1, */
+ /* }; */
+
+ /* vbl.request.type |= ecore_drm2_output_vblank_get(ob->priv.output); */
+ /* vbl.request.signal = (unsigned long)ob; */
+
+ /* ecore_drm2_fb_dirty(fb, rects, count); */
+
+ /* if (!ecore_drm2_plane_fb_set(plane, fb)) */
+ /* { */
+ /* ERR("Failed to set FB on Plane"); */
+ /* return; */
+ /* } */
+
+ /* ret = drmWaitVBlank(ob->fd, &vbl); */
+ /* if (ret) return; */
+ /* } */
+ /* else */
+ /* WRN("NO PLANE FOUND"); */
}
+ else
+ WRN("Could not get FBO from Bo");
}
static Eina_Bool
@@ -253,9 +350,6 @@ _evas_outbuf_egl_setup(Outbuf *ob)
return EINA_FALSE;
}
- DBG("Config Format: %d", format);
- DBG("OB Format: %d", ob->info->info.format);
-
if (format == (int)ob->info->info.format)
{
ob->egl.config = cfgs[i];
@@ -369,6 +463,11 @@ evas_outbuf_new(Evas_Engine_Info_GL_Drm *info, int w, int h, Render_Engine_Swap_
/* ob->vsync = info->info.vsync; */
ob->swap_mode = swap_mode;
+ ob->fd = info->info.fd;
+ ob->bpp = info->info.bpp;
+ ob->format = info->info.format;
+ ob->priv.output = info->info.output;
+
/* if ((num = getenv("EVAS_GL_DRM_VSYNC"))) */
/* ob->vsync = atoi(num); */
@@ -383,6 +482,8 @@ evas_outbuf_new(Evas_Engine_Info_GL_Drm *info, int w, int h, Render_Engine_Swap_
return NULL;
}
+ _outbuf_tick_source_set(ob);
+
return ob;
}
@@ -577,9 +678,7 @@ evas_outbuf_buffer_state_get(Outbuf *ob)
return swap_mode;
}
else
- {
- return MODE_FULL;
- }
+ return MODE_FULL;
return ob->swap_mode;
}