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 + +# 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 + +# include +# include +# include +# include +# include + +# include +# include +# include +# include +# include + +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 #endif #ifdef HAVE_ELEMENTARY_DRM -#include +#include #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 #endif -#include -#include #include #include #include "ecore_private.h" @@ -12,12 +10,12 @@ #include #include "ecore_evas_private.h" #include "ecore_evas_drm.h" -#include +#include #include +#include #ifdef BUILD_ECORE_EVAS_GL_DRM # include -# include # include #endif @@ -43,715 +41,213 @@ # endif #endif /* ! _WIN32 */ -typedef struct _Ecore_Evas_Engine_Drm_Data Ecore_Evas_Engine_Drm_Data; - -struct _Ecore_Evas_Engine_Drm_Data +typedef struct _Ecore_Evas_Engine_Drm_Data { - int w, h; -}; + 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; + +static int _drm_init_count = 0; -/* 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 = -{ - _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); - - 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 - - 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) -{ - Ecore_Evas *ee; - Evas_Engine_Info_Drm *einfo; - Ecore_Evas_Interface_Drm *iface; - Ecore_Evas_Engine_Drm_Data *edata; - int method; - - /* try to find the evas drm engine */ - if (!(method = evas_render_method_lookup("drm"))) - { - ERR("Render method lookup failed for Drm"); - return NULL; - } - - /* try to init drm */ - if (_ecore_evas_drm_init(device) < 1) return NULL; - - if (!ecore_drm_device_software_setup(dev)) - { - ERR("Could not setup device for software"); - goto soft_err; - } - - /* 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 = "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)) - { - 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; - } - - 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; - - 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_drm_device_pointer_xy_get(dev, &ev->x, &ev->y); - - ev->root.x = ev->x; - ev->root.y = ev->y; - - ecore_event_evas_mouse_move(NULL, ECORE_EVENT_MOUSE_MOVE, ev); - } - - return ee; - -eng_err: - ecore_evas_free(ee); -soft_err: -ee_err: - _ecore_evas_drm_shutdown(); - return NULL; -} - -#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) -{ - 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; - - /* 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; */ - - /* 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)) - { - 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_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); - } - - 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; - } - - 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); - - return ee; - -eng_err: - ecore_evas_free(ee); -ee_err: - _ecore_evas_drm_shutdown(); - return NULL; -} -#endif - -/* local functions */ static int -_ecore_evas_drm_init(const char *device) +_ecore_evas_drm_init(Ecore_Evas_Engine_Drm_Data *edata, const char *device) { - if (++_ecore_evas_init_count != 1) return _ecore_evas_init_count; + if (++_drm_init_count != 1) return _drm_init_count; - /* try to init ecore_drm */ - if (!ecore_drm_init()) + if (!ecore_drm2_init()) { - ERR("Could not initialize Ecore_Drm"); - return --_ecore_evas_init_count; + ERR("Failed to init Ecore_Drm2 library"); + goto init_err; } - /* try to find the device */ - if (!(dev = ecore_drm_device_find(device, NULL))) + if (!device) device = "seat0"; + + edata->dev = ecore_drm2_device_find(device, 0); + if (!edata->dev) { - 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; + ERR("Failed to create device"); + goto dev_err; } - if (!ecore_drm_launcher_connect(dev)) + edata->fd = ecore_drm2_device_open(edata->dev); + if (edata->fd < 0) { - ERR("Could not connect DRM launcher"); - goto launcher_err; + ERR("Failed to open device"); + goto open_err; } - /* try to open the graphics card */ - if (!ecore_drm_device_open(dev)) - { - ERR("Could not open drm device"); - goto dev_open_err; - } + edata->clockid = ecore_drm2_device_clock_id_get(edata->dev); + ecore_drm2_device_cursor_size_get(edata->dev, &edata->cw, &edata->ch); - /* try to create sprites */ - if (!ecore_drm_sprites_create(dev)) - { - ERR("Could not create sprites"); - goto sprite_err; - } - - /* try to create outputs */ - if (!ecore_drm_outputs_create(dev)) + if (!ecore_drm2_outputs_create(edata->dev)) { ERR("Could not create outputs"); goto output_err; } - /* try to create inputs */ - if (!ecore_drm_inputs_create(dev)) - { - ERR("Could not create inputs"); - goto input_err; - } + 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); ecore_event_evas_init(); - return _ecore_evas_init_count; + return _drm_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: + ecore_drm2_device_close(edata->dev); +open_err: + ecore_drm2_device_free(edata->dev); dev_err: - ecore_drm_shutdown(); - return --_ecore_evas_init_count; + ecore_drm2_shutdown(); +init_err: + return --_drm_init_count; } static int -_ecore_evas_drm_shutdown(void) +_ecore_evas_drm_shutdown(Ecore_Evas_Engine_Drm_Data *edata) { - 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; + if (--_drm_init_count != 0) return _drm_init_count; + 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(); - return _ecore_evas_init_count; + return _drm_init_count; } -static Ecore_Evas_Interface_Drm * -_ecore_evas_drm_interface_new(void) -{ - Ecore_Evas_Interface_Drm *iface; - - if (!(iface = calloc(1, sizeof(Ecore_Evas_Interface_Drm)))) - return NULL; - - iface->base.name = "drm"; - iface->base.version = 1; - - return iface; -} - -/* local ecore_evas functions */ static void -_ecore_evas_drm_free(Ecore_Evas *ee) +_drm_free(Ecore_Evas *ee) { - 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_evas_drm_shutdown(edata); + free(edata); } -static void -_ecore_evas_drm_callback_resize_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func) +static int +_drm_render_updates_process(Ecore_Evas *ee, Eina_List *updates) { - ee->func.fn_resize = func; + int rend = 0; + + if ((ee->visible) && (updates)) + { + _ecore_evas_idle_timeout_update(ee); + rend = 1; + } + else + evas_norender(ee->evas); + + if (ee->func.fn_post_render) ee->func.fn_post_render(ee); + + return rend; } static void -_ecore_evas_drm_callback_move_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func) +_drm_render_updates(void *data, Evas *evas EINA_UNUSED, void *event) { - ee->func.fn_move = func; + Evas_Event_Render_Post *ev; + Ecore_Evas *ee; + + ev = event; + if (!ev) return; + + ee = data; + if (!ee) return; + + ee->in_async_render = EINA_FALSE; + _drm_render_updates_process(ee, ev->updated_area); } -static void -_ecore_evas_drm_callback_focus_in_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func) +static int +_drm_render(Ecore_Evas *ee) { - ee->func.fn_focus_in = func; + int rend = 0; + Eina_List *l; + Ecore_Evas *ee2; + + if (ee->in_async_render) return 0; + + if (!ee->visible) + { + evas_norender(ee->evas); + return 0; + } + + EINA_LIST_FOREACH(ee->sub_ecore_evas, l, ee2) + { + 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); + } + + if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee); + + if (!ee->can_async_render) + { + Eina_List *updates; + + updates = evas_render_updates(ee->evas); + rend = _drm_render_updates_process(ee, updates); + evas_render_updates_free(updates); + } + else if (evas_render_async(ee->evas)) + { + ee->in_async_render = EINA_TRUE; + rend = 1; + } + + return rend; } static void -_ecore_evas_drm_callback_focus_out_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func) +_drm_screen_geometry_get(const Ecore_Evas *ee, int *x, int *y, int *w, int *h) { - ee->func.fn_focus_out = func; + Ecore_Evas_Engine_Drm_Data *edata; + + edata = ee->engine.data; + ecore_drm2_output_geometry_get(edata->output, x, y, w, h); } static void -_ecore_evas_drm_callback_mouse_in_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func) +_drm_pointer_xy_get(const Ecore_Evas *ee, Evas_Coord *x, Evas_Coord *y) { - ee->func.fn_mouse_in = func; + Ecore_Evas_Engine_Drm_Data *edata; + + edata = ee->engine.data; + ecore_drm2_device_pointer_xy_get(edata->dev, x, y); } -static void -_ecore_evas_drm_callback_mouse_out_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func) +static Eina_Bool +_drm_pointer_warp(const Ecore_Evas *ee, Evas_Coord x, Evas_Coord y) { - ee->func.fn_mouse_out = func; + Ecore_Evas_Engine_Drm_Data *edata; + + edata = ee->engine.data; + ecore_drm2_device_pointer_warp(edata->dev, x, y); + return EINA_TRUE; } static void -_ecore_evas_drm_delete_request_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func) -{ - ee->func.fn_delete_request = func; -} - -static void -_ecore_evas_drm_move(Ecore_Evas *ee, int x, int y) -{ - ee->req.x = x; - ee->req.y = y; - if ((ee->x == x) && (ee->y == y)) return; - ee->x = x; - ee->y = y; - if (ee->func.fn_move) ee->func.fn_move(ee); -} - -static void -_ecore_evas_drm_resize(Ecore_Evas *ee, int w, int h) -{ - ee->req.w = w; - ee->req.h = h; - if ((ee->w == w) && (ee->h == h)) return; - ee->w = w; - ee->h = h; - evas_output_size_set(ee->evas, w, h); - evas_output_viewport_set(ee->evas, 0, 0, w, h); - if (ee->func.fn_resize) ee->func.fn_resize(ee); -} - -static void -_ecore_evas_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); - if ((ee->w != w) || (ee->h != h)) - _ecore_evas_drm_resize(ee, w, h); -} - -static void -_ecore_evas_drm_rotation_set(Ecore_Evas *ee, int rotation, int resize EINA_UNUSED) -{ - Evas_Engine_Info_Drm *einfo; - - if (ee->rotation == rotation) return; - einfo = (Evas_Engine_Info_Drm *)evas_engine_info_get(ee->evas); - 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); -} - -static void -_ecore_evas_drm_show(Ecore_Evas *ee) +_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); + _drm_render(ee); if (ee->prop.override) { @@ -771,7 +267,7 @@ _ecore_evas_drm_show(Ecore_Evas *ee) } static void -_ecore_evas_drm_hide(Ecore_Evas *ee) +_drm_hide(Ecore_Evas *ee) { if ((!ee) || (!ee->visible)) return; @@ -790,7 +286,53 @@ _ecore_evas_drm_hide(Ecore_Evas *ee) } static void -_ecore_evas_drm_title_set(Ecore_Evas *ee, const char *title) +_drm_move(Ecore_Evas *ee, int x, int y) +{ + ee->req.x = x; + ee->req.y = y; + if ((ee->x == x) && (ee->y == y)) return; + ee->x = x; + ee->y = y; + if (ee->func.fn_move) ee->func.fn_move(ee); +} + +static void +_drm_resize(Ecore_Evas *ee, int w, int h) +{ + ee->req.w = w; + ee->req.h = h; + if ((ee->w == w) && (ee->h == h)) return; + ee->w = w; + ee->h = h; + evas_output_size_set(ee->evas, w, h); + evas_output_viewport_set(ee->evas, 0, 0, w, h); + if (ee->func.fn_resize) ee->func.fn_resize(ee); +} + +static void +_drm_move_resize(Ecore_Evas *ee, int x, int y, int w, int h) +{ + if ((ee->x != x) || (ee->y != y)) + _drm_move(ee, x, y); + if ((ee->w != w) || (ee->h != h)) + _drm_resize(ee, w, h); +} + +static void +_drm_rotation_set(Ecore_Evas *ee, int rotation, int resize EINA_UNUSED) +{ + Evas_Engine_Info_Drm *einfo; + + if (ee->rotation == rotation) return; + einfo = (Evas_Engine_Info_Drm *)evas_engine_info_get(ee->evas); + 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); +} + +static void +_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; + ee = data; + if (ee) ee->prop.cursor.object = NULL; } static void -_ecore_evas_drm_object_cursor_unset(Ecore_Evas *ee) +_drm_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int hot_x, int hot_y) { - evas_object_event_callback_del_full(ee->prop.cursor.object, EVAS_CALLBACK_DEL, _ecore_evas_drm_object_cursor_del, ee); -} - -static void -_ecore_evas_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) - { - evas_norender(ee->evas); - return 0; - } + iface->base.name = "drm"; + iface->base.version = 1; - EINA_LIST_FOREACH(ee->sub_ecore_evas, l, ee2) - { - 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); - } - - if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee); - - if (!ee->can_async_render) - { - Eina_List *updates; - - 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)) - { - ee->in_async_render = EINA_TRUE; - rend = 1; - } - - return rend; + return iface; } -static void -_ecore_evas_drm_render_updates(void *data, Evas *evas EINA_UNUSED, void *event) +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) { - Evas_Event_Render_Post *ev; Ecore_Evas *ee; + Evas_Engine_Info_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("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); - - /* TODO: handle delayed changes */ -} - -static int -_ecore_evas_drm_render_updates_process(Ecore_Evas *ee, Eina_List *updates) -{ - int rend = 0; - - if ((ee->visible) && (updates)) + edata = calloc(1, sizeof(Ecore_Evas_Engine_Drm_Data)); + if (!edata) { -// Eina_List *l = NULL; -// Eina_Rectangle *r; -// -// EINA_LIST_FOREACH(updates, l, r) -// { -// /* TODO */ -// } - - _ecore_evas_idle_timeout_update(ee); - rend = 1; + free(ee); + return NULL; } - else - evas_norender(ee->evas); - if (ee->func.fn_post_render) ee->func.fn_post_render(ee); + 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; - return rend; + if (_ecore_evas_drm_init(edata, device) < 1) + { + free(edata); + free(ee); + return NULL; + } + + ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS); + + ee->driver = "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 = 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) + { + 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; + } + } + + 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_screen_geometry_get(const Ecore_Evas *ee EINA_UNUSED, int *x, int *y, int *w, int *h) +#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) { - ecore_drm_outputs_geometry_get(dev, x, y, w, h); -} + Ecore_Evas *ee; + Evas_Engine_Info_GL_Drm *einfo; + Ecore_Evas_Interface_Drm *iface; + Ecore_Evas_Engine_Drm_Data *edata; + int method, mw, mh; -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); -} + method = evas_render_method_lookup("gl_drm"); + if (!method) return NULL; -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; + ee = calloc(1, sizeof(Ecore_Evas)); + if (!ee) return NULL; + + edata = calloc(1, sizeof(Ecore_Evas_Engine_Drm_Data)); + if (!edata) + { + free(ee); + return NULL; + } + + 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; + + dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL); + if (dlerror()) + { + free(edata); + free(ee); + return NULL; + } + + if (_ecore_evas_drm_init(edata, device) < 1) + { + free(edata); + free(ee); + return NULL; + } + + 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; + } + } + + 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; } +#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 - -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; + int fd; + int depth, bpp; + unsigned int format, rotation; + + void *output; + Eina_Bool alpha : 1; Eina_Bool vsync : 1; - - unsigned int crtc_id, conn_id, buffer_id; - - Eina_Bool use_hw_accel : 1; - Ecore_Drm_Device *dev; } 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 +# include +# include +# include +# include -#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__) +typedef struct _Outbuf_Fb +{ + int age; + Ecore_Drm2_Fb *fb; + + Eina_Bool valid : 1; + Eina_Bool drawn : 1; + Eina_Bool busy : 1; +} Outbuf_Fb; + struct _Outbuf { - Evas_Engine_Info_Drm *info; - - int w, h; - int rotation; - unsigned int depth; + 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) { - Ecore_Drm_Fb *buff; + Outbuf *ob; - buff = ob->priv.buffer[ob->priv.curr]; + ob = data; + ticking = EINA_TRUE; + if (ob) _outbuf_tick_schedule(ob->fd, ob); +} - /* mark the fb as dirty */ - ecore_drm_fb_dirty(buff, rects, count); +static void +_outbuf_tick_end(void *data EINA_UNUSED) +{ + ticking = EINA_FALSE; +} - /* send this buffer to the crtc */ - ecore_drm_fb_send(ob->info->info.dev, buff, NULL, NULL); +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); + } +} - ob->priv.last = ob->priv.curr; - ob->priv.curr = (ob->priv.curr + 1) % ob->priv.num; +static void +_outbuf_tick_schedule(int fd EINA_UNUSED, void *data) +{ + if (!ticking) return; + + drmVBlank vbl = + { + .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT, + .request.sequence = 1, + .request.signal = (unsigned long)data, + }; + + if (drmWaitVBlank(fd, &vbl) < 0) + _outbuf_tick_source_set(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); +} + +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->info = info; - ob->depth = info->info.depth; + ob->fd = info->info.fd; + ob->alpha = info->info.alpha; ob->rotation = info->info.rotation; - ob->destination_alpha = info->info.destination_alpha; - ob->vsync = info->info.vsync; - /* we must triple-buffer to prevent problems with the page flip handler */ + ob->bpp = info->info.bpp; + ob->depth = info->info.depth; + ob->format = info->info.format; + + ob->priv.output = info->info.output; + 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; - - delta = (ob->priv.last - ob->priv.curr + ob->priv.num) % ob->priv.num; - - /* This is the number of frame since last frame */ - switch (delta) + while (iter++ < 10) { - case 0: - return MODE_COPY; - case 1: - return MODE_DOUBLE; - case 2: - return MODE_TRIPLE; - case 3: - return MODE_QUADRUPLE; - default: - return MODE_FULL; + 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; +} + +static Eina_Bool +_outbuf_fb_assign(Outbuf *ob) +{ + int i; + + ob->priv.current = _outbuf_fb_wait(ob); + + if (!ob->priv.current) + { + 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 +# include # include 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 +# include +# include +# include + # 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,12 +5,86 @@ 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; static PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC dlsym_eglCreatePlatformWindowSurfaceEXT = NULL; #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) { @@ -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); + 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->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"); + 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; }