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.
This commit is contained in:
Jean-Philippe Andre 2014-03-06 17:42:24 +09:00
parent 688c9c3676
commit 59f5216391
5 changed files with 75 additions and 1 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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,