forked from enlightenment/efl
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.
This commit is contained in:
parent
2eaf33d9cf
commit
1f88f93453
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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))
|
||||
|
|
Loading…
Reference in New Issue