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