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