Home | History | Annotate | Download | only in src
      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 
     20 extern "C" {
     21 #include "liblzf/lzf.h"
     22 }
     23 
     24 #include "gltrace_context.h"
     25 
     26 namespace android {
     27 namespace gltrace {
     28 
     29 using ::android::gl_hooks_t;
     30 
     31 static pthread_key_t sTLSKey = -1;
     32 static pthread_once_t sPthreadOnceKey = PTHREAD_ONCE_INIT;
     33 
     34 void createTLSKey() {
     35     pthread_key_create(&sTLSKey, NULL);
     36 }
     37 
     38 GLTraceContext *getGLTraceContext() {
     39     return (GLTraceContext*) pthread_getspecific(sTLSKey);
     40 }
     41 
     42 void setGLTraceContext(GLTraceContext *c) {
     43     pthread_setspecific(sTLSKey, c);
     44 }
     45 
     46 void setupTraceContextThreadSpecific(GLTraceContext *context) {
     47     pthread_once(&sPthreadOnceKey, createTLSKey);
     48     setGLTraceContext(context);
     49 }
     50 
     51 void releaseContext() {
     52     GLTraceContext *c = getGLTraceContext();
     53     if (c != NULL) {
     54         delete c;
     55         setGLTraceContext(NULL);
     56     }
     57 }
     58 
     59 GLTraceState::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 
     69 GLTraceState::~GLTraceState() {
     70     if (mStream) {
     71         mStream->closeStream();
     72         mStream = NULL;
     73     }
     74 }
     75 
     76 TCPStream *GLTraceState::getStream() {
     77     return mStream;
     78 }
     79 
     80 void 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 
     86 bool 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 
     93 void GLTraceState::setCollectFbOnEglSwap(bool en) {
     94     safeSetValue(&mCollectFbOnEglSwap, en, &mTraceOptionsRwLock);
     95 }
     96 
     97 void GLTraceState::setCollectFbOnGlDraw(bool en) {
     98     safeSetValue(&mCollectFbOnGlDraw, en, &mTraceOptionsRwLock);
     99 }
    100 
    101 void GLTraceState::setCollectTextureDataOnGlTexImage(bool en) {
    102     safeSetValue(&mCollectTextureDataOnGlTexImage, en, &mTraceOptionsRwLock);
    103 }
    104 
    105 bool GLTraceState::shouldCollectFbOnEglSwap() {
    106     return safeGetValue(&mCollectFbOnEglSwap, &mTraceOptionsRwLock);
    107 }
    108 
    109 bool GLTraceState::shouldCollectFbOnGlDraw() {
    110     return safeGetValue(&mCollectFbOnGlDraw, &mTraceOptionsRwLock);
    111 }
    112 
    113 bool GLTraceState::shouldCollectTextureDataOnGlTexImage() {
    114     return safeGetValue(&mCollectTextureDataOnGlTexImage, &mTraceOptionsRwLock);
    115 }
    116 
    117 GLTraceContext *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 
    128 GLTraceContext *GLTraceState::getTraceContext(EGLContext c) {
    129     return mPerContextState[c];
    130 }
    131 
    132 GLTraceContext::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 
    144 int GLTraceContext::getId() {
    145     return mId;
    146 }
    147 
    148 int GLTraceContext::getVersion() {
    149     return mVersion;
    150 }
    151 
    152 GLTraceState *GLTraceContext::getGlobalTraceState() {
    153     return mState;
    154 }
    155 
    156 void 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 */
    173 void 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, &currentFb);
    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 
    207 void 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 
    220 void 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 
    230 void 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 
    241 void 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 
    249 void GLTraceContext::deleteBuffer(GLuint bufferId) {
    250     ElementArrayBuffer *buffer = mElementArrayBuffers.valueFor(bufferId);
    251     if (buffer != NULL) {
    252         delete buffer;
    253         mElementArrayBuffers.removeItem(bufferId);
    254     }
    255 }
    256 
    257 ElementArrayBuffer::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 
    266 ElementArrayBuffer::~ElementArrayBuffer() {
    267     if (mBuf != NULL) {
    268         free(mBuf);
    269         mSize = 0;
    270     }
    271 
    272     mBuf = NULL;
    273 }
    274 
    275 void ElementArrayBuffer::updateSubBuffer(GLintptr offset, const GLvoid* data, GLsizeiptr size) {
    276     if (offset + size <= mSize) {
    277         memcpy((char*)mBuf + offset, data, size);
    278     }
    279 }
    280 
    281 GLvoid *ElementArrayBuffer::getBuffer() {
    282     return mBuf;
    283 }
    284 
    285 GLsizeiptr ElementArrayBuffer::getSize() {
    286     return mSize;
    287 }
    288 
    289 }; // namespace gltrace
    290 }; // namespace android
    291