1 /*
2 ** Copyright 2010, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #if EGL_TRACE
18
19 #include <stdarg.h>
20 #include <stdlib.h>
21
22 #include <EGL/egl.h>
23 #include <EGL/eglext.h>
24 #include <GLES/gl.h>
25 #include <GLES/glext.h>
26
27 #include <cutils/log.h>
28
29 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
30 #include <utils/Trace.h>
31
32 #include <utils/CallStack.h>
33
34 #include "egl_tls.h"
35 #include "hooks.h"
36
37 // ----------------------------------------------------------------------------
38 namespace android {
39 // ----------------------------------------------------------------------------
40
41 struct GLenumString {
42 GLenum e;
43 const char* s;
44 };
45
46 #undef GL_ENUM
47 #define GL_ENUM(VAL,NAME) {VAL, #NAME},
48
49 static GLenumString g_enumnames[] = {
50 #include "enums.in"
51 };
52 #undef GL_ENUM
53
compareGLEnum(const void * a,const void * b)54 static int compareGLEnum(const void* a, const void* b) {
55 return ((const GLenumString*) a)->e - ((const GLenumString*) b)->e;
56 }
57
GLEnumToString(GLenum e)58 static const char* GLEnumToString(GLenum e) {
59 GLenumString key = {e, ""};
60 const GLenumString* result = (const GLenumString*) bsearch(
61 &key, g_enumnames,
62 sizeof(g_enumnames) / sizeof(g_enumnames[0]),
63 sizeof(g_enumnames[0]), compareGLEnum);
64 if (result) {
65 return result->s;
66 }
67 return NULL;
68 }
69
GLbooleanToString(GLboolean arg)70 static const char* GLbooleanToString(GLboolean arg) {
71 return arg ? "GL_TRUE" : "GL_FALSE";
72 }
73
74 static GLenumString g_bitfieldNames[] = {
75 {0x00004000, "GL_COLOR_BUFFER_BIT"},
76 {0x00000400, "GL_STENCIL_BUFFER_BIT"},
77 {0x00000100, "GL_DEPTH_BUFFER_BIT"}
78 };
79
80 class StringBuilder {
81 static const int lineSize = 500;
82 char line[lineSize];
83 int line_index;
84 public:
StringBuilder()85 StringBuilder() {
86 line_index = 0;
87 line[0] = '\0';
88 }
append(const char * fmt,...)89 void append(const char* fmt, ...) {
90 va_list argp;
91 va_start(argp, fmt);
92 line_index += vsnprintf(line + line_index, lineSize-line_index, fmt, argp);
93 va_end(argp);
94 }
getString()95 const char* getString() {
96 line_index = 0;
97 line[lineSize-1] = '\0';
98 return line;
99 }
100 };
101
102
TraceGLShaderSource(GLuint shader,GLsizei count,const GLchar ** string,const GLint * length)103 static void TraceGLShaderSource(GLuint shader, GLsizei count,
104 const GLchar** string, const GLint* length) {
105 ALOGD("const char* shaderSrc[] = {");
106 for (GLsizei i = 0; i < count; i++) {
107 const char* comma = i < count-1 ? "," : "";
108 const GLchar* s = string[i];
109 if (length) {
110 GLint len = length[i];
111 ALOGD(" \"%*s\"%s", len, s, comma);
112 } else {
113 ALOGD(" \"%s\"%s", s, comma);
114 }
115 }
116 ALOGD("};");
117 if (length) {
118 ALOGD("const GLint* shaderLength[] = {");
119 for (GLsizei i = 0; i < count; i++) {
120 const char* comma = i < count-1 ? "," : "";
121 GLint len = length[i];
122 ALOGD(" \"%d\"%s", len, comma);
123 }
124 ALOGD("};");
125 ALOGD("glShaderSource(%u, %u, shaderSrc, shaderLength);",
126 shader, count);
127 } else {
128 ALOGD("glShaderSource(%u, %u, shaderSrc, (const GLint*) 0);",
129 shader, count);
130 }
131 }
132
TraceValue(int elementCount,char type,GLsizei chunkCount,GLsizei chunkSize,const void * value)133 static void TraceValue(int elementCount, char type,
134 GLsizei chunkCount, GLsizei chunkSize, const void* value) {
135 StringBuilder stringBuilder;
136 GLsizei count = chunkCount * chunkSize;
137 bool isFloat = type == 'f';
138 const char* typeString = isFloat ? "GLfloat" : "GLint";
139 ALOGD("const %s value[] = {", typeString);
140 for (GLsizei i = 0; i < count; i++) {
141 StringBuilder builder;
142 builder.append(" ");
143 for (int e = 0; e < elementCount; e++) {
144 const char* comma = ", ";
145 if (e == elementCount-1) {
146 if (i == count - 1) {
147 comma = "";
148 } else {
149 comma = ",";
150 }
151 }
152 if (isFloat) {
153 builder.append("%g%s", * (GLfloat*) value, comma);
154 value = (void*) (((GLfloat*) value) + 1);
155 } else {
156 builder.append("%d%s", * (GLint*) value, comma);
157 value = (void*) (((GLint*) value) + 1);
158 }
159 }
160 ALOGD("%s", builder.getString());
161 if (chunkSize > 1 && i < count-1
162 && (i % chunkSize) == (chunkSize-1)) {
163 ALOGD("%s", ""); // Print a blank line.
164 }
165 }
166 ALOGD("};");
167 }
168
TraceUniformv(int elementCount,char type,GLuint location,GLsizei count,const void * value)169 static void TraceUniformv(int elementCount, char type,
170 GLuint location, GLsizei count, const void* value) {
171 TraceValue(elementCount, type, count, 1, value);
172 ALOGD("glUniform%d%c(%u, %u, value);", elementCount, type, location, count);
173 }
174
TraceUniformMatrix(int matrixSideLength,GLuint location,GLsizei count,GLboolean transpose,const void * value)175 static void TraceUniformMatrix(int matrixSideLength,
176 GLuint location, GLsizei count, GLboolean transpose, const void* value) {
177 TraceValue(matrixSideLength, 'f', count, matrixSideLength, value);
178 ALOGD("glUniformMatrix%dfv(%u, %u, %s, value);", matrixSideLength, location, count,
179 GLbooleanToString(transpose));
180 }
181
TraceGL(const char * name,int numArgs,...)182 static void TraceGL(const char* name, int numArgs, ...) {
183 va_list argp;
184 va_start(argp, numArgs);
185 int nameLen = strlen(name);
186
187 // glShaderSource
188 if (nameLen == 14 && strcmp(name, "glShaderSource") == 0) {
189 va_arg(argp, const char*);
190 GLuint shader = va_arg(argp, GLuint);
191 va_arg(argp, const char*);
192 GLsizei count = va_arg(argp, GLsizei);
193 va_arg(argp, const char*);
194 const GLchar** string = (const GLchar**) va_arg(argp, void*);
195 va_arg(argp, const char*);
196 const GLint* length = (const GLint*) va_arg(argp, void*);
197 va_end(argp);
198 TraceGLShaderSource(shader, count, string, length);
199 return;
200 }
201
202 // glUniformXXv
203
204 if (nameLen == 12 && strncmp(name, "glUniform", 9) == 0 && name[11] == 'v') {
205 int elementCount = name[9] - '0'; // 1..4
206 char type = name[10]; // 'f' or 'i'
207 va_arg(argp, const char*);
208 GLuint location = va_arg(argp, GLuint);
209 va_arg(argp, const char*);
210 GLsizei count = va_arg(argp, GLsizei);
211 va_arg(argp, const char*);
212 const void* value = (const void*) va_arg(argp, void*);
213 va_end(argp);
214 TraceUniformv(elementCount, type, location, count, value);
215 return;
216 }
217
218 // glUniformMatrixXfv
219
220 if (nameLen == 18 && strncmp(name, "glUniformMatrix", 15) == 0
221 && name[16] == 'f' && name[17] == 'v') {
222 int matrixSideLength = name[15] - '0'; // 2..4
223 va_arg(argp, const char*);
224 GLuint location = va_arg(argp, GLuint);
225 va_arg(argp, const char*);
226 GLsizei count = va_arg(argp, GLsizei);
227 va_arg(argp, const char*);
228 GLboolean transpose = (GLboolean) va_arg(argp, int);
229 va_arg(argp, const char*);
230 const void* value = (const void*) va_arg(argp, void*);
231 va_end(argp);
232 TraceUniformMatrix(matrixSideLength, location, count, transpose, value);
233 return;
234 }
235
236 StringBuilder builder;
237 builder.append("%s(", name);
238 for (int i = 0; i < numArgs; i++) {
239 if (i > 0) {
240 builder.append(", ");
241 }
242 const char* type = va_arg(argp, const char*);
243 bool isPtr = type[strlen(type)-1] == '*'
244 || strcmp(type, "GLeglImageOES") == 0;
245 if (isPtr) {
246 const void* arg = va_arg(argp, const void*);
247 builder.append("(%s) 0x%08x", type, (size_t) arg);
248 } else if (strcmp(type, "GLbitfield") == 0) {
249 size_t arg = va_arg(argp, size_t);
250 bool first = true;
251 for (size_t i = 0; i < sizeof(g_bitfieldNames) / sizeof(g_bitfieldNames[0]); i++) {
252 const GLenumString* b = &g_bitfieldNames[i];
253 if (b->e & arg) {
254 if (first) {
255 first = false;
256 } else {
257 builder.append(" | ");
258 }
259 builder.append("%s", b->s);
260 arg &= ~b->e;
261 }
262 }
263 if (first || arg != 0) {
264 if (!first) {
265 builder.append(" | ");
266 }
267 builder.append("0x%08x", arg);
268 }
269 } else if (strcmp(type, "GLboolean") == 0) {
270 GLboolean arg = va_arg(argp, int);
271 builder.append("%s", GLbooleanToString(arg));
272 } else if (strcmp(type, "GLclampf") == 0) {
273 double arg = va_arg(argp, double);
274 builder.append("%g", arg);
275 } else if (strcmp(type, "GLenum") == 0) {
276 GLenum arg = va_arg(argp, int);
277 const char* s = GLEnumToString(arg);
278 if (s) {
279 builder.append("%s", s);
280 } else {
281 builder.append("0x%x", arg);
282 }
283 } else if (strcmp(type, "GLfixed") == 0) {
284 int arg = va_arg(argp, int);
285 builder.append("0x%08x", arg);
286 } else if (strcmp(type, "GLfloat") == 0) {
287 double arg = va_arg(argp, double);
288 builder.append("%g", arg);
289 } else if (strcmp(type, "GLint") == 0) {
290 int arg = va_arg(argp, int);
291 const char* s = NULL;
292 if (strcmp(name, "glTexParameteri") == 0) {
293 s = GLEnumToString(arg);
294 }
295 if (s) {
296 builder.append("%s", s);
297 } else {
298 builder.append("%d", arg);
299 }
300 } else if (strcmp(type, "GLintptr") == 0) {
301 int arg = va_arg(argp, unsigned int);
302 builder.append("%u", arg);
303 } else if (strcmp(type, "GLsizei") == 0) {
304 int arg = va_arg(argp, size_t);
305 builder.append("%u", arg);
306 } else if (strcmp(type, "GLsizeiptr") == 0) {
307 int arg = va_arg(argp, size_t);
308 builder.append("%u", arg);
309 } else if (strcmp(type, "GLuint") == 0) {
310 int arg = va_arg(argp, unsigned int);
311 builder.append("%u", arg);
312 } else {
313 builder.append("/* ??? %s */", type);
314 break;
315 }
316 }
317 builder.append(");");
318 ALOGD("%s", builder.getString());
319 va_end(argp);
320 }
321
322 ///////////////////////////////////////////////////////////////////////////
323 // Log trace
324 ///////////////////////////////////////////////////////////////////////////
325
326 #undef TRACE_GL_VOID
327 #undef TRACE_GL
328
329 #define TRACE_GL_VOID(_api, _args, _argList, ...) \
330 static void Tracing_ ## _api _args { \
331 TraceGL(#_api, __VA_ARGS__); \
332 gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl; \
333 _c->_api _argList; \
334 }
335
336 #define TRACE_GL(_type, _api, _args, _argList, ...) \
337 static _type Tracing_ ## _api _args { \
338 TraceGL(#_api, __VA_ARGS__); \
339 gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl; \
340 return _c->_api _argList; \
341 }
342
343 extern "C" {
344 #include "../trace.in"
345 }
346
347 #undef TRACE_GL_VOID
348 #undef TRACE_GL
349
350 #define GL_ENTRY(_r, _api, ...) Tracing_ ## _api,
351 EGLAPI gl_hooks_t gHooksTrace = {
352 {
353 #include "entries.in"
354 },
355 {
356 {0}
357 }
358 };
359 #undef GL_ENTRY
360
361 #undef TRACE_GL_VOID
362 #undef TRACE_GL
363
364 // define the ES 1.0 Debug_gl* functions as Tracing_gl functions
365 #define TRACE_GL_VOID(_api, _args, _argList, ...) \
366 static void Debug_ ## _api _args { \
367 TraceGL(#_api, __VA_ARGS__); \
368 gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl; \
369 _c->_api _argList; \
370 }
371
372 #define TRACE_GL(_type, _api, _args, _argList, ...) \
373 static _type Debug_ ## _api _args { \
374 TraceGL(#_api, __VA_ARGS__); \
375 gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl; \
376 return _c->_api _argList; \
377 }
378
379 extern "C" {
380 #include "../debug.in"
381 }
382
383 ///////////////////////////////////////////////////////////////////////////
384 // Systrace
385 ///////////////////////////////////////////////////////////////////////////
386
387 #undef TRACE_GL_VOID
388 #undef TRACE_GL
389
390 #define TRACE_GL_VOID(_api, _args, _argList, ...) \
391 static void Systrace_ ## _api _args { \
392 ATRACE_NAME(#_api); \
393 gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl; \
394 _c->_api _argList; \
395 }
396
397 #define TRACE_GL(_type, _api, _args, _argList, ...) \
398 static _type Systrace_ ## _api _args { \
399 ATRACE_NAME(#_api); \
400 gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl; \
401 return _c->_api _argList; \
402 }
403
404 extern "C" {
405 #include "../trace.in"
406 }
407
408 #undef TRACE_GL_VOID
409 #undef TRACE_GL
410
411 #define GL_ENTRY(_r, _api, ...) Systrace_ ## _api,
412 EGLAPI gl_hooks_t gHooksSystrace = {
413 {
414 #include "entries.in"
415 },
416 {
417 {0}
418 }
419 };
420 #undef GL_ENTRY
421
422 ///////////////////////////////////////////////////////////////////////////
423 //
424 ///////////////////////////////////////////////////////////////////////////
425
426 #undef TRACE_GL_VOID
427 #undef TRACE_GL
428
429 #define CHECK_ERROR(_c, _api) \
430 GLenum status = GL_NO_ERROR; \
431 bool error = false; \
432 while ((status = _c->glGetError()) != GL_NO_ERROR) { \
433 ALOGD("[" #_api "] 0x%x", status); \
434 error = true; \
435 } \
436 if (error) { \
437 CallStack s; \
438 s.update(); \
439 s.dump("glGetError:" #_api); \
440 } \
441
442 #define TRACE_GL_VOID(_api, _args, _argList, ...) \
443 static void ErrorTrace_ ## _api _args { \
444 gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl; \
445 _c->_api _argList; \
446 CHECK_ERROR(_c, _api); \
447 }
448
449 #define TRACE_GL(_type, _api, _args, _argList, ...) \
450 static _type ErrorTrace_ ## _api _args { \
451 gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl; \
452 _type _r = _c->_api _argList; \
453 CHECK_ERROR(_c, _api); \
454 return _r; \
455 }
456
457 extern "C" {
458 #include "../trace.in"
459 }
460
461 #undef TRACE_GL_VOID
462 #undef TRACE_GL
463
464 #define GL_ENTRY(_r, _api, ...) ErrorTrace_ ## _api,
465 EGLAPI gl_hooks_t gHooksErrorTrace = {
466 {
467 #include "entries.in"
468 },
469 {
470 {0}
471 }
472 };
473 #undef GL_ENTRY
474 #undef CHECK_ERROR
475
476 #undef TRACE_GL_VOID
477 #undef TRACE_GL
478
479 // ----------------------------------------------------------------------------
480 }; // namespace android
481 // ----------------------------------------------------------------------------
482
483 #endif // EGL_TRACE
484