gltrace_context.cpp revision 4e620ddce344e946ced992f61a69c367ff92fe24
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 <pthread.h> 18#include <cutils/log.h> 19 20extern "C" { 21#include "liblzf/lzf.h" 22} 23 24#include "gltrace_context.h" 25 26namespace android { 27namespace gltrace { 28 29using ::android::gl_hooks_t; 30 31static pthread_key_t sTLSKey = -1; 32static pthread_once_t sPthreadOnceKey = PTHREAD_ONCE_INIT; 33 34void createTLSKey() { 35 pthread_key_create(&sTLSKey, (void (*)(void*))&releaseContext); 36} 37 38GLTraceContext *getGLTraceContext() { 39 return (GLTraceContext*) pthread_getspecific(sTLSKey); 40} 41 42void setGLTraceContext(GLTraceContext *c) { 43 pthread_setspecific(sTLSKey, c); 44} 45 46void setupTraceContextThreadSpecific(GLTraceContext *context) { 47 pthread_once(&sPthreadOnceKey, createTLSKey); 48 setGLTraceContext(context); 49} 50 51void releaseContext() { 52 GLTraceContext *c = getGLTraceContext(); 53 if (c != NULL) { 54 delete c; 55 setGLTraceContext(NULL); 56 } 57} 58 59GLTraceState::GLTraceState(TCPStream *stream) { 60 mTraceContextIds = 0; 61 mStream = stream; 62 63 mCollectFbOnEglSwap = false; 64 mCollectFbOnGlDraw = false; 65 mCollectTextureDataOnGlTexImage = false; 66 pthread_rwlock_init(&mTraceOptionsRwLock, NULL); 67} 68 69GLTraceState::~GLTraceState() { 70 if (mStream) { 71 mStream->closeStream(); 72 mStream = NULL; 73 } 74} 75 76TCPStream *GLTraceState::getStream() { 77 return mStream; 78} 79 80void GLTraceState::safeSetValue(bool *ptr, bool value, pthread_rwlock_t *lock) { 81 pthread_rwlock_wrlock(lock); 82 *ptr = value; 83 pthread_rwlock_unlock(lock); 84} 85 86bool GLTraceState::safeGetValue(bool *ptr, pthread_rwlock_t *lock) { 87 pthread_rwlock_rdlock(lock); 88 bool value = *ptr; 89 pthread_rwlock_unlock(lock); 90 return value; 91} 92 93void GLTraceState::setCollectFbOnEglSwap(bool en) { 94 safeSetValue(&mCollectFbOnEglSwap, en, &mTraceOptionsRwLock); 95} 96 97void GLTraceState::setCollectFbOnGlDraw(bool en) { 98 safeSetValue(&mCollectFbOnGlDraw, en, &mTraceOptionsRwLock); 99} 100 101void GLTraceState::setCollectTextureDataOnGlTexImage(bool en) { 102 safeSetValue(&mCollectTextureDataOnGlTexImage, en, &mTraceOptionsRwLock); 103} 104 105bool GLTraceState::shouldCollectFbOnEglSwap() { 106 return safeGetValue(&mCollectFbOnEglSwap, &mTraceOptionsRwLock); 107} 108 109bool GLTraceState::shouldCollectFbOnGlDraw() { 110 return safeGetValue(&mCollectFbOnGlDraw, &mTraceOptionsRwLock); 111} 112 113bool GLTraceState::shouldCollectTextureDataOnGlTexImage() { 114 return safeGetValue(&mCollectTextureDataOnGlTexImage, &mTraceOptionsRwLock); 115} 116 117GLTraceContext *GLTraceState::createTraceContext(int version, EGLContext eglContext) { 118 int id = __sync_fetch_and_add(&mTraceContextIds, 1); 119 120 const size_t DEFAULT_BUFFER_SIZE = 8192; 121 BufferedOutputStream *stream = new BufferedOutputStream(mStream, DEFAULT_BUFFER_SIZE); 122 GLTraceContext *traceContext = new GLTraceContext(id, version, this, stream); 123 mPerContextState[eglContext] = traceContext; 124 125 return traceContext; 126} 127 128GLTraceContext *GLTraceState::getTraceContext(EGLContext c) { 129 return mPerContextState[c]; 130} 131 132GLTraceContext::GLTraceContext(int id, int version, GLTraceState *state, 133 BufferedOutputStream *stream) : 134 mId(id), 135 mVersion(version), 136 mState(state), 137 mBufferedOutputStream(stream), 138 mElementArrayBuffers(DefaultKeyedVector<GLuint, ElementArrayBuffer*>(NULL)) 139{ 140 fbcontents = fbcompressed = NULL; 141 fbcontentsSize = 0; 142} 143 144int GLTraceContext::getId() { 145 return mId; 146} 147 148int GLTraceContext::getVersion() { 149 return mVersion; 150} 151 152GLTraceState *GLTraceContext::getGlobalTraceState() { 153 return mState; 154} 155 156void GLTraceContext::resizeFBMemory(unsigned minSize) { 157 if (fbcontentsSize >= minSize) { 158 return; 159 } 160 161 if (fbcontents != NULL) { 162 free(fbcontents); 163 free(fbcompressed); 164 } 165 166 fbcontents = malloc(minSize); 167 fbcompressed = malloc(minSize); 168 169 fbcontentsSize = minSize; 170} 171 172/** obtain a pointer to the compressed framebuffer image */ 173void GLTraceContext::getCompressedFB(void **fb, unsigned *fbsize, unsigned *fbwidth, 174 unsigned *fbheight, FBBinding fbToRead) { 175 int viewport[4] = {}; 176 hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport); 177 unsigned fbContentsSize = viewport[2] * viewport[3] * 4; 178 179 resizeFBMemory(fbContentsSize); 180 181 // switch current framebuffer binding if necessary 182 GLint currentFb = -1; 183 bool fbSwitched = false; 184 if (fbToRead != CURRENTLY_BOUND_FB) { 185 hooks->gl.glGetIntegerv(GL_FRAMEBUFFER_BINDING, ¤tFb); 186 187 if (currentFb != 0) { 188 hooks->gl.glBindFramebuffer(GL_FRAMEBUFFER, 0); 189 fbSwitched = true; 190 } 191 } 192 193 hooks->gl.glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3], 194 GL_RGBA, GL_UNSIGNED_BYTE, fbcontents); 195 196 // switch back to previously bound buffer if necessary 197 if (fbSwitched) { 198 hooks->gl.glBindFramebuffer(GL_FRAMEBUFFER, currentFb); 199 } 200 201 *fbsize = lzf_compress(fbcontents, fbContentsSize, fbcompressed, fbContentsSize); 202 *fb = fbcompressed; 203 *fbwidth = viewport[2]; 204 *fbheight = viewport[3]; 205} 206 207void GLTraceContext::traceGLMessage(GLMessage *msg) { 208 mBufferedOutputStream->send(msg); 209 210 GLMessage_Function func = msg->function(); 211 if (func == GLMessage::eglSwapBuffers 212 || func == GLMessage::eglCreateContext 213 || func == GLMessage::eglMakeCurrent 214 || func == GLMessage::glDrawArrays 215 || func == GLMessage::glDrawElements) { 216 mBufferedOutputStream->flush(); 217 } 218} 219 220void GLTraceContext::bindBuffer(GLuint bufferId, GLvoid *data, GLsizeiptr size) { 221 // free previously bound buffer if any 222 ElementArrayBuffer *oldBuffer = mElementArrayBuffers.valueFor(bufferId); 223 if (oldBuffer != NULL) { 224 delete oldBuffer; 225 } 226 227 mElementArrayBuffers.add(bufferId, new ElementArrayBuffer(data, size)); 228} 229 230void GLTraceContext::getBuffer(GLuint bufferId, GLvoid **data, GLsizeiptr *size) { 231 ElementArrayBuffer *buffer = mElementArrayBuffers.valueFor(bufferId); 232 if (buffer == NULL) { 233 *data = NULL; 234 *size = 0; 235 } else { 236 *data = buffer->getBuffer(); 237 *size = buffer->getSize(); 238 } 239} 240 241void GLTraceContext::updateBufferSubData(GLuint bufferId, GLintptr offset, GLvoid *data, 242 GLsizeiptr size) { 243 ElementArrayBuffer *buffer = mElementArrayBuffers.valueFor(bufferId); 244 if (buffer != NULL) { 245 buffer->updateSubBuffer(offset, data, size); 246 } 247} 248 249void GLTraceContext::deleteBuffer(GLuint bufferId) { 250 ElementArrayBuffer *buffer = mElementArrayBuffers.valueFor(bufferId); 251 if (buffer != NULL) { 252 delete buffer; 253 mElementArrayBuffers.removeItem(bufferId); 254 } 255} 256 257ElementArrayBuffer::ElementArrayBuffer(GLvoid *buf, GLsizeiptr size) { 258 mBuf = malloc(size); 259 mSize = size; 260 261 if (buf != NULL) { 262 memcpy(mBuf, buf, size); 263 } 264} 265 266ElementArrayBuffer::~ElementArrayBuffer() { 267 if (mBuf != NULL) { 268 free(mBuf); 269 mSize = 0; 270 } 271 272 mBuf = NULL; 273} 274 275void ElementArrayBuffer::updateSubBuffer(GLintptr offset, const GLvoid* data, GLsizeiptr size) { 276 if (offset + size <= mSize) { 277 memcpy((char*)mBuf + offset, data, size); 278 } 279} 280 281GLvoid *ElementArrayBuffer::getBuffer() { 282 return mBuf; 283} 284 285GLsizeiptr ElementArrayBuffer::getSize() { 286 return mSize; 287} 288 289}; // namespace gltrace 290}; // namespace android 291