gltrace_context.cpp revision 50129e4ae2777dfbe0738f0f69b17f4d8f9400e2
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, NULL); 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, 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, GLTraceState *state, BufferedOutputStream *stream) : 133 mId(id), 134 mState(state), 135 mBufferedOutputStream(stream), 136 mElementArrayBuffers(DefaultKeyedVector<GLuint, ElementArrayBuffer*>(NULL)) 137{ 138 fbcontents = fbcompressed = NULL; 139 fbcontentsSize = 0; 140} 141 142int GLTraceContext::getId() { 143 return mId; 144} 145 146GLTraceState *GLTraceContext::getGlobalTraceState() { 147 return mState; 148} 149 150void GLTraceContext::resizeFBMemory(unsigned minSize) { 151 if (fbcontentsSize >= minSize) { 152 return; 153 } 154 155 if (fbcontents != NULL) { 156 free(fbcontents); 157 free(fbcompressed); 158 } 159 160 fbcontents = malloc(minSize); 161 fbcompressed = malloc(minSize); 162 163 fbcontentsSize = minSize; 164} 165 166/** obtain a pointer to the compressed framebuffer image */ 167void GLTraceContext::getCompressedFB(void **fb, unsigned *fbsize, unsigned *fbwidth, 168 unsigned *fbheight, FBBinding fbToRead) { 169 int viewport[4] = {}; 170 hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport); 171 unsigned fbContentsSize = viewport[2] * viewport[3] * 4; 172 173 resizeFBMemory(fbContentsSize); 174 175 // switch current framebuffer binding if necessary 176 GLint currentFb = -1; 177 bool fbSwitched = false; 178 if (fbToRead != CURRENTLY_BOUND_FB) { 179 hooks->gl.glGetIntegerv(GL_FRAMEBUFFER_BINDING, ¤tFb); 180 181 if (currentFb != 0) { 182 hooks->gl.glBindFramebuffer(GL_FRAMEBUFFER, 0); 183 fbSwitched = true; 184 } 185 } 186 187 hooks->gl.glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3], 188 GL_RGBA, GL_UNSIGNED_BYTE, fbcontents); 189 190 // switch back to previously bound buffer if necessary 191 if (fbSwitched) { 192 hooks->gl.glBindFramebuffer(GL_FRAMEBUFFER, currentFb); 193 } 194 195 *fbsize = lzf_compress(fbcontents, fbContentsSize, fbcompressed, fbContentsSize); 196 *fb = fbcompressed; 197 *fbwidth = viewport[2]; 198 *fbheight = viewport[3]; 199} 200 201void GLTraceContext::traceGLMessage(GLMessage *msg) { 202 mBufferedOutputStream->send(msg); 203 204 GLMessage_Function func = msg->function(); 205 if (func == GLMessage::eglSwapBuffers 206 || func == GLMessage::glDrawArrays 207 || func == GLMessage::glDrawElements) { 208 mBufferedOutputStream->flush(); 209 } 210} 211 212void GLTraceContext::bindBuffer(GLuint bufferId, GLvoid *data, GLsizeiptr size) { 213 // free previously bound buffer if any 214 ElementArrayBuffer *oldBuffer = mElementArrayBuffers.valueFor(bufferId); 215 if (oldBuffer != NULL) { 216 delete oldBuffer; 217 } 218 219 mElementArrayBuffers.add(bufferId, new ElementArrayBuffer(data, size)); 220} 221 222void GLTraceContext::getBuffer(GLuint bufferId, GLvoid **data, GLsizeiptr *size) { 223 ElementArrayBuffer *buffer = mElementArrayBuffers.valueFor(bufferId); 224 if (buffer == NULL) { 225 *data = NULL; 226 *size = 0; 227 } else { 228 *data = buffer->getBuffer(); 229 *size = buffer->getSize(); 230 } 231} 232 233void GLTraceContext::updateBufferSubData(GLuint bufferId, GLintptr offset, GLvoid *data, 234 GLsizeiptr size) { 235 ElementArrayBuffer *buffer = mElementArrayBuffers.valueFor(bufferId); 236 if (buffer != NULL) { 237 buffer->updateSubBuffer(offset, data, size); 238 } 239} 240 241void GLTraceContext::deleteBuffer(GLuint bufferId) { 242 ElementArrayBuffer *buffer = mElementArrayBuffers.valueFor(bufferId); 243 if (buffer != NULL) { 244 delete buffer; 245 mElementArrayBuffers.removeItem(bufferId); 246 } 247} 248 249ElementArrayBuffer::ElementArrayBuffer(GLvoid *buf, GLsizeiptr size) { 250 mBuf = malloc(size); 251 mSize = size; 252 253 if (buf != NULL) { 254 memcpy(mBuf, buf, size); 255 } 256} 257 258ElementArrayBuffer::~ElementArrayBuffer() { 259 if (mBuf != NULL) { 260 free(mBuf); 261 mSize = 0; 262 } 263 264 mBuf = NULL; 265} 266 267void ElementArrayBuffer::updateSubBuffer(GLintptr offset, const GLvoid* data, GLsizeiptr size) { 268 if (offset + size <= mSize) { 269 memcpy((char*)mBuf + offset, data, size); 270 } 271} 272 273GLvoid *ElementArrayBuffer::getBuffer() { 274 return mBuf; 275} 276 277GLsizeiptr ElementArrayBuffer::getSize() { 278 return mSize; 279} 280 281}; // namespace gltrace 282}; // namespace android 283