Compare commits

...

1 Commits

Author SHA1 Message Date
Dongyeon Kim 1f88f93453 Evas GL: Minimize internal resource creation
Summary:
Evas GL maintains internal resource (XWindow, EGL Window Surface, EGL Context)
per thread to be used for make current when indirect rendering is used.
Currently this internal resource is created regardless of current rendering mode,
and always created when a new Evas GL thread is created by the application.
Internal resource created in a new thread is not freed until evas shuts down
in the main thread, so this causes memory/fd leak.
This can be fixed by creating internal resource only in necessary cases (ie. indirect rendering),
and adding tls resource destructor to be called when thread exits.
2015-10-19 17:10:01 +09:00
6 changed files with 275 additions and 196 deletions

View File

@ -971,6 +971,11 @@ _evgl_glViewport(GLint x, GLint y, GLsizei width, GLsizei height)
glViewport(nc[0], nc[1], nc[2], nc[3]);
}
ctx->viewport_direct[0] = nc[0];
ctx->viewport_direct[1] = nc[1];
ctx->viewport_direct[2] = nc[2];
ctx->viewport_direct[3] = nc[3];
// Keep a copy of the original coordinates
ctx->viewport_coord[0] = x;
ctx->viewport_coord[1] = y;

View File

@ -502,7 +502,7 @@ evgl_api_egl_ext_init(void *getproc, const char *glueexts)
Eina_Strbuf *sb = NULL;
if (_evgl_api_ext_status & EVASGL_API_EGL_EXT_INITIALIZED)
return EINA_TRUE;
return EINA_TRUE;
sb = eina_strbuf_new();

View File

@ -25,6 +25,9 @@ glsym_func_void_ptr glsym_evas_gl_engine_data_get = NULL;
static void _surface_cap_print(int error);
static void _surface_context_list_print();
static void _internal_resources_destroy(void *eng_data, EVGL_Resource *rsc);
static void *_egl_image_create(EVGL_Context *context, int target, void *buffer);
static void _egl_image_destroy(void *image);
static int _evgl_direct_renderable(EVGL_Resource *rsc, EVGL_Surface *sfc);
// NOTE: These constants are "hidden", kinda non public API. They should not
// be used unless you know exactly what you are doing.
@ -37,6 +40,7 @@ extern void (*EXT_FUNC_GLES1(glBindFramebufferOES)) (GLenum target, GLuint frame
extern void (*EXT_FUNC_GLES1(glFramebufferTexture2DOES)) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
extern void (*EXT_FUNC_GLES1(glFramebufferRenderbufferOES)) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
extern GLenum (*EXT_FUNC_GLES1(glCheckFramebufferStatusOES)) (GLenum target);
//---------------------------------------------------------------//
// Internal Resources:
// - Surface and Context used for internal buffer creation
@ -60,6 +64,8 @@ _internal_resources_create(void *eng_data)
ERR("Error allocating EVGL_Resource");
return NULL;
}
rsc->id = eina_thread_self();
rsc->error_state = EVAS_GL_SUCCESS;
// Get display
rsc->display = evgl_engine->funcs->display_get(eng_data);
@ -69,31 +75,6 @@ _internal_resources_create(void *eng_data)
goto error;
}
// Create resource surface
rsc->window = evgl_engine->funcs->native_window_create(eng_data);
if (!rsc->window)
{
ERR("Error creating native window");
goto error;
}
rsc->surface = evgl_engine->funcs->surface_create(eng_data, rsc->window);
if (!rsc->surface)
{
ERR("Error creating native surface");
goto error;
}
// Create a resource context
rsc->context = evgl_engine->funcs->context_create(eng_data, NULL, EVAS_GL_GLES_2_X);
if (!rsc->context)
{
ERR("Internal resource context creation failed.");
goto error;
}
rsc->error_state = EVAS_GL_SUCCESS;
return rsc;
error:
@ -107,17 +88,17 @@ _internal_resources_destroy(void *eng_data, EVGL_Resource *rsc)
if ((!eng_data) || (!rsc)) return;
if (rsc->context)
evgl_engine->funcs->context_destroy(eng_data, rsc->context);
evgl_engine->funcs->context_destroy(eng_data, rsc->context);
if (rsc->surface)
evgl_engine->funcs->surface_destroy(eng_data, rsc->surface);
evgl_engine->funcs->surface_destroy(eng_data, rsc->surface);
if (rsc->window)
evgl_engine->funcs->native_window_destroy(eng_data, rsc->window);
evgl_engine->funcs->native_window_destroy(eng_data, rsc->window);
free(rsc);
}
static int
_internal_resource_make_current(void *eng_data, EVGL_Context *ctx)
_internal_resource_make_current(void *eng_data, EVGL_Surface *sfc, EVGL_Context *ctx)
{
EVGL_Resource *rsc = NULL;
void *surface = NULL;
@ -129,25 +110,94 @@ _internal_resource_make_current(void *eng_data, EVGL_Context *ctx)
{
if (!(rsc = _evgl_tls_resource_create(eng_data)))
{
ERR("Error creting resources in tls.");
ERR("Error creating resources in tls.");
return 0;
}
}
// Set context from input or from resource
if (ctx)
context = ctx->context;
context = ctx->context;
else
context = (void*)rsc->context;
{
if (!rsc->context)
{
// Create a resource context
rsc->context = evgl_engine->funcs->context_create(eng_data, NULL, EVAS_GL_GLES_2_X);
if (!rsc->context)
{
ERR("Internal resource context creation failed.");
return 0;
}
}
// Set the surface to evas surface if it's there
if (rsc->id == evgl_engine->main_tid)
rsc->direct.surface = evgl_engine->funcs->evas_surface_get(eng_data);
context = (void*)rsc->context;
}
if (rsc->direct.surface)
surface = (void*)rsc->direct.surface;
else
surface = (void*)rsc->surface;
if (sfc)
{
if (_evgl_direct_renderable(rsc, sfc)) // Direct rendering
{
// Do Nothing
}
else if (ctx->pixmap_image_supported) // Pixmap surface
{
if (!sfc->indirect_sfc)
{
evgl_engine->funcs->indirect_surface_create(evgl_engine, eng_data, sfc, sfc->cfg, sfc->w, sfc->h);
if (sfc->egl_image) _egl_image_destroy(sfc->egl_image);
sfc->egl_image = _egl_image_create(NULL, EVAS_GL_NATIVE_PIXMAP, sfc->indirect_sfc_native);
}
surface = (void*)sfc->indirect_sfc;
if (!ctx->indirect_context)
ctx->indirect_context = evgl_engine->funcs->gles_context_create(eng_data, ctx, sfc);
context = (void*)ctx->indirect_context;
}
else if (sfc->pbuffer.native_surface) // Pbuffer surface
{
surface = (void*)sfc->pbuffer.native_surface;
}
else // FBO
{
// Do Nothing
}
}
if (!surface)
{
// Set the surface to evas surface if it's there
if (rsc->id == evgl_engine->main_tid)
rsc->direct.surface = evgl_engine->funcs->evas_surface_get(eng_data);
if (rsc->direct.surface)
surface = (void*)rsc->direct.surface;
else
{
if (!rsc->window)
{
// Create resource surface
rsc->window = evgl_engine->funcs->native_window_create(eng_data);
if (!rsc->window)
{
ERR("Error creating native window");
return 0;
}
}
if (!rsc->surface)
{
rsc->surface = evgl_engine->funcs->surface_create(eng_data, rsc->window);
if (!rsc->surface)
{
ERR("Error creating native surface");
return 0;
}
}
surface = (void*)rsc->surface;
}
}
// Do the make current
if (evgl_engine->api_debug_mode)
@ -798,13 +848,14 @@ error:
static int
_surface_cap_init(void *eng_data)
{
int ret = 0;
int max_size = 0;
// Do internal make current
if (!_internal_resource_make_current(eng_data, NULL))
if (!_internal_resource_make_current(eng_data, NULL, NULL))
{
ERR("Error doing an internal resource make current");
return 0;
return ret;
}
// Query the max width and height of the surface
@ -853,13 +904,17 @@ _surface_cap_init(void *eng_data)
{
_surface_cap_print(0);
DBG("Number of supported surface formats: %d", evgl_engine->caps.num_fbo_fmts);
return 1;
ret = 1;
}
else
{
ERR("There are no available surface formats. Error!");
return 0;
}
// Destroy internal resources
_evgl_tls_resource_destroy(eng_data);
return ret;
}
static int
@ -1173,16 +1228,8 @@ _surface_buffers_create(EVGL_Surface *sfc)
static int
_surface_buffers_allocate(void *eng_data, EVGL_Surface *sfc, int w, int h, int mc)
_surface_buffers_allocate(void *eng_data EINA_UNUSED, EVGL_Surface *sfc, int w, int h)
{
// Set the context current with resource context/surface
if (mc)
if (!_internal_resource_make_current(eng_data, NULL))
{
ERR("Error doing an internal resource make current");
return 0;
}
// Create buffers
if (sfc->color_fmt)
{
@ -1438,12 +1485,22 @@ _evgl_tls_resource_get(void)
return NULL;
}
rsc = eina_tls_get(evgl_engine->resource_key);
if (evgl_engine->resource_key)
rsc = eina_tls_get(evgl_engine->resource_key);
if (!rsc)
return NULL;
else
return rsc;
return rsc;
}
static void
_evgl_tls_resource_destroy_cb(void *data)
{
EVGL_Resource *rsc = data;
LKL(evgl_engine->resource_lock);
evgl_engine->resource_list = eina_list_remove(evgl_engine->resource_list, rsc);
LKU(evgl_engine->resource_lock);
_internal_resources_destroy(rsc->current_eng, rsc);
}
EVGL_Resource *
@ -1458,6 +1515,14 @@ _evgl_tls_resource_create(void *eng_data)
return NULL;
}
// Initialize Resource TLS
if (!evgl_engine->resource_key && eina_tls_cb_new(&evgl_engine->resource_key, _evgl_tls_resource_destroy_cb) == EINA_FALSE)
{
ERR("Error creating tls key");
return NULL;
}
DBG("TLS KEY created: %d", evgl_engine->resource_key);
// Create internal resources if it hasn't been created already
if (!(rsc = _internal_resources_create(eng_data)))
{
@ -1470,7 +1535,6 @@ _evgl_tls_resource_create(void *eng_data)
{
// Add to the resource resource list for cleanup
LKL(evgl_engine->resource_lock);
rsc->id = evgl_engine->resource_count++;
evgl_engine->resource_list = eina_list_prepend(evgl_engine->resource_list, rsc);
LKU(evgl_engine->resource_lock);
return rsc;
@ -1488,6 +1552,8 @@ _evgl_tls_resource_destroy(void *eng_data)
{
Eina_List *l;
EVGL_Resource *rsc;
EVGL_Surface *sfc;
EVGL_Context *ctx;
// Check if engine is valid
if (!evgl_engine)
@ -1496,18 +1562,30 @@ _evgl_tls_resource_destroy(void *eng_data)
return;
}
if (!_evgl_tls_resource_get())
EINA_LIST_FOREACH(evgl_engine->surfaces, l, sfc)
{
ERR("Error retrieving resource from TLS");
return;
evgl_surface_destroy(eng_data, sfc);
}
EINA_LIST_FOREACH(evgl_engine->contexts, l, ctx)
{
evgl_context_destroy(eng_data, ctx);
}
LKL(evgl_engine->resource_lock);
eina_list_free(evgl_engine->surfaces);
evgl_engine->surfaces = NULL;
eina_list_free(evgl_engine->contexts);
evgl_engine->contexts = NULL;
EINA_LIST_FOREACH(evgl_engine->resource_list, l, rsc)
{
_internal_resources_destroy(eng_data, rsc);
}
eina_list_free(evgl_engine->resource_list);
evgl_engine->resource_list = NULL;
LKU(evgl_engine->resource_lock);
// Destroy TLS
@ -1691,17 +1769,11 @@ evgl_engine_init(void *eng_data, const EVGL_Interface *efunc)
// Assign functions
evgl_engine->funcs = efunc;
// Initialize Resource TLS
if (eina_tls_new(&evgl_engine->resource_key) == EINA_FALSE)
{
ERR("Error creating tls key");
goto error;
}
DBG("TLS KEY created: %d", evgl_engine->resource_key);
evgl_engine->safe_extensions = eina_hash_string_small_new(NULL);
// Main Thread ID
evgl_engine->main_tid = eina_thread_self();
// Surface Caps
if (!_surface_cap_init(eng_data))
{
@ -1747,9 +1819,6 @@ evgl_engine_init(void *eng_data, const EVGL_Interface *efunc)
if (debug_mode == 1)
evgl_engine->api_debug_mode = 1;
// Maint Thread ID (get tid not available in eina thread yet)
evgl_engine->main_tid = 0;
return evgl_engine;
error:
@ -1783,15 +1852,19 @@ evgl_engine_shutdown(void *eng_data)
eina_hash_free(evgl_engine->safe_extensions);
evgl_engine->safe_extensions = NULL;
// Log
eina_log_domain_unregister(_evas_gl_log_dom);
_evas_gl_log_dom = -1;
if (gles1_funcs) free(gles1_funcs);
if (gles2_funcs) free(gles2_funcs);
if (gles3_funcs) free(gles3_funcs);
// Destroy internal resources
_evgl_tls_resource_destroy(eng_data);
LKD(evgl_engine->resource_lock);
// Log
eina_log_domain_unregister(_evas_gl_log_dom);
_evas_gl_log_dom = -1;
// Free engine
free(evgl_engine);
evgl_engine = NULL;
@ -1982,43 +2055,41 @@ evgl_surface_destroy(void *eng_data, EVGL_Surface *sfc)
return 0;
}
// Retrieve the resource object
if (!(rsc = _evgl_tls_resource_get()))
{
ERR("Error retrieving resource from TLS");
return 0;
}
if ((dbg = evgl_engine->api_debug_mode))
DBG("Destroying surface sfc %p (eng %p)", sfc, eng_data);
if ((rsc->current_ctx) && (rsc->current_ctx->current_sfc == sfc) )
// Retrieve the resource object
rsc = _evgl_tls_resource_get();
if (rsc && rsc->current_ctx)
{
if (evgl_engine->api_debug_mode)
// Make current to current context to destroy surface buffers
if (!_internal_resource_make_current(eng_data, sfc, rsc->current_ctx))
{
ERR("The context is still current before it's being destroyed. "
"Calling make_current(NULL, NULL)");
ERR("Error doing an internal resource make current");
return 0;
}
else
// Destroy created buffers
if (!_surface_buffers_destroy(sfc))
{
WRN("The context is still current before it's being destroyed. "
"Calling make_current(NULL, NULL)");
ERR("Error deleting surface resources.");
return 0;
}
evgl_make_current(eng_data, NULL, NULL);
}
// Make current to current context to destroy surface buffers
if (!_internal_resource_make_current(eng_data, rsc->current_ctx))
{
ERR("Error doing an internal resource make current");
return 0;
}
// Destroy created buffers
if (!_surface_buffers_destroy(sfc))
{
ERR("Error deleting surface resources.");
return 0;
if (rsc->current_ctx->current_sfc == sfc)
{
if (evgl_engine->api_debug_mode)
{
ERR("The surface is still current before it's being destroyed.");
ERR("Doing make_current(NULL, NULL)");
}
else
{
WRN("The surface is still current before it's being destroyed.");
WRN("Doing make_current(NULL, NULL)");
}
evgl_make_current(eng_data, NULL, NULL);
}
}
// Destroy indirect surface
@ -2065,8 +2136,12 @@ evgl_surface_destroy(void *eng_data, EVGL_Surface *sfc)
}
}
if (sfc->current_ctx && sfc->current_ctx->current_sfc == sfc)
sfc->current_ctx->current_sfc = NULL;
if (dbg) DBG("Calling make_current(NULL, NULL)");
if (!evgl_engine->funcs->make_current(eng_data, NULL, NULL, 0))
{
ERR("Error doing make_current(NULL, NULL).");
return 0;
}
// Remove it from the list
LKL(evgl_engine->resource_lock);
@ -2088,7 +2163,6 @@ evgl_context_create(void *eng_data, EVGL_Context *share_ctx,
void *(*engine_data_get)(void *))
{
EVGL_Context *ctx = NULL;
EVGL_Resource *rsc = NULL;
// A little bit ugly. But it works even when dlsym(DEFAULT) doesn't work.
glsym_evas_gl_native_context_get = native_context_get;
@ -2112,12 +2186,6 @@ evgl_context_create(void *eng_data, EVGL_Context *share_ctx,
if (evgl_engine->api_debug_mode)
DBG("Creating context GLESv%d (eng = %p, shctx = %p)", version, eng_data, share_ctx);
if (!(rsc = _evgl_tls_resource_get()))
{
ERR("Error creating resources in tls.");
return NULL;
}
// Allocate context object
ctx = calloc(1, sizeof(EVGL_Context));
if (!ctx)
@ -2200,16 +2268,31 @@ evgl_context_destroy(void *eng_data, EVGL_Context *ctx)
if (ctx->current_sfc && (ctx->current_sfc->current_ctx == ctx))
ctx->current_sfc->current_ctx = NULL;
// Set the context current with resource context/surface
if (!_internal_resource_make_current(eng_data, rsc->current_ctx))
{
ERR("Error doing an internal resource make current");
return 0;
}
// Delete the FBO
if (ctx->surface_fbo)
glDeleteFramebuffers(1, &ctx->surface_fbo);
{
// Set the context current with resource context/surface
if (!_internal_resource_make_current(eng_data, ctx->current_sfc, ctx))
{
ERR("Error doing an internal resource make current");
return 0;
}
glDeleteFramebuffers(1, &ctx->surface_fbo);
}
// Retrieve the resource object
rsc = _evgl_tls_resource_get();
if (rsc && rsc->current_ctx == ctx)
{
// Unset the currrent context
if (dbg) DBG("Calling make_current(NULL, NULL)");
if (!evgl_engine->funcs->make_current(eng_data, NULL, NULL, 0))
{
ERR("Error doing make_current(NULL, NULL).");
return 0;
}
rsc->current_ctx = NULL;
}
// Destroy indirect rendering context
if (ctx->indirect_context &&
@ -2245,23 +2328,18 @@ evgl_make_current(void *eng_data, EVGL_Surface *sfc, EVGL_Context *ctx)
EVGL_Resource *rsc;
int curr_fbo = 0;
// Check the input validity. If either sfc or ctx is NULL, it's also error.
if ( (!evgl_engine) ||
(sfc && (!ctx)) )
// Check the input validity. If either sfc is valid but ctx is NULL, it's also error.
// sfc can be NULL as evas gl supports surfaceless make current
if ( (!evgl_engine) || ((sfc) && (!ctx)) )
{
ERR("Invalid Inputs. Engine: %p Surface: %p Context: %p!", evgl_engine, sfc, ctx);
if(!sfc) evas_gl_common_error_set(eng_data, EVAS_GL_BAD_SURFACE);
if(!ctx) evas_gl_common_error_set(eng_data, EVAS_GL_BAD_CONTEXT);
ERR("Invalid Input: Engine: %p, Surface: %p, Context: %p", evgl_engine, sfc, ctx);
if (!evgl_engine) evas_gl_common_error_set(eng_data, EVAS_GL_NOT_INITIALIZED);
if (!ctx) evas_gl_common_error_set(eng_data, EVAS_GL_BAD_CONTEXT);
return 0;
}
// Get TLS Resources
rsc = _evgl_tls_resource_get();
// Abuse debug mode - extra tracing for make_current and friends
dbg = evgl_engine->api_debug_mode;
if (dbg) DBG("(eng = %p, sfc = %p, ctx = %p), rsc = %p", eng_data, sfc, ctx, rsc);
if (!rsc)
{
DBG("Creating new TLS for this thread: %lu", (unsigned long)eina_thread_self());
@ -2269,13 +2347,17 @@ evgl_make_current(void *eng_data, EVGL_Surface *sfc, EVGL_Context *ctx)
if (!rsc) return 0;
}
// Abuse debug mode - extra tracing for make_current and friends
dbg = evgl_engine->api_debug_mode;
if (dbg) DBG("(eng = %p, sfc = %p, ctx = %p), rsc = %p", eng_data, sfc, ctx, rsc);
// Unset
if ((!sfc) && (!ctx))
{
if (rsc->current_ctx)
{
if (rsc->direct.partial.enabled)
evgl_direct_partial_render_end();
evgl_direct_partial_render_end();
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &curr_fbo);
if ((rsc->current_ctx->surface_fbo == (GLuint) curr_fbo) ||
@ -2313,7 +2395,7 @@ evgl_make_current(void *eng_data, EVGL_Surface *sfc, EVGL_Context *ctx)
}
// Do a make current
if (!_internal_resource_make_current(eng_data, ctx))
if (!_internal_resource_make_current(eng_data, sfc, ctx))
{
ERR("Error doing a make current with internal surface. Context: %p", ctx);
evas_gl_common_error_set(eng_data, EVAS_GL_BAD_CONTEXT);
@ -2326,7 +2408,7 @@ evgl_make_current(void *eng_data, EVGL_Surface *sfc, EVGL_Context *ctx)
// to use fbo & egl image passing to evas
if (!ctx->extension_checked)
{
if (!evgl_api_get(eng_data, ctx->version))
if (!evgl_api_get(eng_data, ctx->version, EINA_FALSE))
{
ERR("Unable to get the list of GL APIs for version %d", ctx->version);
evas_gl_common_error_set(eng_data, EVAS_GL_NOT_INITIALIZED);
@ -2371,7 +2453,7 @@ evgl_make_current(void *eng_data, EVGL_Surface *sfc, EVGL_Context *ctx)
// Destroy created resources
if (sfc->buffers_allocated)
{
if (!_surface_buffers_allocate(eng_data, sfc, 0, 0, 0))
if (!_surface_buffers_allocate(eng_data, sfc, 0, 0))
{
ERR("Unable to destroy surface buffers!");
evas_gl_common_error_set(eng_data, EVAS_GL_BAD_ALLOC);
@ -2392,7 +2474,7 @@ evgl_make_current(void *eng_data, EVGL_Surface *sfc, EVGL_Context *ctx)
if (!sfc->buffers_allocated)
{
if (dbg) DBG("Allocating buffers for sfc %p", sfc);
if (!_surface_buffers_allocate(eng_data, sfc, sfc->w, sfc->h, 0))
if (!_surface_buffers_allocate(eng_data, sfc, sfc->w, sfc->h))
{
ERR("Unable Create Specificed Surfaces. Unsupported format!");
evas_gl_common_error_set(eng_data, EVAS_GL_BAD_ALLOC);
@ -2407,7 +2489,7 @@ evgl_make_current(void *eng_data, EVGL_Surface *sfc, EVGL_Context *ctx)
{
if (!sfc->buffers_allocated)
{
if (!_surface_buffers_allocate(eng_data, sfc, sfc->w, sfc->h, 0))
if (!_surface_buffers_allocate(eng_data, sfc, sfc->w, sfc->h))
{
ERR("Unable Create Allocate Memory for Surface.");
evas_gl_common_error_set(eng_data, EVAS_GL_BAD_ALLOC);
@ -2436,24 +2518,6 @@ 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->indirect_context);
if (!evgl_engine->funcs->make_current(eng_data, sfc->indirect_sfc,
ctx->indirect_context, EINA_TRUE))
{
ERR("Failed to make current with indirect surface.");
return 0;
}
// Transition from direct rendering to indirect rendering
if (rsc->direct.rendered)
{
@ -2474,16 +2538,15 @@ evgl_make_current(void *eng_data, EVGL_Surface *sfc, EVGL_Context *ctx)
use_extension = EINA_TRUE;
#endif
// Normal FBO Rendering
// Create FBO if it hasn't been created
if (!ctx->surface_fbo)
_framebuffer_create(&ctx->surface_fbo, use_extension);
// Direct Rendering
if (_evgl_direct_renderable(rsc, sfc))
{
if (dbg) DBG("sfc %p is direct renderable.", sfc);
// Create FBO if it hasn't been created
if (!ctx->surface_fbo)
_framebuffer_create(&ctx->surface_fbo, use_extension);
// This is to transition from FBO rendering to direct rendering
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &curr_fbo);
if (ctx->surface_fbo == (GLuint)curr_fbo)
@ -2527,10 +2590,6 @@ evgl_make_current(void *eng_data, EVGL_Surface *sfc, EVGL_Context *ctx)
ERR("Could not detach current FBO");
}
if (dbg) DBG("Calling make_current(%p, %p)", sfc->pbuffer.native_surface, ctx->context);
evgl_engine->funcs->make_current(eng_data, sfc->pbuffer.native_surface,
ctx->context, EINA_TRUE);
// Bind to the previously bound buffer (may be 0)
if (ctx->current_fbo)
_framebuffer_bind(ctx->current_fbo, use_extension);
@ -2541,6 +2600,10 @@ evgl_make_current(void *eng_data, EVGL_Surface *sfc, EVGL_Context *ctx)
{
if (dbg) DBG("Surface sfc %p is a normal surface.", sfc);
// Create FBO if it hasn't been created
if (!ctx->surface_fbo)
_framebuffer_create(&ctx->surface_fbo, use_extension);
// Attach fbo and the buffers
if ((rsc->current_ctx != ctx) || (ctx->current_sfc != sfc) || (rsc->direct.rendered))
{
@ -2852,8 +2915,28 @@ evgl_get_pixels_post(void)
}
Evas_GL_API *
evgl_api_get(void *eng_data, Evas_GL_Context_Version version)
evgl_api_get(void *eng_data, Evas_GL_Context_Version version, Eina_Bool alloc_only)
{
Evas_GL_API *api = NULL;
if (version == EVAS_GL_GLES_2_X)
{
if (!gles2_funcs) gles2_funcs = calloc(1, EVAS_GL_API_STRUCT_SIZE);
api = gles2_funcs;
}
else if (version == EVAS_GL_GLES_1_X)
{
if (!gles1_funcs) gles1_funcs = calloc(1, EVAS_GL_API_STRUCT_SIZE);
api = gles1_funcs;
}
else if (version == EVAS_GL_GLES_3_X)
{
if (!gles3_funcs) gles3_funcs = calloc(1, EVAS_GL_API_STRUCT_SIZE);
api = gles3_funcs;
}
else return NULL;
if (alloc_only) return api;
#ifdef GL_GLES
if (!evgl_api_egl_ext_init(evgl_engine->funcs->proc_address_get, evgl_engine->funcs->ext_string_get(eng_data)))
{
@ -2862,32 +2945,21 @@ evgl_api_get(void *eng_data, Evas_GL_Context_Version version)
#endif
if (version == EVAS_GL_GLES_2_X)
{
if (!gles2_funcs) gles2_funcs = calloc(1, EVAS_GL_API_STRUCT_SIZE);
_evgl_api_gles2_get(gles2_funcs, evgl_engine->api_debug_mode);
evgl_api_gles2_ext_get(gles2_funcs, evgl_engine->funcs->proc_address_get, evgl_engine->funcs->ext_string_get(eng_data));
return gles2_funcs;
_evgl_api_gles2_get(api, evgl_engine->api_debug_mode);
evgl_api_gles2_ext_get(api, evgl_engine->funcs->proc_address_get, evgl_engine->funcs->ext_string_get(eng_data));
}
else if (version == EVAS_GL_GLES_1_X)
{
if (!gles1_funcs) gles1_funcs = calloc(1, EVAS_GL_API_STRUCT_SIZE);
_evgl_api_gles1_get(gles1_funcs, evgl_engine->api_debug_mode);
evgl_api_gles1_ext_get(gles1_funcs, evgl_engine->funcs->proc_address_get, evgl_engine->funcs->ext_string_get(eng_data));
return gles1_funcs;
_evgl_api_gles1_get(api, evgl_engine->api_debug_mode);
evgl_api_gles1_ext_get(api, evgl_engine->funcs->proc_address_get, evgl_engine->funcs->ext_string_get(eng_data));
}
else if (version == EVAS_GL_GLES_3_X)
{
if (!gles3_funcs) gles3_funcs = calloc(1, EVAS_GL_API_STRUCT_SIZE);
_evgl_api_gles3_get(gles3_funcs, evgl_engine->api_debug_mode);
evgl_api_gles3_ext_get(gles3_funcs, evgl_engine->funcs->proc_address_get, evgl_engine->funcs->ext_string_get(eng_data));
return gles3_funcs;
_evgl_api_gles3_get(api, evgl_engine->api_debug_mode);
evgl_api_gles3_ext_get(api, evgl_engine->funcs->proc_address_get, evgl_engine->funcs->ext_string_get(eng_data));
}
else return NULL;
return api;
}

View File

@ -64,7 +64,7 @@ int evgl_make_current(void *eng_data, EVGL_Surface *sfc, EVGL_Context *
const char *evgl_string_query(int name);
int evgl_native_surface_get(EVGL_Surface *sfc, Evas_Native_Surface *ns);
Evas_GL_API *evgl_api_get(void *eng_data, Evas_GL_Context_Version version);
Evas_GL_API *evgl_api_get(void *eng_data, Evas_GL_Context_Version version, Eina_Bool alloc_only);
void evgl_safe_extension_add(const char *name, void *funcptr);
Eina_Bool evgl_safe_extension_get(const char *name, void **pfuncptr);

View File

@ -254,7 +254,7 @@ struct _EVGL_Cap
struct _EVGL_Resource
{
int id;
Eina_Thread id;
EVGLNative_Display display;
EVGLNative_Context context;
@ -317,8 +317,7 @@ struct _EVGL_Engine
LK(resource_lock);
Eina_TLS resource_key;
Eina_List *resource_list;
int resource_count;
int main_tid;
Eina_Thread main_tid;
// Add more debug logs (DBG levels 4 and 6)
int api_debug_mode;

View File

@ -63,7 +63,8 @@ _context_restore(void)
{
if (rsc->id == evgl_engine->main_tid)
{
evgl_make_current(rsc->stored.data, rsc->stored.surface, rsc->stored.context);
if (rsc->stored.data)
evgl_make_current(rsc->stored.data, rsc->stored.surface, rsc->stored.context);
_need_context_restore = EINA_FALSE;
}
}
@ -1503,14 +1504,13 @@ eng_gl_make_current(void *data, void *surface, void *context)
Render_Engine_GL_Generic *re = data;
EVGL_Surface *sfc = (EVGL_Surface *)surface;
EVGL_Context *ctx = (EVGL_Context *)context;
int ret = 0;
// TODO: Add check for main thread before flush
EVGLINIT(data, 0);
if (ctx)
if ((sfc) && (ctx))
{
Evas_Engine_GL_Context *gl_context;
CONTEXT_STORE(data, surface, context);
gl_context = re->window_gl_context_get(re->software.ob);
if ((gl_context->havestuff) ||
@ -1523,7 +1523,10 @@ eng_gl_make_current(void *data, void *surface, void *context)
}
}
return evgl_make_current(data, sfc, ctx);
ret = evgl_make_current(data, sfc, ctx);
CONTEXT_STORE(data, surface, context);
return ret;
}
static void *
@ -1606,7 +1609,7 @@ eng_gl_api_get(void *data, int version)
ERR("Version not supported!");
return NULL;
}
ret = evgl_api_get(data, version);
ret = evgl_api_get(data, version, EINA_TRUE);
//Disable GLES3 support if symbols not present
if ((!ret) && (version == EVAS_GL_GLES_3_X))