forked from enlightenment/efl
Compare commits
147 Commits
master
...
devs/devil
Author | SHA1 | Date |
---|---|---|
Chris Michael | efbb4d612f | |
Chris Michael | dd93f55773 | |
Chris Michael | c2e190a8e2 | |
Chris Michael | 49b27eb1c7 | |
Chris Michael | c7adbc9292 | |
Chris Michael | 826d6a30f4 | |
Chris Michael | 180810c009 | |
Chris Michael | 219154c1e6 | |
Chris Michael | 0ee3e3f2cf | |
Chris Michael | 7cb302f24f | |
Chris Michael | fe303288f9 | |
Chris Michael | e5825f2d41 | |
Chris Michael | c09abfc763 | |
Chris Michael | 345842da5d | |
Chris Michael | a26e161c5d | |
Chris Michael | 642ea4b29b | |
Chris Michael | 9eb1a71689 | |
Chris Michael | 8a065c97ac | |
Chris Michael | a0691e0445 | |
Chris Michael | 6f65d5c983 | |
Chris Michael | 124ce1fcfe | |
Chris Michael | fb2e5c2ea1 | |
Chris Michael | 80534ca65a | |
Chris Michael | f8148865c2 | |
Chris Michael | 4c7df8ba31 | |
Chris Michael | 3cb2978f3e | |
Chris Michael | 1984303de1 | |
Chris Michael | a7376722f7 | |
Chris Michael | 0954fca98b | |
Chris Michael | c50fbc1e2c | |
Chris Michael | 43bdee1489 | |
Chris Michael | 261af2c931 | |
Chris Michael | e5fd334a2d | |
Chris Michael | a36cd37783 | |
Chris Michael | 084fef467b | |
Chris Michael | 87f9dcbb9e | |
Chris Michael | c7b520cd80 | |
Chris Michael | 49f0d2790b | |
Chris Michael | d2113986f1 | |
Chris Michael | 8b7c00439c | |
Chris Michael | d5fdaf9a73 | |
Chris Michael | f14bf0a943 | |
Chris Michael | ba3c667f4a | |
Chris Michael | 624fe65bda | |
Chris Michael | b30dfbe4c2 | |
Chris Michael | 73a7ac2ec8 | |
Chris Michael | 5d008992d1 | |
Chris Michael | 4e6fd8fee9 | |
Chris Michael | 8f40229dc2 | |
Chris Michael | 44333dda7d | |
Chris Michael | 9584b01c03 | |
Chris Michael | 0f0eb80fc5 | |
Chris Michael | 6a425e6a3a | |
Chris Michael | 1bba4b85e8 | |
Chris Michael | 26244208ef | |
Chris Michael | 6571f552c4 | |
Chris Michael | 0e1a9bd077 | |
Chris Michael | 94f2c999ca | |
Chris Michael | 4af3cd4099 | |
Chris Michael | 56efb6ae64 | |
Chris Michael | 89c3d3079a | |
Chris Michael | af2fdf7cd7 | |
Chris Michael | dd20bcffa7 | |
Chris Michael | 74445104d0 | |
Chris Michael | 57fd12a75d | |
Chris Michael | 0872c9b1f5 | |
Chris Michael | 473156ab76 | |
Chris Michael | ce667f0c42 | |
Chris Michael | b51b92522f | |
Chris Michael | 874609a680 | |
Chris Michael | 5b06621c05 | |
Chris Michael | 45c5605840 | |
Chris Michael | d1da3d85f7 | |
Chris Michael | 523b61413e | |
Chris Michael | cc141cfd92 | |
Chris Michael | 694e685bf5 | |
Chris Michael | 672413a97e | |
Chris Michael | 845994c441 | |
Chris Michael | 6c6aef928c | |
Chris Michael | 09cbfb0e36 | |
Chris Michael | edf9eee500 | |
Chris Michael | 661177022a | |
Chris Michael | 521260b916 | |
Chris Michael | 128a355f17 | |
Chris Michael | e8ff6be5ca | |
Chris Michael | 54c4a4675d | |
Chris Michael | 3b79d6841b | |
Chris Michael | 11a6485f70 | |
Chris Michael | 4a242ac724 | |
Chris Michael | 6b36a36179 | |
Chris Michael | fc38fc173c | |
Chris Michael | 1e1b9d77de | |
Chris Michael | 314a2364c6 | |
Chris Michael | 8bcc51addf | |
Chris Michael | 2d7a7da291 | |
Chris Michael | 27a61cd4d0 | |
Chris Michael | e4c1a1fc33 | |
Chris Michael | 77f023268d | |
Chris Michael | e2dfb240f6 | |
Chris Michael | b2590044e9 | |
Chris Michael | 2f78806319 | |
Chris Michael | c537913e4d | |
Chris Michael | 492f6bc150 | |
Chris Michael | e84800c8cb | |
Chris Michael | cf2aa071cf | |
Chris Michael | fb0d304f14 | |
Chris Michael | 1e19eac751 | |
Chris Michael | e0bdbd62c1 | |
Chris Michael | 43911a80fe | |
Chris Michael | 405b0865a4 | |
Chris Michael | 055669d5c7 | |
Chris Michael | 79e42237f0 | |
Chris Michael | 3058e2f6bc | |
Chris Michael | 4965f01088 | |
Chris Michael | 68eb4ba837 | |
Chris Michael | b12bdc779b | |
Chris Michael | bf2d1cc4b3 | |
Chris Michael | 56bcf2f107 | |
Chris Michael | 2ec85c631e | |
Chris Michael | 47e3268628 | |
Chris Michael | 461ffcd83d | |
Chris Michael | d3dbfc27c8 | |
Chris Michael | 04bdebcd04 | |
Chris Michael | 92fa2ed483 | |
Chris Michael | 35580e3378 | |
Chris Michael | 39f15e6142 | |
Chris Michael | 3b57f1ddcd | |
Chris Michael | b41d7e67af | |
Chris Michael | 056fb866e9 | |
Chris Michael | 099e17f58a | |
Chris Michael | 6e14f2c317 | |
Chris Michael | 3459a23b09 | |
Chris Michael | cda78b1b12 | |
Chris Michael | e4d203762a | |
Chris Michael | 0be06f44b3 | |
Chris Michael | 68d94c340e | |
Chris Michael | 70b603572b | |
Chris Michael | 702e3d42eb | |
Chris Michael | df98346938 | |
Chris Michael | 6475a69c29 | |
Chris Michael | c47017aa91 | |
Chris Michael | e48ff7c3f3 | |
Chris Michael | 286ceeed13 | |
Chris Michael | 55c5e96405 | |
Chris Michael | 57fe700547 | |
Chris Michael | 56844d19a3 | |
Chris Michael | 3eea4099e4 |
|
@ -187,10 +187,18 @@ if BUILD_ENGINE_WAYLAND_EGL
|
||||||
pkgconfig_DATA += pc/evas-wayland-egl.pc
|
pkgconfig_DATA += pc/evas-wayland-egl.pc
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if BUILD_ENGINE_DRM
|
||||||
|
pkgconfig_DATA += pc/evas-drm.pc
|
||||||
|
endif
|
||||||
|
|
||||||
if HAVE_ECORE_COCOA
|
if HAVE_ECORE_COCOA
|
||||||
pkgconfig_DATA += pc/ecore-cocoa.pc
|
pkgconfig_DATA += pc/ecore-cocoa.pc
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if HAVE_ECORE_DRM
|
||||||
|
pkgconfig_DATA += pc/ecore-drm.pc
|
||||||
|
endif
|
||||||
|
|
||||||
if HAVE_ECORE_FB
|
if HAVE_ECORE_FB
|
||||||
pkgconfig_DATA += pc/ecore-fb.pc
|
pkgconfig_DATA += pc/ecore-fb.pc
|
||||||
endif
|
endif
|
||||||
|
|
57
configure.ac
57
configure.ac
|
@ -1107,6 +1107,17 @@ AC_ARG_ENABLE([drm],
|
||||||
],
|
],
|
||||||
[want_drm="no"])
|
[want_drm="no"])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE([drm_hw_accel],
|
||||||
|
[AC_HELP_STRING([--enable-drm-hw-accel],
|
||||||
|
[enable drm hardware acceleration. @<:@default=disabled@:>@])],
|
||||||
|
[
|
||||||
|
if test "x${enableval}" = "xyes" ; then
|
||||||
|
want_drm_hw_accel="yes"
|
||||||
|
else
|
||||||
|
want_drm_hw_accel="no"
|
||||||
|
fi
|
||||||
|
],
|
||||||
|
[want_drm_hw_accel="no"])
|
||||||
|
|
||||||
# Fontconfig
|
# Fontconfig
|
||||||
AC_ARG_ENABLE([fontconfig],
|
AC_ARG_ENABLE([fontconfig],
|
||||||
|
@ -2476,6 +2487,46 @@ EFL_LIB_END_OPTIONAL([Ecore_Wayland])
|
||||||
#### End of Ecore_Wayland
|
#### End of Ecore_Wayland
|
||||||
|
|
||||||
|
|
||||||
|
#### Ecore_Drm
|
||||||
|
EFL_LIB_START_OPTIONAL([Ecore_Drm], [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_DRM], [ecore])
|
||||||
|
EFL_INTERNAL_DEPEND_PKG([ECORE_DRM], [ecore-input])
|
||||||
|
EFL_INTERNAL_DEPEND_PKG([ECORE_DRM], [eo])
|
||||||
|
EFL_INTERNAL_DEPEND_PKG([ECORE_DRM], [eina])
|
||||||
|
|
||||||
|
EFL_DEPEND_PKG([ECORE_DRM], [DRM], [libudev >= 148 libdrm >= 2.4])
|
||||||
|
EFL_OPTIONAL_DEPEND_PKG([ECORE_DRM], [${want_drm_hw_accel}], [GBM], [gbm egl >= 7.10 glesv2])
|
||||||
|
|
||||||
|
EFL_EVAL_PKGS([ECORE_DRM])
|
||||||
|
|
||||||
|
### 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_Drm])
|
||||||
|
AM_CONDITIONAL([BUILD_ECORE_DRM_HW_ACCEL], [test "x${want_drm_hw_accel}" = "xyes"])
|
||||||
|
#### End of Ecore_Drm
|
||||||
|
|
||||||
#### Ecore_Audio
|
#### Ecore_Audio
|
||||||
|
|
||||||
AC_ARG_ENABLE([audio],
|
AC_ARG_ENABLE([audio],
|
||||||
|
@ -3298,7 +3349,6 @@ AM_CONDITIONAL([BUILD_ECORE_EVAS_SDL],
|
||||||
|
|
||||||
ECORE_EVAS_MODULE([wayland-shm], [${want_wayland}])
|
ECORE_EVAS_MODULE([wayland-shm], [${want_wayland}])
|
||||||
ECORE_EVAS_MODULE([wayland-egl], [${want_ecore_evas_wayland_egl}])
|
ECORE_EVAS_MODULE([wayland-egl], [${want_ecore_evas_wayland_egl}])
|
||||||
ECORE_EVAS_MODULE([drm], [${want_drm}])
|
|
||||||
|
|
||||||
build_ecore_evas_wayland="no"
|
build_ecore_evas_wayland="no"
|
||||||
if test "x${have_ecore_evas_wayland_shm}" = "xyes" || \
|
if test "x${have_ecore_evas_wayland_shm}" = "xyes" || \
|
||||||
|
@ -3387,6 +3437,10 @@ if test "x$have_ecore_evas_software_x11" = "xyes" || \
|
||||||
fi
|
fi
|
||||||
AM_CONDITIONAL([BUILD_ECORE_EVAS_X11], [test "${build_ecore_evas_x11}" = "yes"])
|
AM_CONDITIONAL([BUILD_ECORE_EVAS_X11], [test "${build_ecore_evas_x11}" = "yes"])
|
||||||
|
|
||||||
|
ECORE_EVAS_MODULE([drm], [${want_drm}],
|
||||||
|
[ EFL_INTERNAL_DEPEND_PKG([ECORE_EVAS], [ecore-drm]) ]
|
||||||
|
)
|
||||||
|
|
||||||
EFL_EVAL_PKGS([ECORE_EVAS])
|
EFL_EVAL_PKGS([ECORE_EVAS])
|
||||||
|
|
||||||
### Checks for header files
|
### Checks for header files
|
||||||
|
@ -3918,6 +3972,7 @@ pc/ecore-file.pc
|
||||||
pc/ecore-input.pc
|
pc/ecore-input.pc
|
||||||
pc/ecore-input-evas.pc
|
pc/ecore-input-evas.pc
|
||||||
pc/ecore-cocoa.pc
|
pc/ecore-cocoa.pc
|
||||||
|
pc/ecore-drm.pc
|
||||||
pc/ecore-fb.pc
|
pc/ecore-fb.pc
|
||||||
pc/ecore-psl1ght.pc
|
pc/ecore-psl1ght.pc
|
||||||
pc/ecore-sdl.pc
|
pc/ecore-sdl.pc
|
||||||
|
|
|
@ -591,10 +591,18 @@ AC_DEFUN([EVAS_CHECK_ENGINE_DEP_DRM],
|
||||||
[
|
[
|
||||||
|
|
||||||
requirement=""
|
requirement=""
|
||||||
|
requirement_egl=""
|
||||||
have_dep="no"
|
have_dep="no"
|
||||||
|
have_egl="no"
|
||||||
evas_engine_[]$1[]_cflags=""
|
evas_engine_[]$1[]_cflags=""
|
||||||
evas_engine_[]$1[]_libs=""
|
evas_engine_[]$1[]_libs=""
|
||||||
|
|
||||||
|
if test "x${with_opengl}" = "xes" ; then
|
||||||
|
gl_library="glesv2"
|
||||||
|
else
|
||||||
|
gl_library="no"
|
||||||
|
fi
|
||||||
|
|
||||||
PKG_CHECK_EXISTS([libdrm],
|
PKG_CHECK_EXISTS([libdrm],
|
||||||
[
|
[
|
||||||
have_dep="yes"
|
have_dep="yes"
|
||||||
|
@ -602,12 +610,22 @@ PKG_CHECK_EXISTS([libdrm],
|
||||||
],
|
],
|
||||||
[have_dep="no"])
|
[have_dep="no"])
|
||||||
|
|
||||||
|
if test "x${gl_library}" = "xglesv2" ; then
|
||||||
|
PKG_CHECK_EXISTS([egl >= 7.10 ${gl_library}],
|
||||||
|
[
|
||||||
|
have_egl="yes"
|
||||||
|
requirement_egl="egl >= 7.10 ${gl_library}"
|
||||||
|
],
|
||||||
|
[have_egl="no"])
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
if test "x${have_dep}" = "xyes" ; then
|
if test "x${have_dep}" = "xyes" ; then
|
||||||
if test "x$3" = "xstatic" ; then
|
if test "x$3" = "xstatic" ; then
|
||||||
requirements_pc_evas="${requirement} ${requirements_pc_evas}"
|
requirements_pc_evas="${requirement} ${requirement_egl} ${requirements_pc_evas}"
|
||||||
requirements_pc_deps_evas="${requirement} ${requirements_pc_deps_evas}"
|
requirements_pc_deps_evas="${requirement} ${requirement_egl} ${requirements_pc_deps_evas}"
|
||||||
else
|
else
|
||||||
PKG_CHECK_MODULES([DRM], [${requirement}])
|
PKG_CHECK_MODULES([DRM], [${requirement} ${requirement_egl}])
|
||||||
evas_engine_[]$1[]_cflags="${DRM_CFLAGS}"
|
evas_engine_[]$1[]_cflags="${DRM_CFLAGS}"
|
||||||
evas_engine_[]$1[]_libs="${DRM_LIBS}"
|
evas_engine_[]$1[]_libs="${DRM_LIBS}"
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
prefix=@prefix@
|
||||||
|
exec_prefix=@exec_prefix@
|
||||||
|
libdir=@libdir@
|
||||||
|
includedir=@includedir@
|
||||||
|
|
||||||
|
Name: ecore-drm
|
||||||
|
Description: E core library, DRM module
|
||||||
|
Requires.private: @requirements_pc_ecore_drm@
|
||||||
|
Version: @VERSION@
|
||||||
|
Libs: -L${libdir} -lecore_drm
|
||||||
|
Libs.private: @requirements_libs_ecore_drm@
|
||||||
|
Cflags: -I${includedir}/efl-@VMAJ@ -I${includedir}/ecore-drm-@VMAJ@
|
|
@ -33,6 +33,7 @@ include Makefile_Ecore_File.am
|
||||||
include Makefile_Ecore_Input.am
|
include Makefile_Ecore_Input.am
|
||||||
include Makefile_Ecore_Input_Evas.am
|
include Makefile_Ecore_Input_Evas.am
|
||||||
include Makefile_Ecore_Cocoa.am
|
include Makefile_Ecore_Cocoa.am
|
||||||
|
include Makefile_Ecore_Drm.am
|
||||||
include Makefile_Ecore_FB.am
|
include Makefile_Ecore_FB.am
|
||||||
include Makefile_Ecore_Psl1ght.am
|
include Makefile_Ecore_Psl1ght.am
|
||||||
include Makefile_Ecore_SDL.am
|
include Makefile_Ecore_SDL.am
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
if HAVE_ECORE_DRM
|
||||||
|
|
||||||
|
### Library
|
||||||
|
|
||||||
|
lib_LTLIBRARIES += lib/ecore_drm/libecore_drm.la
|
||||||
|
|
||||||
|
installed_ecoredrmmainheadersdir = $(includedir)/ecore-drm-@VMAJ@
|
||||||
|
dist_installed_ecoredrmmainheaders_DATA = \
|
||||||
|
lib/ecore_drm/Ecore_Drm.h
|
||||||
|
|
||||||
|
lib_ecore_drm_libecore_drm_la_SOURCES = \
|
||||||
|
lib/ecore_drm/ecore_drm_sprites.c \
|
||||||
|
lib/ecore_drm/ecore_drm_fb.c \
|
||||||
|
lib/ecore_drm/ecore_drm_evdev.c \
|
||||||
|
lib/ecore_drm/ecore_drm_inputs.c \
|
||||||
|
lib/ecore_drm/ecore_drm_output.c \
|
||||||
|
lib/ecore_drm/ecore_drm_tty.c \
|
||||||
|
lib/ecore_drm/ecore_drm_device.c \
|
||||||
|
lib/ecore_drm/ecore_drm.c \
|
||||||
|
lib/ecore_drm/ecore_drm_private.h
|
||||||
|
|
||||||
|
lib_ecore_drm_libecore_drm_la_CPPFLAGS = \
|
||||||
|
-I$(top_builddir)/src/lib/efl \
|
||||||
|
@ECORE_DRM_CFLAGS@ \
|
||||||
|
-DPACKAGE_LIB_DIR=\"$(libdir)\" \
|
||||||
|
-DMODULE_ARCH=\"$(MODULE_ARCH)\"
|
||||||
|
|
||||||
|
lib_ecore_drm_libecore_drm_la_LIBADD = @ECORE_DRM_LIBS@
|
||||||
|
lib_ecore_drm_libecore_drm_la_DEPENDENCIES = @ECORE_DRM_INTERNAL_LIBS@
|
||||||
|
lib_ecore_drm_libecore_drm_la_LDFLAGS = @EFL_LTLIBRARY_FLAGS@
|
||||||
|
|
||||||
|
### Drm Launch Binary
|
||||||
|
|
||||||
|
ecoredrmlaunchinternal_bindir = $(libdir)/ecore_drm/bin/$(MODULE_ARCH)
|
||||||
|
ecoredrmlaunchinternal_bin_PROGRAMS = bin/ecore_drm/ecore_drm_launch
|
||||||
|
|
||||||
|
bin_ecore_drm_ecore_drm_launch_SOURCES = \
|
||||||
|
bin/ecore_drm/ecore_drm_launch.c
|
||||||
|
|
||||||
|
bin_ecore_drm_ecore_drm_launch_CPPFLAGS = \
|
||||||
|
-I$(top_builddir)/src/lib/efl \
|
||||||
|
@ECORE_DRM_CFLAGS@ @SUID_CFLAGS@ \
|
||||||
|
-DPACKAGE_LIB_DIR=\"$(libdir)\" \
|
||||||
|
-DMODULE_ARCH=\"$(MODULE_ARCH)\"
|
||||||
|
|
||||||
|
bin_ecore_drm_ecore_drm_launch_LDADD = \
|
||||||
|
@ECORE_DRM_LIBS@ \
|
||||||
|
@SUID_LDFLAGS@
|
||||||
|
|
||||||
|
bin_ecore_drm_ecore_drm_launch_DEPENDENCIES = \
|
||||||
|
@USE_ECORE_DRM_INTERNAL_LIBS@
|
||||||
|
|
||||||
|
setuid_root_mode = a=rx,u+xs
|
||||||
|
EFL_INSTALL_EXEC_HOOK += @chmod $(setuid_root_mode) $(DESTDIR)$(libdir)/ecore_drm/bin/$(MODULE_ARCH)/ecore_drm_launch$(EXEEXT) || true;
|
||||||
|
|
||||||
|
endif
|
|
@ -961,9 +961,11 @@ endif
|
||||||
if BUILD_ENGINE_DRM
|
if BUILD_ENGINE_DRM
|
||||||
dist_installed_evasmainheaders_DATA += modules/evas/engines/drm/Evas_Engine_Drm.h
|
dist_installed_evasmainheaders_DATA += modules/evas/engines/drm/Evas_Engine_Drm.h
|
||||||
DRM_SOURCES = \
|
DRM_SOURCES = \
|
||||||
modules/evas/engines/drm/evas_outbuf.c \
|
|
||||||
modules/evas/engines/drm/evas_engine.c \
|
modules/evas/engines/drm/evas_engine.c \
|
||||||
modules/evas/engines/drm/evas_engine.h
|
modules/evas/engines/drm/evas_engine.h \
|
||||||
|
modules/evas/engines/drm/evas_swapbuf.c \
|
||||||
|
modules/evas/engines/drm/evas_swapper.c \
|
||||||
|
modules/evas/engines/drm/evas_buffer_manager.c
|
||||||
if EVAS_STATIC_BUILD_DRM
|
if EVAS_STATIC_BUILD_DRM
|
||||||
lib_evas_libevas_la_SOURCES += $(DRM_SOURCES)
|
lib_evas_libevas_la_SOURCES += $(DRM_SOURCES)
|
||||||
lib_evas_libevas_la_CPPFLAGS += @evas_engine_drm_cflags@
|
lib_evas_libevas_la_CPPFLAGS += @evas_engine_drm_cflags@
|
||||||
|
|
|
@ -0,0 +1,407 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* standard headers */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/epoll.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
/* #include <syslog.h> */
|
||||||
|
/* #include <pwd.h> */
|
||||||
|
|
||||||
|
/* #include <linux/major.h> */
|
||||||
|
/* #include <linux/vt.h> */
|
||||||
|
/* #include <linux/kd.h> */
|
||||||
|
|
||||||
|
#include <xf86drm.h>
|
||||||
|
#include <xf86drmMode.h>
|
||||||
|
#include <drm_fourcc.h>
|
||||||
|
|
||||||
|
#include <Eina.h>
|
||||||
|
#include <Ecore_Drm.h>
|
||||||
|
|
||||||
|
#define RIGHTS_LEN CMSG_LEN(sizeof(int))
|
||||||
|
|
||||||
|
#define IOVSET(_iov, _addr, _len) \
|
||||||
|
(_iov)->iov_base = (void *)(_addr); \
|
||||||
|
(_iov)->iov_len = (_len);
|
||||||
|
|
||||||
|
/* local prototypes */
|
||||||
|
static int _send_msg(int opcode, int fd, void *data, size_t bytes);
|
||||||
|
|
||||||
|
/* local variables */
|
||||||
|
static struct cmsghdr *cmsgptr = NULL;
|
||||||
|
static int _read_fd = -1;
|
||||||
|
static int _write_fd = -1;
|
||||||
|
|
||||||
|
static int
|
||||||
|
_open_device(const char *device)
|
||||||
|
{
|
||||||
|
int fd = -1, ret = ECORE_DRM_OP_SUCCESS;
|
||||||
|
|
||||||
|
if (!device)
|
||||||
|
{
|
||||||
|
ret = ECORE_DRM_OP_FAILURE;
|
||||||
|
_send_msg(ECORE_DRM_OP_DEVICE_OPEN, fd, &ret, sizeof(int));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Launcher Trying to Open Device: %s\n", device);
|
||||||
|
|
||||||
|
if ((fd = open(device, O_RDWR | O_NONBLOCK)) < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to Open Device: %s: %m\n", device);
|
||||||
|
ret = ECORE_DRM_OP_FAILURE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fprintf(stderr, "Launcher Opened Device: %s %d\n", device, fd);
|
||||||
|
|
||||||
|
_send_msg(ECORE_DRM_OP_DEVICE_OPEN, fd, &ret, sizeof(int));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_close_device(int fd)
|
||||||
|
{
|
||||||
|
int ret = ECORE_DRM_OP_SUCCESS;
|
||||||
|
|
||||||
|
if (!fd)
|
||||||
|
{
|
||||||
|
ret = ECORE_DRM_OP_FAILURE;
|
||||||
|
_send_msg(ECORE_DRM_OP_DEVICE_CLOSE, fd, &ret, sizeof(int));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
_send_msg(ECORE_DRM_OP_DEVICE_CLOSE, fd, &ret, sizeof(int));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_open_tty(const char *name)
|
||||||
|
{
|
||||||
|
int fd = -1, ret = ECORE_DRM_OP_SUCCESS;
|
||||||
|
/* struct stat st; */
|
||||||
|
|
||||||
|
if (!name) goto fail;
|
||||||
|
|
||||||
|
fprintf(stderr, "Launcher Trying to Open Tty: %s\n", name);
|
||||||
|
|
||||||
|
if ((fd = open(name, O_RDWR | O_NOCTTY)) < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to Open Tty: %s: %m\n", name);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fprintf(stderr, "Launcher Opened Tty: %s %d\n", name, fd);
|
||||||
|
|
||||||
|
/* if ((fstat(fd, &st) == -1) || */
|
||||||
|
/* (major(st.st_rdev) != TTY_MAJOR) || (minor(st.st_rdev) == 0)) */
|
||||||
|
/* { */
|
||||||
|
/* fprintf(stderr, "%d is Not a Tty\n", fd); */
|
||||||
|
/* goto fail; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
_send_msg(ECORE_DRM_OP_TTY_OPEN, fd, &ret, sizeof(int));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (fd > -1) close(fd);
|
||||||
|
fd = -1;
|
||||||
|
ret = ECORE_DRM_OP_FAILURE;
|
||||||
|
_send_msg(ECORE_DRM_OP_DEVICE_OPEN, fd, &ret, sizeof(int));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_drop_master(int fd)
|
||||||
|
{
|
||||||
|
int ret = ECORE_DRM_OP_SUCCESS;
|
||||||
|
|
||||||
|
fprintf(stderr, "Drop Master: %d\n", fd);
|
||||||
|
|
||||||
|
if (drmDropMaster(fd) != 0)
|
||||||
|
{
|
||||||
|
ret = ECORE_DRM_OP_FAILURE;
|
||||||
|
fprintf(stderr, "\tFailed to drop master: %m\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
_send_msg(ECORE_DRM_OP_DEVICE_MASTER_DROP, fd, &ret, sizeof(int));
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_set_master(int fd)
|
||||||
|
{
|
||||||
|
int ret = ECORE_DRM_OP_SUCCESS;
|
||||||
|
|
||||||
|
fprintf(stderr, "Set Master: %d\n", fd);
|
||||||
|
|
||||||
|
if (drmSetMaster(fd) != 0)
|
||||||
|
{
|
||||||
|
ret = ECORE_DRM_OP_FAILURE;
|
||||||
|
fprintf(stderr, "\tFailed to set master: %m\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
_send_msg(ECORE_DRM_OP_DEVICE_MASTER_SET, fd, &ret, sizeof(int));
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_read_fd_get(void)
|
||||||
|
{
|
||||||
|
char *ev, *end;
|
||||||
|
int fd = -1, flags = -1;
|
||||||
|
|
||||||
|
if (!(ev = getenv("ECORE_DRM_LAUNCHER_SOCKET_READ")))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
fd = strtol(ev, &end, 0);
|
||||||
|
if (*end != '\0') return -1;
|
||||||
|
|
||||||
|
flags = fcntl(fd, F_GETFD);
|
||||||
|
if (flags < 0) return -1;
|
||||||
|
|
||||||
|
fprintf(stderr, "Got Read FD: %d\n", fd);
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_write_fd_get(void)
|
||||||
|
{
|
||||||
|
char *ev, *end;
|
||||||
|
int fd = -1, flags = -1;
|
||||||
|
|
||||||
|
if (!(ev = getenv("ECORE_DRM_LAUNCHER_SOCKET_WRITE")))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
fd = strtol(ev, &end, 0);
|
||||||
|
if (*end != '\0') return -1;
|
||||||
|
|
||||||
|
flags = fcntl(fd, F_GETFD);
|
||||||
|
if (flags < 0) return -1;
|
||||||
|
|
||||||
|
fprintf(stderr, "Got Write FD: %d\n", fd);
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_send_msg(int opcode, int fd, void *data, size_t bytes)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Message dmsg;
|
||||||
|
struct iovec iov[2];
|
||||||
|
struct msghdr msg;
|
||||||
|
ssize_t size;
|
||||||
|
|
||||||
|
/* send a message to the calling process */
|
||||||
|
/* 'fd' is the fd to send */
|
||||||
|
|
||||||
|
memset(&dmsg, 0, sizeof(dmsg));
|
||||||
|
|
||||||
|
IOVSET(iov + 0, &dmsg, sizeof(dmsg));
|
||||||
|
IOVSET(iov + 1, &data, bytes);
|
||||||
|
|
||||||
|
dmsg.opcode = opcode;
|
||||||
|
dmsg.size = bytes;
|
||||||
|
|
||||||
|
msg.msg_name = NULL;
|
||||||
|
msg.msg_namelen = 0;
|
||||||
|
msg.msg_iov = iov;
|
||||||
|
msg.msg_iovlen = 2;
|
||||||
|
msg.msg_flags = 0;
|
||||||
|
|
||||||
|
if ((!cmsgptr) && (!(cmsgptr = malloc(RIGHTS_LEN))))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
cmsgptr->cmsg_level = SOL_SOCKET;
|
||||||
|
cmsgptr->cmsg_type = SCM_RIGHTS;
|
||||||
|
cmsgptr->cmsg_len = RIGHTS_LEN;
|
||||||
|
|
||||||
|
msg.msg_control = cmsgptr;
|
||||||
|
msg.msg_controllen = RIGHTS_LEN;
|
||||||
|
|
||||||
|
fprintf(stderr, "Launcher Sending FD: %d\n", fd);
|
||||||
|
*((int *)CMSG_DATA(cmsgptr)) = fd;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
size = sendmsg(_write_fd, &msg, MSG_EOR);
|
||||||
|
if (errno != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to send message: %s", strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Launcher Wrote %li to %d\n", size, _write_fd);
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_recv_msg(void)
|
||||||
|
{
|
||||||
|
int fd = -1;
|
||||||
|
Ecore_Drm_Message dmsg;
|
||||||
|
struct iovec iov[2];
|
||||||
|
struct msghdr msg;
|
||||||
|
struct cmsghdr *cmsg = NULL;
|
||||||
|
char data[BUFSIZ];
|
||||||
|
ssize_t size;
|
||||||
|
|
||||||
|
fprintf(stderr, "Received Message\n");
|
||||||
|
|
||||||
|
memset(&dmsg, 0, sizeof(dmsg));
|
||||||
|
memset(&data, 0, sizeof(data));
|
||||||
|
|
||||||
|
IOVSET(iov + 0, &dmsg, sizeof(dmsg));
|
||||||
|
IOVSET(iov + 1, &data, sizeof(data));
|
||||||
|
|
||||||
|
msg.msg_name = NULL;
|
||||||
|
msg.msg_namelen = 0;
|
||||||
|
msg.msg_iov = iov;
|
||||||
|
msg.msg_iovlen = 2;
|
||||||
|
msg.msg_flags = 0;
|
||||||
|
|
||||||
|
if ((!cmsgptr) && (!(cmsgptr = malloc(RIGHTS_LEN))))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
msg.msg_control = cmsgptr;
|
||||||
|
msg.msg_controllen = RIGHTS_LEN;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
size = recvmsg(_read_fd, &msg, 0);
|
||||||
|
if (errno != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to receive message: %m\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "\tReceived %li bytes from %d\n", size, _read_fd);
|
||||||
|
|
||||||
|
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
|
||||||
|
cmsg = CMSG_NXTHDR(&msg, cmsg))
|
||||||
|
{
|
||||||
|
if (cmsg->cmsg_level != SOL_SOCKET)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (cmsg->cmsg_type)
|
||||||
|
{
|
||||||
|
case SCM_RIGHTS:
|
||||||
|
fd = *((int *)CMSG_DATA(cmsg));
|
||||||
|
switch (dmsg.opcode)
|
||||||
|
{
|
||||||
|
case ECORE_DRM_OP_DEVICE_OPEN:
|
||||||
|
fprintf(stderr, "Open Device: %s\n", (char *)data);
|
||||||
|
_open_device((char *)data);
|
||||||
|
break;
|
||||||
|
case ECORE_DRM_OP_DEVICE_CLOSE:
|
||||||
|
fprintf(stderr, "Close Device: %d\n", fd);
|
||||||
|
_close_device(fd);
|
||||||
|
case ECORE_DRM_OP_TTY_OPEN:
|
||||||
|
fprintf(stderr, "Open Tty: %s\n", (char *)data);
|
||||||
|
_open_tty((char *)data);
|
||||||
|
break;
|
||||||
|
case ECORE_DRM_OP_DEVICE_MASTER_DROP:
|
||||||
|
fprintf(stderr, "Drop Master: %d\n", fd);
|
||||||
|
_drop_master(fd);
|
||||||
|
break;
|
||||||
|
case ECORE_DRM_OP_DEVICE_MASTER_SET:
|
||||||
|
fprintf(stderr, "Set Master\n");
|
||||||
|
_set_master(fd);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Unhandled Opcode: %d\n", dmsg.opcode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Unhandled message type: %d\n", cmsg->cmsg_type);
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
|
||||||
|
{
|
||||||
|
struct epoll_event ev, events[1];
|
||||||
|
int ret, i, _epoll_fd = -1;
|
||||||
|
|
||||||
|
setvbuf(stdout, NULL, _IONBF, 0);
|
||||||
|
setvbuf(stderr, NULL, _IONBF, 0);
|
||||||
|
|
||||||
|
fprintf(stderr, "Spartacus Is Alive\n");
|
||||||
|
|
||||||
|
_read_fd = _read_fd_get();
|
||||||
|
if (_read_fd < 0) return EXIT_FAILURE;
|
||||||
|
|
||||||
|
_write_fd = _write_fd_get();
|
||||||
|
if (_write_fd < 0) return EXIT_FAILURE;
|
||||||
|
|
||||||
|
fprintf(stderr, "Creating Epoll\n");
|
||||||
|
_epoll_fd = epoll_create(1);
|
||||||
|
|
||||||
|
memset(&ev, 0, sizeof(ev));
|
||||||
|
ev.events = EPOLLIN;
|
||||||
|
ev.data.fd = _read_fd;
|
||||||
|
|
||||||
|
if (epoll_ctl(_epoll_fd, EPOLL_CTL_ADD, _read_fd, &ev) < 0)
|
||||||
|
{
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&events, 0, sizeof(events));
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
ret = epoll_wait(_epoll_fd, events, sizeof(events) / sizeof(struct epoll_event), -1);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Epoll Failed: %m\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < ret; i++)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Epoll Event on: %d\n", events[i].data.fd);
|
||||||
|
if (events[i].data.fd != _read_fd) continue;
|
||||||
|
|
||||||
|
if (events[i].events & EPOLLIN)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Epoll Data In\n");
|
||||||
|
_recv_msg();
|
||||||
|
}
|
||||||
|
else if (events[i].events & EPOLLERR)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Epoll Data Error\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Spartacus Is Dead\n");
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
|
@ -0,0 +1,171 @@
|
||||||
|
#ifndef _ECORE_DRM_H
|
||||||
|
# define _ECORE_DRM_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
|
||||||
|
|
||||||
|
typedef enum _Ecore_Drm_Op
|
||||||
|
{
|
||||||
|
ECORE_DRM_OP_READ_FD_SET,
|
||||||
|
ECORE_DRM_OP_WRITE_FD_SET,
|
||||||
|
ECORE_DRM_OP_DEVICE_OPEN,
|
||||||
|
ECORE_DRM_OP_DEVICE_CLOSE,
|
||||||
|
ECORE_DRM_OP_DEVICE_MASTER_DROP,
|
||||||
|
ECORE_DRM_OP_DEVICE_MASTER_SET,
|
||||||
|
ECORE_DRM_OP_TTY_OPEN,
|
||||||
|
ECORE_DRM_OP_TTY_CLOSE
|
||||||
|
} Ecore_Drm_Op;
|
||||||
|
|
||||||
|
typedef enum _Ecore_Drm_Op_Result
|
||||||
|
{
|
||||||
|
ECORE_DRM_OP_SUCCESS,
|
||||||
|
ECORE_DRM_OP_FAILURE
|
||||||
|
} Ecore_Drm_Op_Result;
|
||||||
|
|
||||||
|
typedef enum _Ecore_Drm_Evdev_Capabilities
|
||||||
|
{
|
||||||
|
EVDEV_KEYBOARD = (1 << 0),
|
||||||
|
EVDEV_BUTTON = (1 << 1),
|
||||||
|
EVDEV_MOTION_ABS = (1 << 2),
|
||||||
|
EVDEV_MOTION_REL = (1 << 3),
|
||||||
|
EVDEV_TOUCH = (1 << 4),
|
||||||
|
} Ecore_Drm_Evdev_Capabilities;
|
||||||
|
|
||||||
|
typedef enum _Ecore_Drm_Evdev_Event_Type
|
||||||
|
{
|
||||||
|
EVDEV_NONE,
|
||||||
|
EVDEV_ABSOLUTE_TOUCH_DOWN,
|
||||||
|
EVDEV_ABSOLUTE_MOTION,
|
||||||
|
EVDEV_ABSOLUTE_TOUCH_UP,
|
||||||
|
EVDEV_ABSOLUTE_MT_DOWN,
|
||||||
|
EVDEV_ABSOLUTE_MT_MOTION,
|
||||||
|
EVDEV_ABSOLUTE_MT_UP,
|
||||||
|
EVDEV_RELATIVE_MOTION,
|
||||||
|
} Ecore_Drm_Evdev_Event_Type;
|
||||||
|
|
||||||
|
typedef enum _Ecore_Drm_Seat_Capabilities
|
||||||
|
{
|
||||||
|
EVDEV_SEAT_POINTER = (1 << 0),
|
||||||
|
EVDEV_SEAT_KEYBOARD = (1 << 1),
|
||||||
|
EVDEV_SEAT_TOUCH = (1 << 2),
|
||||||
|
} Ecore_Drm_Seat_Capabilities;
|
||||||
|
|
||||||
|
/* structure for message passing */
|
||||||
|
typedef struct _Ecore_Drm_Message
|
||||||
|
{
|
||||||
|
int opcode, size;
|
||||||
|
void *data;
|
||||||
|
} Ecore_Drm_Message;
|
||||||
|
|
||||||
|
/* structure for fb objects */
|
||||||
|
typedef struct _Ecore_Drm_Fb
|
||||||
|
{
|
||||||
|
Eina_Bool from_client : 1;
|
||||||
|
unsigned int id, hdl;
|
||||||
|
unsigned int stride, size;
|
||||||
|
int fd;
|
||||||
|
void *mmap;
|
||||||
|
#ifdef HAVE_GBM
|
||||||
|
struct gbm_bo *bo;
|
||||||
|
#endif
|
||||||
|
} Ecore_Drm_Fb;
|
||||||
|
|
||||||
|
/* opaque structure to represent a drm device */
|
||||||
|
typedef struct _Ecore_Drm_Device Ecore_Drm_Device;
|
||||||
|
|
||||||
|
/* opaque structure to represent a drm output mode */
|
||||||
|
typedef struct _Ecore_Drm_Output_Mode Ecore_Drm_Output_Mode;
|
||||||
|
|
||||||
|
/* opaque structure to represent a drm output */
|
||||||
|
typedef struct _Ecore_Drm_Output Ecore_Drm_Output;
|
||||||
|
|
||||||
|
/* opaque structure to represent a drm udev input */
|
||||||
|
typedef struct _Ecore_Drm_Input Ecore_Drm_Input;
|
||||||
|
|
||||||
|
/* opaque structure to represent a drm evdev input */
|
||||||
|
typedef struct _Ecore_Drm_Evdev Ecore_Drm_Evdev;
|
||||||
|
|
||||||
|
/* opaque structure to represent a drm seat */
|
||||||
|
typedef struct _Ecore_Drm_Seat Ecore_Drm_Seat;
|
||||||
|
|
||||||
|
/* opaque structure to represent a drm sprite */
|
||||||
|
typedef struct _Ecore_Drm_Sprite Ecore_Drm_Sprite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief Ecore functions for dealing with drm, virtual terminals
|
||||||
|
*
|
||||||
|
* @defgroup Ecore_Drm_Group Ecore_Drm - Drm Integration
|
||||||
|
* @ingroup Ecore
|
||||||
|
*
|
||||||
|
* Ecore_Drm provides a wrapper and functions for using libdrm
|
||||||
|
*
|
||||||
|
* @li @ref Ecore_Drm_Init_Group
|
||||||
|
* @li @ref Ecore_Drm_Device_Group
|
||||||
|
* @li @ref Ecore_Drm_Tty_Group
|
||||||
|
* @li @ref Ecore_Drm_Output_Group
|
||||||
|
* @li @ref Ecore_Drm_Input_Group
|
||||||
|
* @li @ref Ecore_Drm_Sprite_Group
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
EAPI int ecore_drm_init(void);
|
||||||
|
EAPI int ecore_drm_shutdown(void);
|
||||||
|
|
||||||
|
EAPI void *ecore_drm_gbm_get(Ecore_Drm_Device *dev);
|
||||||
|
EAPI unsigned int ecore_drm_gbm_format_get(Ecore_Drm_Device *dev);
|
||||||
|
|
||||||
|
EAPI Ecore_Drm_Device *ecore_drm_device_find(const char *name, const char *seat);
|
||||||
|
EAPI void ecore_drm_device_free(Ecore_Drm_Device *dev);
|
||||||
|
EAPI Eina_Bool ecore_drm_device_open(Ecore_Drm_Device *dev);
|
||||||
|
EAPI Eina_Bool ecore_drm_device_close(Ecore_Drm_Device *dev);
|
||||||
|
EAPI Eina_Bool ecore_drm_device_master_get(Ecore_Drm_Device *dev);
|
||||||
|
EAPI Eina_Bool ecore_drm_device_master_set(Ecore_Drm_Device *dev);
|
||||||
|
EAPI Eina_Bool ecore_drm_device_master_drop(Ecore_Drm_Device *dev);
|
||||||
|
EAPI int ecore_drm_device_fd_get(Ecore_Drm_Device *dev);
|
||||||
|
|
||||||
|
EAPI Eina_Bool ecore_drm_tty_open(Ecore_Drm_Device *dev, const char *name);
|
||||||
|
EAPI Eina_Bool ecore_drm_tty_close(Ecore_Drm_Device *dev);
|
||||||
|
EAPI Eina_Bool ecore_drm_tty_release(Ecore_Drm_Device *dev);
|
||||||
|
EAPI Eina_Bool ecore_drm_tty_acquire(Ecore_Drm_Device *dev);
|
||||||
|
|
||||||
|
EAPI Eina_Bool ecore_drm_outputs_create(Ecore_Drm_Device *dev);
|
||||||
|
EAPI void ecore_drm_output_free(Ecore_Drm_Output *output);
|
||||||
|
EAPI void ecore_drm_output_cursor_size_set(Ecore_Drm_Output *output, int handle, int w, int h);
|
||||||
|
EAPI Eina_Bool ecore_drm_output_enable(Ecore_Drm_Output *output);
|
||||||
|
EAPI void ecore_drm_output_fb_release(Ecore_Drm_Output *output, Ecore_Drm_Fb *fb);
|
||||||
|
EAPI void ecore_drm_output_repaint(Ecore_Drm_Output *output);
|
||||||
|
|
||||||
|
EAPI Eina_Bool ecore_drm_inputs_create(Ecore_Drm_Device *dev);
|
||||||
|
EAPI void ecore_drm_inputs_destroy(Ecore_Drm_Device *dev);
|
||||||
|
EAPI Eina_Bool ecore_drm_inputs_enable(Ecore_Drm_Input *input);
|
||||||
|
EAPI void ecore_drm_inputs_disable(Ecore_Drm_Input *input);
|
||||||
|
|
||||||
|
EAPI Eina_Bool ecore_drm_sprites_create(Ecore_Drm_Device *dev);
|
||||||
|
EAPI void ecore_drm_sprites_destroy(Ecore_Drm_Device *dev);
|
||||||
|
EAPI void ecore_drm_sprites_fb_set(Ecore_Drm_Sprite *sprite, int fb_id, int flags);
|
||||||
|
EAPI Eina_Bool ecore_drm_sprites_crtc_supported(Ecore_Drm_Output *output, unsigned int supported);
|
||||||
|
|
||||||
|
EAPI Ecore_Drm_Fb *ecore_drm_fb_create(Ecore_Drm_Device *dev, int width, int height);
|
||||||
|
EAPI void ecore_drm_fb_destroy(Ecore_Drm_Fb *fb);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,414 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "ecore_drm_private.h"
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
#define RIGHTS_LEN CMSG_LEN(sizeof(int))
|
||||||
|
|
||||||
|
#define IOVSET(_iov, _addr, _len) \
|
||||||
|
(_iov)->iov_base = (void *)(_addr); \
|
||||||
|
(_iov)->iov_len = (_len);
|
||||||
|
|
||||||
|
/* local variables */
|
||||||
|
static int _ecore_drm_init_count = 0;
|
||||||
|
static int _ecore_drm_sockets[2] = { -1, -1 };
|
||||||
|
static struct cmsghdr *cmsgptr = NULL;
|
||||||
|
|
||||||
|
/* external variables */
|
||||||
|
struct udev *udev;
|
||||||
|
int _ecore_drm_log_dom = -1;
|
||||||
|
#ifdef LOG_TO_FILE
|
||||||
|
FILE *lg;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_ecore_drm_sockets_create(void)
|
||||||
|
{
|
||||||
|
if (_ecore_drm_sockets[0] > -1) return EINA_TRUE;
|
||||||
|
|
||||||
|
/* create a pair of sequenced sockets (fixed-length)
|
||||||
|
* NB: when reading from one of these, it is required that we read
|
||||||
|
* an entire packet with each read() call */
|
||||||
|
if (socketpair(AF_LOCAL, SOCK_SEQPACKET | SOCK_NONBLOCK,
|
||||||
|
0, _ecore_drm_sockets) < 0)
|
||||||
|
{
|
||||||
|
ERR("Socketpair Failed: %m");
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NB: We don't want cloexec for the sockets. That would cause them to be
|
||||||
|
* closed when we exec the child process but we need them open so that
|
||||||
|
* we can pass messages */
|
||||||
|
/* if (fcntl(_ecore_drm_sockets[0], F_SETFD, FD_CLOEXEC) < 0) */
|
||||||
|
/* { */
|
||||||
|
/* ERR("Failed to set CLOEXEC: %m"); */
|
||||||
|
/* return EINA_FALSE; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* DBG("Parent Socket: %d", _ecore_drm_sockets[0]); */
|
||||||
|
/* DBG("Child Socket: %d", _ecore_drm_sockets[1]); */
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_ecore_drm_launcher_spawn(void)
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
if ((pid = fork()) < 0) return EINA_FALSE;
|
||||||
|
|
||||||
|
if (pid == 0)
|
||||||
|
{
|
||||||
|
char renv[64], wenv[64], buff[PATH_MAX];
|
||||||
|
char *args[1] = { NULL };
|
||||||
|
sigset_t mask;
|
||||||
|
|
||||||
|
/* read socket for slave is 1 */
|
||||||
|
snprintf(renv, sizeof(renv), "ECORE_DRM_LAUNCHER_SOCKET_READ=%d",
|
||||||
|
_ecore_drm_sockets[1]);
|
||||||
|
|
||||||
|
/* write socket for slave is 0 */
|
||||||
|
snprintf(wenv, sizeof(wenv), "ECORE_DRM_LAUNCHER_SOCKET_WRITE=%d",
|
||||||
|
_ecore_drm_sockets[0]);
|
||||||
|
|
||||||
|
/* assemble exec path */
|
||||||
|
snprintf(buff, sizeof(buff),
|
||||||
|
"%s/ecore_drm/bin/%s/ecore_drm_launch",
|
||||||
|
PACKAGE_LIB_DIR, MODULE_ARCH);
|
||||||
|
|
||||||
|
/* don't give our signal mask to the child */
|
||||||
|
sigemptyset(&mask);
|
||||||
|
sigaddset(&mask, SIGTERM);
|
||||||
|
sigaddset(&mask, SIGCHLD);
|
||||||
|
sigaddset(&mask, SIGINT);
|
||||||
|
sigaddset(&mask, SIGTTIN);
|
||||||
|
sigaddset(&mask, SIGTTOU);
|
||||||
|
sigprocmask(SIG_UNBLOCK, &mask, NULL);
|
||||||
|
|
||||||
|
/* NB: We need to use execve here so that capabilities are inherited.
|
||||||
|
* Also, this should set Our (ecore_drm) effective uid to be the
|
||||||
|
* owner of the launched process (setuid in this case) */
|
||||||
|
char *ev[3] = { strdup(renv), strdup(wenv), NULL };
|
||||||
|
execve(buff, args, ev);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
|
||||||
|
while (waitpid(pid, &status, WNOHANG) < 0)
|
||||||
|
if (errno != EINTR) break;
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
_ecore_drm_socket_send(int opcode, int fd, void *data, size_t bytes)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Message dmsg;
|
||||||
|
struct iovec iov[2];
|
||||||
|
struct msghdr msg;
|
||||||
|
ssize_t size;
|
||||||
|
|
||||||
|
/* Simplified version of sending messages. We don't need to send any
|
||||||
|
* 'credentials' with this as it is just basically an IPC to send over
|
||||||
|
* our request to the slave process */
|
||||||
|
|
||||||
|
/* NB: Hmm, don't think we need to set any socket options here */
|
||||||
|
|
||||||
|
memset(&dmsg, 0, sizeof(dmsg));
|
||||||
|
|
||||||
|
IOVSET(iov + 0, &dmsg, sizeof(dmsg));
|
||||||
|
IOVSET(iov + 1, &data, bytes);
|
||||||
|
|
||||||
|
dmsg.opcode = opcode;
|
||||||
|
dmsg.size = bytes;
|
||||||
|
|
||||||
|
msg.msg_name = NULL;
|
||||||
|
msg.msg_namelen = 0;
|
||||||
|
msg.msg_iov = iov;
|
||||||
|
msg.msg_iovlen = 2;
|
||||||
|
msg.msg_flags = 0;
|
||||||
|
|
||||||
|
if ((!cmsgptr) && (!(cmsgptr = malloc(RIGHTS_LEN))))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
cmsgptr->cmsg_level = SOL_SOCKET;
|
||||||
|
cmsgptr->cmsg_type = SCM_RIGHTS;
|
||||||
|
cmsgptr->cmsg_len = RIGHTS_LEN;
|
||||||
|
|
||||||
|
msg.msg_control = cmsgptr;
|
||||||
|
msg.msg_controllen = RIGHTS_LEN;
|
||||||
|
|
||||||
|
if (fd > -1)
|
||||||
|
*((int *)CMSG_DATA(cmsgptr)) = fd;
|
||||||
|
else
|
||||||
|
*((int *)CMSG_DATA(cmsgptr)) = _ecore_drm_sockets[1];
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
size = sendmsg(_ecore_drm_sockets[1], &msg, MSG_EOR);
|
||||||
|
if (errno != 0)
|
||||||
|
{
|
||||||
|
DBG("Error Sending Message: %m");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DBG("Sent %li bytes to Socket %d", size, _ecore_drm_sockets[1]); */
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_ecore_drm_socket_receive(int opcode EINA_UNUSED, int *fd, void **data, size_t bytes)
|
||||||
|
{
|
||||||
|
int ret = ECORE_DRM_OP_FAILURE;
|
||||||
|
Ecore_Drm_Message dmsg;
|
||||||
|
struct cmsghdr *cmsg;
|
||||||
|
struct iovec iov[2];
|
||||||
|
struct msghdr msg;
|
||||||
|
char buff[CMSG_SPACE(sizeof(fd))];
|
||||||
|
/* ssize_t size; */
|
||||||
|
|
||||||
|
memset(&dmsg, 0, sizeof(dmsg));
|
||||||
|
memset(&buff, 0, sizeof(buff));
|
||||||
|
|
||||||
|
IOVSET(iov + 0, &dmsg, sizeof(dmsg));
|
||||||
|
IOVSET(iov + 1, &buff, sizeof(buff));
|
||||||
|
|
||||||
|
msg.msg_name = NULL;
|
||||||
|
msg.msg_namelen = 0;
|
||||||
|
msg.msg_iov = iov;
|
||||||
|
msg.msg_iovlen = 2;
|
||||||
|
msg.msg_flags = 0;
|
||||||
|
|
||||||
|
if ((!cmsgptr) && (!(cmsgptr = malloc(RIGHTS_LEN))))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
msg.msg_control = cmsgptr;
|
||||||
|
msg.msg_controllen = RIGHTS_LEN;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
recvmsg(_ecore_drm_sockets[0], &msg, 0);
|
||||||
|
if (errno != 0)
|
||||||
|
{
|
||||||
|
ERR("Failed to receive message: %m");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DBG("Received %li bytes from %d", size, _ecore_drm_sockets[0]); */
|
||||||
|
|
||||||
|
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
|
||||||
|
cmsg = CMSG_NXTHDR(&msg, cmsg))
|
||||||
|
{
|
||||||
|
if (cmsg->cmsg_level != SOL_SOCKET)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (cmsg->cmsg_type)
|
||||||
|
{
|
||||||
|
case SCM_RIGHTS:
|
||||||
|
if (fd) *fd = *((int *)CMSG_DATA(cmsg));
|
||||||
|
switch (dmsg.opcode)
|
||||||
|
{
|
||||||
|
case ECORE_DRM_OP_DEVICE_OPEN:
|
||||||
|
case ECORE_DRM_OP_DEVICE_CLOSE:
|
||||||
|
case ECORE_DRM_OP_TTY_OPEN:
|
||||||
|
case ECORE_DRM_OP_DEVICE_MASTER_DROP:
|
||||||
|
case ECORE_DRM_OP_DEVICE_MASTER_SET:
|
||||||
|
if ((fd) && (*fd >= 0)) ret = ECORE_DRM_OP_SUCCESS;
|
||||||
|
if (data) memcpy(*data, buff, bytes);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_ecore_drm_message_send(int opcode, int fd, void *data, size_t bytes)
|
||||||
|
{
|
||||||
|
_ecore_drm_socket_send(opcode, fd, data, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
Eina_Bool
|
||||||
|
_ecore_drm_message_receive(int opcode, int *fd, void **data, size_t bytes)
|
||||||
|
{
|
||||||
|
int ret = ECORE_DRM_OP_FAILURE;
|
||||||
|
|
||||||
|
ret = _ecore_drm_socket_receive(opcode, fd, data, bytes);
|
||||||
|
if (ret != ECORE_DRM_OP_SUCCESS) return EINA_FALSE;
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup Ecore_Drm_Init_Group Drm Library Init and Shutdown Functions
|
||||||
|
*
|
||||||
|
* Functions that start and shutdown the Ecore_Drm Library.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the Ecore_Drm library
|
||||||
|
*
|
||||||
|
* @return The number of times the library has been initialized without
|
||||||
|
* being shut down. 0 is returned if an error occurs.
|
||||||
|
*
|
||||||
|
* @ingroup Ecore_Drm_Init_Group
|
||||||
|
*/
|
||||||
|
EAPI int
|
||||||
|
ecore_drm_init(void)
|
||||||
|
{
|
||||||
|
/* if we have already initialized, return the count */
|
||||||
|
if (++_ecore_drm_init_count != 1) return _ecore_drm_init_count;
|
||||||
|
|
||||||
|
/* try to init eina */
|
||||||
|
if (!eina_init()) return --_ecore_drm_init_count;
|
||||||
|
|
||||||
|
if (!ecore_init())
|
||||||
|
{
|
||||||
|
eina_shutdown();
|
||||||
|
return --_ecore_drm_init_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set logging level */
|
||||||
|
eina_log_level_set(EINA_LOG_LEVEL_DBG);
|
||||||
|
|
||||||
|
setvbuf(stdout, NULL, _IONBF, 0);
|
||||||
|
setvbuf(stderr, NULL, _IONBF, 0);
|
||||||
|
|
||||||
|
/* optionally log output to a file */
|
||||||
|
#ifdef LOG_TO_FILE
|
||||||
|
int log_fd;
|
||||||
|
char log_path[PATH_MAX];
|
||||||
|
mode_t um;
|
||||||
|
|
||||||
|
/* assemble logging file path */
|
||||||
|
strcpy(log_path, "/tmp/ecore_drm_XXXXXX");
|
||||||
|
|
||||||
|
/* create temporary logging file */
|
||||||
|
um = umask(S_IRWXG | S_IRWXO);
|
||||||
|
log_fd = mkstemp(log_path);
|
||||||
|
umask(um);
|
||||||
|
|
||||||
|
/* try to open logging file */
|
||||||
|
if (!(lg = fdopen(log_fd, "w")))
|
||||||
|
goto log_err;
|
||||||
|
|
||||||
|
eina_log_print_cb_set(eina_log_print_cb_file, lg);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* try to create logging domain */
|
||||||
|
_ecore_drm_log_dom =
|
||||||
|
eina_log_domain_register("ecore_drm", ECORE_DRM_DEFAULT_LOG_COLOR);
|
||||||
|
if (!_ecore_drm_log_dom)
|
||||||
|
{
|
||||||
|
EINA_LOG_ERR("Could not create log domain for Ecore_Drm");
|
||||||
|
goto log_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set default logging level for this domain */
|
||||||
|
if (!eina_log_domain_level_check(_ecore_drm_log_dom, EINA_LOG_LEVEL_DBG))
|
||||||
|
eina_log_domain_level_set("ecore_drm", EINA_LOG_LEVEL_DBG);
|
||||||
|
|
||||||
|
/* try to init udev */
|
||||||
|
if (!(udev = udev_new()))
|
||||||
|
goto udev_err;
|
||||||
|
|
||||||
|
/* try to create the socketpair */
|
||||||
|
if (!_ecore_drm_sockets_create())
|
||||||
|
goto sock_err;
|
||||||
|
|
||||||
|
/* try to run Spartacus */
|
||||||
|
if (!_ecore_drm_launcher_spawn())
|
||||||
|
goto spawn_err;
|
||||||
|
|
||||||
|
/* return init count */
|
||||||
|
return _ecore_drm_init_count;
|
||||||
|
|
||||||
|
spawn_err:
|
||||||
|
close(_ecore_drm_sockets[0]);
|
||||||
|
close(_ecore_drm_sockets[1]);
|
||||||
|
sock_err:
|
||||||
|
if (udev) udev_unref(udev);
|
||||||
|
udev_err:
|
||||||
|
ecore_shutdown();
|
||||||
|
eina_log_domain_unregister(_ecore_drm_log_dom);
|
||||||
|
_ecore_drm_log_dom = -1;
|
||||||
|
log_err:
|
||||||
|
#ifdef LOG_TO_FILE
|
||||||
|
if (lg) fclose(lg);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* shutdown eina */
|
||||||
|
eina_shutdown();
|
||||||
|
|
||||||
|
return --_ecore_drm_init_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shutdown the Ecore_Drm library.
|
||||||
|
*
|
||||||
|
* @return The number of times the library has been initialized without
|
||||||
|
* being shutdown. 0 is returned if an error occurs.
|
||||||
|
*
|
||||||
|
* @ingroup Ecore_Drm_Init_Group
|
||||||
|
*/
|
||||||
|
EAPI int
|
||||||
|
ecore_drm_shutdown(void)
|
||||||
|
{
|
||||||
|
/* if we are still in use, decrement init count and get out */
|
||||||
|
if (--_ecore_drm_init_count != 0) return _ecore_drm_init_count;
|
||||||
|
|
||||||
|
/* close udev handle */
|
||||||
|
if (udev) udev_unref(udev);
|
||||||
|
|
||||||
|
/* close sockets */
|
||||||
|
close(_ecore_drm_sockets[0]);
|
||||||
|
close(_ecore_drm_sockets[1]);
|
||||||
|
|
||||||
|
ecore_shutdown();
|
||||||
|
|
||||||
|
/* unregsiter log domain */
|
||||||
|
eina_log_domain_unregister(_ecore_drm_log_dom);
|
||||||
|
_ecore_drm_log_dom = -1;
|
||||||
|
|
||||||
|
#ifdef LOG_TO_FILE
|
||||||
|
if (lg) fclose(lg);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* shutdown eina */
|
||||||
|
eina_shutdown();
|
||||||
|
|
||||||
|
/* return init count */
|
||||||
|
return _ecore_drm_init_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI void *
|
||||||
|
ecore_drm_gbm_get(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
if (!dev) return NULL;
|
||||||
|
|
||||||
|
#ifdef HAVE_GBM
|
||||||
|
return dev->gbm;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI unsigned int
|
||||||
|
ecore_drm_gbm_format_get(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
if (!dev) return 0;
|
||||||
|
return dev->format;
|
||||||
|
}
|
|
@ -0,0 +1,585 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "ecore_drm_private.h"
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_GBM
|
||||||
|
static Eina_Bool
|
||||||
|
_ecore_drm_device_egl_config_get(Ecore_Drm_Device *dev, const EGLint *attribs, const EGLint *visual)
|
||||||
|
{
|
||||||
|
EGLint c = 0, m = 0;
|
||||||
|
EGLConfig *cfgs;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (!eglGetConfigs(dev->egl.disp, NULL, 0, &c) || (c < 1))
|
||||||
|
return EINA_FALSE;
|
||||||
|
|
||||||
|
if (!(cfgs = calloc(c, sizeof(*cfgs)))) return EINA_FALSE;
|
||||||
|
|
||||||
|
if (!eglChooseConfig(dev->egl.disp, attribs, cfgs, c, &m))
|
||||||
|
{
|
||||||
|
free(cfgs);
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < m; i++)
|
||||||
|
{
|
||||||
|
EGLint id;
|
||||||
|
|
||||||
|
if (visual)
|
||||||
|
{
|
||||||
|
if (!eglGetConfigAttrib(dev->egl.disp, cfgs[i],
|
||||||
|
EGL_NATIVE_VISUAL_ID, &id))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((id != 0) && (id != *visual))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->egl.cfg = cfgs[i];
|
||||||
|
free(cfgs);
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(cfgs);
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
_ecore_drm_device_cb_page_flip(int fd EINA_UNUSED, unsigned int frame EINA_UNUSED, unsigned int sec EINA_UNUSED, unsigned int usec EINA_UNUSED, void *data)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Output *output;
|
||||||
|
|
||||||
|
DBG("Drm Page Flip Event");
|
||||||
|
|
||||||
|
if (!(output = data)) return;
|
||||||
|
|
||||||
|
if (output->pending_flip)
|
||||||
|
{
|
||||||
|
ecore_drm_output_fb_release(output, output->current);
|
||||||
|
output->current = output->next;
|
||||||
|
output->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
output->pending_flip = EINA_FALSE;
|
||||||
|
if (!output->pending_vblank) ecore_drm_output_repaint(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_ecore_drm_device_cb_vblank(int fd EINA_UNUSED, unsigned int frame EINA_UNUSED, unsigned int sec EINA_UNUSED, unsigned int usec EINA_UNUSED, void *data)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Sprite *sprite;
|
||||||
|
Ecore_Drm_Output *output;
|
||||||
|
|
||||||
|
DBG("Drm VBlank Event");
|
||||||
|
|
||||||
|
if (!(sprite = data)) return;
|
||||||
|
|
||||||
|
output = sprite->output;
|
||||||
|
output->pending_vblank = EINA_FALSE;
|
||||||
|
|
||||||
|
ecore_drm_output_fb_release(output, sprite->current_fb);
|
||||||
|
sprite->current_fb = sprite->next_fb;
|
||||||
|
sprite->next_fb = NULL;
|
||||||
|
|
||||||
|
if (!output->pending_flip) _ecore_drm_output_frame_finish(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_ecore_drm_device_cb_event(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Device *dev;
|
||||||
|
drmEventContext ctx;
|
||||||
|
|
||||||
|
if (!(dev = data)) return ECORE_CALLBACK_RENEW;
|
||||||
|
|
||||||
|
DBG("Drm Device Event");
|
||||||
|
|
||||||
|
memset(&ctx, 0, sizeof(ctx));
|
||||||
|
|
||||||
|
ctx.version = DRM_EVENT_CONTEXT_VERSION;
|
||||||
|
ctx.page_flip_handler = _ecore_drm_device_cb_page_flip;
|
||||||
|
ctx.vblank_handler = _ecore_drm_device_cb_vblank;
|
||||||
|
|
||||||
|
drmHandleEvent(dev->drm.fd, &ctx);
|
||||||
|
|
||||||
|
return ECORE_CALLBACK_RENEW;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_ecore_drm_device_cb_idle(void *data)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Device *dev;
|
||||||
|
Ecore_Drm_Output *output;
|
||||||
|
Eina_List *l;
|
||||||
|
|
||||||
|
if (!(dev = data)) return ECORE_CALLBACK_CANCEL;
|
||||||
|
|
||||||
|
EINA_LIST_FOREACH(dev->outputs, l, output)
|
||||||
|
{
|
||||||
|
output->need_repaint = EINA_TRUE;
|
||||||
|
if (output->repaint_scheduled) continue;
|
||||||
|
_ecore_drm_output_repaint_start(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ECORE_CALLBACK_RENEW;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup Ecore_Drm_Device_Group Device manipulation functions
|
||||||
|
*
|
||||||
|
* Functions that deal with finding, opening, closing, and otherwise using
|
||||||
|
* the DRM device itself.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a drm device in the system.
|
||||||
|
*
|
||||||
|
* @param name The name of the device to find. If NULL, this function will
|
||||||
|
* search for the default drm device.
|
||||||
|
* @param seat The name of the seat where this device may be found. If NULL,
|
||||||
|
* this function will use a default seat name 'seat0'.
|
||||||
|
*
|
||||||
|
* @return An opaque Ecore_Drm_Device structure representing the card.
|
||||||
|
*
|
||||||
|
* @ingroup Ecore_Drm_Device_Group
|
||||||
|
*/
|
||||||
|
EAPI Ecore_Drm_Device *
|
||||||
|
ecore_drm_device_find(const char *name, const char *seat)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Device *dev = NULL;
|
||||||
|
struct udev_enumerate *uenum;
|
||||||
|
struct udev_list_entry *uentry;
|
||||||
|
struct udev_device *udevice, *tmpdevice = NULL, *pcidevice;
|
||||||
|
const char *path = NULL, *devseat = NULL;
|
||||||
|
|
||||||
|
/* check for existing udev reference */
|
||||||
|
if (!udev) return NULL;
|
||||||
|
|
||||||
|
/* setup udev enumerator */
|
||||||
|
uenum = udev_enumerate_new(udev);
|
||||||
|
udev_enumerate_add_match_subsystem(uenum, "drm");
|
||||||
|
udev_enumerate_add_match_subsystem(uenum, "card[0-9]*");
|
||||||
|
|
||||||
|
/* ask udev for list of drm devices */
|
||||||
|
udev_enumerate_scan_devices(uenum);
|
||||||
|
|
||||||
|
/* loop list of returned devices */
|
||||||
|
udev_list_entry_foreach(uentry, udev_enumerate_get_list_entry(uenum))
|
||||||
|
{
|
||||||
|
/* get device path */
|
||||||
|
path = udev_list_entry_get_name(uentry);
|
||||||
|
|
||||||
|
/* get udev device */
|
||||||
|
if (!(udevice = udev_device_new_from_syspath(udev, path)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* if we are looking for a certain device, then compare names */
|
||||||
|
if (name)
|
||||||
|
{
|
||||||
|
if (strcmp(name, udev_device_get_devnode(udevice)))
|
||||||
|
{
|
||||||
|
udev_device_unref(udevice);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get this devices' seat */
|
||||||
|
devseat = udev_device_get_property_value(udevice, "ID_SEAT");
|
||||||
|
if (!devseat) devseat = "seat0";
|
||||||
|
|
||||||
|
/* if we are looking for a device on a certain seat, compare it */
|
||||||
|
if (seat)
|
||||||
|
{
|
||||||
|
if (strcmp(seat, devseat))
|
||||||
|
{
|
||||||
|
udev_device_unref(udevice);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* no seat name passed to use. check default */
|
||||||
|
if (strcmp(devseat, "seat0"))
|
||||||
|
{
|
||||||
|
udev_device_unref(udevice);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* try to find the boot_vga attribute */
|
||||||
|
if ((pcidevice =
|
||||||
|
udev_device_get_parent_with_subsystem_devtype(udevice, "pci", NULL)))
|
||||||
|
{
|
||||||
|
const char *id;
|
||||||
|
|
||||||
|
if ((id = udev_device_get_sysattr_value(pcidevice, "boot_vga")))
|
||||||
|
{
|
||||||
|
if (!strcmp(id, "1"))
|
||||||
|
{
|
||||||
|
if (tmpdevice) udev_device_unref(tmpdevice);
|
||||||
|
tmpdevice = udevice;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tmpdevice)
|
||||||
|
tmpdevice = udevice;
|
||||||
|
else
|
||||||
|
udev_device_unref(udevice);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* destroy the enumerator */
|
||||||
|
udev_enumerate_unref(uenum);
|
||||||
|
|
||||||
|
if (tmpdevice)
|
||||||
|
{
|
||||||
|
DBG("Found Drm Device");
|
||||||
|
DBG("\tFilename: %s", udev_device_get_devnode(tmpdevice));
|
||||||
|
DBG("\tDriver: %s", udev_device_get_driver(tmpdevice));
|
||||||
|
DBG("\tDevpath: %s", udev_device_get_devpath(tmpdevice));
|
||||||
|
DBG("\tSyspath: %s", udev_device_get_syspath(tmpdevice));
|
||||||
|
DBG("\tSysname: %s", udev_device_get_sysname(tmpdevice));
|
||||||
|
|
||||||
|
/* try to allocate space for return device structure */
|
||||||
|
if ((dev = calloc(1, sizeof(Ecore_Drm_Device))))
|
||||||
|
{
|
||||||
|
const char *id, *seat;
|
||||||
|
|
||||||
|
/* set device name */
|
||||||
|
dev->drm.name =
|
||||||
|
eina_stringshare_add(udev_device_get_devnode(tmpdevice));
|
||||||
|
|
||||||
|
/* set device path */
|
||||||
|
dev->drm.path =
|
||||||
|
eina_stringshare_add(udev_device_get_syspath(tmpdevice));
|
||||||
|
|
||||||
|
/* store id for this device */
|
||||||
|
if ((id = udev_device_get_sysnum(tmpdevice)))
|
||||||
|
dev->id = atoi(id);
|
||||||
|
|
||||||
|
/* set dev seat */
|
||||||
|
seat = udev_device_get_property_value(tmpdevice, "ID_SEAT");
|
||||||
|
if (!seat) seat = "seat0";
|
||||||
|
|
||||||
|
dev->seat = eina_stringshare_add(seat);
|
||||||
|
|
||||||
|
dev->format = GBM_FORMAT_XRGB8888;
|
||||||
|
dev->use_hw_accel = EINA_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* release device reference */
|
||||||
|
udev_device_unref(tmpdevice);
|
||||||
|
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free an Ecore_Drm_Device
|
||||||
|
*
|
||||||
|
* This function will cleanup and free any previously allocated Ecore_Drm_Device.
|
||||||
|
*
|
||||||
|
* @param dev The Ecore_Drm_Device to free
|
||||||
|
*
|
||||||
|
* @ingroup Ecore_Drm_Device_Group
|
||||||
|
*/
|
||||||
|
EAPI void
|
||||||
|
ecore_drm_device_free(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Output *output;
|
||||||
|
|
||||||
|
/* check for valid device */
|
||||||
|
if (!dev) return;
|
||||||
|
|
||||||
|
/* free outputs */
|
||||||
|
EINA_LIST_FREE(dev->outputs, output)
|
||||||
|
ecore_drm_output_free(output);
|
||||||
|
|
||||||
|
/* free crtcs */
|
||||||
|
if (dev->crtcs) free(dev->crtcs);
|
||||||
|
|
||||||
|
/* free device name */
|
||||||
|
if (dev->drm.name) eina_stringshare_del(dev->drm.name);
|
||||||
|
|
||||||
|
/* free device path */
|
||||||
|
if (dev->drm.path) eina_stringshare_del(dev->drm.path);
|
||||||
|
|
||||||
|
/* free device seat */
|
||||||
|
if (dev->seat) eina_stringshare_del(dev->seat);
|
||||||
|
|
||||||
|
/* free structure */
|
||||||
|
free(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open an Ecore_Drm_Device
|
||||||
|
*
|
||||||
|
* This function will open an existing Ecore_Drm_Device for use.
|
||||||
|
*
|
||||||
|
* @param dev The Ecore_Drm_Device to try and open
|
||||||
|
*
|
||||||
|
* @return EINA_TRUE on success, EINA_FALSE on failure
|
||||||
|
*
|
||||||
|
* @ingroup Ecore_Drm_Device_Group
|
||||||
|
*/
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_device_open(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
uint64_t caps;
|
||||||
|
|
||||||
|
/* check for valid device */
|
||||||
|
if ((!dev) || (!dev->drm.name)) return EINA_FALSE;
|
||||||
|
|
||||||
|
dev->drm.fd = open(dev->drm.name, O_RDWR);
|
||||||
|
if (dev->drm.fd < 0) return EINA_FALSE;
|
||||||
|
|
||||||
|
DBG("Opened Device %s : %d", dev->drm.name, dev->drm.fd);
|
||||||
|
|
||||||
|
if (!drmGetCap(dev->drm.fd, DRM_CAP_TIMESTAMP_MONOTONIC, &caps))
|
||||||
|
{
|
||||||
|
if (caps == 1)
|
||||||
|
dev->drm.clock = CLOCK_MONOTONIC;
|
||||||
|
else
|
||||||
|
dev->drm.clock = CLOCK_REALTIME;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERR("Could not get device capabilities: %m");
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_GBM
|
||||||
|
if (getenv("ECORE_DRM_HW_ACCEL"))
|
||||||
|
{
|
||||||
|
/* 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 ((dev->gbm = gbm_create_device(dev->drm.fd)))
|
||||||
|
{
|
||||||
|
EGLint major, minor, visual;
|
||||||
|
const EGLint attribs[] =
|
||||||
|
{
|
||||||
|
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
||||||
|
EGL_RED_SIZE, 1, EGL_GREEN_SIZE, 1,
|
||||||
|
EGL_BLUE_SIZE, 1, EGL_ALPHA_SIZE, 0,
|
||||||
|
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE
|
||||||
|
};
|
||||||
|
|
||||||
|
dev->use_hw_accel = EINA_TRUE;
|
||||||
|
/* TODO: gbm_device_is_format_supported to check that
|
||||||
|
* argb can be used for scanout | rendering */
|
||||||
|
dev->format = GBM_FORMAT_XRGB8888;
|
||||||
|
|
||||||
|
dev->egl.disp = eglGetDisplay(dev->gbm);
|
||||||
|
if (dev->egl.disp == EGL_NO_DISPLAY)
|
||||||
|
{
|
||||||
|
ERR("Could not get egl display");
|
||||||
|
goto init_software;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!eglInitialize(dev->egl.disp, &major, &minor))
|
||||||
|
{
|
||||||
|
ERR("Could not initialize egl");
|
||||||
|
goto init_software;
|
||||||
|
}
|
||||||
|
|
||||||
|
visual = dev->format;
|
||||||
|
if (!_ecore_drm_device_egl_config_get(dev, attribs, &visual))
|
||||||
|
{
|
||||||
|
ERR("Could not get egl config");
|
||||||
|
goto init_software;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WRN("Failed to create gbm device");
|
||||||
|
goto init_software;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
/* TODO: init software */
|
||||||
|
init_software:
|
||||||
|
DBG("Init Software Engine");
|
||||||
|
#ifdef HAVE_GBM
|
||||||
|
if (dev->egl.disp)
|
||||||
|
{
|
||||||
|
eglMakeCurrent(dev->egl.disp, EGL_NO_SURFACE, EGL_NO_SURFACE,
|
||||||
|
EGL_NO_CONTEXT);
|
||||||
|
eglTerminate(dev->egl.disp);
|
||||||
|
eglReleaseThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev->gbm) gbm_device_destroy(dev->gbm);
|
||||||
|
dev->gbm = NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->drm.hdlr =
|
||||||
|
ecore_main_fd_handler_add(dev->drm.fd, ECORE_FD_READ,
|
||||||
|
_ecore_drm_device_cb_event, dev, NULL, NULL);
|
||||||
|
|
||||||
|
dev->drm.idler =
|
||||||
|
ecore_idle_enterer_add(_ecore_drm_device_cb_idle, dev);
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close an Ecore_Drm_Device
|
||||||
|
*
|
||||||
|
* This function will close a previously opened Ecore_Drm_Device
|
||||||
|
*
|
||||||
|
* @param dev The Ecore_Drm_Device to free
|
||||||
|
*
|
||||||
|
* @return EINA_TRUE on success, EINA_FALSE on failure
|
||||||
|
*
|
||||||
|
* @ingroup Ecore_Drm_Device_Group
|
||||||
|
*/
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_device_close(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
/* check for valid device */
|
||||||
|
if (!dev) return EINA_FALSE;
|
||||||
|
|
||||||
|
#ifdef HAVE_GBM
|
||||||
|
if (dev->use_hw_accel)
|
||||||
|
{
|
||||||
|
if (dev->egl.disp)
|
||||||
|
{
|
||||||
|
eglMakeCurrent(dev->egl.disp, EGL_NO_SURFACE, EGL_NO_SURFACE,
|
||||||
|
EGL_NO_CONTEXT);
|
||||||
|
eglTerminate(dev->egl.disp);
|
||||||
|
eglReleaseThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev->gbm) gbm_device_destroy(dev->gbm);
|
||||||
|
dev->gbm = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (dev->drm.hdlr) ecore_main_fd_handler_del(dev->drm.hdlr);
|
||||||
|
dev->drm.hdlr = NULL;
|
||||||
|
|
||||||
|
close(dev->drm.fd);
|
||||||
|
|
||||||
|
/* reset device fd */
|
||||||
|
dev->drm.fd = -1;
|
||||||
|
|
||||||
|
/* free(data); */
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get if a given Ecore_Drm_Device is master
|
||||||
|
*
|
||||||
|
* This function will check if the given drm device is set to master
|
||||||
|
*
|
||||||
|
* @param dev The Ecore_Drm_Device to check
|
||||||
|
*
|
||||||
|
* @return EINA_TRUE if device is master, EINA_FALSE otherwise
|
||||||
|
*
|
||||||
|
* @ingroup Ecore_Drm_Device_Group
|
||||||
|
*/
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_device_master_get(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
/* drm_magic_t mag; */
|
||||||
|
|
||||||
|
/* check for valid device */
|
||||||
|
if ((!dev) || (dev->drm.fd < 0)) return EINA_FALSE;
|
||||||
|
|
||||||
|
/* FIXME: Remote this to the slave process !! */
|
||||||
|
|
||||||
|
/* get if we are master or not */
|
||||||
|
/* if ((drmGetMagic(dev->drm.fd, &mag) == 0) && */
|
||||||
|
/* (drmAuthMagic(dev->drm.fd, mag) == 0)) */
|
||||||
|
/* return EINA_TRUE; */
|
||||||
|
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a given Ecore_Drm_Device to master
|
||||||
|
*
|
||||||
|
* This function will attempt to set a given drm device to be master
|
||||||
|
*
|
||||||
|
* @param dev The Ecore_Drm_Device to set
|
||||||
|
*
|
||||||
|
* @return EINA_TRUE on success, EINA_FALSE on failure
|
||||||
|
*
|
||||||
|
* @ingroup Ecore_Drm_Device_Group
|
||||||
|
*/
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_device_master_set(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
Eina_Bool ret = EINA_FALSE;
|
||||||
|
int dfd;
|
||||||
|
|
||||||
|
/* check for valid device */
|
||||||
|
if ((!dev) || (dev->drm.fd < 0)) return EINA_FALSE;
|
||||||
|
|
||||||
|
DBG("Set Master On Fd: %d", dev->drm.fd);
|
||||||
|
|
||||||
|
/* try to close the device */
|
||||||
|
_ecore_drm_message_send(ECORE_DRM_OP_DEVICE_MASTER_SET, dev->drm.fd,
|
||||||
|
NULL, 0);
|
||||||
|
|
||||||
|
/* get the result of the close operation */
|
||||||
|
ret = _ecore_drm_message_receive(ECORE_DRM_OP_DEVICE_MASTER_SET, &dfd,
|
||||||
|
NULL, 0);
|
||||||
|
if (!ret) return EINA_FALSE;
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell a given Ecore_Drm_Device to stop being master
|
||||||
|
*
|
||||||
|
* This function will attempt to ask a drm device to stop being master
|
||||||
|
*
|
||||||
|
* @param dev The Ecore_Drm_Device to set
|
||||||
|
*
|
||||||
|
* @return EINA_TRUE on success, EINA_FALSE on failure
|
||||||
|
*
|
||||||
|
* @ingroup Ecore_Drm_Device_Group
|
||||||
|
*/
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_device_master_drop(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
Eina_Bool ret = EINA_FALSE;
|
||||||
|
int dfd;
|
||||||
|
|
||||||
|
/* check for valid device */
|
||||||
|
if ((!dev) || (dev->drm.fd < 0)) return EINA_FALSE;
|
||||||
|
|
||||||
|
DBG("Drop Master On Fd: %d", dev->drm.fd);
|
||||||
|
|
||||||
|
/* try to close the device */
|
||||||
|
_ecore_drm_message_send(ECORE_DRM_OP_DEVICE_MASTER_DROP, dev->drm.fd,
|
||||||
|
NULL, 0);
|
||||||
|
|
||||||
|
/* get the result of the close operation */
|
||||||
|
ret = _ecore_drm_message_receive(ECORE_DRM_OP_DEVICE_MASTER_DROP, &dfd,
|
||||||
|
NULL, 0);
|
||||||
|
if (!ret) return EINA_FALSE;
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI int
|
||||||
|
ecore_drm_device_fd_get(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
if (!dev) return -1;
|
||||||
|
return dev->drm.fd;
|
||||||
|
}
|
|
@ -0,0 +1,360 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* copied from udev/extras/input_id/input_id.c */
|
||||||
|
/* we must use this kernel-compatible implementation */
|
||||||
|
#define BITS_PER_LONG (sizeof(unsigned long) * 8)
|
||||||
|
#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
|
||||||
|
#define OFF(x) ((x)%BITS_PER_LONG)
|
||||||
|
#define BIT(x) (1UL<<OFF(x))
|
||||||
|
#define LONG(x) ((x)/BITS_PER_LONG)
|
||||||
|
#define TEST_BIT(array, bit) ((array[LONG(bit)] >> OFF(bit)) & 1)
|
||||||
|
/* end copied */
|
||||||
|
|
||||||
|
#include "ecore_drm_private.h"
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <linux/input.h>
|
||||||
|
|
||||||
|
/* local functions */
|
||||||
|
static Eina_Bool
|
||||||
|
_device_configure(Ecore_Drm_Evdev *edev)
|
||||||
|
{
|
||||||
|
Eina_Bool ret = EINA_FALSE;
|
||||||
|
|
||||||
|
if (!edev) return EINA_FALSE;
|
||||||
|
|
||||||
|
if ((edev->caps & (EVDEV_MOTION_ABS | EVDEV_MOTION_REL)) &&
|
||||||
|
(edev->caps & EVDEV_BUTTON))
|
||||||
|
{
|
||||||
|
DBG("Input device %s is a pointer", edev->name);
|
||||||
|
edev->seat_caps |= EVDEV_SEAT_POINTER;
|
||||||
|
ret = EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (edev->caps & EVDEV_KEYBOARD)
|
||||||
|
{
|
||||||
|
DBG("Input device %s is a keyboard", edev->name);
|
||||||
|
edev->seat_caps |= EVDEV_SEAT_KEYBOARD;
|
||||||
|
ret = EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (edev->caps & EVDEV_TOUCH)
|
||||||
|
{
|
||||||
|
DBG("Input device %s is a touchpad", edev->name);
|
||||||
|
edev->seat_caps |= EVDEV_SEAT_TOUCH;
|
||||||
|
ret = EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_device_handle(Ecore_Drm_Evdev *edev)
|
||||||
|
{
|
||||||
|
struct input_absinfo absinfo;
|
||||||
|
unsigned long dev_bits[NBITS(EV_MAX)];
|
||||||
|
unsigned long abs_bits[NBITS(ABS_MAX)];
|
||||||
|
unsigned long rel_bits[NBITS(REL_MAX)];
|
||||||
|
unsigned long key_bits[NBITS(KEY_MAX)];
|
||||||
|
/* Eina_Bool have_key = EINA_FALSE; */
|
||||||
|
Eina_Bool have_abs = EINA_FALSE;
|
||||||
|
|
||||||
|
if (!edev) return EINA_FALSE;
|
||||||
|
|
||||||
|
ioctl(edev->fd, EVIOCGBIT(0, sizeof(dev_bits)), dev_bits);
|
||||||
|
if (TEST_BIT(dev_bits, EV_ABS))
|
||||||
|
{
|
||||||
|
have_abs = EINA_TRUE;
|
||||||
|
|
||||||
|
ioctl(edev->fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), abs_bits);
|
||||||
|
|
||||||
|
if ((TEST_BIT(abs_bits, ABS_WHEEL)) ||
|
||||||
|
(TEST_BIT(abs_bits, ABS_GAS)) ||
|
||||||
|
(TEST_BIT(abs_bits, ABS_BRAKE)) ||
|
||||||
|
(TEST_BIT(abs_bits, ABS_HAT0X)))
|
||||||
|
{
|
||||||
|
/* ignore joystick */
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TEST_BIT(abs_bits, ABS_X))
|
||||||
|
{
|
||||||
|
ioctl(edev->fd, EVIOCGABS(ABS_X), &absinfo);
|
||||||
|
edev->abs.min_x = absinfo.minimum;
|
||||||
|
edev->abs.max_x = absinfo.maximum;
|
||||||
|
edev->caps |= EVDEV_MOTION_ABS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TEST_BIT(abs_bits, ABS_Y))
|
||||||
|
{
|
||||||
|
ioctl(edev->fd, EVIOCGABS(ABS_Y), &absinfo);
|
||||||
|
edev->abs.min_y = absinfo.minimum;
|
||||||
|
edev->abs.max_y = absinfo.maximum;
|
||||||
|
edev->caps |= EVDEV_MOTION_ABS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((TEST_BIT(abs_bits, ABS_MT_POSITION_X)) &&
|
||||||
|
(TEST_BIT(abs_bits, ABS_MT_POSITION_Y)))
|
||||||
|
{
|
||||||
|
DBG("Handle MultiTouch Device: %s", edev->path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TEST_BIT(dev_bits, EV_REL))
|
||||||
|
{
|
||||||
|
ioctl(edev->fd, EVIOCGBIT(EV_REL, sizeof(rel_bits)), rel_bits);
|
||||||
|
|
||||||
|
if ((TEST_BIT(rel_bits, REL_X)) || (TEST_BIT(rel_bits, REL_Y)))
|
||||||
|
edev->caps |= EVDEV_MOTION_REL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TEST_BIT(dev_bits, EV_KEY))
|
||||||
|
{
|
||||||
|
unsigned int i = 0;
|
||||||
|
|
||||||
|
/* have_key = EINA_TRUE; */
|
||||||
|
|
||||||
|
ioctl(edev->fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)), key_bits);
|
||||||
|
|
||||||
|
if (have_abs)
|
||||||
|
{
|
||||||
|
if ((TEST_BIT(key_bits, BTN_TOOL_FINGER)) &&
|
||||||
|
(!TEST_BIT(key_bits, BTN_TOOL_PEN)))
|
||||||
|
{
|
||||||
|
DBG("Device Is Touchpad: %s", edev->path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = KEY_ESC; i < KEY_MAX; i++)
|
||||||
|
{
|
||||||
|
if ((i >= BTN_MISC) && (i < KEY_OK)) continue;
|
||||||
|
if (TEST_BIT(key_bits, i))
|
||||||
|
{
|
||||||
|
edev->caps |= EVDEV_KEYBOARD;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TEST_BIT(key_bits, BTN_TOUCH))
|
||||||
|
edev->caps |= EVDEV_TOUCH;
|
||||||
|
|
||||||
|
for (i = BTN_MISC; i < BTN_JOYSTICK; i++)
|
||||||
|
{
|
||||||
|
if (TEST_BIT(key_bits, i))
|
||||||
|
{
|
||||||
|
edev->caps |= EVDEV_BUTTON;
|
||||||
|
edev->caps &= ~EVDEV_TOUCH;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TEST_BIT(dev_bits, EV_LED)) edev->caps |= EVDEV_KEYBOARD;
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_device_notify_key(Ecore_Drm_Evdev *dev, struct input_event *event, unsigned int timestamp)
|
||||||
|
{
|
||||||
|
DBG("Key Event");
|
||||||
|
DBG("\tCode: %d", event->code);
|
||||||
|
DBG("\tValue: %d", event->value);
|
||||||
|
|
||||||
|
if ((event->code >= KEY_ESC) && (event->code <= KEY_COMPOSE))
|
||||||
|
{
|
||||||
|
/* ignore key repeat */
|
||||||
|
if (event->value == 2)
|
||||||
|
{
|
||||||
|
DBG("\tKey Repeat");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_device_process_flush(Ecore_Drm_Evdev *dev, unsigned int timestamp)
|
||||||
|
{
|
||||||
|
switch (dev->pending_event)
|
||||||
|
{
|
||||||
|
case EVDEV_NONE:
|
||||||
|
return;
|
||||||
|
case EVDEV_RELATIVE_MOTION:
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
case EVDEV_ABSOLUTE_MT_DOWN:
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
case EVDEV_ABSOLUTE_MT_MOTION:
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
case EVDEV_ABSOLUTE_MT_UP:
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
case EVDEV_ABSOLUTE_TOUCH_DOWN:
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
case EVDEV_ABSOLUTE_MOTION:
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
case EVDEV_ABSOLUTE_TOUCH_UP:
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
dev->pending_event = EVDEV_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_device_process_key(Ecore_Drm_Evdev *dev, struct input_event *event, unsigned int timestamp)
|
||||||
|
{
|
||||||
|
if (event->code == BTN_TOUCH)
|
||||||
|
{
|
||||||
|
/* TODO: check for mt device */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_device_process_flush(dev, timestamp);
|
||||||
|
|
||||||
|
switch (event->code)
|
||||||
|
{
|
||||||
|
case BTN_LEFT:
|
||||||
|
case BTN_RIGHT:
|
||||||
|
case BTN_MIDDLE:
|
||||||
|
case BTN_SIDE:
|
||||||
|
case BTN_EXTRA:
|
||||||
|
case BTN_FORWARD:
|
||||||
|
case BTN_BACK:
|
||||||
|
case BTN_TASK:
|
||||||
|
/* TODO: notify button */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_device_notify_key(dev, event, timestamp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_device_process(Ecore_Drm_Evdev *dev, struct input_event *event, int count)
|
||||||
|
{
|
||||||
|
struct input_event *ev, *end;
|
||||||
|
unsigned int timestamp = 0;
|
||||||
|
|
||||||
|
DBG("Evdev Device Process");
|
||||||
|
|
||||||
|
ev = event;
|
||||||
|
end = ev + count;
|
||||||
|
for (ev = event; ev < end; ev++)
|
||||||
|
{
|
||||||
|
timestamp = (ev->time.tv_sec * 1000) + (ev->time.tv_usec / 1000);
|
||||||
|
|
||||||
|
switch (ev->type)
|
||||||
|
{
|
||||||
|
case EV_KEY:
|
||||||
|
_device_process_key(dev, ev, timestamp);
|
||||||
|
break;
|
||||||
|
case EV_REL:
|
||||||
|
DBG("\tRelative Event");
|
||||||
|
break;
|
||||||
|
case EV_ABS:
|
||||||
|
DBG("\tAbsolute Event");
|
||||||
|
break;
|
||||||
|
case EV_SYN:
|
||||||
|
_device_process_flush(dev, timestamp);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_cb_device_data(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Evdev *edev;
|
||||||
|
struct input_event ev[32];
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
if (!(edev = data)) return EINA_TRUE;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
len = read(edev->fd, &ev, sizeof(ev));
|
||||||
|
|
||||||
|
if ((len < 0) || ((len % sizeof(ev[0])) != 0))
|
||||||
|
{
|
||||||
|
if ((len < 0) && (errno != EAGAIN) && (errno != EINTR))
|
||||||
|
{
|
||||||
|
ERR("Device Died");
|
||||||
|
}
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
edev->event_process(edev, ev, (len / sizeof(ev[0])));
|
||||||
|
|
||||||
|
} while (len > 0);
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* external functions */
|
||||||
|
Ecore_Drm_Evdev *
|
||||||
|
_ecore_drm_evdev_device_create(Ecore_Drm_Seat *seat, const char *path, int fd)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Evdev *edev;
|
||||||
|
char name[256] = "unknown";
|
||||||
|
|
||||||
|
if (!(edev = calloc(1, sizeof(Ecore_Drm_Evdev))))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
edev->seat = seat;
|
||||||
|
edev->path = eina_stringshare_add(path);
|
||||||
|
edev->fd = fd;
|
||||||
|
|
||||||
|
if (ioctl(edev->fd, EVIOCGNAME(sizeof(name)), name) < 0)
|
||||||
|
DBG("Error getting device name: %m");
|
||||||
|
|
||||||
|
name[sizeof(name) - 1] = '\0';
|
||||||
|
edev->name = eina_stringshare_add(name);
|
||||||
|
|
||||||
|
if (!_device_handle(edev))
|
||||||
|
{
|
||||||
|
ERR("Unhandled Input Device: %s", name);
|
||||||
|
_ecore_drm_evdev_device_destroy(edev);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_device_configure(edev))
|
||||||
|
{
|
||||||
|
_ecore_drm_evdev_device_destroy(edev);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
edev->event_process = _device_process;
|
||||||
|
|
||||||
|
edev->hdlr =
|
||||||
|
ecore_main_fd_handler_add(edev->fd, ECORE_FD_READ,
|
||||||
|
_cb_device_data, edev, NULL, NULL);
|
||||||
|
if (!edev->hdlr)
|
||||||
|
{
|
||||||
|
ERR("Could not create fd handler");
|
||||||
|
_ecore_drm_evdev_device_destroy(edev);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return edev;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_ecore_drm_evdev_device_destroy(Ecore_Drm_Evdev *dev)
|
||||||
|
{
|
||||||
|
if (!dev) return;
|
||||||
|
|
||||||
|
if (dev->path) eina_stringshare_del(dev->path);
|
||||||
|
if (dev->name) eina_stringshare_del(dev->name);
|
||||||
|
if (dev->hdlr) ecore_main_fd_handler_del(dev->hdlr);
|
||||||
|
|
||||||
|
free(dev);
|
||||||
|
}
|
|
@ -0,0 +1,152 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "ecore_drm_private.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup Ecore_Drm_Fb_Group
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* TODO: DOXY !! */
|
||||||
|
|
||||||
|
EAPI Ecore_Drm_Fb *
|
||||||
|
ecore_drm_fb_create(Ecore_Drm_Device *dev, int width, int height)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Fb *fb;
|
||||||
|
struct drm_mode_create_dumb carg;
|
||||||
|
struct drm_mode_destroy_dumb darg;
|
||||||
|
struct drm_mode_map_dumb marg;
|
||||||
|
|
||||||
|
if (!(fb = calloc(1, sizeof(Ecore_Drm_Fb)))) return NULL;
|
||||||
|
|
||||||
|
memset(&carg, 0, sizeof(struct drm_mode_create_dumb));
|
||||||
|
|
||||||
|
carg.bpp = 32; // FIXME: Hard-coded depth
|
||||||
|
carg.width = width;
|
||||||
|
carg.height = height;
|
||||||
|
|
||||||
|
if (drmIoctl(dev->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &carg))
|
||||||
|
{
|
||||||
|
ERR("Could not create dumb framebuffer: %m");
|
||||||
|
goto create_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
fb->from_client = EINA_TRUE;
|
||||||
|
fb->hdl = carg.handle;
|
||||||
|
fb->stride = carg.pitch;
|
||||||
|
fb->size = carg.size;
|
||||||
|
fb->fd = dev->drm.fd;
|
||||||
|
|
||||||
|
if (drmModeAddFB(dev->drm.fd, width, height, 24, 32,
|
||||||
|
fb->stride, fb->hdl, &fb->id))
|
||||||
|
{
|
||||||
|
ERR("Could not add framebuffer: %m");
|
||||||
|
goto add_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&marg, 0, sizeof(struct drm_mode_map_dumb));
|
||||||
|
marg.handle = fb->hdl;
|
||||||
|
if (drmIoctl(dev->drm.fd, DRM_IOCTL_MODE_MAP_DUMB, &marg))
|
||||||
|
{
|
||||||
|
ERR("Could not map framebuffer: %m");
|
||||||
|
goto map_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
fb->mmap =
|
||||||
|
mmap(0, fb->size, PROT_WRITE | PROT_READ, MAP_SHARED,
|
||||||
|
dev->drm.fd, marg.offset);
|
||||||
|
if (fb->mmap == MAP_FAILED)
|
||||||
|
{
|
||||||
|
ERR("Could not mmap framebuffer space: %m");
|
||||||
|
goto map_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(fb->mmap, 0, fb->size);
|
||||||
|
|
||||||
|
return fb;
|
||||||
|
|
||||||
|
map_err:
|
||||||
|
drmModeRmFB(fb->fd, fb->id);
|
||||||
|
add_err:
|
||||||
|
memset(&darg, 0, sizeof(struct drm_mode_destroy_dumb));
|
||||||
|
darg.handle = fb->hdl;
|
||||||
|
drmIoctl(dev->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &darg);
|
||||||
|
create_err:
|
||||||
|
free(fb);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI void
|
||||||
|
ecore_drm_fb_destroy(Ecore_Drm_Fb *fb)
|
||||||
|
{
|
||||||
|
struct drm_mode_destroy_dumb darg;
|
||||||
|
|
||||||
|
if ((!fb) || (!fb->mmap)) return;
|
||||||
|
|
||||||
|
if (fb->id) drmModeRmFB(fb->fd, fb->id);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_GBM
|
||||||
|
static void
|
||||||
|
_ecore_drm_fb_user_data_destroy(struct gbm_bo *bo EINA_UNUSED, void *data)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Fb *fb;
|
||||||
|
|
||||||
|
if (!(fb = data)) return;
|
||||||
|
ecore_drm_fb_destroy(fb);
|
||||||
|
/* free(data); */
|
||||||
|
}
|
||||||
|
|
||||||
|
Ecore_Drm_Fb *
|
||||||
|
_ecore_drm_fb_bo_get(Ecore_Drm_Device *dev, struct gbm_bo *bo)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Fb *fb;
|
||||||
|
unsigned int width, height;
|
||||||
|
unsigned int h[4], p[4], o[4];
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if ((fb = gbm_bo_get_user_data(bo))) return fb;
|
||||||
|
|
||||||
|
if (!(fb = calloc(1, sizeof(Ecore_Drm_Fb)))) return NULL;
|
||||||
|
|
||||||
|
fb->bo = bo;
|
||||||
|
|
||||||
|
width = gbm_bo_get_width(bo);
|
||||||
|
height = gbm_bo_get_height(bo);
|
||||||
|
fb->stride = gbm_bo_get_stride(bo);
|
||||||
|
fb->hdl = gbm_bo_get_handle(bo).u32;
|
||||||
|
fb->size = (fb->stride * height);
|
||||||
|
fb->fd = dev->drm.fd;
|
||||||
|
|
||||||
|
h[0] = fb->hdl;
|
||||||
|
p[0] = fb->stride;
|
||||||
|
o[0] = 0;
|
||||||
|
|
||||||
|
ret = drmModeAddFB2(dev->drm.fd, width, height, dev->format, h, p, o,
|
||||||
|
&fb->id, 0);
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
ret = drmModeAddFB(dev->drm.fd, width, height, 24, 32,
|
||||||
|
fb->stride, fb->hdl, &fb->id);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
ERR("Error during ModeAddFb");
|
||||||
|
free(fb);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
gbm_bo_set_user_data(bo, fb, _ecore_drm_fb_user_data_destroy);
|
||||||
|
|
||||||
|
return fb;
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,303 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "ecore_drm_private.h"
|
||||||
|
|
||||||
|
/* local functions */
|
||||||
|
static Ecore_Drm_Seat *
|
||||||
|
_seat_get(Ecore_Drm_Input *input, const char *seat)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Seat *s;
|
||||||
|
Eina_List *l;
|
||||||
|
|
||||||
|
EINA_LIST_FOREACH(input->dev->seats, l, s)
|
||||||
|
{
|
||||||
|
if (!strcmp(s->name, seat)) return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(s = calloc(1, sizeof(Ecore_Drm_Seat))))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
s->input = input;
|
||||||
|
s->name = eina_stringshare_add(seat);
|
||||||
|
|
||||||
|
input->dev->seats = eina_list_append(input->dev->seats, s);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_device_add(Ecore_Drm_Input *input, struct udev_device *device)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Evdev *edev;
|
||||||
|
Ecore_Drm_Seat *seat;
|
||||||
|
const char *dev_seat, *wl_seat;
|
||||||
|
const char *node;
|
||||||
|
char n[PATH_MAX];
|
||||||
|
int fd = -1;
|
||||||
|
|
||||||
|
if (!(dev_seat = udev_device_get_property_value(device, "ID_SEAT")))
|
||||||
|
dev_seat = "seat0";
|
||||||
|
|
||||||
|
if (strcmp(dev_seat, input->seat)) return EINA_FALSE;
|
||||||
|
|
||||||
|
if (!(wl_seat = udev_device_get_property_value(device, "WL_SEAT")))
|
||||||
|
wl_seat = "seat0";
|
||||||
|
|
||||||
|
if (!(seat = _seat_get(input, wl_seat)))
|
||||||
|
return EINA_FALSE;
|
||||||
|
|
||||||
|
node = udev_device_get_devnode(device);
|
||||||
|
strcpy(n, node);
|
||||||
|
fd = open(n, O_RDWR | O_NONBLOCK);
|
||||||
|
/* _ecore_drm_message_send(ECORE_DRM_OP_DEVICE_OPEN, -1, n, strlen(n)); */
|
||||||
|
/* _ecore_drm_message_receive(ECORE_DRM_OP_DEVICE_OPEN, &fd, NULL, 0); */
|
||||||
|
/* DBG("Opened Restricted Input: %s %d", node, fd); */
|
||||||
|
|
||||||
|
if (!(edev = _ecore_drm_evdev_device_create(seat, node, fd)))
|
||||||
|
{
|
||||||
|
close(fd);
|
||||||
|
/* _ecore_drm_message_send(ECORE_DRM_OP_DEVICE_CLOSE, fd, NULL, 0); */
|
||||||
|
/* _ecore_drm_message_receive(ECORE_DRM_OP_DEVICE_OPEN, &fd, NULL, 0); */
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
seat->devices = eina_list_append(seat->devices, edev);
|
||||||
|
|
||||||
|
/* TODO: finish */
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_device_remove(Ecore_Drm_Input *input, const char *device)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Seat *seat;
|
||||||
|
Eina_List *l;
|
||||||
|
|
||||||
|
if (!input) return;
|
||||||
|
|
||||||
|
EINA_LIST_FOREACH(input->dev->seats, l, seat)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Evdev *edev;
|
||||||
|
Eina_List *ll;
|
||||||
|
|
||||||
|
EINA_LIST_FOREACH(seat->devices, ll, edev)
|
||||||
|
{
|
||||||
|
if (!strcmp(edev->path, device))
|
||||||
|
{
|
||||||
|
seat->devices = eina_list_remove(seat->devices, edev);
|
||||||
|
_ecore_drm_evdev_device_destroy(edev);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_cb_input_event(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Input *input;
|
||||||
|
struct udev_device *udevice;
|
||||||
|
const char *act;
|
||||||
|
|
||||||
|
DBG("Input Event");
|
||||||
|
|
||||||
|
if (!(input = data)) return EINA_FALSE;
|
||||||
|
|
||||||
|
if (!(udevice = udev_monitor_receive_device(input->monitor)))
|
||||||
|
return EINA_TRUE;
|
||||||
|
|
||||||
|
if (!(act = udev_device_get_action(udevice))) return EINA_TRUE;
|
||||||
|
|
||||||
|
if (strncmp("event", udev_device_get_sysname(udevice), 5) != 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
if (!strcmp(act, "add"))
|
||||||
|
{
|
||||||
|
DBG("\tDevice Added");
|
||||||
|
_device_add(input, udevice);
|
||||||
|
}
|
||||||
|
else if (!strcmp(act, "remove"))
|
||||||
|
{
|
||||||
|
const char *node;
|
||||||
|
|
||||||
|
node = udev_device_get_devnode(udevice);
|
||||||
|
|
||||||
|
DBG("\tDevice Removed: %s", node);
|
||||||
|
_device_remove(input, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
|
||||||
|
err:
|
||||||
|
if (udevice) udev_device_unref(udevice);
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_devices_add(Ecore_Drm_Input *input)
|
||||||
|
{
|
||||||
|
struct udev_enumerate *uenum;
|
||||||
|
struct udev_list_entry *uentry;
|
||||||
|
struct udev_device *udevice;
|
||||||
|
const char *path, *name;
|
||||||
|
Eina_Bool found = EINA_FALSE;
|
||||||
|
|
||||||
|
uenum = udev_enumerate_new(udev);
|
||||||
|
udev_enumerate_add_match_subsystem(uenum, "input");
|
||||||
|
udev_enumerate_scan_devices(uenum);
|
||||||
|
|
||||||
|
udev_list_entry_foreach(uentry, udev_enumerate_get_list_entry(uenum))
|
||||||
|
{
|
||||||
|
path = udev_list_entry_get_name(uentry);
|
||||||
|
udevice = udev_device_new_from_syspath(udev, path);
|
||||||
|
name = udev_device_get_sysname(udevice);
|
||||||
|
|
||||||
|
if (strncmp("event", name, 5) != 0)
|
||||||
|
{
|
||||||
|
udev_device_unref(udevice);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_device_add(input, udevice))
|
||||||
|
{
|
||||||
|
udev_device_unref(udevice);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
found = EINA_TRUE;
|
||||||
|
|
||||||
|
udev_device_unref(udevice);
|
||||||
|
}
|
||||||
|
|
||||||
|
udev_enumerate_unref(uenum);
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
ERR("No Input Devices Found");
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* public functions */
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_inputs_create(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Input *input;
|
||||||
|
|
||||||
|
/* check for valid device */
|
||||||
|
if ((!dev) || (!udev)) return EINA_FALSE;
|
||||||
|
|
||||||
|
/* try to allocate space for input structure */
|
||||||
|
if (!(input = calloc(1, sizeof(Ecore_Drm_Input))))
|
||||||
|
return EINA_FALSE;
|
||||||
|
|
||||||
|
/* FIXME: Hardcoded seat name */
|
||||||
|
input->seat = eina_stringshare_add("seat0");
|
||||||
|
input->dev = dev;
|
||||||
|
|
||||||
|
/* try to enable this input */
|
||||||
|
if (!ecore_drm_inputs_enable(input))
|
||||||
|
{
|
||||||
|
ERR("Could not enable input");
|
||||||
|
if (input->seat) eina_stringshare_del(input->seat);
|
||||||
|
free(input);
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add this input to dev */
|
||||||
|
dev->inputs = eina_list_append(dev->inputs, input);
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI void
|
||||||
|
ecore_drm_inputs_destroy(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Seat *seat;
|
||||||
|
Eina_List *l;
|
||||||
|
|
||||||
|
if (!dev) return;
|
||||||
|
|
||||||
|
EINA_LIST_FOREACH(dev->seats, l, seat)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Evdev *edev;
|
||||||
|
|
||||||
|
EINA_LIST_FREE(seat->devices, edev)
|
||||||
|
_ecore_drm_evdev_device_destroy(edev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_inputs_enable(Ecore_Drm_Input *input)
|
||||||
|
{
|
||||||
|
/* check for valid input */
|
||||||
|
if (!input) return EINA_FALSE;
|
||||||
|
|
||||||
|
if (!input->monitor)
|
||||||
|
input->monitor = udev_monitor_new_from_netlink(udev, "udev");
|
||||||
|
|
||||||
|
if (!input->monitor)
|
||||||
|
{
|
||||||
|
ERR("Could not create udev monitor: %m");
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* setup input filter */
|
||||||
|
udev_monitor_filter_add_match_subsystem_devtype(input->monitor,
|
||||||
|
"input", NULL);
|
||||||
|
|
||||||
|
/* try to enable receiving udev events */
|
||||||
|
if (udev_monitor_enable_receiving(input->monitor))
|
||||||
|
{
|
||||||
|
ERR("Could not bind udev monitor: %m");
|
||||||
|
udev_monitor_unref(input->monitor);
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* save the fd */
|
||||||
|
if ((input->fd = udev_monitor_get_fd(input->monitor)) < 0)
|
||||||
|
{
|
||||||
|
ERR("Input monitor has no fd: %m");
|
||||||
|
udev_monitor_unref(input->monitor);
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create fd handler */
|
||||||
|
if (!input->hdlr)
|
||||||
|
{
|
||||||
|
input->hdlr =
|
||||||
|
ecore_main_fd_handler_add(input->fd, ECORE_FD_READ,
|
||||||
|
_cb_input_event, input, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!input->hdlr)
|
||||||
|
{
|
||||||
|
ERR("Failed to setup input fd handler: %m");
|
||||||
|
udev_monitor_unref(input->monitor);
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* try to add devices */
|
||||||
|
if (!_devices_add(input))
|
||||||
|
{
|
||||||
|
ERR("Could not add input devices");
|
||||||
|
udev_monitor_unref(input->monitor);
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
input->enabled = EINA_TRUE;
|
||||||
|
input->suspended = EINA_FALSE;
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI void
|
||||||
|
ecore_drm_inputs_disable(Ecore_Drm_Input *input)
|
||||||
|
{
|
||||||
|
if (!input) return;
|
||||||
|
}
|
|
@ -0,0 +1,712 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "ecore_drm_private.h"
|
||||||
|
|
||||||
|
#define ALEN(array) (sizeof(array) / sizeof(array)[0])
|
||||||
|
|
||||||
|
static const char *conn_types[] =
|
||||||
|
{
|
||||||
|
"None", "VGA", "DVI", "DVI", "DVI",
|
||||||
|
"Composite", "TV", "LVDS", "CTV", "DIN",
|
||||||
|
"DP", "HDMI", "HDMI", "TV", "eDP",
|
||||||
|
};
|
||||||
|
|
||||||
|
/* local functions */
|
||||||
|
#ifdef HAVE_GBM
|
||||||
|
static Eina_Bool
|
||||||
|
_ecore_drm_output_context_create(Ecore_Drm_Device *dev, EGLSurface surface)
|
||||||
|
{
|
||||||
|
EGLBoolean r;
|
||||||
|
static const EGLint attribs[] =
|
||||||
|
{
|
||||||
|
EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE
|
||||||
|
};
|
||||||
|
|
||||||
|
if ((!dev->egl.disp) || (!dev->egl.cfg)) return EINA_FALSE;
|
||||||
|
|
||||||
|
if (!eglBindAPI(EGL_OPENGL_ES_API))
|
||||||
|
{
|
||||||
|
ERR("Could not bind egl api");
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->egl.ctxt =
|
||||||
|
eglCreateContext(dev->egl.disp, dev->egl.cfg, EGL_NO_CONTEXT, attribs);
|
||||||
|
if (!dev->egl.ctxt)
|
||||||
|
{
|
||||||
|
ERR("Could not create Egl Context");
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = eglMakeCurrent(dev->egl.disp, surface, surface, dev->egl.ctxt);
|
||||||
|
if (r == EGL_FALSE)
|
||||||
|
{
|
||||||
|
ERR("Could not make surface current");
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: bind display, handle extensions, compile shaders, etc */
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_ecore_drm_output_hardware_setup(Ecore_Drm_Device *dev, Ecore_Drm_Output *output)
|
||||||
|
{
|
||||||
|
unsigned int i = 0;
|
||||||
|
int flags = 0;
|
||||||
|
int w = 0, h = 0;
|
||||||
|
|
||||||
|
if ((!dev) || (!output)) return EINA_FALSE;
|
||||||
|
|
||||||
|
if (output->current_mode)
|
||||||
|
{
|
||||||
|
w = output->current_mode->width;
|
||||||
|
h = output->current_mode->height;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
w = 1024;
|
||||||
|
h = 768;
|
||||||
|
}
|
||||||
|
|
||||||
|
flags = (GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
|
||||||
|
|
||||||
|
/* FIXME: NB: Should this really be XARGB8888 ?? */
|
||||||
|
if (!(output->surface =
|
||||||
|
gbm_surface_create(dev->gbm, w, h, GBM_FORMAT_ARGB8888, flags)))
|
||||||
|
{
|
||||||
|
ERR("Could not create output surface");
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(output->egl.surface =
|
||||||
|
eglCreateWindowSurface(dev->egl.disp, dev->egl.cfg,
|
||||||
|
output->surface, NULL)))
|
||||||
|
{
|
||||||
|
ERR("Could not create output egl surface");
|
||||||
|
gbm_surface_destroy(output->surface);
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dev->egl.ctxt)
|
||||||
|
{
|
||||||
|
if (!_ecore_drm_output_context_create(dev, output->egl.surface))
|
||||||
|
{
|
||||||
|
ERR("Could not create context");
|
||||||
|
gbm_surface_destroy(output->surface);
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
flags = (GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
|
||||||
|
for (i = 0; i < NUM_FRAME_BUFFERS; i++)
|
||||||
|
{
|
||||||
|
if (output->cursor[i]) continue;
|
||||||
|
if (!(output->cursor[i] =
|
||||||
|
gbm_bo_create(dev->gbm, 64, 64, dev->format, flags)))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((!output->cursor[0]) || (!output->cursor[1]))
|
||||||
|
{
|
||||||
|
WRN("Hardware Cursor Buffers not available");
|
||||||
|
dev->cursors_broken = EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_ecore_drm_output_hardware_render(Ecore_Drm_Output *output)
|
||||||
|
{
|
||||||
|
struct gbm_bo *bo;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!output) return;
|
||||||
|
if (!output->current_mode) return;
|
||||||
|
|
||||||
|
glViewport(output->x, output->y,
|
||||||
|
output->current_mode->width, output->current_mode->height);
|
||||||
|
|
||||||
|
if (eglMakeCurrent(output->dev->egl.disp, output->egl.surface,
|
||||||
|
output->egl.surface, output->dev->egl.ctxt) == EGL_FALSE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* TODO: calculate damage */
|
||||||
|
|
||||||
|
/* TODO: repaint surfaces */
|
||||||
|
|
||||||
|
/* TODO: call egl functions to repaint */
|
||||||
|
glClearColor(1.0, 1.0, 0.0, 1.0);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
glFlush();
|
||||||
|
|
||||||
|
/* eglSwapInterval(output->dev->egl.disp, 1); */
|
||||||
|
eglSwapBuffers(output->dev->egl.disp, output->egl.surface);
|
||||||
|
|
||||||
|
if (!(bo = gbm_surface_lock_front_buffer(output->surface)))
|
||||||
|
{
|
||||||
|
ERR("Failed to lock front buffer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(output->next = _ecore_drm_fb_bo_get(output->dev, bo)))
|
||||||
|
{
|
||||||
|
ERR("Failed to get FB from bo");
|
||||||
|
gbm_surface_release_buffer(output->surface, bo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_ecore_drm_output_software_setup(Ecore_Drm_Device *dev, Ecore_Drm_Output *output)
|
||||||
|
{
|
||||||
|
unsigned int i = 0;
|
||||||
|
int w = 0, h = 0;
|
||||||
|
|
||||||
|
if ((!dev) || (!output)) return EINA_FALSE;
|
||||||
|
|
||||||
|
if (output->current_mode)
|
||||||
|
{
|
||||||
|
w = output->current_mode->width;
|
||||||
|
h = output->current_mode->height;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
w = 1024;
|
||||||
|
h = 768;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_FRAME_BUFFERS; i++)
|
||||||
|
{
|
||||||
|
if (!(output->dumb[i] = ecore_drm_fb_create(dev, w, h)))
|
||||||
|
{
|
||||||
|
ERR("Could not create dumb framebuffer %d", i);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
|
||||||
|
err:
|
||||||
|
for (i = 0; i < NUM_FRAME_BUFFERS; i++)
|
||||||
|
{
|
||||||
|
if (output->dumb[i]) ecore_drm_fb_destroy(output->dumb[i]);
|
||||||
|
output->dumb[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_ecore_drm_output_software_render(Ecore_Drm_Output *output)
|
||||||
|
{
|
||||||
|
if (!output) return;
|
||||||
|
if (!output->current_mode) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_ecore_drm_output_crtc_find(Ecore_Drm_Device *dev, drmModeRes *res, drmModeConnector *conn)
|
||||||
|
{
|
||||||
|
drmModeEncoder *enc;
|
||||||
|
unsigned int p;
|
||||||
|
int i = 0, j = 0;
|
||||||
|
|
||||||
|
for (j = 0; j < conn->count_encoders; j++)
|
||||||
|
{
|
||||||
|
/* get the encoder on this connector */
|
||||||
|
if (!(enc = drmModeGetEncoder(dev->drm.fd, conn->encoders[j])))
|
||||||
|
{
|
||||||
|
ERR("Failed to get encoder: %m");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = enc->possible_crtcs;
|
||||||
|
drmModeFreeEncoder(enc);
|
||||||
|
|
||||||
|
for (i = 0; i < res->count_crtcs; i++)
|
||||||
|
{
|
||||||
|
if ((p & (1 << i)) &&
|
||||||
|
(!(dev->crtc_allocator & (1 << res->crtcs[i]))))
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Ecore_Drm_Output_Mode *
|
||||||
|
_ecore_drm_output_mode_add(Ecore_Drm_Output *output, drmModeModeInfo *info)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Output_Mode *mode;
|
||||||
|
uint64_t refresh;
|
||||||
|
|
||||||
|
/* try to allocate space for mode */
|
||||||
|
if (!(mode = malloc(sizeof(Ecore_Drm_Output_Mode))))
|
||||||
|
{
|
||||||
|
ERR("Could not allocate space for mode");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mode->flags = 0;
|
||||||
|
mode->width = info->hdisplay;
|
||||||
|
mode->height = info->vdisplay;
|
||||||
|
|
||||||
|
refresh = (info->clock * 1000000LL / 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;
|
||||||
|
|
||||||
|
/* DBG("Added Mode: %dx%d@%d to Output %d", */
|
||||||
|
/* mode->width, mode->height, mode->refresh, output->crtc_id); */
|
||||||
|
|
||||||
|
output->modes = eina_list_append(output->modes, mode);
|
||||||
|
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Ecore_Drm_Output *
|
||||||
|
_ecore_drm_output_create(Ecore_Drm_Device *dev, drmModeRes *res, drmModeConnector *conn, int x, int y)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Output *output;
|
||||||
|
Ecore_Drm_Output_Mode *mode;
|
||||||
|
const char *conn_name;
|
||||||
|
char name[32];
|
||||||
|
int i = 0;
|
||||||
|
drmModeEncoder *enc;
|
||||||
|
drmModeModeInfo crtc_mode;
|
||||||
|
drmModeCrtc *crtc;
|
||||||
|
Eina_List *l;
|
||||||
|
|
||||||
|
i = _ecore_drm_output_crtc_find(dev, res, conn);
|
||||||
|
if (i < 0)
|
||||||
|
{
|
||||||
|
ERR("Could not find crtc or encoder for connector");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* try to allocate space for output */
|
||||||
|
if (!(output = calloc(1, sizeof(Ecore_Drm_Output))))
|
||||||
|
{
|
||||||
|
ERR("Could not allocate space for output");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
output->dev = dev;
|
||||||
|
output->x = x;
|
||||||
|
output->y = y;
|
||||||
|
|
||||||
|
output->subpixel = conn->subpixel;
|
||||||
|
output->make = eina_stringshare_add("unknown");
|
||||||
|
output->model = eina_stringshare_add("unknown");
|
||||||
|
|
||||||
|
if (conn->connector_type < ALEN(conn_types))
|
||||||
|
conn_name = conn_types[conn->connector_type];
|
||||||
|
else
|
||||||
|
conn_name = "UNKNOWN";
|
||||||
|
|
||||||
|
snprintf(name, sizeof(name), "%s%d", conn_name, conn->connector_type_id);
|
||||||
|
output->name = eina_stringshare_add(name);
|
||||||
|
|
||||||
|
output->crtc_id = res->crtcs[i];
|
||||||
|
dev->crtc_allocator |= (1 << output->crtc_id);
|
||||||
|
output->conn_id = conn->connector_id;
|
||||||
|
output->crtc = drmModeGetCrtc(dev->drm.fd, output->crtc_id);
|
||||||
|
|
||||||
|
memset(&mode, 0, sizeof(mode));
|
||||||
|
if ((enc = drmModeGetEncoder(dev->drm.fd, conn->encoder_id)))
|
||||||
|
{
|
||||||
|
crtc = drmModeGetCrtc(dev->drm.fd, enc->crtc_id);
|
||||||
|
drmModeFreeEncoder(enc);
|
||||||
|
if (!crtc) goto mode_err;
|
||||||
|
if (crtc->mode_valid) crtc_mode = crtc->mode;
|
||||||
|
drmModeFreeCrtc(crtc);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < conn->count_modes; i++)
|
||||||
|
{
|
||||||
|
if (!(mode = _ecore_drm_output_mode_add(output, &conn->modes[i])))
|
||||||
|
{
|
||||||
|
ERR("Failed to add mode to output");
|
||||||
|
goto mode_err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EINA_LIST_REVERSE_FOREACH(output->modes, l, mode)
|
||||||
|
{
|
||||||
|
if (!memcmp(&crtc_mode, &mode->info, sizeof(crtc_mode)))
|
||||||
|
{
|
||||||
|
output->current_mode = mode;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!output->current_mode)
|
||||||
|
output->current_mode = _ecore_drm_output_mode_add(output, &crtc_mode);
|
||||||
|
|
||||||
|
#ifdef HAVE_GBM
|
||||||
|
if ((dev->use_hw_accel) && (dev->gbm))
|
||||||
|
{
|
||||||
|
if (!_ecore_drm_output_hardware_setup(dev, output))
|
||||||
|
{
|
||||||
|
ERR("Could not setup output for hardware acceleration");
|
||||||
|
dev->use_hw_accel = EINA_FALSE;
|
||||||
|
if (!_ecore_drm_output_software_setup(dev, output))
|
||||||
|
goto mode_err;
|
||||||
|
else
|
||||||
|
DBG("Setup Output %d for Software Rendering", output->crtc_id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
DBG("Setup Output %d for Hardware Acceleration", output->crtc_id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
dev->use_hw_accel = EINA_FALSE;
|
||||||
|
if (!_ecore_drm_output_software_setup(dev, output))
|
||||||
|
goto mode_err;
|
||||||
|
else
|
||||||
|
DBG("Setup Output %d for Software Rendering", output->crtc_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: output_init_pixman/output_init_egl ?? */
|
||||||
|
|
||||||
|
return output;
|
||||||
|
|
||||||
|
mode_err:
|
||||||
|
EINA_LIST_FREE(output->modes, mode)
|
||||||
|
free(mode);
|
||||||
|
drmModeFreeCrtc(output->crtc);
|
||||||
|
dev->crtc_allocator &= ~(1 << output->crtc_id);
|
||||||
|
free(output);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_ecore_drm_output_frame_finish(Ecore_Drm_Output *output)
|
||||||
|
{
|
||||||
|
if (!output) return;
|
||||||
|
|
||||||
|
if (output->need_repaint) ecore_drm_output_repaint(output);
|
||||||
|
|
||||||
|
output->repaint_scheduled = EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_ecore_drm_output_fb_release(Ecore_Drm_Output *output, Ecore_Drm_Fb *fb)
|
||||||
|
{
|
||||||
|
if ((!output) || (!fb)) return;
|
||||||
|
|
||||||
|
if ((fb->mmap) && (fb != output->dumb[0]) && (fb != output->dumb[1]))
|
||||||
|
ecore_drm_fb_destroy(fb);
|
||||||
|
/* #ifdef HAVE_GBM */
|
||||||
|
/* else if (fb->bo) */
|
||||||
|
/* gbm_bo_destroy(fb->bo); */
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_ecore_drm_output_repaint_start(Ecore_Drm_Output *output)
|
||||||
|
{
|
||||||
|
unsigned int fb;
|
||||||
|
|
||||||
|
DBG("Output Repaint Start");
|
||||||
|
|
||||||
|
if (!output) return;
|
||||||
|
|
||||||
|
if (!output->current)
|
||||||
|
{
|
||||||
|
DBG("\tNo Current FB");
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
fb = output->current->id;
|
||||||
|
|
||||||
|
if (drmModePageFlip(output->dev->drm.fd, output->crtc_id, fb,
|
||||||
|
DRM_MODE_PAGE_FLIP_EVENT, output) < 0)
|
||||||
|
{
|
||||||
|
ERR("Could not schedule output page flip event");
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
finish:
|
||||||
|
_ecore_drm_output_frame_finish(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup Ecore_Drm_Output_Group
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* TODO: DOXY !! */
|
||||||
|
|
||||||
|
/* public functions */
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_outputs_create(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
Eina_Bool ret = EINA_TRUE;
|
||||||
|
Ecore_Drm_Output *output;
|
||||||
|
drmModeConnector *conn;
|
||||||
|
drmModeRes *res;
|
||||||
|
drmModeCrtc *crtc;
|
||||||
|
int i = 0, x = 0, y = 0;
|
||||||
|
|
||||||
|
/* DBG("Create outputs for %d", dev->drm.fd); */
|
||||||
|
|
||||||
|
/* get the resources */
|
||||||
|
if (!(res = drmModeGetResources(dev->drm.fd)))
|
||||||
|
{
|
||||||
|
ERR("Could not get resources for drm card: %m");
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(dev->crtcs = calloc(res->count_crtcs, sizeof(unsigned int))))
|
||||||
|
{
|
||||||
|
ERR("Could not allocate space for crtcs");
|
||||||
|
/* free resources */
|
||||||
|
drmModeFreeResources(res);
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->crtc_count = res->count_crtcs;
|
||||||
|
memcpy(dev->crtcs, res->crtcs, sizeof(unsigned int) * res->count_crtcs);
|
||||||
|
|
||||||
|
dev->min_width = res->min_width;
|
||||||
|
dev->min_height = res->min_height;
|
||||||
|
dev->max_width = res->max_width;
|
||||||
|
dev->max_height = res->max_height;
|
||||||
|
|
||||||
|
for (i = 0; i < res->count_connectors; i++)
|
||||||
|
{
|
||||||
|
if (i > 0) break;
|
||||||
|
/* get the connector */
|
||||||
|
if (!(conn = drmModeGetConnector(dev->drm.fd, res->connectors[i])))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((conn->connection == DRM_MODE_CONNECTED) &&
|
||||||
|
(conn->count_modes > 0))
|
||||||
|
{
|
||||||
|
drmModeEncoder *enc;
|
||||||
|
|
||||||
|
/* create output for this connector */
|
||||||
|
if (!(output = _ecore_drm_output_create(dev, res, conn, x, y)))
|
||||||
|
{
|
||||||
|
/* free the connector */
|
||||||
|
drmModeFreeConnector(conn);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
output->drm_fd = dev->drm.fd;
|
||||||
|
dev->outputs = eina_list_append(dev->outputs, output);
|
||||||
|
|
||||||
|
if (!(enc = drmModeGetEncoder(dev->drm.fd, conn->encoder_id)))
|
||||||
|
{
|
||||||
|
drmModeFreeConnector(conn);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(crtc = drmModeGetCrtc(dev->drm.fd, enc->crtc_id)))
|
||||||
|
{
|
||||||
|
drmModeFreeEncoder(enc);
|
||||||
|
drmModeFreeConnector(conn);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
x += crtc->width;
|
||||||
|
|
||||||
|
drmModeFreeCrtc(crtc);
|
||||||
|
drmModeFreeEncoder(enc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free the connector */
|
||||||
|
drmModeFreeConnector(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = EINA_TRUE;
|
||||||
|
if (eina_list_count(dev->outputs) < 1)
|
||||||
|
{
|
||||||
|
ret = EINA_FALSE;
|
||||||
|
free(dev->crtcs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free resources */
|
||||||
|
drmModeFreeResources(res);
|
||||||
|
|
||||||
|
/* TODO: add hook for udev drm output updates */
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI void
|
||||||
|
ecore_drm_output_free(Ecore_Drm_Output *output)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Output_Mode *mode;
|
||||||
|
|
||||||
|
/* check for valid output */
|
||||||
|
if (!output) return;
|
||||||
|
|
||||||
|
/* free modes */
|
||||||
|
EINA_LIST_FREE(output->modes, mode)
|
||||||
|
free(mode);
|
||||||
|
|
||||||
|
/* free strings */
|
||||||
|
if (output->name) eina_stringshare_del(output->name);
|
||||||
|
if (output->model) eina_stringshare_del(output->model);
|
||||||
|
if (output->make) eina_stringshare_del(output->make);
|
||||||
|
|
||||||
|
free(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI void
|
||||||
|
ecore_drm_output_cursor_size_set(Ecore_Drm_Output *output, int handle, int w, int h)
|
||||||
|
{
|
||||||
|
if (!output) return;
|
||||||
|
drmModeSetCursor(output->drm_fd, output->crtc_id, handle, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_output_enable(Ecore_Drm_Output *output)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Output_Mode *mode;
|
||||||
|
|
||||||
|
if ((!output) || (!output->current)) return EINA_FALSE;
|
||||||
|
|
||||||
|
mode = output->current_mode;
|
||||||
|
if (drmModeSetCrtc(output->drm_fd, output->crtc_id, output->current->id,
|
||||||
|
0, 0, &output->conn_id, 1, &mode->info) < 0)
|
||||||
|
{
|
||||||
|
ERR("Could not set output crtc: %m");
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI void
|
||||||
|
ecore_drm_output_fb_release(Ecore_Drm_Output *output, Ecore_Drm_Fb *fb)
|
||||||
|
{
|
||||||
|
if ((!output) || (!fb)) return;
|
||||||
|
|
||||||
|
if ((fb->mmap) && (fb != output->dumb[0]) && (fb != output->dumb[1]))
|
||||||
|
ecore_drm_fb_destroy(fb);
|
||||||
|
#ifdef HAVE_GBM
|
||||||
|
else if (fb->bo)
|
||||||
|
{
|
||||||
|
if (fb->from_client)
|
||||||
|
gbm_bo_destroy(fb->bo);
|
||||||
|
else
|
||||||
|
gbm_surface_release_buffer(output->surface, fb->bo);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI void
|
||||||
|
ecore_drm_output_repaint(Ecore_Drm_Output *output)
|
||||||
|
{
|
||||||
|
Eina_List *l;
|
||||||
|
Ecore_Drm_Sprite *sprite;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!output) return;
|
||||||
|
|
||||||
|
DBG("Output Repaint: %d %d", output->crtc_id, output->conn_id);
|
||||||
|
|
||||||
|
/* TODO: assign planes ? */
|
||||||
|
|
||||||
|
if (!output->next)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_GBM
|
||||||
|
if (output->dev->use_hw_accel)
|
||||||
|
{
|
||||||
|
_ecore_drm_output_hardware_render(output);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
_ecore_drm_output_software_render(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!output->next)
|
||||||
|
{
|
||||||
|
DBG("\tNo Next Fb");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
output->need_repaint = EINA_FALSE;
|
||||||
|
|
||||||
|
if (!output->current)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Output_Mode *mode;
|
||||||
|
|
||||||
|
mode = output->current_mode;
|
||||||
|
|
||||||
|
ret = drmModeSetCrtc(output->dev->drm.fd, output->crtc_id,
|
||||||
|
output->next->id, 0, 0, &output->conn_id, 1,
|
||||||
|
&mode->info);
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
ERR("Setting output mode failed");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drmModePageFlip(output->dev->drm.fd, output->crtc_id, output->next->id,
|
||||||
|
DRM_MODE_PAGE_FLIP_EVENT, output) < 0)
|
||||||
|
{
|
||||||
|
ERR("Scheduling pageflip failed");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
output->pending_flip = EINA_TRUE;
|
||||||
|
|
||||||
|
EINA_LIST_FOREACH(output->dev->sprites, l, sprite)
|
||||||
|
{
|
||||||
|
unsigned int flags = 0, id = 0;
|
||||||
|
drmVBlank vbl =
|
||||||
|
{
|
||||||
|
.request.type = (DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT),
|
||||||
|
.request.sequence = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (((!sprite->current_fb) && (!sprite->next_fb)) ||
|
||||||
|
(!ecore_drm_sprites_crtc_supported(output, sprite->crtcs)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((sprite->next_fb) && (!output->dev->cursors_broken))
|
||||||
|
id = sprite->next_fb->id;
|
||||||
|
|
||||||
|
ecore_drm_sprites_fb_set(sprite, id, flags);
|
||||||
|
|
||||||
|
vbl.request.signal = (unsigned long)sprite;
|
||||||
|
ret = drmWaitVBlank(output->dev->drm.fd, &vbl);
|
||||||
|
if (ret) ERR("Error Wait VBlank: %m");
|
||||||
|
|
||||||
|
sprite->output = output;
|
||||||
|
output->pending_vblank = EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
err:
|
||||||
|
if (output->next)
|
||||||
|
{
|
||||||
|
ecore_drm_output_fb_release(output, output->next);
|
||||||
|
output->next = NULL;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,283 @@
|
||||||
|
#ifndef _ECORE_DRM_PRIVATE_H
|
||||||
|
# define _ECORE_DRM_PRIVATE_H
|
||||||
|
|
||||||
|
# include "Ecore.h"
|
||||||
|
# include "ecore_private.h"
|
||||||
|
# include "Ecore_Input.h"
|
||||||
|
|
||||||
|
# include <stdio.h>
|
||||||
|
# include <stdlib.h>
|
||||||
|
# include <string.h>
|
||||||
|
# include <unistd.h>
|
||||||
|
# include <errno.h>
|
||||||
|
# include <sys/mman.h>
|
||||||
|
# include <fcntl.h>
|
||||||
|
|
||||||
|
# include <libudev.h>
|
||||||
|
# include <linux/input.h>
|
||||||
|
//# include <libinput.h>
|
||||||
|
|
||||||
|
# include <xf86drm.h>
|
||||||
|
# include <xf86drmMode.h>
|
||||||
|
# include <drm_fourcc.h>
|
||||||
|
|
||||||
|
# ifdef HAVE_GBM
|
||||||
|
# include <gbm.h>
|
||||||
|
# include <EGL/egl.h>
|
||||||
|
# include <EGL/eglext.h>
|
||||||
|
# include <GLES2/gl2.h>
|
||||||
|
# include <GLES2/gl2ext.h>
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# include <Ecore_Drm.h>
|
||||||
|
|
||||||
|
# define NUM_FRAME_BUFFERS 2
|
||||||
|
|
||||||
|
# ifndef DRM_MAJOR
|
||||||
|
# define DRM_MAJOR 226
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifndef DRM_CAP_TIMESTAMP_MONOTONIC
|
||||||
|
# define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifdef ECORE_DRM_DEFAULT_LOG_COLOR
|
||||||
|
# undef ECORE_DRM_DEFAULT_LOG_COLOR
|
||||||
|
# endif
|
||||||
|
# define ECORE_DRM_DEFAULT_LOG_COLOR EINA_COLOR_BLUE
|
||||||
|
|
||||||
|
# define EVDEV_SEAT_POINTER (1 << 0)
|
||||||
|
# define EVDEV_SEAT_KEYBOARD (1 << 1)
|
||||||
|
# define EVDEV_SEAT_TOUCH (1 << 2)
|
||||||
|
|
||||||
|
# ifdef ERR
|
||||||
|
# undef ERR
|
||||||
|
# endif
|
||||||
|
# ifdef DBG
|
||||||
|
# undef DBG
|
||||||
|
# endif
|
||||||
|
# ifdef INF
|
||||||
|
# undef INF
|
||||||
|
# endif
|
||||||
|
# ifdef WRN
|
||||||
|
# undef WRN
|
||||||
|
# endif
|
||||||
|
# ifdef CRIT
|
||||||
|
# undef CRIT
|
||||||
|
# endif
|
||||||
|
|
||||||
|
extern int _ecore_drm_log_dom;
|
||||||
|
|
||||||
|
/* undef this for non-testing builds */
|
||||||
|
# define LOG_TO_FILE
|
||||||
|
|
||||||
|
# ifdef LOG_TO_FILE
|
||||||
|
extern FILE *lg;
|
||||||
|
|
||||||
|
# define ERR(...) \
|
||||||
|
EINA_LOG_DOM_ERR(_ecore_drm_log_dom, __VA_ARGS__); \
|
||||||
|
fflush(lg);
|
||||||
|
|
||||||
|
# define DBG(...) \
|
||||||
|
EINA_LOG_DOM_DBG(_ecore_drm_log_dom, __VA_ARGS__); \
|
||||||
|
fflush(lg);
|
||||||
|
|
||||||
|
# define INF(...) \
|
||||||
|
EINA_LOG_DOM_INFO(_ecore_drm_log_dom, __VA_ARGS__); \
|
||||||
|
fflush(lg);
|
||||||
|
|
||||||
|
# define WRN(...) \
|
||||||
|
EINA_LOG_DOM_WARN(_ecore_drm_log_dom, __VA_ARGS__); \
|
||||||
|
fflush(lg);
|
||||||
|
|
||||||
|
# define CRIT(...) \
|
||||||
|
EINA_LOG_DOM_CRIT(_ecore_drm_log_dom, __VA_ARGS__); \
|
||||||
|
fflush(lg);
|
||||||
|
|
||||||
|
# else
|
||||||
|
# define ERR(...) EINA_LOG_DOM_ERR(_ecore_drm_log_dom, __VA_ARGS__)
|
||||||
|
# define DBG(...) EINA_LOG_DOM_DBG(_ecore_drm_log_dom, __VA_ARGS__)
|
||||||
|
# define INF(...) EINA_LOG_DOM_INFO(_ecore_drm_log_dom, __VA_ARGS__)
|
||||||
|
# define WRN(...) EINA_LOG_DOM_WARN(_ecore_drm_log_dom, __VA_ARGS__)
|
||||||
|
# define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_drm_log_dom, __VA_ARGS__)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
extern struct udev *udev;
|
||||||
|
|
||||||
|
struct _Ecore_Drm_Output_Mode
|
||||||
|
{
|
||||||
|
unsigned int flags;
|
||||||
|
int width, height;
|
||||||
|
unsigned int refresh;
|
||||||
|
drmModeModeInfo info;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _Ecore_Drm_Output
|
||||||
|
{
|
||||||
|
Ecore_Drm_Device *dev;
|
||||||
|
unsigned int crtc_id;
|
||||||
|
unsigned int conn_id;
|
||||||
|
drmModeCrtcPtr crtc;
|
||||||
|
|
||||||
|
int x, y;
|
||||||
|
int drm_fd;
|
||||||
|
|
||||||
|
Eina_Bool need_repaint : 1;
|
||||||
|
Eina_Bool repaint_scheduled : 1;
|
||||||
|
|
||||||
|
Eina_Bool pending_flip : 1;
|
||||||
|
Eina_Bool pending_vblank : 1;
|
||||||
|
|
||||||
|
const char *make, *model, *name;
|
||||||
|
unsigned int subpixel;
|
||||||
|
|
||||||
|
Ecore_Drm_Output_Mode *current_mode;
|
||||||
|
Eina_List *modes;
|
||||||
|
|
||||||
|
Ecore_Drm_Fb *current, *next;
|
||||||
|
Ecore_Drm_Fb *dumb[NUM_FRAME_BUFFERS];
|
||||||
|
|
||||||
|
# ifdef HAVE_GBM
|
||||||
|
struct gbm_surface *surface;
|
||||||
|
struct gbm_bo *cursor[NUM_FRAME_BUFFERS];
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
EGLSurface surface;
|
||||||
|
} egl;
|
||||||
|
# endif
|
||||||
|
|
||||||
|
/* TODO: finish */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _Ecore_Drm_Seat
|
||||||
|
{
|
||||||
|
// struct libinput_seat *seat;
|
||||||
|
const char *name;
|
||||||
|
Ecore_Drm_Input *input;
|
||||||
|
Eina_List *devices;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _Ecore_Drm_Input
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
const char *seat;
|
||||||
|
struct udev_monitor *monitor;
|
||||||
|
Ecore_Fd_Handler *hdlr;
|
||||||
|
Ecore_Drm_Device *dev;
|
||||||
|
|
||||||
|
Eina_Bool enabled : 1;
|
||||||
|
Eina_Bool suspended : 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _Ecore_Drm_Evdev
|
||||||
|
{
|
||||||
|
Ecore_Drm_Seat *seat;
|
||||||
|
/* struct libinput *linput; */
|
||||||
|
/* struct libinput_device *dev; */
|
||||||
|
const char *name, *path;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
int min_x, min_y;
|
||||||
|
int max_x, max_y;
|
||||||
|
int x, y;
|
||||||
|
} abs;
|
||||||
|
|
||||||
|
Ecore_Drm_Evdev_Event_Type pending_event;
|
||||||
|
Ecore_Drm_Evdev_Capabilities caps;
|
||||||
|
Ecore_Drm_Seat_Capabilities seat_caps;
|
||||||
|
|
||||||
|
void (*event_process)(Ecore_Drm_Evdev *dev, struct input_event *event, int count);
|
||||||
|
|
||||||
|
Ecore_Fd_Handler *hdlr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _Ecore_Drm_Sprite
|
||||||
|
{
|
||||||
|
Ecore_Drm_Fb *current_fb, *next_fb;
|
||||||
|
Ecore_Drm_Output *output;
|
||||||
|
|
||||||
|
int drm_fd;
|
||||||
|
|
||||||
|
unsigned int crtcs;
|
||||||
|
unsigned int plane_id;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
unsigned int w, h;
|
||||||
|
} src, dest;
|
||||||
|
|
||||||
|
unsigned int num_formats;
|
||||||
|
unsigned int formats[];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _Ecore_Drm_Device
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
const char *seat;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
const char *name;
|
||||||
|
const char *path;
|
||||||
|
clockid_t clock;
|
||||||
|
Ecore_Fd_Handler *hdlr;
|
||||||
|
Ecore_Idle_Enterer *idler;
|
||||||
|
} drm;
|
||||||
|
|
||||||
|
unsigned int min_width, min_height;
|
||||||
|
unsigned int max_width, max_height;
|
||||||
|
|
||||||
|
unsigned int crtc_count;
|
||||||
|
unsigned int *crtcs;
|
||||||
|
unsigned int crtc_allocator;
|
||||||
|
|
||||||
|
Eina_List *seats;
|
||||||
|
Eina_List *inputs;
|
||||||
|
Eina_List *outputs;
|
||||||
|
Eina_List *sprites;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
const char *name;
|
||||||
|
Ecore_Event_Handler *event_hdlr;
|
||||||
|
} tty;
|
||||||
|
|
||||||
|
unsigned int format;
|
||||||
|
Eina_Bool use_hw_accel : 1;
|
||||||
|
Eina_Bool cursors_broken : 1;
|
||||||
|
|
||||||
|
#ifdef HAVE_GBM
|
||||||
|
struct gbm_device *gbm;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
EGLDisplay disp;
|
||||||
|
EGLContext ctxt;
|
||||||
|
EGLConfig cfg;
|
||||||
|
} egl;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
void _ecore_drm_message_send(int opcode, int fd, void *data, size_t bytes);
|
||||||
|
Eina_Bool _ecore_drm_message_receive(int opcode, int *fd, void **data, size_t bytes);
|
||||||
|
|
||||||
|
Ecore_Drm_Evdev *_ecore_drm_evdev_device_create(Ecore_Drm_Seat *seat, const char *path, int fd);
|
||||||
|
void _ecore_drm_evdev_device_destroy(Ecore_Drm_Evdev *evdev);
|
||||||
|
/* int _ecore_drm_evdev_event_process(struct libinput_event *event); */
|
||||||
|
|
||||||
|
Ecore_Drm_Fb *_ecore_drm_fb_create(Ecore_Drm_Device *dev, int width, int height);
|
||||||
|
void _ecore_drm_fb_destroy(Ecore_Drm_Fb *fb);
|
||||||
|
|
||||||
|
#ifdef HAVE_GBM
|
||||||
|
Ecore_Drm_Fb *_ecore_drm_fb_bo_get(Ecore_Drm_Device *dev, struct gbm_bo *bo);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void _ecore_drm_output_fb_release(Ecore_Drm_Output *output, Ecore_Drm_Fb *fb);
|
||||||
|
void _ecore_drm_output_repaint_start(Ecore_Drm_Output *output);
|
||||||
|
void _ecore_drm_output_frame_finish(Ecore_Drm_Output *output);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,115 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "ecore_drm_private.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup Ecore_Drm_Fb_Group
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* TODO: DOXY !! */
|
||||||
|
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_sprites_create(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
drmModePlaneRes *res;
|
||||||
|
drmModePlane *p;
|
||||||
|
unsigned int i = 0;
|
||||||
|
|
||||||
|
/* check for valid device */
|
||||||
|
if ((!dev) || (dev->drm.fd < 0)) return EINA_FALSE;
|
||||||
|
|
||||||
|
/* get plane resources */
|
||||||
|
if (!(res = drmModeGetPlaneResources(dev->drm.fd))) return EINA_FALSE;
|
||||||
|
|
||||||
|
for (i = 0; i < res->count_planes; i++)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Sprite *sprite;
|
||||||
|
|
||||||
|
if (!(p = drmModeGetPlane(dev->drm.fd, res->planes[i])))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* allocate space for sprite */
|
||||||
|
if (!(sprite =
|
||||||
|
malloc(sizeof(Ecore_Drm_Sprite) +
|
||||||
|
((sizeof(unsigned int)) * p->count_formats))))
|
||||||
|
{
|
||||||
|
drmModeFreePlane(p);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprite->drm_fd = dev->drm.fd;
|
||||||
|
sprite->crtcs = p->possible_crtcs;
|
||||||
|
sprite->plane_id = p->plane_id;
|
||||||
|
sprite->num_formats = p->count_formats;
|
||||||
|
memcpy(sprite->formats, p->formats,
|
||||||
|
p->count_formats * sizeof(p->formats[0]));
|
||||||
|
drmModeFreePlane(p);
|
||||||
|
|
||||||
|
dev->sprites = eina_list_append(dev->sprites, sprite);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free resources */
|
||||||
|
drmModeFreePlaneResources(res);
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI void
|
||||||
|
ecore_drm_sprites_destroy(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Sprite *sprite;
|
||||||
|
|
||||||
|
/* check for valid device */
|
||||||
|
if (!dev) return;
|
||||||
|
|
||||||
|
EINA_LIST_FREE(dev->sprites, sprite)
|
||||||
|
{
|
||||||
|
ecore_drm_sprites_fb_set(sprite, 0, 0);
|
||||||
|
|
||||||
|
_ecore_drm_output_fb_release(sprite->output, sprite->current_fb);
|
||||||
|
_ecore_drm_output_fb_release(sprite->output, sprite->next_fb);
|
||||||
|
|
||||||
|
free(sprite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI void
|
||||||
|
ecore_drm_sprites_fb_set(Ecore_Drm_Sprite *sprite, int fb_id, int flags)
|
||||||
|
{
|
||||||
|
if ((!sprite) || (!sprite->output)) return;
|
||||||
|
|
||||||
|
if (fb_id)
|
||||||
|
{
|
||||||
|
drmModeSetPlane(sprite->drm_fd, sprite->plane_id,
|
||||||
|
sprite->output->crtc_id, fb_id, flags,
|
||||||
|
sprite->dest.x, sprite->dest.y, sprite->dest.w,
|
||||||
|
sprite->dest.h, sprite->src.x, sprite->src.y,
|
||||||
|
sprite->src.w, sprite->src.h);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
drmModeSetPlane(sprite->drm_fd, sprite->plane_id,
|
||||||
|
sprite->output->crtc_id, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_sprites_crtc_supported(Ecore_Drm_Output *output, unsigned int supported)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Device *dev;
|
||||||
|
unsigned int c = 0;
|
||||||
|
|
||||||
|
dev = output->dev;
|
||||||
|
|
||||||
|
for (c = 0; c < dev->crtc_count; c++)
|
||||||
|
{
|
||||||
|
if (dev->crtcs[c] != output->crtc_id) continue;
|
||||||
|
if ((supported) && (1 << c)) return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
|
@ -0,0 +1,297 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "ecore_drm_private.h"
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <linux/vt.h>
|
||||||
|
#include <linux/kd.h>
|
||||||
|
|
||||||
|
#ifndef KDSKBMUTE
|
||||||
|
# define KDSKBMUTE 0x4B51
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_ecore_drm_tty_cb_signal(void *data, int type EINA_UNUSED, void *event)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Device *dev;
|
||||||
|
Ecore_Event_Signal_User *ev;
|
||||||
|
|
||||||
|
dev = data;
|
||||||
|
ev = event;
|
||||||
|
|
||||||
|
DBG("Caught user signal: %d", ev->number);
|
||||||
|
|
||||||
|
if (ev->number == 1)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Input *input;
|
||||||
|
Ecore_Drm_Output *output;
|
||||||
|
Ecore_Drm_Sprite *sprite;
|
||||||
|
Eina_List *l;
|
||||||
|
|
||||||
|
DBG("Release VT");
|
||||||
|
|
||||||
|
/* disable inputs (suspends) */
|
||||||
|
EINA_LIST_FOREACH(dev->inputs, l, input)
|
||||||
|
ecore_drm_inputs_disable(input);
|
||||||
|
|
||||||
|
/* disable hardware cursor */
|
||||||
|
EINA_LIST_FOREACH(dev->outputs, l, output)
|
||||||
|
ecore_drm_output_cursor_size_set(output, 0, 0, 0);
|
||||||
|
|
||||||
|
/* disable sprites */
|
||||||
|
EINA_LIST_FOREACH(dev->sprites, l, sprite)
|
||||||
|
ecore_drm_sprites_fb_set(sprite, 0, 0);
|
||||||
|
|
||||||
|
/* close input fds ?? */
|
||||||
|
|
||||||
|
/* drop drm master */
|
||||||
|
if (ecore_drm_device_master_drop(dev))
|
||||||
|
{
|
||||||
|
/* issue ioctl to release vt */
|
||||||
|
if (!ecore_drm_tty_release(dev))
|
||||||
|
ERR("Could not release VT: %m");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ERR("Could not drop drm master: %m");
|
||||||
|
}
|
||||||
|
else if (ev->number == 2)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Output *output;
|
||||||
|
Ecore_Drm_Input *input;
|
||||||
|
Eina_List *l;
|
||||||
|
|
||||||
|
DBG("Acquire VT");
|
||||||
|
|
||||||
|
/* issue ioctl to acquire vt */
|
||||||
|
if (ecore_drm_tty_acquire(dev))
|
||||||
|
{
|
||||||
|
/* set drm master */
|
||||||
|
if (!ecore_drm_device_master_set(dev))
|
||||||
|
ERR("Could not set drm master: %m");
|
||||||
|
|
||||||
|
/* set output mode */
|
||||||
|
EINA_LIST_FOREACH(dev->outputs, l, output)
|
||||||
|
ecore_drm_output_enable(output);
|
||||||
|
|
||||||
|
/* enable inputs */
|
||||||
|
EINA_LIST_FOREACH(dev->inputs, l, input)
|
||||||
|
ecore_drm_inputs_enable(input);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ERR("Could not acquire VT: %m");
|
||||||
|
}
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_ecore_drm_tty_setup(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
int kb_mode;
|
||||||
|
struct vt_mode vtmode = { 0 };
|
||||||
|
|
||||||
|
if (fstat(dev->tty.fd, &st) == -1)
|
||||||
|
{
|
||||||
|
ERR("Failed to get stats for tty: %m");
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioctl(dev->tty.fd, KDGKBMODE, &kb_mode))
|
||||||
|
{
|
||||||
|
ERR("Could not get tty keyboard mode: %m");
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NB: Don't set this. This Turns OFF keyboard on the VT */
|
||||||
|
/* if (ioctl(dev->tty.fd, KDSKBMUTE, 1) && */
|
||||||
|
/* ioctl(dev->tty.fd, KDSKBMODE, K_OFF)) */
|
||||||
|
/* { */
|
||||||
|
/* ERR("Could not set K_OFF keyboard mode: %m"); */
|
||||||
|
/* return EINA_FALSE; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* if (ioctl(dev->tty.fd, KDSETMODE, KD_GRAPHICS)) */
|
||||||
|
/* { */
|
||||||
|
/* ERR("Could not set graphics mode: %m"); */
|
||||||
|
/* return EINA_FALSE; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
vtmode.mode = VT_PROCESS;
|
||||||
|
vtmode.waitv = 0;
|
||||||
|
vtmode.relsig = SIGUSR1;
|
||||||
|
vtmode.acqsig = SIGUSR2;
|
||||||
|
if (ioctl(dev->tty.fd, VT_SETMODE, &vtmode) < 0)
|
||||||
|
{
|
||||||
|
ERR("Could not set Terminal Mode: %m");
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if (ioctl(dev->tty.fd, VT_ACTIVATE, minor(st.st_rdev)) < 0) */
|
||||||
|
/* { */
|
||||||
|
/* ERR("Failed to activate vt: %m"); */
|
||||||
|
/* return EINA_FALSE; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* if (ioctl(dev->tty.fd, VT_WAITACTIVE, minor(st.st_rdev)) < 0) */
|
||||||
|
/* { */
|
||||||
|
/* ERR("Failed to wait active: %m"); */
|
||||||
|
/* return EINA_FALSE; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup Ecore_Drm_Tty_Group Tty manipulation functions
|
||||||
|
*
|
||||||
|
* Functions that deal with opening, closing, and otherwise using a tty
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a tty for use
|
||||||
|
*
|
||||||
|
* @param dev The Ecore_Drm_Device that this tty will belong to.
|
||||||
|
* @param name The name of the tty to try and open.
|
||||||
|
* If NULL, /dev/tty0 will be used.
|
||||||
|
*
|
||||||
|
* @return EINA_TRUE on success, EINA_FALSE on failure
|
||||||
|
*
|
||||||
|
* @ingroup Ecore_Drm_Tty_Group
|
||||||
|
*/
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_tty_open(Ecore_Drm_Device *dev, const char *name)
|
||||||
|
{
|
||||||
|
char tty[32] = "<stdin>";
|
||||||
|
|
||||||
|
/* check for valid device */
|
||||||
|
if ((!dev) || (!dev->drm.name)) return EINA_FALSE;
|
||||||
|
|
||||||
|
/* assign default tty fd of -1 */
|
||||||
|
dev->tty.fd = -1;
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
{
|
||||||
|
char *env;
|
||||||
|
|
||||||
|
if ((env = getenv("ECORE_DRM_TTY")))
|
||||||
|
snprintf(tty, sizeof(tty), "%s", env);
|
||||||
|
else
|
||||||
|
dev->tty.fd = STDIN_FILENO;
|
||||||
|
}
|
||||||
|
else // FIXME: NB: This should Really check for format of name (/dev/xyz)
|
||||||
|
snprintf(tty, sizeof(tty), "%s", name);
|
||||||
|
|
||||||
|
if (dev->tty.fd < 0)
|
||||||
|
{
|
||||||
|
DBG("Trying to Open Tty: %s", tty);
|
||||||
|
|
||||||
|
dev->tty.fd = open(tty, O_RDWR | O_NOCTTY);
|
||||||
|
if (dev->tty.fd < 0)
|
||||||
|
{
|
||||||
|
DBG("Failed to Open Tty: %m");
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev->tty.fd < 0)
|
||||||
|
{
|
||||||
|
DBG("Failed to open tty %s", tty);
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBG("Opened Tty %s : %d", tty, dev->tty.fd);
|
||||||
|
|
||||||
|
/* save tty name */
|
||||||
|
dev->tty.name = eina_stringshare_add(tty);
|
||||||
|
|
||||||
|
/* FIXME */
|
||||||
|
if (!_ecore_drm_tty_setup(dev))
|
||||||
|
return EINA_FALSE;
|
||||||
|
|
||||||
|
/* setup handler for signals */
|
||||||
|
dev->tty.event_hdlr =
|
||||||
|
ecore_event_handler_add(ECORE_EVENT_SIGNAL_USER,
|
||||||
|
_ecore_drm_tty_cb_signal, dev);
|
||||||
|
|
||||||
|
/* set current tty into env */
|
||||||
|
setenv("ECORE_DRM_TTY", tty, 1);
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close an already opened tty
|
||||||
|
*
|
||||||
|
* @param dev The Ecore_Drm_Device which owns this tty.
|
||||||
|
*
|
||||||
|
* @return EINA_TRUE on success, EINA_FALSE on failure
|
||||||
|
*
|
||||||
|
* @ingroup Ecore_Drm_Tty_Group
|
||||||
|
*/
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_tty_close(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
/* check for valid device */
|
||||||
|
if ((!dev) || (!dev->drm.name)) return EINA_FALSE;
|
||||||
|
|
||||||
|
close(dev->tty.fd);
|
||||||
|
|
||||||
|
dev->tty.fd = -1;
|
||||||
|
|
||||||
|
/* destroy the event handler */
|
||||||
|
if (dev->tty.event_hdlr) ecore_event_handler_del(dev->tty.event_hdlr);
|
||||||
|
dev->tty.event_hdlr = NULL;
|
||||||
|
|
||||||
|
/* clear the tty name */
|
||||||
|
if (dev->tty.name) eina_stringshare_del(dev->tty.name);
|
||||||
|
dev->tty.name = NULL;
|
||||||
|
|
||||||
|
unsetenv("ECORE_DRM_TTY");
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release a virtual terminal
|
||||||
|
*
|
||||||
|
* @param dev The Ecore_Drm_Device which owns this tty.
|
||||||
|
*
|
||||||
|
* @return EINA_TRUE on success, EINA_FALSE on failure
|
||||||
|
*
|
||||||
|
* @ingroup Ecore_Drm_Tty_Group
|
||||||
|
*/
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_tty_release(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
/* check for valid device */
|
||||||
|
if ((!dev) || (!dev->drm.name) || (dev->tty.fd < 0)) return EINA_FALSE;
|
||||||
|
|
||||||
|
/* send ioctl for vt release */
|
||||||
|
if (ioctl(dev->tty.fd, VT_RELDISP, 1) < 0) return EINA_FALSE;
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acquire a virtual terminal
|
||||||
|
*
|
||||||
|
* @param dev The Ecore_Drm_Device which owns this tty.
|
||||||
|
*
|
||||||
|
* @return EINA_TRUE on success, EINA_FALSE on failure
|
||||||
|
*
|
||||||
|
* @ingroup Ecore_Drm_Tty_Group
|
||||||
|
*/
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_tty_acquire(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
/* check for valid device */
|
||||||
|
if ((!dev) || (!dev->drm.name) || (dev->tty.fd < 0)) return EINA_FALSE;
|
||||||
|
|
||||||
|
/* send ioctl for vt acquire */
|
||||||
|
if (ioctl(dev->tty.fd, VT_RELDISP, VT_ACKACQ) < 0) return EINA_FALSE;
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
|
@ -253,6 +253,12 @@ _ecore_evas_available_engines_get(void)
|
||||||
#endif
|
#endif
|
||||||
#ifdef BUILD_ECORE_EVAS_OPENGL_GLEW
|
#ifdef BUILD_ECORE_EVAS_OPENGL_GLEW
|
||||||
ADDENG("opengl_glew");
|
ADDENG("opengl_glew");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (!strcmp(name, "drm"))
|
||||||
|
{
|
||||||
|
#ifdef BUILD_ECORE_EVAS_DRM
|
||||||
|
ADDENG("drm");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <Eina.h>
|
#include <Eina.h>
|
||||||
#include <Ecore.h>
|
#include <Ecore.h>
|
||||||
|
@ -16,12 +17,19 @@
|
||||||
|
|
||||||
#ifdef BUILD_ECORE_EVAS_DRM
|
#ifdef BUILD_ECORE_EVAS_DRM
|
||||||
# include <Evas_Engine_Drm.h>
|
# include <Evas_Engine_Drm.h>
|
||||||
|
# include <Ecore_Drm.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* local structures */
|
#undef ERR
|
||||||
typedef struct _Ecore_Evas_Engine_Data_Drm Ecore_Evas_Engine_Data_Drm;
|
#define ERR(...) fprintf(stderr, __VA_ARGS__)
|
||||||
|
|
||||||
struct _Ecore_Evas_Engine_Data_Drm
|
#undef DBG
|
||||||
|
#define DBG(...) fprintf(stderr, __VA_ARGS__)
|
||||||
|
|
||||||
|
/* local structures */
|
||||||
|
typedef struct _Ecore_Evas_Engine_Drm_Data Ecore_Evas_Engine_Drm_Data;
|
||||||
|
|
||||||
|
struct _Ecore_Evas_Engine_Drm_Data
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
};
|
};
|
||||||
|
@ -31,8 +39,13 @@ static int _ecore_evas_drm_init(void);
|
||||||
static int _ecore_evas_drm_shutdown(void);
|
static int _ecore_evas_drm_shutdown(void);
|
||||||
static Ecore_Evas_Interface_Drm *_ecore_evas_drm_interface_new(void);
|
static Ecore_Evas_Interface_Drm *_ecore_evas_drm_interface_new(void);
|
||||||
|
|
||||||
|
static void _ecore_evas_show(Ecore_Evas *ee);
|
||||||
|
static void _ecore_evas_render_updates(void *data, Evas *evas EINA_UNUSED, void *event);
|
||||||
|
static int _ecore_evas_render(Ecore_Evas *ee);
|
||||||
|
|
||||||
/* local variables */
|
/* local variables */
|
||||||
static int _ecore_evas_init_count = 0;
|
static int _ecore_evas_init_count = 0;
|
||||||
|
static Ecore_Drm_Device *dev = NULL;
|
||||||
|
|
||||||
static Ecore_Evas_Engine_Func _ecore_evas_drm_engine_func =
|
static Ecore_Evas_Engine_Func _ecore_evas_drm_engine_func =
|
||||||
{
|
{
|
||||||
|
@ -57,7 +70,7 @@ static Ecore_Evas_Engine_Func _ecore_evas_drm_engine_func =
|
||||||
NULL, //void (*fn_move_resize) (Ecore_Evas *ee, int x, int y, int w, int h);
|
NULL, //void (*fn_move_resize) (Ecore_Evas *ee, int x, int y, int w, int h);
|
||||||
NULL, //void (*fn_rotation_set) (Ecore_Evas *ee, int rot, int resize);
|
NULL, //void (*fn_rotation_set) (Ecore_Evas *ee, int rot, int resize);
|
||||||
NULL, //void (*fn_shaped_set) (Ecore_Evas *ee, int shaped);
|
NULL, //void (*fn_shaped_set) (Ecore_Evas *ee, int shaped);
|
||||||
NULL, //void (*fn_show) (Ecore_Evas *ee);
|
_ecore_evas_show,
|
||||||
NULL, //void (*fn_hide) (Ecore_Evas *ee);
|
NULL, //void (*fn_hide) (Ecore_Evas *ee);
|
||||||
NULL, //void (*fn_raise) (Ecore_Evas *ee);
|
NULL, //void (*fn_raise) (Ecore_Evas *ee);
|
||||||
NULL, //void (*fn_lower) (Ecore_Evas *ee);
|
NULL, //void (*fn_lower) (Ecore_Evas *ee);
|
||||||
|
@ -92,7 +105,8 @@ static Ecore_Evas_Engine_Func _ecore_evas_drm_engine_func =
|
||||||
NULL, //void (*fn_demands_attention_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);
|
NULL, //void (*fn_focus_skip_set) (Ecore_Evas *ee, Eina_Bool on);
|
||||||
|
|
||||||
NULL, //int (*fn_render) (Ecore_Evas *ee);
|
_ecore_evas_render,
|
||||||
|
|
||||||
NULL, //void (*fn_screen_geometry_get) (const Ecore_Evas *ee, int *x, int *y, int *w, int *h);
|
NULL, //void (*fn_screen_geometry_get) (const Ecore_Evas *ee, int *x, int *y, int *w, int *h);
|
||||||
NULL, //void (*fn_screen_dpi_get) (const Ecore_Evas *ee, int *xdpi, int *ydpi);
|
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_parent_send) (Ecore_Evas *ee, int maj, int min, void *data, int size);
|
||||||
|
@ -103,6 +117,8 @@ EAPI Ecore_Evas *
|
||||||
ecore_evas_drm_new_internal(const char *device, unsigned int parent, int x, int y, int w, int h)
|
ecore_evas_drm_new_internal(const char *device, unsigned int parent, int x, int y, int w, int h)
|
||||||
{
|
{
|
||||||
Ecore_Evas *ee;
|
Ecore_Evas *ee;
|
||||||
|
Evas_Engine_Info_Drm *einfo;
|
||||||
|
Ecore_Evas_Interface_Drm *iface;
|
||||||
int method;
|
int method;
|
||||||
|
|
||||||
/* try to find the evas drm engine */
|
/* try to find the evas drm engine */
|
||||||
|
@ -112,36 +128,303 @@ ecore_evas_drm_new_internal(const char *device, unsigned int parent, int x, int
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* try to init drm and company */
|
||||||
|
if (_ecore_evas_drm_init() < 1) return NULL;
|
||||||
|
|
||||||
|
/* try to allocate space for Ecore_Evas structure */
|
||||||
if (!(ee = calloc(1, sizeof(Ecore_Evas))))
|
if (!(ee = calloc(1, sizeof(Ecore_Evas))))
|
||||||
{
|
{
|
||||||
ERR("Failed to allocate space for new Ecore_Evas");
|
ERR("Failed to allocate space for new Ecore_Evas");
|
||||||
return NULL;
|
goto ee_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* FIXME: STORE Ecore_Drm_Dev in engine somewhere ?? */
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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->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);
|
||||||
|
|
||||||
|
/* FIXME: Support initial rotation ?? */
|
||||||
|
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_render_updates, ee);
|
||||||
|
|
||||||
|
if ((einfo = (Evas_Engine_Info_Drm *)evas_engine_info_get(ee->evas)))
|
||||||
|
{
|
||||||
|
einfo->info.depth = 32; // FIXME
|
||||||
|
einfo->info.destination_alpha = ee->alpha;
|
||||||
|
einfo->info.rotation = ee->rotation;
|
||||||
|
einfo->info.fd = ecore_drm_device_fd_get(dev);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ecore_evas_register(ee);
|
||||||
|
ecore_evas_input_event_register(ee);
|
||||||
|
|
||||||
return ee;
|
return ee;
|
||||||
|
|
||||||
|
eng_err:
|
||||||
|
ecore_evas_free(ee);
|
||||||
|
ee_err:
|
||||||
|
_ecore_evas_drm_shutdown();
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* local functions */
|
/* local functions */
|
||||||
static int
|
static int
|
||||||
_ecore_evas_drm_init(void)
|
_ecore_evas_drm_init(void)
|
||||||
{
|
{
|
||||||
_ecore_evas_init_count++;
|
if (++_ecore_evas_init_count != 1)
|
||||||
if (_ecore_evas_init_count > 1) return _ecore_evas_init_count;
|
return _ecore_evas_init_count;
|
||||||
|
|
||||||
|
/* try to init ecore_drm */
|
||||||
|
if (!ecore_drm_init())
|
||||||
|
{
|
||||||
|
ERR("Could not initialize Ecore_Drm");
|
||||||
|
return --_ecore_evas_init_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* try to find the device */
|
||||||
|
if (!(dev = ecore_drm_device_find(NULL, NULL)))
|
||||||
|
{
|
||||||
|
ERR("Could not find default drm device");
|
||||||
|
goto dev_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* try to open the graphics card */
|
||||||
|
if (!ecore_drm_device_open(dev))
|
||||||
|
{
|
||||||
|
ERR("Could not open drm device");
|
||||||
|
goto dev_open_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* try to open the tty */
|
||||||
|
if (!ecore_drm_tty_open(dev, NULL))
|
||||||
|
{
|
||||||
|
ERR("Could not open tty: %m");
|
||||||
|
goto tty_open_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: Init egl/software renderer here ?? */
|
||||||
|
|
||||||
|
/* try to create sprites */
|
||||||
|
if (!ecore_drm_sprites_create(dev))
|
||||||
|
{
|
||||||
|
ERR("Could not create sprites: %m");
|
||||||
|
goto sprite_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* try to create outputs */
|
||||||
|
if (!ecore_drm_outputs_create(dev))
|
||||||
|
{
|
||||||
|
ERR("Could not create outputs: %m");
|
||||||
|
goto output_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* try to create inputs */
|
||||||
|
if (!ecore_drm_inputs_create(dev))
|
||||||
|
{
|
||||||
|
ERR("Could not create inputs: %m");
|
||||||
|
goto output_err;
|
||||||
|
}
|
||||||
|
|
||||||
ecore_event_evas_init();
|
ecore_event_evas_init();
|
||||||
|
|
||||||
return _ecore_evas_init_count;
|
return _ecore_evas_init_count;
|
||||||
|
|
||||||
|
output_err:
|
||||||
|
ecore_drm_sprites_destroy(dev);
|
||||||
|
sprite_err:
|
||||||
|
ecore_drm_tty_close(dev);
|
||||||
|
tty_open_err:
|
||||||
|
ecore_drm_device_close(dev);
|
||||||
|
dev_open_err:
|
||||||
|
ecore_drm_device_free(dev);
|
||||||
|
dev_err:
|
||||||
|
ecore_drm_shutdown();
|
||||||
|
return --_ecore_evas_init_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_ecore_evas_drm_shutdown(void)
|
_ecore_evas_drm_shutdown(void)
|
||||||
{
|
{
|
||||||
_ecore_evas_init_count--;
|
if (--_ecore_evas_init_count != 0)
|
||||||
if (_ecore_evas_init_count == 0)
|
return _ecore_evas_init_count;
|
||||||
{
|
|
||||||
ecore_event_evas_shutdown();
|
ecore_drm_sprites_destroy(dev);
|
||||||
}
|
/* NB: No need to free outputs here. Is done in device free */
|
||||||
|
ecore_drm_inputs_destroy(dev);
|
||||||
|
ecore_drm_tty_close(dev);
|
||||||
|
ecore_drm_device_close(dev);
|
||||||
|
ecore_drm_device_free(dev);
|
||||||
|
ecore_drm_shutdown();
|
||||||
|
|
||||||
|
ecore_event_evas_shutdown();
|
||||||
|
|
||||||
if (_ecore_evas_init_count < 0) _ecore_evas_init_count = 0;
|
|
||||||
return _ecore_evas_init_count;
|
return _ecore_evas_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;
|
||||||
|
|
||||||
|
/* iface->pixmap_visual_get; */
|
||||||
|
/* iface->pixmap_colormap_get; */
|
||||||
|
/* iface->pixmap_depth_get; */
|
||||||
|
|
||||||
|
return iface;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_ecore_evas_show(Ecore_Evas *ee)
|
||||||
|
{
|
||||||
|
if ((!ee) || (ee->visible)) return;
|
||||||
|
DBG("Show Ecore_Evas\n");
|
||||||
|
/* TODO: fixme */
|
||||||
|
evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
|
||||||
|
ee->visible = 1;
|
||||||
|
if (ee->func.fn_show) ee->func.fn_show(ee);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_ecore_evas_render_updates_process(Ecore_Evas *ee, Eina_List *updates)
|
||||||
|
{
|
||||||
|
int rend = 0;
|
||||||
|
|
||||||
|
DBG("\tRender Updates Process\n");
|
||||||
|
if ((ee->visible) && (updates))
|
||||||
|
{
|
||||||
|
Eina_List *l;
|
||||||
|
Eina_Rectangle *r;
|
||||||
|
|
||||||
|
EINA_LIST_FOREACH(updates, l, r)
|
||||||
|
{
|
||||||
|
/* TODO: damage window */
|
||||||
|
DBG("\t\tDamage Window: %d %d %d %d\n", r->x, r->y, r->w, r->h);
|
||||||
|
}
|
||||||
|
|
||||||
|
_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_render_updates(void *data, Evas *evas EINA_UNUSED, void *event)
|
||||||
|
{
|
||||||
|
Ecore_Evas *ee;
|
||||||
|
Evas_Event_Render_Post *ev;
|
||||||
|
|
||||||
|
if (!(ev = event)) return;
|
||||||
|
if (!(ee = data)) return;
|
||||||
|
|
||||||
|
ee->in_async_render = EINA_FALSE;
|
||||||
|
|
||||||
|
_ecore_evas_render_updates_process(ee, ev->updated_area);
|
||||||
|
|
||||||
|
/* TODO: handle delayed setting */
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_ecore_evas_render(Ecore_Evas *ee)
|
||||||
|
{
|
||||||
|
int rend = 0;
|
||||||
|
Eina_List *l;
|
||||||
|
Ecore_Evas *ee2;
|
||||||
|
|
||||||
|
if (!ee) return 0;
|
||||||
|
|
||||||
|
if (ee->in_async_render) return 0;
|
||||||
|
|
||||||
|
if (!ee->visible)
|
||||||
|
{
|
||||||
|
evas_norender(ee->evas);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DBG("Render Ecore_Evas\n"); */
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
if ((updates = evas_render_updates(ee->evas)))
|
||||||
|
{
|
||||||
|
rend = _ecore_evas_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;
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,10 @@ struct _Evas_Engine_Info_Drm
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
void *gbm;
|
||||||
|
unsigned int format;
|
||||||
|
int fd;
|
||||||
|
|
||||||
unsigned int rotation, depth;
|
unsigned int rotation, depth;
|
||||||
Eina_Bool destination_alpha : 1;
|
Eina_Bool destination_alpha : 1;
|
||||||
} info;
|
} info;
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "evas_engine.h"
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
static int _init_count = 0;
|
||||||
|
|
||||||
|
/* the actual Manager device returned from init of the library */
|
||||||
|
static void *bufmgr;
|
||||||
|
|
||||||
|
/* the actual library we successfully dlopen'd */
|
||||||
|
static void *libbufmgr;
|
||||||
|
|
||||||
|
/* pointers to library functions that we need */
|
||||||
|
void *(*libbufmgr_init)(int fd);
|
||||||
|
void (*libbufmgr_shutdown)(void *mgr);
|
||||||
|
|
||||||
|
//void *(*libbufmgr_buffer_create)(void *mgr);
|
||||||
|
|
||||||
|
int
|
||||||
|
evas_buffer_manager_init(void)
|
||||||
|
{
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
if (++_init_count != 1) return _init_count;
|
||||||
|
|
||||||
|
/* try to dlopen various buffer managers until we find one that works
|
||||||
|
* (libgbm, libtbm, etc)
|
||||||
|
*
|
||||||
|
* NB: as I am testing this on desktop and do not have libtbm, I am
|
||||||
|
* just going to code for that. Feel free to hack in libtbm support */
|
||||||
|
libbufmgr = dlopen("libgbm.so", (RTLD_LAZY | RTLD_GLOBAL));
|
||||||
|
if (!libbufmgr)
|
||||||
|
libbufmgr = dlopen("libgbm.so.1", (RTLD_LAZY | RTLD_GLOBAL));
|
||||||
|
if (!libbufmgr)
|
||||||
|
libbufmgr = dlopen("libgbm.so.1.0.0", (RTLD_LAZY | RTLD_GLOBAL));
|
||||||
|
if (!libbufmgr) return --_init_count;
|
||||||
|
|
||||||
|
/* with the library found, symlink the functions we need */
|
||||||
|
libbufmgr_init = dlsym(libbufmgr, "gbm_create_device");
|
||||||
|
libbufmgr_shutdown = dlsym(libbufmgr, "gbm_device_destroy");
|
||||||
|
|
||||||
|
return _init_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
evas_buffer_manager_shutdown(void)
|
||||||
|
{
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
if (--_init_count != 0) return _init_count;
|
||||||
|
|
||||||
|
/* call function to shutdown the manager */
|
||||||
|
evas_buffer_manager_close();
|
||||||
|
}
|
||||||
|
|
||||||
|
Eina_Bool
|
||||||
|
evas_buffer_manager_open(int fd)
|
||||||
|
{
|
||||||
|
Eina_Bool ret = EINA_FALSE;
|
||||||
|
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
if (bufmgr) return EINA_TRUE;
|
||||||
|
|
||||||
|
/* call any init functions required by the dlsym'd buffer manager */
|
||||||
|
if (libbufmgr_init)
|
||||||
|
{
|
||||||
|
if ((bufmgr = libbufmgr_init(fd)))
|
||||||
|
ret = EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
evas_buffer_manager_close(void)
|
||||||
|
{
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
/* call any shutdown functions required by the dlsym'd buffer manager */
|
||||||
|
if (libbufmgr_shutdown)
|
||||||
|
libbufmgr_shutdown(bufmgr);
|
||||||
|
|
||||||
|
bufmgr = NULL;
|
||||||
|
}
|
|
@ -1,6 +1,3 @@
|
||||||
#include "evas_common_private.h"
|
|
||||||
#include "evas_private.h"
|
|
||||||
#include "Evas_Engine_Drm.h"
|
|
||||||
#include "evas_engine.h"
|
#include "evas_engine.h"
|
||||||
|
|
||||||
/* local structures */
|
/* local structures */
|
||||||
|
@ -9,112 +6,207 @@ typedef struct _Render_Engine Render_Engine;
|
||||||
struct _Render_Engine
|
struct _Render_Engine
|
||||||
{
|
{
|
||||||
Evas_Engine_Info_Drm *info;
|
Evas_Engine_Info_Drm *info;
|
||||||
|
Outbuf *ob;
|
||||||
Tilebuf *tb;
|
Tilebuf *tb;
|
||||||
|
|
||||||
Tilebuf_Rect *rects;
|
Tilebuf_Rect *rects;
|
||||||
Tilebuf_Rect *prev_rects[3];
|
Tilebuf_Rect *prev_rects[3];
|
||||||
|
Eina_Inlist *cur_rect;
|
||||||
Outbuf *ob;
|
|
||||||
|
|
||||||
short mode;
|
short mode;
|
||||||
|
|
||||||
Eina_Inlist *cur_rect;
|
|
||||||
|
|
||||||
Eina_Bool end : 1;
|
Eina_Bool end : 1;
|
||||||
Eina_Bool lost_back : 1;
|
Eina_Bool lost_back : 1;
|
||||||
|
|
||||||
|
/* function pointers for output buffer functions that we can
|
||||||
|
* override based on if we are swapping or not */
|
||||||
|
void (*outbuf_free)(Outbuf *ob);
|
||||||
|
void (*outbuf_reconfigure)(Outbuf *ob, int x, int y, int w, int h, unsigned int rotation, Outbuf_Depth depth, Eina_Bool alpha);
|
||||||
|
RGBA_Image *(*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);
|
||||||
|
void (*outbuf_idle_flush)(Outbuf *ob);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* local function prototypes */
|
/* local function prototypes */
|
||||||
static void *_output_setup(int w, int h, unsigned int rotation, unsigned int depth, Eina_Bool alpha, int swap);
|
static void *_output_engine_setup(int w, int h, unsigned int rotation, unsigned int depth, Eina_Bool destination_alpha, int fd, int try_swap);
|
||||||
|
static Tilebuf_Rect *_merge_rects(Tilebuf *tb, Tilebuf_Rect *r1, Tilebuf_Rect *r2, Tilebuf_Rect *r3);
|
||||||
|
|
||||||
/* function tables - filled in later (func and parent func) */
|
/* engine function prototypes */
|
||||||
|
static void *eng_info(Evas *eo_evas EINA_UNUSED);
|
||||||
|
static void eng_info_free(Evas *eo_evas EINA_UNUSED, void *einfo);
|
||||||
|
static int eng_setup(Evas *eo_evas, void *einfo);
|
||||||
|
static void eng_output_free(void *data);
|
||||||
|
static void eng_output_resize(void *data, int w, int h);
|
||||||
|
static void eng_output_tile_size_set(void *data, int w, int h);
|
||||||
|
static void eng_output_redraws_rect_add(void *data, int x, int y, int w, int h);
|
||||||
|
static void eng_output_redraws_rect_del(void *data, int x, int y, int w, int h);
|
||||||
|
static void eng_output_redraws_clear(void *data);
|
||||||
|
static void *eng_output_redraws_next_update_get(void *data, int *x, int *y, int *w, int *h, int *cx, int *cy, int *cw, int *ch);
|
||||||
|
static void eng_output_redraws_next_update_push(void *data, void *surface, int x, int y, int w, int h, Evas_Render_Mode render_mode);
|
||||||
|
static void eng_output_flush(void *data, Evas_Render_Mode render_mode);
|
||||||
|
static void eng_output_idle_flush(void *data);
|
||||||
|
|
||||||
|
/* local variables */
|
||||||
static Evas_Func func, pfunc;
|
static Evas_Func func, pfunc;
|
||||||
|
|
||||||
/* external variables */
|
/* external variables */
|
||||||
int _evas_engine_drm_log_dom;
|
int _evas_engine_drm_log_dom = -1;
|
||||||
|
|
||||||
/* local functions */
|
/* local functions */
|
||||||
static void *
|
static void *
|
||||||
_output_setup(int w, int h, unsigned int rotation, unsigned int depth, Eina_Bool alpha, int swap)
|
_output_engine_setup(int w, int h, unsigned int rotation, unsigned int depth, Eina_Bool destination_alpha, int fd, int try_swap)
|
||||||
{
|
{
|
||||||
Render_Engine *re;
|
Render_Engine *re = NULL;
|
||||||
|
|
||||||
/* try to allocate space for our render engine structure */
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
/* try to allocate a new render engine */
|
||||||
if (!(re = calloc(1, sizeof(Render_Engine))))
|
if (!(re = calloc(1, sizeof(Render_Engine))))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* try to create a new tilebuffer */
|
/* try to create a new tilebuf first */
|
||||||
if (!(re->tb = evas_common_tilebuf_new(w, h)))
|
if (!(re->tb = evas_common_tilebuf_new(w, h)))
|
||||||
{
|
{
|
||||||
free(re);
|
free(re);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set tilesize */
|
/* set tile size for the tile buffer */
|
||||||
evas_common_tilebuf_set_tile_size(re->tb, TILESIZE, TILESIZE);
|
evas_common_tilebuf_set_tile_size(re->tb, TILESIZE, TILESIZE);
|
||||||
|
|
||||||
if (swap)
|
if (try_swap)
|
||||||
{
|
{
|
||||||
/* free any existing outbuf */
|
if ((re->ob = evas_swapbuf_setup(w, h, rotation, depth,
|
||||||
if (re->ob) evas_outbuf_free(re->ob);
|
destination_alpha, fd)))
|
||||||
|
|
||||||
/* try to create new outbuf */
|
|
||||||
if (!(re->ob = evas_outbuf_setup(w, h, rotation, depth, alpha)))
|
|
||||||
{
|
{
|
||||||
if (re->tb) evas_common_tilebuf_free(re->tb);
|
re->outbuf_free = evas_swapbuf_free;
|
||||||
free(re);
|
re->outbuf_reconfigure = evas_swapbuf_reconfigure;
|
||||||
return NULL;
|
re->outbuf_update_region_new = evas_swapbuf_update_region_new;
|
||||||
|
re->outbuf_update_region_push = evas_swapbuf_update_region_push;
|
||||||
|
re->outbuf_update_region_free = evas_swapbuf_update_region_free;
|
||||||
|
re->outbuf_flush = evas_swapbuf_flush;
|
||||||
|
re->outbuf_idle_flush = evas_swapbuf_idle_flush;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return the allocated render_engine structure */
|
/* if creating an output buffer failed, then return NULL */
|
||||||
|
if (!re->ob)
|
||||||
|
{
|
||||||
|
if (re->tb) evas_common_tilebuf_free(re->tb);
|
||||||
|
free(re);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return allocated render engine */
|
||||||
return re;
|
return re;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* engine api functions */
|
static Tilebuf_Rect *
|
||||||
|
_merge_rects(Tilebuf *tb, Tilebuf_Rect *r1, Tilebuf_Rect *r2, Tilebuf_Rect *r3)
|
||||||
|
{
|
||||||
|
Tilebuf_Rect *r, *rects;
|
||||||
|
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
if (r1)
|
||||||
|
{
|
||||||
|
EINA_INLIST_FOREACH(EINA_INLIST_GET(r1), r)
|
||||||
|
evas_common_tilebuf_add_redraw(tb, r->x, r->y, r->w, r->h);
|
||||||
|
}
|
||||||
|
if (r2)
|
||||||
|
{
|
||||||
|
EINA_INLIST_FOREACH(EINA_INLIST_GET(r2), r)
|
||||||
|
evas_common_tilebuf_add_redraw(tb, r->x, r->y, r->w, r->h);
|
||||||
|
}
|
||||||
|
if (r3)
|
||||||
|
{
|
||||||
|
EINA_INLIST_FOREACH(EINA_INLIST_GET(r3), r)
|
||||||
|
evas_common_tilebuf_add_redraw(tb, r->x, r->y, r->w, r->h);
|
||||||
|
}
|
||||||
|
rects = evas_common_tilebuf_get_render_rects(tb);
|
||||||
|
|
||||||
|
/*
|
||||||
|
// bounding box -> make a bounding box single region update of all regions.
|
||||||
|
// yes we could try and be smart and figure out size of regions, how far
|
||||||
|
// apart etc. etc. to try and figure out an optimal "set". this is a tradeoff
|
||||||
|
// between multiple update regions to render and total pixels to render.
|
||||||
|
if (rects)
|
||||||
|
{
|
||||||
|
px1 = rects->x; py1 = rects->y;
|
||||||
|
px2 = rects->x + rects->w; py2 = rects->y + rects->h;
|
||||||
|
EINA_INLIST_FOREACH(EINA_INLIST_GET(rects), r)
|
||||||
|
{
|
||||||
|
if (r->x < x1) px1 = r->x;
|
||||||
|
if (r->y < y1) py1 = r->y;
|
||||||
|
if ((r->x + r->w) > x2) px2 = r->x + r->w;
|
||||||
|
if ((r->y + r->h) > y2) py2 = r->y + r->h;
|
||||||
|
}
|
||||||
|
evas_common_tilebuf_free_render_rects(rects);
|
||||||
|
rects = calloc(1, sizeof(Tilebuf_Rect));
|
||||||
|
if (rects)
|
||||||
|
{
|
||||||
|
rects->x = px1;
|
||||||
|
rects->y = py1;
|
||||||
|
rects->w = px2 - px1;
|
||||||
|
rects->h = py2 - py1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
evas_common_tilebuf_clear(tb);
|
||||||
|
return rects;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* engine functions */
|
||||||
static void *
|
static void *
|
||||||
eng_info(Evas *evas EINA_UNUSED)
|
eng_info(Evas *eo_evas EINA_UNUSED)
|
||||||
{
|
{
|
||||||
Evas_Engine_Info_Drm *info;
|
Evas_Engine_Info_Drm *info;
|
||||||
|
|
||||||
/* try to allocate space for our engine info structure */
|
/* try to allocate space for engine info */
|
||||||
if (!(info = calloc(1, sizeof(Evas_Engine_Info_Drm))))
|
if (!(info = calloc(1, sizeof(Evas_Engine_Info_Drm))))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* set some engine default properties */
|
/* fill in default engine info fields */
|
||||||
info->magic.magic = rand();
|
info->magic.magic = rand();
|
||||||
info->render_mode = EVAS_RENDER_MODE_BLOCKING;
|
info->render_mode = EVAS_RENDER_MODE_BLOCKING;
|
||||||
|
|
||||||
|
/* return allocated engine info */
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
eng_info_free(Evas *evas EINA_UNUSED, void *einfo)
|
eng_info_free(Evas *eo_evas EINA_UNUSED, void *einfo)
|
||||||
{
|
{
|
||||||
Evas_Engine_Info_Drm *info;
|
Evas_Engine_Info_Drm *info;
|
||||||
|
|
||||||
/* free the engine info */
|
/* try to free previously allocated engine info */
|
||||||
if ((info = (Evas_Engine_Info_Drm *)einfo))
|
if ((info = (Evas_Engine_Info_Drm *)einfo))
|
||||||
free(info);
|
free(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
eng_setup(Evas *evas, void *einfo)
|
eng_setup(Evas *eo_evas, void *einfo)
|
||||||
{
|
{
|
||||||
Evas_Engine_Info_Drm *info;
|
Evas_Engine_Info_Drm *info;
|
||||||
Evas_Public_Data *epd;
|
Evas_Public_Data *epd;
|
||||||
Render_Engine *re;
|
Render_Engine *re = NULL;
|
||||||
|
|
||||||
/* try to cast to our engine info structure */
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
if (!(info = (Evas_Engine_Info_Drm *)einfo)) return 0;
|
|
||||||
|
|
||||||
/* try to get the evas public data */
|
/* try to cast the engine info to our engine info */
|
||||||
if (!(epd = eo_data_scope_get(evas, EVAS_CLASS))) return 0;
|
if (!(info = (Evas_Engine_Info_Drm *)einfo))
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* check for valid engine output */
|
/* try to get evas public data from the canvas */
|
||||||
|
if (!(epd = eo_data_scope_get(eo_evas, EVAS_CLASS)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* test for valid engine output */
|
||||||
if (!(re = epd->engine.data.output))
|
if (!(re = epd->engine.data.output))
|
||||||
{
|
{
|
||||||
static int swap = -1;
|
static int try_swap = -1;
|
||||||
|
|
||||||
/* NB: If we have no valid output then assume we have not been
|
/* NB: If we have no valid output then assume we have not been
|
||||||
* initialized yet and call any needed common init routines */
|
* initialized yet and call any needed common init routines */
|
||||||
|
@ -130,47 +222,74 @@ eng_setup(Evas *evas, void *einfo)
|
||||||
evas_common_draw_init();
|
evas_common_draw_init();
|
||||||
evas_common_tilebuf_init();
|
evas_common_tilebuf_init();
|
||||||
|
|
||||||
/* check if swapping is disabled */
|
if (try_swap == -1)
|
||||||
if (swap == -1)
|
|
||||||
{
|
{
|
||||||
if (getenv("EVAS_DRM_NO_SWAP")) swap = 0;
|
/* check for env var to see if we should try swapping */
|
||||||
else swap = 1;
|
if (getenv("EVAS_NO_DRM_SWAPBUF")) try_swap = 0;
|
||||||
|
else try_swap = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* try to create a new render_engine */
|
/* ensure the buffer manager has been opened */
|
||||||
if (!(re = _output_setup(epd->output.w, epd->output.h,
|
if (!evas_buffer_manager_open(info->info.fd))
|
||||||
info->info.rotation, info->info.depth,
|
{
|
||||||
info->info.destination_alpha, swap)))
|
fprintf(stderr, "COULD NOT OPEN BUFFER MANAGER !!!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(re =
|
||||||
|
_output_engine_setup(epd->output.w, epd->output.h,
|
||||||
|
info->info.rotation, info->info.depth,
|
||||||
|
info->info.destination_alpha,
|
||||||
|
info->info.fd, try_swap)))
|
||||||
return 0;
|
return 0;
|
||||||
|
re->info = info;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* if we have an existing outbuf, free it */
|
int ponebuf = 0;
|
||||||
if (re->ob) evas_outbuf_free(re->ob);
|
|
||||||
|
|
||||||
/* try to create a new outbuf */
|
if ((re) && (re->ob)) ponebuf = re->ob->onebuf;
|
||||||
if (!(re->ob =
|
|
||||||
evas_outbuf_setup(epd->output.w, epd->output.h,
|
/* free any existing tile buffer */
|
||||||
info->info.rotation, info->info.depth,
|
if (re->tb) evas_common_tilebuf_free(re->tb);
|
||||||
info->info.destination_alpha)))
|
|
||||||
return 0;
|
/* we have an existing output buffer, free it */
|
||||||
|
if (re->ob) re->outbuf_free(re->ob);
|
||||||
|
|
||||||
|
/* create new tile buffer */
|
||||||
|
if ((re->tb = evas_common_tilebuf_new(epd->output.w, epd->output.h)))
|
||||||
|
evas_common_tilebuf_set_tile_size(re->tb, TILESIZE, TILESIZE);
|
||||||
|
|
||||||
|
if ((re->ob = evas_swapbuf_setup(epd->output.w, epd->output.h,
|
||||||
|
info->info.rotation,
|
||||||
|
info->info.depth,
|
||||||
|
info->info.destination_alpha,
|
||||||
|
info->info.fd)))
|
||||||
|
{
|
||||||
|
re->outbuf_free = evas_swapbuf_free;
|
||||||
|
re->outbuf_reconfigure = evas_swapbuf_reconfigure;
|
||||||
|
re->outbuf_update_region_new = evas_swapbuf_update_region_new;
|
||||||
|
re->outbuf_update_region_push = evas_swapbuf_update_region_push;
|
||||||
|
re->outbuf_update_region_free = evas_swapbuf_update_region_free;
|
||||||
|
re->outbuf_flush = evas_swapbuf_flush;
|
||||||
|
re->outbuf_idle_flush = evas_swapbuf_idle_flush;
|
||||||
|
}
|
||||||
|
|
||||||
|
re->info = info;
|
||||||
|
if ((re) && (re->ob)) re->ob->onebuf = ponebuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* update the info structure pointer */
|
/* reassign render engine to output */
|
||||||
re->info = info;
|
|
||||||
|
|
||||||
/* reassign engine output */
|
|
||||||
epd->engine.data.output = re;
|
epd->engine.data.output = re;
|
||||||
if (!epd->engine.data.output) return 0;
|
if (!epd->engine.data.output) return 0;
|
||||||
|
|
||||||
/* check for valid engine context */
|
|
||||||
if (!epd->engine.data.context)
|
if (!epd->engine.data.context)
|
||||||
{
|
{
|
||||||
/* create a context if needed */
|
|
||||||
epd->engine.data.context =
|
epd->engine.data.context =
|
||||||
epd->engine.func->context_new(epd->engine.data.output);
|
epd->engine.func->context_new(epd->engine.data.output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* return success */
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,11 +298,14 @@ eng_output_free(void *data)
|
||||||
{
|
{
|
||||||
Render_Engine *re;
|
Render_Engine *re;
|
||||||
|
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
if ((re = data))
|
if ((re = data))
|
||||||
{
|
{
|
||||||
if (re->ob) evas_outbuf_free(re->ob);
|
re->outbuf_free(re->ob);
|
||||||
if (re->tb) evas_common_tilebuf_free(re->tb);
|
evas_common_tilebuf_free(re->tb);
|
||||||
if (re->rects) evas_common_tilebuf_free_render_rects(re->rects);
|
if (re->rects)
|
||||||
|
evas_common_tilebuf_free_render_rects(re->rects);
|
||||||
if (re->prev_rects[0])
|
if (re->prev_rects[0])
|
||||||
evas_common_tilebuf_free_render_rects(re->prev_rects[0]);
|
evas_common_tilebuf_free_render_rects(re->prev_rects[0]);
|
||||||
if (re->prev_rects[1])
|
if (re->prev_rects[1])
|
||||||
|
@ -197,52 +319,311 @@ eng_output_free(void *data)
|
||||||
evas_common_image_shutdown();
|
evas_common_image_shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* module api functions */
|
static void
|
||||||
|
eng_output_resize(void *data, int w, int h)
|
||||||
|
{
|
||||||
|
Render_Engine *re;
|
||||||
|
Evas_Engine_Info_Drm *info;
|
||||||
|
/* int dx = 0, dy = 0; */
|
||||||
|
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
if (!(re = (Render_Engine *)data)) return;
|
||||||
|
|
||||||
|
if (!(info = re->info)) return;
|
||||||
|
|
||||||
|
/* if (info->info.edges & 4) */
|
||||||
|
/* { */
|
||||||
|
/* if ((info->info.rotation == 90) || (info->info.rotation == 270)) */
|
||||||
|
/* dx = re->ob->h - h; */
|
||||||
|
/* else */
|
||||||
|
/* dx = re->ob->w - w; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* if (info->info.edges & 1) */
|
||||||
|
/* { */
|
||||||
|
/* if ((info->info.rotation == 90) || (info->info.rotation == 270)) */
|
||||||
|
/* dy = re->ob->w - w; */
|
||||||
|
/* else */
|
||||||
|
/* dy = re->ob->h - h; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
re->outbuf_reconfigure(re->ob, 0, 0, w, h,
|
||||||
|
info->info.rotation, info->info.depth,
|
||||||
|
info->info.destination_alpha);
|
||||||
|
|
||||||
|
evas_common_tilebuf_free(re->tb);
|
||||||
|
if ((re->tb = evas_common_tilebuf_new(w, h)))
|
||||||
|
evas_common_tilebuf_set_tile_size(re->tb, TILESIZE, TILESIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
eng_output_tile_size_set(void *data, int w, int h)
|
||||||
|
{
|
||||||
|
Render_Engine *re;
|
||||||
|
|
||||||
|
if (!(re = (Render_Engine *)data)) return;
|
||||||
|
if (re->tb) evas_common_tilebuf_set_tile_size(re->tb, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
eng_output_redraws_rect_add(void *data, int x, int y, int w, int h)
|
||||||
|
{
|
||||||
|
Render_Engine *re;
|
||||||
|
|
||||||
|
if (!(re = (Render_Engine *)data)) return;
|
||||||
|
evas_common_tilebuf_add_redraw(re->tb, x, y, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
eng_output_redraws_rect_del(void *data, int x, int y, int w, int h)
|
||||||
|
{
|
||||||
|
Render_Engine *re;
|
||||||
|
|
||||||
|
if (!(re = (Render_Engine *)data)) return;
|
||||||
|
if (re->tb) evas_common_tilebuf_del_redraw(re->tb, x, y, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
eng_output_redraws_clear(void *data)
|
||||||
|
{
|
||||||
|
Render_Engine *re;
|
||||||
|
|
||||||
|
if (!(re = (Render_Engine *)data)) return;
|
||||||
|
if (re->tb) evas_common_tilebuf_clear(re->tb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
eng_output_redraws_next_update_get(void *data, int *x, int *y, int *w, int *h, int *cx, int *cy, int *cw, int *ch)
|
||||||
|
{
|
||||||
|
Render_Engine *re;
|
||||||
|
RGBA_Image *surface;
|
||||||
|
Tilebuf_Rect *rect;
|
||||||
|
Eina_Bool first_rect = EINA_FALSE;
|
||||||
|
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
#define CLEAR_PREV_RECTS(x) \
|
||||||
|
do { \
|
||||||
|
if (re->prev_rects[x]) \
|
||||||
|
evas_common_tilebuf_free_render_rects(re->prev_rects[x]); \
|
||||||
|
re->prev_rects[x] = NULL; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
re = (Render_Engine *)data;
|
||||||
|
if (re->end)
|
||||||
|
{
|
||||||
|
re->end = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!re->rects)
|
||||||
|
{
|
||||||
|
re->mode = evas_swapbuf_state_get(re->ob);
|
||||||
|
re->rects = evas_common_tilebuf_get_render_rects(re->tb);
|
||||||
|
if (re->rects)
|
||||||
|
{
|
||||||
|
if ((re->lost_back) || (re->mode == MODE_FULL))
|
||||||
|
{
|
||||||
|
/* if we lost our backbuffer since the last frame redraw all */
|
||||||
|
re->lost_back = 0;
|
||||||
|
evas_common_tilebuf_add_redraw(re->tb, 0, 0, re->ob->w, re->ob->h);
|
||||||
|
evas_common_tilebuf_free_render_rects(re->rects);
|
||||||
|
re->rects = evas_common_tilebuf_get_render_rects(re->tb);
|
||||||
|
}
|
||||||
|
/* ensure we get rid of previous rect lists we dont need if mode
|
||||||
|
* changed/is appropriate */
|
||||||
|
evas_common_tilebuf_clear(re->tb);
|
||||||
|
CLEAR_PREV_RECTS(2);
|
||||||
|
re->prev_rects[2] = re->prev_rects[1];
|
||||||
|
re->prev_rects[1] = re->prev_rects[0];
|
||||||
|
re->prev_rects[0] = re->rects;
|
||||||
|
re->rects = NULL;
|
||||||
|
switch (re->mode)
|
||||||
|
{
|
||||||
|
case MODE_FULL:
|
||||||
|
case MODE_COPY: // no prev rects needed
|
||||||
|
re->rects =
|
||||||
|
_merge_rects(re->tb, re->prev_rects[0], NULL, NULL);
|
||||||
|
break;
|
||||||
|
case MODE_DOUBLE: // double mode - only 1 level of prev rect
|
||||||
|
re->rects =
|
||||||
|
_merge_rects(re->tb, re->prev_rects[0], re->prev_rects[1], NULL);
|
||||||
|
break;
|
||||||
|
case MODE_TRIPLE: // keep all
|
||||||
|
re->rects =
|
||||||
|
_merge_rects(re->tb, re->prev_rects[0], re->prev_rects[1], re->prev_rects[2]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
first_rect = EINA_TRUE;
|
||||||
|
}
|
||||||
|
evas_common_tilebuf_clear(re->tb);
|
||||||
|
re->cur_rect = EINA_INLIST_GET(re->rects);
|
||||||
|
}
|
||||||
|
if (!re->cur_rect) return NULL;
|
||||||
|
rect = (Tilebuf_Rect *)re->cur_rect;
|
||||||
|
if (re->rects)
|
||||||
|
{
|
||||||
|
switch (re->mode)
|
||||||
|
{
|
||||||
|
case MODE_COPY:
|
||||||
|
case MODE_DOUBLE:
|
||||||
|
case MODE_TRIPLE:
|
||||||
|
rect = (Tilebuf_Rect *)re->cur_rect;
|
||||||
|
*x = rect->x;
|
||||||
|
*y = rect->y;
|
||||||
|
*w = rect->w;
|
||||||
|
*h = rect->h;
|
||||||
|
*cx = rect->x;
|
||||||
|
*cy = rect->y;
|
||||||
|
*cw = rect->w;
|
||||||
|
*ch = rect->h;
|
||||||
|
re->cur_rect = re->cur_rect->next;
|
||||||
|
break;
|
||||||
|
case MODE_FULL:
|
||||||
|
re->cur_rect = NULL;
|
||||||
|
if (x) *x = 0;
|
||||||
|
if (y) *y = 0;
|
||||||
|
if (w) *w = re->ob->w;
|
||||||
|
if (h) *h = re->ob->h;
|
||||||
|
if (cx) *cx = 0;
|
||||||
|
if (cy) *cy = 0;
|
||||||
|
if (cw) *cw = re->ob->w;
|
||||||
|
if (ch) *ch = re->ob->h;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (first_rect)
|
||||||
|
{
|
||||||
|
// do anything needed for the first frame
|
||||||
|
}
|
||||||
|
surface =
|
||||||
|
re->outbuf_update_region_new(re->ob,
|
||||||
|
*x, *y, *w, *h,
|
||||||
|
cx, cy, cw, ch);
|
||||||
|
if (!re->cur_rect) re->end = EINA_TRUE;
|
||||||
|
return surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
eng_output_redraws_next_update_push(void *data, void *surface, int x, int y, int w, int h, Evas_Render_Mode render_mode)
|
||||||
|
{
|
||||||
|
Render_Engine *re;
|
||||||
|
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
if (render_mode == EVAS_RENDER_MODE_ASYNC_INIT) return;
|
||||||
|
|
||||||
|
if (!(re = (Render_Engine *)data)) return;
|
||||||
|
#if defined(BUILD_PIPE_RENDER)
|
||||||
|
evas_common_pipe_map_begin(surface);
|
||||||
|
#endif
|
||||||
|
re->outbuf_update_region_push(re->ob, surface, x, y, w, h);
|
||||||
|
re->outbuf_update_region_free(re->ob, surface);
|
||||||
|
evas_common_cpu_end_opt();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
eng_output_flush(void *data, Evas_Render_Mode render_mode)
|
||||||
|
{
|
||||||
|
Render_Engine *re;
|
||||||
|
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
if (render_mode == EVAS_RENDER_MODE_ASYNC_INIT) return;
|
||||||
|
|
||||||
|
if (!(re = (Render_Engine *)data)) return;
|
||||||
|
re->outbuf_flush(re->ob);
|
||||||
|
if (re->rects)
|
||||||
|
{
|
||||||
|
evas_common_tilebuf_free_render_rects(re->rects);
|
||||||
|
re->rects = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
eng_output_idle_flush(void *data)
|
||||||
|
{
|
||||||
|
Render_Engine *re;
|
||||||
|
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
if (!(re = (Render_Engine *)data)) return;
|
||||||
|
re->outbuf_idle_flush(re->ob);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* module functions */
|
||||||
static int
|
static int
|
||||||
module_open(Evas_Module *em)
|
module_open(Evas_Module *em)
|
||||||
{
|
{
|
||||||
/* check for valid evas module */
|
/* check for valid evas module */
|
||||||
if (!em) return 0;
|
if (!em) return 0;
|
||||||
|
|
||||||
/* try to inherit functions from software_generic engine */
|
/* try to create our logging domain */
|
||||||
if (!_evas_module_engine_inherit(&pfunc, "software_generic")) return 0;
|
|
||||||
|
|
||||||
/* try to create eina logging domain */
|
|
||||||
_evas_engine_drm_log_dom =
|
_evas_engine_drm_log_dom =
|
||||||
eina_log_domain_register("evas-drm", EVAS_DEFAULT_LOG_COLOR);
|
eina_log_domain_register("evas-drm", EVAS_DEFAULT_LOG_COLOR);
|
||||||
|
|
||||||
/* if we could not create a logging domain, error out */
|
|
||||||
if (_evas_engine_drm_log_dom < 0)
|
if (_evas_engine_drm_log_dom < 0)
|
||||||
{
|
{
|
||||||
EINA_LOG_ERR("Can not create a module log domain.");
|
/* creating the logging domain failed. notify user */
|
||||||
|
EINA_LOG_ERR("Could not create a module log domain.");
|
||||||
|
|
||||||
|
/* return failure */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* store parent functions */
|
/* try to inherit base functions from the software generic engine */
|
||||||
|
if (!_evas_module_engine_inherit(&pfunc, "software_generic"))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* try to init the buffer manager */
|
||||||
|
if (!evas_buffer_manager_init()) return 0;
|
||||||
|
|
||||||
|
/* copy base functions from the software_generic engine */
|
||||||
func = pfunc;
|
func = pfunc;
|
||||||
|
|
||||||
/* override the methods we provide */
|
/* override any engine specific functions that we provide */
|
||||||
EVAS_API_OVERRIDE(info, &func, eng_);
|
#define ORD(f) EVAS_API_OVERRIDE(f, &func, eng_)
|
||||||
EVAS_API_OVERRIDE(info_free, &func, eng_);
|
ORD(info);
|
||||||
EVAS_API_OVERRIDE(setup, &func, eng_);
|
ORD(info_free);
|
||||||
EVAS_API_OVERRIDE(output_free, &func, eng_);
|
ORD(setup);
|
||||||
|
ORD(output_free);
|
||||||
|
ORD(output_resize);
|
||||||
|
ORD(output_tile_size_set);
|
||||||
|
ORD(output_redraws_rect_add);
|
||||||
|
ORD(output_redraws_rect_del);
|
||||||
|
ORD(output_redraws_clear);
|
||||||
|
ORD(output_redraws_next_update_get);
|
||||||
|
ORD(output_redraws_next_update_push);
|
||||||
|
ORD(output_flush);
|
||||||
|
ORD(output_idle_flush);
|
||||||
|
|
||||||
/* advertise our engine functions */
|
/* advertise out our own api */
|
||||||
em->functions = (void *)(&func);
|
em->functions = (void *)(&func);
|
||||||
|
|
||||||
|
/* return success */
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
module_close(Evas_Module *em EINA_UNUSED)
|
module_close(Evas_Module *em EINA_UNUSED)
|
||||||
{
|
{
|
||||||
/* unregister the eina log domain for this engine */
|
/* shutdown the buffer manager */
|
||||||
eina_log_domain_unregister(_evas_engine_drm_log_dom);
|
evas_buffer_manager_shutdown();
|
||||||
|
|
||||||
|
/* if we have the log domain, unregister it */
|
||||||
|
if (_evas_engine_drm_log_dom > -1)
|
||||||
|
eina_log_domain_unregister(_evas_engine_drm_log_dom);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Evas_Module_Api evas_modapi =
|
static Evas_Module_Api evas_modapi =
|
||||||
{
|
{
|
||||||
EVAS_MODULE_API_VERSION, "drm", "none", { module_open, module_close }
|
EVAS_MODULE_API_VERSION, "drm", "none", {module_open, module_close}
|
||||||
};
|
};
|
||||||
|
|
||||||
EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_ENGINE, engine, drm);
|
EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_ENGINE, engine, drm);
|
||||||
|
|
|
@ -1,5 +1,29 @@
|
||||||
#ifndef EVAS_ENGINE_H
|
#ifndef _EVAS_ENGINE_H
|
||||||
# define EVAS_ENGINE_H
|
# define _EVAS_ENGINE_H
|
||||||
|
|
||||||
|
# define LOGFNS 1
|
||||||
|
|
||||||
|
# ifdef LOGFNS
|
||||||
|
# include <stdio.h>
|
||||||
|
# define LOGFN(fl, ln, fn) printf("-EVAS-DRM: %25s: %5i - %s\n", fl, ln, fn);
|
||||||
|
# else
|
||||||
|
# define LOGFN(fl, ln, fn)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# include "evas_common_private.h"
|
||||||
|
# include "evas_macros.h"
|
||||||
|
# include "evas_private.h"
|
||||||
|
# include "Evas.h"
|
||||||
|
# include "Evas_Engine_Drm.h"
|
||||||
|
|
||||||
|
/* # include <xf86drm.h> */
|
||||||
|
/* # include <xf86drmMode.h> */
|
||||||
|
/* # include <drm_fourcc.h> */
|
||||||
|
|
||||||
|
/* # ifdef GL_GLES */
|
||||||
|
/* # include <EGL/egl.h> */
|
||||||
|
/* # define GL_GLEXT_PROTOTYPES */
|
||||||
|
/* # endif */
|
||||||
|
|
||||||
extern int _evas_engine_drm_log_dom;
|
extern int _evas_engine_drm_log_dom;
|
||||||
|
|
||||||
|
@ -28,8 +52,18 @@ extern int _evas_engine_drm_log_dom;
|
||||||
# endif
|
# endif
|
||||||
# define CRI(...) EINA_LOG_DOM_CRIT(_evas_engine_drm_log_dom, __VA_ARGS__)
|
# define CRI(...) EINA_LOG_DOM_CRIT(_evas_engine_drm_log_dom, __VA_ARGS__)
|
||||||
|
|
||||||
|
typedef enum _Outbuf_Depth Outbuf_Depth;
|
||||||
|
typedef struct _Wl_Swapper Wl_Swapper;
|
||||||
typedef struct _Outbuf Outbuf;
|
typedef struct _Outbuf Outbuf;
|
||||||
|
|
||||||
|
enum _Outbuf_Depth
|
||||||
|
{
|
||||||
|
OUTBUF_DEPTH_NONE,
|
||||||
|
OUTBUF_DEPTH_ARGB_32BPP_8888_8888,
|
||||||
|
OUTBUF_DEPTH_RGB_32BPP_8888_8888,
|
||||||
|
OUTBUF_DEPTH_LAST
|
||||||
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
MODE_FULL,
|
MODE_FULL,
|
||||||
|
@ -41,12 +75,54 @@ enum
|
||||||
struct _Outbuf
|
struct _Outbuf
|
||||||
{
|
{
|
||||||
int w, h;
|
int w, h;
|
||||||
unsigned int rotation, depth;
|
unsigned int rotation;
|
||||||
Eina_Bool destination_alpha : 1;
|
Outbuf_Depth depth;
|
||||||
|
int onebuf;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
/* file descriptor for drm card */
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
/* swapper */
|
||||||
|
void *swapper;
|
||||||
|
|
||||||
|
/* one big buffer for updates. flushed on idle_flush */
|
||||||
|
RGBA_Image *onebuf;
|
||||||
|
Eina_Array onebuf_regions;
|
||||||
|
|
||||||
|
/* a list of pending regions to write out */
|
||||||
|
Eina_List *pending_writes;
|
||||||
|
|
||||||
|
/* list of previous frame pending regions to write out */
|
||||||
|
Eina_List *prev_pending_writes;
|
||||||
|
|
||||||
|
Eina_Bool destination_alpha : 1;
|
||||||
|
} priv;
|
||||||
};
|
};
|
||||||
|
|
||||||
Outbuf *evas_outbuf_setup(int w, int h, unsigned int rotation, unsigned int depth, Eina_Bool alpha);
|
Outbuf *evas_swapbuf_setup(int w, int h, unsigned int rotation, Outbuf_Depth depth, Eina_Bool alpha, int fd);
|
||||||
void evas_outbuf_free(Outbuf *ob);
|
void evas_swapbuf_free(Outbuf *ob);
|
||||||
void evas_outbuf_reconfigure(Outbuf *ob, int w, int h, unsigned int rotation, unsigned int depth, Eina_Bool alpha);
|
void evas_swapbuf_reconfigure(Outbuf *ob, int x, int y, int w, int h, unsigned int rotation, Outbuf_Depth depth, Eina_Bool alpha);
|
||||||
|
RGBA_Image *evas_swapbuf_update_region_new(Outbuf *ob, int x, int y, int w, int h, int *cx, int *cy, int *cw, int *ch);
|
||||||
|
void evas_swapbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int w, int h);
|
||||||
|
void evas_swapbuf_update_region_free(Outbuf *ob, RGBA_Image *update);
|
||||||
|
void evas_swapbuf_flush(Outbuf *ob);
|
||||||
|
void evas_swapbuf_idle_flush(Outbuf *ob EINA_UNUSED);
|
||||||
|
int evas_swapbuf_state_get(Outbuf *ob);
|
||||||
|
|
||||||
|
Wl_Swapper *evas_swapper_setup(int dx, int dy, int w, int h, Outbuf_Depth depth, Eina_Bool alpha, int fd);
|
||||||
|
Wl_Swapper *evas_swapper_reconfigure(Wl_Swapper *ws, int dx, int dy, int w, int h, Outbuf_Depth depth, Eina_Bool alpha);
|
||||||
|
void evas_swapper_swap(Wl_Swapper *ws, Eina_Rectangle *rects, unsigned int count);
|
||||||
|
void evas_swapper_free(Wl_Swapper *ws);
|
||||||
|
void *evas_swapper_buffer_map(Wl_Swapper *ws, int *w, int *h);
|
||||||
|
void evas_swapper_buffer_unmap(Wl_Swapper *ws);
|
||||||
|
int evas_swapper_buffer_state_get(Wl_Swapper *ws);
|
||||||
|
void evas_swapper_buffer_idle_flush(Wl_Swapper *ws);
|
||||||
|
|
||||||
|
int evas_buffer_manager_init(void);
|
||||||
|
int evas_buffer_manager_shutdown(void);
|
||||||
|
Eina_Bool evas_buffer_manager_open(int fd);
|
||||||
|
void evas_buffer_manager_close(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
#include "evas_common_private.h"
|
|
||||||
#include "evas_private.h"
|
|
||||||
#include "evas_engine.h"
|
|
||||||
|
|
||||||
Outbuf *
|
|
||||||
evas_outbuf_setup(int w, int h, unsigned int rotation, unsigned int depth, Eina_Bool alpha)
|
|
||||||
{
|
|
||||||
Outbuf *ob;
|
|
||||||
|
|
||||||
/* try to allocate space for out outbuf structure */
|
|
||||||
if (!(ob = calloc(1, sizeof(Outbuf))))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* set some default outbuf properties */
|
|
||||||
ob->w = w;
|
|
||||||
ob->h = h;
|
|
||||||
ob->rotation = rotation;
|
|
||||||
ob->depth = depth;
|
|
||||||
ob->destination_alpha = alpha;
|
|
||||||
|
|
||||||
/* return the allocated outbuf structure */
|
|
||||||
return ob;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
evas_outbuf_free(Outbuf *ob)
|
|
||||||
{
|
|
||||||
/* free the allocated outbuf structure */
|
|
||||||
free(ob);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
evas_outbuf_reconfigure(Outbuf *ob, int w, int h, unsigned int rotation, unsigned int depth, Eina_Bool alpha)
|
|
||||||
{
|
|
||||||
/* check for changes */
|
|
||||||
if ((ob->w == w) && (ob->h == h) && (ob->destination_alpha == alpha) &&
|
|
||||||
(ob->rotation == rotation) && (ob->depth == depth)) return;
|
|
||||||
|
|
||||||
/* set new outbuf properties */
|
|
||||||
ob->w = w;
|
|
||||||
ob->h = h;
|
|
||||||
ob->rotation = rotation;
|
|
||||||
ob->depth = depth;
|
|
||||||
ob->destination_alpha = alpha;
|
|
||||||
}
|
|
|
@ -0,0 +1,522 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//#include <sys/mman.h>
|
||||||
|
|
||||||
|
#ifdef EVAS_CSERVE2
|
||||||
|
# include "evas_cs2_private.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "evas_engine.h"
|
||||||
|
|
||||||
|
#define RED_MASK 0x00ff0000
|
||||||
|
#define GREEN_MASK 0x0000ff00
|
||||||
|
#define BLUE_MASK 0x000000ff
|
||||||
|
|
||||||
|
/* local function prototypes */
|
||||||
|
|
||||||
|
Outbuf *
|
||||||
|
evas_swapbuf_setup(int w, int h, unsigned int rotation, Outbuf_Depth depth, Eina_Bool alpha, int fd)
|
||||||
|
{
|
||||||
|
Outbuf *ob = NULL;
|
||||||
|
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
/* try to allocate a new Outbuf */
|
||||||
|
if (!(ob = calloc(1, sizeof(Outbuf))))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* set some properties */
|
||||||
|
ob->w = w;
|
||||||
|
ob->h = h;
|
||||||
|
ob->rotation = rotation;
|
||||||
|
ob->depth = depth;
|
||||||
|
ob->priv.destination_alpha = alpha;
|
||||||
|
ob->priv.fd = fd;
|
||||||
|
|
||||||
|
if ((ob->rotation == 0) || (ob->rotation == 180))
|
||||||
|
{
|
||||||
|
ob->priv.swapper =
|
||||||
|
evas_swapper_setup(0, 0, w, h, depth, alpha, fd);
|
||||||
|
}
|
||||||
|
else if ((ob->rotation == 90) || (ob->rotation == 270))
|
||||||
|
{
|
||||||
|
ob->priv.swapper =
|
||||||
|
evas_swapper_setup(0, 0, h, w, depth, alpha, fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check that a swapper was created */
|
||||||
|
if (!ob->priv.swapper)
|
||||||
|
{
|
||||||
|
/* free the Outbuf structure allocation */
|
||||||
|
free(ob);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set step size of regions array */
|
||||||
|
eina_array_step_set(&ob->priv.onebuf_regions, sizeof(Eina_Array), 8);
|
||||||
|
|
||||||
|
/* return allocated Outbuf */
|
||||||
|
return ob;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
evas_swapbuf_free(Outbuf *ob)
|
||||||
|
{
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
/* check for valid output buffer */
|
||||||
|
if (!ob) return;
|
||||||
|
|
||||||
|
/* flush the output buffer */
|
||||||
|
evas_swapbuf_flush(ob);
|
||||||
|
evas_swapbuf_idle_flush(ob);
|
||||||
|
evas_swapper_free(ob->priv.swapper);
|
||||||
|
eina_array_flush(&ob->priv.onebuf_regions);
|
||||||
|
|
||||||
|
/* free the allocated structure */
|
||||||
|
free(ob);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
evas_swapbuf_reconfigure(Outbuf *ob, int x, int y, int w, int h, unsigned int rotation, Outbuf_Depth depth, Eina_Bool alpha)
|
||||||
|
{
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
/* check for valid output buffer */
|
||||||
|
if (!ob) return;
|
||||||
|
|
||||||
|
/* check that something was actually changed */
|
||||||
|
if ((ob->w == w) && (ob->h == h) &&
|
||||||
|
(ob->rotation == rotation) && (ob->depth == depth))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* set some properties */
|
||||||
|
ob->w = w;
|
||||||
|
ob->h = h;
|
||||||
|
ob->rotation = rotation;
|
||||||
|
ob->depth = depth;
|
||||||
|
ob->priv.destination_alpha = alpha;
|
||||||
|
|
||||||
|
/* check for valid swapper */
|
||||||
|
if (ob->priv.swapper)
|
||||||
|
{
|
||||||
|
if ((ob->rotation == 0) || (ob->rotation == 180))
|
||||||
|
ob->priv.swapper = evas_swapper_reconfigure(ob->priv.swapper,
|
||||||
|
x, y, w, h, depth,
|
||||||
|
alpha);
|
||||||
|
else if ((ob->rotation == 90) || (ob->rotation == 270))
|
||||||
|
ob->priv.swapper = evas_swapper_reconfigure(ob->priv.swapper,
|
||||||
|
x, y, h, w, depth,
|
||||||
|
alpha);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create new swapper */
|
||||||
|
if ((ob->rotation == 0) || (ob->rotation == 180))
|
||||||
|
{
|
||||||
|
ob->priv.swapper =
|
||||||
|
evas_swapper_setup(x, y, w, h, depth, alpha, ob->priv.fd);
|
||||||
|
}
|
||||||
|
else if ((ob->rotation == 90) || (ob->rotation == 270))
|
||||||
|
{
|
||||||
|
ob->priv.swapper =
|
||||||
|
evas_swapper_setup(x, y, h, w, depth, alpha, ob->priv.fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RGBA_Image *
|
||||||
|
evas_swapbuf_update_region_new(Outbuf *ob, int x, int y, int w, int h, int *cx, int *cy, int *cw, int *ch)
|
||||||
|
{
|
||||||
|
RGBA_Image *img;
|
||||||
|
Eina_Rectangle *rect;
|
||||||
|
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
RECTS_CLIP_TO_RECT(x, y, w, h, 0, 0, ob->w, ob->h);
|
||||||
|
if ((w <= 0) || (h <= 0)) return NULL;
|
||||||
|
|
||||||
|
if (ob->rotation == 0)
|
||||||
|
{
|
||||||
|
if (!(img = ob->priv.onebuf))
|
||||||
|
{
|
||||||
|
int bpl = 0;
|
||||||
|
int bw = 0, bh = 0;
|
||||||
|
void *data;
|
||||||
|
|
||||||
|
if (!(data = evas_swapper_buffer_map(ob->priv.swapper, &bw, &bh)))
|
||||||
|
{
|
||||||
|
ERR("NO BUFFER DATA !!");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bpl = (bw * sizeof(int));
|
||||||
|
|
||||||
|
#ifdef EVAS_CSERVE2
|
||||||
|
if (evas_cserve2_use_get())
|
||||||
|
img = (RGBA_Image *)evas_cache2_image_data(evas_common_image_cache2_get(),
|
||||||
|
bpl / sizeof(int), bh,
|
||||||
|
data,
|
||||||
|
ob->priv.destination_alpha,
|
||||||
|
EVAS_COLORSPACE_ARGB8888);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
img = (RGBA_Image *)evas_cache_image_data(evas_common_image_cache_get(),
|
||||||
|
bpl / sizeof(int), bh,
|
||||||
|
data,
|
||||||
|
ob->priv.destination_alpha,
|
||||||
|
EVAS_COLORSPACE_ARGB8888);
|
||||||
|
|
||||||
|
ob->priv.onebuf = img;
|
||||||
|
if (!img) return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(rect = eina_rectangle_new(x, y, w, h)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!eina_array_push(&ob->priv.onebuf_regions, rect))
|
||||||
|
{
|
||||||
|
#ifdef EVAS_CSERVE2
|
||||||
|
if (evas_cserve2_use_get())
|
||||||
|
evas_cache2_image_close(&img->cache_entry);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
evas_cache_image_drop(&img->cache_entry);
|
||||||
|
|
||||||
|
eina_rectangle_free(rect);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clip the region to the onebuf region */
|
||||||
|
if (cx) *cx = x;
|
||||||
|
if (cy) *cy = y;
|
||||||
|
if (cw) *cw = w;
|
||||||
|
if (ch) *ch = h;
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!(rect = eina_rectangle_new(x, y, w, h)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
#ifdef EVAS_CSERVE2
|
||||||
|
if (evas_cserve2_use_get())
|
||||||
|
img = (RGBA_Image *)evas_cache2_image_empty(evas_common_image_cache2_get());
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
img = (RGBA_Image *)evas_cache_image_empty(evas_common_image_cache_get());
|
||||||
|
|
||||||
|
if (!img)
|
||||||
|
{
|
||||||
|
eina_rectangle_free(rect);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
img->cache_entry.flags.alpha |= ob->priv.destination_alpha;
|
||||||
|
|
||||||
|
#ifdef EVAS_CSERVE2
|
||||||
|
if (evas_cserve2_use_get())
|
||||||
|
evas_cache2_image_surface_alloc(&img->cache_entry, w, h);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
evas_cache_image_surface_alloc(&img->cache_entry, w, h);
|
||||||
|
|
||||||
|
img->extended_info = rect;
|
||||||
|
|
||||||
|
ob->priv.pending_writes =
|
||||||
|
eina_list_append(ob->priv.pending_writes, img);
|
||||||
|
|
||||||
|
if (cx) *cx = 0;
|
||||||
|
if (cy) *cy = 0;
|
||||||
|
if (cw) *cw = w;
|
||||||
|
if (ch) *ch = h;
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
evas_swapbuf_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;
|
||||||
|
int depth = 32, bpp = 0, bpl = 0, wid = 0;
|
||||||
|
int ww = 0, hh = 0;
|
||||||
|
int rx = 0, ry = 0;
|
||||||
|
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
/* check for valid output buffer */
|
||||||
|
if (!ob) return;
|
||||||
|
|
||||||
|
/* check for pending writes */
|
||||||
|
if (!ob->priv.pending_writes) return;
|
||||||
|
|
||||||
|
if ((ob->rotation == 0) || (ob->rotation == 180))
|
||||||
|
{
|
||||||
|
func =
|
||||||
|
evas_common_convert_func_get(0, w, h, depth,
|
||||||
|
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, depth,
|
||||||
|
RED_MASK, GREEN_MASK, BLUE_MASK,
|
||||||
|
PAL_MODE_NONE, ob->rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make sure we have a valid convert function */
|
||||||
|
if (!func) return;
|
||||||
|
|
||||||
|
/* based on rotation, set rectangle position */
|
||||||
|
if (ob->rotation == 0)
|
||||||
|
{
|
||||||
|
rect.x = x;
|
||||||
|
rect.y = y;
|
||||||
|
}
|
||||||
|
else if (ob->rotation == 90)
|
||||||
|
{
|
||||||
|
rect.x = y;
|
||||||
|
rect.y = (ob->w - x - w);
|
||||||
|
}
|
||||||
|
else if (ob->rotation == 180)
|
||||||
|
{
|
||||||
|
rect.x = (ob->w - x - w);
|
||||||
|
rect.y = (ob->h - y - h);
|
||||||
|
}
|
||||||
|
else if (ob->rotation == 270)
|
||||||
|
{
|
||||||
|
rect.x = (ob->h - y - h);
|
||||||
|
rect.y = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* based on rotation, set rectangle size */
|
||||||
|
if ((ob->rotation == 0) || (ob->rotation == 180))
|
||||||
|
{
|
||||||
|
rect.w = w;
|
||||||
|
rect.h = h;
|
||||||
|
}
|
||||||
|
else if ((ob->rotation == 90) || (ob->rotation == 270))
|
||||||
|
{
|
||||||
|
rect.w = h;
|
||||||
|
rect.h = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check for valid update image data */
|
||||||
|
if (!(src = update->image.data)) return;
|
||||||
|
|
||||||
|
bpp = depth / 8;
|
||||||
|
if (bpp <= 0) return;
|
||||||
|
|
||||||
|
/* check for valid desination data */
|
||||||
|
if (!(dst = evas_swapper_buffer_map(ob->priv.swapper, &ww, &hh))) return;
|
||||||
|
|
||||||
|
bpl = (ww * sizeof(int));
|
||||||
|
|
||||||
|
if (ob->rotation == 0)
|
||||||
|
{
|
||||||
|
RECTS_CLIP_TO_RECT(rect.x, rect.y, rect.w, rect.h, 0, 0, ww, hh);
|
||||||
|
dst += (bpl * rect.y) + (rect.x + bpp);
|
||||||
|
w -= rx;
|
||||||
|
}
|
||||||
|
else if (ob->rotation == 180)
|
||||||
|
{
|
||||||
|
pr = rect;
|
||||||
|
RECTS_CLIP_TO_RECT(rect.x, rect.y, rect.w, rect.h, 0, 0, ww, hh);
|
||||||
|
rx = pr.w - rect.w;
|
||||||
|
ry = pr.h - rect.h;
|
||||||
|
src += (update->cache_entry.w * ry) + rx;
|
||||||
|
w -= rx;
|
||||||
|
}
|
||||||
|
else if (ob->rotation == 90)
|
||||||
|
{
|
||||||
|
pr = rect;
|
||||||
|
RECTS_CLIP_TO_RECT(rect.x, rect.y, rect.w, rect.h, 0, 0, ww, hh);
|
||||||
|
rx = pr.w - rect.w; ry = pr.h - rect.h;
|
||||||
|
src += ry;
|
||||||
|
w -= ry;
|
||||||
|
}
|
||||||
|
else if (ob->rotation == 270)
|
||||||
|
{
|
||||||
|
pr = rect;
|
||||||
|
RECTS_CLIP_TO_RECT(rect.x, rect.y, rect.w, rect.h, 0, 0, ww, hh);
|
||||||
|
rx = pr.w - rect.w; ry = pr.h - rect.h;
|
||||||
|
src += (update->cache_entry.w * rx);
|
||||||
|
w -= ry;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((rect.w <= 0) || (rect.h <= 0)) return;
|
||||||
|
|
||||||
|
wid = bpl / bpp;
|
||||||
|
|
||||||
|
dst += (bpl * rect.y) + (rect.x * bpp);
|
||||||
|
|
||||||
|
func(src, dst, (update->cache_entry.w - w), (wid - rect.w),
|
||||||
|
rect.w, rect.h, x + rx, y + ry, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
evas_swapbuf_update_region_free(Outbuf *ob EINA_UNUSED, RGBA_Image *update EINA_UNUSED)
|
||||||
|
{
|
||||||
|
/* NB: nothing to do, they are cleaned up on flush */
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
evas_swapbuf_flush(Outbuf *ob)
|
||||||
|
{
|
||||||
|
Eina_Rectangle *rects;
|
||||||
|
RGBA_Image *img;
|
||||||
|
unsigned int n = 0, i = 0;
|
||||||
|
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
/* check for valid output buffer */
|
||||||
|
if (!ob) return;
|
||||||
|
|
||||||
|
/* check for pending writes */
|
||||||
|
if (!ob->priv.pending_writes)
|
||||||
|
{
|
||||||
|
Eina_Rectangle *rect;
|
||||||
|
Eina_Array_Iterator it;
|
||||||
|
|
||||||
|
/* get number of buffer regions */
|
||||||
|
n = eina_array_count_get(&ob->priv.onebuf_regions);
|
||||||
|
if (n == 0) return;
|
||||||
|
|
||||||
|
/* allocate rectangles */
|
||||||
|
if (!(rects = alloca(n * sizeof(Eina_Rectangle)))) return;
|
||||||
|
|
||||||
|
/* loop the buffer regions and assign to rects */
|
||||||
|
EINA_ARRAY_ITER_NEXT(&ob->priv.onebuf_regions, i, rect, it)
|
||||||
|
rects[i] = *rect;
|
||||||
|
|
||||||
|
/* unmap the buffer */
|
||||||
|
evas_swapper_buffer_unmap(ob->priv.swapper);
|
||||||
|
|
||||||
|
/* force a buffer swap */
|
||||||
|
evas_swapper_swap(ob->priv.swapper, rects, n);
|
||||||
|
|
||||||
|
/* clean array */
|
||||||
|
eina_array_clean(&ob->priv.onebuf_regions);
|
||||||
|
|
||||||
|
img = ob->priv.onebuf;
|
||||||
|
ob->priv.onebuf = NULL;
|
||||||
|
if (img)
|
||||||
|
{
|
||||||
|
#ifdef EVAS_CSERVE2
|
||||||
|
if (evas_cserve2_use_get())
|
||||||
|
evas_cache2_image_close(&img->cache_entry);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
evas_cache_image_drop(&img->cache_entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* get number of pending writes */
|
||||||
|
n = eina_list_count(ob->priv.pending_writes);
|
||||||
|
if (n == 0) return;
|
||||||
|
|
||||||
|
/* allocate rectangles */
|
||||||
|
if (!(rects = alloca(n * sizeof(Eina_Rectangle)))) return;
|
||||||
|
|
||||||
|
/* loop the pending writes */
|
||||||
|
EINA_LIST_FREE(ob->priv.pending_writes, img)
|
||||||
|
{
|
||||||
|
Eina_Rectangle *rect;
|
||||||
|
int x = 0, y = 0, w = 0, h = 0;
|
||||||
|
|
||||||
|
if (!(rect = img->extended_info)) continue;
|
||||||
|
|
||||||
|
x = rect->x; y = rect->y; w = rect->w; h = rect->h;
|
||||||
|
|
||||||
|
/* based on rotation, set rectangle position */
|
||||||
|
if (ob->rotation == 0)
|
||||||
|
{
|
||||||
|
rects[i].x = x;
|
||||||
|
rects[i].y = y;
|
||||||
|
}
|
||||||
|
else if (ob->rotation == 90)
|
||||||
|
{
|
||||||
|
rects[i].x = y;
|
||||||
|
rects[i].y = (ob->w - x - w);
|
||||||
|
}
|
||||||
|
else if (ob->rotation == 180)
|
||||||
|
{
|
||||||
|
rects[i].x = (ob->w - x - w);
|
||||||
|
rects[i].y = (ob->h - y - h);
|
||||||
|
}
|
||||||
|
else if (ob->rotation == 270)
|
||||||
|
{
|
||||||
|
rects[i].x = (ob->h - y - h);
|
||||||
|
rects[i].y = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* based on rotation, set rectangle size */
|
||||||
|
if ((ob->rotation == 0) || (ob->rotation == 180))
|
||||||
|
{
|
||||||
|
rects[i].w = w;
|
||||||
|
rects[i].h = h;
|
||||||
|
}
|
||||||
|
else if ((ob->rotation == 90) || (ob->rotation == 270))
|
||||||
|
{
|
||||||
|
rects[i].w = h;
|
||||||
|
rects[i].h = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
eina_rectangle_free(rect);
|
||||||
|
|
||||||
|
#ifdef EVAS_CSERVE2
|
||||||
|
if (evas_cserve2_use_get())
|
||||||
|
evas_cache2_image_close(&img->cache_entry);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
evas_cache_image_drop(&img->cache_entry);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* unmap the buffer */
|
||||||
|
evas_swapper_buffer_unmap(ob->priv.swapper);
|
||||||
|
|
||||||
|
/* force a buffer swap */
|
||||||
|
evas_swapper_swap(ob->priv.swapper, rects, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
evas_swapbuf_idle_flush(Outbuf *ob EINA_UNUSED)
|
||||||
|
{
|
||||||
|
// LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
/* check for valid output buffer */
|
||||||
|
/* if (!ob) return; */
|
||||||
|
|
||||||
|
/* check for valid swapper */
|
||||||
|
/* if (!ob->priv.swapper) return; */
|
||||||
|
|
||||||
|
/* tell the swapper to release any buffers that have been rendered */
|
||||||
|
/* evas_swapper_buffer_idle_flush(ob->priv.swapper); */
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
evas_swapbuf_state_get(Outbuf *ob)
|
||||||
|
{
|
||||||
|
int mode = 0;
|
||||||
|
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
if (!ob->priv.swapper) return MODE_FULL;
|
||||||
|
mode = evas_swapper_buffer_state_get(ob->priv.swapper);
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* local functions */
|
|
@ -0,0 +1,401 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
#ifdef EVAS_CSERVE2
|
||||||
|
# include "evas_cs2_private.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "evas_engine.h"
|
||||||
|
|
||||||
|
/* local structures */
|
||||||
|
typedef struct _Wl_Buffer Wl_Buffer;
|
||||||
|
struct _Wl_Buffer
|
||||||
|
{
|
||||||
|
Wl_Swapper *ws;
|
||||||
|
int w, h;
|
||||||
|
void *data;
|
||||||
|
int offset;
|
||||||
|
unsigned int id, hdl;
|
||||||
|
size_t size;
|
||||||
|
Eina_Bool valid : 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _Wl_Swapper
|
||||||
|
{
|
||||||
|
Wl_Buffer buff[3];
|
||||||
|
Wl_Buffer *buffer_sent;
|
||||||
|
|
||||||
|
int in_use, drm_fd;
|
||||||
|
int dx, dy, w, h, depth;
|
||||||
|
int buff_cur, buff_num;
|
||||||
|
|
||||||
|
/* void *data; */
|
||||||
|
|
||||||
|
Eina_Bool alpha : 1;
|
||||||
|
Eina_Bool mapped : 1;
|
||||||
|
Eina_Bool delete_me : 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* local function prototypes */
|
||||||
|
/* static Eina_Bool _evas_swapper_shm_pool_new(Wl_Swapper *ws); */
|
||||||
|
/* static void _evas_swapper_shm_pool_free(Wl_Swapper *ws); */
|
||||||
|
static Eina_Bool _evas_swapper_buffer_new(Wl_Swapper *ws, Wl_Buffer *wb);
|
||||||
|
static void _evas_swapper_buffer_free(Wl_Swapper *ws, Wl_Buffer *wb);
|
||||||
|
static void _evas_swapper_buffer_put(Wl_Swapper *ws, Wl_Buffer *wb, Eina_Rectangle *rects, unsigned int count);
|
||||||
|
|
||||||
|
/* local variables */
|
||||||
|
|
||||||
|
Wl_Swapper *
|
||||||
|
evas_swapper_setup(int dx, int dy, int w, int h, Outbuf_Depth depth, Eina_Bool alpha, int fd)
|
||||||
|
{
|
||||||
|
Wl_Swapper *ws;
|
||||||
|
int i = 0;
|
||||||
|
char *num_buffers;
|
||||||
|
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
/* try to allocate a new swapper */
|
||||||
|
if (!(ws = calloc(1, sizeof(Wl_Swapper))))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* set some properties */
|
||||||
|
ws->dx = dx;
|
||||||
|
ws->dy = dy;
|
||||||
|
ws->w = w;
|
||||||
|
ws->h = h;
|
||||||
|
ws->depth = depth;
|
||||||
|
ws->alpha = alpha;
|
||||||
|
ws->drm_fd = fd;
|
||||||
|
|
||||||
|
/* double buffer by default */
|
||||||
|
ws->buff_num = 2;
|
||||||
|
|
||||||
|
/* check for buffer override number */
|
||||||
|
if ((num_buffers = getenv("EVAS_DRM_BUFFERS")))
|
||||||
|
{
|
||||||
|
int num = 0;
|
||||||
|
|
||||||
|
num = atoi(num_buffers);
|
||||||
|
|
||||||
|
if (num <= 0) num = 1;
|
||||||
|
if (num > 3) num = 3;
|
||||||
|
|
||||||
|
ws->buff_num = num;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < ws->buff_num; i++)
|
||||||
|
{
|
||||||
|
/* try to create new internal Wl_Buffer */
|
||||||
|
if (!_evas_swapper_buffer_new(ws, &(ws->buff[i])))
|
||||||
|
{
|
||||||
|
/* failed to create buffer. free the swapper */
|
||||||
|
ERR("Failed to create new buffer");
|
||||||
|
evas_swapper_free(ws);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return allocated swapper */
|
||||||
|
return ws;
|
||||||
|
}
|
||||||
|
|
||||||
|
Wl_Swapper *
|
||||||
|
evas_swapper_reconfigure(Wl_Swapper *ws, int dx, int dy, int w, int h, Outbuf_Depth depth, Eina_Bool alpha)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
if (!ws) return NULL;
|
||||||
|
|
||||||
|
/* loop the swapper's buffers and free them */
|
||||||
|
for (i = 0; i < ws->buff_num; i++)
|
||||||
|
_evas_swapper_buffer_free(ws, &(ws->buff[i]));
|
||||||
|
|
||||||
|
ws->dx += dx;
|
||||||
|
ws->dy += dy;
|
||||||
|
ws->w = w;
|
||||||
|
ws->h = h;
|
||||||
|
ws->depth = depth;
|
||||||
|
ws->alpha = alpha;
|
||||||
|
|
||||||
|
for (i = 0; i < ws->buff_num; i++)
|
||||||
|
{
|
||||||
|
/* try to create new internal Wl_Buffer */
|
||||||
|
if (!_evas_swapper_buffer_new(ws, &(ws->buff[i])))
|
||||||
|
{
|
||||||
|
ERR("failed to create wl_buffer. free the swapper.");
|
||||||
|
evas_swapper_free(ws);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return reconfigured swapper */
|
||||||
|
return ws;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
evas_swapper_swap(Wl_Swapper *ws, Eina_Rectangle *rects, unsigned int count)
|
||||||
|
{
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
/* check for valid swapper */
|
||||||
|
if (!ws) return;
|
||||||
|
|
||||||
|
n = ws->buff_cur;
|
||||||
|
_evas_swapper_buffer_put(ws, &(ws->buff[n]), rects, count);
|
||||||
|
ws->buff[n].valid = EINA_TRUE;
|
||||||
|
ws->in_use++;
|
||||||
|
ws->buff_cur = (ws->buff_cur + 1) % ws->buff_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
evas_swapper_free(Wl_Swapper *ws)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
/* check for valid swapper */
|
||||||
|
if (!ws) return;
|
||||||
|
|
||||||
|
/* loop the swapper's buffers and free them */
|
||||||
|
for (i = 0; i < ws->buff_num; i++)
|
||||||
|
_evas_swapper_buffer_free(ws, &(ws->buff[i]));
|
||||||
|
|
||||||
|
if (ws->in_use)
|
||||||
|
{
|
||||||
|
ws->delete_me = EINA_TRUE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free the allocated structure */
|
||||||
|
free(ws);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
evas_swapper_buffer_map(Wl_Swapper *ws, int *w, int *h)
|
||||||
|
{
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
/* check for valid swapper */
|
||||||
|
if (!ws) return NULL;
|
||||||
|
|
||||||
|
/* set mapped property */
|
||||||
|
ws->mapped = EINA_TRUE;
|
||||||
|
if (w) *w = ws->w;
|
||||||
|
if (h) *h = ws->h;
|
||||||
|
|
||||||
|
/* return wl_buffer data */
|
||||||
|
return ws->buff[ws->buff_cur].data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
evas_swapper_buffer_unmap(Wl_Swapper *ws)
|
||||||
|
{
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
/* check for valid swapper */
|
||||||
|
if (!ws) return;
|
||||||
|
|
||||||
|
ws->mapped = EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
evas_swapper_buffer_state_get(Wl_Swapper *ws)
|
||||||
|
{
|
||||||
|
int i = 0, n = 0, count = 0;
|
||||||
|
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
for (i = 0; i < ws->buff_num; i++)
|
||||||
|
{
|
||||||
|
n = (ws->buff_num + ws->buff_cur - (i)) % ws->buff_num;
|
||||||
|
if (ws->buff[n].valid) count++;
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count == ws->buff_num)
|
||||||
|
{
|
||||||
|
if (count == 1) return MODE_COPY;
|
||||||
|
else if (count == 2) return MODE_DOUBLE;
|
||||||
|
else if (count == 3) return MODE_TRIPLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MODE_FULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
evas_swapper_buffer_idle_flush(Wl_Swapper *ws)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
/* check for valid swapper */
|
||||||
|
if (!ws) return;
|
||||||
|
|
||||||
|
/* loop the swapper's buffers and free them */
|
||||||
|
for (i = 0; i < ws->buff_num; i++)
|
||||||
|
{
|
||||||
|
Wl_Buffer *wb = NULL;
|
||||||
|
|
||||||
|
/* try to get out Wl_Buffer struct */
|
||||||
|
if (!(wb = (&(ws->buff[i])))) continue;
|
||||||
|
|
||||||
|
/* if this buffer is not valid, then unmap data */
|
||||||
|
if (!wb->valid) _evas_swapper_buffer_free(ws, wb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* local functions */
|
||||||
|
static Eina_Bool
|
||||||
|
_evas_swapper_buffer_new(Wl_Swapper *ws, Wl_Buffer *wb)
|
||||||
|
{
|
||||||
|
/* struct drm_mode_create_dumb carg; */
|
||||||
|
/* struct drm_mode_map_dumb marg; */
|
||||||
|
/* struct drm_mode_destroy_dumb darg; */
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
wb->w = ws->w;
|
||||||
|
wb->h = ws->h;
|
||||||
|
|
||||||
|
/* NB: Create drm Dumb FB for software rendering */
|
||||||
|
/* memset(&carg, 0, sizeof(struct drm_mode_create_dumb)); */
|
||||||
|
/* carg.bpp = 32; */
|
||||||
|
/* carg.width = wb->w; */
|
||||||
|
/* carg.height = wb->h; */
|
||||||
|
|
||||||
|
/* ret = drmIoctl(ws->drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &carg); */
|
||||||
|
/* if (ret < 0) */
|
||||||
|
/* { */
|
||||||
|
/* ERR("Failed to create dumb buffer: %m"); */
|
||||||
|
/* return EINA_FALSE; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* ret = drmModeAddFB(ws->drm_fd, wb->w, wb->h, 24, 32, */
|
||||||
|
/* carg.pitch, carg.handle, &wb->id); */
|
||||||
|
/* if (ret) */
|
||||||
|
/* { */
|
||||||
|
/* ERR("Failed to add fb: %m"); */
|
||||||
|
/* goto err; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* memset(&marg, 0, sizeof(struct drm_mode_map_dumb)); */
|
||||||
|
/* marg.handle = carg.handle; */
|
||||||
|
/* ret = drmIoctl(ws->drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &marg); */
|
||||||
|
/* if (ret) */
|
||||||
|
/* { */
|
||||||
|
/* ERR("Failed to Map fb: %m"); */
|
||||||
|
/* goto err_map; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* wb->data = mmap(0, carg.size, PROT_WRITE | PROT_READ, MAP_SHARED, */
|
||||||
|
/* ws->drm_fd, marg.offset); */
|
||||||
|
/* memset(wb->data, 0, carg.size); */
|
||||||
|
|
||||||
|
/* wb->hdl = marg.handle; */
|
||||||
|
|
||||||
|
wb->ws = ws;
|
||||||
|
|
||||||
|
/* return allocated buffer */
|
||||||
|
return EINA_TRUE;
|
||||||
|
|
||||||
|
/* err_map: */
|
||||||
|
/* drmModeRmFB(ws->drm_fd, wb->id); */
|
||||||
|
/* err: */
|
||||||
|
/* memset(&darg, 0, sizeof(darg)); */
|
||||||
|
/* darg.handle = carg.handle; */
|
||||||
|
/* drmIoctl(ws->drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &darg); */
|
||||||
|
/* return EINA_FALSE; */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_evas_swapper_buffer_free(Wl_Swapper *ws, Wl_Buffer *wb)
|
||||||
|
{
|
||||||
|
/* struct drm_mode_destroy_dumb darg; */
|
||||||
|
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
/* check for valid buffer */
|
||||||
|
if ((!wb) || (wb->valid)) return;
|
||||||
|
|
||||||
|
/* unmap the buffer data */
|
||||||
|
/* if (wb->data) munmap(wb->data, wb->size); */
|
||||||
|
/* wb->data = NULL; */
|
||||||
|
|
||||||
|
/* kill the wl_buffer */
|
||||||
|
/* if (wb->id) drmModeRmFB(ws->drm_fd, wb->id); */
|
||||||
|
|
||||||
|
/* if (wb->buffer) wl_buffer_destroy(wb->buffer); */
|
||||||
|
/* wb->buffer = NULL; */
|
||||||
|
|
||||||
|
/* memset(&darg, 0, sizeof(darg)); */
|
||||||
|
/* darg.handle = wb->hdl; */
|
||||||
|
/* drmIoctl(ws->drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &darg); */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_evas_swapper_buffer_put(Wl_Swapper *ws, Wl_Buffer *wb, Eina_Rectangle *rects, unsigned int count)
|
||||||
|
{
|
||||||
|
Eina_Rectangle *rect;
|
||||||
|
|
||||||
|
LOGFN(__FILE__, __LINE__, __FUNCTION__);
|
||||||
|
|
||||||
|
/* check for valid swapper */
|
||||||
|
if (!ws) return;
|
||||||
|
|
||||||
|
/* make sure swapper has a surface */
|
||||||
|
/* if (!ws->surface) return; */
|
||||||
|
|
||||||
|
/* check for valid buffer */
|
||||||
|
if (!wb) return;
|
||||||
|
|
||||||
|
/* make sure buffer has mapped data */
|
||||||
|
if ((!wb->data))
|
||||||
|
{
|
||||||
|
/* call function to mmap buffer data */
|
||||||
|
if (!_evas_swapper_buffer_new(ws, wb))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rect = eina_rectangle_new(0, 0, 0, 0);
|
||||||
|
if ((rects) && (count > 0))
|
||||||
|
{
|
||||||
|
unsigned int i = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
eina_rectangle_union(rect, &rects[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Eina_Rectangle r;
|
||||||
|
|
||||||
|
r.x = 0; r.y = 0;
|
||||||
|
r.w = wb->w; r.h = wb->h;
|
||||||
|
|
||||||
|
eina_rectangle_union(rect, &r);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* surface attach */
|
||||||
|
if (ws->buffer_sent != wb)
|
||||||
|
{
|
||||||
|
DBG("Send Buffer !!");
|
||||||
|
/* wl_surface_attach(ws->surface, wb->buffer, ws->dx, ws->dy); */
|
||||||
|
ws->dx = 0;
|
||||||
|
ws->dy = 0;
|
||||||
|
ws->buffer_sent = wb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* wl_surface_damage(ws->surface, rect->x, rect->y, rect->w, rect->h); */
|
||||||
|
|
||||||
|
/* surface commit */
|
||||||
|
/* wl_surface_commit(ws->surface); */
|
||||||
|
}
|
Loading…
Reference in New Issue