From 59f5216391ab6919dd03b629ece62ba01b82284b Mon Sep 17 00:00:00 2001 From: Jean-Philippe Andre Date: Thu, 6 Mar 2014 17:42:24 +0900 Subject: [PATCH] Evas gl_x11: Add support for glReadPixels This will be needed by the filters for proxy rendering, for textures and maps (displacement). Add new engine functions to unleash the (sluggish) power of glReadPixels. The idea is to be able to bypass glReadPixels later, so 3 new APIs are added: - surface_lock - surface_read_pixels - surface_unlock They must be called in that order. Note (for history): glReadPixels was always getting the wrong data during first draw, but the right data during a redraw... Why? Well simply because for OpenGL itself, the image had never been drawn in teh first place! Only the Evas GL context knew about the image drawing, as it was queued somewhere in the pipe. One line solution: Call evas_gl_common_context_flush before doing anything else. --- src/lib/evas/include/evas_private.h | 5 +- .../evas/engines/gl_common/evas_gl_common.h | 3 ++ .../evas/engines/gl_common/evas_gl_context.c | 3 ++ src/modules/evas/engines/gl_x11/evas_engine.c | 62 ++++++++++++++++++++++ .../evas/engines/software_generic/evas_engine.c | 3 ++ 5 files changed, 75 insertions(+), 1 deletion(-) diff --git a/src/lib/evas/include/evas_private.h b/src/lib/evas/include/evas_private.h index 95dd249..9650805 100644 --- a/src/lib/evas/include/evas_private.h +++ b/src/lib/evas/include/evas_private.h @@ -907,8 +907,11 @@ struct _Evas_Func void *(*gl_proc_address_get) (void *data, const char *name); int (*gl_native_surface_get) (void *data, void *surface, void *native_surface); void *(*gl_api_get) (void *data); - void (*gl_direct_override_get) (void *data, int *override, int *force_off); + void (*gl_direct_override_get) (void *data, int *override, int *force_off); void (*gl_get_pixels_set) (void *data, void *get_pixels, void *get_pixels_data, void *obj); + Eina_Bool (*gl_surface_lock) (void *data, void *surface); + Eina_Bool (*gl_surface_read_pixels) (void *data, void *surface, int x, int y, int w, int h, Evas_Colorspace cspace, void *pixels); + Eina_Bool (*gl_surface_unlock) (void *data, void *surface); int (*image_load_error_get) (void *data, void *image); int (*font_run_end_get) (void *data, Evas_Font_Set *font, Evas_Font_Instance **script_fi, Evas_Font_Instance **cur_fi, Evas_Script_Type script, const Eina_Unicode *text, int run_len); diff --git a/src/modules/evas/engines/gl_common/evas_gl_common.h b/src/modules/evas/engines/gl_common/evas_gl_common.h index a6b624d..3f5bab2 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_common.h +++ b/src/modules/evas/engines/gl_common/evas_gl_common.h @@ -628,6 +628,7 @@ struct _Evas_GL_Image unsigned char cached : 1; unsigned char alpha : 1; unsigned char tex_only : 1; + unsigned char locked : 1; // gl_surface_lock/unlock }; struct _Evas_GL_Font_Texture @@ -838,6 +839,8 @@ extern void (*glsym_glReleaseShaderCompiler)(void); extern void *(*glsym_glMapBuffer) (GLenum a, GLenum b); extern GLboolean (*glsym_glUnmapBuffer) (GLenum a); +extern void (*glsym_glReadPixels) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *data); + #ifdef GL_GLES extern void *(*secsym_eglCreateImage) (void *a, void *b, GLenum c, void *d, const int *e); extern unsigned int (*secsym_eglDestroyImage) (void *a, void *b); diff --git a/src/modules/evas/engines/gl_common/evas_gl_context.c b/src/modules/evas/engines/gl_common/evas_gl_context.c index 2e447d9..000a396 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_context.c +++ b/src/modules/evas/engines/gl_common/evas_gl_context.c @@ -29,6 +29,7 @@ void *(*glsym_glMapBuffer) (GLenum a, GLenum b) = NULL; GLboolean (*glsym_glUnmapBuffer) (GLenum a) = NULL; void (*glsym_glStartTiling) (GLuint a, GLuint b, GLuint c, GLuint d, GLuint e) = NULL; void (*glsym_glEndTiling) (GLuint a) = NULL; +void (*glsym_glReadPixels) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *data) = NULL; #ifdef GL_GLES // just used for finding symbols :) @@ -211,6 +212,8 @@ gl_symbols(void) FINDSYM(secsym_eglGetImageAttribSEC, "eglGetImageAttribSEC", secsym_func_uint); #endif + + FINDSYM(glsym_glReadPixels, "glReadPixels", glsym_func_void); } static void shader_array_flush(Evas_Engine_GL_Context *gc); diff --git a/src/modules/evas/engines/gl_x11/evas_engine.c b/src/modules/evas/engines/gl_x11/evas_engine.c index d899ad9..cc44704 100644 --- a/src/modules/evas/engines/gl_x11/evas_engine.c +++ b/src/modules/evas/engines/gl_x11/evas_engine.c @@ -3371,6 +3371,65 @@ eng_gl_get_pixels_set(void *data, void *get_pixels, void *get_pixels_data, void re->func.get_pixels_data = get_pixels_data; re->func.obj = (Evas_Object*)obj; } + +static Eina_Bool +eng_gl_surface_lock(void *data, void *surface) +{ + Render_Engine *re = data; + Evas_GL_Image *im = surface; + + EVGLINIT(re, EINA_FALSE); + if (!im->tex || !im->tex->pt) + { + ERR("Can not lock image that is not a surface!"); + return EINA_FALSE; + } + + evas_gl_common_context_flush(im->gc); + im->locked = EINA_TRUE; + return EINA_TRUE; +} + +static Eina_Bool +eng_gl_surface_unlock(void *data, void *surface) +{ + Render_Engine *re = data; + Evas_GL_Image *im = surface; + + EVGLINIT(re, EINA_FALSE); + im->locked = EINA_FALSE; + return EINA_TRUE; +} + +static Eina_Bool +eng_gl_surface_read_pixels(void *data, void *surface, + int x, int y, int w, int h, + Evas_Colorspace cspace, void *pixels) +{ + Render_Engine *re = data; + Evas_GL_Image *im = surface; + + EINA_SAFETY_ON_NULL_RETURN_VAL(pixels, EINA_FALSE); + + EVGLINIT(re, EINA_FALSE); + if (!im->locked) + { + // For now, this is useless, but let's force clients to lock :) + CRI("The surface must be locked before reading its pixels!"); + return EINA_FALSE; + } + + if (cspace != EVAS_COLORSPACE_ARGB8888) + { + ERR("Conversion to colorspace %d is not supported!", (int) cspace); + return EINA_FALSE; + } + + glsym_glBindFramebuffer(GL_READ_FRAMEBUFFER, im->tex->pt->fb); + glsym_glReadPixels(x, y, w, h, GL_BGRA, GL_UNSIGNED_BYTE, pixels); + glsym_glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + return EINA_TRUE; +} //--------------------------------// static int @@ -3696,6 +3755,9 @@ module_open(Evas_Module *em) ORD(gl_api_get); ORD(gl_direct_override_get); ORD(gl_get_pixels_set); + ORD(gl_surface_lock); + ORD(gl_surface_read_pixels); + ORD(gl_surface_unlock); ORD(image_load_error_get); diff --git a/src/modules/evas/engines/software_generic/evas_engine.c b/src/modules/evas/engines/software_generic/evas_engine.c index 1017ba2..584883b 100644 --- a/src/modules/evas/engines/software_generic/evas_engine.c +++ b/src/modules/evas/engines/software_generic/evas_engine.c @@ -2692,6 +2692,9 @@ static Evas_Func func = NULL, // need software mesa for gl rendering <- gl_api_get NULL, // need software mesa for gl rendering <- gl_direct_override NULL, // need software mesa for gl rendering <- gl_get_pixels_set + NULL, // need software mesa for gl rendering <- gl_surface_lock + NULL, // need software mesa for gl rendering <- gl_surface_read_pixels + NULL, // need software mesa for gl rendering <- gl_surface_unlock eng_image_load_error_get, eng_font_run_font_end_get, eng_image_animated_get, -- 2.7.4