tizen 2.4 release
[framework/graphics/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                 /* Prevent CID : 390717 */
571                 if (newitm == NULL) goto finish;
572                 strncpy(newitm->name, name, strlen(name));
573                 newitm->next = NULL;
574
575                 if (prev != NULL)
576                 {
577                         prev->next = newitm;
578                 }
579                 else
580                 {
581                         ftd_table[hash] = newitm;
582                 }
583                 ret = newitm;
584         }
585
586         goto finish;
587
588 finish:
589         return ret;
590 }
591
592 void
593 tracepath_mem_trace_add(const char *desc, int alloc_size)
594 {
595         Memuse_Data *mtd = NULL;
596
597         if (trace_mem_flag == 1)
598         {
599                 AST(mutex_lock(&mtd_access_mutex) == 1);
600
601                 if (mtd_table == NULL)
602                 {
603                         mtd_table = (Memuse_Data **)calloc(1, sizeof(Memuse_Data *) * MAX_TRACE_TABLE_SIZE);
604                 }
605
606                 mtd = (Memuse_Data *)_get_trace_data((Trace_Data **)mtd_table, sizeof(Memuse_Data), desc);
607
608                 AST(mtd != NULL);
609
610                 mtd->alloc_count++;
611
612                 if (mtd->memsize == 0)
613                         mtd->memsize = alloc_size;
614
615                 AST(mtd->memsize == alloc_size);
616
617                 AST(mutex_unlock(&mtd_access_mutex) == 1);
618
619                 if (trace_mem_all_flag == 1)
620                         _COREGL_TRACE_MEM_OUTPUT(1);
621         }
622
623 }
624
625 void
626 tracepath_mem_trace_remove(const char *desc, int alloc_size)
627 {
628         Memuse_Data *mtd = NULL;
629
630         if (trace_mem_flag == 1)
631         {
632                 AST(mutex_lock(&mtd_access_mutex) == 1);
633
634                 if (mtd_table == NULL)
635                 {
636                         mtd_table = (Memuse_Data **)calloc(1, sizeof(Memuse_Data *) * MAX_TRACE_TABLE_SIZE);
637                 }
638
639                 mtd = (Memuse_Data *)_get_trace_data((Trace_Data **)mtd_table, sizeof(Memuse_Data), desc);
640
641                 AST(mtd != NULL);
642                 AST(mtd->memsize == alloc_size);
643
644                 AST(mtd->alloc_count > mtd->remove_count);
645                 mtd->remove_count++;
646
647                 AST(mutex_unlock(&mtd_access_mutex) == 1);
648
649                 if (trace_mem_all_flag == 1)
650                         _COREGL_TRACE_MEM_OUTPUT(1);
651         }
652 }
653
654 void *
655 tracepath_api_trace_begin(const char *funcname, void *hint, int trace_total_time)
656 {
657         Apicall_Data *ftd = NULL;
658         struct timeval t = TIMEVAL_INIT;
659
660         if (trace_api_flag == 1)
661         {
662                 AST(gettimeofday(&t, NULL) == 0);
663
664                 ftd = (Apicall_Data *)hint;
665
666                 if (ftd == NULL)
667                 {
668                         MY_MODULE_TSTATE *tstate = NULL;
669                         GET_MY_TSTATE(tstate, get_current_thread_state());
670
671                         if (tstate == NULL)
672                         {
673                                 init_new_thread_state();
674
675                                 GET_MY_TSTATE(tstate, get_current_thread_state());
676                                 AST(tstate != NULL);
677
678                                 /* Prevent CID : 389488 */
679                                 if (tstate == NULL) return NULL;
680                         }
681
682                         if (tstate->ftd_table == NULL)
683                         {
684                                 tstate->ftd_table = (Apicall_Data **)calloc(1, sizeof(Apicall_Data *) * MAX_TRACE_TABLE_SIZE);
685                                 /* Prevent CID : 393786 */
686                                 if (tstate->ftd_table == NULL) return NULL;
687                         }
688
689                         ftd = (Apicall_Data *)_get_trace_data((Trace_Data **)tstate->ftd_table, sizeof(Apicall_Data), funcname);
690                 }
691
692                 AST(ftd != NULL);
693
694                 ftd->call_count++;
695                 AST(ftd->last_time.tv_sec == 0);
696
697                 AST(gettimeofday(&ftd->last_time, NULL) == 0);
698
699                 if (initial_time.tv_sec == 0)
700                 {
701                         initial_time = ftd->last_time;
702                         last_initial_time = ftd->last_time;
703                 }
704
705                 if (trace_total_time == 1)
706                 {
707                         if (last_trace_time.tv_sec != 0)
708                         {
709                                 _add_timeval_period(&other_elapsed_time, t, last_trace_time);
710                                 last_trace_time.tv_sec = 0;
711                         }
712                 }
713
714         }
715
716         return ftd;
717 }
718
719 void *
720 tracepath_api_trace_end(const char *funcname, void *hint, int trace_total_time)
721 {
722         Apicall_Data *ftd = NULL;
723         struct timeval t = TIMEVAL_INIT;
724
725         if (trace_api_flag == 1)
726         {
727                 MY_MODULE_TSTATE *tstate = NULL;
728                 struct timeval elapsed_time = TIMEVAL_INIT;
729
730                 AST(gettimeofday(&t, NULL) == 0);
731
732                 ftd = (Apicall_Data *)hint;
733
734                 if (ftd == NULL)
735                 {
736                         GET_MY_TSTATE(tstate, get_current_thread_state());
737
738                         if (tstate == NULL)
739                         {
740                                 init_new_thread_state();
741
742                                 GET_MY_TSTATE(tstate, get_current_thread_state());
743                                 AST(tstate != NULL);
744                                 /* Prevent CID : 389595 */
745                                 if (tstate == NULL) return NULL;
746                         }
747
748                         AST(tstate != NULL);
749                         AST(tstate->ftd_table != NULL);
750
751                         ftd = (Apicall_Data *)_get_trace_data((Trace_Data **)tstate->ftd_table, sizeof(Apicall_Data), funcname);
752                 }
753
754                 AST(ftd != NULL);
755
756                 _add_timeval_period(&elapsed_time, t, ftd->last_time);
757
758                 _add_timeval(&ftd->elapsed_time, elapsed_time);
759
760                 if (elapsed_time.tv_sec >= ftd->elapsed_time_max.tv_sec &&
761                     elapsed_time.tv_usec > ftd->elapsed_time_max.tv_usec)
762                 {
763                         ftd->elapsed_time_max.tv_sec = elapsed_time.tv_sec;
764                         ftd->elapsed_time_max.tv_usec = elapsed_time.tv_usec;
765                 }
766
767                 ftd->last_time.tv_sec = 0;
768
769                 if (trace_total_time == 1)
770                 {
771                         _add_timeval(&ftd->total_elapsed_time, elapsed_time);
772
773                         AST(gettimeofday(&last_trace_time, NULL) == 0);
774
775                         if (initial_time.tv_sec == 0)
776                         {
777                                 initial_time = t;
778                                 last_initial_time = t;
779                         }
780                 }
781
782         }
783
784
785         return ftd;
786 }
787
788 void
789 tracepath_api_trace_output(int force_output)
790 {
791         static struct timeval tv_last = TIMEVAL_INIT;
792         struct timeval total_now = TIMEVAL_INIT;
793         GLThreadState *tstate = NULL;
794         MY_MODULE_TSTATE *tstate_tm = NULL;
795         Apicall_Data **ftd_table = NULL;
796
797         double total_elapsed_time = 0.0;
798         double total_elapsed_time_period = 0.0;
799         double total_opengl_elapsed_time = 0.0;
800         double total_opengl_elapsed_time_period = 0.0;
801         double total_other_elapsed_time = 0.0;
802         double total_other_elapsed_time_period = 0.0;
803
804         double swaps_per_sec = 0.0;
805
806         int i;
807
808         if (trace_api_flag != 1)
809         {
810                 goto finish;
811         }
812
813         if (!force_output)
814         {
815                 struct timeval tv_now = TIMEVAL_INIT;
816                 AST(gettimeofday(&tv_now, NULL) == 0);
817                 if (tv_now.tv_sec - tv_last.tv_sec < _COREGL_TRACE_OUTPUT_INTERVAL_SEC)
818                 {
819                         goto finish;
820                 }
821                 tv_last = tv_now;
822         }
823
824         AST(gettimeofday(&total_now, NULL) == 0);
825
826         total_elapsed_time = _get_timeval_period(total_now, initial_time);
827         total_elapsed_time_period = _get_timeval_period(total_now, last_initial_time);
828         last_initial_time = total_now;
829
830         total_other_elapsed_time = _get_timeval(other_elapsed_time);
831         total_other_elapsed_time_period = _get_timeval_period(other_elapsed_time, traced_other_elapsed_time);
832         traced_other_elapsed_time = other_elapsed_time;
833
834         tstate = get_current_thread_state();
835
836         if (tstate == NULL)
837         {
838                 init_new_thread_state();
839
840                 tstate = get_current_thread_state();
841                 AST(tstate != NULL);
842         }
843
844         GET_MY_TSTATE(tstate_tm, tstate);
845         if (tstate_tm == NULL) goto finish;
846
847         ftd_table = tstate_tm->ftd_table;
848         if (ftd_table == NULL) goto finish;
849
850         {
851                 static Apicall_Data *trace_hint_swap = NULL;
852                 if (trace_hint_swap == NULL)
853                         trace_hint_swap = (Apicall_Data *)_get_trace_data((Trace_Data **)ftd_table, sizeof(Apicall_Data), "tracepath_eglSwapBuffers");
854
855                 if (trace_hint_swap != NULL && total_elapsed_time_period > 0)
856                 {
857                         swaps_per_sec = (trace_hint_swap->call_count - trace_hint_swap->last_call_count) / (total_elapsed_time_period / 1000);
858                 }
859         }
860
861
862         TRACE("\n");
863         TRACE("\E[40;34m========================================================================================================================\E[0m\n");
864         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);
865         TRACE("\E[40;34m========================================================================================================================\E[0m\n");
866
867         // highlighted
868         for (i = 0; i < MAX_TRACE_TABLE_SIZE; i++)
869         {
870                 if (ftd_table[i] != NULL)
871                 {
872                         Apicall_Data *current = ftd_table[i];
873
874                         while (current != NULL)
875                         {
876                                 double elapsed_time = _get_timeval(current->elapsed_time);
877                                 double elapsed_time_per_call = elapsed_time / current->call_count;
878
879                                 total_opengl_elapsed_time += _get_timeval(current->total_elapsed_time);
880                                 total_opengl_elapsed_time_period += _get_timeval(current->total_elapsed_time) - _get_timeval(current->last_total_elapsed_time);
881
882                                 current->traced = 0;
883
884                                 if (current->call_count > current->last_call_count)
885                                 {
886                                         double elapsed_time_period = _get_timeval_period(current->elapsed_time, current->last_elapsed_time);
887                                         double elapsed_time_max = _get_timeval(current->elapsed_time_max);
888                                         double elapsed_time_per_call_period = elapsed_time_period / (current->call_count - current->last_call_count);
889                                         char *fname = current->trace_data.name;
890
891                                         if (!strncmp(fname, "tracepath_", 10))
892                                                 fname = &current->trace_data.name[10];
893
894                                         if (elapsed_time_per_call_period >= 0.01 || current->call_count - current->last_call_count > 1000)
895                                         {
896                                                 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",
897                                                       fname, current->call_count, elapsed_time_per_call, elapsed_time_max, elapsed_time_per_call_period);
898                                                 current->traced = 1;
899                                         }
900                                 }
901                                 current = (Apicall_Data *)current->trace_data.next;
902                         }
903                 }
904         }
905
906         {
907                 int fp_env = 0;
908                 fp_env = atoi(get_env_setting("COREGL_TRACE_API_ALL"));
909                 if (fp_env == 1)
910                 {
911                         // other
912                         for (i = 0; i < MAX_TRACE_TABLE_SIZE; i++)
913                         {
914                                 if (ftd_table[i] != NULL)
915                                 {
916                                         Apicall_Data *current = ftd_table[i];
917
918                                         while (current != NULL)
919                                         {
920                                                 if (current->traced == 0 && current->call_count > 0)
921                                                 {
922                                                         double elapsed_time = _get_timeval(current->elapsed_time);
923                                                         double elapsed_time_per_call = elapsed_time / current->call_count;
924                                                         double elapsed_time_max = _get_timeval(current->elapsed_time_max);
925                                                         char *fname = current->trace_data.name;
926
927                                                         if (!strncmp(fname, "tracepath_", 10))
928                                                                 fname = &current->trace_data.name[10];
929
930                                                         TRACE(" %-39.39s : %10d call(s), %9.3f ms/API, %9.2f ms(MAX)\n",
931                                                               fname, current->call_count, elapsed_time_per_call, elapsed_time_max);
932                                                 }
933                                                 current = (Apicall_Data *)current->trace_data.next;
934                                         }
935                                 }
936                         }
937                 }
938         }
939
940         TRACE("\E[40;34m========================================================================================================================\E[0m\n");
941
942         if (trace_api_frame_flag == 0)
943         {
944                 TRACE("\E[40;36;1m %-39.39s : %13.2f ms[%6.2f%%], %13.2f ms(P)[%6.2f%%]\E[0m\n",
945                       "TOTAL elapsed Time",
946                       total_elapsed_time,
947                       100.0,
948                       total_elapsed_time_period,
949                       100.0);
950
951
952                 TRACE("\E[40;36;1m %-39.39s : %13.2f ms[%6.2f%%], %13.2f ms(P)[%6.2f%%]\E[0m\n",
953                       "OpenGL elapsed Time",
954                       total_opengl_elapsed_time,
955                       total_opengl_elapsed_time * 100.0 / total_elapsed_time,
956                       total_opengl_elapsed_time_period,
957                       total_opengl_elapsed_time_period * 100.0 / total_elapsed_time_period);
958
959                 TRACE("\E[40;36;1m %-39.39s : %13.2f ms[%6.2f%%], %13.2f ms(P)[%6.2f%%]\E[0m\n",
960                       "Out of OpenGL elapsed time",
961                       total_other_elapsed_time,
962                       total_other_elapsed_time * 100.0 / total_elapsed_time,
963                       total_other_elapsed_time_period,
964                       total_other_elapsed_time_period * 100.0 / total_elapsed_time_period);
965
966                 TRACE("\E[40;36;1m %-39.39s : %13.2f ms[%6.2f%%], %13.2f ms(P)[%6.2f%%]\E[0m\n",
967                       "CoreGL API tracing overhead",
968                       total_elapsed_time - total_opengl_elapsed_time - total_other_elapsed_time,
969                       (total_elapsed_time - total_opengl_elapsed_time - total_other_elapsed_time) * 100.0 / total_elapsed_time,
970                       total_elapsed_time_period - total_opengl_elapsed_time_period - total_other_elapsed_time_period,
971                       (total_elapsed_time_period - total_opengl_elapsed_time_period - total_other_elapsed_time_period) * 100.0 / total_elapsed_time_period);
972
973                 TRACE("\E[40;34m========================================================================================================================\E[0m\n");
974         }
975         TRACE("\n");
976
977         for (i = 0; i < MAX_TRACE_TABLE_SIZE; i++)
978         {
979                 if (ftd_table[i] != NULL)
980                 {
981                         Apicall_Data *current = ftd_table[i];
982
983                         while (current != NULL)
984                         {
985                                 current->last_call_count = current->call_count;
986                                 current->last_elapsed_time = current->elapsed_time;
987                                 current->last_total_elapsed_time = current->total_elapsed_time;
988                                 current = (Apicall_Data *)current->trace_data.next;
989                         }
990                 }
991         }
992
993         TRACE_END();
994
995         goto finish;
996
997 finish:
998         return;
999 }
1000
1001 void
1002 tracepath_api_trace_reset_frame()
1003 {
1004         GLThreadState *tstate = NULL;
1005         MY_MODULE_TSTATE *tstate_tm = NULL;
1006         Apicall_Data **ftd_table = NULL;
1007
1008         int i;
1009
1010         if (trace_api_flag != 1)
1011         {
1012                 goto finish;
1013         }
1014
1015         tstate = get_current_thread_state();
1016
1017         if (tstate == NULL)
1018         {
1019                 init_new_thread_state();
1020
1021                 tstate = get_current_thread_state();
1022                 AST(tstate != NULL);
1023         }
1024
1025         GET_MY_TSTATE(tstate_tm, tstate);
1026         if (tstate_tm == NULL) goto finish;
1027
1028         ftd_table = tstate_tm->ftd_table;
1029         if (ftd_table == NULL) goto finish;
1030
1031         for (i = 0; i < MAX_TRACE_TABLE_SIZE; i++)
1032         {
1033                 if (ftd_table[i] != NULL)
1034                 {
1035                         Apicall_Data *current = ftd_table[i];
1036
1037                         while (current != NULL)
1038                         {
1039                                 current->call_count = 0;
1040                                 current->last_call_count = 0;
1041                                 current->elapsed_time.tv_sec = 0;
1042                                 current->elapsed_time.tv_usec = 0;
1043                                 current->last_elapsed_time.tv_sec = 0;
1044                                 current->last_elapsed_time.tv_usec = 0;
1045                                 current->last_total_elapsed_time.tv_sec = 0;
1046                                 current->last_total_elapsed_time.tv_usec = 0;
1047                                 current->total_elapsed_time.tv_sec = 0;
1048                                 current->total_elapsed_time.tv_usec = 0;
1049                                 current = (Apicall_Data *)current->trace_data.next;
1050                         }
1051                 }
1052         }
1053         AST(gettimeofday(&last_initial_time, NULL) == 0);
1054
1055 finish:
1056         return;
1057
1058 }
1059
1060 void
1061 tracepath_mem_trace_output(int force_output)
1062 {
1063         static struct timeval tv_last = TIMEVAL_INIT;
1064
1065         int i;
1066
1067         if (trace_mem_flag != 1)
1068         {
1069                 goto finish;
1070         }
1071
1072         if (!force_output)
1073         {
1074                 struct timeval tv_now = TIMEVAL_INIT;
1075                 AST(gettimeofday(&tv_now, NULL) == 0);
1076                 if (tv_now.tv_sec - tv_last.tv_sec < _COREGL_TRACE_OUTPUT_INTERVAL_SEC)
1077                 {
1078                         goto finish;
1079                 }
1080                 tv_last = tv_now;
1081         }
1082
1083         TRACE("\n");
1084         TRACE("\E[40;34m========================================================================================================================\E[0m\n");
1085         TRACE("\E[40;32;1m  Memory usage info \E[1;37;1m: <PID = %d>\E[0m\n", getpid());
1086         TRACE("\E[40;34m========================================================================================================================\E[0m\n");
1087
1088         if (mtd_table != NULL)
1089         {
1090                 for (i = 0; i < MAX_TRACE_TABLE_SIZE; i++)
1091                 {
1092                         if (mtd_table[i] != NULL)
1093                         {
1094                                 Memuse_Data *current = mtd_table[i];
1095
1096                                 while (current != NULL)
1097                                 {
1098                                         int obj_count = current->alloc_count - current->remove_count;
1099                                         if (obj_count > 0)
1100                                         {
1101                                                 TRACE("\E[40;37;1m %-46.46s : %12d byte(s)(E), %9d object(s) [%9d+/%9d-]\E[0m\n",
1102                                                       current->trace_data.name, current->memsize, obj_count, current->alloc_count, current->remove_count);
1103                                         }
1104                                         current = (Memuse_Data *)current->trace_data.next;
1105                                 }
1106                         }
1107                 }
1108
1109                 for (i = 0; i < MAX_TRACE_TABLE_SIZE; i++)
1110                 {
1111                         if (mtd_table[i] != NULL)
1112                         {
1113                                 Memuse_Data *current = mtd_table[i];
1114
1115                                 while (current != NULL)
1116                                 {
1117                                         int obj_count = current->alloc_count - current->remove_count;
1118                                         if (obj_count == 0)
1119                                         {
1120                                                 TRACE(" %-46.46s : %12d byte(s)(E), %9d object(s) [%9d+/%9d-]\n",
1121                                                       current->trace_data.name, current->memsize, obj_count, current->alloc_count, current->remove_count);
1122                                         }
1123                                         current = (Memuse_Data *)current->trace_data.next;
1124                                 }
1125                         }
1126                 }
1127         }
1128
1129         TRACE("\E[40;34m========================================================================================================================\E[0m\n");
1130         TRACE("\n");
1131
1132         TRACE_END();
1133
1134         goto finish;
1135
1136 finish:
1137         return;
1138 }
1139
1140 #include "png.h"
1141
1142 void *png_lib_handle = NULL;
1143
1144 png_structp (*dl_png_create_write_struct) (png_const_charp user_png_ver,
1145                                               png_voidp error_ptr,
1146                                               png_error_ptr error_fn,
1147                                               png_error_ptr warn_fn);
1148
1149
1150 void (*dl_png_destroy_write_struct) (png_structpp png_ptr_ptr,
1151                                         png_infopp info_ptr_ptr);
1152
1153
1154 png_infop (*dl_png_create_info_struct) (png_structp png_ptr);
1155
1156 void (*dl_png_init_io) (png_structp png_ptr,
1157                           png_FILE_p fp);
1158
1159
1160 void (*dl_png_set_IHDR) (png_structp png_ptr,
1161                            png_infop info_ptr,
1162                            png_uint_32 width,
1163                            png_uint_32 height,
1164                            int bit_depth,
1165                            int color_type,
1166                            int interlace_method,
1167                            int compression_method,
1168                            int filter_method);
1169
1170 void (*dl_png_set_bKGD) (png_structp png_ptr,
1171                            png_infop info_ptr,
1172                            png_color_16p background);
1173
1174 void (*dl_png_set_bgr) (png_structp png_ptr);
1175
1176 void (*dl_png_write_info) (png_structp png_ptr,
1177                              png_infop info_ptr);
1178
1179 void (*dl_png_write_image) (png_structp png_ptr,
1180                               png_bytepp image);
1181
1182 void (*dl_png_write_end) (png_structp png_ptr,
1183                             png_infop info_ptr);
1184
1185 static void
1186 _dump_surface(int force_output, int type, const char *position, Surface_Data *sdata)
1187 {
1188         static int alldumpcount = 0;
1189         unsigned char *data = NULL;
1190         EGLint width = -1, height = -1, channel = -1;
1191         char name[200];
1192         FILE *write_fd = NULL;
1193         png_struct *png = NULL;
1194         png_info *info = NULL;
1195         png_byte **rows = NULL;
1196
1197         if (!png_lib_handle)
1198         {
1199                 png_lib_handle = dlopen("libpng.so.3", RTLD_NOW);
1200
1201                 dl_png_create_write_struct = dlsym(png_lib_handle, "png_create_write_struct");
1202                 dl_png_destroy_write_struct = dlsym(png_lib_handle, "png_destroy_write_struct");
1203                 dl_png_create_info_struct = dlsym(png_lib_handle, "png_create_info_struct");
1204
1205                 dl_png_init_io = dlsym(png_lib_handle, "png_init_io");
1206
1207                 dl_png_set_IHDR = dlsym(png_lib_handle, "png_set_IHDR");
1208                 dl_png_set_bKGD = dlsym(png_lib_handle, "png_set_bKGD");
1209                 dl_png_set_bgr = dlsym(png_lib_handle, "png_set_bgr");
1210
1211                 dl_png_write_info = dlsym(png_lib_handle, "png_write_info");
1212                 dl_png_write_image = dlsym(png_lib_handle, "png_write_image");
1213                 dl_png_write_end = dlsym(png_lib_handle, "png_write_end");
1214         }
1215
1216         {
1217                 if (!png_lib_handle ||
1218                     dl_png_create_write_struct == NULL ||
1219                     dl_png_destroy_write_struct == NULL ||
1220                     dl_png_create_info_struct == NULL ||
1221                     dl_png_init_io == NULL ||
1222                     dl_png_set_IHDR == NULL ||
1223                     dl_png_set_bKGD == NULL ||
1224                     dl_png_set_bgr == NULL ||
1225                     dl_png_write_info == NULL ||
1226                     dl_png_write_image == NULL ||
1227                     dl_png_write_end == NULL)
1228                 {
1229                         COREGL_ERR("Can't trace surface : Failed to use libpng (recommend : 1.2.50-3.4)");
1230                         goto finish;
1231                 }
1232
1233                 if (trace_surface_sequence_sort_flag == 1)
1234                         snprintf(name,sizeof(name), "[%d (%06d)%p-%p] %s %04d (%s).png", getpid(), alldumpcount, sdata->display, sdata->context, sdata->trace_data.name, sdata->dump_count, position);
1235                 else
1236                         snprintf(name,sizeof(name), "[%d %p-%p] %s %04d (%s).png", getpid(), sdata->display, sdata->context, sdata->trace_data.name, sdata->dump_count, position);
1237
1238                 if (!strncmp(sdata->trace_data.name, "EGL", 3) && type != 2)
1239                 { // EGL
1240                         if (trace_surface_filter_type != 0 &&
1241                             trace_surface_filter_type != 1) goto finish;;
1242
1243                         if (trace_surface_filter_handle != 0 &&
1244                             trace_surface_filter_handle != (int)sdata->surface) goto finish;
1245
1246                         EGLConfig eglconfig;
1247                         GLint asize, rsize, gsize, bsize;
1248                         _orig_tracepath_eglQuerySurface(sdata->display, sdata->surface, EGL_WIDTH, &width);
1249                         _orig_tracepath_eglQuerySurface(sdata->display, sdata->surface, EGL_HEIGHT, &height);
1250                         _orig_tracepath_eglQuerySurface(sdata->display, sdata->surface, EGL_CONFIG_ID, (GLint *)&eglconfig);
1251                         _orig_tracepath_eglGetConfigAttrib(sdata->display, eglconfig, EGL_ALPHA_SIZE, &asize);
1252                         _orig_tracepath_eglGetConfigAttrib(sdata->display, eglconfig, EGL_RED_SIZE, &rsize);
1253                         _orig_tracepath_eglGetConfigAttrib(sdata->display, eglconfig, EGL_GREEN_SIZE, &gsize);
1254                         _orig_tracepath_eglGetConfigAttrib(sdata->display, eglconfig, EGL_BLUE_SIZE, &bsize);
1255                         channel = 4;
1256                         if (asize == 0) channel = 3;
1257                         if (bsize == 0) channel = 2;
1258                         if (gsize == 0) channel = 1;
1259                         if (rsize == 0) channel = 0;
1260
1261                         if (channel == 2) channel = 3;
1262                         if (width <= 0 || height <= 0 || channel <= 0) goto finish;
1263                         if (trace_surface_filter_size_w > 0 && trace_surface_filter_size_h > 0 &&
1264                             (trace_surface_filter_size_w != width || trace_surface_filter_size_h != height))
1265                                 goto finish;
1266
1267                         if ((trace_surface_filter_period_begin > 0 || trace_surface_filter_period_end > 0) &&
1268                             (trace_surface_filter_period_begin > alldumpcount || trace_surface_filter_period_end < alldumpcount))
1269                         {
1270                                 alldumpcount++;
1271                                 sdata->dump_count++;
1272                                 goto finish;
1273                         }
1274
1275                         if (channel == 3) channel = 4;
1276
1277                         TRACE("\E[40;31;1m[[TRACE SURFACE]] : '%s' is dumped (%dx%dx%d).\E[0m\n", name, width, height, channel);
1278                         if (trace_surface_print_only_flag == 1 && force_output == 0)
1279                         {
1280                                 alldumpcount++;
1281                                 sdata->dump_count++;
1282                                 goto finish;
1283                         }
1284
1285                         data = (unsigned char *)calloc(1, width * height * channel * sizeof(unsigned char));
1286                         if (data == NULL)
1287                         {
1288                                 COREGL_ERR("Can't trace surface : Failed to allocate memory");
1289                                 goto finish;
1290                         }
1291
1292                         GLint oldfb;
1293                         _orig_tracepath_glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldfb);
1294                         _orig_tracepath_glBindFramebuffer(GL_FRAMEBUFFER, 0);
1295
1296                         switch (channel)
1297                         {
1298                                 case 4: _orig_tracepath_glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data); break;
1299                                 //case 3: _orig_tracepath_glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, data); break;
1300                                 case 1: _orig_tracepath_glReadPixels(0, 0, width, height, GL_ALPHA, GL_UNSIGNED_BYTE, data); break;
1301                         }
1302
1303                         _orig_tracepath_glBindFramebuffer(GL_FRAMEBUFFER, oldfb);
1304                 }
1305                 if (!strncmp(sdata->trace_data.name, "FBO", 3) && type != 1)
1306                 { // FBO
1307                         if (sdata->fbo == 0) goto finish;
1308
1309                         if (trace_surface_filter_type != 0 &&
1310                             trace_surface_filter_type != 2) goto finish;
1311
1312                         if (trace_surface_filter_handle != 0 &&
1313                             trace_surface_filter_handle != sdata->tex &&
1314                             trace_surface_filter_handle != sdata->rb) goto finish;
1315
1316                         GLint oldfb;
1317                         _orig_tracepath_glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldfb);
1318                         _orig_tracepath_glBindFramebuffer(GL_FRAMEBUFFER, sdata->fbo);
1319
1320                         if (_orig_tracepath_glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE)
1321                         {
1322                                 _orig_tracepath_glBindFramebuffer(GL_FRAMEBUFFER, oldfb);
1323                                 width = sdata->tex_w;
1324                                 height = sdata->tex_h;
1325                                 channel = sdata->tex_format;
1326
1327                                 if (channel == 2) channel = 3;
1328                                 if (width <= 0 || height <= 0 || channel <= 0) goto finish;
1329                                 if (trace_surface_filter_size_w > 0 && trace_surface_filter_size_h > 0 &&
1330                                     (trace_surface_filter_size_w != width || trace_surface_filter_size_h != height))
1331                                         goto finish;
1332
1333                                 if ((trace_surface_filter_period_begin > 0 || trace_surface_filter_period_end > 0) &&
1334                                     (trace_surface_filter_period_begin > alldumpcount || trace_surface_filter_period_end < alldumpcount))
1335                                 {
1336                                         alldumpcount++;
1337                                         sdata->dump_count++;
1338                                         goto finish;
1339                                 }
1340
1341                                 TRACE("\E[40;31;1m[[TRACE SURFACE]] : '%s' is dumped (%dx%dx%d).\E[0m\n", name, width, height, channel);
1342                                 if (trace_surface_print_only_flag == 1 && force_output == 0)
1343                                 {
1344                                         alldumpcount++;
1345                                         sdata->dump_count++;
1346                                         goto finish;
1347                                 }
1348
1349                                 if (channel == 3) channel = 4;
1350
1351                                 data = (unsigned char *)calloc(1, width * height * channel * sizeof(unsigned char));
1352                                 if (data == NULL)
1353                                 {
1354                                         COREGL_ERR("Can't trace surface : Failed to allocate memory");
1355                                         goto finish;
1356                                 }
1357
1358                                 _orig_tracepath_glBindFramebuffer(GL_FRAMEBUFFER, sdata->fbo);
1359                                 int atttype = _COREGL_INT_INIT_VALUE;
1360                            _orig_tracepath_glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &atttype);
1361                                 AST(atttype != sdata->tex);
1362                                 int attname = _COREGL_INT_INIT_VALUE;
1363                            _orig_tracepath_glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &attname);
1364                                 switch (atttype)
1365                                 {
1366                                         case GL_TEXTURE:
1367                                                 AST(attname == sdata->tex);
1368                                                 break;
1369                                         case GL_RENDERBUFFER:
1370                                                 AST(attname == sdata->rb);
1371                                                 break;
1372                                 }
1373
1374                                 switch (channel)
1375                                 {
1376                                         case 4: _orig_tracepath_glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data); break;
1377                                         //case 3: _orig_tracepath_glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, data); break;
1378                                         case 1: _orig_tracepath_glReadPixels(0, 0, width, height, GL_ALPHA, GL_UNSIGNED_BYTE, data); break;
1379                                 }
1380                         }
1381                         _orig_tracepath_glBindFramebuffer(GL_FRAMEBUFFER, oldfb);
1382                 }
1383
1384
1385
1386                 if (data == NULL) goto finish;
1387
1388                 unlink(name);
1389                 write_fd = fopen(name, "wb");
1390
1391                 if (write_fd == NULL)
1392                 {
1393                         COREGL_ERR("Can't trace surface : Failed to create png file");
1394                         goto finish;
1395                 }
1396
1397                 rows = (png_byte **)malloc(height * sizeof(png_byte *));
1398                 if (rows == NULL)
1399                 {
1400                         COREGL_ERR("Can't trace surface : Failed to allocate memory");
1401                         goto finish;
1402                 }
1403
1404                 for (int i = 0; i < height; i++)
1405                 {
1406                         rows[i] = data + (height - i - 1) * (width * channel);
1407                 }
1408
1409                 png = dl_png_create_write_struct(PNG_LIBPNG_VER_STRING,
1410                                                  NULL,
1411                                                  NULL,
1412                                                  NULL);
1413                 if (png == NULL)
1414                 {
1415                         COREGL_ERR("Can't trace surface : Failed to create write structure of png file");
1416                         goto finish;
1417                 }
1418
1419                 info = dl_png_create_info_struct(png);
1420                 if (info == NULL)
1421                 {
1422                         COREGL_ERR("Can't trace surface : Failed to create info structure of png file");
1423                         goto finish;
1424                 }
1425
1426                 dl_png_init_io(png, write_fd);
1427
1428                 switch (channel)
1429                 {
1430                         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;
1431                         //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;
1432                         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;
1433                 }
1434
1435                 dl_png_write_info(png, info);
1436
1437                 dl_png_write_image(png, rows);
1438
1439                 dl_png_write_end(png, info);
1440
1441                 dl_png_destroy_write_struct(&png, &info);
1442
1443                 alldumpcount++;
1444                 sdata->dump_count++;
1445         }
1446
1447         goto finish;
1448
1449 finish:
1450         if (data != NULL)
1451         {
1452                 free(data);
1453                 data = NULL;
1454         }
1455         if (write_fd != NULL)
1456         {
1457                 fclose(write_fd);
1458                 write_fd = NULL;
1459         }
1460         if (rows != NULL)
1461         {
1462                 free(rows);
1463                 rows = NULL;
1464         }
1465         if (png != NULL)
1466         {
1467                 if (info != NULL)
1468                 {
1469                         dl_png_destroy_write_struct(&png, &info);
1470                         info = NULL;
1471                 }
1472                 else
1473                         dl_png_destroy_write_struct(&png, NULL);
1474                 png = NULL;
1475         }
1476 }
1477
1478 void
1479 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)
1480 {
1481         Surface_Data *std = NULL;
1482
1483         if (trace_surface_flag == 1)
1484         {
1485                 AST(mutex_lock(&std_access_mutex) == 1);
1486
1487                 if (std_table == NULL)
1488                 {
1489                         std_table = (Surface_Data **)calloc(1, sizeof(Surface_Data *) * MAX_TRACE_TABLE_SIZE);
1490                 }
1491
1492                 std = (Surface_Data *)_get_trace_data((Trace_Data **)std_table, sizeof(Surface_Data), desc);
1493
1494                 AST(std != NULL);
1495
1496                 if (dump != NULL)
1497                 {
1498                         _dump_surface(0, 0, dump, std);
1499                 }
1500
1501                 std->display = dpy;
1502                 std->surface = surf;
1503                 std->context = ctx;
1504                 if (fbo >= 0) std->fbo = fbo;
1505                 std->tex = tex;
1506                 std->rb = rb;
1507                 if (tex_w >= 0) std->tex_w = tex_w;
1508                 if (tex_h >= 0) std->tex_h = tex_h;
1509                 if (tex_format >= 0) std->tex_format = tex_format;
1510
1511                 AST(mutex_unlock(&std_access_mutex) == 1);
1512
1513         }
1514
1515 }
1516
1517 void
1518 tracepath_surface_trace(int force_output, int type, const char *position)
1519 {
1520         int i;
1521
1522         if (trace_surface_flag != 1)
1523         {
1524                 goto finish;
1525         }
1526
1527         AST(mutex_lock(&std_access_mutex) == 1);
1528
1529         if (std_table != NULL)
1530         {
1531                 EGLDisplay olddpy = _orig_tracepath_eglGetCurrentDisplay();
1532                 EGLContext oldctx = _orig_tracepath_eglGetCurrentContext();
1533                 EGLSurface oldsurf_read = _orig_tracepath_eglGetCurrentSurface(EGL_READ);
1534                 EGLSurface oldsurf_draw = _orig_tracepath_eglGetCurrentSurface(EGL_DRAW);
1535
1536                 for (i = 0; i < MAX_TRACE_TABLE_SIZE; i++)
1537                 {
1538                         if (std_table[i] != NULL)
1539                         {
1540                                 Surface_Data *current = std_table[i];
1541
1542                                 while (current != NULL)
1543                                 {
1544                                         if (current->surface != EGL_NO_SURFACE && current->display != EGL_NO_DISPLAY && current->context != EGL_NO_CONTEXT)
1545                                         {
1546                                                 if (_orig_tracepath_eglMakeCurrent(current->display, current->surface, current->surface, current->context) == EGL_TRUE)
1547                                                 {
1548                                                         _dump_surface(force_output, type, position, current);
1549                                                 }
1550                                         }
1551
1552                                         current = (Surface_Data *)current->trace_data.next;
1553                                 }
1554                         }
1555                 }
1556                 _orig_tracepath_eglMakeCurrent(olddpy, oldsurf_read, oldsurf_draw, oldctx);
1557
1558         }
1559
1560         AST(mutex_unlock(&std_access_mutex) == 1);
1561
1562         goto finish;
1563
1564         finish:
1565                 return;
1566 }
1567
1568
1569 COREGL_API void
1570 coregl_dump_surface()
1571 {
1572         _COREGL_TRACE_SURFACE(1, 0, "USER CALL");
1573 }
1574