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