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 // ----------------------------------------------------------------------------
33 namespace android {
34 // ----------------------------------------------------------------------------
35
36 struct GLenumString {
37 GLenum e;
38 const char* s;
39 };
40
41 #undef GL_ENUM
42 #define GL_ENUM(VAL,NAME) {VAL, #NAME},
43
44 static GLenumString g_enumnames[] = {
45 #include "enums.in"
46 };
47 #undef GL_ENUM
48
compareGLEnum(const void * a,const void * b)49 static int compareGLEnum(const void* a, const void* b) {
50 return ((const GLenumString*) a)->e - ((const GLenumString*) b)->e;
51 }
52
GLEnumToString(GLenum e)53 static 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
GLbooleanToString(GLboolean arg)65 static const char* GLbooleanToString(GLboolean arg) {
66 return arg ? "GL_TRUE" : "GL_FALSE";
67 }
68
69 static GLenumString g_bitfieldNames[] = {
70 {0x00004000, "GL_COLOR_BUFFER_BIT"},
71 {0x00000400, "GL_STENCIL_BUFFER_BIT"},
72 {0x00000100, "GL_DEPTH_BUFFER_BIT"}
73 };
74
75 class StringBuilder {
76 static const int lineSize = 500;
77 char line[lineSize];
78 int line_index;
79 public:
StringBuilder()80 StringBuilder() {
81 line_index = 0;
82 line[0] = '\0';
83 }
append(const char * fmt,...)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 }
getString()90 const char* getString() {
91 line_index = 0;
92 line[lineSize-1] = '\0';
93 return line;
94 }
95 };
96
97
TraceGLShaderSource(GLuint shader,GLsizei count,const GLchar ** string,const GLint * length)98 static 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
TraceValue(int elementCount,char type,GLsizei chunkCount,GLsizei chunkSize,const void * value)128 static 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
TraceUniformv(int elementCount,char type,GLuint location,GLsizei count,const void * value)164 static 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
TraceUniformMatrix(int matrixSideLength,GLuint location,GLsizei count,GLboolean transpose,const void * value)170 static 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
TraceGL(const char * name,int numArgs,...)177 static 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, ...) \
321 static 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, ...) \
328 static _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
334 extern "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,
342 EGLAPI 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, ...) \
358 static 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, ...) \
365 static _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
371 extern "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,
384 EGLAPI 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