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]); 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 // Keep a copy of the original coordinates
ctx->viewport_coord[0] = x; ctx->viewport_coord[0] = x;
ctx->viewport_coord[1] = y; 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; Eina_Strbuf *sb = NULL;
if (_evgl_api_ext_status & EVASGL_API_EGL_EXT_INITIALIZED) if (_evgl_api_ext_status & EVASGL_API_EGL_EXT_INITIALIZED)
return EINA_TRUE; return EINA_TRUE;
sb = eina_strbuf_new(); 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_cap_print(int error);
static void _surface_context_list_print(); static void _surface_context_list_print();
static void _internal_resources_destroy(void *eng_data, EVGL_Resource *rsc); 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 // NOTE: These constants are "hidden", kinda non public API. They should not
// be used unless you know exactly what you are doing. // 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(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 void (*EXT_FUNC_GLES1(glFramebufferRenderbufferOES)) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
extern GLenum (*EXT_FUNC_GLES1(glCheckFramebufferStatusOES)) (GLenum target); extern GLenum (*EXT_FUNC_GLES1(glCheckFramebufferStatusOES)) (GLenum target);
//---------------------------------------------------------------// //---------------------------------------------------------------//
// Internal Resources: // Internal Resources:
// - Surface and Context used for internal buffer creation // - Surface and Context used for internal buffer creation
@ -60,6 +64,8 @@ _internal_resources_create(void *eng_data)
ERR("Error allocating EVGL_Resource"); ERR("Error allocating EVGL_Resource");
return NULL; return NULL;
} }
rsc->id = eina_thread_self();
rsc->error_state = EVAS_GL_SUCCESS;
// Get display // Get display
rsc->display = evgl_engine->funcs->display_get(eng_data); rsc->display = evgl_engine->funcs->display_get(eng_data);
@ -69,31 +75,6 @@ _internal_resources_create(void *eng_data)
goto error; 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; return rsc;
error: error:
@ -107,17 +88,17 @@ _internal_resources_destroy(void *eng_data, EVGL_Resource *rsc)
if ((!eng_data) || (!rsc)) return; if ((!eng_data) || (!rsc)) return;
if (rsc->context) if (rsc->context)
evgl_engine->funcs->context_destroy(eng_data, rsc->context); evgl_engine->funcs->context_destroy(eng_data, rsc->context);
if (rsc->surface) if (rsc->surface)
evgl_engine->funcs->surface_destroy(eng_data, rsc->surface); evgl_engine->funcs->surface_destroy(eng_data, rsc->surface);
if (rsc->window) 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); free(rsc);
} }
static int 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; EVGL_Resource *rsc = NULL;
void *surface = 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))) if (!(rsc = _evgl_tls_resource_create(eng_data)))
{ {
ERR("Error creting resources in tls."); ERR("Error creating resources in tls.");
return 0; return 0;
} }
} }
// Set context from input or from resource // Set context from input or from resource
if (ctx) if (ctx)
context = ctx->context; context = ctx->context;
else 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 context = (void*)rsc->context;
if (rsc->id == evgl_engine->main_tid) }
rsc->direct.surface = evgl_engine->funcs->evas_surface_get(eng_data);
if (rsc->direct.surface) if (sfc)
surface = (void*)rsc->direct.surface; {
else if (_evgl_direct_renderable(rsc, sfc)) // Direct rendering
surface = (void*)rsc->surface; {
// 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 // Do the make current
if (evgl_engine->api_debug_mode) if (evgl_engine->api_debug_mode)
@ -798,13 +848,14 @@ error:
static int static int
_surface_cap_init(void *eng_data) _surface_cap_init(void *eng_data)
{ {
int ret = 0;
int max_size = 0; int max_size = 0;
// Do internal make current // 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"); ERR("Error doing an internal resource make current");
return 0; return ret;
} }
// Query the max width and height of the surface // Query the max width and height of the surface
@ -853,13 +904,17 @@ _surface_cap_init(void *eng_data)
{ {
_surface_cap_print(0); _surface_cap_print(0);
DBG("Number of supported surface formats: %d", evgl_engine->caps.num_fbo_fmts); DBG("Number of supported surface formats: %d", evgl_engine->caps.num_fbo_fmts);
return 1; ret = 1;
} }
else else
{ {
ERR("There are no available surface formats. Error!"); ERR("There are no available surface formats. Error!");
return 0;
} }
// Destroy internal resources
_evgl_tls_resource_destroy(eng_data);
return ret;
} }
static int static int
@ -1173,16 +1228,8 @@ _surface_buffers_create(EVGL_Surface *sfc)
static int 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 // Create buffers
if (sfc->color_fmt) if (sfc->color_fmt)
{ {
@ -1438,12 +1485,22 @@ _evgl_tls_resource_get(void)
return NULL; 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 rsc;
return NULL; }
else
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 * EVGL_Resource *
@ -1458,6 +1515,14 @@ _evgl_tls_resource_create(void *eng_data)
return NULL; 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 // Create internal resources if it hasn't been created already
if (!(rsc = _internal_resources_create(eng_data))) 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 // Add to the resource resource list for cleanup
LKL(evgl_engine->resource_lock); LKL(evgl_engine->resource_lock);
rsc->id = evgl_engine->resource_count++;
evgl_engine->resource_list = eina_list_prepend(evgl_engine->resource_list, rsc); evgl_engine->resource_list = eina_list_prepend(evgl_engine->resource_list, rsc);
LKU(evgl_engine->resource_lock); LKU(evgl_engine->resource_lock);
return rsc; return rsc;
@ -1488,6 +1552,8 @@ _evgl_tls_resource_destroy(void *eng_data)
{ {
Eina_List *l; Eina_List *l;
EVGL_Resource *rsc; EVGL_Resource *rsc;
EVGL_Surface *sfc;
EVGL_Context *ctx;
// Check if engine is valid // Check if engine is valid
if (!evgl_engine) if (!evgl_engine)
@ -1496,18 +1562,30 @@ _evgl_tls_resource_destroy(void *eng_data)
return; return;
} }
if (!_evgl_tls_resource_get()) EINA_LIST_FOREACH(evgl_engine->surfaces, l, sfc)
{ {
ERR("Error retrieving resource from TLS"); evgl_surface_destroy(eng_data, sfc);
return; }
EINA_LIST_FOREACH(evgl_engine->contexts, l, ctx)
{
evgl_context_destroy(eng_data, ctx);
} }
LKL(evgl_engine->resource_lock); 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) EINA_LIST_FOREACH(evgl_engine->resource_list, l, rsc)
{ {
_internal_resources_destroy(eng_data, rsc); _internal_resources_destroy(eng_data, rsc);
} }
eina_list_free(evgl_engine->resource_list); eina_list_free(evgl_engine->resource_list);
evgl_engine->resource_list = NULL;
LKU(evgl_engine->resource_lock); LKU(evgl_engine->resource_lock);
// Destroy TLS // Destroy TLS
@ -1691,17 +1769,11 @@ evgl_engine_init(void *eng_data, const EVGL_Interface *efunc)
// Assign functions // Assign functions
evgl_engine->funcs = efunc; 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); evgl_engine->safe_extensions = eina_hash_string_small_new(NULL);
// Main Thread ID
evgl_engine->main_tid = eina_thread_self();
// Surface Caps // Surface Caps
if (!_surface_cap_init(eng_data)) if (!_surface_cap_init(eng_data))
{ {
@ -1747,9 +1819,6 @@ evgl_engine_init(void *eng_data, const EVGL_Interface *efunc)
if (debug_mode == 1) if (debug_mode == 1)
evgl_engine->api_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; return evgl_engine;
error: error:
@ -1783,15 +1852,19 @@ evgl_engine_shutdown(void *eng_data)
eina_hash_free(evgl_engine->safe_extensions); eina_hash_free(evgl_engine->safe_extensions);
evgl_engine->safe_extensions = NULL; evgl_engine->safe_extensions = NULL;
// Log if (gles1_funcs) free(gles1_funcs);
eina_log_domain_unregister(_evas_gl_log_dom); if (gles2_funcs) free(gles2_funcs);
_evas_gl_log_dom = -1; if (gles3_funcs) free(gles3_funcs);
// Destroy internal resources // Destroy internal resources
_evgl_tls_resource_destroy(eng_data); _evgl_tls_resource_destroy(eng_data);
LKD(evgl_engine->resource_lock); LKD(evgl_engine->resource_lock);
// Log
eina_log_domain_unregister(_evas_gl_log_dom);
_evas_gl_log_dom = -1;
// Free engine // Free engine
free(evgl_engine); free(evgl_engine);
evgl_engine = NULL; evgl_engine = NULL;
@ -1982,43 +2055,41 @@ evgl_surface_destroy(void *eng_data, EVGL_Surface *sfc)
return 0; 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)) if ((dbg = evgl_engine->api_debug_mode))
DBG("Destroying surface sfc %p (eng %p)", sfc, eng_data); 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. " ERR("Error doing an internal resource make current");
"Calling make_current(NULL, NULL)"); return 0;
} }
else
// Destroy created buffers
if (!_surface_buffers_destroy(sfc))
{ {
WRN("The context is still current before it's being destroyed. " ERR("Error deleting surface resources.");
"Calling make_current(NULL, NULL)"); return 0;
} }
evgl_make_current(eng_data, NULL, NULL);
}
// Make current to current context to destroy surface buffers if (rsc->current_ctx->current_sfc == sfc)
if (!_internal_resource_make_current(eng_data, rsc->current_ctx)) {
{ if (evgl_engine->api_debug_mode)
ERR("Error doing an internal resource make current"); {
return 0; ERR("The surface is still current before it's being destroyed.");
} ERR("Doing make_current(NULL, NULL)");
}
// Destroy created buffers else
if (!_surface_buffers_destroy(sfc)) {
{ WRN("The surface is still current before it's being destroyed.");
ERR("Error deleting surface resources."); WRN("Doing make_current(NULL, NULL)");
return 0; }
evgl_make_current(eng_data, NULL, NULL);
}
} }
// Destroy indirect surface // 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) if (dbg) DBG("Calling make_current(NULL, NULL)");
sfc->current_ctx->current_sfc = 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 // Remove it from the list
LKL(evgl_engine->resource_lock); LKL(evgl_engine->resource_lock);
@ -2088,7 +2163,6 @@ evgl_context_create(void *eng_data, EVGL_Context *share_ctx,
void *(*engine_data_get)(void *)) void *(*engine_data_get)(void *))
{ {
EVGL_Context *ctx = NULL; EVGL_Context *ctx = NULL;
EVGL_Resource *rsc = NULL;
// A little bit ugly. But it works even when dlsym(DEFAULT) doesn't work. // A little bit ugly. But it works even when dlsym(DEFAULT) doesn't work.
glsym_evas_gl_native_context_get = native_context_get; 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) if (evgl_engine->api_debug_mode)
DBG("Creating context GLESv%d (eng = %p, shctx = %p)", version, eng_data, share_ctx); 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 // Allocate context object
ctx = calloc(1, sizeof(EVGL_Context)); ctx = calloc(1, sizeof(EVGL_Context));
if (!ctx) 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)) if (ctx->current_sfc && (ctx->current_sfc->current_ctx == ctx))
ctx->current_sfc->current_ctx = NULL; 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 // Delete the FBO
if (ctx->surface_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 // Destroy indirect rendering context
if (ctx->indirect_context && if (ctx->indirect_context &&
@ -2245,23 +2328,18 @@ evgl_make_current(void *eng_data, EVGL_Surface *sfc, EVGL_Context *ctx)
EVGL_Resource *rsc; EVGL_Resource *rsc;
int curr_fbo = 0; int curr_fbo = 0;
// Check the input validity. If either sfc or ctx is NULL, it's also error. // Check the input validity. If either sfc is valid but ctx is NULL, it's also error.
if ( (!evgl_engine) || // sfc can be NULL as evas gl supports surfaceless make current
(sfc && (!ctx)) ) if ( (!evgl_engine) || ((sfc) && (!ctx)) )
{ {
ERR("Invalid Inputs. Engine: %p Surface: %p Context: %p!", evgl_engine, sfc, ctx); ERR("Invalid Input: Engine: %p, Surface: %p, Context: %p", evgl_engine, sfc, ctx);
if(!sfc) evas_gl_common_error_set(eng_data, EVAS_GL_BAD_SURFACE); 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); if (!ctx) evas_gl_common_error_set(eng_data, EVAS_GL_BAD_CONTEXT);
return 0; return 0;
} }
// Get TLS Resources // Get TLS Resources
rsc = _evgl_tls_resource_get(); 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) if (!rsc)
{ {
DBG("Creating new TLS for this thread: %lu", (unsigned long)eina_thread_self()); 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; 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 // Unset
if ((!sfc) && (!ctx)) if ((!sfc) && (!ctx))
{ {
if (rsc->current_ctx) if (rsc->current_ctx)
{ {
if (rsc->direct.partial.enabled) if (rsc->direct.partial.enabled)
evgl_direct_partial_render_end(); evgl_direct_partial_render_end();
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &curr_fbo); glGetIntegerv(GL_FRAMEBUFFER_BINDING, &curr_fbo);
if ((rsc->current_ctx->surface_fbo == (GLuint) 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 // 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); ERR("Error doing a make current with internal surface. Context: %p", ctx);
evas_gl_common_error_set(eng_data, EVAS_GL_BAD_CONTEXT); 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 // to use fbo & egl image passing to evas
if (!ctx->extension_checked) 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); 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); 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 // Destroy created resources
if (sfc->buffers_allocated) 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!"); ERR("Unable to destroy surface buffers!");
evas_gl_common_error_set(eng_data, EVAS_GL_BAD_ALLOC); 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 (!sfc->buffers_allocated)
{ {
if (dbg) DBG("Allocating buffers for sfc %p", sfc); 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!"); ERR("Unable Create Specificed Surfaces. Unsupported format!");
evas_gl_common_error_set(eng_data, EVAS_GL_BAD_ALLOC); 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 (!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."); ERR("Unable Create Allocate Memory for Surface.");
evas_gl_common_error_set(eng_data, EVAS_GL_BAD_ALLOC); 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 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 // Transition from direct rendering to indirect rendering
if (rsc->direct.rendered) if (rsc->direct.rendered)
{ {
@ -2474,16 +2538,15 @@ evgl_make_current(void *eng_data, EVGL_Surface *sfc, EVGL_Context *ctx)
use_extension = EINA_TRUE; use_extension = EINA_TRUE;
#endif #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 // Direct Rendering
if (_evgl_direct_renderable(rsc, sfc)) if (_evgl_direct_renderable(rsc, sfc))
{ {
if (dbg) DBG("sfc %p is direct renderable.", 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 // This is to transition from FBO rendering to direct rendering
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &curr_fbo); glGetIntegerv(GL_FRAMEBUFFER_BINDING, &curr_fbo);
if (ctx->surface_fbo == (GLuint)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"); 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) // Bind to the previously bound buffer (may be 0)
if (ctx->current_fbo) if (ctx->current_fbo)
_framebuffer_bind(ctx->current_fbo, use_extension); _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); 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 // Attach fbo and the buffers
if ((rsc->current_ctx != ctx) || (ctx->current_sfc != sfc) || (rsc->direct.rendered)) if ((rsc->current_ctx != ctx) || (ctx->current_sfc != sfc) || (rsc->direct.rendered))
{ {
@ -2852,8 +2915,28 @@ evgl_get_pixels_post(void)
} }
Evas_GL_API * 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 #ifdef GL_GLES
if (!evgl_api_egl_ext_init(evgl_engine->funcs->proc_address_get, evgl_engine->funcs->ext_string_get(eng_data))) 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 #endif
if (version == EVAS_GL_GLES_2_X) if (version == EVAS_GL_GLES_2_X)
{ {
if (!gles2_funcs) gles2_funcs = calloc(1, EVAS_GL_API_STRUCT_SIZE); _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));
_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;
} }
else if (version == EVAS_GL_GLES_1_X) else if (version == EVAS_GL_GLES_1_X)
{ {
if (!gles1_funcs) gles1_funcs = calloc(1, EVAS_GL_API_STRUCT_SIZE); _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));
_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;
} }
else if (version == EVAS_GL_GLES_3_X) else if (version == EVAS_GL_GLES_3_X)
{ {
if (!gles3_funcs) gles3_funcs = calloc(1, EVAS_GL_API_STRUCT_SIZE); _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));
_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;
} }
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); const char *evgl_string_query(int name);
int evgl_native_surface_get(EVGL_Surface *sfc, Evas_Native_Surface *ns); 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); void evgl_safe_extension_add(const char *name, void *funcptr);
Eina_Bool evgl_safe_extension_get(const char *name, void **pfuncptr); Eina_Bool evgl_safe_extension_get(const char *name, void **pfuncptr);

View File

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

View File

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