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