gltrace_fixup.cpp revision 88e8e5a3f16f0003bd2b43142241b8e1a9a46abe
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 <GLES/gl.h> 19#include <GLES/glext.h> 20#include <GLES2/gl2.h> 21#include <GLES2/gl2ext.h> 22 23#include "gltrace.pb.h" 24#include "gltrace_api.h" 25#include "gltrace_context.h" 26#include "gltrace_fixup.h" 27 28namespace android { 29namespace gltrace { 30 31unsigned getBytesPerTexel(const GLenum format, const GLenum type) { 32 /* 33 Description from glTexImage2D spec: 34 35 Data is read from data as a sequence of unsigned bytes or shorts, depending on type. 36 When type is GL_UNSIGNED_BYTE, each of the bytes is interpreted as one color component. 37 When type is one of GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_4_4_4_4, or 38 GL_UNSIGNED_SHORT_5_5_5_1, each unsigned short value is interpreted as containing all 39 the components for a single texel, with the color components arranged according to 40 format. Color components are treated as groups of one, two, three, or four values, 41 again based on format. Groups of components are referred to as texels. 42 43 width × height texels are read from memory, starting at location data. By default, 44 these texels are taken from adjacent memory locations, except that after all width 45 texels are read, the read pointer is advanced to the next four-byte boundary. 46 The four-byte row alignment is specified by glPixelStorei with argument 47 GL_UNPACK_ALIGNMENT, and it can be set to one, two, four, or eight bytes. 48 */ 49 50 switch (type) { 51 case GL_UNSIGNED_SHORT_5_6_5: 52 case GL_UNSIGNED_SHORT_4_4_4_4: 53 case GL_UNSIGNED_SHORT_5_5_5_1: 54 return 2; 55 case GL_UNSIGNED_BYTE: 56 break; 57 default: 58 ALOGE("GetBytesPerPixel: unknown type %x", type); 59 } 60 61 switch (format) { 62 case GL_ALPHA: 63 case GL_LUMINANCE: 64 return 1; 65 case GL_LUMINANCE_ALPHA: 66 return 2; 67 case GL_RGB: 68 return 3; 69 case GL_RGBA: 70 case 0x80E1: // GL_BGRA_EXT 71 return 4; 72 default: 73 ALOGE("GetBytesPerPixel: unknown format %x", format); 74 } 75 76 return 1; // in doubt... 77} 78 79/** Generic helper function: extract pointer at argIndex and 80 replace it with the C style string at *pointer */ 81void fixup_CStringPtr(int argIndex, GLMessage *glmsg) { 82 GLMessage_DataType *arg = glmsg->mutable_args(argIndex); 83 GLchar *ptr = (GLchar *)arg->intvalue(0); 84 85 arg->set_type(GLMessage::DataType::CHAR); 86 arg->set_isarray(true); 87 arg->add_charvalue(ptr); 88} 89 90void fixup_glGetString(GLMessage *glmsg) { 91 /* const GLubyte* GLTrace_glGetString(GLenum name) */ 92 GLMessage_DataType *ret = glmsg->mutable_returnvalue(); 93 GLchar *ptr = (GLchar *)ret->intvalue(0); 94 95 if (ptr != NULL) { 96 ret->set_type(GLMessage::DataType::CHAR); 97 ret->set_isarray(true); 98 ret->add_charvalue(ptr); 99 } 100} 101 102/* Add the contents of the framebuffer to the protobuf message */ 103void fixup_addFBContents(GLTraceContext *context, GLMessage *glmsg, FBBinding fbToRead) { 104 void *fbcontents; 105 unsigned fbsize, fbwidth, fbheight; 106 context->getCompressedFB(&fbcontents, &fbsize, &fbwidth, &fbheight, fbToRead); 107 108 GLMessage_FrameBuffer *fb = glmsg->mutable_fb(); 109 fb->set_width(fbwidth); 110 fb->set_height(fbheight); 111 fb->add_contents(fbcontents, fbsize); 112} 113 114/** Common fixup routing for glTexImage2D & glTexSubImage2D. */ 115void fixup_glTexImage(int widthIndex, int heightIndex, GLMessage *glmsg) { 116 GLMessage_DataType arg_width = glmsg->args(widthIndex); 117 GLMessage_DataType arg_height = glmsg->args(heightIndex); 118 119 GLMessage_DataType arg_format = glmsg->args(6); 120 GLMessage_DataType arg_type = glmsg->args(7); 121 GLMessage_DataType *arg_data = glmsg->mutable_args(8); 122 123 GLsizei width = arg_width.intvalue(0); 124 GLsizei height = arg_height.intvalue(0); 125 GLenum format = arg_format.intvalue(0); 126 GLenum type = arg_type.intvalue(0); 127 void *data = (void *)arg_data->intvalue(0); 128 129 int bytesPerTexel = getBytesPerTexel(format, type); 130 131 arg_data->set_type(GLMessage::DataType::BYTE); 132 arg_data->clear_rawbytes(); 133 134 if (data != NULL) { 135 arg_data->set_isarray(true); 136 arg_data->add_rawbytes(data, bytesPerTexel * width * height); 137 } else { 138 arg_data->set_isarray(false); 139 arg_data->set_type(GLMessage::DataType::VOID); 140 } 141} 142 143 144void fixup_glTexImage2D(GLMessage *glmsg) { 145 /* void glTexImage2D(GLenum target, 146 GLint level, 147 GLint internalformat, 148 GLsizei width, 149 GLsizei height, 150 GLint border, 151 GLenum format, 152 GLenum type, 153 const GLvoid *data); 154 */ 155 int widthIndex = 3; 156 int heightIndex = 4; 157 fixup_glTexImage(widthIndex, heightIndex, glmsg); 158} 159 160void fixup_glTexSubImage2D(GLMessage *glmsg) { 161 /* 162 void glTexSubImage2D(GLenum target, 163 GLint level, 164 GLint xoffset, 165 GLint yoffset, 166 GLsizei width, 167 GLsizei height, 168 GLenum format, 169 GLenum type, 170 const GLvoid * data); 171 */ 172 int widthIndex = 4; 173 int heightIndex = 5; 174 fixup_glTexImage(widthIndex, heightIndex, glmsg); 175} 176 177void fixup_glShaderSource(GLMessage *glmsg) { 178 /* void glShaderSource(GLuint shader, GLsizei count, const GLchar** string, 179 const GLint* length) */ 180 GLMessage_DataType arg_count = glmsg->args(1); 181 GLMessage_DataType arg_lenp = glmsg->args(3); 182 GLMessage_DataType *arg_strpp = glmsg->mutable_args(2); 183 184 GLsizei count = arg_count.intvalue(0); 185 GLchar **stringpp = (GLchar **)arg_strpp->intvalue(0); 186 GLint *lengthp = (GLint *)arg_lenp.intvalue(0); 187 188 arg_strpp->set_type(GLMessage::DataType::CHAR); 189 arg_strpp->set_isarray(true); 190 arg_strpp->clear_charvalue(); 191 192 ::std::string src = ""; 193 for (int i = 0; i < count; i++) { 194 if (lengthp != NULL) 195 src.append(*stringpp, *lengthp); 196 else 197 src.append(*stringpp); // assume null terminated 198 stringpp++; 199 lengthp++; 200 } 201 202 arg_strpp->add_charvalue(src); 203} 204 205void fixup_glUniformGenericInteger(int argIndex, int nIntegers, GLMessage *glmsg) { 206 /* void glUniform?iv(GLint location, GLsizei count, const GLint *value); */ 207 GLMessage_DataType *arg_values = glmsg->mutable_args(argIndex); 208 GLint *src = (GLint*)arg_values->intvalue(0); 209 210 arg_values->set_type(GLMessage::DataType::INT); 211 arg_values->set_isarray(true); 212 arg_values->clear_intvalue(); 213 214 for (int i = 0; i < nIntegers; i++) { 215 arg_values->add_intvalue(*src++); 216 } 217} 218 219void fixup_glUniformGeneric(int argIndex, int nFloats, GLMessage *glmsg) { 220 GLMessage_DataType *arg_values = glmsg->mutable_args(argIndex); 221 GLfloat *src = (GLfloat*)arg_values->intvalue(0); 222 223 arg_values->set_type(GLMessage::DataType::FLOAT); 224 arg_values->set_isarray(true); 225 arg_values->clear_floatvalue(); 226 227 for (int i = 0; i < nFloats; i++) { 228 arg_values->add_floatvalue(*src++); 229 } 230} 231 232void fixup_glUniformMatrixGeneric(int matrixSize, GLMessage *glmsg) { 233 /* void glUniformMatrix?fv(GLint location, GLsizei count, GLboolean transpose, 234 const GLfloat* value) */ 235 GLMessage_DataType arg_count = glmsg->args(1); 236 int n_matrices = arg_count.intvalue(0); 237 fixup_glUniformGeneric(3, matrixSize * matrixSize * n_matrices, glmsg); 238} 239 240void fixup_GenericIntArray(int argIndex, int nInts, GLMessage *glmsg) { 241 GLMessage_DataType *arg_intarray = glmsg->mutable_args(argIndex); 242 GLint *intp = (GLint *)arg_intarray->intvalue(0); 243 244 if (intp == NULL) { 245 return; 246 } 247 248 arg_intarray->set_type(GLMessage::DataType::INT); 249 arg_intarray->set_isarray(true); 250 arg_intarray->clear_intvalue(); 251 252 for (int i = 0; i < nInts; i++, intp++) { 253 arg_intarray->add_intvalue(*intp); 254 } 255} 256 257void fixup_GenericEnumArray(int argIndex, int nEnums, GLMessage *glmsg) { 258 // fixup as if they were ints 259 fixup_GenericIntArray(argIndex, nEnums, glmsg); 260 261 // and then set the data type to be enum 262 GLMessage_DataType *arg_enumarray = glmsg->mutable_args(argIndex); 263 arg_enumarray->set_type(GLMessage::DataType::ENUM); 264} 265 266void fixup_glGenGeneric(GLMessage *glmsg) { 267 /* void glGen*(GLsizei n, GLuint * buffers); */ 268 GLMessage_DataType arg_n = glmsg->args(0); 269 GLsizei n = arg_n.intvalue(0); 270 271 fixup_GenericIntArray(1, n, glmsg); 272} 273 274void fixup_glDeleteGeneric(GLMessage *glmsg) { 275 /* void glDelete*(GLsizei n, GLuint *buffers); */ 276 GLMessage_DataType arg_n = glmsg->args(0); 277 GLsizei n = arg_n.intvalue(0); 278 279 fixup_GenericIntArray(1, n, glmsg); 280} 281 282void fixup_glGetBooleanv(GLMessage *glmsg) { 283 /* void glGetBooleanv(GLenum pname, GLboolean *params); */ 284 GLMessage_DataType *arg_params = glmsg->mutable_args(1); 285 GLboolean *src = (GLboolean*)arg_params->intvalue(0); 286 287 arg_params->set_type(GLMessage::DataType::BOOL); 288 arg_params->set_isarray(true); 289 arg_params->clear_boolvalue(); 290 arg_params->add_boolvalue(*src); 291} 292 293void fixup_glGetFloatv(GLMessage *glmsg) { 294 /* void glGetFloatv(GLenum pname, GLfloat *params); */ 295 GLMessage_DataType *arg_params = glmsg->mutable_args(1); 296 GLfloat *src = (GLfloat*)arg_params->intvalue(0); 297 298 arg_params->set_type(GLMessage::DataType::FLOAT); 299 arg_params->set_isarray(true); 300 arg_params->clear_floatvalue(); 301 arg_params->add_floatvalue(*src); 302} 303 304void fixup_glLinkProgram(GLMessage *glmsg) { 305 /* void glLinkProgram(GLuint program); */ 306 GLuint program = glmsg->args(0).intvalue(0); 307 308 /* We don't have to fixup this call, but as soon as a program is linked, 309 we obtain information about all active attributes and uniforms to 310 pass on to the debugger. Note that in order to pass this info to 311 the debugger, all we need to do is call the trace versions of the 312 necessary calls. */ 313 314 GLint n, maxNameLength; 315 GLchar *name; 316 GLint size; 317 GLenum type; 318 319 // obtain info regarding active attributes 320 GLTrace_glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &n); 321 GLTrace_glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxNameLength); 322 323 name = (GLchar *) malloc(maxNameLength); 324 for (int i = 0; i < n; i++) { 325 GLTrace_glGetActiveAttrib(program, i, maxNameLength, NULL, &size, &type, name); 326 } 327 free(name); 328 329 // obtain info regarding active uniforms 330 GLTrace_glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &n); 331 GLTrace_glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxNameLength); 332 333 name = (GLchar *) malloc(maxNameLength); 334 for (int i = 0; i < n; i++) { 335 GLTrace_glGetActiveUniform(program, i, maxNameLength, NULL, &size, &type, name); 336 } 337 free(name); 338} 339 340/** Given a glGetActive[Uniform|Attrib] call, obtain the location 341 * of the variable in the call. 342 */ 343int getShaderVariableLocation(GLTraceContext *context, GLMessage *glmsg) { 344 GLMessage_Function func = glmsg->function(); 345 if (func != GLMessage::glGetActiveAttrib && func != GLMessage::glGetActiveUniform) { 346 return -1; 347 } 348 349 int program = glmsg->args(0).intvalue(0); 350 GLchar *name = (GLchar*) glmsg->args(6).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 359void fixup_glGetActiveAttribOrUniform(GLMessage *glmsg, int location) { 360 /* void glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, 361 GLsizei* length, GLint* size, GLenum* type, GLchar* name); */ 362 /* void glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, 363 GLsizei* length, GLint* size, GLenum* type, GLchar* name) */ 364 365 fixup_GenericIntArray(3, 1, glmsg); // length 366 fixup_GenericIntArray(4, 1, glmsg); // size 367 fixup_GenericEnumArray(5, 1, glmsg); // type 368 fixup_CStringPtr(6, glmsg); // name 369 370 // The index argument in the glGetActive[Attrib|Uniform] functions 371 // does not correspond to the actual location index as used in 372 // glUniform*() or glVertexAttrib*() to actually upload the data. 373 // In order to make things simpler for the debugger, we also pass 374 // a hidden location argument that stores the actual location. 375 // append the location value to the end of the argument list 376 GLMessage_DataType *arg_location = glmsg->add_args(); 377 arg_location->set_isarray(false); 378 arg_location->set_type(GLMessage::DataType::INT); 379 arg_location->add_intvalue(location); 380} 381 382void fixupGLMessage(GLTraceContext *context, nsecs_t start, nsecs_t end, GLMessage *glmsg) { 383 // for all messages, set the current context id 384 glmsg->set_context_id(context->getId()); 385 386 // set start time and duration 387 glmsg->set_start_time(start); 388 glmsg->set_duration((unsigned)(end - start)); 389 390 // do any custom message dependent processing 391 switch (glmsg->function()) { 392 case GLMessage::glDeleteBuffers: /* glDeleteBuffers(GLsizei n, GLuint *buffers); */ 393 case GLMessage::glDeleteFramebuffers: /* glDeleteFramebuffers(GLsizei n, GLuint *buffers); */ 394 case GLMessage::glDeleteRenderbuffers:/* glDeleteRenderbuffers(GLsizei n, GLuint *buffers); */ 395 case GLMessage::glDeleteTextures: /* glDeleteTextures(GLsizei n, GLuint *textures); */ 396 fixup_glDeleteGeneric(glmsg); 397 break; 398 case GLMessage::glGenBuffers: /* void glGenBuffers(GLsizei n, GLuint *buffers); */ 399 case GLMessage::glGenFramebuffers: /* void glGenFramebuffers(GLsizei n, GLuint *buffers); */ 400 case GLMessage::glGenRenderbuffers: /* void glGenFramebuffers(GLsizei n, GLuint *buffers); */ 401 case GLMessage::glGenTextures: /* void glGenTextures(GLsizei n, GLuint *textures); */ 402 fixup_glGenGeneric(glmsg); 403 break; 404 case GLMessage::glLinkProgram: /* void glLinkProgram(GLuint program); */ 405 fixup_glLinkProgram(glmsg); 406 break; 407 case GLMessage::glGetActiveAttrib: 408 fixup_glGetActiveAttribOrUniform(glmsg, getShaderVariableLocation(context, glmsg)); 409 break; 410 case GLMessage::glGetActiveUniform: 411 fixup_glGetActiveAttribOrUniform(glmsg, getShaderVariableLocation(context, glmsg)); 412 break; 413 case GLMessage::glBindAttribLocation: 414 /* void glBindAttribLocation(GLuint program, GLuint index, const GLchar* name); */ 415 fixup_CStringPtr(2, glmsg); 416 break; 417 case GLMessage::glGetAttribLocation: 418 case GLMessage::glGetUniformLocation: 419 /* int glGetAttribLocation(GLuint program, const GLchar* name) */ 420 /* int glGetUniformLocation(GLuint program, const GLchar* name) */ 421 fixup_CStringPtr(1, glmsg); 422 break; 423 case GLMessage::glGetBooleanv: 424 fixup_glGetBooleanv(glmsg); 425 break; 426 case GLMessage::glGetFloatv: 427 fixup_glGetFloatv(glmsg); 428 break; 429 case GLMessage::glGetIntegerv: /* void glGetIntegerv(GLenum pname, GLint *params); */ 430 fixup_GenericIntArray(1, 1, glmsg); 431 break; 432 case GLMessage::glGetProgramiv: 433 case GLMessage::glGetRenderbufferParameteriv: 434 case GLMessage::glGetShaderiv: 435 /* void glGetProgramiv(GLuint program, GLenum pname, GLint* params) */ 436 /* void glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params) */ 437 /* void glGetShaderiv(GLuint shader, GLenum pname, GLint* params) */ 438 fixup_GenericIntArray(2, 1, glmsg); 439 break; 440 case GLMessage::glGetString: 441 fixup_glGetString(glmsg); 442 break; 443 case GLMessage::glTexImage2D: 444 if (context->getGlobalTraceState()->shouldCollectTextureDataOnGlTexImage()) { 445 fixup_glTexImage2D(glmsg); 446 } 447 break; 448 case GLMessage::glTexSubImage2D: 449 if (context->getGlobalTraceState()->shouldCollectTextureDataOnGlTexImage()) { 450 fixup_glTexSubImage2D(glmsg); 451 } 452 break; 453 case GLMessage::glShaderSource: 454 fixup_glShaderSource(glmsg); 455 break; 456 case GLMessage::glUniform1iv: 457 /* void glUniform1iv(GLint location, GLsizei count, const GLint *value); */ 458 fixup_glUniformGenericInteger(2, 1, glmsg); 459 break; 460 case GLMessage::glUniform2iv: 461 /* void glUniform2iv(GLint location, GLsizei count, const GLint *value); */ 462 fixup_glUniformGenericInteger(2, 2, glmsg); 463 break; 464 case GLMessage::glUniform3iv: 465 /* void glUniform3iv(GLint location, GLsizei count, const GLint *value); */ 466 fixup_glUniformGenericInteger(2, 3, glmsg); 467 break; 468 case GLMessage::glUniform4iv: 469 /* void glUniform4iv(GLint location, GLsizei count, const GLint *value); */ 470 fixup_glUniformGenericInteger(2, 4, glmsg); 471 break; 472 case GLMessage::glUniform1fv: 473 /* void glUniform1fv(GLint location, GLsizei count, const GLfloat *value); */ 474 fixup_glUniformGeneric(2, 1, glmsg); 475 break; 476 case GLMessage::glUniform2fv: 477 /* void glUniform2fv(GLint location, GLsizei count, const GLfloat *value); */ 478 fixup_glUniformGeneric(2, 2, glmsg); 479 break; 480 case GLMessage::glUniform3fv: 481 /* void glUniform3fv(GLint location, GLsizei count, const GLfloat *value); */ 482 fixup_glUniformGeneric(2, 3, glmsg); 483 break; 484 case GLMessage::glUniform4fv: 485 /* void glUniform4fv(GLint location, GLsizei count, const GLfloat *value); */ 486 fixup_glUniformGeneric(2, 4, glmsg); 487 break; 488 case GLMessage::glUniformMatrix2fv: 489 /* void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, 490 const GLfloat* value) */ 491 fixup_glUniformMatrixGeneric(2, glmsg); 492 break; 493 case GLMessage::glUniformMatrix3fv: 494 /* void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, 495 const GLfloat* value) */ 496 fixup_glUniformMatrixGeneric(3, glmsg); 497 break; 498 case GLMessage::glUniformMatrix4fv: 499 /* void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, 500 const GLfloat* value) */ 501 fixup_glUniformMatrixGeneric(4, glmsg); 502 break; 503 case GLMessage::glDrawArrays: 504 /* void glDrawArrays(GLenum mode, GLint first, GLsizei count) */ 505 if (context->getGlobalTraceState()->shouldCollectFbOnGlDraw()) { 506 fixup_addFBContents(context, glmsg, CURRENTLY_BOUND_FB); 507 } 508 break; 509 case GLMessage::glDrawElements: 510 /* void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) */ 511 if (context->getGlobalTraceState()->shouldCollectFbOnGlDraw()) { 512 fixup_addFBContents(context, glmsg, CURRENTLY_BOUND_FB); 513 } 514 break; 515 case GLMessage::glPushGroupMarkerEXT: 516 /* void PushGroupMarkerEXT(sizei length, const char *marker); */ 517 fixup_CStringPtr(1, glmsg); 518 break; 519 case GLMessage::glInsertEventMarkerEXT: 520 /* void InsertEventMarkerEXT(sizei length, const char *marker); */ 521 fixup_CStringPtr(1, glmsg); 522 break; 523 default: 524 break; 525 } 526} 527 528}; 529}; 530