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 "header.h" 18 19 extern "C" { 20 #include "liblzf/lzf.h" 21 } 22 23 namespace android { 24 25 static pthread_key_t dbgEGLThreadLocalStorageKey = -1; 26 static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER; 27 28 DbgContext * getDbgContextThreadSpecific() { 29 return (DbgContext*)pthread_getspecific(dbgEGLThreadLocalStorageKey); 30 } 31 32 DbgContext::DbgContext(const unsigned version, const gl_hooks_t * const hooks, 33 const unsigned MAX_VERTEX_ATTRIBS) 34 : lzf_buf(NULL), lzf_readIndex(0), lzf_refSize(0), lzf_refBufSize(0) 35 , version(version), hooks(hooks) 36 , MAX_VERTEX_ATTRIBS(MAX_VERTEX_ATTRIBS) 37 , readBytesPerPixel(4) 38 , captureSwap(0), captureDraw(0) 39 , vertexAttribs(new VertexAttrib[MAX_VERTEX_ATTRIBS]) 40 , hasNonVBOAttribs(false), indexBuffers(NULL), indexBuffer(NULL) 41 , program(0), maxAttrib(0) 42 { 43 lzf_ref[0] = lzf_ref[1] = NULL; 44 for (unsigned i = 0; i < MAX_VERTEX_ATTRIBS; i++) 45 vertexAttribs[i] = VertexAttrib(); 46 memset(&expectResponse, 0, sizeof(expectResponse)); 47 } 48 49 DbgContext::~DbgContext() 50 { 51 delete vertexAttribs; 52 free(lzf_buf); 53 free(lzf_ref[0]); 54 free(lzf_ref[1]); 55 } 56 57 DbgContext* CreateDbgContext(const unsigned version, const gl_hooks_t * const hooks) 58 { 59 pthread_mutex_lock(&gThreadLocalStorageKeyMutex); 60 if (dbgEGLThreadLocalStorageKey == -1) 61 pthread_key_create(&dbgEGLThreadLocalStorageKey, NULL); 62 pthread_mutex_unlock(&gThreadLocalStorageKeyMutex); 63 64 assert(version < 2); 65 assert(GL_NO_ERROR == hooks->gl.glGetError()); 66 GLint MAX_VERTEX_ATTRIBS = 0; 67 hooks->gl.glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &MAX_VERTEX_ATTRIBS); 68 DbgContext* dbg = new DbgContext(version, hooks, MAX_VERTEX_ATTRIBS); 69 glesv2debugger::Message msg, cmd; 70 msg.set_context_id(reinterpret_cast<int>(dbg)); 71 msg.set_expect_response(false); 72 msg.set_type(msg.Response); 73 msg.set_function(msg.SETPROP); 74 msg.set_prop(msg.GLConstant); 75 msg.set_arg0(GL_MAX_VERTEX_ATTRIBS); 76 msg.set_arg1(MAX_VERTEX_ATTRIBS); 77 Send(msg, cmd); 78 79 GLint MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0; 80 hooks->gl.glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &MAX_COMBINED_TEXTURE_IMAGE_UNITS); 81 msg.set_arg0(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS); 82 msg.set_arg1(MAX_COMBINED_TEXTURE_IMAGE_UNITS); 83 Send(msg, cmd); 84 85 pthread_setspecific(dbgEGLThreadLocalStorageKey, dbg); 86 return dbg; 87 } 88 89 void dbgReleaseThread() { 90 delete getDbgContextThreadSpecific(); 91 } 92 93 unsigned GetBytesPerPixel(const GLenum format, const GLenum type) 94 { 95 switch (type) { 96 case GL_UNSIGNED_SHORT_5_6_5: 97 case GL_UNSIGNED_SHORT_4_4_4_4: 98 case GL_UNSIGNED_SHORT_5_5_5_1: 99 return 2; 100 case GL_UNSIGNED_BYTE: 101 break; 102 default: 103 LOGE("GetBytesPerPixel: unknown type %x", type); 104 } 105 106 switch (format) { 107 case GL_ALPHA: 108 case GL_LUMINANCE: 109 return 1; 110 case GL_LUMINANCE_ALPHA: 111 return 2; 112 case GL_RGB: 113 return 3; 114 case GL_RGBA: 115 case 0x80E1: // GL_BGRA_EXT 116 return 4; 117 default: 118 LOGE("GetBytesPerPixel: unknown format %x", format); 119 } 120 121 return 1; // in doubt... 122 } 123 124 void DbgContext::Fetch(const unsigned index, std::string * const data) const 125 { 126 // VBO data is already on client, just send user pointer data 127 for (unsigned i = 0; i < maxAttrib; i++) { 128 if (!vertexAttribs[i].enabled) 129 continue; 130 if (vertexAttribs[i].buffer > 0) 131 continue; 132 const char * ptr = (const char *)vertexAttribs[i].ptr; 133 ptr += index * vertexAttribs[i].stride; 134 data->append(ptr, vertexAttribs[i].elemSize); 135 } 136 } 137 138 void DbgContext::Compress(const void * in_data, unsigned int in_len, 139 std::string * const outStr) 140 { 141 if (!lzf_buf) 142 lzf_buf = (char *)malloc(LZF_CHUNK_SIZE); 143 assert(lzf_buf); 144 const uint32_t totalDecompSize = in_len; 145 outStr->append((const char *)&totalDecompSize, sizeof(totalDecompSize)); 146 for (unsigned int i = 0; i < in_len; i += LZF_CHUNK_SIZE) { 147 uint32_t chunkSize = LZF_CHUNK_SIZE; 148 if (i + LZF_CHUNK_SIZE > in_len) 149 chunkSize = in_len - i; 150 const uint32_t compSize = lzf_compress((const char *)in_data + i, chunkSize, 151 lzf_buf, LZF_CHUNK_SIZE); 152 outStr->append((const char *)&chunkSize, sizeof(chunkSize)); 153 outStr->append((const char *)&compSize, sizeof(compSize)); 154 if (compSize > 0) 155 outStr->append(lzf_buf, compSize); 156 else // compressed chunk bigger than LZF_CHUNK_SIZE (and uncompressed) 157 outStr->append((const char *)in_data + i, chunkSize); 158 } 159 } 160 161 unsigned char * DbgContext::Decompress(const void * in, const unsigned int inLen, 162 unsigned int * const outLen) 163 { 164 assert(inLen > 4 * 3); 165 if (inLen < 4 * 3) 166 return NULL; 167 *outLen = *(uint32_t *)in; 168 unsigned char * const out = (unsigned char *)malloc(*outLen); 169 unsigned int outPos = 0; 170 const unsigned char * const end = (const unsigned char *)in + inLen; 171 for (const unsigned char * inData = (const unsigned char *)in + 4; inData < end; ) { 172 const uint32_t chunkOut = *(uint32_t *)inData; 173 inData += 4; 174 const uint32_t chunkIn = *(uint32_t *)inData; 175 inData += 4; 176 if (chunkIn > 0) { 177 assert(inData + chunkIn <= end); 178 assert(outPos + chunkOut <= *outLen); 179 outPos += lzf_decompress(inData, chunkIn, out + outPos, chunkOut); 180 inData += chunkIn; 181 } else { 182 assert(inData + chunkOut <= end); 183 assert(outPos + chunkOut <= *outLen); 184 memcpy(out + outPos, inData, chunkOut); 185 inData += chunkOut; 186 outPos += chunkOut; 187 } 188 } 189 return out; 190 } 191 192 void * DbgContext::GetReadPixelsBuffer(const unsigned size) 193 { 194 if (lzf_refBufSize < size + 8) { 195 lzf_refBufSize = size + 8; 196 lzf_ref[0] = (unsigned *)realloc(lzf_ref[0], lzf_refBufSize); 197 assert(lzf_ref[0]); 198 memset(lzf_ref[0], 0, lzf_refBufSize); 199 lzf_ref[1] = (unsigned *)realloc(lzf_ref[1], lzf_refBufSize); 200 assert(lzf_ref[1]); 201 memset(lzf_ref[1], 0, lzf_refBufSize); 202 } 203 if (lzf_refSize != size) // need to clear unused ref to maintain consistency 204 { // since ref and src are swapped each time 205 memset((char *)lzf_ref[0] + lzf_refSize, 0, lzf_refBufSize - lzf_refSize); 206 memset((char *)lzf_ref[1] + lzf_refSize, 0, lzf_refBufSize - lzf_refSize); 207 } 208 lzf_refSize = size; 209 lzf_readIndex ^= 1; 210 return lzf_ref[lzf_readIndex]; 211 } 212 213 void DbgContext::CompressReadPixelBuffer(std::string * const outStr) 214 { 215 assert(lzf_ref[0] && lzf_ref[1]); 216 unsigned * const ref = lzf_ref[lzf_readIndex ^ 1]; 217 unsigned * const src = lzf_ref[lzf_readIndex]; 218 for (unsigned i = 0; i < lzf_refSize / sizeof(*ref) + 1; i++) 219 ref[i] ^= src[i]; 220 Compress(ref, lzf_refSize, outStr); 221 } 222 223 char * DbgContext::GetBuffer() 224 { 225 if (!lzf_buf) 226 lzf_buf = (char *)malloc(LZF_CHUNK_SIZE); 227 assert(lzf_buf); 228 return lzf_buf; 229 } 230 231 unsigned int DbgContext::GetBufferSize() 232 { 233 if (!lzf_buf) 234 lzf_buf = (char *)malloc(LZF_CHUNK_SIZE); 235 assert(lzf_buf); 236 if (lzf_buf) 237 return LZF_CHUNK_SIZE; 238 else 239 return 0; 240 } 241 242 void DbgContext::glUseProgram(GLuint program) 243 { 244 while (GLenum error = hooks->gl.glGetError()) 245 LOGD("DbgContext::glUseProgram(%u): before glGetError() = 0x%.4X", 246 program, error); 247 this->program = program; 248 maxAttrib = 0; 249 if (program == 0) 250 return; 251 GLint activeAttributes = 0; 252 hooks->gl.glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &activeAttributes); 253 maxAttrib = 0; 254 GLint maxNameLen = -1; 255 hooks->gl.glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxNameLen); 256 char * name = new char [maxNameLen + 1]; 257 name[maxNameLen] = 0; 258 // find total number of attribute slots used 259 for (unsigned i = 0; i < activeAttributes; i++) { 260 GLint size = -1; 261 GLenum type = -1; 262 hooks->gl.glGetActiveAttrib(program, i, maxNameLen + 1, NULL, &size, &type, name); 263 GLint slot = hooks->gl.glGetAttribLocation(program, name); 264 assert(slot >= 0); 265 switch (type) { 266 case GL_FLOAT: 267 case GL_FLOAT_VEC2: 268 case GL_FLOAT_VEC3: 269 case GL_FLOAT_VEC4: 270 slot += size; 271 break; 272 case GL_FLOAT_MAT2: 273 slot += size * 2; 274 break; 275 case GL_FLOAT_MAT3: 276 slot += size * 3; 277 break; 278 case GL_FLOAT_MAT4: 279 slot += size * 4; 280 break; 281 default: 282 assert(0); 283 } 284 if (slot > maxAttrib) 285 maxAttrib = slot; 286 } 287 delete name; 288 while (GLenum error = hooks->gl.glGetError()) 289 LOGD("DbgContext::glUseProgram(%u): after glGetError() = 0x%.4X", 290 program, error); 291 } 292 293 static bool HasNonVBOAttribs(const DbgContext * const ctx) 294 { 295 bool need = false; 296 for (unsigned i = 0; !need && i < ctx->maxAttrib; i++) 297 if (ctx->vertexAttribs[i].enabled && ctx->vertexAttribs[i].buffer == 0) 298 need = true; 299 return need; 300 } 301 302 void DbgContext::glVertexAttribPointer(GLuint indx, GLint size, GLenum type, 303 GLboolean normalized, GLsizei stride, const GLvoid* ptr) 304 { 305 assert(GL_NO_ERROR == hooks->gl.glGetError()); 306 assert(indx < MAX_VERTEX_ATTRIBS); 307 vertexAttribs[indx].size = size; 308 vertexAttribs[indx].type = type; 309 vertexAttribs[indx].normalized = normalized; 310 switch (type) { 311 case GL_FLOAT: 312 vertexAttribs[indx].elemSize = sizeof(GLfloat) * size; 313 break; 314 case GL_INT: 315 case GL_UNSIGNED_INT: 316 vertexAttribs[indx].elemSize = sizeof(GLint) * size; 317 break; 318 case GL_SHORT: 319 case GL_UNSIGNED_SHORT: 320 vertexAttribs[indx].elemSize = sizeof(GLshort) * size; 321 break; 322 case GL_BYTE: 323 case GL_UNSIGNED_BYTE: 324 vertexAttribs[indx].elemSize = sizeof(GLbyte) * size; 325 break; 326 default: 327 assert(0); 328 } 329 if (0 == stride) 330 stride = vertexAttribs[indx].elemSize; 331 vertexAttribs[indx].stride = stride; 332 vertexAttribs[indx].ptr = ptr; 333 hooks->gl.glGetVertexAttribiv(indx, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, 334 (GLint *)&vertexAttribs[indx].buffer); 335 hasNonVBOAttribs = HasNonVBOAttribs(this); 336 } 337 338 void DbgContext::glEnableVertexAttribArray(GLuint index) 339 { 340 if (index >= MAX_VERTEX_ATTRIBS) 341 return; 342 vertexAttribs[index].enabled = true; 343 hasNonVBOAttribs = HasNonVBOAttribs(this); 344 } 345 346 void DbgContext::glDisableVertexAttribArray(GLuint index) 347 { 348 if (index >= MAX_VERTEX_ATTRIBS) 349 return; 350 vertexAttribs[index].enabled = false; 351 hasNonVBOAttribs = HasNonVBOAttribs(this); 352 } 353 354 void DbgContext::glBindBuffer(GLenum target, GLuint buffer) 355 { 356 if (GL_ELEMENT_ARRAY_BUFFER != target) 357 return; 358 if (0 == buffer) { 359 indexBuffer = NULL; 360 return; 361 } 362 VBO * b = indexBuffers; 363 indexBuffer = NULL; 364 while (b) { 365 if (b->name == buffer) { 366 assert(GL_ELEMENT_ARRAY_BUFFER == b->target); 367 indexBuffer = b; 368 break; 369 } 370 b = b->next; 371 } 372 if (!indexBuffer) 373 indexBuffer = indexBuffers = new VBO(buffer, target, indexBuffers); 374 } 375 376 void DbgContext::glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) 377 { 378 if (GL_ELEMENT_ARRAY_BUFFER != target) 379 return; 380 assert(indexBuffer); 381 assert(size >= 0); 382 indexBuffer->size = size; 383 indexBuffer->data = realloc(indexBuffer->data, size); 384 memcpy(indexBuffer->data, data, size); 385 } 386 387 void DbgContext::glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) 388 { 389 if (GL_ELEMENT_ARRAY_BUFFER != target) 390 return; 391 assert(indexBuffer); 392 assert(size >= 0); 393 assert(offset >= 0); 394 assert(offset + size <= indexBuffer->size); 395 memcpy((char *)indexBuffer->data + offset, data, size); 396 } 397 398 void DbgContext::glDeleteBuffers(GLsizei n, const GLuint *buffers) 399 { 400 for (unsigned i = 0; i < n; i++) { 401 for (unsigned j = 0; j < MAX_VERTEX_ATTRIBS; j++) 402 if (buffers[i] == vertexAttribs[j].buffer) { 403 vertexAttribs[j].buffer = 0; 404 vertexAttribs[j].enabled = false; 405 } 406 VBO * b = indexBuffers, * previous = NULL; 407 while (b) { 408 if (b->name == buffers[i]) { 409 assert(GL_ELEMENT_ARRAY_BUFFER == b->target); 410 if (indexBuffer == b) 411 indexBuffer = NULL; 412 if (previous) 413 previous->next = b->next; 414 else 415 indexBuffers = b->next; 416 free(b->data); 417 delete b; 418 break; 419 } 420 previous = b; 421 b = b->next; 422 } 423 } 424 hasNonVBOAttribs = HasNonVBOAttribs(this); 425 } 426 427 }; // namespace android 428