Merge branch 'devs/devilhorns/ecore_drm2'

This new Ecore_Drm2 library is going to replace the existing Ecore_Drm.
This will refactor a lot of the code, bring improvements over the existing API,
and provide additional support for missing features such as
atomic modeset, nuclear pageflip, and hardware planes support.

@feature
This commit is contained in:
Chris Michael 2016-05-27 11:58:51 -04:00
commit 3c50101f73
26 changed files with 4154 additions and 1103 deletions

View File

@ -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 = \

View File

@ -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

View File

@ -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])}"

View File

@ -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"])

1
pc/.gitignore vendored
View File

@ -74,3 +74,4 @@
/efl-js.pc
/elementary-cxx.pc
/elput.pc
/ecore-drm2.pc

12
pc/ecore-drm2.pc.in Normal file
View File

@ -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@

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,771 @@
#ifndef _ECORE_DRM2_H
# define _ECORE_DRM2_H
# include <Ecore.h>
# ifdef EAPI
# undef EAPI
# endif
# ifdef _MSC_VER
# ifdef BUILDING_DLL
# define EAPI __declspec(dllexport)
# else // ifdef BUILDING_DLL
# define EAPI __declspec(dllimport)
# endif // ifdef BUILDING_DLL
# else // ifdef _MSC_VER
# ifdef __GNUC__
# if __GNUC__ >= 4
# define EAPI __attribute__ ((visibility("default")))
# else // if __GNUC__ >= 4
# define EAPI
# endif // if __GNUC__ >= 4
# else // ifdef __GNUC__
# define EAPI
# endif // ifdef __GNUC__
# endif // ifdef _MSC_VER
# ifdef EFL_BETA_API_SUPPORT
/* opaque structure to represent a drm device */
typedef struct _Ecore_Drm2_Device Ecore_Drm2_Device;
/* opaque structure to represent a framebuffer object */
typedef struct _Ecore_Drm2_Fb Ecore_Drm2_Fb;
/* opaque structure to represent an output device */
typedef struct _Ecore_Drm2_Output Ecore_Drm2_Output;
/* opaque structure to represent an output mode */
typedef struct _Ecore_Drm2_Output_Mode Ecore_Drm2_Output_Mode;
/* structure to represent event for output changes */
typedef struct _Ecore_Drm2_Event_Output_Changed
{
unsigned int id;
int x, y, w, h;
int phys_width, phys_height;
unsigned int refresh, scale;
int subpixel, transform;
const char *make, *model, *name;
Eina_Bool connected : 1;
Eina_Bool enabled : 1;
} Ecore_Drm2_Event_Output_Changed;
/* structure to represent event for session state changes */
typedef struct _Ecore_Drm2_Event_Activate
{
Eina_Bool active : 1;
} Ecore_Drm2_Event_Activate;
EAPI extern int ECORE_DRM2_EVENT_OUTPUT_CHANGED;
EAPI extern int ECORE_DRM2_EVENT_ACTIVATE;
/**
* @file
* @brief Ecore functions for dealing with drm, virtual terminals
*
* @defgroup Ecore_Drm2_Group Ecore_Drm2 - Drm Integration
* @ingroup Ecore
*
* Ecore_Drm2 provides a wrapper and functions for using libdrm
*
* @li @ref Ecore_Drm2_Init_Group
* @li @ref Ecore_Drm2_Device_Group
* @li @ref Ecore_Drm2_Output_Group
* @li @ref Ecore_Drm2_Fb_Group
*/
/**
* @defgroup Ecore_Drm2_Init_Group Drm library Init and Shutdown functions
*
* Functions that start and shutdown the Ecore_Drm2 library
*/
/**
* Initialize the Ecore_Drm2 library
*
* @return The number of times the library has been initialized without
* being shut down. 0 is returned if an error occurs.
*
* @ingroup Ecore_Drm2_Init_Group
* @since 1.18
*/
EAPI int ecore_drm2_init(void);
/**
* Shutdown the Ecore_Drm2 library
*
* @return The number of times the library has been initialized without
* being shutdown. 0 is returned if an error occurs.
*
* @ingroup Ecore_Drm2_Init_Group
* @since 1.18
*/
EAPI int ecore_drm2_shutdown(void);
/**
* @defgroup Ecore_Drm2_Device_Group Drm device functions
*
* Functions that deal with finding, opening, closing, or obtaining various
* information about a drm device
*/
/**
* Try to find a drm device on a given seat
*
* @param seat
* @param tty
* @param sync
*
* @return A newly allocated Ecore_Drm2_Device on success, NULL otherwise
*
* @ingroup Ecore_Drm2_Device_Group
* @since 1.18
*/
EAPI Ecore_Drm2_Device *ecore_drm2_device_find(const char *seat, unsigned int tty);
/**
* Try to open a given Ecore_Drm2_Device
*
* @param device
*
* @return A valid file descriptor if open succeeds, -1 otherwise.
*
* @ingroup Ecore_Drm2_Device_Group
* @since 1.18
*/
EAPI int ecore_drm2_device_open(Ecore_Drm2_Device *device);
/**
* Close an open Ecore_Drm2_Device
*
* @param device
*
* @ingroup Ecore_Drm2_Device_Group
* @since 1.18
*/
EAPI void ecore_drm2_device_close(Ecore_Drm2_Device *device);
/**
* Free a given Ecore_Drm2_Device
*
* @param device
*
* @ingroup Ecore_Drm2_Device_Group
* @since 1.18
*/
EAPI void ecore_drm2_device_free(Ecore_Drm2_Device *device);
/**
* Get the type of clock used by a given Ecore_Drm2_Device
*
* @param device
*
* @return The clockid_t used by this drm device
*
* @ingroup Ecore_Drm2_Device_Group
* @since 1.18
*/
EAPI int ecore_drm2_device_clock_id_get(Ecore_Drm2_Device *device);
/**
* Get the size of the cursor supported by a given Ecore_Drm2_Device
*
* @param device
* @param width
* @param height
*
* @ingroup Ecore_Drm2_Device_Group
* @since 1.18
*/
EAPI void ecore_drm2_device_cursor_size_get(Ecore_Drm2_Device *device, int *width, int *height);
/**
* Get the current pointer position
*
* @param device
* @param x
* @param y
*
* @ingroup Ecore_Drm2_Device_Group
* @since 1.18
*/
EAPI void ecore_drm2_device_pointer_xy_get(Ecore_Drm2_Device *device, int *x, int *y);
/**
* Warp the pointer position to given coordinates
*
* @param dev
* @param x
* @param y
*
* @ingroup Ecore_Drm2_Device_Group
* @since 1.18
*/
EAPI void ecore_drm2_device_pointer_warp(Ecore_Drm2_Device *device, int x, int y);
/**
* Set a left handed mode for the given device
*
* @param device
* @param left
*
* @return EINA_TRUE on success, EINA_FALSE otherwise
*
* @ingroup Ecore_Drm2_Device_Group
* @since 1.18
*/
EAPI Eina_Bool ecore_drm2_device_pointer_left_handed_set(Ecore_Drm2_Device *device, Eina_Bool left);
/**
* Set which window is to be used for input events
*
* @param device
* @param window
*
* @ingroup Ecore_Drm2_Device_Group
* @since 1.18
*/
EAPI void ecore_drm2_device_window_set(Ecore_Drm2_Device *device, unsigned int window);
/**
* Set maximium position that pointer device is allowed to move
*
* @param device
* @param w
* @param h
*
* @ingroup Ecore_Drm2_Device_Group
* @since 1.18
*/
EAPI void ecore_drm2_device_pointer_max_set(Ecore_Drm2_Device *device, int w, int h);
/**
* Set a cached context to be used on keyboards
*
* @param device
* @param context
*
* @ingroup Ecore_Drm2_Device_Group
* @since 1.18
*/
EAPI void ecore_drm2_device_keyboard_cached_context_set(Ecore_Drm2_Device *device, void *context);
/**
* Set a cached keymap to be used on keyboards
*
* @param device
* @param keymap
*
* @ingroup Ecore_Drm2_Device_Group
* @since 1.18
*/
EAPI void ecore_drm2_device_keyboard_cached_keymap_set(Ecore_Drm2_Device *device, void *keymap);
/**
* Get the crtcs of a given device
*
* @param device
* @param num
*
* @return The crtcs of this given device or NULL on failure
*
* @ingroup Ecore_Drm2_Device_Group
* @since 1.18
*/
EAPI unsigned int *ecore_drm2_device_crtcs_get(Ecore_Drm2_Device *device, int *num);
/**
* Get the minimum and maximum screen size range
*
* @param device
* @param *minw
* @param *minh
* @param *maxw
* @param *maxh
*
* @ingroup Ecore_Drm2_Device_Group
* @since 1.18
*/
EAPI void ecore_drm2_device_screen_size_range_get(Ecore_Drm2_Device *device, int *minw, int *minh, int *maxw, int *maxh);
/**
* Calibrate any input devices for given screen size
*
* @param device
* @param w
* @param h
*
* @ingroup Ecore_Drm2_Device_Group
* @since 1.18
*/
EAPI void ecore_drm2_device_calibrate(Ecore_Drm2_Device *device, int w, int h);
/**
* @defgroup Ecore_Drm2_Output_Group Drm output functions
*
* Functions that deal with setup of outputs
*/
/**
* Iterate drm resources and create outputs
*
* @param device
*
* @return EINA_TRUE on success, EINA_FALSE otherwise
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI Eina_Bool ecore_drm2_outputs_create(Ecore_Drm2_Device *device);
/**
* Destroy any created outputs
*
* @param device
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI void ecore_drm2_outputs_destroy(Ecore_Drm2_Device *device);
/**
* Get the list of outputs from a drm device
*
* @param device
*
* @return
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI const Eina_List *ecore_drm2_outputs_get(Ecore_Drm2_Device *device);
/**
* Get the dpms level of a given output
*
* @param output
*
* @return Integer value representing the state of DPMS on a given output
* or -1 on error
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI int ecore_drm2_output_dpms_get(Ecore_Drm2_Output *output);
/**
* Set the dpms level of a given output
*
* @param output
* @param level
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI void ecore_drm2_output_dpms_set(Ecore_Drm2_Output *output, int level);
/**
* Get the edid of a given output
*
* @param output
*
* @return A string representing the edid
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI char *ecore_drm2_output_edid_get(Ecore_Drm2_Output *output);
/**
* Get if a given output has a backlight
*
* @param output
*
* @return EINA_TRUE if this output has a backlight, EINA_FALSE otherwise
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI Eina_Bool ecore_drm2_output_backlight_get(Ecore_Drm2_Output *output);
/**
* Find an output at the given position
*
* @param device
* @param x
* @param y
*
* @return An Ecore_Drm2_Output which exists at the given coordinates, or NULL on failure
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI Ecore_Drm2_Output *ecore_drm2_output_find(Ecore_Drm2_Device *device, int x, int y);
/**
* Get the geometry of a given output
*
* @param output
* @param x
* @param y
* @param w
* @param h
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI void ecore_drm2_output_geometry_get(Ecore_Drm2_Output *output, int *x, int *y, int *w, int *h);
/**
* Get the id of the crtc that an output is using
*
* @param output
*
* @return A valid crtc id or 0 on failure
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI unsigned int ecore_drm2_output_crtc_get(Ecore_Drm2_Output *output);
/**
* Return the next Ecore_Drm2_Fb to be used on a given output
*
* @param output
*
* @return The next Ecore_Drm2_Fb which is scheduled to to be flipped, or NULL otherwise
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI Ecore_Drm2_Fb *ecore_drm2_output_next_fb_get(Ecore_Drm2_Output *output);
/**
* Return the current Ecore_Drm2_Fb used on a given output
*
* @param output
*
* @return The current Ecore_Drm2_Fb used on this output, or NULL otherwise
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI Ecore_Drm2_Fb *ecore_drm2_output_current_fb_get(Ecore_Drm2_Output *output);
/**
* Set the next Ecore_Drm2_Fb to be used on a given output
*
* @param output
* @param fb
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI void ecore_drm2_output_next_fb_set(Ecore_Drm2_Output *output, Ecore_Drm2_Fb *fb);
/**
* Get the size of the crtc for a given output
*
* @param output
* @param *w
* @param *h
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI void ecore_drm2_output_crtc_size_get(Ecore_Drm2_Output *output, int *w, int *h);
/**
* Get if a given output is marked as the primary output
*
* @param output
*
* @return EINA_TRUE if output is primary, EINA_FALSE otherwise
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI Eina_Bool ecore_drm2_output_primary_get(Ecore_Drm2_Output *output);
/**
* Set a given output to be primary
*
* @param output
* @param primary
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI void ecore_drm2_output_primary_set(Ecore_Drm2_Output *output, Eina_Bool primary);
/**
* Get if a given output is enabled
*
* @param output
*
* @return EINA_TRUE if enabled, EINA_FALSE otherwise.
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI Eina_Bool ecore_drm2_output_enabled_get(Ecore_Drm2_Output *output);
/**
* Set if a given output is enabled
*
* @param output
* @param enabled
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI void ecore_drm2_output_enabled_set(Ecore_Drm2_Output *output, Eina_Bool enabled);
/**
* Get the physical size of a given output
*
* This function will give the physical size (in mm) of an output
*
* @param output
* @param *w
* @param *h
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI void ecore_drm2_output_physical_size_get(Ecore_Drm2_Output *output, int *w, int *h);
/**
* Get a list of the modes supported on a given output
*
* @param output
*
* @return An Eina_List of the modes supported for this output
*
* @note The returned list should not be freed
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI const Eina_List *ecore_drm2_output_modes_get(Ecore_Drm2_Output *output);
/**
* Get information from an existing output mode
*
* @param mode
* @param w
* @param h
* @param refresh
* @param flags
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI void ecore_drm2_output_mode_info_get(Ecore_Drm2_Output_Mode *mode, int *w, int *h, unsigned int *refresh, unsigned int *flags);
/**
* Set a given mode to be used on a given output
*
* @param output
* @param mode
* @param x
* @param y
*
* @return EINA_TRUE on success, EINA_FALSE otherwise
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI Eina_Bool ecore_drm2_output_mode_set(Ecore_Drm2_Output *output, Ecore_Drm2_Output_Mode *mode, int x, int y);
/**
* Get the name of a given output
*
* @param output
*
* @return A string representing the output's name. Caller should free this return.
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI char *ecore_drm2_output_name_get(Ecore_Drm2_Output *output);
/**
* Get the model of a given output
*
* @param output
*
* @return A string representing the output's model. Caller should free this return.
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI char *ecore_drm2_output_model_get(Ecore_Drm2_Output *output);
/**
* Get if a given output is connected
*
* @param output
*
* @return EINA_TRUE if connected, EINA_FALSE otherwise
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI Eina_Bool ecore_drm2_output_connected_get(Ecore_Drm2_Output *output);
/**
* Get if a given output is cloned
*
* @param output
*
* @return EINA_TRUE if cloned, EINA_FALSE otherwise.
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI Eina_Bool ecore_drm2_output_cloned_get(Ecore_Drm2_Output *output);
/**
* Get the connector type of a given output
*
* @param output
*
* @return An unsigned integer representing the type of connector for this output
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI unsigned int ecore_drm2_output_connector_type_get(Ecore_Drm2_Output *output);
/**
* Get the current resolution of a given output
*
* @param output
* @param *w
* @param *h
* @param *refresh
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI void ecore_drm2_output_resolution_get(Ecore_Drm2_Output *output, int *w, int *h, unsigned int *refresh);
/**
* Get if an output can be used on a given crtc
*
* This function will loop the possible crtcs of an encoder to determine if
* a given output can be assigned to a given crtc
*
* @param output
* @param crtc
*
* @return EINA_TRUE if the output can be assigned to given crtc, EINA_FALSE otherwise
*
* @ingroup Ecore_Drm2_Output_Group
* @since 1.18
*/
EAPI Eina_Bool ecore_drm2_output_possible_crtc_get(Ecore_Drm2_Output *output, unsigned int crtc);
/**
* @defgroup Ecore_Drm2_Fb_Group Drm framebuffer functions
*
* Functions that deal with setup of framebuffers
*/
/**
* Create a new framebuffer object
*
* @param fd
* @param width
* @param height
* @param depth
* @param bpp
* @param format
*
* @return A newly create framebuffer object, or NULL on failure
*
* @ingroup Ecore_Drm2_Fb_Group
* @since 1.18
*/
EAPI Ecore_Drm2_Fb *ecore_drm2_fb_create(int fd, int width, int height, int depth, int bpp, unsigned int format);
EAPI Ecore_Drm2_Fb *ecore_drm2_fb_gbm_create(int fd, int width, int height, int depth, int bpp, unsigned int format, unsigned int handle, unsigned int stride);
/**
* Destroy a framebuffer object
*
* @param fb
*
* @ingroup Ecore_Drm2_Fb_Group
* @since 1.18
*/
EAPI void ecore_drm2_fb_destroy(Ecore_Drm2_Fb *fb);
/**
* Get a framebuffer's mmap'd data
*
* @param fb
*
* @return The mmap'd area of the framebuffer or NULL on failure
*
* @ingroup Ecore_Drm2_Fb_Group
* @since 1.18
*/
EAPI void *ecore_drm2_fb_data_get(Ecore_Drm2_Fb *fb);
/**
* Get a framebuffer's size
*
* @param fb
*
* @return size of the framebuffers' mmap'd data or 0 on failure
*
* @ingroup Ecore_Drm2_Fb_Group
* @since 1.18
*/
EAPI unsigned int ecore_drm2_fb_size_get(Ecore_Drm2_Fb *fb);
/**
* Get a framebuffer's stride
*
* @param fb
*
* @return stride of the framebuffer or 0 on failure
*
* @ingroup Ecore_Drm2_Fb_Group
* @since 1.18
*/
EAPI unsigned int ecore_drm2_fb_stride_get(Ecore_Drm2_Fb *fb);
/**
* Mark regions of a framebuffer as dirty
*
* @param fb
* @param rects
* @param count
*
* @ingroup Ecore_Drm2_Fb_Group
* @since 1.18
*/
EAPI void ecore_drm2_fb_dirty(Ecore_Drm2_Fb *fb, Eina_Rectangle *rects, unsigned int count);
/**
* Schedule a pageflip to the given Ecore_Drm2_Fb
*
* @param fb
* @param output
* @param data
*
* @return The result of drmModePageFlip function call
*
* @ingroup Ecore_Drm2_Fb_Group
* @since 1.18
*/
EAPI int ecore_drm2_fb_flip(Ecore_Drm2_Fb *fb, Ecore_Drm2_Output *output, void *data);
# endif
#endif

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,185 @@
#ifndef _ECORE_DRM2_PRIVATE_H
# define _ECORE_DRM2_PRIVATE_H
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
# include "Ecore.h"
# include "ecore_private.h"
# include "Eeze.h"
# include "Elput.h"
# include <Ecore_Drm2.h>
# include <unistd.h>
# include <strings.h>
# include <sys/mman.h>
# include <fcntl.h>
# include <ctype.h>
# include <sys/ioctl.h>
# include <xf86drm.h>
# include <xf86drmMode.h>
# include <drm_mode.h>
# include <drm_fourcc.h>
extern int _ecore_drm2_log_dom;
# ifdef ECORE_DRM2_DEFAULT_LOG_COLOR
# undef ECORE_DRM2_DEFAULT_LOG_COLOR
# endif
# define ECORE_DRM2_DEFAULT_LOG_COLOR EINA_COLOR_BLUE
# ifdef ERR
# undef ERR
# endif
# define ERR(...) EINA_LOG_DOM_ERR(_ecore_drm2_log_dom, __VA_ARGS__)
# ifdef DBG
# undef DBG
# endif
# define DBG(...) EINA_LOG_DOM_DBG(_ecore_drm2_log_dom, __VA_ARGS__)
# ifdef INF
# undef INF
# endif
# define INF(...) EINA_LOG_DOM_INFO(_ecore_drm2_log_dom, __VA_ARGS__)
# ifdef WRN
# undef WRN
# endif
# define WRN(...) EINA_LOG_DOM_WARN(_ecore_drm2_log_dom, __VA_ARGS__)
# ifdef CRIT
# undef CRIT
# endif
# define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_drm2_log_dom, __VA_ARGS__)
typedef enum _Ecore_Drm2_Backlight_Type
{
ECORE_DRM2_BACKLIGHT_RAW,
ECORE_DRM2_BACKLIGHT_PLATFORM,
ECORE_DRM2_BACKLIGHT_FIRMWARE
} Ecore_Drm2_Backlight_Type;
typedef enum _Ecore_Drm2_Transform
{
ECORE_DRM2_TRANSFORM_NORMAL,
ECORE_DRM2_TRANSFORM_90,
ECORE_DRM2_TRANSFORM_180,
ECORE_DRM2_TRANSFORM_270,
ECORE_DRM2_TRANSFORM_FLIPPED,
ECORE_DRM2_TRANSFORM_FLIPPED_90,
ECORE_DRM2_TRANSFORM_FLIPPED_180,
ECORE_DRM2_TRANSFORM_FLIPPED_270
} Ecore_Drm2_Transform;
typedef enum _Ecore_Drm2_Rotation
{
ECORE_DRM2_ROTATION_NORMAL = 1,
ECORE_DRM2_ROTATION_90 = 2,
ECORE_DRM2_ROTATION_180 = 4,
ECORE_DRM2_ROTATION_270 = 8,
ECORE_DRM2_ROTATION_REFLECT_X = 16,
ECORE_DRM2_ROTATION_REFLECT_Y = 32
} Ecore_Drm2_Rotation;
struct _Ecore_Drm2_Fb
{
int fd;
int w, h;
int depth, bpp;
uint32_t id, hdl;
uint32_t stride, size;
uint32_t format;
Eina_Bool gbm : 1;
void *mmap;
};
struct _Ecore_Drm2_Output_Mode
{
uint32_t flags;
int32_t width, height;
uint32_t refresh;
drmModeModeInfo info;
};
struct _Ecore_Drm2_Output
{
Eina_Stringshare *name;
Eina_Stringshare *make, *model, *serial;
int fd;
int pipe;
int x, y, w, h, pw, ph;
uint32_t subpixel;
uint32_t crtc_id, conn_id, conn_type;
uint32_t scale;
struct
{
char eisa[13];
char monitor[13];
char pnp[5];
char serial[13];
unsigned char *blob; // unused when doing atomic
} edid;
struct
{
const char *path;
int value, max;
Ecore_Drm2_Backlight_Type type;
} backlight;
drmModeCrtcPtr ocrtc;
Ecore_Drm2_Fb *current, *next;
Eina_Matrix4 matrix, inverse;
Ecore_Drm2_Transform transform;
/* unused when doing atomic */
drmModePropertyPtr dpms;
Ecore_Drm2_Output_Mode *current_mode;
Eina_List *modes;
Eina_List *planes;
Eina_Bool connected : 1;
Eina_Bool primary : 1;
Eina_Bool cloned : 1;
Eina_Bool enabled : 1;
};
struct _Ecore_Drm2_Device
{
Elput_Manager *em;
int fd;
const char *path;
int num_crtcs;
uint32_t *crtcs;
struct
{
uint32_t crtc, conn;
} alloc;
struct
{
uint32_t width, height;
} min, max;
Eeze_Udev_Watch *watch;
Ecore_Event_Handler *active_hdlr;
Eina_List *outputs;
};
#endif

View File

@ -10,7 +10,7 @@
#include <Ecore_Wl2.h>
#endif
#ifdef HAVE_ELEMENTARY_DRM
#include <Ecore_Drm.h>
#include <Ecore_Drm2.h>
#endif
#ifdef HAVE_ELEMENTARY_COCOA
/* Ecore_Cocoa is still in Beta. In Elementary, we know what we are

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,7 @@
#ifndef _EVAS_ENGINE_DRM_H
# define _EVAS_ENGINE_DRM_H
# include <Ecore_Drm.h>
typedef struct _Evas_Engine_Info_Drm Evas_Engine_Info_Drm;
struct _Evas_Engine_Info_Drm
typedef struct _Evas_Engine_Info_Drm
{
/* PRIVATE - don't mess with this baby or evas will poke its tongue out */
/* at you and make nasty noises */
@ -13,18 +9,17 @@ struct _Evas_Engine_Info_Drm
struct
{
unsigned int rotation, depth;
Eina_Bool destination_alpha : 1;
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

View File

@ -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 =

View File

@ -6,8 +6,13 @@
# include "evas_private.h"
# include "Evas.h"
# include "Evas_Engine_Drm.h"
# include <Ecore.h>
# include <Ecore_Drm2.h>
# include <drm_fourcc.h>
# include <xf86drm.h>
# include <xf86drmMode.h>
#include "../software_generic/Evas_Engine_Software_Generic.h"
# include "../software_generic/Evas_Engine_Software_Generic.h"
extern int _evas_engine_drm_log_dom;
@ -36,35 +41,44 @@ extern int _evas_engine_drm_log_dom;
# endif
# define CRI(...) EINA_LOG_DOM_CRIT(_evas_engine_drm_log_dom, __VA_ARGS__)
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

View File

@ -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);
}

View File

@ -1,7 +1,7 @@
#ifndef _EVAS_ENGINE_GL_DRM_H
# define _EVAS_ENGINE_GL_DRM_H
# include <Ecore_Drm.h>
# include <Ecore_Drm2.h>
# include <gbm.h>
typedef enum _Evas_Engine_Info_GL_Drm_Swap_Mode
@ -26,11 +26,11 @@ struct _Evas_Engine_Info_GL_Drm
{
struct gbm_device *gbm;
int fd, bpp;
unsigned int rotation, depth;
unsigned int crtc_id, conn_id, buffer_id;
unsigned int format, flags;
Ecore_Drm_Device *dev;
void *output;
Eina_Bool destination_alpha : 1;
Eina_Bool vsync : 1;

View File

@ -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 =

View File

@ -7,6 +7,11 @@
# include "Evas.h"
# include "Evas_Engine_GL_Drm.h"
# include <Ecore.h>
# include <drm_fourcc.h>
# include <xf86drm.h>
# include <xf86drmMode.h>
# define EGL_EGLEXT_PROTOTYPES
# define GL_GLEXT_PROTOTYPES
@ -64,6 +69,10 @@ typedef struct _Render_Engine Render_Engine;
struct _Render_Engine
{
Render_Engine_GL_Generic generic;
int fd;
drmEventContext ctx;
Ecore_Fd_Handler *hdlr;
};
struct _Context_3D
@ -80,11 +89,10 @@ struct _Outbuf
Evas *evas; // used for pre_swap, post_swap
int w, h;
unsigned int rotation, depth;
int fd, w, h, bpp;
unsigned int rotation, depth, format;
Render_Engine_Swap_Mode swap_mode;
/* struct gbm_device *gbm; */
struct gbm_surface *surface;
struct
@ -98,6 +106,7 @@ struct _Outbuf
struct
{
struct gbm_bo *bo[2];
Ecore_Drm2_Output *output;
} priv;
Eina_Bool destination_alpha : 1;
@ -123,6 +132,9 @@ void *evas_outbuf_update_region_new(Outbuf *ob, int x, int y, int w, int h, int
void evas_outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int w, int h);
void evas_outbuf_update_region_free(Outbuf *ob, RGBA_Image *update);
void evas_outbuf_flush(Outbuf *ob, Tilebuf_Rect *rects, Evas_Render_Mode render_mode);
void evas_outbuf_vblank(void *data, int fd);
void evas_outbuf_page_flip(void *data, int fd);
Evas_Engine_GL_Context* evas_outbuf_gl_context_get(Outbuf *ob);
void *evas_outbuf_egl_display_get(Outbuf *ob);
Context_3D *evas_outbuf_gl_context_new(Outbuf *ob);
@ -138,6 +150,12 @@ _re_wincheck(Outbuf *ob)
return EINA_FALSE;
}
static inline Outbuf *
eng_get_ob(Render_Engine *re)
{
return re->generic.software.ob;
}
extern unsigned int (*glsym_eglSwapBuffersWithDamage)(EGLDisplay a, void *b, const EGLint *d, EGLint c);
extern unsigned int (*glsym_eglSetDamageRegionKHR)(EGLDisplay a, EGLSurface b, EGLint *c, EGLint d);

View File

@ -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;
}