dbgcontext.cpp revision cbe4e5e5ab59adc107373ad52af8bd490000b75c
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
19extern "C"
20{
21#include "liblzf/lzf.h"
22}
23
24namespace android
25{
26
27DbgContext::DbgContext(const unsigned version, const gl_hooks_t * const hooks,
28                       const unsigned MAX_VERTEX_ATTRIBS)
29        : lzf_buf(NULL), lzf_readIndex(0), lzf_refSize(0), lzf_refBufSize(0)
30        , version(version), hooks(hooks)
31        , MAX_VERTEX_ATTRIBS(MAX_VERTEX_ATTRIBS)
32        , vertexAttribs(new VertexAttrib[MAX_VERTEX_ATTRIBS])
33        , hasNonVBOAttribs(false), indexBuffers(NULL), indexBuffer(NULL)
34        , program(0), maxAttrib(0)
35{
36    lzf_ref[0] = lzf_ref[1] = NULL;
37    for (unsigned i = 0; i < MAX_VERTEX_ATTRIBS; i++)
38        vertexAttribs[i] = VertexAttrib();
39    memset(&expectResponse, 0, sizeof(expectResponse));
40}
41
42DbgContext::~DbgContext()
43{
44    delete vertexAttribs;
45    free(lzf_buf);
46    free(lzf_ref[0]);
47    free(lzf_ref[1]);
48}
49
50DbgContext * CreateDbgContext(const unsigned version, const gl_hooks_t * const hooks)
51{
52    assert(version < 2);
53    assert(GL_NO_ERROR == hooks->gl.glGetError());
54    GLint MAX_VERTEX_ATTRIBS = 0;
55    hooks->gl.glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &MAX_VERTEX_ATTRIBS);
56    return new DbgContext(version, hooks, MAX_VERTEX_ATTRIBS);
57}
58
59void DestroyDbgContext(DbgContext * const dbg)
60{
61    delete dbg;
62}
63
64unsigned GetBytesPerPixel(const GLenum format, const GLenum type)
65{
66    switch (type) {
67    case GL_UNSIGNED_SHORT_5_6_5:
68        return 2;
69    case GL_UNSIGNED_SHORT_4_4_4_4:
70        return 2;
71    case GL_UNSIGNED_SHORT_5_5_5_1:
72        return 2;
73    case GL_UNSIGNED_BYTE:
74        break;
75    default:
76        assert(0);
77    }
78
79    switch (format) {
80    case GL_ALPHA:
81        return 1;
82    case GL_LUMINANCE:
83        return 1;
84        break;
85    case GL_LUMINANCE_ALPHA:
86        return 2;
87    case GL_RGB:
88        return 3;
89    case GL_RGBA:
90        return 4;
91    default:
92        assert(0);
93        return 0;
94    }
95}
96
97void DbgContext::Fetch(const unsigned index, std::string * const data) const
98{
99    // VBO data is already on client, just send user pointer data
100    for (unsigned i = 0; i < maxAttrib; i++) {
101        if (!vertexAttribs[i].enabled)
102            continue;
103        if (vertexAttribs[i].buffer > 0)
104            continue;
105        const char * ptr = (const char *)vertexAttribs[i].ptr;
106        ptr += index * vertexAttribs[i].stride;
107        data->append(ptr, vertexAttribs[i].elemSize);
108    }
109}
110
111void DbgContext::Compress(const void * in_data, unsigned int in_len,
112                          std::string * const outStr)
113{
114    if (!lzf_buf)
115        lzf_buf = (char *)malloc(LZF_CHUNK_SIZE);
116    const uint32_t totalDecompSize = in_len;
117    outStr->append((const char *)&totalDecompSize, sizeof(totalDecompSize));
118    for (unsigned int i = 0; i < in_len; i += LZF_CHUNK_SIZE) {
119        uint32_t chunkSize = LZF_CHUNK_SIZE;
120        if (i + LZF_CHUNK_SIZE > in_len)
121            chunkSize = in_len - i;
122        const uint32_t compSize = lzf_compress((const char *)in_data + i, chunkSize,
123                                               lzf_buf, LZF_CHUNK_SIZE);
124        outStr->append((const char *)&chunkSize, sizeof(chunkSize));
125        outStr->append((const char *)&compSize, sizeof(compSize));
126        if (compSize > 0)
127            outStr->append(lzf_buf, compSize);
128        else // compressed chunk bigger than LZF_CHUNK_SIZE (and uncompressed)
129            outStr->append((const char *)in_data + i, chunkSize);
130    }
131}
132
133void * DbgContext::GetReadPixelsBuffer(const unsigned size)
134{
135    if (lzf_refBufSize < size + 8) {
136        lzf_refBufSize = size + 8;
137        lzf_ref[0] = (unsigned *)realloc(lzf_ref[0], lzf_refBufSize);
138        memset(lzf_ref[0], 0, lzf_refBufSize);
139        lzf_ref[1] = (unsigned *)realloc(lzf_ref[1], lzf_refBufSize);
140        memset(lzf_ref[1], 0, lzf_refBufSize);
141    }
142    if (lzf_refSize != size) // need to clear unused ref to maintain consistency
143    { // since ref and src are swapped each time
144        memset((char *)lzf_ref[0] + lzf_refSize, 0, lzf_refBufSize - lzf_refSize);
145        memset((char *)lzf_ref[1] + lzf_refSize, 0, lzf_refBufSize - lzf_refSize);
146    }
147    lzf_refSize = size;
148    lzf_readIndex ^= 1;
149    return lzf_ref[lzf_readIndex];
150}
151
152void DbgContext::CompressReadPixelBuffer(std::string * const outStr)
153{
154    unsigned * const ref = lzf_ref[lzf_readIndex ^ 1];
155    unsigned * const src = lzf_ref[lzf_readIndex];
156    for (unsigned i = 0; i < lzf_refSize / sizeof(*ref) + 1; i++)
157        ref[i] ^= src[i];
158    Compress(ref, lzf_refSize, outStr);
159}
160
161void DbgContext::glUseProgram(GLuint program)
162{
163    while (GLenum error = hooks->gl.glGetError())
164        LOGD("DbgContext::glUseProgram: before glGetError() = 0x%.4X", error);
165
166    this->program = program;
167
168    GLint activeAttributes = 0;
169    hooks->gl.glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &activeAttributes);
170    maxAttrib = 0;
171    GLint maxNameLen = -1;
172    hooks->gl.glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxNameLen);
173    char * name = new char [maxNameLen + 1];
174    name[maxNameLen] = 0;
175    // find total number of attribute slots used
176    for (unsigned i = 0; i < activeAttributes; i++) {
177        GLint size = -1;
178        GLenum type = -1;
179        hooks->gl.glGetActiveAttrib(program, i, maxNameLen + 1, NULL, &size, &type, name);
180        GLint slot = hooks->gl.glGetAttribLocation(program, name);
181        assert(slot >= 0);
182        switch (type) {
183        case GL_FLOAT:
184        case GL_FLOAT_VEC2:
185        case GL_FLOAT_VEC3:
186        case GL_FLOAT_VEC4:
187            slot += size;
188            break;
189        case GL_FLOAT_MAT2:
190            slot += size * 2;
191            break;
192        case GL_FLOAT_MAT3:
193            slot += size * 3;
194            break;
195        case GL_FLOAT_MAT4:
196            slot += size * 4;
197            break;
198        default:
199            assert(0);
200        }
201        if (slot > maxAttrib)
202            maxAttrib = slot;
203    }
204    delete name;
205
206    while (GLenum error = hooks->gl.glGetError())
207        LOGD("DbgContext::glUseProgram: after glGetError() = 0x%.4X", error);
208}
209
210static bool HasNonVBOAttribs(const DbgContext * const ctx)
211{
212    bool need = false;
213    for (unsigned i = 0; !need && i < ctx->maxAttrib; i++)
214        if (ctx->vertexAttribs[i].enabled && ctx->vertexAttribs[i].buffer == 0)
215            need = true;
216    return need;
217}
218
219void DbgContext::glVertexAttribPointer(GLuint indx, GLint size, GLenum type,
220                                       GLboolean normalized, GLsizei stride, const GLvoid* ptr)
221{
222    assert(GL_NO_ERROR == hooks->gl.glGetError());
223    assert(indx < MAX_VERTEX_ATTRIBS);
224    vertexAttribs[indx].size = size;
225    vertexAttribs[indx].type = type;
226    vertexAttribs[indx].normalized = normalized;
227    switch (type) {
228    case GL_FLOAT:
229        vertexAttribs[indx].elemSize = sizeof(GLfloat) * size;
230        break;
231    case GL_INT:
232    case GL_UNSIGNED_INT:
233        vertexAttribs[indx].elemSize = sizeof(GLint) * size;
234        break;
235    case GL_SHORT:
236    case GL_UNSIGNED_SHORT:
237        vertexAttribs[indx].elemSize = sizeof(GLshort) * size;
238        break;
239    case GL_BYTE:
240    case GL_UNSIGNED_BYTE:
241        vertexAttribs[indx].elemSize = sizeof(GLbyte) * size;
242        break;
243    default:
244        assert(0);
245    }
246    if (0 == stride)
247        stride = vertexAttribs[indx].elemSize;
248    vertexAttribs[indx].stride = stride;
249    vertexAttribs[indx].ptr = ptr;
250    hooks->gl.glGetVertexAttribiv(indx, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING,
251                                  (GLint *)&vertexAttribs[indx].buffer);
252    hasNonVBOAttribs = HasNonVBOAttribs(this);
253}
254
255void DbgContext::glEnableVertexAttribArray(GLuint index)
256{
257    assert(index < MAX_VERTEX_ATTRIBS);
258    vertexAttribs[index].enabled = true;
259    hasNonVBOAttribs = HasNonVBOAttribs(this);
260}
261
262void DbgContext::glDisableVertexAttribArray(GLuint index)
263{
264    assert(index < MAX_VERTEX_ATTRIBS);
265    vertexAttribs[index].enabled = false;
266    hasNonVBOAttribs = HasNonVBOAttribs(this);
267}
268
269void DbgContext::glBindBuffer(GLenum target, GLuint buffer)
270{
271    if (GL_ELEMENT_ARRAY_BUFFER != target)
272        return;
273    if (0 == buffer) {
274        indexBuffer = NULL;
275        return;
276    }
277    VBO * b = indexBuffers;
278    indexBuffer = NULL;
279    while (b) {
280        if (b->name == buffer) {
281            assert(GL_ELEMENT_ARRAY_BUFFER == b->target);
282            indexBuffer = b;
283            break;
284        }
285        b = b->next;
286    }
287    if (!indexBuffer)
288        indexBuffer = indexBuffers = new VBO(buffer, target, indexBuffers);
289}
290
291void DbgContext::glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
292{
293    if (GL_ELEMENT_ARRAY_BUFFER != target)
294        return;
295    assert(indexBuffer);
296    assert(size >= 0);
297    indexBuffer->size = size;
298    indexBuffer->data = realloc(indexBuffer->data, size);
299    memcpy(indexBuffer->data, data, size);
300}
301
302void DbgContext::glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
303{
304    if (GL_ELEMENT_ARRAY_BUFFER != target)
305        return;
306    assert(indexBuffer);
307    assert(size >= 0);
308    assert(offset >= 0);
309    assert(offset + size <= indexBuffer->size);
310    memcpy((char *)indexBuffer->data + offset, data, size);
311}
312
313void DbgContext::glDeleteBuffers(GLsizei n, const GLuint *buffers)
314{
315    for (unsigned i = 0; i < n; i++) {
316        for (unsigned j = 0; j < MAX_VERTEX_ATTRIBS; j++)
317            if (buffers[i] == vertexAttribs[j].buffer) {
318                vertexAttribs[j].buffer = 0;
319                vertexAttribs[j].enabled = false;
320            }
321        VBO * b = indexBuffers, * previous = NULL;
322        while (b) {
323            if (b->name == buffers[i]) {
324                assert(GL_ELEMENT_ARRAY_BUFFER == b->target);
325                if (indexBuffer == b)
326                    indexBuffer = NULL;
327                if (previous)
328                    previous->next = b->next;
329                else
330                    indexBuffers = b->next;
331                free(b->data);
332                delete b;
333                break;
334            }
335            previous = b;
336            b = b->next;
337        }
338    }
339    hasNonVBOAttribs = HasNonVBOAttribs(this);
340}
341
342}; // namespace android
343