Evas GL: Add indirect surface fallback and yinvert callback

Summary:
When either FBO or EGL image from texture extension is not supported,
we can use pixmap surface as indirect surface fallback.
Since native pixmaps have (0,0) in the upper left while
FBOs have (0,0) in the lower left, we should invert the y coordinates
when native pixmaps are used as the render target.
To accomodate run-time y-invert check we add a new callback for
EVAS_NATIVE_SURFACE_EVASGL type.

Reviewers: cedric, jpeg

Subscribers: wonsik, mer.kim, cedric
This commit is contained in:
Dongyeon Kim 2015-04-21 10:54:02 +09:00 committed by Jean-Philippe Andre
parent 63e057bff9
commit b0d2643f93
6 changed files with 191 additions and 82 deletions

View File

@ -657,9 +657,10 @@ struct _Evas_GL_Image
struct {
void *data;
struct {
void (*bind) (void *data, void *image);
void (*unbind) (void *data, void *image);
void (*free) (void *data, void *image);
void (*bind) (void *data, void *image);
void (*unbind) (void *data, void *image);
void (*free) (void *data, void *image);
int (*yinvert) (void *data, void *image);
void *data;
} func;
int yinvert;

View File

@ -2029,6 +2029,7 @@ evas_gl_common_context_image_push(Evas_Engine_GL_Context *gc,
Evas_GL_Shader shader = SHADER_IMG;
GLuint prog = gc->shared->shader[shader].prog;
int pn = 0, sam = 0, render_op = gc->dc->render_op, nomul = 0;
int yinvert = 0;
if (!!mtex)
{
@ -2121,7 +2122,15 @@ evas_gl_common_context_image_push(Evas_Engine_GL_Context *gc,
ox4 = sx;
oy4 = sy + sh;
if (tex->im)
if ((tex->im) && (tex->im->native.data))
{
if (tex->im->native.func.yinvert)
yinvert = tex->im->native.func.yinvert(tex->im->native.func.data, tex->im);
else
yinvert = tex->im->native.yinvert;
}
if ((tex->im) && (tex->im->native.data) && (!yinvert))
{
switch (tex->im->orient)
{
@ -2707,7 +2716,7 @@ evas_gl_common_context_image_map_push(Evas_Engine_GL_Context *gc,
Eina_Bool use_texa = EINA_FALSE;
Shader_Type type;
int pn = 0, i;
int flat = 0, nomul = 0;
int flat = 0, nomul = 0, yinvert = 0;
GLuint prog;
if (!(gc->dc->render_op == EVAS_RENDER_COPY) &&
@ -2868,7 +2877,15 @@ evas_gl_common_context_image_map_push(Evas_Engine_GL_Context *gc,
pipe_region_expand(gc, pn, x, y, w, h);
PIPE_GROW(gc, pn, 6);
if ((tex->im) && (tex->im->native.data) && (!tex->im->native.yinvert))
if ((tex->im) && (tex->im->native.data))
{
if (tex->im->native.func.yinvert)
yinvert = tex->im->native.func.yinvert(tex->im->native.func.data, tex->im);
else
yinvert = tex->im->native.yinvert;
}
if ((tex->im) && (tex->im->native.data) && (!yinvert))
{
for (i = 0; i < 4; i++)
{

View File

@ -239,32 +239,36 @@ _texture_attach_2d(GLuint tex, GLenum attach, GLenum attach2, int samples, Eina_
}
static void *
_egl_image_create(EVGL_Context *context, GLuint tex)
_egl_image_create(EVGL_Context *context, int target, void *buffer)
{
#ifdef GL_GLES
EGLDisplay dpy = EGL_NO_DISPLAY;
EGLContext ctx = EGL_NO_CONTEXT;
EVGL_Resource *rsc = NULL;
int attribs[10];
int n = 0;
int attribs[] = {
EGL_GL_TEXTURE_LEVEL_KHR, 0,
EGL_IMAGE_PRESERVED_KHR, 0,
EGL_NONE
};
// Retrieve the resource object
if (!(rsc = _evgl_tls_resource_get()))
{
ERR("Error creating resources in tls.");
return NULL;
}
dpy = (EGLDisplay)rsc->display;
ctx = (EGLContext)context->context;
return EXT_FUNC(eglCreateImage)(dpy, ctx, EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)(uintptr_t)tex, attribs);
dpy = (EGLDisplay)rsc->display;
if (target == EGL_GL_TEXTURE_2D_KHR)
{
ctx = (EGLContext)context->context;
attribs[n++] = EGL_GL_TEXTURE_LEVEL_KHR;
attribs[n++] = 0;
}
attribs[n++] = EGL_IMAGE_PRESERVED_KHR;
attribs[n++] = 0;
attribs[n++] = EGL_NONE;
return EXT_FUNC(eglCreateImage)(dpy, ctx, target, (EGLClientBuffer)(uintptr_t)buffer, attribs);
#else
(void) context; (void) tex;
(void) context; (void) target; (void) buffer;
return NULL;
#endif
}
@ -856,6 +860,10 @@ _surface_cap_init(void *eng_data)
static int
_context_ext_check(EVGL_Context *ctx)
{
int fbo_supported = 0;
int egl_image_supported = 0;
int texture_image_supported = 0;
if (!ctx)
return 0;
@ -863,9 +871,6 @@ _context_ext_check(EVGL_Context *ctx)
return 1;
#ifdef GL_GLES
int fbo_supported = 0;
int egl_image_supported = 0;
switch (ctx->version)
{
case EVAS_GL_GLES_1_X:
@ -878,21 +883,31 @@ _context_ext_check(EVGL_Context *ctx)
fbo_supported = 1;
}
if (EXTENSION_SUPPORT(EGL_KHR_image_base)
&& EXTENSION_SUPPORT(EGL_KHR_gl_texture_2D_image))
if (EXTENSION_SUPPORT(EGL_KHR_image_base))
egl_image_supported = 1;
if (fbo_supported && egl_image_supported)
ctx->fbo_image_supported = 1;
if (EXTENSION_SUPPORT(EGL_KHR_gl_texture_2D_image))
texture_image_supported = 1;
#else
ctx->fbo_image_supported = 1;
fbo_supported = 1;
egl_image_supported = 0;
texture_image_supported = 0;
#endif
if (egl_image_supported)
{
if (fbo_supported && texture_image_supported)
ctx->fbo_image_supported = 1;
else
ctx->pixmap_image_supported = 1;
}
ctx->extension_checked = 1;
return 1;
}
static const char *
_glenum_string_get(GLenum e)
{
@ -1179,7 +1194,7 @@ _surface_buffers_allocate(void *eng_data, EVGL_Surface *sfc, int w, int h, int m
sfc->egl_image = NULL;
}
if ((sfc->current_ctx) && (sfc->current_ctx->fbo_image_supported) && (w) && (h))
sfc->egl_image = _egl_image_create(sfc->current_ctx, sfc->color_buf);
sfc->egl_image = _egl_image_create(sfc->current_ctx, EGL_GL_TEXTURE_2D_KHR, (void *)(uintptr_t)sfc->color_buf);
sfc->buffer_mem[0] = w * h * 4;
}
@ -1792,6 +1807,7 @@ evgl_surface_create(void *eng_data, Evas_GL_Config *cfg, int w, int h)
evas_gl_common_error_set(eng_data, EVAS_GL_BAD_CONFIG);
goto error;
}
sfc->cfg = cfg;
// Keep track of all the created surfaces
LKL(evgl_engine->resource_lock);
@ -1865,6 +1881,7 @@ evgl_pbuffer_surface_create(void *eng_data, Evas_GL_Config *cfg,
goto error;
}
}
sfc->cfg = cfg;
pbuffer = evgl_engine->funcs->pbuffer_surface_create
(eng_data, sfc, attrib_list);
@ -2320,7 +2337,7 @@ evgl_make_current(void *eng_data, EVGL_Surface *sfc, EVGL_Context *ctx)
}
}
if (!ctx->fbo_image_supported)
if (ctx->pixmap_image_supported)
{
if (dbg) DBG("ctx %p is GLES %d", ctx, ctx->version);
if (_evgl_direct_renderable(rsc, sfc))
@ -2338,12 +2355,17 @@ evgl_make_current(void *eng_data, EVGL_Surface *sfc, EVGL_Context *ctx)
}
else
{
if (!sfc->indirect_sfc)
{
evgl_engine->funcs->indirect_surface_create(evgl_engine, eng_data, sfc, sfc->cfg, sfc->w, sfc->h);
sfc->egl_image = _egl_image_create(NULL, EVAS_GL_NATIVE_PIXMAP, sfc->indirect_sfc_native);
}
if (!ctx->indirect_context)
{
ctx->indirect_context =
evgl_engine->funcs->gles_context_create(eng_data, ctx, sfc);
}
if (dbg) DBG("Calling make_current(%p, %p)", sfc->indirect_sfc, ctx->context);
if (dbg) DBG("Calling make_current(%p, %p)", sfc->indirect_sfc, ctx->indirect_context);
if (!evgl_engine->funcs->make_current(eng_data, sfc->indirect_sfc,
ctx->indirect_context, EINA_TRUE))
{
@ -2559,6 +2581,22 @@ evgl_native_surface_buffer_get(EVGL_Surface *sfc)
#endif
}
int
evgl_native_surface_yinvert_get(EVGL_Surface *sfc)
{
int ret = 0;
if (!evgl_engine)
{
ERR("Invalid input data. Engine: %p", evgl_engine);
return 0;
}
if (sfc->indirect)
ret = sfc->yinvert;
return ret;
}
int
evgl_native_surface_get(EVGL_Surface *sfc, Evas_Native_Surface *ns)
{

View File

@ -44,13 +44,12 @@ typedef struct _EVGL_Surface_Cap EVGL_Surface_Cap;
typedef struct _EVGL_Surface_Format EVGL_Surface_Format;
EAPI void evgl_engine_shutdown(void *eng_data);
EAPI void *evgl_native_surface_buffer_get(EVGL_Surface *sfc);
EAPI int evgl_native_surface_yinvert_get(EVGL_Surface *sfc);
typedef void (*EVGL_Engine_Call)(void *eng_data);
EAPI void *evgl_native_surface_buffer_get(EVGL_Surface *sfc);
typedef void *(*EVGL_Native_Surface_Call)(void *sfc);
typedef int (*EVGL_Native_Surface_Yinvert_Call)(void *sfc);
EVGL_Engine *evgl_engine_init(void *eng_data, const EVGL_Interface *efunc);

View File

@ -116,6 +116,7 @@ struct _EVGL_Surface
// Flag indicating this surface is used for indirect rendering
unsigned indirect : 1;
unsigned yinvert : 1;
// Moved from evgl_engine
unsigned direct_override : 1;
@ -124,6 +125,7 @@ struct _EVGL_Surface
// Init Flag
unsigned buffers_allocated : 1;
void *cfg;
int cfg_index;
@ -174,6 +176,7 @@ struct _EVGL_Context
unsigned viewport_updated : 1;
unsigned extension_checked : 1;
unsigned fbo_image_supported : 1;
unsigned pixmap_image_supported : 1;
int scissor_coord[4];
int viewport_coord[4];

View File

@ -60,6 +60,7 @@ Evas_GL_Preload glsym_evas_gl_preload_init = NULL;
Evas_GL_Preload glsym_evas_gl_preload_shutdown = NULL;
EVGL_Engine_Call glsym_evgl_engine_shutdown = NULL;
EVGL_Native_Surface_Call glsym_evgl_native_surface_buffer_get = NULL;
EVGL_Native_Surface_Yinvert_Call glsym_evgl_native_surface_yinvert_get = NULL;
Evas_Gl_Symbols glsym_evas_gl_symbols = NULL;
Evas_GL_Common_Context_New glsym_evas_gl_common_context_new = NULL;
@ -893,8 +894,7 @@ evgl_eng_indirect_surface_create(EVGL_Engine *evgl EINA_UNUSED, void *data,
return NULL;
}
if (((cfg->gles_version != EVAS_GL_GLES_3_X) && (cfg->gles_version != EVAS_GL_GLES_1_X))
|| (w < 1) || (h < 1))
if ((w < 1) || (h < 1))
{
ERR("Inconsistent parameters, not creating any surface!");
glsym_evas_gl_common_error_set(data, EVAS_GL_BAD_PARAMETER);
@ -932,6 +932,7 @@ evgl_eng_indirect_surface_create(EVGL_Engine *evgl EINA_UNUSED, void *data,
int msaa = 0, depth = 0, stencil = 0;
Visual *visual = NULL;
Eina_Bool retried = EINA_FALSE;
int val;
/* Now we need to iterate over all EGL configurations to check the compatible
* ones and finally check their visual ID. */
@ -955,6 +956,8 @@ try_again:
config_attrs[i++] = EGL_RENDERABLE_TYPE;
if (cfg->gles_version == EVAS_GL_GLES_3_X)
config_attrs[i++] = EGL_OPENGL_ES3_BIT;
else if (cfg->gles_version == EVAS_GL_GLES_2_X)
config_attrs[i++] = EGL_OPENGL_ES2_BIT;
else
config_attrs[i++] = EGL_OPENGL_ES_BIT;
if (alpha)
@ -1084,6 +1087,13 @@ try_again:
return NULL;
}
if (extn_have_y_inverted &&
eglGetConfigAttrib(eng_get_ob(re)->egl_disp, egl_cfg,
EGL_Y_INVERTED_NOK, &val))
evgl_sfc->yinvert = val;
else
evgl_sfc->yinvert = 1;
evgl_sfc->indirect = EINA_TRUE;
evgl_sfc->indirect_sfc = egl_sfc;
evgl_sfc->indirect_sfc_native = (void *)(intptr_t) px;
@ -1171,7 +1181,7 @@ evgl_eng_gles_context_create(void *data,
else config = sfc->indirect_sfc_config;
context = eglCreateContext(eng_get_ob(re)->egl_disp, config,
share_ctx ? share_ctx->context : NULL,
share_ctx->context,
context_attrs);
if (!context)
{
@ -1269,6 +1279,7 @@ gl_symbols(void)
LINK2GENERIC(evas_gl_preload_shutdown);
LINK2GENERIC(evgl_engine_shutdown);
LINK2GENERIC(evgl_native_surface_buffer_get);
LINK2GENERIC(evgl_native_surface_yinvert_get);
LINK2GENERIC(evas_gl_symbols);
LINK2GENERIC(evas_gl_common_error_get);
LINK2GENERIC(evas_gl_common_error_set);
@ -1961,12 +1972,14 @@ struct _Native
Visual *visual;
void *buffer;
void *egl_surface;
void *config;
void *surface;
/*
#ifndef GL_GLES
void *fbc;
XID glx_pixmap;
#endif
*/
};
// FIXME: this is enabled so updates happen - but its SLOOOOOOOOOOOOOOOW
@ -1987,11 +2000,11 @@ _native_bind_cb(void *data EINA_UNUSED, void *image)
if (n->ns.type == EVAS_NATIVE_SURFACE_X11)
{
#ifdef GL_GLES
if (n->egl_surface)
if (n->surface)
{
if (glsym_glEGLImageTargetTexture2DOES)
{
glsym_glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, n->egl_surface);
glsym_glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, n->surface);
if (eglGetError() != EGL_SUCCESS)
ERR("glEGLImageTargetTexture2DOES() failed.");
}
@ -2004,7 +2017,7 @@ _native_bind_cb(void *data EINA_UNUSED, void *image)
if (glsym_glXBindTexImage)
{
glsym_glXBindTexImage(eng_get_ob(re)->disp, n->glx_pixmap,
glsym_glXBindTexImage(eng_get_ob(re)->disp, (XID)n->surface,
GLX_FRONT_LEFT_EXT, NULL);
GLERRV("glsym_glXBindTexImage");
}
@ -2020,11 +2033,11 @@ _native_bind_cb(void *data EINA_UNUSED, void *image)
else if (n->ns.type == EVAS_NATIVE_SURFACE_TBM)
{
#ifdef GL_GLES
if (n->egl_surface)
if (n->surface)
{
if (glsym_glEGLImageTargetTexture2DOES)
{
glsym_glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, n->egl_surface);
glsym_glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, n->surface);
if (eglGetError() != EGL_SUCCESS)
ERR("glEGLImageTargetTexture2DOES() failed.");
}
@ -2035,10 +2048,10 @@ _native_bind_cb(void *data EINA_UNUSED, void *image)
}
else if (n->ns.type == EVAS_NATIVE_SURFACE_EVASGL)
{
if (n->egl_surface)
if (n->surface)
{
#ifdef GL_GLES
void *surface = glsym_evgl_native_surface_buffer_get(n->egl_surface);
void *surface = glsym_evgl_native_surface_buffer_get(n->surface);
if (glsym_glEGLImageTargetTexture2DOES)
{
glsym_glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, surface);
@ -2048,7 +2061,7 @@ _native_bind_cb(void *data EINA_UNUSED, void *image)
else
ERR("Try glEGLImageTargetTexture2DOES on EGL with no support");
#else
GLuint tex = (GLuint)(uintptr_t)glsym_evgl_native_surface_buffer_get(n->egl_surface);
GLuint tex = (GLuint)(uintptr_t)glsym_evgl_native_surface_buffer_get(n->surface);
glBindTexture(GL_TEXTURE_2D, tex);
#endif
}
@ -2071,7 +2084,7 @@ _native_unbind_cb(void *data EINA_UNUSED, void *image)
if (glsym_glXReleaseTexImage)
{
glsym_glXReleaseTexImage(eng_get_ob(re)->disp, n->glx_pixmap,
glsym_glXReleaseTexImage(eng_get_ob(re)->disp, (XID)n->surface,
GLX_FRONT_LEFT_EXT);
}
else
@ -2110,13 +2123,13 @@ _native_free_cb(void *data, void *image)
pmid = n->pixmap;
eina_hash_del(eng_get_ob(re)->gl_context->shared->native_pm_hash, &pmid, im);
#ifdef GL_GLES
if (n->egl_surface)
if (n->surface)
{
int err;
if (glsym_eglDestroyImage)
{
glsym_eglDestroyImage(eng_get_ob(re)->egl_disp,
n->egl_surface);
n->surface);
if ((err = eglGetError()) != EGL_SUCCESS)
{
ERR("eglDestroyImage() failed.");
@ -2128,13 +2141,13 @@ _native_free_cb(void *data, void *image)
}
#else
# ifdef GLX_BIND_TO_TEXTURE_TARGETS_EXT
if (n->glx_pixmap)
if (n->surface)
{
if (im->native.loose)
{
if (glsym_glXReleaseTexImage)
{
glsym_glXReleaseTexImage(eng_get_ob(re)->disp, n->glx_pixmap,
glsym_glXReleaseTexImage(eng_get_ob(re)->disp, (XID)n->surface,
GLX_FRONT_LEFT_EXT);
}
else
@ -2142,12 +2155,12 @@ _native_free_cb(void *data, void *image)
}
if (glsym_glXDestroyPixmap)
{
glsym_glXDestroyPixmap(eng_get_ob(re)->disp, n->glx_pixmap);
glsym_glXDestroyPixmap(eng_get_ob(re)->disp, (XID)n->surface);
GLERRV("glsym_glXDestroyPixmap");
}
else
ERR("Try glXDestroyPixmap on GLX with no support");
n->glx_pixmap = 0;
n->surface = 0;
}
# endif
#endif
@ -2161,13 +2174,13 @@ _native_free_cb(void *data, void *image)
{
eina_hash_del(eng_get_ob(re)->gl_context->shared->native_tbm_hash, &n->buffer, im);
#ifdef GL_GLES
if (n->egl_surface)
if (n->surface)
{
int err;
if (glsym_eglDestroyImage)
{
glsym_eglDestroyImage(eng_get_ob(re)->egl_disp,
n->egl_surface);
n->surface);
if ((err = eglGetError()) != EGL_SUCCESS)
{
ERR("eglDestroyImage() failed.");
@ -2191,6 +2204,45 @@ _native_free_cb(void *data, void *image)
free(n);
}
static int
_native_yinvert_cb(void *data, void *image)
{
Render_Engine *re = data;
Evas_GL_Image *im = image;
Native *n = im->native.data;
int yinvert = 0, val;
// Yinvert callback should only be used for EVAS_NATIVE_SURFACE_EVASGL type now,
// as yinvert value is not changed for other types.
if (n->ns.type == EVAS_NATIVE_SURFACE_X11)
{
#if GL_GLES
if (extn_have_y_inverted &&
eglGetConfigAttrib(eng_get_ob(re)->egl_disp, n->config,
EGL_Y_INVERTED_NOK, &val))
yinvert = val;
#else
glXGetFBConfigAttrib(eng_get_ob(re)->disp, n->config,
GLX_Y_INVERTED_EXT, &val);
yinvert = val;
#endif
}
else if (n->ns.type == EVAS_NATIVE_SURFACE_OPENGL)
{
yinvert = 0;
}
else if (n->ns.type == EVAS_NATIVE_SURFACE_TBM)
{
yinvert = 1;
}
else if (n->ns.type == EVAS_NATIVE_SURFACE_EVASGL)
{
yinvert = glsym_evgl_native_surface_yinvert_get(n->surface);
}
return yinvert;
}
static void *
eng_image_native_set(void *data, void *image, void *native)
{
@ -2406,15 +2458,17 @@ eng_image_native_set(void *data, void *image, void *native)
n->pixmap = pm;
n->visual = vis;
if (glsym_eglCreateImage)
n->egl_surface = glsym_eglCreateImage(eng_get_ob(re)->egl_disp,
n->surface = glsym_eglCreateImage(eng_get_ob(re)->egl_disp,
EGL_NO_CONTEXT,
EGL_NATIVE_PIXMAP_KHR,
(void *)pm,
NULL);
else
ERR("Try eglCreateImage on EGL with no support");
if (!n->egl_surface)
if (!n->surface)
ERR("eglCreatePixmapSurface() for 0x%x failed", (unsigned int)pm);
n->config = (void *)egl_config;
im->native.yinvert = yinvert;
im->native.loose = 0;
im->native.data = n;
@ -2537,7 +2591,7 @@ eng_image_native_set(void *data, void *image, void *native)
glXGetFBConfigAttrib(eng_get_ob(re)->disp, configs[j],
GLX_BIND_TO_MIPMAP_TEXTURE_EXT, &val);
mipmap = val;
n->fbc = configs[j];
n->config = configs[j];
found = 1;
break;
}
@ -2582,16 +2636,16 @@ eng_image_native_set(void *data, void *image, void *native)
n->pixmap = pm;
n->visual = vis;
if (glsym_glXCreatePixmap)
n->glx_pixmap = glsym_glXCreatePixmap(eng_get_ob(re)->disp,
n->fbc,
n->pixmap,
pixmap_att);
n->surface = (void *)glsym_glXCreatePixmap(eng_get_ob(re)->disp,
n->config,
n->pixmap,
pixmap_att);
else
ERR("Try glXCreatePixmap on GLX with no support");
if (n->glx_pixmap)
if (n->surface)
{
// printf("%p: new native texture for %x | %4i x %4i @ %2i = %p\n",
// n, pm, w, h, depth, n->glx_pixmap);
// n, pm, w, h, depth, n->surface);
if (!target)
{
ERR("no target :(");
@ -2650,12 +2704,8 @@ eng_image_native_set(void *data, void *image, void *native)
n->pixmap = 0;
n->visual = 0;
#ifdef GL_GLES
n->egl_surface = 0;
#else
n->fbc = 0;
n->glx_pixmap = 0;
#endif
n->config = 0;
n->surface = 0;
im->native.yinvert = 0;
im->native.loose = 0;
@ -2688,14 +2738,14 @@ eng_image_native_set(void *data, void *image, void *native)
memcpy(&(n->ns), ns, sizeof(Evas_Native_Surface));
n->buffer = buffer;
if (glsym_eglCreateImage)
n->egl_surface = glsym_eglCreateImage(eng_get_ob(re)->egl_disp,
n->surface = glsym_eglCreateImage(eng_get_ob(re)->egl_disp,
EGL_NO_CONTEXT,
EGL_NATIVE_SURFACE_TIZEN,
(void *)buffer,
NULL);
else
ERR("Try eglCreateImage on EGL with no support");
if (!n->egl_surface)
if (!n->surface)
ERR("eglCreateImage() for %p failed", buffer);
im->native.yinvert = 1;
im->native.loose = 0;
@ -2725,17 +2775,18 @@ eng_image_native_set(void *data, void *image, void *native)
n->pixmap = 0;
n->visual = 0;
n->egl_surface = ns->data.evasgl.surface;
n->surface = ns->data.evasgl.surface;
im->native.yinvert = 0;
im->native.loose = 0;
im->native.data = n;
im->native.func.data = re;
im->native.func.bind = _native_bind_cb;
im->native.func.unbind = _native_unbind_cb;
im->native.func.free = _native_free_cb;
im->native.target = GL_TEXTURE_2D;
im->native.mipmap = 0;
im->native.yinvert = 0;
im->native.loose = 0;
im->native.data = n;
im->native.func.data = re;
im->native.func.bind = _native_bind_cb;
im->native.func.unbind = _native_unbind_cb;
im->native.func.free = _native_free_cb;
im->native.func.yinvert = _native_yinvert_cb;
im->native.target = GL_TEXTURE_2D;
im->native.mipmap = 0;
// FIXME: need to implement mapping sub texture regions
// x, y, w, h for possible texture atlasing