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, 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, 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 
    142 int GLTraceContext::getId() {
    143     return mId;
    144 }
    145 
    146 GLTraceState *GLTraceContext::getGlobalTraceState() {
    147     return mState;
    148 }
    149 
    150 void 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 */
    167 void 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, &currentFb);
    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 
    201 void 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 
    212 void 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 
    222 void 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 
    233 void 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 
    241 void GLTraceContext::deleteBuffer(GLuint bufferId) {
    242     ElementArrayBuffer *buffer = mElementArrayBuffers.valueFor(bufferId);
    243     if (buffer != NULL) {
    244         delete buffer;
    245         mElementArrayBuffers.removeItem(bufferId);
    246     }
    247 }
    248 
    249 ElementArrayBuffer::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 
    258 ElementArrayBuffer::~ElementArrayBuffer() {
    259     if (mBuf != NULL) {
    260         free(mBuf);
    261         mSize = 0;
    262     }
    263 
    264     mBuf = NULL;
    265 }
    266 
    267 void ElementArrayBuffer::updateSubBuffer(GLintptr offset, const GLvoid* data, GLsizeiptr size) {
    268     if (offset + size <= mSize) {
    269         memcpy((char*)mBuf + offset, data, size);
    270     }
    271 }
    272 
    273 GLvoid *ElementArrayBuffer::getBuffer() {
    274     return mBuf;
    275 }
    276 
    277 GLsizeiptr ElementArrayBuffer::getSize() {
    278     return mSize;
    279 }
    280 
    281 }; // namespace gltrace
    282 }; // namespace android
    283