aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am4
-rw-r--r--configure.ac17
-rw-r--r--m4/evas_check_engine.m443
-rw-r--r--pc/.gitignore1
-rw-r--r--pc/evas-eglfs.pc.in3
-rw-r--r--src/Makefile_Evas.am42
-rw-r--r--src/modules/evas/engines/eglfs/Evas_Engine_Eglfs.h45
-rw-r--r--src/modules/evas/engines/eglfs/evas_engine.c1254
-rw-r--r--src/modules/evas/engines/eglfs/evas_engine.h133
-rw-r--r--src/modules/evas/engines/eglfs/evas_outbuf.c703
10 files changed, 2245 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am
index 8206b161b8..ef7c8a4292 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -188,6 +188,10 @@ if BUILD_ENGINE_FB
pkgconfig_DATA += pc/evas-fb.pc
endif
+if BUILD_ENGINE_EGLFS
+pkgconfig_DATA += pc/evas-eglfs.pc
+endif
+
if BUILD_ENGINE_BUFFER
pkgconfig_DATA += pc/evas-software-buffer.pc
endif
diff --git a/configure.ac b/configure.ac
index 0768936675..da7e01283b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1624,6 +1624,19 @@ AC_ARG_ENABLE([fb],
],
[want_fb="no"])
+# Eglfs
+AC_ARG_ENABLE([eglfs],
+ [AS_HELP_STRING([--enable-eglfs],[enable hardware accelerated framebuffer access. @<:@default=disabled@:>@])],
+ [
+ if test "x${enableval}" = "xyes" ; then
+ want_eglfs="yes"
+ want_fb="yes"
+ else
+ want_eglfs="no"
+ fi
+ ],
+ [want_eglfs="no"])
+
# SDL
AC_ARG_ENABLE([sdl],
[AS_HELP_STRING([--enable-sdl],[enable SDL support. @<:@default=disabled@:>@])],
@@ -2080,6 +2093,7 @@ EVAS_CHECK_ENGINE([wayland-egl], [${want_evas_engine_wayland_egl}], [no], [Wayla
EVAS_CHECK_ENGINE([wayland-shm], [${want_wayland}], [no], [Wayland Shm])
EVAS_CHECK_ENGINE([drm], [${want_drm}], [no], [Drm])
EVAS_CHECK_ENGINE([gl-drm], [${want_gl_drm}], [no], [OpenGL Drm])
+EVAS_CHECK_ENGINE([eglfs], [${want_eglfs}], [no], [OpenGL Fb])
# Software XCB
@@ -2236,6 +2250,7 @@ if test "x$have_evas_engine_gl_xlib" = "xyes" || \
test "x$have_evas_engine_gl_sdl" = "xyes" || \
test "x$have_evas_engine_gl_cocoa" = "xyes" || \
test "x$have_evas_engine_gl_drm" = "xyes" || \
+ test "x$have_evas_engine_eglfs" = "xyes" || \
test "x$have_evas_engine_wayland_egl" = "xyes"; then
have_evas_engine_gl_common="yes"
fi
@@ -2244,6 +2259,7 @@ if test "x$have_evas_engine_gl_xlib" = "xstatic" || \
test "x$have_evas_engine_gl_sdl" = "xstatic" || \
test "x$have_evas_engine_gl_cocoa" = "xstatic" || \
test "x$have_evas_engine_gl_drm" = "xstatic" || \
+ test "x$have_evas_engine_eglfs" = "xstatic" || \
test "x$have_evas_engine_wayland_egl" = "xstatic"; then
have_evas_engine_gl_common="yes"
have_static_evas_engine_gl_common="yes"
@@ -5095,6 +5111,7 @@ pc/eo-js.pc
pc/efl.pc
pc/efl-cxx.pc
pc/evas-fb.pc
+pc/evas-eglfs.pc
pc/evas-opengl-x11.pc
pc/evas-opengl-sdl.pc
pc/evas-opengl-cocoa.pc
diff --git a/m4/evas_check_engine.m4 b/m4/evas_check_engine.m4
index 42ecc892d8..e38589c48a 100644
--- a/m4/evas_check_engine.m4
+++ b/m4/evas_check_engine.m4
@@ -661,6 +661,49 @@ AS_IF([test "x${have_dep}" = "xyes"], [$4], [$5])
])
+dnl use: EVAS_CHECK_ENGINE_DEP_EGLFS(engine, simple, want_static[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+
+AC_DEFUN([EVAS_CHECK_ENGINE_DEP_EGLFS],
+[
+
+requirement=""
+have_dep="no"
+have_hw_dep="no"
+evas_engine_[]$1[]_cflags=""
+evas_engine_[]$1[]_libs=""
+
+if test "x${with_opengl}" = "xes" ; then
+ gl_library="glesv2"
+else
+ AC_MSG_ERROR([We do not support Eglfs without OpenGL ES. Please consider OpenGL ES if you want to use it.])
+fi
+
+PKG_CHECK_EXISTS([egl >= 7.10 ${gl_library}],
+ [
+ have_dep="yes"
+ requirement="egl >= 7.10 ${gl_library}"
+ ],
+ [have_dep="no"])
+
+if test "x${have_dep}" = "xyes" ; then
+ if test "x$3" = "xstatic" ; then
+ requirements_pc_evas="${requirement} ${requirements_pc_evas}"
+ requirements_pc_deps_evas="${requirement} ${requirements_pc_deps_evas}"
+ else
+ PKG_CHECK_MODULES([EGLFS], [${requirement}])
+ evas_engine_[]$1[]_cflags="${EGLFS_CFLAGS}"
+ evas_engine_[]$1[]_libs="${EGLFS_LIBS}"
+ evas_engine_gl_common_libs="$evas_engine_[]$1[]_libdirs -lGLESv2 -lm -lEGL"
+ fi
+fi
+
+AC_SUBST([evas_engine_$1_cflags])
+AC_SUBST([evas_engine_$1_libs])
+
+AS_IF([test "x${have_dep}" = "xyes"], [$4], [$5])
+
+])
+
dnl use: EVAS_ENGINE(name, want_engine, [DEPENDENCY-CHECK-CODE])
dnl
diff --git a/pc/.gitignore b/pc/.gitignore
index c3422d5f99..ee97ef9620 100644
--- a/pc/.gitignore
+++ b/pc/.gitignore
@@ -44,6 +44,7 @@
/ethumb_client.pc
/evas-drm.pc
/evas-fb.pc
+/evas-eglfs.pc
/evas-opengl-cocoa.pc
/evas-opengl-sdl.pc
/evas-opengl-x11.pc
diff --git a/pc/evas-eglfs.pc.in b/pc/evas-eglfs.pc.in
new file mode 100644
index 0000000000..c8dfc5c8c3
--- /dev/null
+++ b/pc/evas-eglfs.pc.in
@@ -0,0 +1,3 @@
+Name: evas-eglfs
+Description: Evas eglfs engine
+Version: @VERSION@
diff --git a/src/Makefile_Evas.am b/src/Makefile_Evas.am
index 4f5656470b..47642aa300 100644
--- a/src/Makefile_Evas.am
+++ b/src/Makefile_Evas.am
@@ -874,6 +874,9 @@ endif
if BUILD_ENGINE_GL_DRM
modules_evas_engines_gl_common_libevas_engine_gl_common_la_CPPFLAGS += @evas_engine_gl_drm_cflags@
endif
+if BUILD_ENGINE_EGLFS
+modules_evas_engines_gl_common_libevas_engine_gl_common_la_CPPFLAGS += @evas_engine_eglfs_cflags@
+endif
modules_evas_engines_gl_common_libevas_engine_gl_common_la_LIBADD = @USE_EVAS_LIBS@
modules_evas_engines_gl_common_libevas_engine_gl_common_la_DEPENDENCIES = @USE_EVAS_INTERNAL_LIBS@
modules_evas_engines_gl_common_libevas_engine_gl_common_la_LDFLAGS = -module @EFL_LTMODULE_FLAGS@
@@ -1330,6 +1333,45 @@ modules_evas_engines_gl_drm_module_la_LIBTOOLFLAGS = --tag=disable-static
endif
endif
+if BUILD_ENGINE_EGLFS
+dist_installed_evasmainheaders_DATA += modules/evas/engines/eglfs/Evas_Engine_Eglfs.h
+EGLFS_SOURCES = \
+modules/evas/engines/eglfs/evas_outbuf.c \
+modules/evas/engines/eglfs/evas_engine.c \
+modules/evas/engines/eglfs/evas_engine.h \
+modules/evas/engines/eglfs/Evas_Engine_Eglfs.h
+if EVAS_STATIC_BUILD_EGLFS
+lib_evas_libevas_la_SOURCES += $(EGLFS_SOURCES)
+lib_evas_libevas_la_CPPFLAGS += @evas_engine_eglfs_cflags@
+lib_evas_libevas_la_LIBADD += @evas_engine_eglfs_libs@
+else
+engineeglfspkgdir = $(libdir)/evas/modules/engines/eglfs/$(MODULE_ARCH)
+engineeglfspkg_LTLIBRARIES = modules/evas/engines/eglfs/module.la
+
+# Workaround for broken parallel install support in automake (relink issue)
+# http://debbugs.gnu.org/cgi/bugreport.cgi?bug=7328
+install_engineeglfspkgLTLIBRARIES = install-engineeglfspkgLTLIBRARIES
+$(install_engineeglfspkgLTLIBRARIES): install-libLTLIBRARIES
+
+modules_evas_engines_eglfs_module_la_SOURCES = $(EGLFS_SOURCES)
+modules_evas_engines_eglfs_module_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
+-I$(top_srcdir)/src/lib/evas/include \
+-I$(top_srcdir)/src/lib/evas/cserve2 \
+-I$(top_srcdir)/src/modules/evas/engines/eglfs \
+@EVAS_CFLAGS@ \
+@ECORE_DRM_CFLAGS@ \
+@evas_engine_eglfs_cflags@
+modules_evas_engines_eglfs_module_la_LIBADD = \
+@USE_EVAS_LIBS@ \
+@USE_ECORE_DRM_LIBS@ \
+@evas_engine_eglfs_libs@ \
+@USE_EEZE_INTERNAL_LIBS@
+modules_evas_engines_eglfs_module_la_DEPENDENCIES = @USE_EVAS_INTERNAL_LIBS@ @USE_EEZE_INTERNAL_LIBS@ @USE_ECORE_DRM_INTERNAL_LIBS@
+modules_evas_engines_eglfs_module_la_LDFLAGS = -module @EFL_LTMODULE_FLAGS@
+modules_evas_engines_eglfs_module_la_LIBTOOLFLAGS = --tag=disable-static
+endif
+endif
+
### Cserve2 binary
if EVAS_CSERVE2
diff --git a/src/modules/evas/engines/eglfs/Evas_Engine_Eglfs.h b/src/modules/evas/engines/eglfs/Evas_Engine_Eglfs.h
new file mode 100644
index 0000000000..7472c7b306
--- /dev/null
+++ b/src/modules/evas/engines/eglfs/Evas_Engine_Eglfs.h
@@ -0,0 +1,45 @@
+#ifndef _EVAS_ENGINE_EGLFS_H
+# define _EVAS_ENGINE_EGLFS_H
+
+typedef enum _Evas_Engine_Info_Eglfs_Swap_Mode
+{
+ EVAS_ENGINE_EGLFS_SWAP_MODE_AUTO = 0,
+ EVAS_ENGINE_EGLFS_SWAP_MODE_FULL = 1,
+ EVAS_ENGINE_EGLFS_SWAP_MODE_COPY = 2,
+ EVAS_ENGINE_EGLFS_SWAP_MODE_DOUBLE = 3,
+ EVAS_ENGINE_EGLFS_SWAP_MODE_TRIPLE = 4,
+ EVAS_ENGINE_EGLFS_SWAP_MODE_QUADRUPLE = 5
+} Evas_Engine_Info_Eglfs_Swap_Mode;
+
+typedef struct _Evas_Engine_Info_Eglfs Evas_Engine_Info_Eglfs;
+
+struct _Evas_Engine_Info_Eglfs
+{
+ /* PRIVATE - don't mess with this baby or evas will poke its tongue out */
+ /* at you and make nasty noises */
+ Evas_Engine_Info magic;
+
+ struct
+ {
+ unsigned int rotation, depth;
+ unsigned int crtc_id, conn_id, buffer_id;
+ unsigned int format, flags;
+
+ Eina_Bool destination_alpha : 1;
+ Eina_Bool vsync : 1;
+ Eina_Bool indirect : 1;
+ unsigned char swap_mode : 4;
+ } info;
+
+ struct
+ {
+ void (*pre_swap)(void *data, Evas *evas);
+ void (*post_swap)(void *data, Evas *evas);
+ void *data;
+ } callback;
+
+ /* non-blocking or blocking mode */
+ Evas_Engine_Render_Mode render_mode;
+};
+
+#endif
diff --git a/src/modules/evas/engines/eglfs/evas_engine.c b/src/modules/evas/engines/eglfs/evas_engine.c
new file mode 100644
index 0000000000..c408375c96
--- /dev/null
+++ b/src/modules/evas/engines/eglfs/evas_engine.c
@@ -0,0 +1,1254 @@
+#include "config.h"
+#include "evas_engine.h"
+#include <wayland-client.h>
+
+#ifdef HAVE_DLSYM
+# include <dlfcn.h> /* dlopen,dlclose,etc */
+#else
+# error eglfs should not get compiled if dlsym is not found on the system!
+#endif
+
+#ifdef EVAS_CSERVE2
+# include "evas_cs2_private.h"
+#endif
+
+#define EVAS_GL_NO_GL_H_CHECK 1
+#include "Evas_GL.h"
+
+#define EVAS_GL_UPDATE_TILE_SIZE 16
+
+#ifndef EGL_NATIVE_PIXMAP_KHR
+# define EGL_NATIVE_PIXMAP_KHR 0x30b0
+#endif
+
+/* external variables */
+int _evas_engine_eglfs_log_dom = -1;
+int _extn_have_buffer_age = 1;
+
+/* local variables */
+static Eina_Bool initted = EINA_FALSE;
+static int gl_wins = 0;
+
+/* local structures */
+typedef struct _Render_Engine Render_Engine;
+struct _Render_Engine
+{
+ Render_Engine_GL_Generic generic;
+};
+
+typedef struct _Native Native;
+struct _Native
+{
+ Evas_Native_Surface ns;
+ struct wl_buffer *wl_buf;
+ void *egl_surface;
+};
+
+/* local function prototype types */
+typedef void (*_eng_fn)(void);
+typedef _eng_fn (*glsym_func_eng_fn)();
+typedef void (*glsym_func_void)();
+typedef void *(*glsym_func_void_ptr)();
+typedef int (*glsym_func_int)();
+typedef unsigned int (*glsym_func_uint)();
+typedef const char *(*glsym_func_const_char_ptr)();
+
+/* external dynamic loaded Evas_GL function pointers */
+Evas_GL_Common_Image_Call glsym_evas_gl_common_image_ref = NULL;
+Evas_GL_Common_Image_Call glsym_evas_gl_common_image_unref = NULL;
+Evas_GL_Common_Image_Call glsym_evas_gl_common_image_free = NULL;
+Evas_GL_Common_Image_Call glsym_evas_gl_common_image_native_disable = NULL;
+Evas_GL_Common_Image_Call glsym_evas_gl_common_image_native_enable = NULL;
+Evas_GL_Common_Image_New_From_Data glsym_evas_gl_common_image_new_from_data = NULL;
+Evas_GL_Common_Context_Call glsym_evas_gl_common_image_all_unload = NULL;
+Evas_GL_Preload glsym_evas_gl_preload_init = NULL;
+Evas_GL_Preload glsym_evas_gl_preload_shutdown = NULL;
+EVGL_Engine_Call glsym_evgl_engine_shutdown = NULL;
+EVGL_Current_Native_Context_Get_Call glsym_evgl_current_native_context_get = NULL;
+Evas_Gl_Symbols glsym_evas_gl_symbols = NULL;
+
+Evas_GL_Common_Context_New glsym_evas_gl_common_context_new = NULL;
+Evas_GL_Common_Context_Call glsym_evas_gl_common_context_flush = NULL;
+Evas_GL_Common_Context_Call glsym_evas_gl_common_context_free = NULL;
+Evas_GL_Common_Context_Call glsym_evas_gl_common_context_use = NULL;
+Evas_GL_Common_Context_Call glsym_evas_gl_common_context_newframe = NULL;
+Evas_GL_Common_Context_Call glsym_evas_gl_common_context_done = NULL;
+Evas_GL_Common_Context_Resize_Call glsym_evas_gl_common_context_resize = NULL;
+Evas_GL_Common_Buffer_Dump_Call glsym_evas_gl_common_buffer_dump = NULL;
+Evas_GL_Preload_Render_Call glsym_evas_gl_preload_render_lock = NULL;
+Evas_GL_Preload_Render_Call glsym_evas_gl_preload_render_unlock = NULL;
+Evas_GL_Preload_Render_Call glsym_evas_gl_preload_render_relax = NULL;
+
+glsym_func_void_ptr glsym_evas_gl_common_current_context_get = NULL;
+
+/* dynamic loaded local egl function pointers */
+_eng_fn (*glsym_eglGetProcAddress)(const char *a) = NULL;
+void *(*glsym_eglCreateImage)(EGLDisplay a, EGLContext b, EGLenum c, EGLClientBuffer d, const int *e) = NULL;
+void (*glsym_eglDestroyImage)(EGLDisplay a, void *b) = NULL;
+void (*glsym_glEGLImageTargetTexture2DOES)(int a, void *b) = NULL;
+unsigned int (*glsym_eglSwapBuffersWithDamage)(EGLDisplay a, void *b, const EGLint *d, EGLint c) = NULL;
+unsigned int (*glsym_eglQueryWaylandBufferWL)(EGLDisplay a, struct wl_resource *b, EGLint c, EGLint *d) = NULL;
+
+/* local function prototypes */
+static void gl_symbols(void);
+static void gl_extn_veto(Render_Engine *re);
+
+static void *evgl_eng_display_get(void *data);
+static void *evgl_eng_evas_surface_get(void *data);
+static int evgl_eng_make_current(void *data, void *surface, void *context, int flush);
+static void *evgl_eng_native_window_create(void *data);
+static int evgl_eng_native_window_destroy(void *data, void *native_window);
+static void *evgl_eng_window_surface_create(void *data, void *native_window);
+static int evgl_eng_window_surface_destroy(void *data, void *surface);
+static void *evgl_eng_context_create(void *data, void *share_ctx, Evas_GL_Context_Version version);
+static int evgl_eng_context_destroy(void *data, void *context);
+static const char *evgl_eng_string_get(void *data);
+static void *evgl_eng_proc_address_get(const char *name);
+static int evgl_eng_rotation_angle_get(void *data);
+
+/* function tables - filled in later (func and parent func) */
+static Evas_Func func, pfunc;
+static const EVGL_Interface evgl_funcs =
+{
+ evgl_eng_display_get,
+ evgl_eng_evas_surface_get,
+ evgl_eng_native_window_create,
+ evgl_eng_native_window_destroy,
+ evgl_eng_window_surface_create,
+ evgl_eng_window_surface_destroy,
+ evgl_eng_context_create,
+ evgl_eng_context_destroy,
+ evgl_eng_make_current,
+ evgl_eng_proc_address_get,
+ evgl_eng_string_get,
+ evgl_eng_rotation_angle_get,
+ NULL, // PBuffer
+ NULL, // PBuffer
+ NULL, // OpenGL-ES 1
+ NULL, // OpenGL-ES 1
+ NULL, // OpenGL-ES 1
+ NULL, // native_win_surface_config_get
+};
+
+
+/* local inline functions */
+static inline Outbuf *
+eng_get_ob(Render_Engine *re)
+{
+ return re->generic.software.ob;
+}
+
+/* local functions */
+static void
+gl_symbols(void)
+{
+ static Eina_Bool done = EINA_FALSE;
+
+ if (done) return;
+
+#define LINK2GENERIC(sym) \
+ glsym_##sym = dlsym(RTLD_DEFAULT, #sym);
+
+ // Get function pointer to evas_gl_common that is now provided through the link of GL_Generic.
+ LINK2GENERIC(evas_gl_common_image_all_unload);
+ LINK2GENERIC(evas_gl_common_image_ref);
+ LINK2GENERIC(evas_gl_common_image_unref);
+ LINK2GENERIC(evas_gl_common_image_new_from_data);
+ LINK2GENERIC(evas_gl_common_image_native_disable);
+ LINK2GENERIC(evas_gl_common_image_free);
+ LINK2GENERIC(evas_gl_common_image_native_enable);
+ LINK2GENERIC(evas_gl_common_context_new);
+ LINK2GENERIC(evas_gl_common_context_flush);
+ LINK2GENERIC(evas_gl_common_context_free);
+ LINK2GENERIC(evas_gl_common_context_use);
+ LINK2GENERIC(evas_gl_common_context_newframe);
+ LINK2GENERIC(evas_gl_common_context_done);
+ LINK2GENERIC(evas_gl_common_context_resize);
+ LINK2GENERIC(evas_gl_common_buffer_dump);
+ LINK2GENERIC(evas_gl_preload_render_lock);
+ LINK2GENERIC(evas_gl_preload_render_unlock);
+ LINK2GENERIC(evas_gl_preload_render_relax);
+ LINK2GENERIC(evas_gl_preload_init);
+ LINK2GENERIC(evas_gl_preload_shutdown);
+ LINK2GENERIC(evgl_engine_shutdown);
+ LINK2GENERIC(evas_gl_symbols);
+
+#define FINDSYM(dst, sym, typ) \
+ if (glsym_eglGetProcAddress) { \
+ if (!dst) dst = (typ)glsym_eglGetProcAddress(sym); \
+ } else { \
+ if (!dst) dst = (typ)dlsym(RTLD_DEFAULT, sym); \
+ }
+
+ FINDSYM(glsym_eglGetProcAddress, "eglGetProcAddressKHR", glsym_func_eng_fn);
+ FINDSYM(glsym_eglGetProcAddress, "eglGetProcAddressEXT", glsym_func_eng_fn);
+ FINDSYM(glsym_eglGetProcAddress, "eglGetProcAddressARB", glsym_func_eng_fn);
+ FINDSYM(glsym_eglGetProcAddress, "eglGetProcAddress", glsym_func_eng_fn);
+
+ glsym_evas_gl_symbols((void*)glsym_eglGetProcAddress);
+
+ FINDSYM(glsym_eglCreateImage, "eglCreateImageKHR", glsym_func_void_ptr);
+ FINDSYM(glsym_eglCreateImage, "eglCreateImageEXT", glsym_func_void_ptr);
+ FINDSYM(glsym_eglCreateImage, "eglCreateImageARB", glsym_func_void_ptr);
+ FINDSYM(glsym_eglCreateImage, "eglCreateImage", glsym_func_void_ptr);
+
+ FINDSYM(glsym_eglDestroyImage, "eglDestroyImageKHR", glsym_func_void);
+ FINDSYM(glsym_eglDestroyImage, "eglDestroyImageEXT", glsym_func_void);
+ FINDSYM(glsym_eglDestroyImage, "eglDestroyImageARB", glsym_func_void);
+ FINDSYM(glsym_eglDestroyImage, "eglDestroyImage", glsym_func_void);
+
+ FINDSYM(glsym_glEGLImageTargetTexture2DOES,
+ "glEGLImageTargetTexture2DOES", glsym_func_void);
+
+ FINDSYM(glsym_eglSwapBuffersWithDamage, "eglSwapBuffersWithDamageEXT",
+ glsym_func_uint);
+ FINDSYM(glsym_eglSwapBuffersWithDamage, "eglSwapBuffersWithDamageINTEL",
+ glsym_func_uint);
+ FINDSYM(glsym_eglSwapBuffersWithDamage, "eglSwapBuffersWithDamage",
+ glsym_func_uint);
+
+ FINDSYM(glsym_eglQueryWaylandBufferWL, "eglQueryWaylandBufferWL",
+ glsym_func_uint);
+
+ done = EINA_TRUE;
+}
+
+static void
+gl_extn_veto(Render_Engine *re)
+{
+ const char *str = NULL;
+
+ str = eglQueryString(eng_get_ob(re)->egl.disp, EGL_EXTENSIONS);
+ if (str)
+ {
+ const char *s = NULL;
+
+ if (getenv("EVAS_GL_INFO")) printf("EGL EXTN:\n%s\n", str);
+
+ // Disable Partial Rendering
+ s = getenv("EVAS_GL_PARTIAL_DISABLE");
+ if ((s) && (atoi(s)))
+ {
+ _extn_have_buffer_age = 0;
+ glsym_eglSwapBuffersWithDamage = NULL;
+ }
+ if (!strstr(str, "EGL_EXT_buffer_age")) _extn_have_buffer_age = 0;
+ if (!strstr(str, "EGL_EXT_swap_buffers_with_damage"))
+ glsym_eglSwapBuffersWithDamage = NULL;
+ }
+ else
+ {
+ if (getenv("EVAS_GL_INFO")) printf("NO EGL EXTN!\n");
+ _extn_have_buffer_age = 0;
+ }
+}
+
+static void *
+evgl_eng_display_get(void *data)
+{
+ Render_Engine *re;
+
+ re = (Render_Engine *)data;
+ if (!re)
+ {
+ ERR("Invalid Render Engine Data!");
+ return NULL;
+ }
+
+ if (eng_get_ob(re))
+ return (void *)eng_get_ob(re)->egl.disp;
+ else
+ return NULL;
+}
+
+static void *
+evgl_eng_evas_surface_get(void *data)
+{
+ Render_Engine *re;
+
+ re = (Render_Engine *)data;
+ if (!re)
+ {
+ ERR("Invalid Render Engine Data!");
+ return NULL;
+ }
+
+ if (eng_get_ob(re))
+ return (void *)eng_get_ob(re)->egl.surface[0];
+ else
+ return NULL;
+}
+
+static int
+evgl_eng_make_current(void *data, void *surface, void *context, int flush)
+{
+ Render_Engine *re;
+ EGLContext ctx;
+ EGLSurface sfc;
+ EGLDisplay dpy;
+ int ret = 0;
+
+ re = (Render_Engine *)data;
+ if (!re)
+ {
+ ERR("Invalid Render Engine Data!");
+ return 0;
+ }
+
+ dpy = eng_get_ob(re)->egl.disp;
+ ctx = (EGLContext)context;
+ sfc = (EGLSurface)surface;
+
+ if ((!context) && (!surface))
+ {
+ ret = eglMakeCurrent(dpy, EGL_NO_SURFACE,
+ EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ if (!ret)
+ {
+ ERR("eglMakeCurrent() failed! Error Code=%#x", eglGetError());
+ return 0;
+ }
+
+ return 1;
+ }
+
+ if ((eglGetCurrentContext() != ctx) ||
+ (eglGetCurrentSurface(EGL_READ) != sfc) ||
+ (eglGetCurrentSurface(EGL_DRAW) != sfc) )
+ {
+ if (flush) evas_outbuf_use(NULL);
+
+ ret = eglMakeCurrent(dpy, sfc, sfc, ctx);
+ if (!ret)
+ {
+ ERR("eglMakeCurrent() failed! Error Code=%#x", eglGetError());
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static void _hwc_present_cb(void *user_data, struct ANativeWindow *window,
+ struct ANativeWindowBuffer *buffer)
+{
+
+}
+
+static void *
+evgl_eng_native_window_create(void *data)
+{
+ Render_Engine *re;
+ Evas_Engine_Info_Eglfs *info;
+ struct ANativeWindow *native_window;
+
+ re = (Render_Engine *)data;
+ if (!re)
+ {
+ ERR("Invalid Render Engine Data!");
+ return NULL;
+ }
+
+ info = eng_get_ob(re)->info;
+ if (!info)
+ {
+ ERR("Invalid Evas Engine Eglfs Info!");
+ return NULL;
+ }
+ EGLNativeWindowType win;
+ win = create_hwcomposernativewindow();
+ return (void *)win;
+}
+
+static int
+evgl_eng_native_window_destroy(void *data, void *native_window)
+{
+ Render_Engine *re = (Render_Engine *)data;
+
+ if (!re)
+ {
+ ERR("Invalid Render Engine Data!");
+ return 0;
+ }
+
+ if (!native_window)
+ {
+ ERR("Invalid native surface.");
+ return 0;
+ }
+
+ HWCNativeWindowDestroy(native_window);
+
+ return 1;
+}
+
+static void *
+evgl_eng_window_surface_create(void *data, void *native_window)
+{
+ Render_Engine *re;
+ EGLSurface surface = EGL_NO_SURFACE;
+
+ re = (Render_Engine *)data;
+ if (!re)
+ {
+ ERR("Invalid Render Engine Data!");
+ return NULL;
+ }
+
+ // Create resource surface for EGL
+ surface = eglCreateWindowSurface(eng_get_ob(re)->egl.disp,
+ eng_get_ob(re)->egl.config,
+ (EGLNativeWindowType)native_window,
+ NULL);
+ if (!surface)
+ {
+ ERR("Creating window surface failed. Error: %#x.", eglGetError());
+ return NULL;
+ }
+
+ return (void *)surface;
+}
+
+static int
+evgl_eng_window_surface_destroy(void *data, void *surface)
+{
+ Render_Engine *re;
+ EGLBoolean ret = EGL_FALSE;
+
+ re = (Render_Engine *)data;
+ if (!re)
+ {
+ ERR("Invalid Render Engine Data!");
+ return 0;
+ }
+
+ if (!surface)
+ {
+ ERR("Invalid surface.");
+ return 0;
+ }
+
+ ret = eglDestroySurface(eng_get_ob(re)->egl.disp, (EGLSurface)surface);
+ if (ret == EGL_TRUE) return 1;
+
+ return 0;
+}
+
+static void *
+evgl_eng_context_create(void *data, void *share_ctx, Evas_GL_Context_Version version)
+{
+ Render_Engine *re;
+ EGLContext context = EGL_NO_CONTEXT;
+ int context_attrs[3];
+
+ re = (Render_Engine *)data;
+ if (!re)
+ {
+ ERR("Invalid Render Engine Data!");
+ return NULL;
+ }
+
+ if (version != EVAS_GL_GLES_2_X)
+ {
+ ERR("This engine only supports OpenGL-ES 2.0 contexts for now!");
+ return NULL;
+ }
+
+ context_attrs[0] = EGL_CONTEXT_CLIENT_VERSION;
+ context_attrs[1] = 2;
+ context_attrs[2] = EGL_NONE;
+
+ // Share context already assumes that it's sharing with evas' context
+ if (share_ctx)
+ {
+ context = eglCreateContext(eng_get_ob(re)->egl.disp,
+ eng_get_ob(re)->egl.config,
+ (EGLContext)share_ctx,
+ context_attrs);
+ }
+ else
+ {
+ context = eglCreateContext(eng_get_ob(re)->egl.disp,
+ eng_get_ob(re)->egl.config,
+ eng_get_ob(re)->egl.context[0], // Evas' GL Context
+ context_attrs);
+ }
+
+ if (!context)
+ {
+ ERR("eglMakeCurrent() failed! Error Code=%#x", eglGetError());
+ return NULL;
+ }
+
+ return (void *)context;
+}
+
+static int
+evgl_eng_context_destroy(void *data, void *context)
+{
+ Render_Engine *re;
+ EGLBoolean ret = EGL_FALSE;
+
+ re = (Render_Engine *)data;
+ if ((!re) || (!context))
+ {
+ ERR("Invalid Render Input Data. Engine: %p, Context: %p",
+ data, context);
+ return 0;
+ }
+
+ ret = eglDestroyContext(eng_get_ob(re)->egl.disp, (EGLContext)context);
+ if (ret == EGL_TRUE) return 1;
+
+ return 0;
+}
+
+static const char *
+evgl_eng_string_get(void *data)
+{
+ Render_Engine *re;
+
+ re = (Render_Engine *)data;
+ if (!re)
+ {
+ ERR("Invalid Render Engine Data!");
+ return NULL;
+ }
+
+ return eglQueryString(eng_get_ob(re)->egl.disp, EGL_EXTENSIONS);
+}
+
+static void *
+evgl_eng_proc_address_get(const char *name)
+{
+ if (glsym_eglGetProcAddress) return glsym_eglGetProcAddress(name);
+ return dlsym(RTLD_DEFAULT, name);
+}
+
+static int
+evgl_eng_rotation_angle_get(void *data)
+{
+ Render_Engine *re;
+
+ re = (Render_Engine *)data;
+ if (!re)
+ {
+ ERR("Invalid Render Engine Data!");
+ return 0;
+ }
+
+ if ((eng_get_ob(re)) && (eng_get_ob(re)->gl_context))
+ return eng_get_ob(re)->gl_context->rot;
+ else
+ {
+ ERR("Unable to retrieve rotation angle.");
+ return 0;
+ }
+}
+
+static Eina_Bool
+eng_preload_make_current(void *data, void *doit)
+{
+ Outbuf *ob;
+
+ ob = (Outbuf *)data;
+ if (!ob) return EINA_FALSE;
+
+ if (doit)
+ {
+ if (!eglMakeCurrent(ob->egl.disp, ob->egl.surface[0],
+ ob->egl.surface[0], ob->egl.context[0]))
+ return EINA_FALSE;
+ }
+ else
+ {
+ if (!eglMakeCurrent(ob->egl.disp, EGL_NO_SURFACE,
+ EGL_NO_SURFACE, EGL_NO_CONTEXT))
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+static void
+_re_winfree(Render_Engine *re)
+{
+ if (!re) return;
+ if (!eng_get_ob(re)->surf) return;
+ glsym_evas_gl_preload_render_relax(eng_preload_make_current, eng_get_ob(re));
+ evas_outbuf_unsurf(eng_get_ob(re));
+}
+
+static void
+_native_cb_bind(void *data EINA_UNUSED, void *image)
+{
+ Evas_GL_Image *img;
+ Native *n;
+
+ if (!(img = image)) return;
+ if (!(n = img->native.data)) return;
+
+ if (n->ns.type == EVAS_NATIVE_SURFACE_WL)
+ {
+ if (n->egl_surface)
+ {
+ if (glsym_glEGLImageTargetTexture2DOES)
+ {
+ glsym_glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, n->egl_surface);
+ if (eglGetError() != EGL_SUCCESS)
+ ERR("glEGLImageTargetTexture2DOES() failed.");
+ }
+ else
+ ERR("Try glEGLImageTargetTexture2DOES on EGL with no support");
+ }
+ }
+ else if (n->ns.type == EVAS_NATIVE_SURFACE_OPENGL)
+ glBindTexture(GL_TEXTURE_2D, n->ns.data.opengl.texture_id);
+
+ /* TODO: NATIVE_SURFACE_TBM and NATIVE_SURFACE_EVASGL */
+}
+
+static void
+_native_cb_unbind(void *data EINA_UNUSED, void *image)
+{
+ Evas_GL_Image *img;
+ Native *n;
+
+ if (!(img = image)) return;
+ if (!(n = img->native.data)) return;
+
+ else if (n->ns.type == EVAS_NATIVE_SURFACE_OPENGL)
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ /* TODO: NATIVE_SURFACE_TBM and NATIVE_SURFACE_EVASGL */
+}
+
+static void
+_native_cb_free(void *data, void *image)
+{
+ Render_Engine *re;
+ Outbuf *ob;
+ Evas_GL_Image *img;
+ Native *n;
+ uint32_t texid;
+ void *wlid;
+
+ if (!(re = (Render_Engine *)data)) return;
+ if (!(img = image)) return;
+ if (!(n = img->native.data)) return;
+ if (!(ob = eng_get_ob(re))) return;
+
+ if (n->ns.type == EVAS_NATIVE_SURFACE_WL)
+ {
+ wlid = (void*)n->wl_buf;
+ eina_hash_del(ob->gl_context->shared->native_wl_hash, &wlid, img);
+ if (n->egl_surface)
+ {
+ if (glsym_eglDestroyImage)
+ {
+ glsym_eglDestroyImage(ob->egl.disp, n->egl_surface);
+ if (eglGetError() != EGL_SUCCESS)
+ ERR("eglDestroyImage() failed.");
+ }
+ else
+ ERR("Try eglDestroyImage on EGL with no support");
+ }
+ }
+ else if (n->ns.type == EVAS_NATIVE_SURFACE_OPENGL)
+ {
+ texid = n->ns.data.opengl.texture_id;
+ eina_hash_del(ob->gl_context->shared->native_tex_hash, &texid, img);
+ }
+
+ img->native.data = NULL;
+ img->native.func.data = NULL;
+ img->native.func.bind = NULL;
+ img->native.func.unbind = NULL;
+ img->native.func.free = NULL;
+
+ free(n);
+}
+
+/* engine specific override functions */
+static void *
+eng_info(Evas *eo_e EINA_UNUSED)
+{
+ Evas_Engine_Info_Eglfs *info;
+
+ /* try to allocate space for our engine info */
+ if (!(info = calloc(1, sizeof(Evas_Engine_Info_Eglfs))))
+ return NULL;
+
+ info->magic.magic = rand();
+ info->render_mode = EVAS_RENDER_MODE_BLOCKING;
+
+ return info;
+}
+
+static void
+eng_info_free(Evas *eo_e EINA_UNUSED, void *in)
+{
+ Evas_Engine_Info_Eglfs *info;
+
+ if ((info = (Evas_Engine_Info_Eglfs *)in))
+ free(info);
+}
+
+static int
+eng_setup(Evas *evas, void *in)
+{
+ Evas_Engine_Info_Eglfs *info;
+ Evas_Public_Data *epd;
+ Render_Engine *re;
+ Render_Engine_Swap_Mode swap_mode = MODE_FULL;
+ const char *s = NULL;
+
+ /* try to cast to our engine info structure */
+ if (!(info = (Evas_Engine_Info_Eglfs *)in)) return 0;
+
+ /* try to get the evas public data */
+ if (!(epd = eo_data_scope_get(evas, EVAS_CANVAS_CLASS))) return 0;
+
+ s = getenv("EVAS_GL_SWAP_MODE");
+ if (s)
+ {
+ if ((!strcasecmp(s, "full")) || (!strcasecmp(s, "f")))
+ swap_mode = MODE_FULL;
+ else if ((!strcasecmp(s, "copy")) || (!strcasecmp(s, "c")))
+ swap_mode = MODE_COPY;
+ else if ((!strcasecmp(s, "double")) ||
+ (!strcasecmp(s, "d")) || (!strcasecmp(s, "2")))
+ swap_mode = MODE_DOUBLE;
+ else if ((!strcasecmp(s, "triple")) ||
+ (!strcasecmp(s, "t")) || (!strcasecmp(s, "3")))
+ swap_mode = MODE_TRIPLE;
+ else if ((!strcasecmp(s, "quadruple")) ||
+ (!strcasecmp(s, "q")) || (!strcasecmp(s, "4")))
+ swap_mode = MODE_QUADRUPLE;
+ }
+ else
+ {
+// in most gl implementations - egl and glx here that we care about the TEND
+// to either swap or copy backbuffer and front buffer, but strictly that is
+// not true. technically backbuffer content is totally undefined after a swap
+// and thus you MUST re-render all of it, thus MODE_FULL
+ swap_mode = MODE_FULL;
+// BUT... reality is that lmost every implementation copies or swaps so
+// triple buffer mode can be used as it is a superset of double buffer and
+// copy (though using those explicitly is more efficient). so let's play with
+// triple buffer mdoe as a default and see.
+// re->mode = MODE_TRIPLE;
+// XXX: note - the above seems to break on some older intel chipsets and
+// drivers. it seems we CANT depend on backbuffer staying around. bugger!
+ switch (info->info.swap_mode)
+ {
+ case EVAS_ENGINE_EGLFS_SWAP_MODE_FULL:
+ swap_mode = MODE_FULL;
+ break;
+ case EVAS_ENGINE_EGLFS_SWAP_MODE_COPY:
+ swap_mode = MODE_COPY;
+ break;
+ case EVAS_ENGINE_EGLFS_SWAP_MODE_DOUBLE:
+ swap_mode = MODE_DOUBLE;
+ break;
+ case EVAS_ENGINE_EGLFS_SWAP_MODE_TRIPLE:
+ swap_mode = MODE_TRIPLE;
+ break;
+ case EVAS_ENGINE_EGLFS_SWAP_MODE_QUADRUPLE:
+ swap_mode = MODE_QUADRUPLE;
+ break;
+ default:
+ swap_mode = MODE_AUTO;
+ break;
+ }
+ }
+
+ if (!(re = epd->engine.data.output))
+ {
+ Outbuf *ob;
+ Render_Engine_Merge_Mode merge_mode = MERGE_BOUNDING;
+
+ if (!initted)
+ {
+ evas_common_init();
+ glsym_evas_gl_preload_init();
+ }
+
+ if (!(re = calloc(1, sizeof(Render_Engine)))) return 0;
+
+ /* try to create new outbuf */
+ ob = evas_outbuf_new(info, epd->output.w, epd->output.h, swap_mode);
+ if (!ob)
+ {
+ free(re);
+ return 0;
+ }
+
+ ob->evas = evas;
+
+ if (!evas_render_engine_gl_generic_init(&re->generic, ob,
+ evas_outbuf_buffer_state_get,
+ evas_outbuf_rot_get,
+ evas_outbuf_reconfigure,
+ evas_outbuf_update_region_first_rect,
+ evas_outbuf_update_region_new,
+ evas_outbuf_update_region_push,
+ evas_outbuf_update_region_free,
+ NULL,
+ evas_outbuf_flush,
+ evas_outbuf_free,
+ evas_outbuf_use,
+ evas_outbuf_gl_context_get,
+ evas_outbuf_egl_display_get,
+ evas_outbuf_gl_context_new,
+ evas_outbuf_gl_context_use,
+ &evgl_funcs, ob->w, ob->h))
+ {
+ /* free outbuf */
+
+ evas_outbuf_free(ob);
+ free(re);
+ return 0;
+ }
+
+ epd->engine.data.output = re;
+ gl_wins++;
+
+ s = getenv("EVAS_GL_PARTIAL_MERGE");
+ if (s)
+ {
+ if ((!strcmp(s, "bounding")) || (!strcmp(s, "b")))
+ merge_mode = MERGE_BOUNDING;
+ else if ((!strcmp(s, "full")) || (!strcmp(s, "f")))
+ merge_mode = MERGE_FULL;
+ }
+
+ evas_render_engine_software_generic_merge_mode_set(&re->generic.software, merge_mode);
+
+ if (!initted)
+ {
+ gl_extn_veto(re);
+ initted = EINA_TRUE;
+ }
+ }
+ else
+ {
+ if (eng_get_ob(re) && _re_wincheck(eng_get_ob(re)))
+ {
+ if ((info->info.depth != eng_get_ob(re)->depth) ||
+ (info->info.destination_alpha != eng_get_ob(re)->destination_alpha))
+ {
+ Outbuf *ob, *ob_old;
+
+ ob_old = re->generic.software.ob;
+ re->generic.software.ob = NULL;
+ gl_wins--;
+
+ ob = evas_outbuf_new(info, epd->output.w, epd->output.h, swap_mode);
+ if (!ob)
+ {
+ if (ob_old) evas_outbuf_free(ob_old);
+ free(re);
+ return 0;
+ }
+
+ evas_outbuf_use(ob);
+ if (ob_old) evas_outbuf_free(ob_old);
+
+ ob->evas = evas;
+
+ evas_render_engine_software_generic_update(&re->generic.software, ob,
+ epd->output.w, epd->output.h);
+
+ gl_wins++;
+ }
+ else if ((eng_get_ob(re)->w != epd->output.w) ||
+ (eng_get_ob(re)->h != epd->output.h) ||
+ (info->info.rotation != eng_get_ob(re)->rotation))
+ {
+ evas_outbuf_reconfigure(eng_get_ob(re),
+ epd->output.w, epd->output.h,
+ info->info.rotation,
+ info->info.depth);
+ }
+ }
+ }
+
+ if (!eng_get_ob(re))
+ {
+ free(re);
+ return 0;
+ }
+
+ if (!epd->engine.data.output)
+ {
+ if (eng_get_ob(re))
+ {
+ evas_outbuf_free(eng_get_ob(re));
+ gl_wins--;
+ }
+ free(re);
+ return 0;
+ }
+
+ if (re->generic.software.tb)
+ evas_common_tilebuf_free(re->generic.software.tb);
+ re->generic.software.tb =
+ evas_common_tilebuf_new(epd->output.w, epd->output.h);
+ if (re->generic.software.tb)
+ evas_common_tilebuf_set_tile_size(re->generic.software.tb,
+ TILESIZE, TILESIZE);
+
+ if (re->generic.software.tb)
+ evas_render_engine_software_generic_tile_strict_set(&re->generic.software, EINA_TRUE);
+
+ if (!epd->engine.data.context)
+ {
+ epd->engine.data.context =
+ epd->engine.func->context_new(epd->engine.data.output);
+ }
+
+ evas_outbuf_use(eng_get_ob(re));
+
+ return 1;
+}
+
+static void
+eng_output_free(void *data)
+{
+ Render_Engine *re;
+
+ re = (Render_Engine *)data;
+ if (re)
+ {
+ glsym_evas_gl_preload_render_relax(eng_preload_make_current, eng_get_ob(re));
+
+ if (gl_wins == 1) glsym_evgl_engine_shutdown(re);
+
+ /* NB: evas_render_engine_software_generic_clean() frees ob */
+ evas_render_engine_software_generic_clean(&re->generic.software);
+
+ gl_wins--;
+
+ free(re);
+ }
+
+ if ((initted == EINA_TRUE) && (gl_wins == 0))
+ {
+ glsym_evas_gl_preload_shutdown();
+ evas_common_shutdown();
+ initted = EINA_FALSE;
+ }
+}
+
+static Eina_Bool
+eng_canvas_alpha_get(void *data, void *info EINA_UNUSED)
+{
+ Render_Engine *re;
+
+ re = (Render_Engine *)data;
+ if (!re) return EINA_FALSE;
+
+ return eng_get_ob(re)->destination_alpha;
+}
+
+static void
+eng_output_dump(void *data)
+{
+ Render_Engine *re;
+
+ re = (Render_Engine *)data;
+ if (!re) return;
+
+ evas_common_image_image_all_unload();
+ evas_common_font_font_all_unload();
+ glsym_evas_gl_common_image_all_unload(eng_get_ob(re)->gl_context);
+ _re_winfree(re);
+}
+
+static void *
+eng_image_native_set(void *data, void *image, void *native)
+{
+ Render_Engine *re;
+ Outbuf *ob;
+ Native *n;
+ Evas_Native_Surface *ns;
+ Evas_GL_Image *img, *img2;
+ unsigned int tex = 0, fbo = 0;
+ uint32_t texid;
+ void *wlid, *wl_buf = NULL;
+
+ re = (Render_Engine *)data;
+ if (!re) return NULL;
+
+ ob = eng_get_ob(re);
+ if (!ob) return NULL;
+
+ ns = native;
+
+ if (!(img = image))
+ {
+ if ((ns) && (ns->type == EVAS_NATIVE_SURFACE_OPENGL))
+ {
+ img =
+ glsym_evas_gl_common_image_new_from_data(ob->gl_context,
+ ns->data.opengl.w,
+ ns->data.opengl.h,
+ NULL, 1,
+ EVAS_COLORSPACE_ARGB8888);
+ }
+ else
+ return NULL;
+ }
+
+ if (ns)
+ {
+ if (ns->type == EVAS_NATIVE_SURFACE_WL)
+ {
+ wl_buf = ns->data.wl.legacy_buffer;
+ if (img->native.data)
+ {
+ Evas_Native_Surface *ens;
+
+ ens = img->native.data;
+ if (ens->data.wl.legacy_buffer == wl_buf)
+ return img;
+ }
+ }
+ else if (ns->type == EVAS_NATIVE_SURFACE_OPENGL)
+ {
+ tex = ns->data.opengl.texture_id;
+ fbo = ns->data.opengl.framebuffer_id;
+ if (img->native.data)
+ {
+ Evas_Native_Surface *ens;
+
+ ens = img->native.data;
+ if ((ens->data.opengl.texture_id == tex) &&
+ (ens->data.opengl.framebuffer_id == fbo))
+ return img;
+ }
+ }
+ }
+
+ if ((!ns) && (!img->native.data)) return img;
+
+ evas_outbuf_use(ob);
+
+ if (img->native.data)
+ {
+ if (img->native.func.free)
+ img->native.func.free(img->native.func.data, img);
+ glsym_evas_gl_common_image_native_disable(img);
+ }
+
+ if (!ns) return img;
+
+ if (ns->type == EVAS_NATIVE_SURFACE_WL)
+ {
+ wlid = wl_buf;
+ img2 = eina_hash_find(ob->gl_context->shared->native_wl_hash, &wlid);
+ if (img2 == img) return img;
+ if (img2)
+ {
+ if((n = img2->native.data))
+ {
+ glsym_evas_gl_common_image_ref(img2);
+ glsym_evas_gl_common_image_free(img);
+ return img2;
+ }
+ }
+ }
+ else if (ns->type == EVAS_NATIVE_SURFACE_OPENGL)
+ {
+ texid = tex;
+ img2 = eina_hash_find(ob->gl_context->shared->native_tex_hash, &texid);
+ if (img2 == img) return img;
+ if (img2)
+ {
+ if ((n = img2->native.data))
+ {
+ glsym_evas_gl_common_image_ref(img2);
+ glsym_evas_gl_common_image_free(img);
+ return img2;
+ }
+ }
+ }
+
+ img2 = glsym_evas_gl_common_image_new_from_data(ob->gl_context, img->w,
+ img->h, NULL, img->alpha,
+ EVAS_COLORSPACE_ARGB8888);
+ glsym_evas_gl_common_image_free(img);
+
+ if (!(img = img2)) return NULL;
+
+ if (ns->type == EVAS_NATIVE_SURFACE_WL)
+ {
+ if (native)
+ {
+ if ((n = calloc(1, sizeof(Native))))
+ {
+ EGLint attribs[3];
+ int format, yinvert = 1;
+
+ glsym_eglQueryWaylandBufferWL(ob->egl.disp, wl_buf,
+ EGL_TEXTURE_FORMAT, &format);
+ if ((format != EGL_TEXTURE_RGB) &&
+ (format != EGL_TEXTURE_RGBA))
+ {
+ ERR("eglQueryWaylandBufferWL() %d format is not supported ", format);
+ glsym_evas_gl_common_image_free(img);
+ free(n);
+ return NULL;
+ }
+
+ attribs[0] = EGL_WAYLAND_PLANE_WL;
+ attribs[1] = 0; //if plane is 1 then 0, if plane is 2 then 1
+ attribs[2] = EGL_NONE;
+
+ memcpy(&(n->ns), ns, sizeof(Evas_Native_Surface));
+ glsym_eglQueryWaylandBufferWL(ob->egl.disp, wl_buf,
+ EGL_WAYLAND_Y_INVERTED_WL,
+ &yinvert);
+ eina_hash_add(ob->gl_context->shared->native_wl_hash,
+ &wlid, img);
+
+ n->wl_buf = wl_buf;
+ if (glsym_eglCreateImage)
+ n->egl_surface = glsym_eglCreateImage(ob->egl.disp,
+ NULL,
+ EGL_WAYLAND_BUFFER_WL,
+ wl_buf, attribs);
+ else
+ {
+ ERR("Try eglCreateImage on EGL with no support");
+ eina_hash_del(ob->gl_context->shared->native_wl_hash,
+ &wlid, img);
+ glsym_evas_gl_common_image_free(img);
+ free(n);
+ return NULL;
+ }
+
+ if (!n->egl_surface)
+ {
+ ERR("eglCreatePixmapSurface() for %p failed", wl_buf);
+ eina_hash_del(ob->gl_context->shared->native_wl_hash,
+ &wlid, img);
+ glsym_evas_gl_common_image_free(img);
+ free(n);
+ return NULL;
+ }
+
+ //XXX: workaround for mesa-10.2.8
+ // mesa's eglQueryWaylandBufferWL() with EGL_WAYLAND_Y_INVERTED_WL works incorrect.
+ //img->native.yinvert = yinvert;
+ img->native.yinvert = 1;
+ img->native.loose = 0;
+ img->native.data = n;
+ img->native.func.data = re;
+ img->native.func.bind = _native_cb_bind;
+ img->native.func.unbind = _native_cb_unbind;
+ img->native.func.free = _native_cb_free;
+ img->native.target = GL_TEXTURE_2D;
+ img->native.mipmap = 0;
+
+ glsym_evas_gl_common_image_native_enable(img);
+ }
+ }
+ }
+ else if (ns->type == EVAS_NATIVE_SURFACE_OPENGL)
+ {
+ if (native)
+ {
+ if ((n = calloc(1, sizeof(Native))))
+ {
+ memcpy(&(n->ns), ns, sizeof(Evas_Native_Surface));
+ eina_hash_add(ob->gl_context->shared->native_tex_hash,
+ &texid, img);
+
+ n->egl_surface = 0;
+
+ img->native.yinvert = 0;
+ img->native.loose = 0;
+ img->native.data = n;
+ img->native.func.data = re;
+ img->native.func.bind = _native_cb_bind;
+ img->native.func.unbind = _native_cb_unbind;
+ img->native.func.free = _native_cb_free;
+ img->native.target = GL_TEXTURE_2D;
+ img->native.mipmap = 0;
+
+ glsym_evas_gl_common_image_native_enable(img);
+ }
+ }
+ }
+
+ /* TODO: NATIVE_SURFACE_TBM and NATIVE_SURFACE_EVASGL */
+
+ return img;
+}
+
+/* module api functions */
+static int
+module_open(Evas_Module *em)
+{
+ /* check for valid evas module */
+ if (!em) return 0;
+
+ /* get whatever engine module we inherit from */
+ if (!_evas_module_engine_inherit(&pfunc, "gl_generic")) return 0;
+
+ /* try to create eina logging domain */
+ if (_evas_engine_eglfs_log_dom < 0)
+ {
+ _evas_engine_eglfs_log_dom =
+ eina_log_domain_register("evas-eglfs", EVAS_DEFAULT_LOG_COLOR);
+ }
+
+ /* if we could not create a logging domain, error out */
+ if (_evas_engine_eglfs_log_dom < 0)
+ {
+ EINA_LOG_ERR("Can not create a module log domain.");
+ return 0;
+ }
+
+ /* store it for later use */
+ func = pfunc;
+
+ /* now to override methods */
+ EVAS_API_OVERRIDE(info, &func, eng_);
+ EVAS_API_OVERRIDE(info_free, &func, eng_);
+ EVAS_API_OVERRIDE(setup, &func, eng_);
+ EVAS_API_OVERRIDE(canvas_alpha_get, &func, eng_);
+ EVAS_API_OVERRIDE(output_free, &func, eng_);
+ EVAS_API_OVERRIDE(output_dump, &func, eng_);
+ EVAS_API_OVERRIDE(image_native_set, &func, eng_);
+
+ setenv("EGL_PLATFORM", "fbdev", 1);
+
+ gl_symbols();
+
+ /* now advertise out own api */
+ em->functions = (void *)(&func);
+
+ return 1;
+}
+
+static void
+module_close(Evas_Module *em EINA_UNUSED)
+{
+ /* unregister the eina log domain for this engine */
+ eina_log_domain_unregister(_evas_engine_eglfs_log_dom);
+ _evas_engine_eglfs_log_dom = -1;
+}
+
+static Evas_Module_Api evas_modapi =
+{
+ EVAS_MODULE_API_VERSION, "eglfs", "none", { module_open, module_close }
+};
+
+EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_ENGINE, engine, eglfs);
+
+#ifndef EVAS_STATIC_BUILD_EGLFS
+EVAS_EINA_MODULE_DEFINE(engine, eglfs);
+#endif
diff --git a/src/modules/evas/engines/eglfs/evas_engine.h b/src/modules/evas/engines/eglfs/evas_engine.h
new file mode 100644
index 0000000000..e02acb0d03
--- /dev/null
+++ b/src/modules/evas/engines/eglfs/evas_engine.h
@@ -0,0 +1,133 @@
+#ifndef EVAS_ENGINE_H
+# define EVAS_ENGINE_H
+
+# include "evas_common_private.h"
+# include "evas_macros.h"
+# include "evas_private.h"
+# include "Evas.h"
+# include "Evas_Engine_Eglfs.h"
+
+# define EGL_EGLEXT_PROTOTYPES
+# define GL_GLEXT_PROTOTYPES
+
+# include <EGL/egl.h>
+# include <EGL/eglext.h>
+# include <EGL/eglmesaext.h>
+# include <GLES2/gl2.h>
+# include <GLES2/gl2ext.h>
+# include <hwcomposer.h>
+# include <hardware/hardware.h>
+# include <hardware/hwcomposer.h>
+# include "../gl_generic/Evas_Engine_GL_Generic.h"
+
+extern int _evas_engine_eglfs_log_dom;
+extern int _extn_have_buffer_age;
+
+# ifdef ERR
+# undef ERR
+# endif
+# define ERR(...) EINA_LOG_DOM_ERR(_evas_engine_eglfs_log_dom, __VA_ARGS__)
+
+# ifdef DBG
+# undef DBG
+# endif
+# define DBG(...) EINA_LOG_DOM_DBG(_evas_engine_eglfs_log_dom, __VA_ARGS__)
+
+# ifdef INF
+# undef INF
+# endif
+# define INF(...) EINA_LOG_DOM_INFO(_evas_engine_eglfs_log_dom, __VA_ARGS__)
+
+# ifdef WRN
+# undef WRN
+# endif
+# define WRN(...) EINA_LOG_DOM_WARN(_evas_engine_eglfs_log_dom, __VA_ARGS__)
+
+# ifdef CRI
+# undef CRI
+# endif
+# define CRI(...) EINA_LOG_DOM_CRIT(_evas_engine_eglfs_log_dom, __VA_ARGS__)
+
+extern Evas_GL_Common_Context_New glsym_evas_gl_common_context_new;
+extern Evas_GL_Common_Context_Call glsym_evas_gl_common_context_flush;
+extern Evas_GL_Common_Context_Call glsym_evas_gl_common_context_free;
+extern Evas_GL_Common_Context_Call glsym_evas_gl_common_context_use;
+extern Evas_GL_Common_Context_Call glsym_evas_gl_common_context_newframe;
+extern Evas_GL_Common_Context_Call glsym_evas_gl_common_context_done;
+extern Evas_GL_Common_Context_Resize_Call glsym_evas_gl_common_context_resize;
+extern Evas_GL_Common_Buffer_Dump_Call glsym_evas_gl_common_buffer_dump;
+extern Evas_GL_Preload_Render_Call glsym_evas_gl_preload_render_lock;
+extern Evas_GL_Preload_Render_Call glsym_evas_gl_preload_render_unlock;
+
+struct _Context_3D
+{
+ EGLDisplay display;
+ EGLContext context;
+ EGLSurface surface;
+};
+
+struct _Outbuf
+{
+ Evas_Engine_Info_Eglfs *info;
+ Evas_Engine_GL_Context *gl_context;
+
+ Evas *evas; // used for pre_swap, post_swap
+
+ int w, h;
+ unsigned int rotation, depth;
+ Render_Engine_Swap_Mode swap_mode;
+
+ struct
+ {
+ EGLContext context[1];
+ EGLSurface surface[1];
+ EGLConfig config;
+ EGLDisplay disp;
+ } egl;
+
+ struct
+ {
+ int prev_age, frame_cnt;
+ int curr, last, num;
+ Eina_List *pending_writes;
+ } priv;
+
+ Eina_Bool destination_alpha : 1;
+ Eina_Bool vsync : 1;
+ Eina_Bool lost_back : 1;
+ Eina_Bool surf : 1;
+ Eina_Bool drew : 1;
+};
+
+Outbuf *evas_outbuf_new(Evas_Engine_Info_Eglfs *info, int w, int h, Render_Engine_Swap_Mode swap_mode);
+void evas_outbuf_free(Outbuf *ob);
+void evas_outbuf_use(Outbuf *ob);
+void evas_outbuf_resurf(Outbuf *ob);
+void evas_outbuf_unsurf(Outbuf *ob);
+void evas_outbuf_reconfigure(Outbuf *ob, int w, int h, int rot, Outbuf_Depth depth);
+Render_Engine_Swap_Mode evas_outbuf_buffer_state_get(Outbuf *ob);
+int evas_outbuf_rot_get(Outbuf *ob);
+Eina_Bool evas_outbuf_update_region_first_rect(Outbuf *ob);
+void *evas_outbuf_update_region_new(Outbuf *ob, int x, int y, int w, int h, int *cx, int *cy, int *cw, int *ch);
+void evas_outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int w, int h);
+void evas_outbuf_update_region_free(Outbuf *ob, RGBA_Image *update);
+void evas_outbuf_flush(Outbuf *ob, Tilebuf_Rect *rects, Evas_Render_Mode render_mode);
+Evas_Engine_GL_Context* evas_outbuf_gl_context_get(Outbuf *ob);
+void *evas_outbuf_egl_display_get(Outbuf *ob);
+Context_3D *evas_outbuf_gl_context_new(Outbuf *ob);
+void evas_outbuf_gl_context_use(Context_3D *ctx);
+EGLNativeWindowType create_hwcomposernativewindow(void);
+
+static inline Eina_Bool
+_re_wincheck(Outbuf *ob)
+{
+ if (ob->surf) return EINA_TRUE;
+ evas_outbuf_resurf(ob);
+ ob->lost_back = 1;
+ if (!ob->surf) ERR("GL engine can't re-create window surface!");
+ return EINA_FALSE;
+}
+
+extern unsigned int (*glsym_eglSwapBuffersWithDamage)(EGLDisplay a, void *b, const EGLint *d, EGLint c);
+
+#endif
diff --git a/src/modules/evas/engines/eglfs/evas_outbuf.c b/src/modules/evas/engines/eglfs/evas_outbuf.c
new file mode 100644
index 0000000000..aa3cd8a1b2
--- /dev/null
+++ b/src/modules/evas/engines/eglfs/evas_outbuf.c
@@ -0,0 +1,703 @@
+#include "evas_engine.h"
+
+#include <hybris/hwcomposerwindow/hwcomposer.h>
+#include <hardware/hwcomposer.h>
+#include <hardware/hardware.h>
+#include <android-config.h>
+
+static hwc_layer_1_t *fblayer;
+static hwc_composer_device_1_t *hwcDevicePtr;
+static hwc_display_contents_1_t **mList;
+
+void present(void *user_data, struct ANativeWindow *window,
+ struct ANativeWindowBuffer *buffer)
+{
+
+ int oldretire = mList[0]->retireFenceFd;
+ mList[0]->retireFenceFd = -1;
+ fblayer->handle = buffer->handle;
+ fblayer->acquireFenceFd = HWCNativeBufferGetFence(buffer);
+ fblayer->releaseFenceFd = -1;
+ int err = hwcDevicePtr->prepare(hwcDevicePtr, HWC_NUM_DISPLAY_TYPES, mList);
+ //assert(err == 0);
+
+ err = hwcDevicePtr->set(hwcDevicePtr, HWC_NUM_DISPLAY_TYPES, mList);
+ //assert(err == 0);
+ HWCNativeBufferSetFence(buffer, fblayer->releaseFenceFd);
+
+ if (oldretire != -1)
+ {
+ sync_wait(oldretire, -1);
+ close(oldretire);
+ }
+}
+
+
+EGLNativeWindowType create_hwcomposernativewindow(void)
+{
+ int err;
+ hw_module_t *hwcModule = 0;
+ hwcDevicePtr = 0;
+
+ err = hw_get_module(HWC_HARDWARE_MODULE_ID, (const hw_module_t **) &hwcModule);
+ //assert(err == 0);
+
+ err = hwc_open_1(hwcModule, &hwcDevicePtr);
+ //assert(err == 0);
+
+ hwcDevicePtr->blank(hwcDevicePtr, 0, 0);
+
+ uint32_t configs[5];
+ size_t numConfigs = 5;
+
+ err = hwcDevicePtr->getDisplayConfigs(hwcDevicePtr, 0, configs, &numConfigs);
+ //assert (err == 0);
+
+ int32_t attr_values[2];
+ uint32_t attributes[] = { HWC_DISPLAY_WIDTH, HWC_DISPLAY_HEIGHT, HWC_DISPLAY_NO_ATTRIBUTE };
+
+ hwcDevicePtr->getDisplayAttributes(hwcDevicePtr, 0,
+ configs[0], attributes, attr_values);
+
+ size_t size = sizeof(hwc_display_contents_1_t) + 2 * sizeof(hwc_layer_1_t);
+ hwc_display_contents_1_t *list = (hwc_display_contents_1_t *) malloc(size);
+ mList = (hwc_display_contents_1_t **) malloc(HWC_NUM_DISPLAY_TYPES * sizeof(hwc_display_contents_1_t *));
+ const hwc_rect_t r = { 0, 0, attr_values[0], attr_values[1] };
+
+ int counter = 0;
+ for (; counter < HWC_NUM_DISPLAY_TYPES; counter++)
+ mList[counter] = NULL;
+ // Assign buffer only to the first item, otherwise you get tearing
+ // if passed the same to multiple places
+ mList[0] = list;
+
+ fblayer = &list->hwLayers[0];
+ memset(fblayer, 0, sizeof(hwc_layer_1_t));
+ fblayer->compositionType = HWC_FRAMEBUFFER;
+ fblayer->hints = 0;
+ fblayer->flags = 0;
+ fblayer->handle = 0;
+ fblayer->transform = 0;
+ fblayer->blending = HWC_BLENDING_NONE;
+ fblayer->sourceCrop = r;
+ fblayer->displayFrame = r;
+ fblayer->visibleRegionScreen.numRects = 1;
+ fblayer->visibleRegionScreen.rects = &fblayer->displayFrame;
+ fblayer->acquireFenceFd = -1;
+ fblayer->releaseFenceFd = -1;
+ fblayer = &list->hwLayers[1];
+ memset(fblayer, 0, sizeof(hwc_layer_1_t));
+ fblayer->compositionType = HWC_FRAMEBUFFER_TARGET;
+ fblayer->hints = 0;
+ fblayer->flags = 0;
+ fblayer->handle = 0;
+ fblayer->transform = 0;
+ fblayer->blending = HWC_BLENDING_NONE;
+ fblayer->sourceCrop = r;
+ fblayer->displayFrame = r;
+ fblayer->visibleRegionScreen.numRects = 1;
+ fblayer->visibleRegionScreen.rects = &fblayer->displayFrame;
+ fblayer->acquireFenceFd = -1;
+ fblayer->releaseFenceFd = -1;
+
+ list->retireFenceFd = -1;
+ list->flags = HWC_GEOMETRY_CHANGED;
+ list->numHwLayers = 2;
+
+ EGLNativeWindowType win = NULL;
+ win = (EGLNativeWindowType)HWCNativeWindowCreate(attr_values[0], attr_values[1], HAL_PIXEL_FORMAT_RGBA_8888, present, NULL);
+ return win;
+}
+
+/* local variables */
+static Outbuf *_evas_eglfs_window = NULL;
+static EGLContext context = EGL_NO_CONTEXT;
+static int win_count = 0;
+
+static Eina_Bool
+_evas_outbuf_make_current(void *data, void *doit)
+{
+ Outbuf *ob;
+
+ if (!(ob = data)) return EINA_FALSE;
+
+ if (doit)
+ {
+ if (!eglMakeCurrent(ob->egl.disp, ob->egl.surface[0],
+ ob->egl.surface[0], ob->egl.context[0]))
+ return EINA_FALSE;
+ }
+ else
+ {
+ if (!eglMakeCurrent(ob->egl.disp, EGL_NO_SURFACE,
+ EGL_NO_SURFACE, EGL_NO_CONTEXT))
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+void _hwcomposer_present_cb(void *user_data, struct ANativeWindow *window, struct ANativeWindowBuffer *buffer)
+{
+}
+
+static Eina_Bool
+_evas_outbuf_egl_setup(Outbuf *ob)
+{
+ int ctx_attr[3];
+ int cfg_attr[40];
+ int maj = 0, min = 0, n = 0, i = 0;
+ EGLint ncfg;
+ EGLConfig *cfgs;
+ const GLubyte *vendor, *renderer, *version, *glslversion;
+ Eina_Bool blacklist = EINA_FALSE;
+
+ /* setup egl surface */
+ ctx_attr[0] = EGL_CONTEXT_CLIENT_VERSION;
+ ctx_attr[1] = 2;
+ ctx_attr[2] = EGL_NONE;
+
+ cfg_attr[n++] = EGL_BUFFER_SIZE;
+ cfg_attr[n++] = 32;
+ cfg_attr[n++] = EGL_DEPTH_SIZE;
+ cfg_attr[n++] = EGL_DONT_CARE;
+ cfg_attr[n++] = EGL_STENCIL_SIZE;
+ cfg_attr[n++] = EGL_DONT_CARE;
+ cfg_attr[n++] = EGL_RENDERABLE_TYPE;
+ cfg_attr[n++] = EGL_OPENGL_ES2_BIT;
+ cfg_attr[n++] = EGL_SURFACE_TYPE;
+ cfg_attr[n++] = EGL_WINDOW_BIT;
+
+ cfg_attr[n++] = EGL_ALPHA_SIZE;
+ if (ob->destination_alpha) cfg_attr[n++] = 1;
+ else cfg_attr[n++] = 0;
+ cfg_attr[n++] = EGL_NONE;
+
+ int err;
+ hw_module_t *hwcModule = 0;
+ hwc_composer_device_1_t *hwcDevicePtr = 0;
+
+ err = hw_get_module(HWC_HARDWARE_MODULE_ID, (const hw_module_t **) &hwcModule);
+ if (err != 0)
+ {
+ ERR("hw_get_module() fail. code=%d", err);
+ return EINA_FALSE;
+ }
+ err = hwc_open_1(hwcModule, &hwcDevicePtr);
+ if (err != 0)
+ {
+ ERR("hwc_open_1 fail. code=%d", err);
+ return EINA_FALSE;
+ }
+ hwcDevicePtr->blank(hwcDevicePtr, 0, 0);
+
+ uint32_t configs[5];
+ size_t numConfigs = 5;
+
+ err = hwcDevicePtr->getDisplayConfigs(hwcDevicePtr, 0, configs, &numConfigs);
+ if (err != 0)
+ {
+ ERR("getDisplayConfig. code=%d", err);
+ return EINA_FALSE;
+ }
+
+ int32_t attr_values[2];
+ uint32_t attributes[] = { HWC_DISPLAY_WIDTH, HWC_DISPLAY_HEIGHT, HWC_DISPLAY_NO_ATTRIBUTE };
+
+ hwcDevicePtr->getDisplayAttributes(hwcDevicePtr, 0,
+ configs[0], attributes, attr_values);
+
+ DBG("width: %i height: %i\n", attr_values[0], attr_values[1]);
+
+ size_t size = sizeof(hwc_display_contents_1_t) + 2 * sizeof(hwc_layer_1_t);
+ hwc_display_contents_1_t *list = (hwc_display_contents_1_t *) malloc(size);
+ hwc_display_contents_1_t **mList = (hwc_display_contents_1_t **) malloc(HWC_NUM_DISPLAY_TYPES * sizeof(hwc_display_contents_1_t *));
+ const hwc_rect_t r = { 0, 0, attr_values[0], attr_values[1] };
+
+ int counter = 0;
+ for (; counter < HWC_NUM_DISPLAY_TYPES; counter++)
+ mList[counter] = NULL;
+ mList[0] = list;
+
+ hwc_layer_1_t *layer = &list->hwLayers[0];
+ memset(layer, 0, sizeof(hwc_layer_1_t));
+ layer->compositionType = HWC_FRAMEBUFFER;
+ layer->hints = 0;
+ layer->flags = 0;
+ layer->handle = 0;
+ layer->transform = 0;
+ layer->blending = HWC_BLENDING_NONE;
+ layer->sourceCrop = r;
+ layer->displayFrame = r;
+ layer->visibleRegionScreen.numRects = 1;
+ layer->visibleRegionScreen.rects = &layer->displayFrame;
+ layer->acquireFenceFd = -1;
+ layer->releaseFenceFd = -1;
+ layer = &list->hwLayers[1];
+ memset(layer, 0, sizeof(hwc_layer_1_t));
+ layer->compositionType = HWC_FRAMEBUFFER_TARGET;
+ layer->hints = 0;
+ layer->flags = 0;
+ layer->handle = 0;
+ layer->transform = 0;
+ layer->blending = HWC_BLENDING_NONE;
+ layer->sourceCrop = r;
+ layer->displayFrame = r;
+ layer->visibleRegionScreen.numRects = 1;
+ layer->visibleRegionScreen.rects = &layer->displayFrame;
+ layer->acquireFenceFd = -1;
+ layer->releaseFenceFd = -1;
+
+ list->retireFenceFd = -1;
+ list->flags = HWC_GEOMETRY_CHANGED;
+ list->numHwLayers = 2;
+
+ ob->egl.disp = eglGetDisplay(NULL);
+ if (ob->egl.disp == EGL_NO_DISPLAY)
+ {
+ ERR("eglGetDisplay() fail. code=%#x", eglGetError());
+ return EINA_FALSE;
+ }
+
+ if (!eglInitialize(ob->egl.disp, &maj, &min))
+ {
+ ERR("eglInitialize() fail. code=%#x", eglGetError());
+ return EINA_FALSE;
+ }
+
+ eglBindAPI(EGL_OPENGL_ES_API);
+ if (eglGetError() != EGL_SUCCESS)
+ {
+ ERR("eglBindAPI() fail. code=%#x", eglGetError());
+ return EINA_FALSE;
+ }
+
+ if (!eglGetConfigs(ob->egl.disp, NULL, 0, &ncfg) || (ncfg == 0))
+ {
+ ERR("eglGetConfigs() fail. code=%#x", eglGetError());
+ return EINA_FALSE;
+ }
+
+ cfgs = malloc(ncfg * sizeof(EGLConfig));
+ if (!cfgs)
+ {
+ ERR("Failed to malloc space for egl configs");
+ return EINA_FALSE;
+ }
+
+ if (!eglChooseConfig(ob->egl.disp, cfg_attr, cfgs,
+ ncfg, &ncfg) || (ncfg == 0))
+ {
+ ERR("eglChooseConfig() fail. code=%#x", eglGetError());
+ return EINA_FALSE;
+ }
+
+ // First is always best...
+ ob->egl.config = cfgs[0];
+
+ EGLNativeWindowType win = create_hwcomposernativewindow();
+ ob->egl.surface[0] =
+ eglCreateWindowSurface(ob->egl.disp, ob->egl.config,
+ (EGLNativeWindowType)win, NULL);
+
+ if (ob->egl.surface[0] == EGL_NO_SURFACE)
+ {
+ ERR("eglCreateWindowSurface() fail for %p. code=%#x",
+ NULL, eglGetError());
+ return EINA_FALSE;
+ }
+
+ ob->egl.context[0] =
+ eglCreateContext(ob->egl.disp, ob->egl.config, EGL_NO_CONTEXT, ctx_attr);
+ if (ob->egl.context[0] == EGL_NO_CONTEXT)
+ {
+ ERR("eglCreateContext() fail. code=%#x", eglGetError());
+ return EINA_FALSE;
+ }
+
+ if (context == EGL_NO_CONTEXT) context = ob->egl.context[0];
+
+ if (eglMakeCurrent(ob->egl.disp, ob->egl.surface[0],
+ ob->egl.surface[0], ob->egl.context[0]) == EGL_FALSE)
+ {
+ ERR("eglMakeCurrent() fail. code=%#x", eglGetError());
+ return EINA_FALSE;
+ }
+
+ vendor = glGetString(GL_VENDOR);
+ renderer = glGetString(GL_RENDERER);
+ version = glGetString(GL_VERSION);
+ glslversion = glGetString(GL_SHADING_LANGUAGE_VERSION);
+ if (!vendor) vendor = (unsigned char *)"-UNKNOWN-";
+ if (!renderer) renderer = (unsigned char *)"-UNKNOWN-";
+ if (!version) version = (unsigned char *)"-UNKNOWN-";
+ if (!glslversion) glslversion = (unsigned char *)"-UNKNOWN-";
+ if (getenv("EVAS_GL_INFO"))
+ {
+ fprintf(stderr, "vendor : %s\n", vendor);
+ fprintf(stderr, "renderer: %s\n", renderer);
+ fprintf(stderr, "version : %s\n", version);
+ fprintf(stderr, "glsl ver: %s\n", glslversion);
+ }
+
+ if (strstr((const char *)vendor, "Mesa Project"))
+ {
+ if (strstr((const char *)renderer, "Software Rasterizer"))
+ blacklist = EINA_TRUE;
+ }
+ if (strstr((const char *)renderer, "softpipe"))
+ blacklist = EINA_TRUE;
+ if (strstr((const char *)renderer, "llvmpipe"))
+ blacklist = EINA_TRUE;
+
+ if ((blacklist) && (!getenv("EVAS_GL_NO_BLACKLIST")))
+ {
+ ERR("OpenGL Driver blacklisted:");
+ ERR("Vendor: %s", (const char *)vendor);
+ ERR("Renderer: %s", (const char *)renderer);
+ ERR("Version: %s", (const char *)version);
+ return EINA_FALSE;
+ }
+
+ ob->gl_context = glsym_evas_gl_common_context_new();
+ if (!ob->gl_context) return EINA_FALSE;
+
+#ifdef GL_GLES
+ ob->gl_context->egldisp = ob->egl.disp;
+ ob->gl_context->eglctxt = ob->egl.context[0];
+#endif
+
+ evas_outbuf_use(ob);
+ glsym_evas_gl_common_context_resize(ob->gl_context,
+ ob->w, ob->h, ob->rotation);
+
+ ob->surf = EINA_TRUE;
+
+ return EINA_TRUE;
+}
+
+Outbuf *
+evas_outbuf_new(Evas_Engine_Info_Eglfs *info, int w, int h, Render_Engine_Swap_Mode swap_mode)
+{
+ Outbuf *ob;
+ char *num;
+
+ if (!info) return NULL;
+
+ /* try to allocate space for outbuf */
+ if (!(ob = calloc(1, sizeof(Outbuf)))) return NULL;
+
+ win_count++;
+
+ ob->w = w;
+ ob->h = h;
+ ob->info = info;
+ ob->depth = info->info.depth;
+ ob->rotation = info->info.rotation;
+ ob->destination_alpha = info->info.destination_alpha;
+ ob->swap_mode = swap_mode;
+ ob->priv.num = 2;
+
+ if ((num = getenv("EVAS_EGLFS_BUFFERS")))
+ {
+ ob->priv.num = atoi(num);
+ if (ob->priv.num <= 0) ob->priv.num = 1;
+ else if (ob->priv.num > 4) ob->priv.num = 4;
+ }
+
+ if ((num = getenv("EVAS_EGLFS_VSYNC")))
+ ob->vsync = atoi(num);
+
+ if (!_evas_outbuf_egl_setup(ob))
+ {
+ evas_outbuf_free(ob);
+ return NULL;
+ }
+
+ return ob;
+}
+
+void
+evas_outbuf_free(Outbuf *ob)
+{
+ int ref = 0;
+
+ win_count--;
+ evas_outbuf_use(ob);
+
+ if (ob == _evas_eglfs_window) _evas_eglfs_window = NULL;
+
+ if (ob->gl_context)
+ {
+ ref = ob->gl_context->references - 1;
+ glsym_evas_gl_common_context_free(ob->gl_context);
+ }
+
+ eglMakeCurrent(ob->egl.disp, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+ if (ob->egl.context[0] != context)
+ eglDestroyContext(ob->egl.disp, ob->egl.context[0]);
+
+ if (ob->egl.surface[0] != EGL_NO_SURFACE)
+ eglDestroySurface(ob->egl.disp, ob->egl.surface[0]);
+
+ if (ref == 0)
+ {
+ if (context) eglDestroyContext(ob->egl.disp, context);
+ eglTerminate(ob->egl.disp);
+ eglReleaseThread();
+ context = EGL_NO_CONTEXT;
+ }
+
+ free(ob);
+}
+
+void
+evas_outbuf_use(Outbuf *ob)
+{
+ Eina_Bool force = EINA_FALSE;
+
+ glsym_evas_gl_preload_render_lock(_evas_outbuf_make_current, ob);
+
+ if (_evas_eglfs_window)
+ {
+ if (eglGetCurrentContext() != _evas_eglfs_window->egl.context[0])
+ force = EINA_TRUE;
+ }
+
+ if ((_evas_eglfs_window != ob) || (force))
+ {
+ if (_evas_eglfs_window)
+ {
+ glsym_evas_gl_common_context_use(_evas_eglfs_window->gl_context);
+ glsym_evas_gl_common_context_flush(_evas_eglfs_window->gl_context);
+ }
+
+ _evas_eglfs_window = ob;
+
+ if (ob)
+ {
+ if (ob->egl.surface[0] != EGL_NO_SURFACE)
+ {
+ if (eglMakeCurrent(ob->egl.disp, ob->egl.surface[0],
+ ob->egl.surface[0],
+ ob->egl.context[0]) == EGL_FALSE)
+ ERR("eglMakeCurrent() failed!");
+ }
+ }
+ }
+
+ if (ob) glsym_evas_gl_common_context_use(ob->gl_context);
+}
+
+void
+evas_outbuf_resurf(Outbuf *ob)
+{
+ if (ob->surf) return;
+ if (getenv("EVAS_GL_INFO")) printf("resurf %p\n", ob);
+
+ ob->egl.surface[0] =
+ eglCreateWindowSurface(ob->egl.disp, ob->egl.config,
+ NULL, NULL);
+
+ if (ob->egl.surface[0] == EGL_NO_SURFACE)
+ {
+ ERR("eglCreateWindowSurface() fail for %p. code=%#x",
+ NULL, eglGetError());
+ return;
+ }
+
+ if (eglMakeCurrent(ob->egl.disp, ob->egl.surface[0], ob->egl.surface[0],
+ ob->egl.context[0]) == EGL_FALSE)
+ ERR("eglMakeCurrent() failed!");
+
+ ob->surf = EINA_TRUE;
+}
+
+void
+evas_outbuf_unsurf(Outbuf *ob)
+{
+ if (!ob->surf) return;
+ if (!getenv("EVAS_GL_WIN_RESURF")) return;
+ if (getenv("EVAS_GL_INFO")) printf("unsurf %p\n", ob);
+
+ if (_evas_eglfs_window)
+ glsym_evas_gl_common_context_flush(_evas_eglfs_window->gl_context);
+ if (_evas_eglfs_window == ob)
+ {
+ eglMakeCurrent(ob->egl.disp, EGL_NO_SURFACE,
+ EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ if (ob->egl.surface[0] != EGL_NO_SURFACE)
+ eglDestroySurface(ob->egl.disp, ob->egl.surface[0]);
+ ob->egl.surface[0] = EGL_NO_SURFACE;
+
+ _evas_eglfs_window = NULL;
+ }
+
+ ob->surf = EINA_FALSE;
+}
+
+void
+evas_outbuf_reconfigure(Outbuf *ob, int w, int h, int rot, Outbuf_Depth depth)
+{
+ if (depth == OUTBUF_DEPTH_INHERIT) depth = ob->depth;
+
+ ob->w = w;
+ ob->h = h;
+ ob->depth = depth;
+ ob->rotation = rot;
+
+ evas_outbuf_use(ob);
+ glsym_evas_gl_common_context_resize(ob->gl_context, w, h, rot);
+}
+
+Render_Engine_Swap_Mode
+evas_outbuf_buffer_state_get(Outbuf *ob)
+{
+ return MODE_FULL;
+ // Forces re-rendering all the screen, that is bad for performance. However
+ // partial rendering makes black area. We should try to find a better solution.
+}
+
+int
+evas_outbuf_rot_get(Outbuf *ob)
+{
+ return ob->rotation;
+}
+
+Eina_Bool
+evas_outbuf_update_region_first_rect(Outbuf *ob)
+{
+ glsym_evas_gl_preload_render_lock(_evas_outbuf_make_current, ob);
+ evas_outbuf_use(ob);
+
+ if (!_re_wincheck(ob)) return EINA_TRUE;
+
+ glsym_evas_gl_common_context_flush(ob->gl_context);
+ glsym_evas_gl_common_context_newframe(ob->gl_context);
+
+ return EINA_FALSE;
+}
+
+void *
+evas_outbuf_update_region_new(Outbuf *ob, int x, int y, int w, int h, int *cx EINA_UNUSED, int *cy EINA_UNUSED, int *cw EINA_UNUSED, int *ch EINA_UNUSED)
+{
+ if ((w == ob->w) && (h == ob->h))
+ ob->gl_context->master_clip.enabled = EINA_FALSE;
+ else
+ {
+ ob->gl_context->master_clip.enabled = EINA_TRUE;
+ ob->gl_context->master_clip.x = x;
+ ob->gl_context->master_clip.y = y;
+ ob->gl_context->master_clip.w = w;
+ ob->gl_context->master_clip.h = h;
+ }
+
+ return ob->gl_context->def_surface;
+}
+
+void
+evas_outbuf_update_region_push(Outbuf *ob, RGBA_Image *update EINA_UNUSED, int x EINA_UNUSED, int y EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED)
+{
+ /* Is it really necessary to flush per region ? Shouldn't we be able to
+ still do that for the full canvas when doing partial update */
+ if (!_re_wincheck(ob)) return;
+ ob->drew = EINA_TRUE;
+ glsym_evas_gl_common_context_flush(ob->gl_context);
+}
+
+void
+evas_outbuf_update_region_free(Outbuf *ob EINA_UNUSED, RGBA_Image *update EINA_UNUSED)
+{
+ /* Nothing to do here as we don't really create an image per area */
+}
+
+void
+evas_outbuf_flush(Outbuf *ob, Tilebuf_Rect *rects EINA_UNUSED, Evas_Render_Mode render_mode)
+{
+ if (render_mode == EVAS_RENDER_MODE_ASYNC_INIT) goto end;
+
+ if (!_re_wincheck(ob)) goto end;
+ if (!ob->drew) goto end;
+
+ ob->drew = EINA_FALSE;
+ evas_outbuf_use(ob);
+ glsym_evas_gl_common_context_done(ob->gl_context);
+
+ if (!ob->vsync)
+ {
+ if (ob->info->info.vsync) eglSwapInterval(ob->egl.disp, 1);
+ else eglSwapInterval(ob->egl.disp, 0);
+ ob->vsync = 1;
+ }
+
+ if (ob->info->callback.pre_swap)
+ ob->info->callback.pre_swap(ob->info->callback.data, ob->evas);
+
+ eglSwapBuffers(ob->egl.disp, ob->egl.surface[0]);
+
+ if (ob->info->callback.post_swap)
+ ob->info->callback.post_swap(ob->info->callback.data, ob->evas);
+
+ ob->priv.frame_cnt++;
+
+end:
+ glsym_evas_gl_preload_render_unlock(_evas_outbuf_make_current, ob);
+}
+
+Evas_Engine_GL_Context *
+evas_outbuf_gl_context_get(Outbuf *ob)
+{
+ return ob->gl_context;
+}
+
+void *
+evas_outbuf_egl_display_get(Outbuf *ob)
+{
+ return ob->egl.disp;
+}
+
+Context_3D *
+evas_outbuf_gl_context_new(Outbuf *ob)
+{
+ Context_3D *ctx;
+ int context_attrs[3] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+
+ if (!ob) return NULL;
+
+ ctx = calloc(1, sizeof(Context_3D));
+ if (!ctx) return NULL;
+
+ ctx->context = eglCreateContext(ob->egl.disp, ob->egl.config,
+ ob->egl.context[0], context_attrs);
+
+ if (!ctx->context)
+ {
+ ERR("EGL context creation failed.");
+ goto error;
+ }
+
+ ctx->display = ob->egl.disp;
+ ctx->surface = ob->egl.surface[0];
+
+ return ctx;
+
+error:
+ free(ctx);
+ return NULL;
+}
+
+void
+evas_outbuf_gl_context_free(Context_3D *ctx)
+{
+ eglDestroyContext(ctx->display, ctx->context);
+ free(ctx);
+}
+
+void
+evas_outbuf_gl_context_use(Context_3D *ctx)
+{
+ if (eglMakeCurrent(ctx->display, ctx->surface,
+ ctx->surface, ctx->context) == EGL_FALSE)
+ ERR("eglMakeCurrent() failed.");
+}