diff options
-rw-r--r-- | Makefile.am | 4 | ||||
-rw-r--r-- | configure.ac | 17 | ||||
-rw-r--r-- | m4/evas_check_engine.m4 | 43 | ||||
-rw-r--r-- | pc/.gitignore | 1 | ||||
-rw-r--r-- | pc/evas-eglfs.pc.in | 3 | ||||
-rw-r--r-- | src/Makefile_Evas.am | 42 | ||||
-rw-r--r-- | src/modules/evas/engines/eglfs/Evas_Engine_Eglfs.h | 45 | ||||
-rw-r--r-- | src/modules/evas/engines/eglfs/evas_engine.c | 1254 | ||||
-rw-r--r-- | src/modules/evas/engines/eglfs/evas_engine.h | 133 | ||||
-rw-r--r-- | src/modules/evas/engines/eglfs/evas_outbuf.c | 703 |
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 | |||
188 | pkgconfig_DATA += pc/evas-fb.pc | 188 | pkgconfig_DATA += pc/evas-fb.pc |
189 | endif | 189 | endif |
190 | 190 | ||
191 | if BUILD_ENGINE_EGLFS | ||
192 | pkgconfig_DATA += pc/evas-eglfs.pc | ||
193 | endif | ||
194 | |||
191 | if BUILD_ENGINE_BUFFER | 195 | if BUILD_ENGINE_BUFFER |
192 | pkgconfig_DATA += pc/evas-software-buffer.pc | 196 | pkgconfig_DATA += pc/evas-software-buffer.pc |
193 | endif | 197 | 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], | |||
1624 | ], | 1624 | ], |
1625 | [want_fb="no"]) | 1625 | [want_fb="no"]) |
1626 | 1626 | ||
1627 | # Eglfs | ||
1628 | AC_ARG_ENABLE([eglfs], | ||
1629 | [AS_HELP_STRING([--enable-eglfs],[enable hardware accelerated framebuffer access. @<:@default=disabled@:>@])], | ||
1630 | [ | ||
1631 | if test "x${enableval}" = "xyes" ; then | ||
1632 | want_eglfs="yes" | ||
1633 | want_fb="yes" | ||
1634 | else | ||
1635 | want_eglfs="no" | ||
1636 | fi | ||
1637 | ], | ||
1638 | [want_eglfs="no"]) | ||
1639 | |||
1627 | # SDL | 1640 | # SDL |
1628 | AC_ARG_ENABLE([sdl], | 1641 | AC_ARG_ENABLE([sdl], |
1629 | [AS_HELP_STRING([--enable-sdl],[enable SDL support. @<:@default=disabled@:>@])], | 1642 | [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 | |||
2080 | EVAS_CHECK_ENGINE([wayland-shm], [${want_wayland}], [no], [Wayland Shm]) | 2093 | EVAS_CHECK_ENGINE([wayland-shm], [${want_wayland}], [no], [Wayland Shm]) |
2081 | EVAS_CHECK_ENGINE([drm], [${want_drm}], [no], [Drm]) | 2094 | EVAS_CHECK_ENGINE([drm], [${want_drm}], [no], [Drm]) |
2082 | EVAS_CHECK_ENGINE([gl-drm], [${want_gl_drm}], [no], [OpenGL Drm]) | 2095 | EVAS_CHECK_ENGINE([gl-drm], [${want_gl_drm}], [no], [OpenGL Drm]) |
2096 | EVAS_CHECK_ENGINE([eglfs], [${want_eglfs}], [no], [OpenGL Fb]) | ||
2083 | 2097 | ||
2084 | 2098 | ||
2085 | # Software XCB | 2099 | # Software XCB |
@@ -2236,6 +2250,7 @@ if test "x$have_evas_engine_gl_xlib" = "xyes" || \ | |||
2236 | test "x$have_evas_engine_gl_sdl" = "xyes" || \ | 2250 | test "x$have_evas_engine_gl_sdl" = "xyes" || \ |
2237 | test "x$have_evas_engine_gl_cocoa" = "xyes" || \ | 2251 | test "x$have_evas_engine_gl_cocoa" = "xyes" || \ |
2238 | test "x$have_evas_engine_gl_drm" = "xyes" || \ | 2252 | test "x$have_evas_engine_gl_drm" = "xyes" || \ |
2253 | test "x$have_evas_engine_eglfs" = "xyes" || \ | ||
2239 | test "x$have_evas_engine_wayland_egl" = "xyes"; then | 2254 | test "x$have_evas_engine_wayland_egl" = "xyes"; then |
2240 | have_evas_engine_gl_common="yes" | 2255 | have_evas_engine_gl_common="yes" |
2241 | fi | 2256 | fi |
@@ -2244,6 +2259,7 @@ if test "x$have_evas_engine_gl_xlib" = "xstatic" || \ | |||
2244 | test "x$have_evas_engine_gl_sdl" = "xstatic" || \ | 2259 | test "x$have_evas_engine_gl_sdl" = "xstatic" || \ |
2245 | test "x$have_evas_engine_gl_cocoa" = "xstatic" || \ | 2260 | test "x$have_evas_engine_gl_cocoa" = "xstatic" || \ |
2246 | test "x$have_evas_engine_gl_drm" = "xstatic" || \ | 2261 | test "x$have_evas_engine_gl_drm" = "xstatic" || \ |
2262 | test "x$have_evas_engine_eglfs" = "xstatic" || \ | ||
2247 | test "x$have_evas_engine_wayland_egl" = "xstatic"; then | 2263 | test "x$have_evas_engine_wayland_egl" = "xstatic"; then |
2248 | have_evas_engine_gl_common="yes" | 2264 | have_evas_engine_gl_common="yes" |
2249 | have_static_evas_engine_gl_common="yes" | 2265 | have_static_evas_engine_gl_common="yes" |
@@ -5095,6 +5111,7 @@ pc/eo-js.pc | |||
5095 | pc/efl.pc | 5111 | pc/efl.pc |
5096 | pc/efl-cxx.pc | 5112 | pc/efl-cxx.pc |
5097 | pc/evas-fb.pc | 5113 | pc/evas-fb.pc |
5114 | pc/evas-eglfs.pc | ||
5098 | pc/evas-opengl-x11.pc | 5115 | pc/evas-opengl-x11.pc |
5099 | pc/evas-opengl-sdl.pc | 5116 | pc/evas-opengl-sdl.pc |
5100 | pc/evas-opengl-cocoa.pc | 5117 | 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]) | |||
661 | 661 | ||
662 | ]) | 662 | ]) |
663 | 663 | ||
664 | dnl use: EVAS_CHECK_ENGINE_DEP_EGLFS(engine, simple, want_static[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) | ||
665 | |||
666 | AC_DEFUN([EVAS_CHECK_ENGINE_DEP_EGLFS], | ||
667 | [ | ||
668 | |||
669 | requirement="" | ||
670 | have_dep="no" | ||
671 | have_hw_dep="no" | ||
672 | evas_engine_[]$1[]_cflags="" | ||
673 | evas_engine_[]$1[]_libs="" | ||
674 | |||
675 | if test "x${with_opengl}" = "xes" ; then | ||
676 | gl_library="glesv2" | ||
677 | else | ||
678 | AC_MSG_ERROR([We do not support Eglfs without OpenGL ES. Please consider OpenGL ES if you want to use it.]) | ||
679 | fi | ||
680 | |||
681 | PKG_CHECK_EXISTS([egl >= 7.10 ${gl_library}], | ||
682 | [ | ||
683 | have_dep="yes" | ||
684 | requirement="egl >= 7.10 ${gl_library}" | ||
685 | ], | ||
686 | [have_dep="no"]) | ||
687 | |||
688 | if test "x${have_dep}" = "xyes" ; then | ||
689 | if test "x$3" = "xstatic" ; then | ||
690 | requirements_pc_evas="${requirement} ${requirements_pc_evas}" | ||
691 | requirements_pc_deps_evas="${requirement} ${requirements_pc_deps_evas}" | ||
692 | else | ||
693 | PKG_CHECK_MODULES([EGLFS], [${requirement}]) | ||
694 | evas_engine_[]$1[]_cflags="${EGLFS_CFLAGS}" | ||
695 | evas_engine_[]$1[]_libs="${EGLFS_LIBS}" | ||
696 | evas_engine_gl_common_libs="$evas_engine_[]$1[]_libdirs -lGLESv2 -lm -lEGL" | ||
697 | fi | ||
698 | fi | ||
699 | |||
700 | AC_SUBST([evas_engine_$1_cflags]) | ||
701 | AC_SUBST([evas_engine_$1_libs]) | ||
702 | |||
703 | AS_IF([test "x${have_dep}" = "xyes"], [$4], [$5]) | ||
704 | |||
705 | ]) | ||
706 | |||
664 | 707 | ||
665 | dnl use: EVAS_ENGINE(name, want_engine, [DEPENDENCY-CHECK-CODE]) | 708 | dnl use: EVAS_ENGINE(name, want_engine, [DEPENDENCY-CHECK-CODE]) |
666 | dnl | 709 | dnl |
diff --git a/pc/.gitignore b/pc/.gitignore index c3422d5f99..ee97ef9620 100644 --- a/pc/.gitignore +++ b/pc/.gitignore | |||
@@ -44,6 +44,7 @@ | |||
44 | /ethumb_client.pc | 44 | /ethumb_client.pc |
45 | /evas-drm.pc | 45 | /evas-drm.pc |
46 | /evas-fb.pc | 46 | /evas-fb.pc |
47 | /evas-eglfs.pc | ||
47 | /evas-opengl-cocoa.pc | 48 | /evas-opengl-cocoa.pc |
48 | /evas-opengl-sdl.pc | 49 | /evas-opengl-sdl.pc |
49 | /evas-opengl-x11.pc | 50 | /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 @@ | |||
1 | Name: evas-eglfs | ||
2 | Description: Evas eglfs engine | ||
3 | 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 | |||
874 | if BUILD_ENGINE_GL_DRM | 874 | if BUILD_ENGINE_GL_DRM |
875 | modules_evas_engines_gl_common_libevas_engine_gl_common_la_CPPFLAGS += @evas_engine_gl_drm_cflags@ | 875 | modules_evas_engines_gl_common_libevas_engine_gl_common_la_CPPFLAGS += @evas_engine_gl_drm_cflags@ |
876 | endif | 876 | endif |
877 | if BUILD_ENGINE_EGLFS | ||
878 | modules_evas_engines_gl_common_libevas_engine_gl_common_la_CPPFLAGS += @evas_engine_eglfs_cflags@ | ||
879 | endif | ||
877 | modules_evas_engines_gl_common_libevas_engine_gl_common_la_LIBADD = @USE_EVAS_LIBS@ | 880 | modules_evas_engines_gl_common_libevas_engine_gl_common_la_LIBADD = @USE_EVAS_LIBS@ |
878 | modules_evas_engines_gl_common_libevas_engine_gl_common_la_DEPENDENCIES = @USE_EVAS_INTERNAL_LIBS@ | 881 | modules_evas_engines_gl_common_libevas_engine_gl_common_la_DEPENDENCIES = @USE_EVAS_INTERNAL_LIBS@ |
879 | modules_evas_engines_gl_common_libevas_engine_gl_common_la_LDFLAGS = -module @EFL_LTMODULE_FLAGS@ | 882 | 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 | |||
1330 | endif | 1333 | endif |
1331 | endif | 1334 | endif |
1332 | 1335 | ||
1336 | if BUILD_ENGINE_EGLFS | ||
1337 | dist_installed_evasmainheaders_DATA += modules/evas/engines/eglfs/Evas_Engine_Eglfs.h | ||
1338 | EGLFS_SOURCES = \ | ||
1339 | modules/evas/engines/eglfs/evas_outbuf.c \ | ||
1340 | modules/evas/engines/eglfs/evas_engine.c \ | ||
1341 | modules/evas/engines/eglfs/evas_engine.h \ | ||
1342 | modules/evas/engines/eglfs/Evas_Engine_Eglfs.h | ||
1343 | if EVAS_STATIC_BUILD_EGLFS | ||
1344 | lib_evas_libevas_la_SOURCES += $(EGLFS_SOURCES) | ||
1345 | lib_evas_libevas_la_CPPFLAGS += @evas_engine_eglfs_cflags@ | ||
1346 | lib_evas_libevas_la_LIBADD += @evas_engine_eglfs_libs@ | ||
1347 | else | ||
1348 | engineeglfspkgdir = $(libdir)/evas/modules/engines/eglfs/$(MODULE_ARCH) | ||
1349 | engineeglfspkg_LTLIBRARIES = modules/evas/engines/eglfs/module.la | ||
1350 | |||
1351 | # Workaround for broken parallel install support in automake (relink issue) | ||
1352 | # http://debbugs.gnu.org/cgi/bugreport.cgi?bug=7328 | ||
1353 | install_engineeglfspkgLTLIBRARIES = install-engineeglfspkgLTLIBRARIES | ||
1354 | $(install_engineeglfspkgLTLIBRARIES): install-libLTLIBRARIES | ||
1355 | |||
1356 | modules_evas_engines_eglfs_module_la_SOURCES = $(EGLFS_SOURCES) | ||
1357 | modules_evas_engines_eglfs_module_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ | ||
1358 | -I$(top_srcdir)/src/lib/evas/include \ | ||
1359 | -I$(top_srcdir)/src/lib/evas/cserve2 \ | ||
1360 | -I$(top_srcdir)/src/modules/evas/engines/eglfs \ | ||
1361 | @EVAS_CFLAGS@ \ | ||
1362 | @ECORE_DRM_CFLAGS@ \ | ||
1363 | @evas_engine_eglfs_cflags@ | ||
1364 | modules_evas_engines_eglfs_module_la_LIBADD = \ | ||
1365 | @USE_EVAS_LIBS@ \ | ||
1366 | @USE_ECORE_DRM_LIBS@ \ | ||
1367 | @evas_engine_eglfs_libs@ \ | ||
1368 | @USE_EEZE_INTERNAL_LIBS@ | ||
1369 | modules_evas_engines_eglfs_module_la_DEPENDENCIES = @USE_EVAS_INTERNAL_LIBS@ @USE_EEZE_INTERNAL_LIBS@ @USE_ECORE_DRM_INTERNAL_LIBS@ | ||
1370 | modules_evas_engines_eglfs_module_la_LDFLAGS = -module @EFL_LTMODULE_FLAGS@ | ||
1371 | modules_evas_engines_eglfs_module_la_LIBTOOLFLAGS = --tag=disable-static | ||
1372 | endif | ||
1373 | endif | ||
1374 | |||
1333 | ### Cserve2 binary | 1375 | ### Cserve2 binary |
1334 | 1376 | ||
1335 | if EVAS_CSERVE2 | 1377 | 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 @@ | |||
1 | #ifndef _EVAS_ENGINE_EGLFS_H | ||
2 | # define _EVAS_ENGINE_EGLFS_H | ||
3 | |||
4 | typedef enum _Evas_Engine_Info_Eglfs_Swap_Mode | ||
5 | { | ||
6 | EVAS_ENGINE_EGLFS_SWAP_MODE_AUTO = 0, | ||
7 | EVAS_ENGINE_EGLFS_SWAP_MODE_FULL = 1, | ||
8 | EVAS_ENGINE_EGLFS_SWAP_MODE_COPY = 2, | ||
9 | EVAS_ENGINE_EGLFS_SWAP_MODE_DOUBLE = 3, | ||
10 | EVAS_ENGINE_EGLFS_SWAP_MODE_TRIPLE = 4, | ||
11 | EVAS_ENGINE_EGLFS_SWAP_MODE_QUADRUPLE = 5 | ||
12 | } Evas_Engine_Info_Eglfs_Swap_Mode; | ||
13 | |||
14 | typedef struct _Evas_Engine_Info_Eglfs Evas_Engine_Info_Eglfs; | ||
15 | |||
16 | struct _Evas_Engine_Info_Eglfs | ||
17 | { | ||
18 | /* PRIVATE - don't mess with this baby or evas will poke its tongue out */ | ||
19 | /* at you and make nasty noises */ | ||
20 | Evas_Engine_Info magic; | ||
21 | |||
22 | struct | ||
23 | { | ||
24 | unsigned int rotation, depth; | ||
25 | unsigned int crtc_id, conn_id, buffer_id; | ||
26 | unsigned int format, flags; | ||
27 | |||
28 | Eina_Bool destination_alpha : 1; | ||
29 | Eina_Bool vsync : 1; | ||
30 | Eina_Bool indirect : 1; | ||
31 | unsigned char swap_mode : 4; | ||
32 | } info; | ||
33 | |||
34 | struct | ||
35 | { | ||
36 | void (*pre_swap)(void *data, Evas *evas); | ||
37 | void (*post_swap)(void *data, Evas *evas); | ||
38 | void *data; | ||
39 | } callback; | ||
40 | |||
41 | /* non-blocking or blocking mode */ | ||
42 | Evas_Engine_Render_Mode render_mode; | ||
43 | }; | ||
44 | |||
45 | #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 @@ | |||
1 | #include "config.h" | ||
2 | #include "evas_engine.h" | ||
3 | #include <wayland-client.h> | ||
4 | |||
5 | #ifdef HAVE_DLSYM | ||
6 | # include <dlfcn.h> /* dlopen,dlclose,etc */ | ||
7 | #else | ||
8 | # error eglfs should not get compiled if dlsym is not found on the system! | ||
9 | #endif | ||
10 | |||
11 | #ifdef EVAS_CSERVE2 | ||
12 | # include "evas_cs2_private.h" | ||
13 | #endif | ||
14 | |||
15 | #define EVAS_GL_NO_GL_H_CHECK 1 | ||
16 | #include "Evas_GL.h" | ||
17 | |||
18 | #define EVAS_GL_UPDATE_TILE_SIZE 16 | ||
19 | |||
20 | #ifndef EGL_NATIVE_PIXMAP_KHR | ||
21 | # define EGL_NATIVE_PIXMAP_KHR 0x30b0 | ||
22 | #endif | ||
23 | |||
24 | /* external variables */ | ||
25 | int _evas_engine_eglfs_log_dom = -1; | ||
26 | int _extn_have_buffer_age = 1; | ||
27 | |||
28 | /* local variables */ | ||
29 | static Eina_Bool initted = EINA_FALSE; | ||
30 | static int gl_wins = 0; | ||
31 | |||
32 | /* local structures */ | ||
33 | typedef struct _Render_Engine Render_Engine; | ||
34 | struct _Render_Engine | ||
35 | { | ||
36 | Render_Engine_GL_Generic generic; | ||
37 | }; | ||
38 | |||
39 | typedef struct _Native Native; | ||
40 | struct _Native | ||
41 | { | ||
42 | Evas_Native_Surface ns; | ||
43 | struct wl_buffer *wl_buf; | ||
44 | void *egl_surface; | ||
45 | }; | ||
46 | |||
47 | /* local function prototype types */ | ||
48 | typedef void (*_eng_fn)(void); | ||
49 | typedef _eng_fn (*glsym_func_eng_fn)(); | ||
50 | typedef void (*glsym_func_void)(); | ||
51 | typedef void *(*glsym_func_void_ptr)(); | ||
52 | typedef int (*glsym_func_int)(); | ||
53 | typedef unsigned int (*glsym_func_uint)(); | ||
54 | typedef const char *(*glsym_func_const_char_ptr)(); | ||
55 | |||
56 | /* external dynamic loaded Evas_GL function pointers */ | ||
57 | Evas_GL_Common_Image_Call glsym_evas_gl_common_image_ref = NULL; | ||
58 | Evas_GL_Common_Image_Call glsym_evas_gl_common_image_unref = NULL; | ||
59 | Evas_GL_Common_Image_Call glsym_evas_gl_common_image_free = NULL; | ||
60 | Evas_GL_Common_Image_Call glsym_evas_gl_common_image_native_disable = NULL; | ||
61 | Evas_GL_Common_Image_Call glsym_evas_gl_common_image_native_enable = NULL; | ||
62 | Evas_GL_Common_Image_New_From_Data glsym_evas_gl_common_image_new_from_data = NULL; | ||
63 | Evas_GL_Common_Context_Call glsym_evas_gl_common_image_all_unload = NULL; | ||
64 | Evas_GL_Preload glsym_evas_gl_preload_init = NULL; | ||
65 | Evas_GL_Preload glsym_evas_gl_preload_shutdown = NULL; | ||
66 | EVGL_Engine_Call glsym_evgl_engine_shutdown = NULL; | ||
67 | EVGL_Current_Native_Context_Get_Call glsym_evgl_current_native_context_get = NULL; | ||
68 | Evas_Gl_Symbols glsym_evas_gl_symbols = NULL; | ||
69 | |||
70 | Evas_GL_Common_Context_New glsym_evas_gl_common_context_new = NULL; | ||
71 | Evas_GL_Common_Context_Call glsym_evas_gl_common_context_flush = NULL; | ||
72 | Evas_GL_Common_Context_Call glsym_evas_gl_common_context_free = NULL; | ||
73 | Evas_GL_Common_Context_Call glsym_evas_gl_common_context_use = NULL; | ||
74 | Evas_GL_Common_Context_Call glsym_evas_gl_common_context_newframe = NULL; | ||
75 | Evas_GL_Common_Context_Call glsym_evas_gl_common_context_done = NULL; | ||
76 | Evas_GL_Common_Context_Resize_Call glsym_evas_gl_common_context_resize = NULL; | ||
77 | Evas_GL_Common_Buffer_Dump_Call glsym_evas_gl_common_buffer_dump = NULL; | ||
78 | Evas_GL_Preload_Render_Call glsym_evas_gl_preload_render_lock = NULL; | ||
79 | Evas_GL_Preload_Render_Call glsym_evas_gl_preload_render_unlock = NULL; | ||
80 | Evas_GL_Preload_Render_Call glsym_evas_gl_preload_render_relax = NULL; | ||
81 | |||
82 | glsym_func_void_ptr glsym_evas_gl_common_current_context_get = NULL; | ||
83 | |||
84 | /* dynamic loaded local egl function pointers */ | ||
85 | _eng_fn (*glsym_eglGetProcAddress)(const char *a) = NULL; | ||
86 | void *(*glsym_eglCreateImage)(EGLDisplay a, EGLContext b, EGLenum c, EGLClientBuffer d, const int *e) = NULL; | ||
87 | void (*glsym_eglDestroyImage)(EGLDisplay a, void *b) = NULL; | ||
88 | void (*glsym_glEGLImageTargetTexture2DOES)(int a, void *b) = NULL; | ||
89 | unsigned int (*glsym_eglSwapBuffersWithDamage)(EGLDisplay a, void *b, const EGLint *d, EGLint c) = NULL; | ||
90 | unsigned int (*glsym_eglQueryWaylandBufferWL)(EGLDisplay a, struct wl_resource *b, EGLint c, EGLint *d) = NULL; | ||
91 | |||
92 | /* local function prototypes */ | ||
93 | static void gl_symbols(void); | ||
94 | static void gl_extn_veto(Render_Engine *re); | ||
95 | |||
96 | static void *evgl_eng_display_get(void *data); | ||
97 | static void *evgl_eng_evas_surface_get(void *data); | ||
98 | static int evgl_eng_make_current(void *data, void *surface, void *context, int flush); | ||
99 | static void *evgl_eng_native_window_create(void *data); | ||
100 | static int evgl_eng_native_window_destroy(void *data, void *native_window); | ||
101 | static void *evgl_eng_window_surface_create(void *data, void *native_window); | ||
102 | static int evgl_eng_window_surface_destroy(void *data, void *surface); | ||
103 | static void *evgl_eng_context_create(void *data, void *share_ctx, Evas_GL_Context_Version version); | ||
104 | static int evgl_eng_context_destroy(void *data, void *context); | ||
105 | static const char *evgl_eng_string_get(void *data); | ||
106 | static void *evgl_eng_proc_address_get(const char *name); | ||
107 | static int evgl_eng_rotation_angle_get(void *data); | ||
108 | |||
109 | /* function tables - filled in later (func and parent func) */ | ||
110 | static Evas_Func func, pfunc; | ||
111 | static const EVGL_Interface evgl_funcs = | ||
112 | { | ||
113 | evgl_eng_display_get, | ||
114 | evgl_eng_evas_surface_get, | ||
115 | evgl_eng_native_window_create, | ||
116 | evgl_eng_native_window_destroy, | ||
117 | evgl_eng_window_surface_create, | ||
118 | evgl_eng_window_surface_destroy, | ||
119 | evgl_eng_context_create, | ||
120 | evgl_eng_context_destroy, | ||
121 | evgl_eng_make_current, | ||
122 | evgl_eng_proc_address_get, | ||
123 | evgl_eng_string_get, | ||
124 | evgl_eng_rotation_angle_get, | ||
125 | NULL, // PBuffer | ||
126 | NULL, // PBuffer | ||
127 | NULL, // OpenGL-ES 1 | ||
128 | NULL, // OpenGL-ES 1 | ||
129 | NULL, // OpenGL-ES 1 | ||
130 | NULL, // native_win_surface_config_get | ||
131 | }; | ||
132 | |||
133 | |||
134 | /* local inline functions */ | ||
135 | static inline Outbuf * | ||
136 | eng_get_ob(Render_Engine *re) | ||
137 | { | ||
138 | return re->generic.software.ob; | ||
139 | } | ||
140 | |||
141 | /* local functions */ | ||
142 | static void | ||
143 | gl_symbols(void) | ||
144 | { | ||
145 | static Eina_Bool done = EINA_FALSE; | ||
146 | |||
147 | if (done) return; | ||
148 | |||
149 | #define LINK2GENERIC(sym) \ | ||
150 | glsym_##sym = dlsym(RTLD_DEFAULT, #sym); | ||
151 | |||
152 | // Get function pointer to evas_gl_common that is now provided through the link of GL_Generic. | ||
153 | LINK2GENERIC(evas_gl_common_image_all_unload); | ||
154 | LINK2GENERIC(evas_gl_common_image_ref); | ||
155 | LINK2GENERIC(evas_gl_common_image_unref); | ||
156 | LINK2GENERIC(evas_gl_common_image_new_from_data); | ||
157 | LINK2GENERIC(evas_gl_common_image_native_disable); | ||
158 | LINK2GENERIC(evas_gl_common_image_free); | ||
159 | LINK2GENERIC(evas_gl_common_image_native_enable); | ||
160 | LINK2GENERIC(evas_gl_common_context_new); | ||
161 | LINK2GENERIC(evas_gl_common_context_flush); | ||
162 | LINK2GENERIC(evas_gl_common_context_free); | ||
163 | LINK2GENERIC(evas_gl_common_context_use); | ||
164 | LINK2GENERIC(evas_gl_common_context_newframe); | ||
165 | LINK2GENERIC(evas_gl_common_context_done); | ||
166 | LINK2GENERIC(evas_gl_common_context_resize); | ||
167 | LINK2GENERIC(evas_gl_common_buffer_dump); | ||
168 | LINK2GENERIC(evas_gl_preload_render_lock); | ||
169 | LINK2GENERIC(evas_gl_preload_render_unlock); | ||
170 | LINK2GENERIC(evas_gl_preload_render_relax); | ||
171 | LINK2GENERIC(evas_gl_preload_init); | ||
172 | LINK2GENERIC(evas_gl_preload_shutdown); | ||
173 | LINK2GENERIC(evgl_engine_shutdown); | ||
174 | LINK2GENERIC(evas_gl_symbols); | ||
175 | |||
176 | #define FINDSYM(dst, sym, typ) \ | ||
177 | if (glsym_eglGetProcAddress) { \ | ||
178 | if (!dst) dst = (typ)glsym_eglGetProcAddress(sym); \ | ||
179 | } else { \ | ||
180 | if (!dst) dst = (typ)dlsym(RTLD_DEFAULT, sym); \ | ||
181 | } | ||
182 | |||
183 | FINDSYM(glsym_eglGetProcAddress, "eglGetProcAddressKHR", glsym_func_eng_fn); | ||
184 | FINDSYM(glsym_eglGetProcAddress, "eglGetProcAddressEXT", glsym_func_eng_fn); | ||
185 | FINDSYM(glsym_eglGetProcAddress, "eglGetProcAddressARB", glsym_func_eng_fn); | ||
186 | FINDSYM(glsym_eglGetProcAddress, "eglGetProcAddress", glsym_func_eng_fn); | ||
187 | |||
188 | glsym_evas_gl_symbols((void*)glsym_eglGetProcAddress); | ||
189 | |||
190 | FINDSYM(glsym_eglCreateImage, "eglCreateImageKHR", glsym_func_void_ptr); | ||
191 | FINDSYM(glsym_eglCreateImage, "eglCreateImageEXT", glsym_func_void_ptr); | ||
192 | FINDSYM(glsym_eglCreateImage, "eglCreateImageARB", glsym_func_void_ptr); | ||
193 | FINDSYM(glsym_eglCreateImage, "eglCreateImage", glsym_func_void_ptr); | ||
194 | |||
195 | FINDSYM(glsym_eglDestroyImage, "eglDestroyImageKHR", glsym_func_void); | ||
196 | FINDSYM(glsym_eglDestroyImage, "eglDestroyImageEXT", glsym_func_void); | ||
197 | FINDSYM(glsym_eglDestroyImage, "eglDestroyImageARB", glsym_func_void); | ||
198 | FINDSYM(glsym_eglDestroyImage, "eglDestroyImage", glsym_func_void); | ||
199 | |||
200 | FINDSYM(glsym_glEGLImageTargetTexture2DOES, | ||
201 | "glEGLImageTargetTexture2DOES", glsym_func_void); | ||
202 | |||
203 | FINDSYM(glsym_eglSwapBuffersWithDamage, "eglSwapBuffersWithDamageEXT", | ||
204 | glsym_func_uint); | ||
205 | FINDSYM(glsym_eglSwapBuffersWithDamage, "eglSwapBuffersWithDamageINTEL", | ||
206 | glsym_func_uint); | ||
207 | FINDSYM(glsym_eglSwapBuffersWithDamage, "eglSwapBuffersWithDamage", | ||
208 | glsym_func_uint); | ||
209 | |||
210 | FINDSYM(glsym_eglQueryWaylandBufferWL, "eglQueryWaylandBufferWL", | ||
211 | glsym_func_uint); | ||
212 | |||
213 | done = EINA_TRUE; | ||
214 | } | ||
215 | |||
216 | static void | ||
217 | gl_extn_veto(Render_Engine *re) | ||
218 | { | ||
219 | const char *str = NULL; | ||
220 | |||
221 | str = eglQueryString(eng_get_ob(re)->egl.disp, EGL_EXTENSIONS); | ||
222 | if (str) | ||
223 | { | ||
224 | const char *s = NULL; | ||
225 | |||
226 | if (getenv("EVAS_GL_INFO")) printf("EGL EXTN:\n%s\n", str); | ||
227 | |||
228 | // Disable Partial Rendering | ||
229 | s = getenv("EVAS_GL_PARTIAL_DISABLE"); | ||
230 | if ((s) && (atoi(s))) | ||
231 | { | ||
232 | _extn_have_buffer_age = 0; | ||
233 | glsym_eglSwapBuffersWithDamage = NULL; | ||
234 | } | ||
235 | if (!strstr(str, "EGL_EXT_buffer_age")) _extn_have_buffer_age = 0; | ||
236 | if (!strstr(str, "EGL_EXT_swap_buffers_with_damage")) | ||
237 | glsym_eglSwapBuffersWithDamage = NULL; | ||
238 | } | ||
239 | else | ||
240 | { | ||
241 | if (getenv("EVAS_GL_INFO")) printf("NO EGL EXTN!\n"); | ||
242 | _extn_have_buffer_age = 0; | ||
243 | } | ||
244 | } | ||
245 | |||
246 | static void * | ||
247 | evgl_eng_display_get(void *data) | ||
248 | { | ||
249 | Render_Engine *re; | ||
250 | |||
251 | re = (Render_Engine *)data; | ||
252 | if (!re) | ||
253 | { | ||
254 | ERR("Invalid Render Engine Data!"); | ||
255 | return NULL; | ||
256 | } | ||
257 | |||
258 | if (eng_get_ob(re)) | ||
259 | return (void *)eng_get_ob(re)->egl.disp; | ||
260 | else | ||
261 | return NULL; | ||
262 | } | ||
263 | |||
264 | static void * | ||
265 | evgl_eng_evas_surface_get(void *data) | ||
266 | { | ||
267 | Render_Engine *re; | ||
268 | |||
269 | re = (Render_Engine *)data; | ||
270 | if (!re) | ||
271 | { | ||
272 | ERR("Invalid Render Engine Data!"); | ||
273 | return NULL; | ||
274 | } | ||
275 | |||
276 | if (eng_get_ob(re)) | ||
277 | return (void *)eng_get_ob(re)->egl.surface[0]; | ||
278 | else | ||
279 | return NULL; | ||
280 | } | ||
281 | |||
282 | static int | ||
283 | evgl_eng_make_current(void *data, void *surface, void *context, int flush) | ||
284 | { | ||
285 | Render_Engine *re; | ||
286 | EGLContext ctx; | ||
287 | EGLSurface sfc; | ||
288 | EGLDisplay dpy; | ||
289 | int ret = 0; | ||
290 | |||
291 | re = (Render_Engine *)data; | ||
292 | if (!re) | ||
293 | { | ||
294 | ERR("Invalid Render Engine Data!"); | ||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | dpy = eng_get_ob(re)->egl.disp; | ||
299 | ctx = (EGLContext)context; | ||
300 | sfc = (EGLSurface)surface; | ||
301 | |||
302 | if ((!context) && (!surface)) | ||
303 | { | ||
304 | ret = eglMakeCurrent(dpy, EGL_NO_SURFACE, | ||
305 | EGL_NO_SURFACE, EGL_NO_CONTEXT); | ||
306 | if (!ret) | ||
307 | { | ||
308 | ERR("eglMakeCurrent() failed! Error Code=%#x", eglGetError()); | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | return 1; | ||
313 | } | ||
314 | |||
315 | if ((eglGetCurrentContext() != ctx) || | ||
316 | (eglGetCurrentSurface(EGL_READ) != sfc) || | ||
317 | (eglGetCurrentSurface(EGL_DRAW) != sfc) ) | ||
318 | { | ||
319 | if (flush) evas_outbuf_use(NULL); | ||
320 | |||
321 | ret = eglMakeCurrent(dpy, sfc, sfc, ctx); | ||
322 | if (!ret) | ||
323 | { | ||
324 | ERR("eglMakeCurrent() failed! Error Code=%#x", eglGetError()); | ||
325 | return 0; | ||
326 | } | ||
327 | } | ||
328 | |||
329 | return 1; | ||
330 | } | ||
331 | |||
332 | static void _hwc_present_cb(void *user_data, struct ANativeWindow *window, | ||
333 | struct ANativeWindowBuffer *buffer) | ||
334 | { | ||
335 | |||
336 | } | ||
337 | |||
338 | static void * | ||
339 | evgl_eng_native_window_create(void *data) | ||
340 | { | ||
341 | Render_Engine *re; | ||
342 | Evas_Engine_Info_Eglfs *info; | ||
343 | struct ANativeWindow *native_window; | ||
344 | |||
345 | re = (Render_Engine *)data; | ||
346 | if (!re) | ||
347 | { | ||
348 | ERR("Invalid Render Engine Data!"); | ||
349 | return NULL; | ||
350 | } | ||
351 | |||
352 | info = eng_get_ob(re)->info; | ||
353 | if (!info) | ||
354 | { | ||
355 | ERR("Invalid Evas Engine Eglfs Info!"); | ||
356 | return NULL; | ||
357 | } | ||
358 | EGLNativeWindowType win; | ||
359 | win = create_hwcomposernativewindow(); | ||
360 | return (void *)win; | ||
361 | } | ||
362 | |||
363 | static int | ||
364 | evgl_eng_native_window_destroy(void *data, void *native_window) | ||
365 | { | ||
366 | Render_Engine *re = (Render_Engine *)data; | ||
367 | |||
368 | if (!re) | ||
369 | { | ||
370 | ERR("Invalid Render Engine Data!"); | ||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | if (!native_window) | ||
375 | { | ||
376 | ERR("Invalid native surface."); | ||
377 | return 0; | ||
378 | } | ||
379 | |||
380 | HWCNativeWindowDestroy(native_window); | ||
381 | |||
382 | return 1; | ||
383 | } | ||
384 | |||
385 | static void * | ||
386 | evgl_eng_window_surface_create(void *data, void *native_window) | ||
387 | { | ||
388 | Render_Engine *re; | ||
389 | EGLSurface surface = EGL_NO_SURFACE; | ||
390 | |||
391 | re = (Render_Engine *)data; | ||
392 | if (!re) | ||
393 | { | ||
394 | ERR("Invalid Render Engine Data!"); | ||
395 | return NULL; | ||
396 | } | ||
397 | |||
398 | // Create resource surface for EGL | ||
399 | surface = eglCreateWindowSurface(eng_get_ob(re)->egl.disp, | ||
400 | eng_get_ob(re)->egl.config, | ||
401 | (EGLNativeWindowType)native_window, | ||
402 | NULL); | ||
403 | if (!surface) | ||
404 | { | ||
405 | ERR("Creating window surface failed. Error: %#x.", eglGetError()); | ||
406 | return NULL; | ||
407 | } | ||
408 | |||
409 | return (void *)surface; | ||
410 | } | ||
411 | |||
412 | static int | ||
413 | evgl_eng_window_surface_destroy(void *data, void *surface) | ||
414 | { | ||
415 | Render_Engine *re; | ||
416 | EGLBoolean ret = EGL_FALSE; | ||
417 | |||
418 | re = (Render_Engine *)data; | ||
419 | if (!re) | ||
420 | { | ||
421 | ERR("Invalid Render Engine Data!"); | ||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | if (!surface) | ||
426 | { | ||
427 | ERR("Invalid surface."); | ||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | ret = eglDestroySurface(eng_get_ob(re)->egl.disp, (EGLSurface)surface); | ||
432 | if (ret == EGL_TRUE) return 1; | ||
433 | |||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | static void * | ||
438 | evgl_eng_context_create(void *data, void *share_ctx, Evas_GL_Context_Version version) | ||
439 | { | ||
440 | Render_Engine *re; | ||
441 | EGLContext context = EGL_NO_CONTEXT; | ||
442 | int context_attrs[3]; | ||
443 | |||
444 | re = (Render_Engine *)data; | ||
445 | if (!re) | ||
446 | { | ||
447 | ERR("Invalid Render Engine Data!"); | ||
448 | return NULL; | ||
449 | } | ||
450 | |||
451 | if (version != EVAS_GL_GLES_2_X) | ||
452 | { | ||
453 | ERR("This engine only supports OpenGL-ES 2.0 contexts for now!"); | ||
454 | return NULL; | ||
455 | } | ||
456 | |||
457 | context_attrs[0] = EGL_CONTEXT_CLIENT_VERSION; | ||
458 | context_attrs[1] = 2; | ||
459 | context_attrs[2] = EGL_NONE; | ||
460 | |||
461 | // Share context already assumes that it's sharing with evas' context | ||
462 | if (share_ctx) | ||
463 | { | ||
464 | context = eglCreateContext(eng_get_ob(re)->egl.disp, | ||
465 | eng_get_ob(re)->egl.config, | ||
466 | (EGLContext)share_ctx, | ||
467 | context_attrs); | ||
468 | } | ||
469 | else | ||
470 | { | ||
471 | context = eglCreateContext(eng_get_ob(re)->egl.disp, | ||
472 | eng_get_ob(re)->egl.config, | ||
473 | eng_get_ob(re)->egl.context[0], // Evas' GL Context | ||
474 | context_attrs); | ||
475 | } | ||
476 | |||
477 | if (!context) | ||
478 | { | ||
479 | ERR("eglMakeCurrent() failed! Error Code=%#x", eglGetError()); | ||
480 | return NULL; | ||
481 | } | ||
482 | |||
483 | return (void *)context; | ||
484 | } | ||
485 | |||
486 | static int | ||
487 | evgl_eng_context_destroy(void *data, void *context) | ||
488 | { | ||
489 | Render_Engine *re; | ||
490 | EGLBoolean ret = EGL_FALSE; | ||
491 | |||
492 | re = (Render_Engine *)data; | ||
493 | if ((!re) || (!context)) | ||
494 | { | ||
495 | ERR("Invalid Render Input Data. Engine: %p, Context: %p", | ||
496 | data, context); | ||
497 | return 0; | ||
498 | } | ||
499 | |||
500 | ret = eglDestroyContext(eng_get_ob(re)->egl.disp, (EGLContext)context); | ||
501 | if (ret == EGL_TRUE) return 1; | ||
502 | |||
503 | return 0; | ||
504 | } | ||
505 | |||
506 | static const char * | ||
507 | evgl_eng_string_get(void *data) | ||
508 | { | ||
509 | Render_Engine *re; | ||
510 | |||
511 | re = (Render_Engine *)data; | ||
512 | if (!re) | ||
513 | { | ||
514 | ERR("Invalid Render Engine Data!"); | ||
515 | return NULL; | ||
516 | } | ||
517 | |||
518 | return eglQueryString(eng_get_ob(re)->egl.disp, EGL_EXTENSIONS); | ||
519 | } | ||
520 | |||
521 | static void * | ||
522 | evgl_eng_proc_address_get(const char *name) | ||
523 | { | ||
524 | if (glsym_eglGetProcAddress) return glsym_eglGetProcAddress(name); | ||
525 | return dlsym(RTLD_DEFAULT, name); | ||
526 | } | ||
527 | |||
528 | static int | ||
529 | evgl_eng_rotation_angle_get(void *data) | ||
530 | { | ||
531 | Render_Engine *re; | ||
532 | |||
533 | re = (Render_Engine *)data; | ||
534 | if (!re) | ||
535 | { | ||
536 | ERR("Invalid Render Engine Data!"); | ||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | if ((eng_get_ob(re)) && (eng_get_ob(re)->gl_context)) | ||
541 | return eng_get_ob(re)->gl_context->rot; | ||
542 | else | ||
543 | { | ||
544 | ERR("Unable to retrieve rotation angle."); | ||
545 | return 0; | ||
546 | } | ||
547 | } | ||
548 | |||
549 | static Eina_Bool | ||
550 | eng_preload_make_current(void *data, void *doit) | ||
551 | { | ||
552 | Outbuf *ob; | ||
553 | |||
554 | ob = (Outbuf *)data; | ||
555 | if (!ob) return EINA_FALSE; | ||
556 | |||
557 | if (doit) | ||
558 | { | ||
559 | if (!eglMakeCurrent(ob->egl.disp, ob->egl.surface[0], | ||
560 | ob->egl.surface[0], ob->egl.context[0])) | ||
561 | return EINA_FALSE; | ||
562 | } | ||
563 | else | ||
564 | { | ||
565 | if (!eglMakeCurrent(ob->egl.disp, EGL_NO_SURFACE, | ||
566 | EGL_NO_SURFACE, EGL_NO_CONTEXT)) | ||
567 | return EINA_FALSE; | ||
568 | } | ||
569 | |||
570 | return EINA_TRUE; | ||
571 | } | ||
572 | |||
573 | static void | ||
574 | _re_winfree(Render_Engine *re) | ||
575 | { | ||
576 | if (!re) return; | ||
577 | if (!eng_get_ob(re)->surf) return; | ||
578 | glsym_evas_gl_preload_render_relax(eng_preload_make_current, eng_get_ob(re)); | ||
579 | evas_outbuf_unsurf(eng_get_ob(re)); | ||
580 | } | ||
581 | |||
582 | static void | ||
583 | _native_cb_bind(void *data EINA_UNUSED, void *image) | ||
584 | { | ||
585 | Evas_GL_Image *img; | ||
586 | Native *n; | ||
587 | |||
588 | if (!(img = image)) return; | ||
589 | if (!(n = img->native.data)) return; | ||
590 | |||
591 | if (n->ns.type == EVAS_NATIVE_SURFACE_WL) | ||
592 | { | ||
593 | if (n->egl_surface) | ||
594 | { | ||
595 | if (glsym_glEGLImageTargetTexture2DOES) | ||
596 | { | ||
597 | glsym_glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, n->egl_surface); | ||
598 | if (eglGetError() != EGL_SUCCESS) | ||
599 | ERR("glEGLImageTargetTexture2DOES() failed."); | ||
600 | } | ||
601 | else | ||
602 | ERR("Try glEGLImageTargetTexture2DOES on EGL with no support"); | ||
603 | } | ||
604 | } | ||
605 | else if (n->ns.type == EVAS_NATIVE_SURFACE_OPENGL) | ||
606 | glBindTexture(GL_TEXTURE_2D, n->ns.data.opengl.texture_id); | ||
607 | |||
608 | /* TODO: NATIVE_SURFACE_TBM and NATIVE_SURFACE_EVASGL */ | ||
609 | } | ||
610 | |||
611 | static void | ||
612 | _native_cb_unbind(void *data EINA_UNUSED, void *image) | ||
613 | { | ||
614 | Evas_GL_Image *img; | ||
615 | Native *n; | ||
616 | |||
617 | if (!(img = image)) return; | ||
618 | if (!(n = img->native.data)) return; | ||
619 | |||
620 | else if (n->ns.type == EVAS_NATIVE_SURFACE_OPENGL) | ||
621 | glBindTexture(GL_TEXTURE_2D, 0); | ||
622 | |||
623 | /* TODO: NATIVE_SURFACE_TBM and NATIVE_SURFACE_EVASGL */ | ||
624 | } | ||
625 | |||
626 | static void | ||
627 | _native_cb_free(void *data, void *image) | ||
628 | { | ||
629 | Render_Engine *re; | ||
630 | Outbuf *ob; | ||
631 | Evas_GL_Image *img; | ||
632 | Native *n; | ||
633 | uint32_t texid; | ||
634 | void *wlid; | ||
635 | |||
636 | if (!(re = (Render_Engine *)data)) return; | ||
637 | if (!(img = image)) return; | ||
638 | if (!(n = img->native.data)) return; | ||
639 | if (!(ob = eng_get_ob(re))) return; | ||
640 | |||
641 | if (n->ns.type == EVAS_NATIVE_SURFACE_WL) | ||
642 | { | ||
643 | wlid = (void*)n->wl_buf; | ||
644 | eina_hash_del(ob->gl_context->shared->native_wl_hash, &wlid, img); | ||
645 | if (n->egl_surface) | ||
646 | { | ||
647 | if (glsym_eglDestroyImage) | ||
648 | { | ||
649 | glsym_eglDestroyImage(ob->egl.disp, n->egl_surface); | ||
650 | if (eglGetError() != EGL_SUCCESS) | ||
651 | ERR("eglDestroyImage() failed."); | ||
652 | } | ||
653 | else | ||
654 | ERR("Try eglDestroyImage on EGL with no support"); | ||
655 | } | ||
656 | } | ||
657 | else if (n->ns.type == EVAS_NATIVE_SURFACE_OPENGL) | ||
658 | { | ||
659 | texid = n->ns.data.opengl.texture_id; | ||
660 | eina_hash_del(ob->gl_context->shared->native_tex_hash, &texid, img); | ||
661 | } | ||
662 | |||
663 | img->native.data = NULL; | ||
664 | img->native.func.data = NULL; | ||
665 | img->native.func.bind = NULL; | ||
666 | img->native.func.unbind = NULL; | ||
667 | img->native.func.free = NULL; | ||
668 | |||
669 | free(n); | ||
670 | } | ||
671 | |||
672 | /* engine specific override functions */ | ||
673 | static void * | ||
674 | eng_info(Evas *eo_e EINA_UNUSED) | ||
675 | { | ||
676 | Evas_Engine_Info_Eglfs *info; | ||
677 | |||
678 | /* try to allocate space for our engine info */ | ||
679 | if (!(info = calloc(1, sizeof(Evas_Engine_Info_Eglfs)))) | ||
680 | return NULL; | ||
681 | |||
682 | info->magic.magic = rand(); | ||
683 | info->render_mode = EVAS_RENDER_MODE_BLOCKING; | ||
684 | |||
685 | return info; | ||
686 | } | ||
687 | |||
688 | static void | ||
689 | eng_info_free(Evas *eo_e EINA_UNUSED, void *in) | ||
690 | { | ||
691 | Evas_Engine_Info_Eglfs *info; | ||
692 | |||
693 | if ((info = (Evas_Engine_Info_Eglfs *)in)) | ||
694 | free(info); | ||
695 | } | ||
696 | |||
697 | static int | ||
698 | eng_setup(Evas *evas, void *in) | ||
699 | { | ||
700 | Evas_Engine_Info_Eglfs *info; | ||
701 | Evas_Public_Data *epd; | ||
702 | Render_Engine *re; | ||
703 | Render_Engine_Swap_Mode swap_mode = MODE_FULL; | ||
704 | const char *s = NULL; | ||
705 | |||
706 | /* try to cast to our engine info structure */ | ||
707 | if (!(info = (Evas_Engine_Info_Eglfs *)in)) return 0; | ||
708 | |||
709 | /* try to get the evas public data */ | ||
710 | if (!(epd = eo_data_scope_get(evas, EVAS_CANVAS_CLASS))) return 0; | ||
711 | |||
712 | s = getenv("EVAS_GL_SWAP_MODE"); | ||
713 | if (s) | ||
714 | { | ||
715 | if ((!strcasecmp(s, "full")) || (!strcasecmp(s, "f"))) | ||
716 | swap_mode = MODE_FULL; | ||
717 | else if ((!strcasecmp(s, "copy")) || (!strcasecmp(s, "c"))) | ||
718 | swap_mode = MODE_COPY; | ||
719 | else if ((!strcasecmp(s, "double")) || | ||
720 | (!strcasecmp(s, "d")) || (!strcasecmp(s, "2"))) | ||
721 | swap_mode = MODE_DOUBLE; | ||
722 | else if ((!strcasecmp(s, "triple")) || | ||
723 | (!strcasecmp(s, "t")) || (!strcasecmp(s, "3"))) | ||
724 | swap_mode = MODE_TRIPLE; | ||
725 | else if ((!strcasecmp(s, "quadruple")) || | ||
726 | (!strcasecmp(s, "q")) || (!strcasecmp(s, "4"))) | ||
727 | swap_mode = MODE_QUADRUPLE; | ||
728 | } | ||
729 | else | ||
730 | { | ||
731 | // in most gl implementations - egl and glx here that we care about the TEND | ||
732 | // to either swap or copy backbuffer and front buffer, but strictly that is | ||
733 | // not true. technically backbuffer content is totally undefined after a swap | ||
734 | // and thus you MUST re-render all of it, thus MODE_FULL | ||
735 | swap_mode = MODE_FULL; | ||
736 | // BUT... reality is that lmost every implementation copies or swaps so | ||
737 | // triple buffer mode can be used as it is a superset of double buffer and | ||
738 | // copy (though using those explicitly is more efficient). so let's play with | ||
739 | // triple buffer mdoe as a default and see. | ||
740 | // re->mode = MODE_TRIPLE; | ||
741 | // XXX: note - the above seems to break on some older intel chipsets and | ||
742 | // drivers. it seems we CANT depend on backbuffer staying around. bugger! | ||
743 | switch (info->info.swap_mode) | ||
744 | { | ||
745 | case EVAS_ENGINE_EGLFS_SWAP_MODE_FULL: | ||
746 | swap_mode = MODE_FULL; | ||
747 | break; | ||
748 | case EVAS_ENGINE_EGLFS_SWAP_MODE_COPY: | ||
749 | swap_mode = MODE_COPY; | ||
750 | break; | ||
751 | case EVAS_ENGINE_EGLFS_SWAP_MODE_DOUBLE: | ||
752 | swap_mode = MODE_DOUBLE; | ||
753 | break; | ||
754 | case EVAS_ENGINE_EGLFS_SWAP_MODE_TRIPLE: | ||
755 | swap_mode = MODE_TRIPLE; | ||
756 | break; | ||
757 | case EVAS_ENGINE_EGLFS_SWAP_MODE_QUADRUPLE: | ||
758 | swap_mode = MODE_QUADRUPLE; | ||
759 | break; | ||
760 | default: | ||
761 | swap_mode = MODE_AUTO; | ||
762 | break; | ||
763 | } | ||
764 | } | ||
765 | |||
766 | if (!(re = epd->engine.data.output)) | ||
767 | { | ||
768 | Outbuf *ob; | ||
769 | Render_Engine_Merge_Mode merge_mode = MERGE_BOUNDING; | ||
770 | |||
771 | if (!initted) | ||
772 | { | ||
773 | evas_common_init(); | ||
774 | glsym_evas_gl_preload_init(); | ||
775 | } | ||
776 | |||
777 | if (!(re = calloc(1, sizeof(Render_Engine)))) return 0; | ||
778 | |||
779 | /* try to create new outbuf */ | ||
780 | ob = evas_outbuf_new(info, epd->output.w, epd->output.h, swap_mode); | ||
781 | if (!ob) | ||
782 | { | ||
783 | free(re); | ||
784 | return 0; | ||
785 | } | ||
786 | |||
787 | ob->evas = evas; | ||
788 | |||
789 | if (!evas_render_engine_gl_generic_init(&re->generic, ob, | ||
790 | evas_outbuf_buffer_state_get, | ||
791 | evas_outbuf_rot_get, | ||
792 | evas_outbuf_reconfigure, | ||
793 | evas_outbuf_update_region_first_rect, | ||
794 | evas_outbuf_update_region_new, | ||
795 | evas_outbuf_update_region_push, | ||
796 | evas_outbuf_update_region_free, | ||
797 | NULL, | ||
798 | evas_outbuf_flush, | ||
799 | evas_outbuf_free, | ||
800 | evas_outbuf_use, | ||
801 | evas_outbuf_gl_context_get, | ||
802 | evas_outbuf_egl_display_get, | ||
803 | evas_outbuf_gl_context_new, | ||
804 | evas_outbuf_gl_context_use, | ||
805 | &evgl_funcs, ob->w, ob->h)) | ||
806 | { | ||
807 | /* free outbuf */ | ||
808 | |||
809 | evas_outbuf_free(ob); | ||
810 | free(re); | ||
811 | return 0; | ||
812 | } | ||
813 | |||
814 | epd->engine.data.output = re; | ||
815 | gl_wins++; | ||
816 | |||
817 | s = getenv("EVAS_GL_PARTIAL_MERGE"); | ||
818 | if (s) | ||
819 | { | ||
820 | if ((!strcmp(s, "bounding")) || (!strcmp(s, "b"))) | ||
821 | merge_mode = MERGE_BOUNDING; | ||
822 | else if ((!strcmp(s, "full")) || (!strcmp(s, "f"))) | ||
823 | merge_mode = MERGE_FULL; | ||
824 | } | ||
825 | |||
826 | evas_render_engine_software_generic_merge_mode_set(&re->generic.software, merge_mode); | ||
827 | |||
828 | if (!initted) | ||
829 | { | ||
830 | gl_extn_veto(re); | ||
831 | initted = EINA_TRUE; | ||
832 | } | ||
833 | } | ||
834 | else | ||
835 | { | ||
836 | if (eng_get_ob(re) && _re_wincheck(eng_get_ob(re))) | ||
837 | { | ||
838 | if ((info->info.depth != eng_get_ob(re)->depth) || | ||
839 | (info->info.destination_alpha != eng_get_ob(re)->destination_alpha)) | ||
840 | { | ||
841 | Outbuf *ob, *ob_old; | ||
842 | |||
843 | ob_old = re->generic.software.ob; | ||
844 | re->generic.software.ob = NULL; | ||
845 | gl_wins--; | ||
846 | |||
847 | ob = evas_outbuf_new(info, epd->output.w, epd->output.h, swap_mode); | ||
848 | if (!ob) | ||
849 | { | ||
850 | if (ob_old) evas_outbuf_free(ob_old); | ||
851 | free(re); | ||
852 | return 0; | ||
853 | } | ||
854 | |||
855 | evas_outbuf_use(ob); | ||
856 | if (ob_old) evas_outbuf_free(ob_old); | ||
857 | |||
858 | ob->evas = evas; | ||
859 | |||
860 | evas_render_engine_software_generic_update(&re->generic.software, ob, | ||
861 | epd->output.w, epd->output.h); | ||
862 | |||
863 | gl_wins++; | ||
864 | } | ||
865 | else if ((eng_get_ob(re)->w != epd->output.w) || | ||
866 | (eng_get_ob(re)->h != epd->output.h) || | ||
867 | (info->info.rotation != eng_get_ob(re)->rotation)) | ||
868 | { | ||
869 | evas_outbuf_reconfigure(eng_get_ob(re), | ||
870 | epd->output.w, epd->output.h, | ||
871 | info->info.rotation, | ||
872 | info->info.depth); | ||
873 | } | ||
874 | } | ||
875 | } | ||
876 | |||
877 | if (!eng_get_ob(re)) | ||
878 | { | ||
879 | free(re); | ||
880 | return 0; | ||
881 | } | ||
882 | |||
883 | if (!epd->engine.data.output) | ||
884 | { | ||
885 | if (eng_get_ob(re)) | ||
886 | { | ||
887 | evas_outbuf_free(eng_get_ob(re)); | ||
888 | gl_wins--; | ||
889 | } | ||
890 | free(re); | ||
891 | return 0; | ||
892 | } | ||
893 | |||
894 | if (re->generic.software.tb) | ||
895 | evas_common_tilebuf_free(re->generic.software.tb); | ||
896 | re->generic.software.tb = | ||
897 | evas_common_tilebuf_new(epd->output.w, epd->output.h); | ||
898 | if (re->generic.software.tb) | ||
899 | evas_common_tilebuf_set_tile_size(re->generic.software.tb, | ||
900 | TILESIZE, TILESIZE); | ||
901 | |||
902 | if (re->generic.software.tb) | ||
903 | evas_render_engine_software_generic_tile_strict_set(&re->generic.software, EINA_TRUE); | ||
904 | |||
905 | if (!epd->engine.data.context) | ||
906 | { | ||
907 | epd->engine.data.context = | ||
908 | epd->engine.func->context_new(epd->engine.data.output); | ||
909 | } | ||
910 | |||
911 | evas_outbuf_use(eng_get_ob(re)); | ||
912 | |||
913 | return 1; | ||
914 | } | ||
915 | |||
916 | static void | ||
917 | eng_output_free(void *data) | ||
918 | { | ||
919 | Render_Engine *re; | ||
920 | |||
921 | re = (Render_Engine *)data; | ||
922 | if (re) | ||
923 | { | ||
924 | glsym_evas_gl_preload_render_relax(eng_preload_make_current, eng_get_ob(re)); | ||
925 | |||
926 | if (gl_wins == 1) glsym_evgl_engine_shutdown(re); | ||
927 | |||
928 | /* NB: evas_render_engine_software_generic_clean() frees ob */ | ||
929 | evas_render_engine_software_generic_clean(&re->generic.software); | ||
930 | |||
931 | gl_wins--; | ||
932 | |||
933 | free(re); | ||
934 | } | ||
935 | |||
936 | if ((initted == EINA_TRUE) && (gl_wins == 0)) | ||
937 | { | ||
938 | glsym_evas_gl_preload_shutdown(); | ||
939 | evas_common_shutdown(); | ||
940 | initted = EINA_FALSE; | ||
941 | } | ||
942 | } | ||
943 | |||
944 | static Eina_Bool | ||
945 | eng_canvas_alpha_get(void *data, void *info EINA_UNUSED) | ||
946 | { | ||
947 | Render_Engine *re; | ||
948 | |||
949 | re = (Render_Engine *)data; | ||
950 | if (!re) return EINA_FALSE; | ||
951 | |||
952 | return eng_get_ob(re)->destination_alpha; | ||
953 | } | ||
954 | |||
955 | static void | ||
956 | eng_output_dump(void *data) | ||
957 | { | ||
958 | Render_Engine *re; | ||
959 | |||
960 | re = (Render_Engine *)data; | ||
961 | if (!re) return; | ||
962 | |||
963 | evas_common_image_image_all_unload(); | ||
964 | evas_common_font_font_all_unload(); | ||
965 | glsym_evas_gl_common_image_all_unload(eng_get_ob(re)->gl_context); | ||
966 | _re_winfree(re); | ||
967 | } | ||
968 | |||
969 | static void * | ||
970 | eng_image_native_set(void *data, void *image, void *native) | ||
971 | { | ||
972 | Render_Engine *re; | ||
973 | Outbuf *ob; | ||
974 | Native *n; | ||
975 | Evas_Native_Surface *ns; | ||
976 | Evas_GL_Image *img, *img2; | ||
977 | unsigned int tex = 0, fbo = 0; | ||
978 | uint32_t texid; | ||
979 | void *wlid, *wl_buf = NULL; | ||
980 | |||
981 | re = (Render_Engine *)data; | ||
982 | if (!re) return NULL; | ||
983 | |||
984 | ob = eng_get_ob(re); | ||
985 | if (!ob) return NULL; | ||
986 | |||
987 | ns = native; | ||
988 | |||
989 | if (!(img = image)) | ||
990 | { | ||
991 | if ((ns) && (ns->type == EVAS_NATIVE_SURFACE_OPENGL)) | ||
992 | { | ||
993 | img = | ||
994 | glsym_evas_gl_common_image_new_from_data(ob->gl_context, | ||
995 | ns->data.opengl.w, | ||
996 | ns->data.opengl.h, | ||
997 | NULL, 1, | ||
998 | EVAS_COLORSPACE_ARGB8888); | ||
999 | } | ||
1000 | else | ||
1001 | return NULL; | ||
1002 | } | ||
1003 | |||
1004 | if (ns) | ||
1005 | { | ||
1006 | if (ns->type == EVAS_NATIVE_SURFACE_WL) | ||
1007 | { | ||
1008 | wl_buf = ns->data.wl.legacy_buffer; | ||
1009 | if (img->native.data) | ||
1010 | { | ||
1011 | Evas_Native_Surface *ens; | ||
1012 | |||
1013 | ens = img->native.data; | ||
1014 | if (ens->data.wl.legacy_buffer == wl_buf) | ||
1015 | return img; | ||
1016 | } | ||
1017 | } | ||
1018 | else if (ns->type == EVAS_NATIVE_SURFACE_OPENGL) | ||
1019 | { | ||
1020 | tex = ns->data.opengl.texture_id; | ||
1021 | fbo = ns->data.opengl.framebuffer_id; | ||
1022 | if (img->native.data) | ||
1023 | { | ||
1024 | Evas_Native_Surface *ens; | ||
1025 | |||
1026 | ens = img->native.data; | ||
1027 | if ((ens->data.opengl.texture_id == tex) && | ||
1028 | (ens->data.opengl.framebuffer_id == fbo)) | ||
1029 | return img; | ||
1030 | } | ||
1031 | } | ||
1032 | } | ||
1033 | |||
1034 | if ((!ns) && (!img->native.data)) return img; | ||
1035 | |||
1036 | evas_outbuf_use(ob); | ||
1037 | |||
1038 | if (img->native.data) | ||
1039 | { | ||
1040 | if (img->native.func.free) | ||
1041 | img->native.func.free(img->native.func.data, img); | ||
1042 | glsym_evas_gl_common_image_native_disable(img); | ||
1043 | } | ||
1044 | |||
1045 | if (!ns) return img; | ||
1046 | |||
1047 | if (ns->type == EVAS_NATIVE_SURFACE_WL) | ||
1048 | { | ||
1049 | wlid = wl_buf; | ||
1050 | img2 = eina_hash_find(ob->gl_context->shared->native_wl_hash, &wlid); | ||
1051 | if (img2 == img) return img; | ||
1052 | if (img2) | ||
1053 | { | ||
1054 | if((n = img2->native.data)) | ||
1055 | { | ||
1056 | glsym_evas_gl_common_image_ref(img2); | ||
1057 | glsym_evas_gl_common_image_free(img); | ||
1058 | return img2; | ||
1059 | } | ||
1060 | } | ||
1061 | } | ||
1062 | else if (ns->type == EVAS_NATIVE_SURFACE_OPENGL) | ||
1063 | { | ||
1064 | texid = tex; | ||
1065 | img2 = eina_hash_find(ob->gl_context->shared->native_tex_hash, &texid); | ||
1066 | if (img2 == img) return img; | ||
1067 | if (img2) | ||
1068 | { | ||
1069 | if ((n = img2->native.data)) | ||
1070 | { | ||
1071 | glsym_evas_gl_common_image_ref(img2); | ||
1072 | glsym_evas_gl_common_image_free(img); | ||
1073 | return img2; | ||
1074 | } | ||
1075 | } | ||
1076 | } | ||
1077 | |||
1078 | img2 = glsym_evas_gl_common_image_new_from_data(ob->gl_context, img->w, | ||
1079 | img->h, NULL, img->alpha, | ||
1080 | EVAS_COLORSPACE_ARGB8888); | ||
1081 | glsym_evas_gl_common_image_free(img); | ||
1082 | |||
1083 | if (!(img = img2)) return NULL; | ||
1084 | |||
1085 | if (ns->type == EVAS_NATIVE_SURFACE_WL) | ||
1086 | { | ||
1087 | if (native) | ||
1088 | { | ||
1089 | if ((n = calloc(1, sizeof(Native)))) | ||
1090 | { | ||
1091 | EGLint attribs[3]; | ||
1092 | int format, yinvert = 1; | ||
1093 | |||
1094 | glsym_eglQueryWaylandBufferWL(ob->egl.disp, wl_buf, | ||
1095 | EGL_TEXTURE_FORMAT, &format); | ||
1096 | if ((format != EGL_TEXTURE_RGB) && | ||
1097 | (format != EGL_TEXTURE_RGBA)) | ||
1098 | { | ||
1099 | ERR("eglQueryWaylandBufferWL() %d format is not supported ", format); | ||
1100 | glsym_evas_gl_common_image_free(img); | ||
1101 | free(n); | ||
1102 | return NULL; | ||
1103 | } | ||
1104 | |||
1105 | attribs[0] = EGL_WAYLAND_PLANE_WL; | ||
1106 | attribs[1] = 0; //if plane is 1 then 0, if plane is 2 then 1 | ||
1107 | attribs[2] = EGL_NONE; | ||
1108 | |||
1109 | memcpy(&(n->ns), ns, sizeof(Evas_Native_Surface)); | ||
1110 | glsym_eglQueryWaylandBufferWL(ob->egl.disp, wl_buf, | ||
1111 | EGL_WAYLAND_Y_INVERTED_WL, | ||
1112 | &yinvert); | ||
1113 | eina_hash_add(ob->gl_context->shared->native_wl_hash, | ||
1114 | &wlid, img); | ||
1115 | |||
1116 | n->wl_buf = wl_buf; | ||
1117 | if (glsym_eglCreateImage) | ||
1118 | n->egl_surface = glsym_eglCreateImage(ob->egl.disp, | ||
1119 | NULL, | ||
1120 | EGL_WAYLAND_BUFFER_WL, | ||
1121 | wl_buf, attribs); | ||
1122 | else | ||
1123 | { | ||
1124 | ERR("Try eglCreateImage on EGL with no support"); | ||
1125 | eina_hash_del(ob->gl_context->shared->native_wl_hash, | ||
1126 | &wlid, img); | ||
1127 | glsym_evas_gl_common_image_free(img); | ||
1128 | free(n); | ||
1129 | return NULL; | ||
1130 | } | ||
1131 | |||
1132 | if (!n->egl_surface) | ||
1133 | { | ||
1134 | ERR("eglCreatePixmapSurface() for %p failed", wl_buf); | ||
1135 | eina_hash_del(ob->gl_context->shared->native_wl_hash, | ||
1136 | &wlid, img); | ||
1137 | glsym_evas_gl_common_image_free(img); | ||
1138 | free(n); | ||
1139 | return NULL; | ||
1140 | } | ||
1141 | |||
1142 | //XXX: workaround for mesa-10.2.8 | ||
1143 | // mesa's eglQueryWaylandBufferWL() with EGL_WAYLAND_Y_INVERTED_WL works incorrect. | ||
1144 | //img->native.yinvert = yinvert; | ||
1145 | img->native.yinvert = 1; | ||
1146 | img->native.loose = 0; | ||
1147 | img->native.data = n; | ||
1148 | img->native.func.data = re; | ||
1149 | img->native.func.bind = _native_cb_bind; | ||
1150 | img->native.func.unbind = _native_cb_unbind; | ||
1151 | img->native.func.free = _native_cb_free; | ||
1152 | img->native.target = GL_TEXTURE_2D; | ||
1153 | img->native.mipmap = 0; | ||
1154 | |||
1155 | glsym_evas_gl_common_image_native_enable(img); | ||
1156 | } | ||
1157 | } | ||
1158 | } | ||
1159 | else if (ns->type == EVAS_NATIVE_SURFACE_OPENGL) | ||
1160 | { | ||
1161 | if (native) | ||
1162 | { | ||
1163 | if ((n = calloc(1, sizeof(Native)))) | ||
1164 | { | ||
1165 | memcpy(&(n->ns), ns, sizeof(Evas_Native_Surface)); | ||
1166 | eina_hash_add(ob->gl_context->shared->native_tex_hash, | ||
1167 | &texid, img); | ||
1168 | |||
1169 | n->egl_surface = 0; | ||
1170 | |||
1171 | img->native.yinvert = 0; | ||
1172 | img->native.loose = 0; | ||
1173 | img->native.data = n; | ||
1174 | img->native.func.data = re; | ||
1175 | img->native.func.bind = _native_cb_bind; | ||
1176 | img->native.func.unbind = _native_cb_unbind; | ||
1177 | img->native.func.free = _native_cb_free; | ||
1178 | img->native.target = GL_TEXTURE_2D; | ||
1179 | img->native.mipmap = 0; | ||
1180 | |||
1181 | glsym_evas_gl_common_image_native_enable(img); | ||
1182 | } | ||
1183 | } | ||
1184 | } | ||
1185 | |||
1186 | /* TODO: NATIVE_SURFACE_TBM and NATIVE_SURFACE_EVASGL */ | ||
1187 | |||
1188 | return img; | ||
1189 | } | ||
1190 | |||
1191 | /* module api functions */ | ||
1192 | static int | ||
1193 | module_open(Evas_Module *em) | ||
1194 | { | ||
1195 | /* check for valid evas module */ | ||
1196 | if (!em) return 0; | ||
1197 | |||
1198 | /* get whatever engine module we inherit from */ | ||
1199 | if (!_evas_module_engine_inherit(&pfunc, "gl_generic")) return 0; | ||
1200 | |||
1201 | /* try to create eina logging domain */ | ||
1202 | if (_evas_engine_eglfs_log_dom < 0) | ||
1203 | { | ||
1204 | _evas_engine_eglfs_log_dom = | ||
1205 | eina_log_domain_register("evas-eglfs", EVAS_DEFAULT_LOG_COLOR); | ||
1206 | } | ||
1207 | |||
1208 | /* if we could not create a logging domain, error out */ | ||
1209 | if (_evas_engine_eglfs_log_dom < 0) | ||
1210 | { | ||
1211 | EINA_LOG_ERR("Can not create a module log domain."); | ||
1212 | return 0; | ||
1213 | } | ||
1214 | |||
1215 | /* store it for later use */ | ||
1216 | func = pfunc; | ||
1217 | |||
1218 | /* now to override methods */ | ||
1219 | EVAS_API_OVERRIDE(info, &func, eng_); | ||
1220 | EVAS_API_OVERRIDE(info_free, &func, eng_); | ||
1221 | EVAS_API_OVERRIDE(setup, &func, eng_); | ||
1222 | EVAS_API_OVERRIDE(canvas_alpha_get, &func, eng_); | ||
1223 | EVAS_API_OVERRIDE(output_free, &func, eng_); | ||
1224 | EVAS_API_OVERRIDE(output_dump, &func, eng_); | ||
1225 | EVAS_API_OVERRIDE(image_native_set, &func, eng_); | ||
1226 | |||
1227 | setenv("EGL_PLATFORM", "fbdev", 1); | ||
1228 | |||
1229 | gl_symbols(); | ||
1230 | |||
1231 | /* now advertise out own api */ | ||
1232 | em->functions = (void *)(&func); | ||
1233 | |||
1234 | return 1; | ||
1235 | } | ||
1236 | |||
1237 | static void | ||
1238 | module_close(Evas_Module *em EINA_UNUSED) | ||
1239 | { | ||
1240 | /* unregister the eina log domain for this engine */ | ||
1241 | eina_log_domain_unregister(_evas_engine_eglfs_log_dom); | ||
1242 | _evas_engine_eglfs_log_dom = -1; | ||
1243 | } | ||
1244 | |||
1245 | static Evas_Module_Api evas_modapi = | ||
1246 | { | ||
1247 | EVAS_MODULE_API_VERSION, "eglfs", "none", { module_open, module_close } | ||
1248 | }; | ||
1249 | |||
1250 | EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_ENGINE, engine, eglfs); | ||
1251 | |||
1252 | #ifndef EVAS_STATIC_BUILD_EGLFS | ||
1253 | EVAS_EINA_MODULE_DEFINE(engine, eglfs); | ||
1254 | #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 @@ | |||
1 | #ifndef EVAS_ENGINE_H | ||
2 | # define EVAS_ENGINE_H | ||
3 | |||
4 | # include "evas_common_private.h" | ||
5 | # include "evas_macros.h" | ||
6 | # include "evas_private.h" | ||
7 | # include "Evas.h" | ||
8 | # include "Evas_Engine_Eglfs.h" | ||
9 | |||
10 | # define EGL_EGLEXT_PROTOTYPES | ||
11 | # define GL_GLEXT_PROTOTYPES | ||
12 | |||
13 | # include <EGL/egl.h> | ||
14 | # include <EGL/eglext.h> | ||
15 | # include <EGL/eglmesaext.h> | ||
16 | # include <GLES2/gl2.h> | ||
17 | # include <GLES2/gl2ext.h> | ||
18 | # include <hwcomposer.h> | ||
19 | # include <hardware/hardware.h> | ||
20 | # include <hardware/hwcomposer.h> | ||
21 | # include "../gl_generic/Evas_Engine_GL_Generic.h" | ||
22 | |||
23 | extern int _evas_engine_eglfs_log_dom; | ||
24 | extern int _extn_have_buffer_age; | ||
25 | |||
26 | # ifdef ERR | ||
27 | # undef ERR | ||
28 | # endif | ||
29 | # define ERR(...) EINA_LOG_DOM_ERR(_evas_engine_eglfs_log_dom, __VA_ARGS__) | ||
30 | |||
31 | # ifdef DBG | ||
32 | # undef DBG | ||
33 | # endif | ||
34 | # define DBG(...) EINA_LOG_DOM_DBG(_evas_engine_eglfs_log_dom, __VA_ARGS__) | ||
35 | |||
36 | # ifdef INF | ||
37 | # undef INF | ||
38 | # endif | ||
39 | # define INF(...) EINA_LOG_DOM_INFO(_evas_engine_eglfs_log_dom, __VA_ARGS__) | ||
40 | |||
41 | # ifdef WRN | ||
42 | # undef WRN | ||
43 | # endif | ||
44 | # define WRN(...) EINA_LOG_DOM_WARN(_evas_engine_eglfs_log_dom, __VA_ARGS__) | ||
45 | |||
46 | # ifdef CRI | ||
47 | # undef CRI | ||
48 | # endif | ||
49 | # define CRI(...) EINA_LOG_DOM_CRIT(_evas_engine_eglfs_log_dom, __VA_ARGS__) | ||
50 | |||
51 | extern Evas_GL_Common_Context_New glsym_evas_gl_common_context_new; | ||
52 | extern Evas_GL_Common_Context_Call glsym_evas_gl_common_context_flush; | ||
53 | extern Evas_GL_Common_Context_Call glsym_evas_gl_common_context_free; | ||
54 | extern Evas_GL_Common_Context_Call glsym_evas_gl_common_context_use; | ||
55 | extern Evas_GL_Common_Context_Call glsym_evas_gl_common_context_newframe; | ||
56 | extern Evas_GL_Common_Context_Call glsym_evas_gl_common_context_done; | ||
57 | extern Evas_GL_Common_Context_Resize_Call glsym_evas_gl_common_context_resize; | ||
58 | extern Evas_GL_Common_Buffer_Dump_Call glsym_evas_gl_common_buffer_dump; | ||
59 | extern Evas_GL_Preload_Render_Call glsym_evas_gl_preload_render_lock; | ||
60 | extern Evas_GL_Preload_Render_Call glsym_evas_gl_preload_render_unlock; | ||
61 | |||
62 | struct _Context_3D | ||
63 | { | ||
64 | EGLDisplay display; | ||
65 | EGLContext context; | ||
66 | EGLSurface surface; | ||
67 | }; | ||
68 | |||
69 | struct _Outbuf | ||
70 | { | ||
71 | Evas_Engine_Info_Eglfs *info; | ||
72 | Evas_Engine_GL_Context *gl_context; | ||
73 | |||
74 | Evas *evas; // used for pre_swap, post_swap | ||
75 | |||
76 | int w, h; | ||
77 | unsigned int rotation, depth; | ||
78 | Render_Engine_Swap_Mode swap_mode; | ||
79 | |||
80 | struct | ||
81 | { | ||
82 | EGLContext context[1]; | ||
83 | EGLSurface surface[1]; | ||
84 | EGLConfig config; | ||
85 | EGLDisplay disp; | ||
86 | } egl; | ||
87 | |||
88 | struct | ||
89 | { | ||
90 | int prev_age, frame_cnt; | ||
91 | int curr, last, num; | ||
92 | Eina_List *pending_writes; | ||
93 | } priv; | ||
94 | |||
95 | Eina_Bool destination_alpha : 1; | ||
96 | Eina_Bool vsync : 1; | ||
97 | Eina_Bool lost_back : 1; | ||
98 | Eina_Bool surf : 1; | ||
99 | Eina_Bool drew : 1; | ||
100 | }; | ||
101 | |||
102 | Outbuf *evas_outbuf_new(Evas_Engine_Info_Eglfs *info, int w, int h, Render_Engine_Swap_Mode swap_mode); | ||
103 | void evas_outbuf_free(Outbuf *ob); | ||
104 | void evas_outbuf_use(Outbuf *ob); | ||
105 | void evas_outbuf_resurf(Outbuf *ob); | ||
106 | void evas_outbuf_unsurf(Outbuf *ob); | ||
107 | void evas_outbuf_reconfigure(Outbuf *ob, int w, int h, int rot, Outbuf_Depth depth); | ||
108 | Render_Engine_Swap_Mode evas_outbuf_buffer_state_get(Outbuf *ob); | ||
109 | int evas_outbuf_rot_get(Outbuf *ob); | ||
110 | Eina_Bool evas_outbuf_update_region_first_rect(Outbuf *ob); | ||
111 | void *evas_outbuf_update_region_new(Outbuf *ob, int x, int y, int w, int h, int *cx, int *cy, int *cw, int *ch); | ||
112 | void evas_outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int w, int h); | ||
113 | void evas_outbuf_update_region_free(Outbuf *ob, RGBA_Image *update); | ||
114 | void evas_outbuf_flush(Outbuf *ob, Tilebuf_Rect *rects, Evas_Render_Mode render_mode); | ||
115 | Evas_Engine_GL_Context* evas_outbuf_gl_context_get(Outbuf *ob); | ||
116 | void *evas_outbuf_egl_display_get(Outbuf *ob); | ||
117 | Context_3D *evas_outbuf_gl_context_new(Outbuf *ob); | ||
118 | void evas_outbuf_gl_context_use(Context_3D *ctx); | ||
119 | EGLNativeWindowType create_hwcomposernativewindow(void); | ||
120 | |||
121 | static inline Eina_Bool | ||
122 | _re_wincheck(Outbuf *ob) | ||
123 | { | ||
124 | if (ob->surf) return EINA_TRUE; | ||
125 | evas_outbuf_resurf(ob); | ||
126 | ob->lost_back = 1; | ||
127 | if (!ob->surf) ERR("GL engine can't re-create window surface!"); | ||
128 | return EINA_FALSE; | ||
129 | } | ||
130 | |||
131 | extern unsigned int (*glsym_eglSwapBuffersWithDamage)(EGLDisplay a, void *b, const EGLint *d, EGLint c); | ||
132 | |||
133 | #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 @@ | |||
1 | #include "evas_engine.h" | ||
2 | |||
3 | #include <hybris/hwcomposerwindow/hwcomposer.h> | ||
4 | #include <hardware/hwcomposer.h> | ||
5 | #include <hardware/hardware.h> | ||
6 | #include <android-config.h> | ||
7 | |||
8 | static hwc_layer_1_t *fblayer; | ||
9 | static hwc_composer_device_1_t *hwcDevicePtr; | ||
10 | static hwc_display_contents_1_t **mList; | ||
11 | |||
12 | void present(void *user_data, struct ANativeWindow *window, | ||
13 | struct ANativeWindowBuffer *buffer) | ||
14 | { | ||
15 | |||
16 | int oldretire = mList[0]->retireFenceFd; | ||
17 | mList[0]->retireFenceFd = -1; | ||
18 | fblayer->handle = buffer->handle; | ||
19 | fblayer->acquireFenceFd = HWCNativeBufferGetFence(buffer); | ||
20 | fblayer->releaseFenceFd = -1; | ||
21 | int err = hwcDevicePtr->prepare(hwcDevicePtr, HWC_NUM_DISPLAY_TYPES, mList); | ||
22 | //assert(err == 0); | ||
23 | |||
24 | err = hwcDevicePtr->set(hwcDevicePtr, HWC_NUM_DISPLAY_TYPES, mList); | ||
25 | //assert(err == 0); | ||
26 | HWCNativeBufferSetFence(buffer, fblayer->releaseFenceFd); | ||
27 | |||
28 | if (oldretire != -1) | ||
29 | { | ||
30 | sync_wait(oldretire, -1); | ||
31 | close(oldretire); | ||
32 | } | ||
33 | } | ||
34 | |||
35 | |||
36 | EGLNativeWindowType create_hwcomposernativewindow(void) | ||
37 | { | ||
38 | int err; | ||
39 | hw_module_t *hwcModule = 0; | ||
40 | hwcDevicePtr = 0; | ||
41 | |||
42 | err = hw_get_module(HWC_HARDWARE_MODULE_ID, (const hw_module_t **) &hwcModule); | ||
43 | //assert(err == 0); | ||
44 | |||
45 | err = hwc_open_1(hwcModule, &hwcDevicePtr); | ||
46 | //assert(err == 0); | ||
47 | |||
48 | hwcDevicePtr->blank(hwcDevicePtr, 0, 0); | ||
49 | |||
50 | uint32_t configs[5]; | ||
51 | size_t numConfigs = 5; | ||
52 | |||
53 | err = hwcDevicePtr->getDisplayConfigs(hwcDevicePtr, 0, configs, &numConfigs); | ||
54 | //assert (err == 0); | ||
55 | |||
56 | int32_t attr_values[2]; | ||
57 | uint32_t attributes[] = { HWC_DISPLAY_WIDTH, HWC_DISPLAY_HEIGHT, HWC_DISPLAY_NO_ATTRIBUTE }; | ||
58 | |||
59 | hwcDevicePtr->getDisplayAttributes(hwcDevicePtr, 0, | ||
60 | configs[0], attributes, attr_values); | ||
61 | |||
62 | size_t size = sizeof(hwc_display_contents_1_t) + 2 * sizeof(hwc_layer_1_t); | ||
63 | hwc_display_contents_1_t *list = (hwc_display_contents_1_t *) malloc(size); | ||
64 | mList = (hwc_display_contents_1_t **) malloc(HWC_NUM_DISPLAY_TYPES * sizeof(hwc_display_contents_1_t *)); | ||
65 | const hwc_rect_t r = { 0, 0, attr_values[0], attr_values[1] }; | ||
66 | |||
67 | int counter = 0; | ||
68 | for (; counter < HWC_NUM_DISPLAY_TYPES; counter++) | ||
69 | mList[counter] = NULL; | ||
70 | // Assign buffer only to the first item, otherwise you get tearing | ||
71 | // if passed the same to multiple places | ||
72 | mList[0] = list; | ||
73 | |||
74 | fblayer = &list->hwLayers[0]; | ||
75 | memset(fblayer, 0, sizeof(hwc_layer_1_t)); | ||
76 | fblayer->compositionType = HWC_FRAMEBUFFER; | ||
77 | fblayer->hints = 0; | ||
78 | fblayer->flags = 0; | ||
79 | fblayer->handle = 0; | ||
80 | fblayer->transform = 0; | ||
81 | fblayer->blending = HWC_BLENDING_NONE; | ||
82 | fblayer->sourceCrop = r; | ||
83 | fblayer->displayFrame = r; | ||
84 | fblayer->visibleRegionScreen.numRects = 1; | ||
85 | fblayer->visibleRegionScreen.rects = &fblayer->displayFrame; | ||
86 | fblayer->acquireFenceFd = -1; | ||
87 | fblayer->releaseFenceFd = -1; | ||
88 | fblayer = &list->hwLayers[1]; | ||
89 | memset(fblayer, 0, sizeof(hwc_layer_1_t)); | ||
90 | fblayer->compositionType = HWC_FRAMEBUFFER_TARGET; | ||
91 | fblayer->hints = 0; | ||
92 | fblayer->flags = 0; | ||
93 | fblayer->handle = 0; | ||
94 | fblayer->transform = 0; | ||
95 | fblayer->blending = HWC_BLENDING_NONE; | ||
96 | fblayer->sourceCrop = r; | ||
97 | fblayer->displayFrame = r; | ||
98 | fblayer->visibleRegionScreen.numRects = 1; | ||
99 | fblayer->visibleRegionScreen.rects = &fblayer->displayFrame; | ||
100 | fblayer->acquireFenceFd = -1; | ||
101 | fblayer->releaseFenceFd = -1; | ||
102 | |||
103 | list->retireFenceFd = -1; | ||
104 | list->flags = HWC_GEOMETRY_CHANGED; | ||
105 | list->numHwLayers = 2; | ||
106 | |||
107 | EGLNativeWindowType win = NULL; | ||
108 | win = (EGLNativeWindowType)HWCNativeWindowCreate(attr_values[0], attr_values[1], HAL_PIXEL_FORMAT_RGBA_8888, present, NULL); | ||
109 | return win; | ||
110 | } | ||
111 | |||
112 | /* local variables */ | ||
113 | static Outbuf *_evas_eglfs_window = NULL; | ||
114 | static EGLContext context = EGL_NO_CONTEXT; | ||
115 | static int win_count = 0; | ||
116 | |||
117 | static Eina_Bool | ||
118 | _evas_outbuf_make_current(void *data, void *doit) | ||
119 | { | ||
120 | Outbuf *ob; | ||
121 | |||
122 | if (!(ob = data)) return EINA_FALSE; | ||
123 | |||
124 | if (doit) | ||
125 | { | ||
126 | if (!eglMakeCurrent(ob->egl.disp, ob->egl.surface[0], | ||
127 | ob->egl.surface[0], ob->egl.context[0])) | ||
128 | return EINA_FALSE; | ||
129 | } | ||
130 | else | ||
131 | { | ||
132 | if (!eglMakeCurrent(ob->egl.disp, EGL_NO_SURFACE, | ||
133 | EGL_NO_SURFACE, EGL_NO_CONTEXT)) | ||
134 | return EINA_FALSE; | ||
135 | } | ||
136 | |||
137 | return EINA_TRUE; | ||
138 | } | ||
139 | |||
140 | void _hwcomposer_present_cb(void *user_data, struct ANativeWindow *window, struct ANativeWindowBuffer *buffer) | ||
141 | { | ||
142 | } | ||
143 | |||
144 | static Eina_Bool | ||
145 | _evas_outbuf_egl_setup(Outbuf *ob) | ||
146 | { | ||
147 | int ctx_attr[3]; | ||
148 | int cfg_attr[40]; | ||
149 | int maj = 0, min = 0, n = 0, i = 0; | ||
150 | EGLint ncfg; | ||
151 | EGLConfig *cfgs; | ||
152 | const GLubyte *vendor, *renderer, *version, *glslversion; | ||
153 | Eina_Bool blacklist = EINA_FALSE; | ||
154 | |||
155 | /* setup egl surface */ | ||
156 | ctx_attr[0] = EGL_CONTEXT_CLIENT_VERSION; | ||
157 | ctx_attr[1] = 2; | ||
158 | ctx_attr[2] = EGL_NONE; | ||
159 | |||
160 | cfg_attr[n++] = EGL_BUFFER_SIZE; | ||
161 | cfg_attr[n++] = 32; | ||
162 | cfg_attr[n++] = EGL_DEPTH_SIZE; | ||
163 | cfg_attr[n++] = EGL_DONT_CARE; | ||
164 | cfg_attr[n++] = EGL_STENCIL_SIZE; | ||
165 | cfg_attr[n++] = EGL_DONT_CARE; | ||
166 | cfg_attr[n++] = EGL_RENDERABLE_TYPE; | ||
167 | cfg_attr[n++] = EGL_OPENGL_ES2_BIT; | ||
168 | cfg_attr[n++] = EGL_SURFACE_TYPE; | ||
169 | cfg_attr[n++] = EGL_WINDOW_BIT; | ||
170 | |||
171 | cfg_attr[n++] = EGL_ALPHA_SIZE; | ||
172 | if (ob->destination_alpha) cfg_attr[n++] = 1; | ||
173 | else cfg_attr[n++] = 0; | ||
174 | cfg_attr[n++] = EGL_NONE; | ||
175 | |||
176 | int err; | ||
177 | hw_module_t *hwcModule = 0; | ||
178 | hwc_composer_device_1_t *hwcDevicePtr = 0; | ||
179 | |||
180 | err = hw_get_module(HWC_HARDWARE_MODULE_ID, (const hw_module_t **) &hwcModule); | ||
181 | if (err != 0) | ||
182 | { | ||
183 | ERR("hw_get_module() fail. code=%d", err); | ||
184 | return EINA_FALSE; | ||
185 | } | ||
186 | err = hwc_open_1(hwcModule, &hwcDevicePtr); | ||
187 | if (err != 0) | ||
188 | { | ||
189 | ERR("hwc_open_1 fail. code=%d", err); | ||
190 | return EINA_FALSE; | ||
191 | } | ||
192 | hwcDevicePtr->blank(hwcDevicePtr, 0, 0); | ||
193 | |||
194 | uint32_t configs[5]; | ||
195 | size_t numConfigs = 5; | ||
196 | |||
197 | err = hwcDevicePtr->getDisplayConfigs(hwcDevicePtr, 0, configs, &numConfigs); | ||
198 | if (err != 0) | ||
199 | { | ||
200 | ERR("getDisplayConfig. code=%d", err); | ||
201 | return EINA_FALSE; | ||
202 | } | ||
203 | |||
204 | int32_t attr_values[2]; | ||
205 | uint32_t attributes[] = { HWC_DISPLAY_WIDTH, HWC_DISPLAY_HEIGHT, HWC_DISPLAY_NO_ATTRIBUTE }; | ||
206 | |||
207 | hwcDevicePtr->getDisplayAttributes(hwcDevicePtr, 0, | ||
208 | configs[0], attributes, attr_values); | ||
209 | |||
210 | DBG("width: %i height: %i\n", attr_values[0], attr_values[1]); | ||
211 | |||
212 | size_t size = sizeof(hwc_display_contents_1_t) + 2 * sizeof(hwc_layer_1_t); | ||
213 | hwc_display_contents_1_t *list = (hwc_display_contents_1_t *) malloc(size); | ||
214 | hwc_display_contents_1_t **mList = (hwc_display_contents_1_t **) malloc(HWC_NUM_DISPLAY_TYPES * sizeof(hwc_display_contents_1_t *)); | ||
215 | const hwc_rect_t r = { 0, 0, attr_values[0], attr_values[1] }; | ||
216 | |||
217 | int counter = 0; | ||
218 | for (; counter < HWC_NUM_DISPLAY_TYPES; counter++) | ||
219 | mList[counter] = NULL; | ||
220 | mList[0] = list; | ||
221 | |||
222 | hwc_layer_1_t *layer = &list->hwLayers[0]; | ||
223 | memset(layer, 0, sizeof(hwc_layer_1_t)); | ||
224 | layer->compositionType = HWC_FRAMEBUFFER; | ||
225 | layer->hints = 0; | ||
226 | layer->flags = 0; | ||
227 | layer->handle = 0; | ||
228 | layer->transform = 0; | ||
229 | layer->blending = HWC_BLENDING_NONE; | ||
230 | layer->sourceCrop = r; | ||
231 | layer->displayFrame = r; | ||
232 | layer->visibleRegionScreen.numRects = 1; | ||
233 | layer->visibleRegionScreen.rects = &layer->displayFrame; | ||
234 | layer->acquireFenceFd = -1; | ||
235 | layer->releaseFenceFd = -1; | ||
236 | layer = &list->hwLayers[1]; | ||
237 | memset(layer, 0, sizeof(hwc_layer_1_t)); | ||
238 | layer->compositionType = HWC_FRAMEBUFFER_TARGET; | ||
239 | layer->hints = 0; | ||
240 | layer->flags = 0; | ||
241 | layer->handle = 0; | ||
242 | layer->transform = 0; | ||
243 | layer->blending = HWC_BLENDING_NONE; | ||
244 | layer->sourceCrop = r; | ||
245 | layer->displayFrame = r; | ||
246 | layer->visibleRegionScreen.numRects = 1; | ||
247 | layer->visibleRegionScreen.rects = &layer->displayFrame; | ||
248 | layer->acquireFenceFd = -1; | ||
249 | layer->releaseFenceFd = -1; | ||
250 | |||
251 | list->retireFenceFd = -1; | ||
252 | list->flags = HWC_GEOMETRY_CHANGED; | ||
253 | list->numHwLayers = 2; | ||
254 | |||
255 | ob->egl.disp = eglGetDisplay(NULL); | ||
256 | if (ob->egl.disp == EGL_NO_DISPLAY) | ||
257 | { | ||
258 | ERR("eglGetDisplay() fail. code=%#x", eglGetError()); | ||
259 | return EINA_FALSE; | ||
260 | } | ||
261 | |||
262 | if (!eglInitialize(ob->egl.disp, &maj, &min)) | ||
263 | { | ||
264 | ERR("eglInitialize() fail. code=%#x", eglGetError()); | ||
265 | return EINA_FALSE; | ||
266 | } | ||
267 | |||
268 | eglBindAPI(EGL_OPENGL_ES_API); | ||
269 | if (eglGetError() != EGL_SUCCESS) | ||
270 | { | ||
271 | ERR("eglBindAPI() fail. code=%#x", eglGetError()); | ||
272 | return EINA_FALSE; | ||
273 | } | ||
274 | |||
275 | if (!eglGetConfigs(ob->egl.disp, NULL, 0, &ncfg) || (ncfg == 0)) | ||
276 | { | ||
277 | ERR("eglGetConfigs() fail. code=%#x", eglGetError()); | ||
278 | return EINA_FALSE; | ||
279 | } | ||
280 | |||
281 | cfgs = malloc(ncfg * sizeof(EGLConfig)); | ||
282 | if (!cfgs) | ||
283 | { | ||
284 | ERR("Failed to malloc space for egl configs"); | ||
285 | return EINA_FALSE; | ||
286 | } | ||
287 | |||
288 | if (!eglChooseConfig(ob->egl.disp, cfg_attr, cfgs, | ||
289 | ncfg, &ncfg) || (ncfg == 0)) | ||
290 | { | ||
291 | ERR("eglChooseConfig() fail. code=%#x", eglGetError()); | ||
292 | return EINA_FALSE; | ||
293 | } | ||
294 | |||
295 | // First is always best... | ||
296 | ob->egl.config = cfgs[0]; | ||
297 | |||
298 | EGLNativeWindowType win = create_hwcomposernativewindow(); | ||
299 | ob->egl.surface[0] = | ||
300 | eglCreateWindowSurface(ob->egl.disp, ob->egl.config, | ||
301 | (EGLNativeWindowType)win, NULL); | ||
302 | |||
303 | if (ob->egl.surface[0] == EGL_NO_SURFACE) | ||
304 | { | ||
305 | ERR("eglCreateWindowSurface() fail for %p. code=%#x", | ||
306 | NULL, eglGetError()); | ||
307 | return EINA_FALSE; | ||
308 | } | ||
309 | |||
310 | ob->egl.context[0] = | ||
311 | eglCreateContext(ob->egl.disp, ob->egl.config, EGL_NO_CONTEXT, ctx_attr); | ||
312 | if (ob->egl.context[0] == EGL_NO_CONTEXT) | ||
313 | { | ||
314 | ERR("eglCreateContext() fail. code=%#x", eglGetError()); | ||
315 | return EINA_FALSE; | ||
316 | } | ||
317 | |||
318 | if (context == EGL_NO_CONTEXT) context = ob->egl.context[0]; | ||
319 | |||
320 | if (eglMakeCurrent(ob->egl.disp, ob->egl.surface[0], | ||
321 | ob->egl.surface[0], ob->egl.context[0]) == EGL_FALSE) | ||
322 | { | ||
323 | ERR("eglMakeCurrent() fail. code=%#x", eglGetError()); | ||
324 | return EINA_FALSE; | ||
325 | } | ||
326 | |||
327 | vendor = glGetString(GL_VENDOR); | ||
328 | renderer = glGetString(GL_RENDERER); | ||
329 | version = glGetString(GL_VERSION); | ||
330 | glslversion = glGetString(GL_SHADING_LANGUAGE_VERSION); | ||
331 | if (!vendor) vendor = (unsigned char *)"-UNKNOWN-"; | ||
332 | if (!renderer) renderer = (unsigned char *)"-UNKNOWN-"; | ||
333 | if (!version) version = (unsigned char *)"-UNKNOWN-"; | ||
334 | if (!glslversion) glslversion = (unsigned char *)"-UNKNOWN-"; | ||
335 | if (getenv("EVAS_GL_INFO")) | ||
336 | { | ||
337 | fprintf(stderr, "vendor : %s\n", vendor); | ||
338 | fprintf(stderr, "renderer: %s\n", renderer); | ||
339 | fprintf(stderr, "version : %s\n", version); | ||
340 | fprintf(stderr, "glsl ver: %s\n", glslversion); | ||
341 | } | ||
342 | |||
343 | if (strstr((const char *)vendor, "Mesa Project")) | ||
344 | { | ||
345 | if (strstr((const char *)renderer, "Software Rasterizer")) | ||
346 | blacklist = EINA_TRUE; | ||
347 | } | ||
348 | if (strstr((const char *)renderer, "softpipe")) | ||
349 | blacklist = EINA_TRUE; | ||
350 | if (strstr((const char *)renderer, "llvmpipe")) | ||
351 | blacklist = EINA_TRUE; | ||
352 | |||
353 | if ((blacklist) && (!getenv("EVAS_GL_NO_BLACKLIST"))) | ||
354 | { | ||
355 | ERR("OpenGL Driver blacklisted:"); | ||
356 | ERR("Vendor: %s", (const char *)vendor); | ||
357 | ERR("Renderer: %s", (const char *)renderer); | ||
358 | ERR("Version: %s", (const char *)version); | ||
359 | return EINA_FALSE; | ||
360 | } | ||
361 | |||
362 | ob->gl_context = glsym_evas_gl_common_context_new(); | ||
363 | if (!ob->gl_context) return EINA_FALSE; | ||
364 | |||
365 | #ifdef GL_GLES | ||
366 | ob->gl_context->egldisp = ob->egl.disp; | ||
367 | ob->gl_context->eglctxt = ob->egl.context[0]; | ||
368 | #endif | ||
369 | |||
370 | evas_outbuf_use(ob); | ||
371 | glsym_evas_gl_common_context_resize(ob->gl_context, | ||
372 | ob->w, ob->h, ob->rotation); | ||
373 | |||
374 | ob->surf = EINA_TRUE; | ||
375 | |||
376 | return EINA_TRUE; | ||
377 | } | ||
378 | |||
379 | Outbuf * | ||
380 | evas_outbuf_new(Evas_Engine_Info_Eglfs *info, int w, int h, Render_Engine_Swap_Mode swap_mode) | ||
381 | { | ||
382 | Outbuf *ob; | ||
383 | char *num; | ||
384 | |||
385 | if (!info) return NULL; | ||
386 | |||
387 | /* try to allocate space for outbuf */ | ||
388 | if (!(ob = calloc(1, sizeof(Outbuf)))) return NULL; | ||
389 | |||
390 | win_count++; | ||
391 | |||
392 | ob->w = w; | ||
393 | ob->h = h; | ||
394 | ob->info = info; | ||
395 | ob->depth = info->info.depth; | ||
396 | ob->rotation = info->info.rotation; | ||
397 | ob->destination_alpha = info->info.destination_alpha; | ||
398 | ob->swap_mode = swap_mode; | ||
399 | ob->priv.num = 2; | ||
400 | |||
401 | if ((num = getenv("EVAS_EGLFS_BUFFERS"))) | ||
402 | { | ||
403 | ob->priv.num = atoi(num); | ||
404 | if (ob->priv.num <= 0) ob->priv.num = 1; | ||
405 | else if (ob->priv.num > 4) ob->priv.num = 4; | ||
406 | } | ||
407 | |||
408 | if ((num = getenv("EVAS_EGLFS_VSYNC"))) | ||
409 | ob->vsync = atoi(num); | ||
410 | |||
411 | if (!_evas_outbuf_egl_setup(ob)) | ||
412 | { | ||
413 | evas_outbuf_free(ob); | ||
414 | return NULL; | ||
415 | } | ||
416 | |||
417 | return ob; | ||
418 | } | ||
419 | |||
420 | void | ||
421 | evas_outbuf_free(Outbuf *ob) | ||
422 | { | ||
423 | int ref = 0; | ||
424 | |||
425 | win_count--; | ||
426 | evas_outbuf_use(ob); | ||
427 | |||
428 | if (ob == _evas_eglfs_window) _evas_eglfs_window = NULL; | ||
429 | |||
430 | if (ob->gl_context) | ||
431 | { | ||
432 | ref = ob->gl_context->references - 1; | ||
433 | glsym_evas_gl_common_context_free(ob->gl_context); | ||
434 | } | ||
435 | |||
436 | eglMakeCurrent(ob->egl.disp, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); | ||
437 | |||
438 | if (ob->egl.context[0] != context) | ||
439 | eglDestroyContext(ob->egl.disp, ob->egl.context[0]); | ||
440 | |||
441 | if (ob->egl.surface[0] != EGL_NO_SURFACE) | ||
442 | eglDestroySurface(ob->egl.disp, ob->egl.surface[0]); | ||
443 | |||
444 | if (ref == 0) | ||
445 | { | ||
446 | if (context) eglDestroyContext(ob->egl.disp, context); | ||
447 | eglTerminate(ob->egl.disp); | ||
448 | eglReleaseThread(); | ||
449 | context = EGL_NO_CONTEXT; | ||
450 | } | ||
451 | |||
452 | free(ob); | ||
453 | } | ||
454 | |||
455 | void | ||
456 | evas_outbuf_use(Outbuf *ob) | ||
457 | { | ||
458 | Eina_Bool force = EINA_FALSE; | ||
459 | |||
460 | glsym_evas_gl_preload_render_lock(_evas_outbuf_make_current, ob); | ||
461 | |||
462 | if (_evas_eglfs_window) | ||
463 | { | ||
464 | if (eglGetCurrentContext() != _evas_eglfs_window->egl.context[0]) | ||
465 | force = EINA_TRUE; | ||
466 | } | ||
467 | |||
468 | if ((_evas_eglfs_window != ob) || (force)) | ||
469 | { | ||
470 | if (_evas_eglfs_window) | ||
471 | { | ||
472 | glsym_evas_gl_common_context_use(_evas_eglfs_window->gl_context); | ||
473 | glsym_evas_gl_common_context_flush(_evas_eglfs_window->gl_context); | ||
474 | } | ||
475 | |||
476 | _evas_eglfs_window = ob; | ||
477 | |||
478 | if (ob) | ||
479 | { | ||
480 | if (ob->egl.surface[0] != EGL_NO_SURFACE) | ||
481 | { | ||
482 | if (eglMakeCurrent(ob->egl.disp, ob->egl.surface[0], | ||
483 | ob->egl.surface[0], | ||
484 | ob->egl.context[0]) == EGL_FALSE) | ||
485 | ERR("eglMakeCurrent() failed!"); | ||
486 | } | ||
487 | } | ||
488 | } | ||
489 | |||
490 | if (ob) glsym_evas_gl_common_context_use(ob->gl_context); | ||
491 | } | ||
492 | |||
493 | void | ||
494 | evas_outbuf_resurf(Outbuf *ob) | ||
495 | { | ||
496 | if (ob->surf) return; | ||
497 | if (getenv("EVAS_GL_INFO")) printf("resurf %p\n", ob); | ||
498 | |||
499 | ob->egl.surface[0] = | ||
500 | eglCreateWindowSurface(ob->egl.disp, ob->egl.config, | ||
501 | NULL, NULL); | ||
502 | |||
503 | if (ob->egl.surface[0] == EGL_NO_SURFACE) | ||
504 | { | ||
505 | ERR("eglCreateWindowSurface() fail for %p. code=%#x", | ||
506 | NULL, eglGetError()); | ||
507 | return; | ||
508 | } | ||
509 | |||
510 | if (eglMakeCurrent(ob->egl.disp, ob->egl.surface[0], ob->egl.surface[0], | ||
511 | ob->egl.context[0]) == EGL_FALSE) | ||
512 | ERR("eglMakeCurrent() failed!"); | ||
513 | |||
514 | ob->surf = EINA_TRUE; | ||
515 | } | ||
516 | |||
517 | void | ||
518 | evas_outbuf_unsurf(Outbuf *ob) | ||
519 | { | ||
520 | if (!ob->surf) return; | ||
521 | if (!getenv("EVAS_GL_WIN_RESURF")) return; | ||
522 | if (getenv("EVAS_GL_INFO")) printf("unsurf %p\n", ob); | ||
523 | |||
524 | if (_evas_eglfs_window) | ||
525 | glsym_evas_gl_common_context_flush(_evas_eglfs_window->gl_context); | ||
526 | if (_evas_eglfs_window == ob) | ||
527 | { | ||
528 | eglMakeCurrent(ob->egl.disp, EGL_NO_SURFACE, | ||
529 | EGL_NO_SURFACE, EGL_NO_CONTEXT); | ||
530 | if (ob->egl.surface[0] != EGL_NO_SURFACE) | ||
531 | eglDestroySurface(ob->egl.disp, ob->egl.surface[0]); | ||
532 | ob->egl.surface[0] = EGL_NO_SURFACE; | ||
533 | |||
534 | _evas_eglfs_window = NULL; | ||
535 | } | ||
536 | |||
537 | ob->surf = EINA_FALSE; | ||
538 | } | ||
539 | |||
540 | void | ||
541 | evas_outbuf_reconfigure(Outbuf *ob, int w, int h, int rot, Outbuf_Depth depth) | ||
542 | { | ||
543 | if (depth == OUTBUF_DEPTH_INHERIT) depth = ob->depth; | ||
544 | |||
545 | ob->w = w; | ||
546 | ob->h = h; | ||
547 | ob->depth = depth; | ||
548 | ob->rotation = rot; | ||
549 | |||
550 | evas_outbuf_use(ob); | ||
551 | glsym_evas_gl_common_context_resize(ob->gl_context, w, h, rot); | ||
552 | } | ||
553 | |||
554 | Render_Engine_Swap_Mode | ||
555 | evas_outbuf_buffer_state_get(Outbuf *ob) | ||
556 | { | ||
557 | return MODE_FULL; | ||
558 | // Forces re-rendering all the screen, that is bad for performance. However | ||
559 | // partial rendering makes black area. We should try to find a better solution. | ||
560 | } | ||
561 | |||
562 | int | ||
563 | evas_outbuf_rot_get(Outbuf *ob) | ||
564 | { | ||
565 | return ob->rotation; | ||
566 | } | ||
567 | |||
568 | Eina_Bool | ||
569 | evas_outbuf_update_region_first_rect(Outbuf *ob) | ||
570 | { | ||
571 | glsym_evas_gl_preload_render_lock(_evas_outbuf_make_current, ob); | ||
572 | evas_outbuf_use(ob); | ||
573 | |||
574 | if (!_re_wincheck(ob)) return EINA_TRUE; | ||
575 | |||
576 | glsym_evas_gl_common_context_flush(ob->gl_context); | ||
577 | glsym_evas_gl_common_context_newframe(ob->gl_context); | ||
578 | |||
579 | return EINA_FALSE; | ||
580 | } | ||
581 | |||
582 | void * | ||
583 | 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) | ||
584 | { | ||
585 | if ((w == ob->w) && (h == ob->h)) | ||
586 | ob->gl_context->master_clip.enabled = EINA_FALSE; | ||
587 | else | ||
588 | { | ||
589 | ob->gl_context->master_clip.enabled = EINA_TRUE; | ||
590 | ob->gl_context->master_clip.x = x; | ||
591 | ob->gl_context->master_clip.y = y; | ||
592 | ob->gl_context->master_clip.w = w; | ||
593 | ob->gl_context->master_clip.h = h; | ||
594 | } | ||
595 | |||
596 | return ob->gl_context->def_surface; | ||
597 | } | ||
598 | |||
599 | void | ||
600 | 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) | ||
601 | { | ||
602 | /* Is it really necessary to flush per region ? Shouldn't we be able to | ||
603 | still do that for the full canvas when doing partial update */ | ||
604 | if (!_re_wincheck(ob)) return; | ||
605 | ob->drew = EINA_TRUE; | ||
606 | glsym_evas_gl_common_context_flush(ob->gl_context); | ||
607 | } | ||
608 | |||
609 | void | ||
610 | evas_outbuf_update_region_free(Outbuf *ob EINA_UNUSED, RGBA_Image *update EINA_UNUSED) | ||
611 | { | ||
612 | /* Nothing to do here as we don't really create an image per area */ | ||
613 | } | ||
614 | |||
615 | void | ||
616 | evas_outbuf_flush(Outbuf *ob, Tilebuf_Rect *rects EINA_UNUSED, Evas_Render_Mode render_mode) | ||
617 | { | ||
618 | if (render_mode == EVAS_RENDER_MODE_ASYNC_INIT) goto end; | ||
619 | |||
620 | if (!_re_wincheck(ob)) goto end; | ||
621 | if (!ob->drew) goto end; | ||
622 | |||
623 | ob->drew = EINA_FALSE; | ||
624 | evas_outbuf_use(ob); | ||
625 | glsym_evas_gl_common_context_done(ob->gl_context); | ||
626 | |||
627 | if (!ob->vsync) | ||
628 | { | ||
629 | if (ob->info->info.vsync) eglSwapInterval(ob->egl.disp, 1); | ||
630 | else eglSwapInterval(ob->egl.disp, 0); | ||
631 | ob->vsync = 1; | ||
632 | } | ||
633 | |||
634 | if (ob->info->callback.pre_swap) | ||
635 | ob->info->callback.pre_swap(ob->info->callback.data, ob->evas); | ||
636 | |||
637 | eglSwapBuffers(ob->egl.disp, ob->egl.surface[0]); | ||
638 | |||
639 | if (ob->info->callback.post_swap) | ||
640 | ob->info->callback.post_swap(ob->info->callback.data, ob->evas); | ||
641 | |||
642 | ob->priv.frame_cnt++; | ||
643 | |||
644 | end: | ||
645 | glsym_evas_gl_preload_render_unlock(_evas_outbuf_make_current, ob); | ||
646 | } | ||
647 | |||
648 | Evas_Engine_GL_Context * | ||
649 | evas_outbuf_gl_context_get(Outbuf *ob) | ||
650 | { | ||
651 | return ob->gl_context; | ||
652 | } | ||
653 | |||
654 | void * | ||
655 | evas_outbuf_egl_display_get(Outbuf *ob) | ||
656 | { | ||
657 | return ob->egl.disp; | ||
658 | } | ||
659 | |||
660 | Context_3D * | ||
661 | evas_outbuf_gl_context_new(Outbuf *ob) | ||
662 | { | ||
663 | Context_3D *ctx; | ||
664 | int context_attrs[3] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; | ||
665 | |||
666 | if (!ob) return NULL; | ||
667 | |||
668 | ctx = calloc(1, sizeof(Context_3D)); | ||
669 | if (!ctx) return NULL; | ||
670 | |||
671 | ctx->context = eglCreateContext(ob->egl.disp, ob->egl.config, | ||
672 | ob->egl.context[0], context_attrs); | ||
673 | |||
674 | if (!ctx->context) | ||
675 | { | ||
676 | ERR("EGL context creation failed."); | ||
677 | goto error; | ||
678 | } | ||
679 | |||
680 | ctx->display = ob->egl.disp; | ||
681 | ctx->surface = ob->egl.surface[0]; | ||
682 | |||
683 | return ctx; | ||
684 | |||
685 | error: | ||
686 | free(ctx); | ||
687 | return NULL; | ||
688 | } | ||
689 | |||
690 | void | ||
691 | evas_outbuf_gl_context_free(Context_3D *ctx) | ||
692 | { | ||
693 | eglDestroyContext(ctx->display, ctx->context); | ||
694 | free(ctx); | ||
695 | } | ||
696 | |||
697 | void | ||
698 | evas_outbuf_gl_context_use(Context_3D *ctx) | ||
699 | { | ||
700 | if (eglMakeCurrent(ctx->display, ctx->surface, | ||
701 | ctx->surface, ctx->context) == EGL_FALSE) | ||
702 | ERR("eglMakeCurrent() failed."); | ||
703 | } | ||