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