From ed442afa11b5f4e016618b5fc0c7e920cbe1d66f Mon Sep 17 00:00:00 2001 From: Chris Michael Date: Wed, 3 Jun 2015 12:56:35 -0400 Subject: evas-gl-drm: Rework gl_drm engine to function again Summary: Previous gl_drm evas engine code did not work properly (or at all really). This reworks/refactors the gl_drm engine code to work again with the changes made to ecore_drm. @fix Signed-off-by: Chris Michael --- src/Makefile_Evas.am | 3 +- .../evas/engines/gl_drm/Evas_Engine_GL_Drm.h | 36 ++ src/modules/evas/engines/gl_drm/evas_engine.c | 668 +++++++++++---------- src/modules/evas/engines/gl_drm/evas_engine.h | 128 ++++ src/modules/evas/engines/gl_drm/evas_outbuf.c | 656 ++++++++++++++++++++ 5 files changed, 1171 insertions(+), 320 deletions(-) create mode 100644 src/modules/evas/engines/gl_drm/Evas_Engine_GL_Drm.h create mode 100644 src/modules/evas/engines/gl_drm/evas_engine.h create mode 100644 src/modules/evas/engines/gl_drm/evas_outbuf.c diff --git a/src/Makefile_Evas.am b/src/Makefile_Evas.am index e5b771d8da..de4626ba62 100644 --- a/src/Makefile_Evas.am +++ b/src/Makefile_Evas.am @@ -1199,8 +1199,7 @@ endif if BUILD_ENGINE_GL_DRM dist_installed_evasmainheaders_DATA += modules/evas/engines/gl_drm/Evas_Engine_GL_Drm.h GL_DRM_SOURCES = \ -modules/evas/engines/gl_drm/evas_drm.c \ -modules/evas/engines/gl_drm/evas_drm_main.c \ +modules/evas/engines/gl_drm/evas_outbuf.c \ modules/evas/engines/gl_drm/evas_engine.c \ modules/evas/engines/gl_drm/evas_engine.h \ modules/evas/engines/gl_drm/Evas_Engine_GL_Drm.h diff --git a/src/modules/evas/engines/gl_drm/Evas_Engine_GL_Drm.h b/src/modules/evas/engines/gl_drm/Evas_Engine_GL_Drm.h new file mode 100644 index 0000000000..6cb7923d70 --- /dev/null +++ b/src/modules/evas/engines/gl_drm/Evas_Engine_GL_Drm.h @@ -0,0 +1,36 @@ +#ifndef _EVAS_ENGINE_GL_DRM_H +# define _EVAS_ENGINE_GL_DRM_H + +# include +# include + +typedef struct _Evas_Engine_Info_GL_Drm Evas_Engine_Info_GL_Drm; + +struct _Evas_Engine_Info_GL_Drm +{ + /* 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 + { + struct gbm_device *gbm; + struct gbm_surface *surface; + + unsigned int rotation, depth; + unsigned int crtc_id, conn_id, buffer_id; + unsigned int format, flags; + + Ecore_Drm_Device *dev; + + Eina_Bool destination_alpha : 1; + Eina_Bool vsync : 1; + Eina_Bool indirect : 1; + unsigned char swap_mode : 4; + } info; + + /* non-blocking or blocking mode */ + Evas_Engine_Render_Mode render_mode; +}; + +#endif diff --git a/src/modules/evas/engines/gl_drm/evas_engine.c b/src/modules/evas/engines/gl_drm/evas_engine.c index 0049819de2..280035da98 100644 --- a/src/modules/evas/engines/gl_drm/evas_engine.c +++ b/src/modules/evas/engines/gl_drm/evas_engine.c @@ -1,5 +1,6 @@ -#include "evas_common_private.h" /* Also includes international specific stuff */ +#include "config.h" #include "evas_engine.h" +#include #ifdef HAVE_DLSYM # include /* dlopen,dlclose,etc */ @@ -7,10 +8,6 @@ # error gl_drm 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" @@ -20,10 +17,28 @@ # define EGL_NATIVE_PIXMAP_KHR 0x30b0 #endif -#include /* external variables */ int _evas_engine_gl_drm_log_dom = -1; -int extn_have_buffer_age = 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; +}; /* external dynamic loaded Evas_GL function pointers */ Evas_GL_Common_Image_Call glsym_evas_gl_common_image_ref = NULL; @@ -50,29 +65,14 @@ 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; -/* 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) (); +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)(); /* dynamic loaded local egl function pointers */ _eng_fn (*glsym_eglGetProcAddress)(const char *a) = NULL; @@ -99,19 +99,6 @@ 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); -static void _re_winfree(Render_Engine *re); - -/* local variables */ -static Eina_Bool initted = EINA_FALSE; -static int gl_wins = 0; - -/* local inline functions */ -static inline Outbuf * -eng_get_ob(Render_Engine *re) -{ - return re->generic.software.ob; -} - /* function tables - filled in later (func and parent func) */ static Evas_Func func, pfunc; static const EVGL_Interface evgl_funcs = @@ -136,6 +123,13 @@ static const EVGL_Interface evgl_funcs = 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) @@ -215,36 +209,38 @@ static void gl_extn_veto(Render_Engine *re) { const char *str = NULL; - str = eglQueryString(eng_get_ob(re)->egl_disp, EGL_EXTENSIONS); + + str = eglQueryString(eng_get_ob(re)->egl.disp, EGL_EXTENSIONS); if (str) { - const char *s; - if (getenv("EVAS_GL_INFO")) - printf("EGL EXTN:\n%s\n", str); + const char *s = NULL; + + if (getenv("EVAS_GL_INFO")) printf("EGL EXTN:\n%s\n", str); + // Disable Partial Rendering - if ((s = getenv("EVAS_GL_PARTIAL_DISABLE")) && atoi(s)) + s = getenv("EVAS_GL_PARTIAL_DISABLE"); + if ((s) && (atoi(s))) { - extn_have_buffer_age = 0; + _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_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; + 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 = (Render_Engine *)data; + Render_Engine *re; + re = (Render_Engine *)data; if (!re) { ERR("Invalid Render Engine Data!"); @@ -252,7 +248,7 @@ evgl_eng_display_get(void *data) } if (eng_get_ob(re)) - return (void*)eng_get_ob(re)->egl_disp; + return (void*)eng_get_ob(re)->egl.disp; else return NULL; } @@ -260,8 +256,9 @@ evgl_eng_display_get(void *data) static void * evgl_eng_evas_surface_get(void *data) { - Render_Engine *re = (Render_Engine *)data; + Render_Engine *re; + re = (Render_Engine *)data; if (!re) { ERR("Invalid Render Engine Data!"); @@ -269,7 +266,7 @@ evgl_eng_evas_surface_get(void *data) } if (eng_get_ob(re)) - return (void*)eng_get_ob(re)->egl_surface[0]; + return (void*)eng_get_ob(re)->egl.surface[0]; else return NULL; } @@ -277,19 +274,20 @@ evgl_eng_evas_surface_get(void *data) static int evgl_eng_make_current(void *data, void *surface, void *context, int flush) { - Render_Engine *re = (Render_Engine *)data; + 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; + dpy = eng_get_ob(re)->egl.disp; ctx = (EGLContext)context; sfc = (EGLSurface)surface; @@ -302,6 +300,7 @@ evgl_eng_make_current(void *data, void *surface, void *context, int flush) ERR("eglMakeCurrent() failed! Error Code=%#x", eglGetError()); return 0; } + return 1; } @@ -309,7 +308,7 @@ evgl_eng_make_current(void *data, void *surface, void *context, int flush) (eglGetCurrentSurface(EGL_READ) != sfc) || (eglGetCurrentSurface(EGL_DRAW) != sfc) ) { - if (flush) eng_window_use(NULL); + if (flush) evas_outbuf_use(NULL); ret = eglMakeCurrent(dpy, sfc, sfc, ctx); if (!ret) @@ -325,10 +324,11 @@ evgl_eng_make_current(void *data, void *surface, void *context, int flush) static void * evgl_eng_native_window_create(void *data) { - Render_Engine *re = (Render_Engine *)data; + Render_Engine *re; struct gbm_surface *surface; Evas_Engine_Info_GL_Drm *info; + re = (Render_Engine *)data; if (!re) { ERR("Invalid Render Engine Data!"); @@ -345,9 +345,12 @@ evgl_eng_native_window_create(void *data) surface = gbm_surface_create(info->info.gbm, 1, 1, info->info.format, info->info.flags); if (!surface) - ERR("Could not create gl drm window: %m"); + { + ERR("Could not create gl drm window: %m"); + return NULL; + } - return (void*)surface; + return (void *)surface; } static int @@ -367,16 +370,17 @@ evgl_eng_native_window_destroy(void *data, void *native_window) return 0; } - gbm_surface_destroy((struct gbm_surface*)native_window); + gbm_surface_destroy((struct gbm_surface *)native_window); return 1; } static void * evgl_eng_window_surface_create(void *data, void *native_window) { - Render_Engine *re = (Render_Engine *)data; + Render_Engine *re; EGLSurface surface = EGL_NO_SURFACE; + re = (Render_Engine *)data; if (!re) { ERR("Invalid Render Engine Data!"); @@ -384,8 +388,8 @@ evgl_eng_window_surface_create(void *data, void *native_window) } // Create resource surface for EGL - surface = eglCreateWindowSurface(eng_get_ob(re)->egl_disp, - eng_get_ob(re)->egl_config, + surface = eglCreateWindowSurface(eng_get_ob(re)->egl.disp, + eng_get_ob(re)->egl.config, (EGLNativeWindowType)native_window, NULL); if (!surface) @@ -394,15 +398,16 @@ evgl_eng_window_surface_create(void *data, void *native_window) return NULL; } - return (void*)surface; + return (void *)surface; } static int evgl_eng_window_surface_destroy(void *data, void *surface) { - Render_Engine *re = (Render_Engine *)data; + Render_Engine *re; EGLBoolean ret = EGL_FALSE; + re = (Render_Engine *)data; if (!re) { ERR("Invalid Render Engine Data!"); @@ -415,7 +420,7 @@ evgl_eng_window_surface_destroy(void *data, void *surface) return 0; } - ret = eglDestroySurface(eng_get_ob(re)->egl_disp, (EGLSurface)surface); + ret = eglDestroySurface(eng_get_ob(re)->egl.disp, (EGLSurface)surface); if (ret == EGL_TRUE) return 1; return 0; @@ -424,10 +429,11 @@ 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) { - Render_Engine *re = (Render_Engine *)data; + Render_Engine *re; EGLContext context = EGL_NO_CONTEXT; int context_attrs[3]; + re = (Render_Engine *)data; if (!re) { ERR("Invalid Render Engine Data!"); @@ -447,16 +453,16 @@ evgl_eng_context_create(void *data, void *share_ctx, Evas_GL_Context_Version ver // 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, + 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 = 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); } @@ -466,22 +472,24 @@ evgl_eng_context_create(void *data, void *share_ctx, Evas_GL_Context_Version ver return NULL; } - return (void*)context; + return (void *)context; } static int evgl_eng_context_destroy(void *data, void *context) { - Render_Engine *re = (Render_Engine *)data; + 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); + ERR("Invalid Render Input Data. Engine: %p, Context: %p", + data, context); return 0; } - ret = eglDestroyContext(eng_get_ob(re)->egl_disp, (EGLContext)context); + ret = eglDestroyContext(eng_get_ob(re)->egl.disp, (EGLContext)context); if (ret == EGL_TRUE) return 1; return 0; @@ -490,15 +498,16 @@ evgl_eng_context_destroy(void *data, void *context) static const char * evgl_eng_string_get(void *data) { - Render_Engine *re = (Render_Engine *)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); + return eglQueryString(eng_get_ob(re)->egl.disp, EGL_EXTENSIONS); } static void * @@ -511,8 +520,9 @@ evgl_eng_proc_address_get(const char *name) static int evgl_eng_rotation_angle_get(void *data) { - Render_Engine *re = (Render_Engine *)data; + Render_Engine *re; + re = (Render_Engine *)data; if (!re) { ERR("Invalid Render Engine Data!"); @@ -528,13 +538,174 @@ evgl_eng_rotation_angle_get(void *data) } } +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)); - eng_window_unsurf(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); +} + +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; + + if (n->ns.type == EVAS_NATIVE_SURFACE_WL) + { + //glBindTexture(GL_TEXTURE_2D, 0); //really need? + } + else if (n->ns.type == EVAS_NATIVE_SURFACE_OPENGL) + glBindTexture(GL_TEXTURE_2D, 0); +} + +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); +} + +static Eina_Bool +eng_gbm_init(Evas_Engine_Info_GL_Drm *info, int w, int h) +{ + Ecore_Drm_Device *dev; + + if (!info) return EINA_FALSE; + if (!(dev = info->info.dev)) return EINA_FALSE; + + DBG("Create GBM Device"); + if (!(info->info.gbm = gbm_create_device(dev->drm.fd))) + { + ERR("Coult not create gbm device: %m"); + return EINA_FALSE; + } + + if (!(info->info.surface = + gbm_surface_create(info->info.gbm, w, h, + info->info.format, info->info.flags))) + { + ERR("Could not create gbm surface: %m"); + gbm_device_destroy(info->info.gbm); + info->info.gbm = NULL; + return EINA_FALSE; + } + + return EINA_TRUE; +} + +static Eina_Bool +eng_gbm_shutdown(Evas_Engine_Info_GL_Drm *info) +{ + if (!info) return EINA_TRUE; + + if (info->info.surface) + { + gbm_surface_destroy(info->info.surface); + info->info.surface = NULL; + } + if (info->info.gbm) + { + gbm_device_destroy(info->info.gbm); + info->info.gbm = NULL; + } + + return EINA_TRUE; } /* engine specific override functions */ @@ -563,21 +734,22 @@ eng_info_free(Evas *eo_e EINA_UNUSED, void *in) } static int -eng_setup(Evas *eo_e, void *in) +eng_setup(Evas *evas, void *in) { - Evas_Engine_Info_GL_Drm *info = NULL; - Evas_Public_Data *epd = NULL; - Render_Engine *re = NULL; + Evas_Engine_Info_GL_Drm *info; + Evas_Public_Data *epd; + Render_Engine *re; Render_Engine_Swap_Mode swap_mode = MODE_FULL; - const char *s; + const char *s = NULL; /* try to cast to our engine info structure */ if (!(info = (Evas_Engine_Info_GL_Drm *)in)) return 0; /* try to get the evas public data */ - if (!(epd = eo_data_scope_get(eo_e, EVAS_CANVAS_CLASS))) return 0; + if (!(epd = eo_data_scope_get(evas, EVAS_CANVAS_CLASS))) return 0; - if ((s = getenv("EVAS_GL_SWAP_MODE"))) + s = getenv("EVAS_GL_SWAP_MODE"); + if (s) { if ((!strcasecmp(s, "full")) || (!strcasecmp(s, "f"))) swap_mode = MODE_FULL; @@ -594,8 +766,7 @@ eng_setup(Evas *eo_e, void *in) swap_mode = MODE_QUADRUPLE; } - /* check for existing engine output */ - if (!epd->engine.data.output) + if (!(re = epd->engine.data.output)) { Outbuf *ob; Render_Engine_Merge_Mode merge_mode = MERGE_FULL; @@ -606,64 +777,53 @@ eng_setup(Evas *eo_e, void *in) glsym_evas_gl_preload_init(); } - if (!(info->info.gbm) || !(info->info.surface)) - return 0; - -#ifdef GL_DRM_DBG - DBG("FD: %d, GBM_DEVICE: 0x%x, GBM_SURFACE: 0x%x", - info->info.fd, (unsigned int)info->info.gbm, - (unsigned int)info->info.surface); -#endif + if (!(re = calloc(1, sizeof(Render_Engine)))) return 0; - re = calloc(1, sizeof(Render_Engine)); - if (!re) return 0; + if (!eng_gbm_init(info, epd->output.w, epd->output.h)) + { + free(re); + return 0; + } /* try to create new outbuf */ - ob = eng_window_new(info, eo_e, info->info.gbm, info->info.surface, - info->info.screen,info->info.depth, - epd->output.w, epd->output.h, info->indirect, - info->info.destination_alpha, - info->info.rotation, swap_mode); + ob = evas_outbuf_new(info, epd->output.w, epd->output.h, swap_mode); if (!ob) { - /* shutdown destroy gbm surface & shutdown gbm device */ - evas_drm_gbm_shutdown(info); + eng_gbm_shutdown(info); free(re); return 0; } if (!evas_render_engine_gl_generic_init(&re->generic, ob, - eng_outbuf_swap_mode, - eng_outbuf_get_rot, - eng_outbuf_reconfigure, - eng_outbuf_region_first_rect, - eng_outbuf_new_region_for_update, - eng_outbuf_push_updated_region, - eng_outbuf_push_free_region_for_update, + 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, - eng_outbuf_flush, - eng_window_free, - eng_window_use, - eng_outbuf_gl_context_get, - eng_outbuf_egl_display_get, - eng_gl_context_new, - eng_gl_context_use, - &evgl_funcs, - epd->output.w, epd->output.h)) + 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)) { + eng_gbm_shutdown(info); /* free outbuf */ - eng_window_free(ob); - /* shutdown destroy gbm surface & shutdown gbm device */ - evas_drm_gbm_shutdown(info); + evas_outbuf_free(ob); free(re); return 0; } - /* tell the engine to use this render_engine for output */ epd->engine.data.output = re; gl_wins++; - if ((s = getenv("EVAS_GL_PARTIAL_MERGE"))) + s = getenv("EVAS_GL_PARTIAL_MERGE"); + if (s) { if ((!strcmp(s, "bounding")) || (!strcmp(s, "b"))) merge_mode = MERGE_BOUNDING; @@ -681,36 +841,24 @@ eng_setup(Evas *eo_e, void *in) } else { - re = epd->engine.data.output; - if (eng_get_ob(re) && _re_wincheck(eng_get_ob(re))) { - if ((eng_get_ob(re)->info->info.gbm != eng_get_ob(re)->gbm) || - (eng_get_ob(re)->info->info.surface != eng_get_ob(re)->surface) || - (eng_get_ob(re)->info->info.screen != eng_get_ob(re)->screen) || - (eng_get_ob(re)->info->info.depth != eng_get_ob(re)->depth) || - (eng_get_ob(re)->info->info.destination_alpha != eng_get_ob(re)->alpha)) + if ((info->info.gbm != eng_get_ob(re)->gbm) || + (info->info.surface != eng_get_ob(re)->surface) || + (info->info.depth != eng_get_ob(re)->depth) || + (info->info.destination_alpha != eng_get_ob(re)->destination_alpha)) { Outbuf *ob; eng_get_ob(re)->gl_context->references++; gl_wins--; - ob = eng_window_new(info, eo_e, - eng_get_ob(re)->info->info.gbm, - eng_get_ob(re)->info->info.surface, - eng_get_ob(re)->info->info.screen, - eng_get_ob(re)->info->info.depth, - epd->output.w, epd->output.h, - eng_get_ob(re)->info->indirect, - eng_get_ob(re)->info->info.destination_alpha, - eng_get_ob(re)->info->info.rotation, - swap_mode); - - eng_window_free(eng_get_ob(re)); + ob = evas_outbuf_new(info, epd->output.w, epd->output.h, swap_mode); + + evas_outbuf_free(eng_get_ob(re)); re->generic.software.ob = NULL; - eng_window_use(ob); + evas_outbuf_use(ob); if (ob) { evas_render_engine_software_generic_update(&re->generic.software, ob, @@ -722,34 +870,23 @@ eng_setup(Evas *eo_e, void *in) } else if ((eng_get_ob(re)->w != epd->output.w) || (eng_get_ob(re)->h != epd->output.h) || - (eng_get_ob(re)->info->info.rotation != eng_get_ob(re)->rot)) + (info->info.rotation != eng_get_ob(re)->rotation)) { Outbuf *ob; eng_get_ob(re)->gl_context->references++; gl_wins--; - eng_window_free(eng_get_ob(re)); + evas_outbuf_free(eng_get_ob(re)); re->generic.software.ob = NULL; - evas_drm_gbm_shutdown(eng_get_ob(re)->info); - if (!evas_drm_gbm_init(info, epd->output.w, epd->output.h)) - return 0; -#ifdef GL_DRM_DBG - DBG("FD: %d, GBM_DEVICE: 0x%x, GBM_SURFACE: 0x%x", - info->info.fd, (unsigned int)info->info.gbm, - (unsigned int)info->info.surface); -#endif + eng_gbm_shutdown(eng_get_ob(re)->info); + if (!eng_gbm_init(info, epd->output.w, epd->output.h)) + return 0; - ob = eng_window_new(info, eo_e, info->info.gbm, - info->info.surface, info->info.screen, - info->info.depth, - epd->output.w, epd->output.h, - info->indirect, - info->info.destination_alpha, - info->info.rotation, swap_mode); + ob = evas_outbuf_new(info, epd->output.w, epd->output.h, swap_mode); - eng_window_use(ob); + evas_outbuf_use(ob); if (ob) { evas_render_engine_software_generic_update(&re->generic.software, ob, @@ -772,9 +909,9 @@ eng_setup(Evas *eo_e, void *in) { if (eng_get_ob(re)) { - eng_window_free(eng_get_ob(re)); + evas_outbuf_free(eng_get_ob(re)); gl_wins--; - evas_drm_gbm_shutdown(info); + eng_gbm_shutdown(info); } free(re); return 0; @@ -788,7 +925,7 @@ eng_setup(Evas *eo_e, void *in) epd->engine.func->context_new(epd->engine.data.output); } - eng_window_use(eng_get_ob(re)); + evas_outbuf_use(eng_get_ob(re)); return 1; } @@ -799,22 +936,22 @@ 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); - evas_drm_gbm_shutdown(eng_get_ob(re)->info); + eng_gbm_shutdown(eng_get_ob(re)->info); - //evas_render_engine_software_generic_clean() frees ob. + /* 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(); @@ -823,35 +960,15 @@ eng_output_free(void *data) } } -Eina_Bool -eng_preload_make_current(void *data, void *doit) -{ - Outbuf *ob = 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 Eina_Bool eng_canvas_alpha_get(void *data, void *info EINA_UNUSED) { Render_Engine *re; - if (!(re = (Render_Engine *)data)) return EINA_FALSE; + re = (Render_Engine *)data; + if (!re) return EINA_FALSE; - return re->generic.software.ob->alpha; + return eng_get_ob(re)->destination_alpha; } static void @@ -859,7 +976,8 @@ eng_output_dump(void *data) { Render_Engine *re; - if (!(re = (Render_Engine *)data)) return; + re = (Render_Engine *)data; + if (!re) return; evas_common_image_image_all_unload(); evas_common_font_font_all_unload(); @@ -867,101 +985,6 @@ eng_output_dump(void *data) _re_winfree(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); - } -} - -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; - - if (n->ns.type == EVAS_NATIVE_SURFACE_WL) - { - //glBindTexture(GL_TEXTURE_2D, 0); //really need? - } - else if (n->ns.type == EVAS_NATIVE_SURFACE_OPENGL) - { - glBindTexture(GL_TEXTURE_2D, 0); - } -} - -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(eng_get_ob(re)->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); -} - static void * eng_image_native_set(void *data, void *image, void *native) { @@ -972,11 +995,13 @@ eng_image_native_set(void *data, void *image, void *native) Evas_GL_Image *img, *img2; unsigned int tex = 0, fbo = 0; uint32_t texid; - void *wlid; - void *wl_buf = NULL; + void *wlid, *wl_buf = NULL; + + re = (Render_Engine *)data; + if (!re) return NULL; - if (!(re = (Render_Engine *)data)) return NULL; - if (!(ob = eng_get_ob(re))) return NULL; + ob = eng_get_ob(re); + if (!ob) return NULL; ns = native; @@ -1027,7 +1052,7 @@ eng_image_native_set(void *data, void *image, void *native) if ((!ns) && (!img->native.data)) return img; - eng_window_use(ob); + evas_outbuf_use(ob); if (img->native.data) { @@ -1085,8 +1110,10 @@ eng_image_native_set(void *data, void *image, void *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)) + 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); @@ -1099,20 +1126,23 @@ eng_image_native_set(void *data, void *image, void *native) 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); + 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, + n->egl_surface = glsym_eglCreateImage(ob->egl.disp, NULL, EGL_WAYLAND_BUFFER_WL, - wl_buf, - attribs); + wl_buf, attribs); else { ERR("Try eglCreateImage on EGL with no support"); - eina_hash_del(ob->gl_context->shared->native_wl_hash, &wlid, img); + eina_hash_del(ob->gl_context->shared->native_wl_hash, + &wlid, img); glsym_evas_gl_common_image_free(img); free(n); return NULL; @@ -1121,7 +1151,8 @@ eng_image_native_set(void *data, void *image, void *native) if (!n->egl_surface) { ERR("eglCreatePixmapSurface() for %p failed", wl_buf); - eina_hash_del(ob->gl_context->shared->native_wl_hash, &wlid, img); + eina_hash_del(ob->gl_context->shared->native_wl_hash, + &wlid, img); glsym_evas_gl_common_image_free(img); free(n); return NULL; @@ -1151,7 +1182,8 @@ eng_image_native_set(void *data, void *image, void *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); + eina_hash_add(ob->gl_context->shared->native_tex_hash, + &texid, img); n->egl_surface = 0; @@ -1173,7 +1205,6 @@ eng_image_native_set(void *data, void *image, void *native) return img; } - /* module api functions */ static int module_open(Evas_Module *em) @@ -1202,14 +1233,13 @@ module_open(Evas_Module *em) func = pfunc; /* now to override methods */ -#define ORD(f) EVAS_API_OVERRIDE(f, &func, eng_) - ORD(info); - ORD(info_free); - ORD(setup); - ORD(canvas_alpha_get); - ORD(output_free); - ORD(output_dump); - ORD(image_native_set); + 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_); /* Mesa's EGL driver loads wayland egl by default. (called by eglGetProcaddr() ) * implicit env set (EGL_PLATFORM=drm) prevent that. */ @@ -1218,6 +1248,7 @@ module_open(Evas_Module *em) /* now advertise out own api */ em->functions = (void *)(&func); + return 1; } @@ -1226,6 +1257,7 @@ module_close(Evas_Module *em EINA_UNUSED) { /* unregister the eina log domain for this engine */ eina_log_domain_unregister(_evas_engine_gl_drm_log_dom); + _evas_engine_gl_drm_log_dom = -1; } static Evas_Module_Api evas_modapi = diff --git a/src/modules/evas/engines/gl_drm/evas_engine.h b/src/modules/evas/engines/gl_drm/evas_engine.h new file mode 100644 index 0000000000..b00cf382cc --- /dev/null +++ b/src/modules/evas/engines/gl_drm/evas_engine.h @@ -0,0 +1,128 @@ +#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_GL_Drm.h" + +# define GL_GLEXT_PROTOTYPES +# include +# include +# include +# include +# include +# include "../gl_generic/Evas_Engine_GL_Generic.h" + +extern int _evas_engine_gl_drm_log_dom; +extern int _extn_have_buffer_age; + +# ifdef ERR +# undef ERR +# endif +# define ERR(...) EINA_LOG_DOM_ERR(_evas_engine_gl_drm_log_dom, __VA_ARGS__) + +# ifdef DBG +# undef DBG +# endif +# define DBG(...) EINA_LOG_DOM_DBG(_evas_engine_gl_drm_log_dom, __VA_ARGS__) + +# ifdef INF +# undef INF +# endif +# define INF(...) EINA_LOG_DOM_INFO(_evas_engine_gl_drm_log_dom, __VA_ARGS__) + +# ifdef WRN +# undef WRN +# endif +# define WRN(...) EINA_LOG_DOM_WARN(_evas_engine_gl_drm_log_dom, __VA_ARGS__) + +# ifdef CRI +# undef CRI +# endif +# define CRI(...) EINA_LOG_DOM_CRIT(_evas_engine_gl_drm_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_GL_Drm *info; + Evas_Engine_GL_Context *gl_context; + + int w, h; + unsigned int rotation, depth; + Render_Engine_Swap_Mode swap_mode; + + struct gbm_device *gbm; + struct gbm_surface *surface; + + struct + { + EGLContext context[1]; + EGLSurface surface[1]; + EGLConfig config; + EGLDisplay disp; + } egl; + + struct + { + int prev_age, frame_cnt; + int curr, last, num; + Ecore_Drm_Fb *buffer[4]; + struct gbm_bo *bo[4]; + 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_GL_Drm *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); + +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; +} + +#endif diff --git a/src/modules/evas/engines/gl_drm/evas_outbuf.c b/src/modules/evas/engines/gl_drm/evas_outbuf.c new file mode 100644 index 0000000000..124a3563a3 --- /dev/null +++ b/src/modules/evas/engines/gl_drm/evas_outbuf.c @@ -0,0 +1,656 @@ +#include "evas_engine.h" + +/* local variables */ +static Outbuf *_evas_gl_drm_window = NULL; +static EGLContext context = EGL_NO_CONTEXT; +static int win_count = 0; + +static void +_evas_outbuf_cb_pageflip(void *data) +{ + Outbuf *ob; + Ecore_Drm_Fb *fb; + + if (!(ob = data)) return; + + if ((fb = ob->priv.buffer[ob->priv.curr])) + { + fb->pending_flip = EINA_FALSE; + gbm_surface_release_buffer(ob->surface, ob->priv.bo[ob->priv.curr]); + } + + ob->priv.last = ob->priv.curr; + ob->priv.curr = (ob->priv.curr + 1) % ob->priv.num; +} + +static void +_evas_outbuf_buffer_swap(Outbuf *ob, Eina_Rectangle *rects, unsigned int count) +{ + Ecore_Drm_Fb *buff; + + buff = ob->priv.buffer[ob->priv.curr]; + + ob->priv.bo[ob->priv.curr] = gbm_surface_lock_front_buffer(ob->surface); + + ecore_drm_fb_dirty(buff, rects, count); + ecore_drm_fb_set(ob->info->info.dev, buff); + ecore_drm_fb_send(ob->info->info.dev, buff, _evas_outbuf_cb_pageflip, ob); +} + +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; +} + +static Eina_Bool +_evas_outbuf_egl_setup(Outbuf *ob) +{ + int ctx_attr[3]; + int cfg_attr[40]; + int maj = 0, min = 0; + int ncfg = 0, n = 0; + const GLubyte *vendor, *renderer, *version, *glslversion; + Eina_Bool blacklist = EINA_FALSE; + + /* setup gbm egl surface */ + ctx_attr[0] = EGL_CONTEXT_CLIENT_VERSION; + ctx_attr[1] = 2; + ctx_attr[2] = EGL_NONE; + + cfg_attr[n++] = EGL_SURFACE_TYPE; + cfg_attr[n++] = EGL_WINDOW_BIT; + cfg_attr[n++] = EGL_RED_SIZE; + cfg_attr[n++] = 1; + cfg_attr[n++] = EGL_GREEN_SIZE; + cfg_attr[n++] = 1; + cfg_attr[n++] = EGL_BLUE_SIZE; + cfg_attr[n++] = 1; + cfg_attr[n++] = EGL_ALPHA_SIZE; + if (ob->destination_alpha) cfg_attr[n++] = 1; + else cfg_attr[n++] = 0; + cfg_attr[n++] = EGL_RENDERABLE_TYPE; + cfg_attr[n++] = EGL_OPENGL_ES2_BIT; + cfg_attr[n++] = EGL_NONE; + + ob->egl.disp = eglGetDisplay((EGLNativeDisplayType)(ob->gbm)); + 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 (!eglChooseConfig(ob->egl.disp, cfg_attr, &ob->egl.config, + 1, &ncfg) || (ncfg != 1)) + { + ERR("eglChooseConfig() fail. code=%#x", eglGetError()); + return EINA_FALSE; + } + + ob->egl.surface[0] = + eglCreateWindowSurface(ob->egl.disp, ob->egl.config, + (EGLNativeWindowType)ob->surface, NULL); + if (ob->egl.surface[0] == EGL_NO_SURFACE) + { + ERR("eglCreateWindowSurface() fail for %p. code=%#x", + ob->surface, eglGetError()); + return EINA_FALSE; + } + + ob->egl.context[0] = + eglCreateContext(ob->egl.disp, ob->egl.config, 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_GL_Drm *info, int w, int h, Render_Engine_Swap_Mode swap_mode) +{ + Outbuf *ob; + char *num; + int i = 0; + + /* 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->vsync = info->info.vsync; + ob->gbm = info->info.gbm; + ob->surface = info->info.surface; + ob->swap_mode = swap_mode; + ob->priv.num = 2; + + if ((num = getenv("EVAS_GL_DRM_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_GL_DRM_VSYNC"))) + ob->vsync = atoi(num); + + if (!_evas_outbuf_egl_setup(ob)) + { + evas_outbuf_free(ob); + return NULL; + } + + for (; i < ob->priv.num; i++) + { + ob->priv.buffer[i] = + ecore_drm_fb_create(ob->info->info.dev, ob->w, ob->h); + if (!ob->priv.buffer[i]) break; + + DBG("Evas Engine Created Dumb Buffer"); + DBG("\tFb: %d", ob->priv.buffer[i]->id); + DBG("\tHandle: %d", ob->priv.buffer[i]->hdl); + DBG("\tStride: %d", ob->priv.buffer[i]->stride); + DBG("\tSize: %d", ob->priv.buffer[i]->size); + DBG("\tW: %d\tH: %d", + ob->priv.buffer[i]->w, ob->priv.buffer[i]->h); + } + + ecore_drm_fb_set(info->info.dev, ob->priv.buffer[0]); + + return ob; +} + +void +evas_outbuf_free(Outbuf *ob) +{ + int i = 0, ref = 0; + + win_count--; + evas_outbuf_use(ob); + + if (ob == _evas_gl_drm_window) _evas_gl_drm_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 0 + if (ob->surface) + { + gbm_surface_destroy(ob->surface); + ob->info->info.surface = NULL; + } +//#endif + + if (ref == 0) + { + if (context) eglDestroyContext(ob->egl.disp, context); + eglTerminate(ob->egl.disp); + eglReleaseThread(); + context = EGL_NO_CONTEXT; + } + + for (; i < ob->priv.num; i++) + ecore_drm_fb_destroy(ob->priv.buffer[i]); + + 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_gl_drm_window) + { + if (eglGetCurrentContext() != _evas_gl_drm_window->egl.context[0]) + force = EINA_TRUE; + } + + if ((_evas_gl_drm_window != ob) || (force)) + { + if (_evas_gl_drm_window) + { + glsym_evas_gl_common_context_use(_evas_gl_drm_window->gl_context); + glsym_evas_gl_common_context_flush(_evas_gl_drm_window->gl_context); + } + + _evas_gl_drm_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, + (EGLNativeWindowType)ob->surface, NULL); + + if (ob->egl.surface[0] == EGL_NO_SURFACE) + { + ERR("eglCreateWindowSurface() fail for %p. code=%#x", + ob->surface, 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_gl_drm_window) + glsym_evas_gl_common_context_flush(_evas_gl_drm_window->gl_context); + if (_evas_gl_drm_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_gl_drm_window = NULL; + } + + ob->surf = EINA_FALSE; +} + +void +evas_outbuf_reconfigure(Outbuf *ob, int w, int h, int rot, Outbuf_Depth depth) +{ + int i = 0; + + if (depth == OUTBUF_DEPTH_INHERIT) depth = ob->depth; + + /* check for changes */ + if ((ob->w == w) && (ob->h == h) && + (ob->destination_alpha == ob->info->info.destination_alpha) && + ((int)ob->rotation == rot) && (ob->depth == depth)) + return; + + ob->w = w; + ob->h = h; + ob->depth = depth; + ob->rotation = rot; + + /* destroy the old buffers */ + for (; i < ob->priv.num; i++) + ecore_drm_fb_destroy(ob->priv.buffer[i]); + + for (i = 0; i < ob->priv.num; i++) + { + ob->priv.buffer[i] = + ecore_drm_fb_create(ob->info->info.dev, ob->w, ob->h); + if (!ob->priv.buffer[i]) + { + ERR("Failed to create buffer %d", i); + break; + } + } + + evas_outbuf_use(ob); + + glsym_evas_gl_common_context_resize(ob->gl_context, w, h, rot); + + //TODO: need drm gbm surface destroy & re-create.? +} + +Render_Engine_Swap_Mode +evas_outbuf_buffer_state_get(Outbuf *ob) +{ + if (ob->swap_mode == MODE_AUTO && _extn_have_buffer_age) + { + Render_Engine_Swap_Mode swap_mode; + EGLint age = 0; + + if (!eglQuerySurface(ob->egl.disp, ob->egl.surface[0], + EGL_BUFFER_AGE_EXT, &age)) + age = 0; + + if (age == 1) swap_mode = MODE_COPY; + else if (age == 2) swap_mode = MODE_DOUBLE; + else if (age == 3) swap_mode = MODE_TRIPLE; + else if (age == 4) swap_mode = MODE_QUADRUPLE; + else swap_mode = MODE_FULL; + if ((int)age != ob->priv.prev_age) swap_mode = MODE_FULL; + ob->priv.prev_age = age; + + return swap_mode; + } + + return ob->swap_mode; +} + +int +evas_outbuf_rot_get(Outbuf *ob) +{ + return ob->rotation; +} + +Eina_Bool +evas_outbuf_update_region_first_rect(Outbuf *ob) +{ + ob->gl_context->preserve_bit = GL_COLOR_BUFFER_BIT0_QCOM; + + 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_resize(ob->gl_context, ob->w, ob->h, ob->rotation); + 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); */ + +// TODO: Check eglSwapBuffersWithDamage for gl_drm and apply +#if 0 + if ((glsym_eglSwapBuffersWithDamage) && (ob->swap_mode != MODE_FULL)) + { + EGLint num = 0, *result = NULL, i = 0; + Tilebuf_Rect *r; + + // if partial swaps can be done use re->rects + num = eina_inlist_count(EINA_INLIST_GET(rects)); + if (num > 0) + { + result = alloca(sizeof(EGLint) * 4 * num); + EINA_INLIST_FOREACH(EINA_INLIST_GET(rects), r) + { + int gw, gh; + + gw = ob->gl_context->w; + gh = ob->gl_context->h; + switch (ob->rot) + { + case 0: + result[i + 0] = r->x; + result[i + 1] = gh - (r->y + r->h); + result[i + 2] = r->w; + result[i + 3] = r->h; + break; + case 90: + result[i + 0] = r->y; + result[i + 1] = r->x; + result[i + 2] = r->h; + result[i + 3] = r->w; + break; + case 180: + result[i + 0] = gw - (r->x + r->w); + result[i + 1] = r->y; + result[i + 2] = r->w; + result[i + 3] = r->h; + break; + case 270: + result[i + 0] = gh - (r->y + r->h); + result[i + 1] = gw - (r->x + r->w); + result[i + 2] = r->h; + result[i + 3] = r->w; + break; + default: + result[i + 0] = r->x; + result[i + 1] = gh - (r->y + r->h); + result[i + 2] = r->w; + result[i + 3] = r->h; + break; + } + i += 4; + } + glsym_eglSwapBuffersWithDamage(ob->egl.disp, ob->egl.surface[0], + result, num); + } + } + else +#endif + 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); */ + + //Flush GL Surface data to Framebuffer + _evas_outbuf_buffer_swap(ob, NULL, 0); + + ob->priv.frame_cnt++; + + end: + //TODO: Need render unlock after drm page flip? + 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_use(Context_3D *ctx) +{ + if (eglMakeCurrent(ctx->display, ctx->surface, + ctx->surface, ctx->context) == EGL_FALSE) + ERR("eglMakeCurrent() failed."); +} -- cgit v1.2.1