1.add fastpath APIs for OpenGLES_DDK
[platform/core/uifw/coregl.git] / src / modules / tracepath / coregl_tracepath.c
1 #include "coregl_tracepath.h"
2
3 #include <stdlib.h>
4 #include <string.h>
5 #include <sys/time.h>
6
7 #include <sys/types.h>
8 #include <unistd.h>
9
10 #include <dlfcn.h>
11 static int         api_gl_version;
12
13
14 #define _COREGL_SYMBOL(RET_TYPE, FUNC_NAME, PARAM_LIST)     RET_TYPE (*_orig_tracepath_##FUNC_NAME) PARAM_LIST = NULL;
15 #include "../../headers/sym.h"
16 #undef _COREGL_SYMBOL
17
18 #define TIMEVAL_INIT            { 0, 0 }
19
20 struct _Trace_Data
21 {
22         char                         name[MAX_TRACE_NAME_LENGTH];
23         struct _Trace_Data          *next;
24 };
25
26 struct _Apicall_Data
27 {
28         struct _Trace_Data          trace_data;
29
30         int                          call_count;
31         int                          last_call_count;
32         struct timeval              elapsed_time;
33         struct timeval              elapsed_time_max;
34         struct timeval              last_elapsed_time;
35         struct timeval              total_elapsed_time;
36         struct timeval              last_total_elapsed_time;
37         struct timeval              last_time;
38
39         int                          traced;
40 };
41
42 struct _Memuse_Data
43 {
44         struct _Trace_Data          trace_data;
45
46         int                          memsize;
47         int                          alloc_count;
48         int                          remove_count;
49 };
50
51 struct _Surface_Data
52 {
53         struct _Trace_Data          trace_data;
54
55         GLDisplay                    display;
56         GLSurface                    surface;
57         GLContext                    context;
58         GLint                        fbo;
59         GLint                        tex;
60         GLint                        rb;
61         int                          dump_count;
62         GLint                        tex_w;
63         GLint                        tex_h;
64         GLint                        tex_format;
65 };
66
67 typedef struct _GLGlueFakeContext
68 {
69         GLuint gl_num_draw_buffers[1];
70         GLuint gl_num_tex_units[1];
71         GLuint gl_num_vertex_attribs[1];
72         GLuint gl_num_transform_feedback_separate_attribs[1];
73         GLuint gl_num_uniform_buffer_bindings[1];
74 } GLGlueFakeContext;
75
76 GLGlueFakeContext initial_fake_ctx_real;
77 GLGlueFakeContext *initial_fake_ctx = &initial_fake_ctx_real;
78
79 struct timeval     initial_time = TIMEVAL_INIT;
80 struct timeval     last_initial_time = TIMEVAL_INIT;
81
82 struct timeval     last_trace_time = TIMEVAL_INIT;
83 struct timeval     other_elapsed_time = TIMEVAL_INIT;
84 struct timeval     traced_other_elapsed_time = TIMEVAL_INIT;
85
86 Mutex               mtd_access_mutex = MUTEX_INITIALIZER;
87 Memuse_Data       **mtd_table;
88
89 Mutex               std_access_mutex = MUTEX_INITIALIZER;
90 Surface_Data      **std_table;
91
92 static void
93 _state_get_texture_states(GLenum pname, GLint *params)
94 {
95         GLuint cur_active_tex = 0;
96
97         AST(initial_fake_ctx != NULL);
98
99         _orig_tracepath_glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint *)&cur_active_tex);
100         int i;
101         for (i = 0; i < initial_fake_ctx->gl_num_tex_units[0]; i++)
102         {
103                 _orig_tracepath_glActiveTexture(GL_TEXTURE0 + i);
104                 _orig_tracepath_glGetIntegerv(pname, (GLint *)&params[i]);
105         }
106         _orig_tracepath_glActiveTexture(cur_active_tex);
107 }
108
109 static void
110 _state_get_draw_buffers(GLenum *params)
111 {
112         AST(initial_fake_ctx != NULL);
113
114         int i;
115         for (i = 0; i < initial_fake_ctx->gl_num_draw_buffers[0]; i++)
116         {
117                 _orig_tracepath_glGetIntegerv(GL_DRAW_BUFFER0 + i, (GLint *)&params[i]);
118         }
119 }
120
121 static void
122 _state_get_transform_feedback_buffer_bindings(GLuint *params)
123 {
124         AST(initial_fake_ctx != NULL);
125
126         int i;
127         for (i = 0; i < initial_fake_ctx->gl_num_transform_feedback_separate_attribs[0]; i++)
128         {
129                 _orig_tracepath_glGetIntegeri_v(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, i, (GLint *)&params[i]);
130         }
131 }
132
133 static void
134 _state_get_transform_feedback_buffer_bindings_offset(GLintptr *params)
135 {
136         AST(initial_fake_ctx != NULL);
137
138         int i;
139         for (i = 0; i < initial_fake_ctx->gl_num_transform_feedback_separate_attribs[0]; i++)
140         {
141                 _orig_tracepath_glGetIntegeri_v(GL_TRANSFORM_FEEDBACK_BUFFER_START, i, (GLint *)&params[i]);
142         }
143 }
144
145 static void
146 _state_get_transform_feedback_buffer_bindings_size(GLsizeiptr *params)
147 {
148         AST(initial_fake_ctx != NULL);
149
150         int i;
151         for (i = 0; i < initial_fake_ctx->gl_num_transform_feedback_separate_attribs[0]; i++)
152         {
153                 _orig_tracepath_glGetIntegeri_v(GL_TRANSFORM_FEEDBACK_BUFFER_SIZE, i, (GLint *)&params[i]);
154         }
155 }
156
157 static void
158 _state_get_uniform_buffer_bindings(GLuint *params)
159 {
160         AST(initial_fake_ctx != NULL);
161
162         int i;
163         for (i = 0; i < initial_fake_ctx->gl_num_uniform_buffer_bindings[0]; i++)
164         {
165 /////////////////////////////////////////////////////////////////////////////////
166 // XXXX : AVOID SEGFAULT in ADRENO
167                 ((GLint *)params)[i] = 0;
168 //              _orig_tracepath_glGetIntegeri_v(GL_UNIFORM_BUFFER_BINDING, i, (GLint *)&params[i]);
169 /////////////////////////////////////////////////////////////////////////////////
170         }
171 }
172
173 static void
174 _state_get_uniform_buffer_bindings_offset(GLintptr *params)
175 {
176         AST(initial_fake_ctx != NULL);
177
178         int i;
179         for (i = 0; i < initial_fake_ctx->gl_num_uniform_buffer_bindings[0]; i++)
180         {
181                 _orig_tracepath_glGetIntegeri_v(GL_UNIFORM_BUFFER_START, i, (GLint *)&params[i]);
182         }
183 }
184
185 static void
186 _state_get_uniform_buffer_bindings_size(GLsizeiptr *params)
187 {
188         AST(initial_fake_ctx != NULL);
189
190         int i;
191         for (i = 0; i < initial_fake_ctx->gl_num_uniform_buffer_bindings[0]; i++)
192         {
193                 _orig_tracepath_glGetIntegeri_v(GL_UNIFORM_BUFFER_SIZE, i, (GLint *)&params[i]);
194         }
195 }
196
197 void
198 init_modules_tracepath()
199 {
200         {
201                 const char *output_file = NULL;
202                 output_file = get_env_setting("COREGL_LOG_FILE");
203                 if (strlen(output_file) > 0)
204                 {
205                         trace_fp = fopen(output_file, "w");
206                 }
207         }
208
209 #ifdef COREGL_TRACEPATH_TRACE_APICALL_INFO
210         trace_api_flag = atoi(get_env_setting("COREGL_TRACE_API"));
211         trace_api_all_flag = atoi(get_env_setting("COREGL_TRACE_API_ALL"));
212         trace_api_frame_flag = atoi(get_env_setting("COREGL_TRACE_API_FRAME"));
213 #endif
214 #ifdef COREGL_TRACEPATH_TRACE_MEMUSE_INFO
215         trace_mem_flag = atoi(get_env_setting("COREGL_TRACE_MEM"));
216         trace_mem_all_flag = atoi(get_env_setting("COREGL_TRACE_MEM_ALL"));
217 #endif
218 #ifdef COREGL_TRACEPATH_TRACE_SURFACE_INFO
219         trace_surface_flag = atoi(get_env_setting("COREGL_TRACE_SURFACE"));
220         trace_surface_sequence_sort_flag = atoi(get_env_setting("COREGL_TRACE_SURFACE_SEQUENCE_SORT"));
221         trace_surface_print_only_flag = atoi(get_env_setting("COREGL_TRACE_SURFACE_PRINT_ONLY"));
222
223         { // COREGL_TRACE_SURFACE_FILTER_PERIOD=40~60
224                 char tmp[64 + 1] = { 0 }, *tmpp = NULL;
225                 strncpy(tmp, get_env_setting("COREGL_TRACE_SURFACE_FILTER_PERIOD"), 64);
226                 for (tmpp = &tmp[0]; ; tmpp++)
227                 {
228                         if (*tmpp == 0x00) break;
229                         if (*tmpp == '~')
230                         {
231                                 *tmpp = 0x00;
232                                 trace_surface_filter_period_begin = atoi(tmp);
233                                 trace_surface_filter_period_end = atoi(tmpp + 1);
234                                 break;
235                         }
236                 }
237         }
238
239         { // COREGL_TRACE_SURFACE_FILTER_TYPE=EGL|FBO
240                 char tmp[64 + 1] = { 0 };
241                 strncpy(tmp, get_env_setting("COREGL_TRACE_SURFACE_FILTER_TYPE"), 64);
242                 if (strcmp(tmp, "EGL") == 0) trace_surface_filter_type = 1;
243                 if (strcmp(tmp, "FBO") == 0) trace_surface_filter_type = 2;
244         }
245
246         { // COREGL_TRACE_SURFACE_FILTER_HANDLE=0x3234
247                 char tmp[64 + 1] = { 0 }, *tmpp = NULL;
248                 strncpy(tmp, get_env_setting("COREGL_TRACE_SURFACE_FILTER_HANDLE"), 64);
249                 if (tmp[0] == '0' && tmp[1] == 'x')
250                 {
251                         for (tmpp = &tmp[2]; ; tmpp++)
252                         {
253                                 if (*tmpp == 0x00) break;
254                                 trace_surface_filter_handle *= 16;
255                                 switch (*tmpp)
256                                 {
257                                         case '1' : trace_surface_filter_handle += 1; break;
258                                         case '2' : trace_surface_filter_handle += 2; break;
259                                         case '3' : trace_surface_filter_handle += 3; break;
260                                         case '4' : trace_surface_filter_handle += 4; break;
261                                         case '5' : trace_surface_filter_handle += 5; break;
262                                         case '6' : trace_surface_filter_handle += 6; break;
263                                         case '7' : trace_surface_filter_handle += 7; break;
264                                         case '8' : trace_surface_filter_handle += 8; break;
265                                         case '9' : trace_surface_filter_handle += 9; break;
266                                         case 'A' : case 'a' : trace_surface_filter_handle += 10; break;
267                                         case 'B' : case 'b' : trace_surface_filter_handle += 11; break;
268                                         case 'C' : case 'c' : trace_surface_filter_handle += 12; break;
269                                         case 'D' : case 'd' : trace_surface_filter_handle += 13; break;
270                                         case 'E' : case 'e' : trace_surface_filter_handle += 14; break;
271                                         case 'F' : case 'f' : trace_surface_filter_handle += 15; break;
272                                 }
273                         }
274                 }
275                 else
276                 {
277                         trace_surface_filter_handle = atoi(tmp);
278                 }
279         }
280
281         { // COREGL_TRACE_SURFACE_FILTER_SIZE=640x480
282                 char tmp[64 + 1] = { 0 }, *tmpp = NULL;
283                 strncpy(tmp, get_env_setting("COREGL_TRACE_SURFACE_FILTER_SIZE"), 64);
284                 for (tmpp = &tmp[0]; ; tmpp++)
285                 {
286                         if (*tmpp == 0x00) break;
287                         if (*tmpp == 'x')
288                         {
289                                 *tmpp = 0x00;
290                                 trace_surface_filter_size_w = atoi(tmp);
291                                 trace_surface_filter_size_h = atoi(tmpp + 1);
292                                 break;
293                         }
294                 }
295         }
296
297 #endif
298 #ifdef COREGL_TRACEPATH_TRACE_CONTEXT_INFO
299         trace_ctx_flag = atoi(get_env_setting("COREGL_TRACE_CTX"));
300         trace_ctx_force_flag = atoi(get_env_setting("COREGL_TRACE_CTX_FORCE"));
301 #endif
302 #ifdef COREGL_TRACEPATH_TRACE_STATE_INFO
303         trace_state_flag = atoi(get_env_setting("COREGL_TRACE_STATE"));
304 #endif
305
306         if (USE_TRACEPATH)
307         {
308                 COREGL_LOG("[CoreGL] \E[40;32;1m<Trace> \E[40;37;1m: ");
309
310                 if (trace_api_flag == 1)
311                 {
312                         COREGL_LOG("\E[40;31;1m(API)\E[0m ");
313                         if (trace_api_all_flag == 1) COREGL_LOG("\E[40;31;1m(API-ALL)\E[0m ");
314                         if (trace_api_frame_flag == 1) COREGL_LOG("\E[40;31;1m(API-FRAME)\E[0m ");
315                 }
316                 if (trace_ctx_flag == 1) {
317                         COREGL_LOG("\E[40;33;1m(CONTEXT)\E[0m ");
318                         if (trace_ctx_force_flag == 1) COREGL_LOG("\E[40;33;1m(CONTEXT-FORCE)\E[0m ");
319                 }
320                 if (trace_state_flag == 1) COREGL_LOG("\E[40;36;1m(STATE)\E[0m ");
321                 if (trace_mem_flag == 1)
322                 {
323                         COREGL_LOG("\E[40;35;1m(MEM)\E[0m ");
324                         if (trace_mem_all_flag == 1) COREGL_LOG("\E[40;35;1m(MEM-ALL)\E[0m ");
325                 }
326                 if (trace_surface_flag == 1) {
327                         COREGL_LOG("\E[40;36;1m(SURFACE)\E[0m ");
328                         if (trace_surface_sequence_sort_flag == 1) COREGL_LOG("\E[40;36;1m(SURFACE-SEQUENCE SORT)\E[0m ");
329                         if (trace_surface_print_only_flag == 1) COREGL_LOG("\E[40;36;1m(PRINT ONLY)\E[0m ");
330                         if (trace_surface_filter_period_begin != 0 || trace_surface_filter_period_end != 0)
331                                 COREGL_LOG("\E[40;36;1m(SURFACE-PERIOD:%d~%d)\E[0m ", trace_surface_filter_period_begin, trace_surface_filter_period_end);
332                         if (trace_surface_filter_type == 1) COREGL_LOG("\E[40;36;1m(SURFACE-TYPE:EGL)\E[0m ");
333                         if (trace_surface_filter_type == 2) COREGL_LOG("\E[40;36;1m(SURFACE-TYPE:FBO)\E[0m ");
334                         if (trace_surface_filter_handle != 0) COREGL_LOG("\E[40;36;1m(SURFACE-HANDLE:0x%x(%d))\E[0m ", trace_surface_filter_handle, trace_surface_filter_handle);
335                         if (trace_surface_filter_size_w > 0 && trace_surface_filter_size_h > 0)
336                                 COREGL_LOG("\E[40;36;1m(SURFACE-SIZE:%dx%d)\E[0m ", trace_surface_filter_size_w, trace_surface_filter_size_h);
337                 }
338
339                 COREGL_LOG("\E[40;37;1menabled\E[0m\n");
340         }
341 }
342
343 void
344 deinit_modules_tracepath()
345 {
346 }
347
348 void
349 init_modules_tstate_tracepath(GLThreadState *tstate)
350 {
351         MY_MODULE_TSTATE *tstate_mt = NULL;
352
353         tstate_mt = (MY_MODULE_TSTATE *)calloc(1, sizeof(MY_MODULE_TSTATE));
354
355
356         tstate->module_data[MY_MODULE_ID] = tstate_mt;
357 }
358
359 void
360 deinit_modules_tstate_tracepath(GLThreadState *tstate)
361 {
362         if (tstate->module_data[MY_MODULE_ID] != NULL)
363         {
364                 free(tstate->module_data[MY_MODULE_ID]);
365                 tstate->module_data[MY_MODULE_ID] = NULL;
366         }
367 }
368
369 void
370 tracepath_apply_overrides()
371 {
372         if (USE_TRACEPATH)
373         {
374                 tracepath_apply_overrides_egl(1);
375                 tracepath_apply_overrides_gl(1);
376         }
377 }
378
379 void
380 tracepath_apply_overrides_egl(int enable)
381 {
382 #define _COREGL_SYMBOL(RET_TYPE, FUNC_NAME, PARAM_LIST)     COREGL_INIT_ORIGINAL(_orig_tracepath_, FUNC_NAME);
383 # include "../../headers/sym_egl.h"
384 #undef _COREGL_SYMBOL
385
386 #define _COREGL_SYMBOL(RET_TYPE, FUNC_NAME, PARAM_LIST)     COREGL_OVERRIDE(tracepath_, FUNC_NAME);
387 # include "../../headers/sym_egl.h"
388 #undef _COREGL_SYMBOL
389 }
390
391 void
392 tracepath_apply_overrides_gl(int enable)
393 {
394 #define _COREGL_START_API(version) api_gl_version = version;
395 #define _COREGL_END_API(version) api_gl_version = COREGL_GLAPI_2;
396 #define _COREGL_SYMBOL(RET_TYPE, FUNC_NAME, PARAM_LIST)     \
397         if(api_gl_version <= driver_gl_version) COREGL_INIT_ORIGINAL(_orig_tracepath_, FUNC_NAME);
398 # include "../../headers/sym_gl.h"
399 #undef _COREGL_SYMBOL
400
401 #define _COREGL_SYMBOL(RET_TYPE, FUNC_NAME, PARAM_LIST) \
402         if(api_gl_version <= driver_gl_version) COREGL_OVERRIDE(tracepath_, FUNC_NAME);
403 # include "../../headers/sym_gl.h"
404 #undef _COREGL_SYMBOL
405 #undef _COREGL_START_API
406 #undef _COREGL_END_API
407 }
408
409 #undef OVERRIDE
410
411 void
412 tracepath_dump_context_states(int force_output)
413 {
414         static struct timeval tv_last = { 0, 0 };
415
416         if (unlikely(trace_state_flag != 1)) return;
417
418         _sym_glGetIntegerv(GL_MAX_DRAW_BUFFERS, (GLint *)initial_fake_ctx->gl_num_draw_buffers);
419         _sym_glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, (GLint *)initial_fake_ctx->gl_num_tex_units);
420         _sym_glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, (GLint *)initial_fake_ctx->gl_num_vertex_attribs);
421         _sym_glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, (GLint *)initial_fake_ctx->gl_num_transform_feedback_separate_attribs);
422         _sym_glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, (GLint *)initial_fake_ctx->gl_num_uniform_buffer_bindings);
423
424         if (!force_output)
425         {
426                 struct timeval tv_now = { 0, 0 };
427                 AST(gettimeofday(&tv_now, NULL) == 0);
428                 if (tv_now.tv_sec - tv_last.tv_sec < _COREGL_TRACE_OUTPUT_INTERVAL_SEC)
429                 {
430                         goto finish;
431                 }
432                 tv_last = tv_now;
433         }
434
435         TRACE("\n");
436         TRACE("\E[0;40;34m===================================================================================================================\E[0m\n");
437         TRACE("\E[40;32;1m  State info \E[1;37;1m: <PID = %d> (CURRENT BINDED CONTEXT)\E[0m\n", getpid());
438         TRACE("\E[0;40;34m===================================================================================================================\E[0m\n");
439
440 #define PRINTF_CHAR_GLenum "0x%8X"
441 #define PRINTF_CHAR_GLboolean "%10d"
442 #define PRINTF_CHAR_GLint "%10d"
443 #define PRINTF_CHAR_GLsizei "%10u"
444 #define PRINTF_CHAR_GLuint "%10u"
445 #define PRINTF_CHAR_GLuintmask "0x%8X"
446 #define PRINTF_CHAR_GLintptr "%10ld"
447 #define PRINTF_CHAR_GLsizeiptr "%10ld"
448
449 #define PRINTF_CHAR_GLclampf "%10.6f"
450 #define PRINTF_CHAR_GLfloat "%10.6f"
451
452 #define PRINTF_CHAR_GLvoidptr "%10p"
453
454 #define PRINTF_CHAR(type) PRINTF_CHAR_##type
455
456 #define INITIAL_CTX initial_fake_ctx
457
458 #define GLUE_STATE(TYPE, NAME, SIZE, ARRAY_SIZE, DEFAULT_STMT, GET_STMT)  \
459    { \
460       TYPE valuedata[SIZE]; \
461       TYPE *value = NULL; \
462       value = valuedata; GET_STMT; value = valuedata; \
463       TRACE("\E[40;37;1m %-30.30s : (\E[0m ", #NAME); \
464       for (int i = 0; i < SIZE; i++) \
465       { \
466          if (i > 0) { \
467             if (i % 4 == 0) \
468                TRACE("\n %-30.30s     ", "");\
469             else \
470                TRACE(", "); \
471          } \
472          TRACE("["PRINTF_CHAR(TYPE)"]", value[i]); \
473       } \
474       TRACE(" \E[40;37;1m)\E[0m\n"); \
475    }
476 # include "../fastpath/coregl_fastpath_state.h"
477 #undef GLUE_STATE
478
479         TRACE("\E[0;40;34m===================================================================================================================\E[0m\n");
480         TRACE("\n");
481
482         TRACE_END();
483
484 finish:
485         return;
486 }
487
488
489 static inline void
490 _add_timeval_period(struct timeval *tv_dst, struct timeval tv_now, struct timeval tv_old)
491 {
492         tv_dst->tv_sec += tv_now.tv_sec - tv_old.tv_sec;
493         tv_dst->tv_usec += 1000000 + (tv_now.tv_usec - tv_old.tv_usec);
494         tv_dst->tv_sec += (tv_dst->tv_usec / 1000000) - 1;
495         tv_dst->tv_usec = tv_dst->tv_usec % 1000000;
496 }
497
498 static inline void
499 _add_timeval(struct timeval *tv_dst, struct timeval tv_src)
500 {
501         tv_dst->tv_sec += tv_src.tv_sec;
502         tv_dst->tv_usec += tv_src.tv_usec;
503         if (tv_dst->tv_usec > 1000000)
504         {
505                 tv_dst->tv_usec -= 1000000;
506                 tv_dst->tv_sec++;
507         }
508         else if (tv_dst->tv_usec < 0)
509         {
510                 tv_dst->tv_usec += 1000000;
511                 tv_dst->tv_sec--;
512         }
513 }
514
515 static inline double
516 _get_timeval_period(struct timeval time_now, struct timeval time_old)
517 {
518         return ((time_now.tv_sec - time_old.tv_sec) * 1000) + ((time_now.tv_usec - time_old.tv_usec) / 1000.0);
519 }
520
521 static inline double
522 _get_timeval(struct timeval time)
523 {
524         return (time.tv_sec * 1000) + (time.tv_usec / 1000.0);
525 }
526
527 static unsigned short
528 _generate_hash_short(const char *string)
529 {
530         unsigned short hash = 0;
531         int i;
532
533         for (i = 0; i < strlen(string); i++)
534         {
535                 hash = 253 * hash + string[i];
536         }
537         return (hash ^ (hash >> 8)) % MAX_TRACE_TABLE_SIZE;
538 }
539
540 static Trace_Data *
541 _get_trace_data(Trace_Data **ftd_table, size_t td_size, const char *name)
542 {
543         Trace_Data *ret = NULL;
544         Trace_Data *current = NULL;
545         Trace_Data *prev = NULL;
546         unsigned short hash = 0;
547
548         AST(strlen(name) < MAX_TRACE_NAME_LENGTH);
549
550         hash = _generate_hash_short(name);
551
552         current = ftd_table[hash];
553
554         while (current != NULL && current->next != NULL)
555         {
556                 if (strcmp(current->name, name) == 0)
557                         break;
558                 prev = current;
559                 current = current->next;
560         }
561
562         if (current != NULL)
563         {
564                 ret = current;
565         }
566         else
567         {
568                 Trace_Data *newitm = NULL;
569                 newitm = (Trace_Data *)calloc(1, td_size);
570                 strcpy(newitm->name, name);
571                 newitm->next = NULL;
572
573                 if (prev != NULL)
574                 {
575                         prev->next = newitm;
576                 }
577                 else
578                 {
579                         ftd_table[hash] = newitm;
580                 }
581                 ret = newitm;
582         }
583
584         goto finish;
585
586 finish:
587         return ret;
588 }
589
590 void
591 tracepath_mem_trace_add(const char *desc, int alloc_size)
592 {
593         Memuse_Data *mtd = NULL;
594
595         if (trace_mem_flag == 1)
596         {
597                 AST(mutex_lock(&mtd_access_mutex) == 1);
598
599                 if (mtd_table == NULL)
600                 {
601                         mtd_table = (Memuse_Data **)calloc(1, sizeof(Memuse_Data *) * MAX_TRACE_TABLE_SIZE);
602                 }
603
604                 mtd = (Memuse_Data *)_get_trace_data((Trace_Data **)mtd_table, sizeof(Memuse_Data), desc);
605
606                 AST(mtd != NULL);
607
608                 mtd->alloc_count++;
609
610                 if (mtd->memsize == 0)
611                         mtd->memsize = alloc_size;
612
613                 AST(mtd->memsize == alloc_size);
614
615                 AST(mutex_unlock(&mtd_access_mutex) == 1);
616
617                 if (trace_mem_all_flag == 1)
618                         _COREGL_TRACE_MEM_OUTPUT(1);
619         }
620
621 }
622
623 void
624 tracepath_mem_trace_remove(const char *desc, int alloc_size)
625 {
626         Memuse_Data *mtd = NULL;
627
628         if (trace_mem_flag == 1)
629         {
630                 AST(mutex_lock(&mtd_access_mutex) == 1);
631
632                 if (mtd_table == NULL)
633                 {
634                         mtd_table = (Memuse_Data **)calloc(1, sizeof(Memuse_Data *) * MAX_TRACE_TABLE_SIZE);
635                 }
636
637                 mtd = (Memuse_Data *)_get_trace_data((Trace_Data **)mtd_table, sizeof(Memuse_Data), desc);
638
639                 AST(mtd != NULL);
640                 AST(mtd->memsize == alloc_size);
641
642                 AST(mtd->alloc_count > mtd->remove_count);
643                 mtd->remove_count++;
644
645                 AST(mutex_unlock(&mtd_access_mutex) == 1);
646
647                 if (trace_mem_all_flag == 1)
648                         _COREGL_TRACE_MEM_OUTPUT(1);
649         }
650 }
651
652 void *
653 tracepath_api_trace_begin(const char *funcname, void *hint, int trace_total_time)
654 {
655         Apicall_Data *ftd = NULL;
656         struct timeval t = TIMEVAL_INIT;
657
658         if (trace_api_flag == 1)
659         {
660                 AST(gettimeofday(&t, NULL) == 0);
661
662                 ftd = (Apicall_Data *)hint;
663
664                 if (ftd == NULL)
665                 {
666                         MY_MODULE_TSTATE *tstate = NULL;
667                         GET_MY_TSTATE(tstate, get_current_thread_state());
668
669                         if (tstate == NULL)
670                         {
671                                 init_new_thread_state();
672
673                                 GET_MY_TSTATE(tstate, get_current_thread_state());
674                                 AST(tstate != NULL);
675                         }
676
677                         if (tstate->ftd_table == NULL)
678                         {
679                                 tstate->ftd_table = (Apicall_Data **)calloc(1, sizeof(Apicall_Data *) * MAX_TRACE_TABLE_SIZE);
680                         }
681
682                         ftd = (Apicall_Data *)_get_trace_data((Trace_Data **)tstate->ftd_table, sizeof(Apicall_Data), funcname);
683                 }
684
685                 AST(ftd != NULL);
686
687                 ftd->call_count++;
688                 AST(ftd->last_time.tv_sec == 0);
689
690                 AST(gettimeofday(&ftd->last_time, NULL) == 0);
691
692                 if (initial_time.tv_sec == 0)
693                 {
694                         initial_time = ftd->last_time;
695                         last_initial_time = ftd->last_time;
696                 }
697
698                 if (trace_total_time == 1)
699                 {
700                         if (last_trace_time.tv_sec != 0)
701                         {
702                                 _add_timeval_period(&other_elapsed_time, t, last_trace_time);
703                                 last_trace_time.tv_sec = 0;
704                         }
705                 }
706
707         }
708
709         return ftd;
710 }
711
712 void *
713 tracepath_api_trace_end(const char *funcname, void *hint, int trace_total_time)
714 {
715         Apicall_Data *ftd = NULL;
716         struct timeval t = TIMEVAL_INIT;
717
718         if (trace_api_flag == 1)
719         {
720                 MY_MODULE_TSTATE *tstate = NULL;
721                 struct timeval elapsed_time = TIMEVAL_INIT;
722
723                 AST(gettimeofday(&t, NULL) == 0);
724
725                 ftd = (Apicall_Data *)hint;
726
727                 if (ftd == NULL)
728                 {
729                         GET_MY_TSTATE(tstate, get_current_thread_state());
730
731                         if (tstate == NULL)
732                         {
733                                 init_new_thread_state();
734
735                                 GET_MY_TSTATE(tstate, get_current_thread_state());
736                                 AST(tstate != NULL);
737                         }
738
739                         AST(tstate != NULL);
740                         AST(tstate->ftd_table != NULL);
741
742                         ftd = (Apicall_Data *)_get_trace_data((Trace_Data **)tstate->ftd_table, sizeof(Apicall_Data), funcname);
743                 }
744
745                 AST(ftd != NULL);
746
747                 _add_timeval_period(&elapsed_time, t, ftd->last_time);
748
749                 _add_timeval(&ftd->elapsed_time, elapsed_time);
750
751                 if (elapsed_time.tv_sec >= ftd->elapsed_time_max.tv_sec &&
752                     elapsed_time.tv_usec > ftd->elapsed_time_max.tv_usec)
753                 {
754                         ftd->elapsed_time_max.tv_sec = elapsed_time.tv_sec;
755                         ftd->elapsed_time_max.tv_usec = elapsed_time.tv_usec;
756                 }
757
758                 ftd->last_time.tv_sec = 0;
759
760                 if (trace_total_time == 1)
761                 {
762                         _add_timeval(&ftd->total_elapsed_time, elapsed_time);
763
764                         AST(gettimeofday(&last_trace_time, NULL) == 0);
765
766                         if (initial_time.tv_sec == 0)
767                         {
768                                 initial_time = t;
769                                 last_initial_time = t;
770                         }
771                 }
772
773         }
774
775
776         return ftd;
777 }
778
779 void
780 tracepath_api_trace_output(int force_output)
781 {
782         static struct timeval tv_last = TIMEVAL_INIT;
783         struct timeval total_now = TIMEVAL_INIT;
784         GLThreadState *tstate = NULL;
785         MY_MODULE_TSTATE *tstate_tm = NULL;
786         Apicall_Data **ftd_table = NULL;
787
788         double total_elapsed_time = 0.0;
789         double total_elapsed_time_period = 0.0;
790         double total_opengl_elapsed_time = 0.0;
791         double total_opengl_elapsed_time_period = 0.0;
792         double total_other_elapsed_time = 0.0;
793         double total_other_elapsed_time_period = 0.0;
794
795         double swaps_per_sec = 0.0;
796
797         int i;
798
799         if (trace_api_flag != 1)
800         {
801                 goto finish;
802         }
803
804         if (!force_output)
805         {
806                 struct timeval tv_now = TIMEVAL_INIT;
807                 AST(gettimeofday(&tv_now, NULL) == 0);
808                 if (tv_now.tv_sec - tv_last.tv_sec < _COREGL_TRACE_OUTPUT_INTERVAL_SEC)
809                 {
810                         goto finish;
811                 }
812                 tv_last = tv_now;
813         }
814
815         AST(gettimeofday(&total_now, NULL) == 0);
816
817         total_elapsed_time = _get_timeval_period(total_now, initial_time);
818         total_elapsed_time_period = _get_timeval_period(total_now, last_initial_time);
819         last_initial_time = total_now;
820
821         total_other_elapsed_time = _get_timeval(other_elapsed_time);
822         total_other_elapsed_time_period = _get_timeval_period(other_elapsed_time, traced_other_elapsed_time);
823         traced_other_elapsed_time = other_elapsed_time;
824
825         tstate = get_current_thread_state();
826
827         if (tstate == NULL)
828         {
829                 init_new_thread_state();
830
831                 tstate = get_current_thread_state();
832                 AST(tstate != NULL);
833         }
834
835         GET_MY_TSTATE(tstate_tm, tstate);
836         if (tstate_tm == NULL) goto finish;
837
838         ftd_table = tstate_tm->ftd_table;
839         if (ftd_table == NULL) goto finish;
840
841         {
842                 static Apicall_Data *trace_hint_swap = NULL;
843                 if (trace_hint_swap == NULL)
844                         trace_hint_swap = (Apicall_Data *)_get_trace_data((Trace_Data **)ftd_table, sizeof(Apicall_Data), "tracepath_eglSwapBuffers");
845
846                 if (trace_hint_swap != NULL && total_elapsed_time_period > 0)
847                 {
848                         swaps_per_sec = (trace_hint_swap->call_count - trace_hint_swap->last_call_count) / (total_elapsed_time_period / 1000);
849                 }
850         }
851
852
853         TRACE("\n");
854         TRACE("\E[40;34m========================================================================================================================\E[0m\n");
855         TRACE("\E[40;32;1m  API call info \E[1;37;1m: <PID = %d> Thread ID = 0x%x  [Swaps per Second(P) = %7.2f]\E[0m\n", getpid(), tstate->thread_id, swaps_per_sec);
856         TRACE("\E[40;34m========================================================================================================================\E[0m\n");
857
858         // highlighted
859         for (i = 0; i < MAX_TRACE_TABLE_SIZE; i++)
860         {
861                 if (ftd_table[i] != NULL)
862                 {
863                         Apicall_Data *current = ftd_table[i];
864
865                         while (current != NULL)
866                         {
867                                 double elapsed_time = _get_timeval(current->elapsed_time);
868                                 double elapsed_time_per_call = elapsed_time / current->call_count;
869
870                                 total_opengl_elapsed_time += _get_timeval(current->total_elapsed_time);
871                                 total_opengl_elapsed_time_period += _get_timeval(current->total_elapsed_time) - _get_timeval(current->last_total_elapsed_time);
872
873                                 current->traced = 0;
874
875                                 if (current->call_count > current->last_call_count)
876                                 {
877                                         double elapsed_time_period = _get_timeval_period(current->elapsed_time, current->last_elapsed_time);
878                                         double elapsed_time_max = _get_timeval(current->elapsed_time_max);
879                                         double elapsed_time_per_call_period = elapsed_time_period / (current->call_count - current->last_call_count);
880                                         char *fname = current->trace_data.name;
881
882                                         if (!strncmp(fname, "tracepath_", 10))
883                                                 fname = &current->trace_data.name[10];
884
885                                         if (elapsed_time_per_call_period >= 0.01 || current->call_count - current->last_call_count > 1000)
886                                         {
887                                                 TRACE("\E[40;37;1m %-39.39s : %10d call(s), %9.3f ms/API, %9.2f ms(MAX), %9.3f ms/API(P)\E[0m\n",
888                                                       fname, current->call_count, elapsed_time_per_call, elapsed_time_max, elapsed_time_per_call_period);
889                                                 current->traced = 1;
890                                         }
891                                 }
892                                 current = (Apicall_Data *)current->trace_data.next;
893                         }
894                 }
895         }
896
897         {
898                 int fp_env = 0;
899                 fp_env = atoi(get_env_setting("COREGL_TRACE_API_ALL"));
900                 if (fp_env == 1)
901                 {
902                         // other
903                         for (i = 0; i < MAX_TRACE_TABLE_SIZE; i++)
904                         {
905                                 if (ftd_table[i] != NULL)
906                                 {
907                                         Apicall_Data *current = ftd_table[i];
908
909                                         while (current != NULL)
910                                         {
911                                                 if (current->traced == 0 && current->call_count > 0)
912                                                 {
913                                                         double elapsed_time = _get_timeval(current->elapsed_time);
914                                                         double elapsed_time_per_call = elapsed_time / current->call_count;
915                                                         double elapsed_time_max = _get_timeval(current->elapsed_time_max);
916                                                         char *fname = current->trace_data.name;
917
918                                                         if (!strncmp(fname, "tracepath_", 10))
919                                                                 fname = &current->trace_data.name[10];
920
921                                                         TRACE(" %-39.39s : %10d call(s), %9.3f ms/API, %9.2f ms(MAX)\n",
922                                                               fname, current->call_count, elapsed_time_per_call, elapsed_time_max);
923                                                 }
924                                                 current = (Apicall_Data *)current->trace_data.next;
925                                         }
926                                 }
927                         }
928                 }
929         }
930
931         TRACE("\E[40;34m========================================================================================================================\E[0m\n");
932
933         if (trace_api_frame_flag == 0)
934         {
935                 TRACE("\E[40;36;1m %-39.39s : %13.2f ms[%6.2f%%], %13.2f ms(P)[%6.2f%%]\E[0m\n",
936                       "TOTAL elapsed Time",
937                       total_elapsed_time,
938                       100.0,
939                       total_elapsed_time_period,
940                       100.0);
941
942
943                 TRACE("\E[40;36;1m %-39.39s : %13.2f ms[%6.2f%%], %13.2f ms(P)[%6.2f%%]\E[0m\n",
944                       "OpenGL elapsed Time",
945                       total_opengl_elapsed_time,
946                       total_opengl_elapsed_time * 100.0 / total_elapsed_time,
947                       total_opengl_elapsed_time_period,
948                       total_opengl_elapsed_time_period * 100.0 / total_elapsed_time_period);
949
950                 TRACE("\E[40;36;1m %-39.39s : %13.2f ms[%6.2f%%], %13.2f ms(P)[%6.2f%%]\E[0m\n",
951                       "Out of OpenGL elapsed time",
952                       total_other_elapsed_time,
953                       total_other_elapsed_time * 100.0 / total_elapsed_time,
954                       total_other_elapsed_time_period,
955                       total_other_elapsed_time_period * 100.0 / total_elapsed_time_period);
956
957                 TRACE("\E[40;36;1m %-39.39s : %13.2f ms[%6.2f%%], %13.2f ms(P)[%6.2f%%]\E[0m\n",
958                       "CoreGL API tracing overhead",
959                       total_elapsed_time - total_opengl_elapsed_time - total_other_elapsed_time,
960                       (total_elapsed_time - total_opengl_elapsed_time - total_other_elapsed_time) * 100.0 / total_elapsed_time,
961                       total_elapsed_time_period - total_opengl_elapsed_time_period - total_other_elapsed_time_period,
962                       (total_elapsed_time_period - total_opengl_elapsed_time_period - total_other_elapsed_time_period) * 100.0 / total_elapsed_time_period);
963
964                 TRACE("\E[40;34m========================================================================================================================\E[0m\n");
965         }
966         TRACE("\n");
967
968         for (i = 0; i < MAX_TRACE_TABLE_SIZE; i++)
969         {
970                 if (ftd_table[i] != NULL)
971                 {
972                         Apicall_Data *current = ftd_table[i];
973
974                         while (current != NULL)
975                         {
976                                 current->last_call_count = current->call_count;
977                                 current->last_elapsed_time = current->elapsed_time;
978                                 current->last_total_elapsed_time = current->total_elapsed_time;
979                                 current = (Apicall_Data *)current->trace_data.next;
980                         }
981                 }
982         }
983
984         TRACE_END();
985
986         goto finish;
987
988 finish:
989         return;
990 }
991
992 void
993 tracepath_api_trace_reset_frame()
994 {
995         GLThreadState *tstate = NULL;
996         MY_MODULE_TSTATE *tstate_tm = NULL;
997         Apicall_Data **ftd_table = NULL;
998
999         int i;
1000
1001         if (trace_api_flag != 1)
1002         {
1003                 goto finish;
1004         }
1005
1006         tstate = get_current_thread_state();
1007
1008         if (tstate == NULL)
1009         {
1010                 init_new_thread_state();
1011
1012                 tstate = get_current_thread_state();
1013                 AST(tstate != NULL);
1014         }
1015
1016         GET_MY_TSTATE(tstate_tm, tstate);
1017         if (tstate_tm == NULL) goto finish;
1018
1019         ftd_table = tstate_tm->ftd_table;
1020         if (ftd_table == NULL) goto finish;
1021
1022         for (i = 0; i < MAX_TRACE_TABLE_SIZE; i++)
1023         {
1024                 if (ftd_table[i] != NULL)
1025                 {
1026                         Apicall_Data *current = ftd_table[i];
1027
1028                         while (current != NULL)
1029                         {
1030                                 current->call_count = 0;
1031                                 current->last_call_count = 0;
1032                                 current->elapsed_time.tv_sec = 0;
1033                                 current->elapsed_time.tv_usec = 0;
1034                                 current->last_elapsed_time.tv_sec = 0;
1035                                 current->last_elapsed_time.tv_usec = 0;
1036                                 current->last_total_elapsed_time.tv_sec = 0;
1037                                 current->last_total_elapsed_time.tv_usec = 0;
1038                                 current->total_elapsed_time.tv_sec = 0;
1039                                 current->total_elapsed_time.tv_usec = 0;
1040                                 current = (Apicall_Data *)current->trace_data.next;
1041                         }
1042                 }
1043         }
1044         AST(gettimeofday(&last_initial_time, NULL) == 0);
1045
1046 finish:
1047         return;
1048
1049 }
1050
1051 void
1052 tracepath_mem_trace_output(int force_output)
1053 {
1054         static struct timeval tv_last = TIMEVAL_INIT;
1055
1056         int i;
1057
1058         if (trace_mem_flag != 1)
1059         {
1060                 goto finish;
1061         }
1062
1063         if (!force_output)
1064         {
1065                 struct timeval tv_now = TIMEVAL_INIT;
1066                 AST(gettimeofday(&tv_now, NULL) == 0);
1067                 if (tv_now.tv_sec - tv_last.tv_sec < _COREGL_TRACE_OUTPUT_INTERVAL_SEC)
1068                 {
1069                         goto finish;
1070                 }
1071                 tv_last = tv_now;
1072         }
1073
1074         TRACE("\n");
1075         TRACE("\E[40;34m========================================================================================================================\E[0m\n");
1076         TRACE("\E[40;32;1m  Memory usage info \E[1;37;1m: <PID = %d>\E[0m\n", getpid());
1077         TRACE("\E[40;34m========================================================================================================================\E[0m\n");
1078
1079         if (mtd_table != NULL)
1080         {
1081                 for (i = 0; i < MAX_TRACE_TABLE_SIZE; i++)
1082                 {
1083                         if (mtd_table[i] != NULL)
1084                         {
1085                                 Memuse_Data *current = mtd_table[i];
1086
1087                                 while (current != NULL)
1088                                 {
1089                                         int obj_count = current->alloc_count - current->remove_count;
1090                                         if (obj_count > 0)
1091                                         {
1092                                                 TRACE("\E[40;37;1m %-46.46s : %12d byte(s)(E), %9d object(s) [%9d+/%9d-]\E[0m\n",
1093                                                       current->trace_data.name, current->memsize, obj_count, current->alloc_count, current->remove_count);
1094                                         }
1095                                         current = (Memuse_Data *)current->trace_data.next;
1096                                 }
1097                         }
1098                 }
1099
1100                 for (i = 0; i < MAX_TRACE_TABLE_SIZE; i++)
1101                 {
1102                         if (mtd_table[i] != NULL)
1103                         {
1104                                 Memuse_Data *current = mtd_table[i];
1105
1106                                 while (current != NULL)
1107                                 {
1108                                         int obj_count = current->alloc_count - current->remove_count;
1109                                         if (obj_count == 0)
1110                                         {
1111                                                 TRACE(" %-46.46s : %12d byte(s)(E), %9d object(s) [%9d+/%9d-]\n",
1112                                                       current->trace_data.name, current->memsize, obj_count, current->alloc_count, current->remove_count);
1113                                         }
1114                                         current = (Memuse_Data *)current->trace_data.next;
1115                                 }
1116                         }
1117                 }
1118         }
1119
1120         TRACE("\E[40;34m========================================================================================================================\E[0m\n");
1121         TRACE("\n");
1122
1123         TRACE_END();
1124
1125         goto finish;
1126
1127 finish:
1128         return;
1129 }
1130
1131 #include <png.h>
1132
1133 void *png_lib_handle = NULL;
1134
1135 png_structp (*dl_png_create_write_struct) (png_const_charp user_png_ver,
1136                                               png_voidp error_ptr,
1137                                               png_error_ptr error_fn,
1138                                               png_error_ptr warn_fn);
1139
1140
1141 void (*dl_png_destroy_write_struct) (png_structpp png_ptr_ptr,
1142                                         png_infopp info_ptr_ptr);
1143
1144
1145 png_infop (*dl_png_create_info_struct) (png_structp png_ptr);
1146
1147 void (*dl_png_init_io) (png_structp png_ptr,
1148                           png_FILE_p fp);
1149
1150
1151 void (*dl_png_set_IHDR) (png_structp png_ptr,
1152                            png_infop info_ptr,
1153                            png_uint_32 width,
1154                            png_uint_32 height,
1155                            int bit_depth,
1156                            int color_type,
1157                            int interlace_method,
1158                            int compression_method,
1159                            int filter_method);
1160
1161 void (*dl_png_set_bKGD) (png_structp png_ptr,
1162                            png_infop info_ptr,
1163                            png_color_16p background);
1164
1165 void (*dl_png_set_bgr) (png_structp png_ptr);
1166
1167 void (*dl_png_write_info) (png_structp png_ptr,
1168                              png_infop info_ptr);
1169
1170 void (*dl_png_write_image) (png_structp png_ptr,
1171                               png_bytepp image);
1172
1173 void (*dl_png_write_end) (png_structp png_ptr,
1174                             png_infop info_ptr);
1175
1176 static void
1177 _dump_surface(int force_output, int type, const char *position, Surface_Data *sdata)
1178 {
1179         static int alldumpcount = 0;
1180         unsigned char *data = NULL;
1181         EGLint width = -1, height = -1, channel = -1;
1182         char name[200];
1183         FILE *write_fd = NULL;
1184         png_struct *png = NULL;
1185         png_info *info = NULL;
1186         png_byte **rows = NULL;
1187         GLenum ret_value = _COREGL_INT_INIT_VALUE;
1188
1189         if (!png_lib_handle)
1190         {
1191                 png_lib_handle = dlopen("libpng16.so.16", RTLD_NOW);
1192
1193                 dl_png_create_write_struct = dlsym(png_lib_handle, "png_create_write_struct");
1194                 dl_png_destroy_write_struct = dlsym(png_lib_handle, "png_destroy_write_struct");
1195                 dl_png_create_info_struct = dlsym(png_lib_handle, "png_create_info_struct");
1196
1197                 dl_png_init_io = dlsym(png_lib_handle, "png_init_io");
1198
1199                 dl_png_set_IHDR = dlsym(png_lib_handle, "png_set_IHDR");
1200                 dl_png_set_bKGD = dlsym(png_lib_handle, "png_set_bKGD");
1201                 dl_png_set_bgr = dlsym(png_lib_handle, "png_set_bgr");
1202
1203                 dl_png_write_info = dlsym(png_lib_handle, "png_write_info");
1204                 dl_png_write_image = dlsym(png_lib_handle, "png_write_image");
1205                 dl_png_write_end = dlsym(png_lib_handle, "png_write_end");
1206         }
1207
1208         {
1209                 if (!png_lib_handle ||
1210                     dl_png_create_write_struct == NULL ||
1211                     dl_png_destroy_write_struct == NULL ||
1212                     dl_png_create_info_struct == NULL ||
1213                     dl_png_init_io == NULL ||
1214                     dl_png_set_IHDR == NULL ||
1215                     dl_png_set_bKGD == NULL ||
1216                     dl_png_set_bgr == NULL ||
1217                     dl_png_write_info == NULL ||
1218                     dl_png_write_image == NULL ||
1219                     dl_png_write_end == NULL)
1220                 {
1221                         COREGL_ERR("Can't trace surface : Failed to use libpng (recommend : 1.2.50-3.4)");
1222                         goto finish;
1223                 }
1224
1225                 if (trace_surface_sequence_sort_flag == 1)
1226                         sprintf(name, "[%d (%06d)%p-%p] %s %04d (%s).png", getpid(), alldumpcount, sdata->display, sdata->context, sdata->trace_data.name, sdata->dump_count, position);
1227                 else
1228                         sprintf(name, "[%d %p-%p] %s %04d (%s).png", getpid(), sdata->display, sdata->context, sdata->trace_data.name, sdata->dump_count, position);
1229
1230                 if (!strncmp(sdata->trace_data.name, "EGL", 3) && type != 2)
1231                 { // EGL
1232                         if (trace_surface_filter_type != 0 &&
1233                             trace_surface_filter_type != 1) goto finish;;
1234
1235                         if (trace_surface_filter_handle != 0 &&
1236                             trace_surface_filter_handle != (int)sdata->surface) goto finish;
1237
1238                         EGLConfig eglconfig;
1239                         GLint asize, rsize, gsize, bsize;
1240                         _orig_tracepath_eglQuerySurface(sdata->display, sdata->surface, EGL_WIDTH, &width);
1241                         _orig_tracepath_eglQuerySurface(sdata->display, sdata->surface, EGL_HEIGHT, &height);
1242                         _orig_tracepath_eglQuerySurface(sdata->display, sdata->surface, EGL_CONFIG_ID, (GLint *)&eglconfig);
1243                         _orig_tracepath_eglGetConfigAttrib(sdata->display, eglconfig, EGL_ALPHA_SIZE, &asize);
1244                         _orig_tracepath_eglGetConfigAttrib(sdata->display, eglconfig, EGL_RED_SIZE, &rsize);
1245                         _orig_tracepath_eglGetConfigAttrib(sdata->display, eglconfig, EGL_GREEN_SIZE, &gsize);
1246                         _orig_tracepath_eglGetConfigAttrib(sdata->display, eglconfig, EGL_BLUE_SIZE, &bsize);
1247                         channel = 4;
1248                         if (asize == 0) channel = 3;
1249                         if (bsize == 0) channel = 2;
1250                         if (gsize == 0) channel = 1;
1251                         if (rsize == 0) channel = 0;
1252
1253                         if (channel == 2) channel = 3;
1254                         if (width <= 0 || height <= 0 || channel <= 0) goto finish;
1255                         if (trace_surface_filter_size_w > 0 && trace_surface_filter_size_h > 0 &&
1256                             (trace_surface_filter_size_w != width || trace_surface_filter_size_h != height))
1257                                 goto finish;
1258
1259                         if ((trace_surface_filter_period_begin > 0 || trace_surface_filter_period_end > 0) &&
1260                             (trace_surface_filter_period_begin > alldumpcount || trace_surface_filter_period_end < alldumpcount))
1261                         {
1262                                 alldumpcount++;
1263                                 sdata->dump_count++;
1264                                 goto finish;
1265                         }
1266
1267                         if (channel == 3) channel = 4;
1268
1269                         TRACE("\E[40;31;1m[[TRACE SURFACE]] : '%s' is dumped (%dx%dx%d).\E[0m\n", name, width, height, channel);
1270                         if (trace_surface_print_only_flag == 1 && force_output == 0)
1271                         {
1272                                 alldumpcount++;
1273                                 sdata->dump_count++;
1274                                 goto finish;
1275                         }
1276
1277                         data = (unsigned char *)calloc(1, width * height * channel * sizeof(unsigned char));
1278                         if (data == NULL)
1279                         {
1280                                 COREGL_ERR("Can't trace surface : Failed to allocate memory");
1281                                 goto finish;
1282                         }
1283
1284                         GLint oldfb;
1285                         _orig_tracepath_glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldfb);
1286                         _orig_tracepath_glBindFramebuffer(GL_FRAMEBUFFER, 0);
1287
1288                         switch (channel)
1289                         {
1290                                 case 4: _orig_tracepath_glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data); break;
1291                                 //case 3: _orig_tracepath_glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, data); break;
1292                                 case 1: _orig_tracepath_glReadPixels(0, 0, width, height, GL_ALPHA, GL_UNSIGNED_BYTE, data); break;
1293                         }
1294
1295                         _orig_tracepath_glBindFramebuffer(GL_FRAMEBUFFER, oldfb);
1296                 }
1297                 if (!strncmp(sdata->trace_data.name, "FBO", 3) && type != 1)
1298                 { // FBO
1299                         if (sdata->fbo == 0) goto finish;
1300
1301                         if (trace_surface_filter_type != 0 &&
1302                             trace_surface_filter_type != 2) goto finish;
1303
1304                         if (trace_surface_filter_handle != 0 &&
1305                             trace_surface_filter_handle != sdata->tex &&
1306                             trace_surface_filter_handle != sdata->rb) goto finish;
1307
1308                         GLint oldfb;
1309                         _orig_tracepath_glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldfb);
1310                         _orig_tracepath_glBindFramebuffer(GL_FRAMEBUFFER, sdata->fbo);
1311
1312                         if(driver_gl_version >=2)
1313                                 ret_value = _orig_tracepath_glCheckFramebufferStatus(GL_FRAMEBUFFER);
1314                         else
1315                                 ret_value = _orig_tracepath_glCheckFramebufferStatusOES(GL_FRAMEBUFFER);
1316                         if (ret_value == GL_FRAMEBUFFER_COMPLETE)
1317                         {
1318                                 _orig_tracepath_glBindFramebuffer(GL_FRAMEBUFFER, oldfb);
1319                                 width = sdata->tex_w;
1320                                 height = sdata->tex_h;
1321                                 channel = sdata->tex_format;
1322
1323                                 if (channel == 2) channel = 3;
1324                                 if (width <= 0 || height <= 0 || channel <= 0) goto finish;
1325                                 if (trace_surface_filter_size_w > 0 && trace_surface_filter_size_h > 0 &&
1326                                     (trace_surface_filter_size_w != width || trace_surface_filter_size_h != height))
1327                                         goto finish;
1328
1329                                 if ((trace_surface_filter_period_begin > 0 || trace_surface_filter_period_end > 0) &&
1330                                     (trace_surface_filter_period_begin > alldumpcount || trace_surface_filter_period_end < alldumpcount))
1331                                 {
1332                                         alldumpcount++;
1333                                         sdata->dump_count++;
1334                                         goto finish;
1335                                 }
1336
1337                                 TRACE("\E[40;31;1m[[TRACE SURFACE]] : '%s' is dumped (%dx%dx%d).\E[0m\n", name, width, height, channel);
1338                                 if (trace_surface_print_only_flag == 1 && force_output == 0)
1339                                 {
1340                                         alldumpcount++;
1341                                         sdata->dump_count++;
1342                                         goto finish;
1343                                 }
1344
1345                                 if (channel == 3) channel = 4;
1346
1347                                 data = (unsigned char *)calloc(1, width * height * channel * sizeof(unsigned char));
1348                                 if (data == NULL)
1349                                 {
1350                                         COREGL_ERR("Can't trace surface : Failed to allocate memory");
1351                                         goto finish;
1352                                 }
1353
1354                                 _orig_tracepath_glBindFramebuffer(GL_FRAMEBUFFER, sdata->fbo);
1355                                 int atttype = _COREGL_INT_INIT_VALUE;
1356                                 if(driver_gl_version >=2)
1357                                         _orig_tracepath_glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &atttype);
1358                                 else
1359                                         _orig_tracepath_glGetFramebufferAttachmentParameterivOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &atttype);
1360                                 AST(atttype != sdata->tex);
1361                                 int attname = _COREGL_INT_INIT_VALUE;
1362                                 if(driver_gl_version >=2)
1363                                         _orig_tracepath_glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &attname);
1364                                 else
1365                                         _orig_tracepath_glGetFramebufferAttachmentParameterivOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &attname);
1366                                 switch (atttype)
1367                                 {
1368                                         case GL_TEXTURE:
1369                                                 AST(attname == sdata->tex);
1370                                                 break;
1371                                         case GL_RENDERBUFFER:
1372                                                 AST(attname == sdata->rb);
1373                                                 break;
1374                                 }
1375
1376                                 switch (channel)
1377                                 {
1378                                         case 4: _orig_tracepath_glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data); break;
1379                                         //case 3: _orig_tracepath_glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, data); break;
1380                                         case 1: _orig_tracepath_glReadPixels(0, 0, width, height, GL_ALPHA, GL_UNSIGNED_BYTE, data); break;
1381                                 }
1382                         }
1383                         _orig_tracepath_glBindFramebuffer(GL_FRAMEBUFFER, oldfb);
1384                 }
1385
1386
1387
1388                 if (data == NULL) goto finish;
1389
1390                 unlink(name);
1391                 write_fd = fopen(name, "wb");
1392
1393                 if (write_fd == NULL)
1394                 {
1395                         COREGL_ERR("Can't trace surface : Failed to create png file");
1396                         goto finish;
1397                 }
1398
1399                 rows = (png_byte **)malloc(height * sizeof(png_byte *));
1400                 if (rows == NULL)
1401                 {
1402                         COREGL_ERR("Can't trace surface : Failed to allocate memory");
1403                         goto finish;
1404                 }
1405
1406                 for (int i = 0; i < height; i++)
1407                 {
1408                         rows[i] = data + (height - i - 1) * (width * channel);
1409                 }
1410
1411                 png = dl_png_create_write_struct(PNG_LIBPNG_VER_STRING,
1412                                                  NULL,
1413                                                  NULL,
1414                                                  NULL);
1415                 if (png == NULL)
1416                 {
1417                         COREGL_ERR("Can't trace surface : Failed to create write structure of png file");
1418                         goto finish;
1419                 }
1420
1421                 info = dl_png_create_info_struct(png);
1422                 if (info == NULL)
1423                 {
1424                         COREGL_ERR("Can't trace surface : Failed to create info structure of png file");
1425                         goto finish;
1426                 }
1427
1428                 dl_png_init_io(png, write_fd);
1429
1430                 switch (channel)
1431                 {
1432                         case 4: dl_png_set_IHDR(png, info, width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); break;
1433                         //case 3: dl_png_set_IHDR(png, info, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); break;
1434                         case 1: dl_png_set_IHDR(png, info, width, height, 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); break;
1435                 }
1436
1437                 dl_png_write_info(png, info);
1438
1439                 dl_png_write_image(png, rows);
1440
1441                 dl_png_write_end(png, info);
1442
1443                 dl_png_destroy_write_struct(&png, &info);
1444
1445                 alldumpcount++;
1446                 sdata->dump_count++;
1447         }
1448
1449         goto finish;
1450
1451 finish:
1452         if (data != NULL)
1453         {
1454                 free(data);
1455                 data = NULL;
1456         }
1457         if (write_fd != NULL)
1458         {
1459                 fclose(write_fd);
1460                 write_fd = NULL;
1461         }
1462         if (rows != NULL)
1463         {
1464                 free(rows);
1465                 rows = NULL;
1466         }
1467         if (png != NULL)
1468         {
1469                 if (info != NULL)
1470                 {
1471                         dl_png_destroy_write_struct(&png, &info);
1472                         info = NULL;
1473                 }
1474                 else
1475                         dl_png_destroy_write_struct(&png, NULL);
1476                 png = NULL;
1477         }
1478 }
1479
1480 void
1481 tracepath_surface_trace_add(const char *desc, GLDisplay dpy, GLContext ctx, GLSurface surf, GLint fbo, GLint tex, GLint rb, GLint tex_w, GLint tex_h, GLint tex_format, const char *dump)
1482 {
1483         Surface_Data *std = NULL;
1484
1485         if (trace_surface_flag == 1)
1486         {
1487                 AST(mutex_lock(&std_access_mutex) == 1);
1488
1489                 if (std_table == NULL)
1490                 {
1491                         std_table = (Surface_Data **)calloc(1, sizeof(Surface_Data *) * MAX_TRACE_TABLE_SIZE);
1492                 }
1493
1494                 std = (Surface_Data *)_get_trace_data((Trace_Data **)std_table, sizeof(Surface_Data), desc);
1495
1496                 AST(std != NULL);
1497
1498                 if (dump != NULL)
1499                 {
1500                         _dump_surface(0, 0, dump, std);
1501                 }
1502
1503                 std->display = dpy;
1504                 std->surface = surf;
1505                 std->context = ctx;
1506                 if (fbo >= 0) std->fbo = fbo;
1507                 std->tex = tex;
1508                 std->rb = rb;
1509                 if (tex_w >= 0) std->tex_w = tex_w;
1510                 if (tex_h >= 0) std->tex_h = tex_h;
1511                 if (tex_format >= 0) std->tex_format = tex_format;
1512
1513                 AST(mutex_unlock(&std_access_mutex) == 1);
1514
1515         }
1516
1517 }
1518
1519 void
1520 tracepath_surface_trace(int force_output, int type, const char *position)
1521 {
1522         int i;
1523
1524         if (trace_surface_flag != 1)
1525         {
1526                 goto finish;
1527         }
1528
1529         AST(mutex_lock(&std_access_mutex) == 1);
1530
1531         if (std_table != NULL)
1532         {
1533                 EGLDisplay olddpy = _orig_tracepath_eglGetCurrentDisplay();
1534                 EGLContext oldctx = _orig_tracepath_eglGetCurrentContext();
1535                 EGLSurface oldsurf_read = _orig_tracepath_eglGetCurrentSurface(EGL_READ);
1536                 EGLSurface oldsurf_draw = _orig_tracepath_eglGetCurrentSurface(EGL_DRAW);
1537
1538                 for (i = 0; i < MAX_TRACE_TABLE_SIZE; i++)
1539                 {
1540                         if (std_table[i] != NULL)
1541                         {
1542                                 Surface_Data *current = std_table[i];
1543
1544                                 while (current != NULL)
1545                                 {
1546                                         if (current->surface != EGL_NO_SURFACE && current->display != EGL_NO_DISPLAY && current->context != EGL_NO_CONTEXT)
1547                                         {
1548                                                 if (_orig_tracepath_eglMakeCurrent(current->display, current->surface, current->surface, current->context) == EGL_TRUE)
1549                                                 {
1550                                                         _dump_surface(force_output, type, position, current);
1551                                                 }
1552                                         }
1553
1554                                         current = (Surface_Data *)current->trace_data.next;
1555                                 }
1556                         }
1557                 }
1558                 _orig_tracepath_eglMakeCurrent(olddpy, oldsurf_read, oldsurf_draw, oldctx);
1559
1560         }
1561
1562         AST(mutex_unlock(&std_access_mutex) == 1);
1563
1564         goto finish;
1565
1566         finish:
1567                 return;
1568 }
1569
1570
1571 COREGL_API void
1572 coregl_dump_surface()
1573 {
1574         _COREGL_TRACE_SURFACE(1, 0, "USER CALL");
1575 }
1576