gltrace_context.cpp revision 3ef9e9671c224af82d2efec1a1e9a275fb9acf44
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, version, 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, 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
144int GLTraceContext::getId() {
145    return mId;
146}
147
148int GLTraceContext::getVersion() {
149    return mVersion;
150}
151
152GLTraceState *GLTraceContext::getGlobalTraceState() {
153    return mState;
154}
155
156void 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 */
173void 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
207void GLTraceContext::traceGLMessage(GLMessage *msg) {
208    mBufferedOutputStream->send(msg);
209
210    GLMessage_Function func = msg->function();
211    if (func == GLMessage::eglSwapBuffers
212        || func == GLMessage::glDrawArrays
213        || func == GLMessage::glDrawElements) {
214        mBufferedOutputStream->flush();
215    }
216}
217
218void GLTraceContext::bindBuffer(GLuint bufferId, GLvoid *data, GLsizeiptr size) {
219    // free previously bound buffer if any
220    ElementArrayBuffer *oldBuffer = mElementArrayBuffers.valueFor(bufferId);
221    if (oldBuffer != NULL) {
222        delete oldBuffer;
223    }
224
225    mElementArrayBuffers.add(bufferId, new ElementArrayBuffer(data, size));
226}
227
228void GLTraceContext::getBuffer(GLuint bufferId, GLvoid **data, GLsizeiptr *size) {
229    ElementArrayBuffer *buffer = mElementArrayBuffers.valueFor(bufferId);
230    if (buffer == NULL) {
231        *data = NULL;
232        *size = 0;
233    } else {
234        *data = buffer->getBuffer();
235        *size = buffer->getSize();
236    }
237}
238
239void GLTraceContext::updateBufferSubData(GLuint bufferId, GLintptr offset, GLvoid *data,
240                                                            GLsizeiptr size) {
241    ElementArrayBuffer *buffer = mElementArrayBuffers.valueFor(bufferId);
242    if (buffer != NULL) {
243        buffer->updateSubBuffer(offset, data, size);
244    }
245}
246
247void GLTraceContext::deleteBuffer(GLuint bufferId) {
248    ElementArrayBuffer *buffer = mElementArrayBuffers.valueFor(bufferId);
249    if (buffer != NULL) {
250        delete buffer;
251        mElementArrayBuffers.removeItem(bufferId);
252    }
253}
254
255ElementArrayBuffer::ElementArrayBuffer(GLvoid *buf, GLsizeiptr size) {
256    mBuf = malloc(size);
257    mSize = size;
258
259    if (buf != NULL) {
260        memcpy(mBuf, buf, size);
261    }
262}
263
264ElementArrayBuffer::~ElementArrayBuffer() {
265    if (mBuf != NULL) {
266        free(mBuf);
267        mSize = 0;
268    }
269
270    mBuf = NULL;
271}
272
273void ElementArrayBuffer::updateSubBuffer(GLintptr offset, const GLvoid* data, GLsizeiptr size) {
274    if (offset + size <= mSize) {
275        memcpy((char*)mBuf + offset, data, size);
276    }
277}
278
279GLvoid *ElementArrayBuffer::getBuffer() {
280    return mBuf;
281}
282
283GLsizeiptr ElementArrayBuffer::getSize() {
284    return mSize;
285}
286
287}; // namespace gltrace
288}; // namespace android
289