Home | History | Annotate | Download | only in src
      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