• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
getDbgContextThreadSpecific()28 DbgContext * getDbgContextThreadSpecific() {
29     return (DbgContext*)pthread_getspecific(dbgEGLThreadLocalStorageKey);
30 }
31 
DbgContext(const unsigned version,const gl_hooks_t * const hooks,const unsigned MAX_VERTEX_ATTRIBS)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 
~DbgContext()49 DbgContext::~DbgContext()
50 {
51     delete vertexAttribs;
52     free(lzf_buf);
53     free(lzf_ref[0]);
54     free(lzf_ref[1]);
55 }
56 
CreateDbgContext(const unsigned version,const gl_hooks_t * const hooks)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 
dbgReleaseThread()89 void dbgReleaseThread() {
90     delete getDbgContextThreadSpecific();
91 }
92 
GetBytesPerPixel(const GLenum format,const GLenum type)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 
Fetch(const unsigned index,std::string * const data) const124 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 
Compress(const void * in_data,unsigned int in_len,std::string * const outStr)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 
Decompress(const void * in,const unsigned int inLen,unsigned int * const outLen)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 
GetReadPixelsBuffer(const unsigned size)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 
CompressReadPixelBuffer(std::string * const outStr)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 
GetBuffer()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 
GetBufferSize()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 
glUseProgram(GLuint program)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 
HasNonVBOAttribs(const DbgContext * const ctx)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 
glVertexAttribPointer(GLuint indx,GLint size,GLenum type,GLboolean normalized,GLsizei stride,const GLvoid * ptr)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 
glEnableVertexAttribArray(GLuint index)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 
glDisableVertexAttribArray(GLuint index)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 
glBindBuffer(GLenum target,GLuint buffer)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 
glBufferData(GLenum target,GLsizeiptr size,const GLvoid * data,GLenum usage)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 
glBufferSubData(GLenum target,GLintptr offset,GLsizeiptr size,const GLvoid * data)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 
glDeleteBuffers(GLsizei n,const GLuint * buffers)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