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 32 GLint glGetInteger(GLTraceContext *context, GLenum param) { 33 GLint x; 34 context->hooks->gl.glGetIntegerv(param, &x); 35 return x; 36 } 37 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 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 51 bool isUsingArrayBuffers(GLTraceContext *context) { 52 return glGetInteger(context, GL_ARRAY_BUFFER_BINDING) != 0; 53 } 54 55 bool isUsingElementArrayBuffers(GLTraceContext *context) { 56 return glGetInteger(context, GL_ELEMENT_ARRAY_BUFFER_BINDING) != 0; 57 } 58 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 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 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 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 */ 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 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 */ 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. */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 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. */ 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 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 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. */ 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. */ 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 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 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 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 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 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 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 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