Add fpgl-call error handling when makecurrent=null (instead of assertion)
[platform/core/uifw/coregl.git] / src / coregl.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <dlfcn.h>
4 #include <string.h>
5 #include "coregl_internal.h"
6
7 CoreGL_Opt_Flag         api_opt = COREGL_UNKNOWN_PATH;
8
9 Mutex                   ctx_list_access_mutex = MUTEX_INITIALIZER;
10
11 void                   *egl_lib_handle;
12 void                   *gl_lib_handle;
13
14 GLContext_List         *glctx_list = NULL;
15
16 int                 trace_api_flag = 0;
17 int                 trace_ctx_flag = 0;
18 int                 trace_ctx_force_flag = 0;
19 int                 trace_state_flag = 0;
20 int                 debug_nofp = 0;
21
22 // Symbol definition for real
23 #define _COREGL_SYMBOL(IS_EXTENSION, RET_TYPE, FUNC_NAME, PARAM_LIST)     RET_TYPE (*_sym_##FUNC_NAME) PARAM_LIST;
24 #include "headers/sym.h"
25 #undef _COREGL_SYMBOL
26
27 const char *
28 get_env_setting(const char *name)
29 {
30         char *fp_env = NULL;
31         static char *fp_default = "\0";
32         fp_env = getenv(name);
33         if (fp_env == NULL) fp_env = fp_default;
34         return fp_env;
35 }
36
37 int
38 add_context_state_to_list(const void *option, const int option_len, GLContextState *cstate, Mutex *mtx)
39 {
40         int ret = 0;
41         int tid = 0;
42         GLContext_List *current = NULL;
43         GLContext_List *newitm = NULL;
44
45         if (mtx != NULL) AST(mutex_lock(mtx) == 1);
46
47         AST(cstate != NULL);
48
49         tid = get_current_thread();
50
51         current = glctx_list;
52         while (current != NULL)
53         {
54                 if (current->option_len == option_len &&
55                     memcmp(current->option, option, option_len) == 0 &&
56                     current->thread_id == tid)
57                 {
58                         AST(current->cstate == cstate);
59                         goto finish;
60                 }
61                 current = current->next;
62         }
63
64         newitm = (GLContext_List *)calloc(1, sizeof(GLContext_List));
65         if (newitm == NULL)
66         {
67                 ERR("Failed to create context list.\n");
68                 goto finish;
69         }
70
71         newitm->cstate = cstate;
72         newitm->thread_id = tid;
73         newitm->option_len = option_len;
74         newitm->option = (void *)malloc(option_len);
75         memcpy(newitm->option, option, option_len);
76
77         if (glctx_list != NULL)
78                 newitm->next = glctx_list;
79
80         glctx_list = newitm;
81
82         ret = 1;
83         goto finish;
84
85 finish:
86         if (ret != 1)
87         {
88                 if (newitm != NULL)
89                 {
90                         free(newitm);
91                         newitm = NULL;
92                 }
93                 if (cstate != NULL)
94                 {
95                         free(cstate);
96                         cstate = NULL;
97                 }
98         }
99         if (mtx != NULL) AST(mutex_unlock(mtx) == 1);
100
101         return ret;
102 }
103
104 GLContextState *
105 get_context_state_from_list(const void *option, const int option_len, Mutex *mtx)
106 {
107         GLContextState *ret = NULL;
108         GLContext_List *current = NULL;
109         int tid = 0;
110
111         if (mtx != NULL) AST(mutex_lock(mtx) == 1);
112
113         tid = get_current_thread();
114
115         current = glctx_list;
116         while (current != NULL)
117         {
118                 if (current->option_len == option_len &&
119                     memcmp(current->option, option, option_len) == 0 &&
120                     current->thread_id == tid)
121                 {
122                         ret = current->cstate;
123                         goto finish;
124                 }
125                 current = current->next;
126         }
127         goto finish;
128
129 finish:
130         if (mtx != NULL) AST(mutex_unlock(mtx) == 1);
131         return ret;
132 }
133
134 int
135 remove_context_states_from_list(GLContextState *cstate, Mutex *mtx)
136 {
137         int ret = 0;
138         int tid = 0;
139         GLContext_List *olditm = NULL;
140         GLContext_List *current = NULL;
141
142         if (mtx != NULL) AST(mutex_lock(mtx) == 1);
143
144         AST(cstate != NULL);
145
146         tid = get_current_thread();
147         current = glctx_list;
148
149         while (current != NULL)
150         {
151                 if (current->cstate == cstate)
152                 {
153                         GLContext_List *nextitm = NULL;
154                         if (olditm != NULL)
155                         {
156                                 olditm->next = current->next;
157                                 nextitm = olditm->next;
158                         }
159                         else
160                         {
161                                 glctx_list = current->next;
162                                 nextitm = glctx_list;
163                         }
164                         free(current);
165                         ret = 1;
166                         current = nextitm;
167                         continue;
168                 }
169                 olditm = current;
170                 current = current->next;
171         }
172         goto finish;
173
174 finish:
175         if (mtx != NULL) AST(mutex_unlock(mtx) == 1);
176         return ret;
177 }
178
179 int
180 init_new_thread_state()
181 {
182         int ret = 0;
183         GLThreadState *tstate = NULL;
184
185         tstate = get_current_thread_state();
186         AST(tstate == NULL);
187
188         tstate = (GLThreadState *)calloc(1, sizeof(GLThreadState));
189         tstate->thread_id = get_current_thread();
190         tstate->binded_api = EGL_NONE;
191
192         set_current_thread_state(&ctx_list_access_mutex, tstate);
193
194 #ifdef COREGL_TRACE_CONTEXT_INFO
195         add_to_general_trace_list(&thread_trace_list, tstate);
196 #endif // COREGL_TRACE_CONTEXT_INFO
197         ret = 1;
198         goto finish;
199
200 finish:
201         return ret;
202 }
203
204 static void
205 _sym_missing()
206 {
207         ERR("GL symbol missing!\n");
208 }
209
210 static int
211 _glue_sym_init(void)
212 {
213
214 #define FINDSYM(libhandle, getproc, dst, sym) \
215    if ((!dst) && (getproc)) dst = (__typeof__(dst))getproc(sym); \
216    if (!dst) dst = (__typeof__(dst))dlsym(libhandle, sym);
217
218 #define FALLBAK(dst) \
219    if (!dst) { dst = (__typeof__(dst))_sym_missing; ERR("WARNING : symbol '"#dst"' missing!\n"); }
220
221
222 #ifndef _COREGL_DESKTOP_GL
223 # define _COREGL_SYMBOL(IS_EXTENSION, RET_TYPE, FUNC_NAME, PARAM_LIST) \
224      FINDSYM(egl_lib_handle, _sym_eglGetProcAddress, _sym_##FUNC_NAME, #FUNC_NAME); \
225      if (IS_EXTENSION == GL_TRUE) { \
226         FINDSYM(egl_lib_handle, _sym_eglGetProcAddress, _sym_##FUNC_NAME, #FUNC_NAME"EXT"); \
227         FINDSYM(egl_lib_handle, _sym_eglGetProcAddress, _sym_##FUNC_NAME, #FUNC_NAME"ARB"); \
228         FINDSYM(egl_lib_handle, _sym_eglGetProcAddress, _sym_##FUNC_NAME, #FUNC_NAME"OES"); \
229         FINDSYM(egl_lib_handle, _sym_eglGetProcAddress, _sym_##FUNC_NAME, #FUNC_NAME"KHR"); \
230      } else { FALLBAK(_sym_##FUNC_NAME); }
231 # include "headers/sym_egl.h"
232 # undef _COREGL_SYMBOL
233 #else
234 # define _COREGL_SYMBOL(IS_EXTENSION, RET_TYPE, FUNC_NAME, PARAM_LIST) \
235      FINDSYM(glue_lib_handle, _sym_glXGetProcAddress, _sym_##FUNC_NAME, #FUNC_NAME); \
236      if (IS_EXTENSION == GL_TRUE) { \
237         FINDSYM(gl_lib_handle, _sym_glXGetProcAddress, _sym_##FUNC_NAME, #FUNC_NAME"EXT"); \
238         FINDSYM(gl_lib_handle, _sym_glXGetProcAddress, _sym_##FUNC_NAME, #FUNC_NAME"ARB"); \
239         FINDSYM(gl_lib_handle, _sym_glXGetProcAddress, _sym_##FUNC_NAME, #FUNC_NAME"OES"); \
240         FINDSYM(gl_lib_handle, _sym_glXGetProcAddress, _sym_##FUNC_NAME, #FUNC_NAME"MESA"); \
241         FINDSYM(gl_lib_handle, _sym_glXGetProcAddress, _sym_##FUNC_NAME, #FUNC_NAME"SGI"); \
242      } else { FALLBAK(_sym_##FUNC_NAME); }
243 # include "headers/sym_glx.h"
244 # undef _COREGL_SYMBOL
245 #endif
246
247 #undef FINDSYM
248 #undef FALLBAK
249
250         return 1;
251 }
252
253 static int
254 _gl_sym_init(void)
255 {
256
257 #define FINDSYM(libhandle, getproc, dst, sym) \
258    if ((!dst) && (getproc)) dst = (__typeof__(dst))getproc(sym); \
259    if (!dst) dst = (__typeof__(dst))dlsym(gl_lib_handle, sym);
260 #define FALLBAK(dst) \
261    if (!dst) { dst = (__typeof__(dst))_sym_missing; ERR("WARNING : symbol '"#dst"' missing!\n"); }
262
263 #ifndef _COREGL_DESKTOP_GL
264 # define _COREGL_SYMBOL(IS_EXTENSION, RET_TYPE, FUNC_NAME, PARAM_LIST) \
265      FINDSYM(gl_lib_handle, _sym_eglGetProcAddress, _sym_##FUNC_NAME, #FUNC_NAME); \
266      if (IS_EXTENSION == GL_TRUE) { \
267         FINDSYM(gl_lib_handle, _sym_eglGetProcAddress, _sym_##FUNC_NAME, #FUNC_NAME"EXT"); \
268         FINDSYM(gl_lib_handle, _sym_eglGetProcAddress, _sym_##FUNC_NAME, #FUNC_NAME"ARB"); \
269         FINDSYM(gl_lib_handle, _sym_eglGetProcAddress, _sym_##FUNC_NAME, #FUNC_NAME"OES"); \
270         FINDSYM(gl_lib_handle, _sym_eglGetProcAddress, _sym_##FUNC_NAME, #FUNC_NAME"KHR"); \
271       } else { FALLBAK(_sym_##FUNC_NAME); }
272 # include "headers/sym_gl.h"
273 # undef _COREGL_SYMBOL
274 #else
275 # define _COREGL_SYMBOL(IS_EXTENSION, RET_TYPE, FUNC_NAME, PARAM_LIST) \
276      if (IS_EXTENSION == GL_TRUE) { \
277         FINDSYM(gl_lib_handle, _sym_glXGetProcAddress, _sym_##FUNC_NAME, #FUNC_NAME); \
278         FINDSYM(gl_lib_handle, _sym_glXGetProcAddress, _sym_##FUNC_NAME, #FUNC_NAME"EXT"); \
279         FINDSYM(gl_lib_handle, _sym_glXGetProcAddress, _sym_##FUNC_NAME, #FUNC_NAME"ARB"); \
280         FINDSYM(gl_lib_handle, _sym_glXGetProcAddress, _sym_##FUNC_NAME, #FUNC_NAME"OES"); \
281      } else { FALLBAK(_sym_##FUNC_NAME); }
282 # include "headers/sym_gl.h"
283 # undef _COREGL_SYMBOL
284 #endif
285
286 #undef FINDSYM
287 #undef FALLBAK
288
289         return 1;
290 }
291
292 COREGL_API void coregl_symbol_exported()
293 {
294         LOG("\E[0;31;1mERROR : Invalid library link! (Check linkage of libCOREGL)\E[0m\n");
295 }
296
297 static int
298 _gl_lib_init(void)
299 {
300
301 #ifndef _COREGL_DESKTOP_GL
302         //------------------------------------------------//
303         // Open EGL Library as EGL is separate
304 #ifndef _COREGL_EMBED_EVAS
305         egl_lib_handle = dlopen("libEGL_drv.so", RTLD_NOW);
306 #else
307         egl_lib_handle = dlopen("libEGL.so.1", RTLD_NOW);
308         if (!egl_lib_handle)
309                 egl_lib_handle = dlopen("libEGL.so", RTLD_NOW);
310 #endif
311         if (!egl_lib_handle)
312         {
313                 ERR("\E[0;31;1mERROR : %s\E[0m\n\n", dlerror());
314                 ERR("\E[0;31;1mERROR : Invalid library link! (Check linkage of libCOREGL -> libEGL_drv)\E[0m\n");
315                 return 0;
316         }
317
318         // test for invalid linking egl
319         if (dlsym(egl_lib_handle, "coregl_symbol_exported"))
320         {
321                 ERR("\E[0;31;1mERROR : Invalid library link! (Check linkage of libCOREGL -> libEGL_drv)\E[0m\n");
322                 return 0;
323         }
324
325         // use gl_lib handle for GL symbols
326 #ifndef _COREGL_EMBED_EVAS
327         gl_lib_handle = dlopen("libGLESv2_drv.so", RTLD_NOW);
328 #else
329         gl_lib_handle = dlopen("libGLESv2.so.1", RTLD_NOW);
330         if (!gl_lib_handle)
331                 gl_lib_handle = dlopen("libGLESv2.so", RTLD_NOW);
332 #endif
333         if (!gl_lib_handle)
334         {
335                 ERR("\E[0;31;1mERROR : %s\E[0m\n\n", dlerror());
336                 ERR("\E[0;31;1mERROR : Invalid library link! (Check linkage of libCOREGL -> libGLESv2_drv)\E[0m\n");
337                 return 0;
338         }
339
340         // test for invalid linking gl
341         if (dlsym(gl_lib_handle, "coregl_symbol_exported"))
342         {
343                 ERR("\E[0;31;1mERROR : Invalid library link! (Check linkage of libCOREGL -> libGLESv2_drv)\E[0m\n");
344                 return 0;
345         }
346         //------------------------------------------------//
347
348 #else // GLX
349
350
351 #ifndef _COREGL_EMBED_EVAS
352         gl_lib_handle = dlopen("libGL_drv.so", RTLD_NOW);
353 #else
354         gl_lib_handle = dlopen("libGL.so.1", RTLD_NOW);
355         if (!gl_lib_handle)
356                 gl_lib_handle = dlopen("libGL.so", RTLD_NOW);
357 #endif
358         if (!gl_lib_handle)
359         {
360                 ERR("%s\n", dlerror());
361                 return 0;
362         }
363
364         //------------------------------------------------//
365
366 #endif // _COREGL_DESKTOP_GL
367
368         if (!_glue_sym_init()) return 0;
369         if (!_gl_sym_init()) return 0;
370
371         return 1;
372 }
373
374 extern void init_fast_gl();
375 extern void init_wrap_gl();
376
377 #ifndef _COREGL_EMBED_EVAS
378 __attribute__((constructor))
379 #endif
380 int
381 init_gl()
382 {
383         int fastpath_opt = 0;
384
385         LOG("[CoreGL] ");
386
387         if (!_gl_lib_init()) return 0;
388
389         fastpath_opt = atoi(get_env_setting("COREGL_FASTPATH"));
390
391         switch (fastpath_opt)
392         {
393                 case 1:
394                         api_opt = COREGL_FAST_PATH;
395                         LOG(": (%d) Fastpath enabled...\n", fastpath_opt);
396                         init_fast_gl();
397                         break;
398                 default:
399                         LOG(": (%d) Default API path enabled...\n", fastpath_opt);
400                         api_opt = COREGL_NORMAL_PATH;
401                         init_wrap_gl();
402                         break;
403         }
404
405 #ifdef COREGL_TRACE_APICALL_INFO
406         trace_api_flag = atoi(get_env_setting("COREGL_TRACE_API"));
407 #endif
408 #ifdef COREGL_TRACE_CONTEXT_INFO
409         trace_ctx_flag = atoi(get_env_setting("COREGL_TRACE_CTX"));
410 #endif
411 #ifdef COREGL_TRACE_CONTEXT_INFO
412         trace_ctx_force_flag = atoi(get_env_setting("COREGL_TRACE_CTX_FORCE"));
413 #endif
414 #ifdef COREGL_TRACE_STATE_INFO
415         trace_state_flag = atoi(get_env_setting("COREGL_TRACE_STATE"));
416 #endif
417
418         debug_nofp = atoi(get_env_setting("COREGL_DEBUG_NOFP"));
419
420
421         override_glue_apis(api_opt);
422         override_gl_apis(api_opt);
423
424         return 1;
425 }
426
427 extern void free_fast_gl();
428 extern void free_wrap_gl();
429
430 #ifndef _COREGL_EMBED_EVAS
431 __attribute__((destructor))
432 #endif
433 void
434 free_gl()
435 {
436         GLContext_List *current = NULL;
437
438         switch (api_opt)
439         {
440                 case COREGL_FAST_PATH:
441                         free_fast_gl();
442                         break;
443                 default:
444                         free_wrap_gl();
445                         break;
446         }
447
448         AST(mutex_lock(&ctx_list_access_mutex) == 1);
449
450         {
451                 // Destroy remained context & Detect leaks
452                 int retry_destroy = 0;
453
454                 while (1)
455                 {
456                         retry_destroy = 0;
457                         current = glctx_list;
458                         while (current)
459                         {
460                                 if (current->cstate != NULL)
461                                 {
462                                         ERR("\E[0;31;1mWARNING : Context attached to [dpy=%p|rctx=%p] has not been completely destroyed.(leak)\E[0m\n", current->cstate->rdpy, current->cstate->rctx);
463
464 #ifndef _COREGL_DESKTOP_GL
465                                         _sym_eglMakeCurrent(current->cstate->rdpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
466                                         _sym_eglDestroyContext(current->cstate->rdpy, current->cstate->rctx);
467 #else
468                                         _sym_glXDestroyContext(current->cstate->rdpy, current->cstate->rctx);
469 #endif
470
471                                         remove_context_states_from_list(current->cstate, NULL);
472                                         retry_destroy = 1;
473                                         break;
474                                 }
475
476                                 glctx_list = current->next;
477                                 free(current);
478                                 current = glctx_list;
479                         }
480                         if (retry_destroy == 0) break;
481                 }
482         }
483
484 #ifndef _COREGL_DESKTOP_GL
485         if (egl_lib_handle) dlclose(egl_lib_handle);
486 #endif
487         if (gl_lib_handle) dlclose(gl_lib_handle);
488         goto finish;
489
490 finish:
491         AST(mutex_unlock(&ctx_list_access_mutex) == 1);
492 }
493