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, &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
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