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, (void (*)(void*))&releaseContext);
     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     mVersionMajor(0),
    137     mVersionMinor(0),
    138     mVersionParsed(false),
    139     mState(state),
    140     mBufferedOutputStream(stream),
    141     mElementArrayBuffers(DefaultKeyedVector<GLuint, ElementArrayBuffer*>(NULL))
    142 {
    143     fbcontents = fbcompressed = NULL;
    144     fbcontentsSize = 0;
    145 }
    146 
    147 int GLTraceContext::getId() {
    148     return mId;
    149 }
    150 
    151 int GLTraceContext::getVersion() {
    152     return mVersion;
    153 }
    154 
    155 int GLTraceContext::getVersionMajor() {
    156     if (!mVersionParsed) {
    157         parseGlesVersion();
    158         mVersionParsed = true;
    159     }
    160     return mVersionMajor;
    161 }
    162 
    163 int GLTraceContext::getVersionMinor() {
    164     if (!mVersionParsed) {
    165         parseGlesVersion();
    166         mVersionParsed = true;
    167     }
    168     return mVersionMinor;
    169 }
    170 
    171 GLTraceState *GLTraceContext::getGlobalTraceState() {
    172     return mState;
    173 }
    174 
    175 void GLTraceContext::parseGlesVersion() {
    176     const char* str = (const char*)hooks->gl.glGetString(GL_VERSION);
    177     int major, minor;
    178     if (sscanf(str, "OpenGL ES-CM %d.%d", &major, &minor) != 2) {
    179         if (sscanf(str, "OpenGL ES %d.%d", &major, &minor) != 2) {
    180             ALOGW("Unable to parse GL_VERSION string: \"%s\"", str);
    181             major = 1;
    182             minor = 0;
    183         }
    184     }
    185     mVersionMajor = major;
    186     mVersionMinor = minor;
    187 }
    188 
    189 void GLTraceContext::resizeFBMemory(unsigned minSize) {
    190     if (fbcontentsSize >= minSize) {
    191         return;
    192     }
    193 
    194     if (fbcontents != NULL) {
    195         free(fbcontents);
    196         free(fbcompressed);
    197     }
    198 
    199     fbcontents = malloc(minSize);
    200     fbcompressed = malloc(minSize);
    201 
    202     fbcontentsSize = minSize;
    203 }
    204 
    205 /** obtain a pointer to the compressed framebuffer image */
    206 void GLTraceContext::getCompressedFB(void **fb, unsigned *fbsize, unsigned *fbwidth,
    207                             unsigned *fbheight, FBBinding fbToRead) {
    208     int viewport[4] = {};
    209     hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport);
    210     unsigned fbContentsSize = viewport[2] * viewport[3] * 4;
    211 
    212     resizeFBMemory(fbContentsSize);
    213 
    214     // switch current framebuffer binding if necessary
    215     GLint currentFb = -1;
    216     bool fbSwitched = false;
    217     if (fbToRead != CURRENTLY_BOUND_FB) {
    218         hooks->gl.glGetIntegerv(GL_FRAMEBUFFER_BINDING, &currentFb);
    219 
    220         if (currentFb != 0) {
    221             hooks->gl.glBindFramebuffer(GL_FRAMEBUFFER, 0);
    222             fbSwitched = true;
    223         }
    224     }
    225 
    226     hooks->gl.glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3],
    227                                         GL_RGBA, GL_UNSIGNED_BYTE, fbcontents);
    228 
    229     // switch back to previously bound buffer if necessary
    230     if (fbSwitched) {
    231         hooks->gl.glBindFramebuffer(GL_FRAMEBUFFER, currentFb);
    232     }
    233 
    234     *fbsize = lzf_compress(fbcontents, fbContentsSize, fbcompressed, fbContentsSize);
    235     *fb = fbcompressed;
    236     *fbwidth = viewport[2];
    237     *fbheight = viewport[3];
    238 }
    239 
    240 void GLTraceContext::traceGLMessage(GLMessage *msg) {
    241     mBufferedOutputStream->send(msg);
    242 
    243     GLMessage_Function func = msg->function();
    244     if (func == GLMessage::eglSwapBuffers
    245         || func == GLMessage::eglCreateContext
    246         || func == GLMessage::eglMakeCurrent
    247         || func == GLMessage::glDrawArrays
    248         || func == GLMessage::glDrawElements) {
    249         mBufferedOutputStream->flush();
    250     }
    251 }
    252 
    253 void GLTraceContext::bindBuffer(GLuint bufferId, GLvoid *data, GLsizeiptr size) {
    254     // free previously bound buffer if any
    255     ElementArrayBuffer *oldBuffer = mElementArrayBuffers.valueFor(bufferId);
    256     if (oldBuffer != NULL) {
    257         delete oldBuffer;
    258     }
    259 
    260     mElementArrayBuffers.add(bufferId, new ElementArrayBuffer(data, size));
    261 }
    262 
    263 void GLTraceContext::getBuffer(GLuint bufferId, GLvoid **data, GLsizeiptr *size) {
    264     ElementArrayBuffer *buffer = mElementArrayBuffers.valueFor(bufferId);
    265     if (buffer == NULL) {
    266         *data = NULL;
    267         *size = 0;
    268     } else {
    269         *data = buffer->getBuffer();
    270         *size = buffer->getSize();
    271     }
    272 }
    273 
    274 void GLTraceContext::updateBufferSubData(GLuint bufferId, GLintptr offset, GLvoid *data,
    275                                                             GLsizeiptr size) {
    276     ElementArrayBuffer *buffer = mElementArrayBuffers.valueFor(bufferId);
    277     if (buffer != NULL) {
    278         buffer->updateSubBuffer(offset, data, size);
    279     }
    280 }
    281 
    282 void GLTraceContext::deleteBuffer(GLuint bufferId) {
    283     ElementArrayBuffer *buffer = mElementArrayBuffers.valueFor(bufferId);
    284     if (buffer != NULL) {
    285         delete buffer;
    286         mElementArrayBuffers.removeItem(bufferId);
    287     }
    288 }
    289 
    290 ElementArrayBuffer::ElementArrayBuffer(GLvoid *buf, GLsizeiptr size) {
    291     mBuf = malloc(size);
    292     mSize = size;
    293 
    294     if (buf != NULL) {
    295         memcpy(mBuf, buf, size);
    296     }
    297 }
    298 
    299 ElementArrayBuffer::~ElementArrayBuffer() {
    300     if (mBuf != NULL) {
    301         free(mBuf);
    302         mSize = 0;
    303     }
    304 
    305     mBuf = NULL;
    306 }
    307 
    308 void ElementArrayBuffer::updateSubBuffer(GLintptr offset, const GLvoid* data, GLsizeiptr size) {
    309     if (offset + size <= mSize) {
    310         memcpy((char*)mBuf + offset, data, size);
    311     }
    312 }
    313 
    314 GLvoid *ElementArrayBuffer::getBuffer() {
    315     return mBuf;
    316 }
    317 
    318 GLsizeiptr ElementArrayBuffer::getSize() {
    319     return mSize;
    320 }
    321 
    322 }; // namespace gltrace
    323 }; // namespace android
    324