1 /*
2 * Copyright 2011, 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 #include <cutils/log.h>
18 #include <EGL/egldefs.h>
19 #include <GLES/gl.h>
20 #include <GLES/glext.h>
21 #include <GLES2/gl2.h>
22 #include <GLES2/gl2ext.h>
23
24 #include "gltrace.pb.h"
25 #include "gltrace_api.h"
26 #include "gltrace_context.h"
27 #include "gltrace_fixup.h"
28
29 namespace android {
30 namespace gltrace {
31
getBytesPerTexel(const GLenum format,const GLenum type)32 unsigned getBytesPerTexel(const GLenum format, const GLenum type) {
33 /*
34 Description from glTexImage2D spec:
35
36 Data is read from data as a sequence of unsigned bytes or shorts, depending on type.
37 When type is GL_UNSIGNED_BYTE, each of the bytes is interpreted as one color component.
38 When type is one of GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_4_4_4_4, or
39 GL_UNSIGNED_SHORT_5_5_5_1, each unsigned short value is interpreted as containing all
40 the components for a single texel, with the color components arranged according to
41 format. Color components are treated as groups of one, two, three, or four values,
42 again based on format. Groups of components are referred to as texels.
43
44 width × height texels are read from memory, starting at location data. By default,
45 these texels are taken from adjacent memory locations, except that after all width
46 texels are read, the read pointer is advanced to the next four-byte boundary.
47 The four-byte row alignment is specified by glPixelStorei with argument
48 GL_UNPACK_ALIGNMENT, and it can be set to one, two, four, or eight bytes.
49 */
50
51 switch (type) {
52 case GL_UNSIGNED_SHORT_5_6_5:
53 case GL_UNSIGNED_SHORT_4_4_4_4:
54 case GL_UNSIGNED_SHORT_5_5_5_1:
55 return 2;
56 case GL_UNSIGNED_BYTE:
57 break;
58 default:
59 ALOGE("GetBytesPerPixel: unknown type %x", type);
60 }
61
62 switch (format) {
63 case GL_ALPHA:
64 case GL_LUMINANCE:
65 return 1;
66 case GL_LUMINANCE_ALPHA:
67 return 2;
68 case GL_RGB:
69 return 3;
70 case GL_RGBA:
71 case 0x80E1: // GL_BGRA_EXT
72 return 4;
73 default:
74 ALOGE("GetBytesPerPixel: unknown format %x", format);
75 }
76
77 return 1; // in doubt...
78 }
79
fixup_GenericFloatArray(int argIndex,int nFloats,GLMessage * glmsg,void * src)80 void fixup_GenericFloatArray(int argIndex, int nFloats, GLMessage *glmsg, void *src) {
81 GLMessage_DataType *arg_floatarray = glmsg->mutable_args(argIndex);
82 GLfloat *floatp = (GLfloat *)src;
83
84 if (floatp == NULL) {
85 return;
86 }
87
88 arg_floatarray->set_type(GLMessage::DataType::FLOAT);
89 arg_floatarray->set_isarray(true);
90 arg_floatarray->clear_floatvalue();
91
92 for (int i = 0; i < nFloats; i++, floatp++) {
93 arg_floatarray->add_floatvalue(*floatp);
94 }
95 }
96
fixup_GenericIntArray(int argIndex,int nInts,GLMessage * glmsg,void * src)97 void fixup_GenericIntArray(int argIndex, int nInts, GLMessage *glmsg, void *src) {
98 GLMessage_DataType *arg_intarray = glmsg->mutable_args(argIndex);
99 GLint *intp = (GLint *)src;
100
101 if (intp == NULL) {
102 return;
103 }
104
105 arg_intarray->set_type(GLMessage::DataType::INT);
106 arg_intarray->set_isarray(true);
107 arg_intarray->clear_intvalue();
108
109 for (int i = 0; i < nInts; i++, intp++) {
110 arg_intarray->add_intvalue(*intp);
111 }
112 }
113
fixup_GenericEnumArray(int argIndex,int nEnums,GLMessage * glmsg,void * src)114 void fixup_GenericEnumArray(int argIndex, int nEnums, GLMessage *glmsg, void *src) {
115 // fixup as if they were ints
116 fixup_GenericIntArray(argIndex, nEnums, glmsg, src);
117
118 // and then set the data type to be enum
119 GLMessage_DataType *arg_enumarray = glmsg->mutable_args(argIndex);
120 arg_enumarray->set_type(GLMessage::DataType::ENUM);
121 }
122
123 /** Generic helper function: extract pointer at argIndex and
124 replace it with the C style string at *pointer */
fixup_CStringPtr(int argIndex,GLMessage * glmsg,void * src)125 void fixup_CStringPtr(int argIndex, GLMessage *glmsg, void *src) {
126 GLMessage_DataType *arg = glmsg->mutable_args(argIndex);
127 GLchar *ptr = (GLchar *) src;
128
129 arg->set_type(GLMessage::DataType::CHAR);
130 arg->set_isarray(true);
131 arg->add_charvalue(ptr);
132 }
133
fixup_glGetString(GLMessage * glmsg,void * pointersToFixup[])134 void fixup_glGetString(GLMessage *glmsg, void *pointersToFixup[]) {
135 /* const GLubyte* GLTrace_glGetString(GLenum name) */
136 GLMessage_DataType *ret = glmsg->mutable_returnvalue();
137 GLchar *ptr = (GLchar *) pointersToFixup[0];
138
139 if (ptr != NULL) {
140 ret->set_type(GLMessage::DataType::CHAR);
141 ret->set_isarray(true);
142 ret->add_charvalue(ptr);
143 }
144 }
145
146 /* Add the contents of the framebuffer to the protobuf message */
fixup_addFBContents(GLTraceContext * context,GLMessage * glmsg,FBBinding fbToRead)147 void fixup_addFBContents(GLTraceContext *context, GLMessage *glmsg, FBBinding fbToRead) {
148 void *fbcontents;
149 unsigned fbsize, fbwidth, fbheight;
150 context->getCompressedFB(&fbcontents, &fbsize, &fbwidth, &fbheight, fbToRead);
151
152 GLMessage_FrameBuffer *fb = glmsg->mutable_fb();
153 fb->set_width(fbwidth);
154 fb->set_height(fbheight);
155 fb->add_contents(fbcontents, fbsize);
156 }
157
158 /** Common fixup routing for glTexImage2D & glTexSubImage2D. */
fixup_glTexImage(int widthIndex,int heightIndex,GLMessage * glmsg,void * dataSrc)159 void fixup_glTexImage(int widthIndex, int heightIndex, GLMessage *glmsg, void *dataSrc) {
160 GLMessage_DataType arg_width = glmsg->args(widthIndex);
161 GLMessage_DataType arg_height = glmsg->args(heightIndex);
162
163 GLMessage_DataType arg_format = glmsg->args(6);
164 GLMessage_DataType arg_type = glmsg->args(7);
165 GLMessage_DataType *arg_data = glmsg->mutable_args(8);
166
167 GLsizei width = arg_width.intvalue(0);
168 GLsizei height = arg_height.intvalue(0);
169 GLenum format = arg_format.intvalue(0);
170 GLenum type = arg_type.intvalue(0);
171 void *data = (void *) dataSrc;
172
173 int bytesPerTexel = getBytesPerTexel(format, type);
174
175 arg_data->set_type(GLMessage::DataType::BYTE);
176 arg_data->clear_rawbytes();
177
178 if (data != NULL) {
179 arg_data->set_isarray(true);
180 arg_data->add_rawbytes(data, bytesPerTexel * width * height);
181 } else {
182 arg_data->set_isarray(false);
183 arg_data->set_type(GLMessage::DataType::VOID);
184 }
185 }
186
187
fixup_glTexImage2D(GLMessage * glmsg,void * pointersToFixup[])188 void fixup_glTexImage2D(GLMessage *glmsg, void *pointersToFixup[]) {
189 /* void glTexImage2D(GLenum target,
190 GLint level,
191 GLint internalformat,
192 GLsizei width,
193 GLsizei height,
194 GLint border,
195 GLenum format,
196 GLenum type,
197 const GLvoid *data);
198 */
199 int widthIndex = 3;
200 int heightIndex = 4;
201 fixup_glTexImage(widthIndex, heightIndex, glmsg, pointersToFixup[0]);
202 }
203
fixup_glTexSubImage2D(GLMessage * glmsg,void * pointersToFixup[])204 void fixup_glTexSubImage2D(GLMessage *glmsg, void *pointersToFixup[]) {
205 /*
206 void glTexSubImage2D(GLenum target,
207 GLint level,
208 GLint xoffset,
209 GLint yoffset,
210 GLsizei width,
211 GLsizei height,
212 GLenum format,
213 GLenum type,
214 const GLvoid * data);
215 */
216 int widthIndex = 4;
217 int heightIndex = 5;
218 fixup_glTexImage(widthIndex, heightIndex, glmsg, pointersToFixup[0]);
219 }
220
fixup_glShaderSource(GLMessage * glmsg,void * pointersToFixup[])221 void fixup_glShaderSource(GLMessage *glmsg, void *pointersToFixup[]) {
222 /* void glShaderSource(GLuint shader, GLsizei count, const GLchar** string,
223 const GLint* length) */
224 GLMessage_DataType arg_count = glmsg->args(1);
225 GLMessage_DataType arg_lenp = glmsg->args(3);
226 GLMessage_DataType *arg_strpp = glmsg->mutable_args(2);
227
228 GLsizei count = arg_count.intvalue(0);
229 GLchar **stringpp = (GLchar **) pointersToFixup[0];
230 GLint *lengthp = (GLint *) pointersToFixup[1];
231
232 arg_strpp->set_type(GLMessage::DataType::CHAR);
233 arg_strpp->set_isarray(true);
234 arg_strpp->clear_charvalue();
235
236 ::std::string src = "";
237 for (int i = 0; i < count; i++) {
238 if (lengthp != NULL)
239 src.append(*stringpp, *lengthp);
240 else
241 src.append(*stringpp); // assume null terminated
242 stringpp++;
243 lengthp++;
244 }
245
246 arg_strpp->add_charvalue(src);
247 }
248
fixup_glUniformGenericInteger(int argIndex,int nIntegers,GLMessage * glmsg,void * pointersToFixup[])249 void fixup_glUniformGenericInteger(int argIndex, int nIntegers, GLMessage *glmsg,
250 void *pointersToFixup[]) {
251 /* void glUniform?iv(GLint location, GLsizei count, const GLint *value); */
252 fixup_GenericIntArray(argIndex, nIntegers, glmsg, pointersToFixup[0]);
253 }
254
fixup_glUniformGeneric(int argIndex,int nFloats,GLMessage * glmsg,void * src)255 void fixup_glUniformGeneric(int argIndex, int nFloats, GLMessage *glmsg, void *src) {
256 fixup_GenericFloatArray(argIndex, nFloats, glmsg, src);
257 }
258
fixup_glUniformMatrixGeneric(int matrixSize,GLMessage * glmsg,void * pointersToFixup[])259 void fixup_glUniformMatrixGeneric(int matrixSize, GLMessage *glmsg, void *pointersToFixup[]) {
260 /* void glUniformMatrix?fv(GLint location, GLsizei count, GLboolean transpose,
261 const GLfloat* value) */
262 GLMessage_DataType arg_count = glmsg->args(1);
263 int n_matrices = arg_count.intvalue(0);
264 fixup_glUniformGeneric(3, matrixSize * matrixSize * n_matrices, glmsg, pointersToFixup[0]);
265 }
266
fixup_glGenGeneric(GLMessage * glmsg,void * pointersToFixup[])267 void fixup_glGenGeneric(GLMessage *glmsg, void *pointersToFixup[]) {
268 /* void glGen*(GLsizei n, GLuint * buffers); */
269 GLMessage_DataType arg_n = glmsg->args(0);
270 GLsizei n = arg_n.intvalue(0);
271
272 fixup_GenericIntArray(1, n, glmsg, pointersToFixup[0]);
273 }
274
fixup_glDeleteGeneric(GLMessage * glmsg,void * pointersToFixup[])275 void fixup_glDeleteGeneric(GLMessage *glmsg, void *pointersToFixup[]) {
276 /* void glDelete*(GLsizei n, GLuint *buffers); */
277 GLMessage_DataType arg_n = glmsg->args(0);
278 GLsizei n = arg_n.intvalue(0);
279
280 fixup_GenericIntArray(1, n, glmsg, pointersToFixup[0]);
281 }
282
fixup_glGetBooleanv(GLMessage * glmsg,void * pointersToFixup[])283 void fixup_glGetBooleanv(GLMessage *glmsg, void *pointersToFixup[]) {
284 /* void glGetBooleanv(GLenum pname, GLboolean *params); */
285 GLMessage_DataType *arg_params = glmsg->mutable_args(1);
286 GLboolean *src = (GLboolean*) pointersToFixup[0];
287
288 arg_params->set_type(GLMessage::DataType::BOOL);
289 arg_params->set_isarray(true);
290 arg_params->clear_boolvalue();
291 arg_params->add_boolvalue(*src);
292 }
293
fixup_glGetFloatv(GLMessage * glmsg,void * pointersToFixup[])294 void fixup_glGetFloatv(GLMessage *glmsg, void *pointersToFixup[]) {
295 /* void glGetFloatv(GLenum pname, GLfloat *params); */
296 GLMessage_DataType *arg_params = glmsg->mutable_args(1);
297 GLfloat *src = (GLfloat*) pointersToFixup[0];
298
299 arg_params->set_type(GLMessage::DataType::FLOAT);
300 arg_params->set_isarray(true);
301 arg_params->clear_floatvalue();
302 arg_params->add_floatvalue(*src);
303 }
304
fixup_glLinkProgram(GLMessage * glmsg)305 void fixup_glLinkProgram(GLMessage *glmsg) {
306 /* void glLinkProgram(GLuint program); */
307 GLuint program = glmsg->args(0).intvalue(0);
308
309 /* We don't have to fixup this call, but as soon as a program is linked,
310 we obtain information about all active attributes and uniforms to
311 pass on to the debugger. Note that in order to pass this info to
312 the debugger, all we need to do is call the trace versions of the
313 necessary calls. */
314
315 GLint n, maxNameLength;
316 GLchar *name;
317 GLint size;
318 GLenum type;
319
320 // obtain info regarding active attributes
321 GLTrace_glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &n);
322 GLTrace_glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxNameLength);
323
324 name = (GLchar *) malloc(maxNameLength);
325 for (int i = 0; i < n; i++) {
326 GLTrace_glGetActiveAttrib(program, i, maxNameLength, NULL, &size, &type, name);
327 }
328 free(name);
329
330 // obtain info regarding active uniforms
331 GLTrace_glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &n);
332 GLTrace_glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxNameLength);
333
334 name = (GLchar *) malloc(maxNameLength);
335 for (int i = 0; i < n; i++) {
336 GLTrace_glGetActiveUniform(program, i, maxNameLength, NULL, &size, &type, name);
337 }
338 free(name);
339 }
340
341 /** Given a glGetActive[Uniform|Attrib] call, obtain the location
342 * of the variable of given name in the call.
343 */
getShaderVariableLocation(GLTraceContext * context,GLMessage * glmsg,GLchar * name)344 int getShaderVariableLocation(GLTraceContext *context, GLMessage *glmsg, GLchar *name) {
345 GLMessage_Function func = glmsg->function();
346 if (func != GLMessage::glGetActiveAttrib && func != GLMessage::glGetActiveUniform) {
347 return -1;
348 }
349
350 int program = glmsg->args(0).intvalue(0);
351
352 if (func == GLMessage::glGetActiveAttrib) {
353 return context->hooks->gl.glGetAttribLocation(program, name);
354 } else {
355 return context->hooks->gl.glGetUniformLocation(program, name);
356 }
357 }
358
fixup_glGetActiveAttribOrUniform(GLTraceContext * context,GLMessage * glmsg,void * pointersToFixup[])359 void fixup_glGetActiveAttribOrUniform(GLTraceContext *context, GLMessage *glmsg,
360 void *pointersToFixup[]) {
361 /* void glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize,
362 GLsizei* length, GLint* size, GLenum* type, GLchar* name); */
363 /* void glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize,
364 GLsizei* length, GLint* size, GLenum* type, GLchar* name) */
365
366 fixup_GenericIntArray(3, 1, glmsg, pointersToFixup[0]); // length
367 fixup_GenericIntArray(4, 1, glmsg, pointersToFixup[1]); // size
368 fixup_GenericEnumArray(5, 1, glmsg, pointersToFixup[2]); // type
369 fixup_CStringPtr(6, glmsg, pointersToFixup[3]); // name
370
371 // The index argument in the glGetActive[Attrib|Uniform] functions
372 // does not correspond to the actual location index as used in
373 // glUniform*() or glVertexAttrib*() to actually upload the data.
374 // In order to make things simpler for the debugger, we also pass
375 // a hidden location argument that stores the actual location.
376 // append the location value to the end of the argument list
377 int location = getShaderVariableLocation(context, glmsg, (GLchar*)pointersToFixup[3]);
378 GLMessage_DataType *arg_location = glmsg->add_args();
379 arg_location->set_isarray(false);
380 arg_location->set_type(GLMessage::DataType::INT);
381 arg_location->add_intvalue(location);
382 }
383
glGetInteger(GLTraceContext * context,GLenum param)384 GLint glGetInteger(GLTraceContext *context, GLenum param) {
385 GLint x;
386 context->hooks->gl.glGetIntegerv(param, &x);
387 return x;
388 }
389
glGetVertexAttrib(GLTraceContext * context,GLuint index,GLenum pname)390 GLint glGetVertexAttrib(GLTraceContext *context, GLuint index, GLenum pname) {
391 GLint x;
392 context->hooks->gl.glGetVertexAttribiv(index, pname, &x);
393 return x;
394 }
395
isUsingArrayBuffers(GLTraceContext * context)396 bool isUsingArrayBuffers(GLTraceContext *context) {
397 return glGetInteger(context, GL_ARRAY_BUFFER_BINDING) != 0;
398 }
399
isUsingElementArrayBuffers(GLTraceContext * context)400 bool isUsingElementArrayBuffers(GLTraceContext *context) {
401 return glGetInteger(context, GL_ELEMENT_ARRAY_BUFFER_BINDING) != 0;
402 }
403
404 /** Copy @len bytes of data from @src into the @dataIndex'th argument of the message. */
addGlBufferData(GLMessage * glmsg,int dataIndex,GLvoid * src,GLsizeiptr len)405 void addGlBufferData(GLMessage *glmsg, int dataIndex, GLvoid *src, GLsizeiptr len) {
406 GLMessage_DataType *arg_datap = glmsg->mutable_args(dataIndex);
407 arg_datap->set_type(GLMessage::DataType::VOID);
408 arg_datap->set_isarray(true);
409 arg_datap->clear_intvalue();
410 arg_datap->add_rawbytes(src, len);
411 }
412
fixup_glBufferData(GLTraceContext * context,GLMessage * glmsg,void * pointersToFixup[])413 void fixup_glBufferData(GLTraceContext *context, GLMessage *glmsg, void *pointersToFixup[]) {
414 /* void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) */
415 GLsizeiptr size = glmsg->args(1).intvalue(0);
416 GLvoid *datap = (GLvoid *) pointersToFixup[0];
417
418 // Save element array buffers for future use to fixup glVertexAttribPointers
419 // when a glDrawElements() call is performed.
420 GLenum target = glmsg->args(0).intvalue(0);
421 if (target == GL_ELEMENT_ARRAY_BUFFER) {
422 GLint bufferId = glGetInteger(context, GL_ELEMENT_ARRAY_BUFFER_BINDING);
423 context->bindBuffer(bufferId, datap, size);
424 }
425
426 // add buffer data to the protobuf message
427 if (datap != NULL) {
428 addGlBufferData(glmsg, 2, datap, size);
429 }
430 }
431
fixup_glBufferSubData(GLTraceContext * context,GLMessage * glmsg,void * pointersToFixup[])432 void fixup_glBufferSubData(GLTraceContext *context, GLMessage *glmsg, void *pointersToFixup[]) {
433 /* void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) */
434 GLenum target = glmsg->args(0).intvalue(0);
435 GLintptr offset = glmsg->args(1).intvalue(0);
436 GLsizeiptr size = glmsg->args(2).intvalue(0);
437 GLvoid *datap = (GLvoid *) pointersToFixup[0];
438 if (target == GL_ELEMENT_ARRAY_BUFFER) {
439 GLint bufferId = glGetInteger(context, GL_ELEMENT_ARRAY_BUFFER_BINDING);
440 context->updateBufferSubData(bufferId, offset, datap, size);
441 }
442
443 // add buffer data to the protobuf message
444 addGlBufferData(glmsg, 3, datap, size);
445 }
446
447 /** Obtain the size of each vertex attribute. */
vertexAttribSize(GLenum type,GLsizei numComponents)448 int vertexAttribSize(GLenum type, GLsizei numComponents) {
449 int sizePerComponent;
450
451 switch(type) {
452 case GL_BYTE:
453 case GL_UNSIGNED_BYTE:
454 sizePerComponent = 1;
455 break;
456 case GL_SHORT:
457 case GL_UNSIGNED_SHORT:
458 sizePerComponent = 2;
459 break;
460 case GL_FIXED:
461 case GL_FLOAT:
462 default:
463 sizePerComponent = 4;
464 break;
465 }
466
467 return sizePerComponent * numComponents;
468 }
469
470 /** Create and send a glVertexAttribPointerData trace message to the host. */
trace_glVertexAttribPointerData(GLTraceContext * context,GLuint indx,GLint size,GLenum type,GLboolean normalized,GLsizei stride,const GLvoid * ptr,GLuint minIndex,GLuint maxIndex,nsecs_t startTime)471 void trace_glVertexAttribPointerData(GLTraceContext *context,
472 GLuint indx, GLint size, GLenum type,
473 GLboolean normalized, GLsizei stride, const GLvoid* ptr,
474 GLuint minIndex, GLuint maxIndex, nsecs_t startTime) {
475 /* void glVertexAttribPointerData(GLuint indx, GLint size, GLenum type,
476 GLboolean normalized, GLsizei stride, const GLvoid* ptr,
477 int minIndex, int maxIndex) */
478 GLMessage glmsg;
479 GLTraceContext *glContext = context;
480
481 glmsg.set_function(GLMessage::glVertexAttribPointerData);
482
483 // copy argument indx
484 GLMessage_DataType *arg_indx = glmsg.add_args();
485 arg_indx->set_isarray(false);
486 arg_indx->set_type(GLMessage::DataType::INT);
487 arg_indx->add_intvalue(indx);
488
489 // copy argument size
490 GLMessage_DataType *arg_size = glmsg.add_args();
491 arg_size->set_isarray(false);
492 arg_size->set_type(GLMessage::DataType::INT);
493 arg_size->add_intvalue(size);
494
495 // copy argument type
496 GLMessage_DataType *arg_type = glmsg.add_args();
497 arg_type->set_isarray(false);
498 arg_type->set_type(GLMessage::DataType::ENUM);
499 arg_type->add_intvalue((int)type);
500
501 // copy argument normalized
502 GLMessage_DataType *arg_normalized = glmsg.add_args();
503 arg_normalized->set_isarray(false);
504 arg_normalized->set_type(GLMessage::DataType::BOOL);
505 arg_normalized->add_boolvalue(normalized);
506
507 // copy argument stride
508 GLMessage_DataType *arg_stride = glmsg.add_args();
509 arg_stride->set_isarray(false);
510 arg_stride->set_type(GLMessage::DataType::INT);
511 arg_stride->add_intvalue(stride);
512
513 // copy argument ptr
514 GLMessage_DataType *arg_ptr = glmsg.add_args();
515 arg_ptr->set_isarray(true);
516 arg_ptr->set_type(GLMessage::DataType::BYTE);
517 int perVertexSize = vertexAttribSize(type, size);
518 GLchar *p = (GLchar*) ptr;
519 std::string data;
520 for (GLuint i = minIndex; i < maxIndex; i++) {
521 data.append(p, perVertexSize);
522 p += stride == 0 ? perVertexSize : stride;
523 }
524 arg_ptr->add_rawbytes(data);
525
526 // copy argument min index
527 GLMessage_DataType *arg_min = glmsg.add_args();
528 arg_min->set_isarray(false);
529 arg_min->set_type(GLMessage::DataType::INT);
530 arg_min->add_intvalue(minIndex);
531
532 // copy argument max index
533 GLMessage_DataType *arg_max = glmsg.add_args();
534 arg_max->set_isarray(false);
535 arg_max->set_type(GLMessage::DataType::INT);
536 arg_max->add_intvalue(maxIndex);
537
538 glmsg.set_context_id(context->getId());
539 glmsg.set_start_time(startTime);
540 glmsg.set_threadtime(0);
541 glmsg.set_duration(0);
542
543 context->traceGLMessage(&glmsg);
544 }
545
findMinAndMaxIndices(GLvoid * indices,GLsizei count,GLenum type,GLuint * minIndex,GLuint * maxIndex)546 void findMinAndMaxIndices(GLvoid *indices, GLsizei count, GLenum type,
547 GLuint *minIndex, GLuint *maxIndex) {
548 GLuint index;
549 *minIndex = UINT_MAX;
550 *maxIndex = 0;
551
552 if (indices == NULL) {
553 return;
554 }
555
556 for (GLsizei i = 0; i < count; i++) {
557 if (type == GL_UNSIGNED_BYTE) {
558 index = *((GLubyte*) indices + i);
559 } else {
560 index = *((GLushort*) indices + i);
561 }
562
563 if (index < *minIndex) *minIndex = index;
564 if (index > *maxIndex) *maxIndex = index;
565 }
566 }
567
trace_VertexAttribPointerData(GLTraceContext * context,GLuint minIndex,GLuint maxIndex,nsecs_t time)568 void trace_VertexAttribPointerData(GLTraceContext *context,
569 GLuint minIndex, GLuint maxIndex, nsecs_t time) {
570 GLuint maxAttribs = glGetInteger(context, GL_MAX_VERTEX_ATTRIBS);
571 for (GLuint index = 0; index < maxAttribs; index++) {
572 if (!glGetVertexAttrib(context, index, GL_VERTEX_ATTRIB_ARRAY_ENABLED)) {
573 // vertex array disabled
574 continue;
575 }
576
577 if (glGetVertexAttrib(context, index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING)) {
578 // vbo
579 continue;
580 }
581
582 GLint size = glGetVertexAttrib(context, index, GL_VERTEX_ATTRIB_ARRAY_SIZE);
583 GLenum type = glGetVertexAttrib(context, index, GL_VERTEX_ATTRIB_ARRAY_TYPE);
584 GLboolean norm = glGetVertexAttrib(context, index, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED);
585 GLsizei stride = glGetVertexAttrib(context, index, GL_VERTEX_ATTRIB_ARRAY_STRIDE);
586 GLvoid* ptr;
587 context->hooks->gl.glGetVertexAttribPointerv(index, GL_VERTEX_ATTRIB_ARRAY_POINTER, &ptr);
588
589 trace_glVertexAttribPointerData(context,
590 index, size, type, norm, stride, ptr,
591 minIndex, maxIndex, time);
592 }
593 }
594
trace_VertexAttribPointerDataForGlDrawArrays(GLTraceContext * context,GLMessage * glmsg)595 void trace_VertexAttribPointerDataForGlDrawArrays(GLTraceContext *context, GLMessage *glmsg) {
596 if (context->getVersion() == egl_connection_t::GLESv1_INDEX) {
597 // only supported for GLES2 and above
598 return;
599 }
600
601 /* void glDrawArrays(GLenum mode, GLint first, GLsizei count) */
602 GLsizei count = glmsg->args(2).intvalue(0);
603
604 // Vertex attrib pointer data patchup calls should appear as if
605 // they occurred right before the draw call.
606 nsecs_t time = glmsg->start_time() - 1;
607
608 trace_VertexAttribPointerData(context, 0, count, time);
609 }
610
trace_VertexAttribPointerDataForGlDrawElements(GLTraceContext * context,GLMessage * glmsg,GLvoid * indices)611 void trace_VertexAttribPointerDataForGlDrawElements(GLTraceContext *context, GLMessage *glmsg,
612 GLvoid *indices) {
613 if (context->getVersion() == egl_connection_t::GLESv1_INDEX) {
614 // only supported for GLES2 and above
615 return;
616 }
617
618 /* void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) */
619 GLsizei count = glmsg->args(1).intvalue(0);
620 GLenum type = glmsg->args(2).intvalue(0);
621 GLuint index;
622
623 GLuint minIndex, maxIndex;
624
625 // The index buffer is either passed in as an argument to the glDrawElements() call,
626 // or it is stored in the current GL_ELEMENT_ARRAY_BUFFER.
627 GLvoid *indexBuffer;
628 if (isUsingElementArrayBuffers(context)) {
629 GLsizeiptr eaBufferSize;
630 GLuint bufferId = glGetInteger(context, GL_ELEMENT_ARRAY_BUFFER_BINDING);
631 context->getBuffer(bufferId, &indexBuffer, &eaBufferSize);
632 } else {
633 indexBuffer = indices;
634 }
635
636 // Rather than sending vertex attribute data that corresponds to the indices
637 // being drawn, we send the vertex attribute data for the entire range of
638 // indices being drawn, including the ones not drawn. The min & max indices
639 // provide the range of indices being drawn.
640 findMinAndMaxIndices(indexBuffer, count, type, &minIndex, &maxIndex);
641
642 // Vertex attrib pointer data patchup calls should appear as if
643 // they occurred right before the draw call.
644 nsecs_t time = glmsg->start_time() - 1;
645
646 trace_VertexAttribPointerData(context, minIndex, maxIndex + 1, time);
647 }
648
fixup_glDrawArrays(GLTraceContext * context,GLMessage * glmsg)649 void fixup_glDrawArrays(GLTraceContext *context, GLMessage *glmsg) {
650 // Trace all vertex attribute data stored in client space.
651 trace_VertexAttribPointerDataForGlDrawArrays(context, glmsg);
652
653 // Attach the FB if requested
654 if (context->getGlobalTraceState()->shouldCollectFbOnGlDraw()) {
655 fixup_addFBContents(context, glmsg, CURRENTLY_BOUND_FB);
656 }
657 }
658
fixup_glDrawElements(GLTraceContext * context,GLMessage * glmsg,void * pointersToFixup[])659 void fixup_glDrawElements(GLTraceContext *context, GLMessage *glmsg, void *pointersToFixup[]) {
660 /* void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) */
661 GLvoid *indices = pointersToFixup[0];
662 GLenum type = glmsg->args(2).intvalue(0);
663 GLsizei count = glmsg->args(1).intvalue(0);
664 GLuint index;
665
666 // Trace all vertex attribute data stored in client space.
667 trace_VertexAttribPointerDataForGlDrawElements(context, glmsg, indices);
668
669 // Fixup indices argument
670 if (!isUsingElementArrayBuffers(context)) {
671 GLMessage_DataType *arg_indices = glmsg->mutable_args(3);
672 arg_indices->set_isarray(true);
673 arg_indices->clear_intvalue();
674 arg_indices->set_type(GLMessage::DataType::INT);
675 for (GLsizei i = 0; i < count; i++) {
676 if (type == GL_UNSIGNED_BYTE) {
677 index = *((GLubyte*) indices + i);
678 } else {
679 index = *((GLushort*) indices + i);
680 }
681 arg_indices->add_intvalue(index);
682 }
683 }
684
685 // Attach the FB if requested
686 if (context->getGlobalTraceState()->shouldCollectFbOnGlDraw()) {
687 fixup_addFBContents(context, glmsg, CURRENTLY_BOUND_FB);
688 }
689 }
690
fixupGLMessage(GLTraceContext * context,nsecs_t wallStart,nsecs_t wallEnd,nsecs_t threadStart,nsecs_t threadEnd,GLMessage * glmsg,void * pointersToFixup[])691 void fixupGLMessage(GLTraceContext *context, nsecs_t wallStart, nsecs_t wallEnd,
692 nsecs_t threadStart, nsecs_t threadEnd,
693 GLMessage *glmsg, void *pointersToFixup[]) {
694 // for all messages, set the current context id
695 glmsg->set_context_id(context->getId());
696
697 // set start time and duration
698 glmsg->set_start_time(wallStart);
699 glmsg->set_duration((unsigned)(wallEnd - wallStart));
700 glmsg->set_threadtime((unsigned)(threadEnd - threadStart));
701
702 // do any custom message dependent processing
703 switch (glmsg->function()) {
704 case GLMessage::glDeleteBuffers: /* glDeleteBuffers(GLsizei n, GLuint *buffers); */
705 case GLMessage::glDeleteFramebuffers: /* glDeleteFramebuffers(GLsizei n, GLuint *buffers); */
706 case GLMessage::glDeleteRenderbuffers:/* glDeleteRenderbuffers(GLsizei n, GLuint *buffers); */
707 case GLMessage::glDeleteTextures: /* glDeleteTextures(GLsizei n, GLuint *textures); */
708 fixup_glDeleteGeneric(glmsg, pointersToFixup);
709 break;
710 case GLMessage::glGenBuffers: /* void glGenBuffers(GLsizei n, GLuint *buffers); */
711 case GLMessage::glGenFramebuffers: /* void glGenFramebuffers(GLsizei n, GLuint *buffers); */
712 case GLMessage::glGenRenderbuffers: /* void glGenFramebuffers(GLsizei n, GLuint *buffers); */
713 case GLMessage::glGenTextures: /* void glGenTextures(GLsizei n, GLuint *textures); */
714 fixup_glGenGeneric(glmsg, pointersToFixup);
715 break;
716 case GLMessage::glLinkProgram: /* void glLinkProgram(GLuint program); */
717 fixup_glLinkProgram(glmsg);
718 break;
719 case GLMessage::glGetActiveAttrib:
720 fixup_glGetActiveAttribOrUniform(context, glmsg, pointersToFixup);
721 break;
722 case GLMessage::glGetActiveUniform:
723 fixup_glGetActiveAttribOrUniform(context, glmsg, pointersToFixup);
724 break;
725 case GLMessage::glBindAttribLocation:
726 /* void glBindAttribLocation(GLuint program, GLuint index, const GLchar* name); */
727 fixup_CStringPtr(2, glmsg, pointersToFixup[0]);
728 break;
729 case GLMessage::glGetAttribLocation:
730 case GLMessage::glGetUniformLocation:
731 /* int glGetAttribLocation(GLuint program, const GLchar* name) */
732 /* int glGetUniformLocation(GLuint program, const GLchar* name) */
733 fixup_CStringPtr(1, glmsg, pointersToFixup[0]);
734 break;
735 case GLMessage::glGetBooleanv:
736 fixup_glGetBooleanv(glmsg, pointersToFixup);
737 break;
738 case GLMessage::glGetFloatv:
739 fixup_glGetFloatv(glmsg, pointersToFixup);
740 break;
741 case GLMessage::glGetIntegerv: /* void glGetIntegerv(GLenum pname, GLint *params); */
742 fixup_GenericIntArray(1, 1, glmsg, pointersToFixup[0]);
743 break;
744 case GLMessage::glGetProgramiv:
745 case GLMessage::glGetRenderbufferParameteriv:
746 case GLMessage::glGetShaderiv:
747 /* void glGetProgramiv(GLuint program, GLenum pname, GLint* params) */
748 /* void glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params) */
749 /* void glGetShaderiv(GLuint shader, GLenum pname, GLint* params) */
750 fixup_GenericIntArray(2, 1, glmsg, pointersToFixup[0]);
751 break;
752 case GLMessage::glGetString:
753 fixup_glGetString(glmsg, pointersToFixup);
754 break;
755 case GLMessage::glTexImage2D:
756 if (context->getGlobalTraceState()->shouldCollectTextureDataOnGlTexImage()) {
757 fixup_glTexImage2D(glmsg, pointersToFixup);
758 }
759 break;
760 case GLMessage::glTexSubImage2D:
761 if (context->getGlobalTraceState()->shouldCollectTextureDataOnGlTexImage()) {
762 fixup_glTexSubImage2D(glmsg, pointersToFixup);
763 }
764 break;
765 case GLMessage::glShaderSource:
766 fixup_glShaderSource(glmsg, pointersToFixup);
767 break;
768 case GLMessage::glUniform1iv:
769 /* void glUniform1iv(GLint location, GLsizei count, const GLint *value); */
770 fixup_glUniformGenericInteger(2, 1, glmsg, pointersToFixup);
771 break;
772 case GLMessage::glUniform2iv:
773 /* void glUniform2iv(GLint location, GLsizei count, const GLint *value); */
774 fixup_glUniformGenericInteger(2, 2, glmsg, pointersToFixup);
775 break;
776 case GLMessage::glUniform3iv:
777 /* void glUniform3iv(GLint location, GLsizei count, const GLint *value); */
778 fixup_glUniformGenericInteger(2, 3, glmsg, pointersToFixup);
779 break;
780 case GLMessage::glUniform4iv:
781 /* void glUniform4iv(GLint location, GLsizei count, const GLint *value); */
782 fixup_glUniformGenericInteger(2, 4, glmsg, pointersToFixup);
783 break;
784 case GLMessage::glUniform1fv:
785 /* void glUniform1fv(GLint location, GLsizei count, const GLfloat *value); */
786 fixup_glUniformGeneric(2, 1, glmsg, pointersToFixup[0]);
787 break;
788 case GLMessage::glUniform2fv:
789 /* void glUniform2fv(GLint location, GLsizei count, const GLfloat *value); */
790 fixup_glUniformGeneric(2, 2, glmsg, pointersToFixup[0]);
791 break;
792 case GLMessage::glUniform3fv:
793 /* void glUniform3fv(GLint location, GLsizei count, const GLfloat *value); */
794 fixup_glUniformGeneric(2, 3, glmsg, pointersToFixup[0]);
795 break;
796 case GLMessage::glUniform4fv:
797 /* void glUniform4fv(GLint location, GLsizei count, const GLfloat *value); */
798 fixup_glUniformGeneric(2, 4, glmsg, pointersToFixup[0]);
799 break;
800 case GLMessage::glUniformMatrix2fv:
801 /* void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose,
802 const GLfloat* value) */
803 fixup_glUniformMatrixGeneric(2, glmsg, pointersToFixup);
804 break;
805 case GLMessage::glUniformMatrix3fv:
806 /* void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose,
807 const GLfloat* value) */
808 fixup_glUniformMatrixGeneric(3, glmsg, pointersToFixup);
809 break;
810 case GLMessage::glUniformMatrix4fv:
811 /* void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose,
812 const GLfloat* value) */
813 fixup_glUniformMatrixGeneric(4, glmsg, pointersToFixup);
814 break;
815 case GLMessage::glBufferData:
816 /* void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) */
817 fixup_glBufferData(context, glmsg, pointersToFixup);
818 break;
819 case GLMessage::glBufferSubData:
820 /* void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) */
821 fixup_glBufferSubData(context, glmsg, pointersToFixup);
822 break;
823 case GLMessage::glDrawArrays:
824 /* void glDrawArrays(GLenum mode, GLint first, GLsizei count) */
825 fixup_glDrawArrays(context, glmsg);
826 break;
827 case GLMessage::glDrawElements:
828 /* void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) */
829 fixup_glDrawElements(context, glmsg, pointersToFixup);
830 break;
831 case GLMessage::glPushGroupMarkerEXT:
832 /* void PushGroupMarkerEXT(sizei length, const char *marker); */
833 fixup_CStringPtr(1, glmsg, pointersToFixup[0]);
834 break;
835 case GLMessage::glInsertEventMarkerEXT:
836 /* void InsertEventMarkerEXT(sizei length, const char *marker); */
837 fixup_CStringPtr(1, glmsg, pointersToFixup[0]);
838 break;
839 default:
840 break;
841 }
842 }
843
844 };
845 };
846