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