trace.cpp 15 KB

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