2 * Copyright 2011, The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <cutils/log.h>
21 #include "liblzf/lzf.h"
24 #include "gltrace_context.h"
29 using ::android::gl_hooks_t;
31 static pthread_key_t sTLSKey = -1;
32 static pthread_once_t sPthreadOnceKey = PTHREAD_ONCE_INIT;
35 pthread_key_create(&sTLSKey, NULL);
38 GLTraceContext *getGLTraceContext() {
39 return (GLTraceContext*) pthread_getspecific(sTLSKey);
42 void setGLTraceContext(GLTraceContext *c) {
43 pthread_setspecific(sTLSKey, c);
46 void setupTraceContextThreadSpecific(GLTraceContext *context) {
47 pthread_once(&sPthreadOnceKey, createTLSKey);
48 setGLTraceContext(context);
51 void releaseContext() {
52 GLTraceContext *c = getGLTraceContext();
55 setGLTraceContext(NULL);
59 GLTraceState::GLTraceState(TCPStream *stream) {
63 mCollectFbOnEglSwap = false;
64 mCollectFbOnGlDraw = false;
65 mCollectTextureDataOnGlTexImage = false;
66 pthread_rwlock_init(&mTraceOptionsRwLock, NULL);
69 GLTraceState::~GLTraceState() {
71 mStream->closeStream();
76 TCPStream *GLTraceState::getStream() {
80 void GLTraceState::safeSetValue(bool *ptr, bool value, pthread_rwlock_t *lock) {
81 pthread_rwlock_wrlock(lock);
83 pthread_rwlock_unlock(lock);
86 bool GLTraceState::safeGetValue(bool *ptr, pthread_rwlock_t *lock) {
87 pthread_rwlock_rdlock(lock);
89 pthread_rwlock_unlock(lock);
93 void GLTraceState::setCollectFbOnEglSwap(bool en) {
94 safeSetValue(&mCollectFbOnEglSwap, en, &mTraceOptionsRwLock);
97 void GLTraceState::setCollectFbOnGlDraw(bool en) {
98 safeSetValue(&mCollectFbOnGlDraw, en, &mTraceOptionsRwLock);
101 void GLTraceState::setCollectTextureDataOnGlTexImage(bool en) {
102 safeSetValue(&mCollectTextureDataOnGlTexImage, en, &mTraceOptionsRwLock);
105 bool GLTraceState::shouldCollectFbOnEglSwap() {
106 return safeGetValue(&mCollectFbOnEglSwap, &mTraceOptionsRwLock);
109 bool GLTraceState::shouldCollectFbOnGlDraw() {
110 return safeGetValue(&mCollectFbOnGlDraw, &mTraceOptionsRwLock);
113 bool GLTraceState::shouldCollectTextureDataOnGlTexImage() {
114 return safeGetValue(&mCollectTextureDataOnGlTexImage, &mTraceOptionsRwLock);
117 GLTraceContext *GLTraceState::createTraceContext(int version, EGLContext eglContext) {
118 int id = __sync_fetch_and_add(&mTraceContextIds, 1);
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;
128 GLTraceContext *GLTraceState::getTraceContext(EGLContext c) {
129 return mPerContextState[c];
132 GLTraceContext::GLTraceContext(int id, GLTraceState *state, BufferedOutputStream *stream) :
135 mBufferedOutputStream(stream),
136 mElementArrayBuffers(DefaultKeyedVector<GLuint, ElementArrayBuffer*>(NULL))
138 fbcontents = fbcompressed = NULL;
142 int GLTraceContext::getId() {
146 GLTraceState *GLTraceContext::getGlobalTraceState() {
150 void GLTraceContext::resizeFBMemory(unsigned minSize) {
151 if (fbcontentsSize >= minSize) {
155 if (fbcontents != NULL) {
160 fbcontents = malloc(minSize);
161 fbcompressed = malloc(minSize);
163 fbcontentsSize = minSize;
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;
173 resizeFBMemory(fbContentsSize);
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, ¤tFb);
181 if (currentFb != 0) {
182 hooks->gl.glBindFramebuffer(GL_FRAMEBUFFER, 0);
187 hooks->gl.glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3],
188 GL_RGBA, GL_UNSIGNED_BYTE, fbcontents);
190 // switch back to previously bound buffer if necessary
192 hooks->gl.glBindFramebuffer(GL_FRAMEBUFFER, currentFb);
195 *fbsize = lzf_compress(fbcontents, fbContentsSize, fbcompressed, fbContentsSize);
197 *fbwidth = viewport[2];
198 *fbheight = viewport[3];
201 void GLTraceContext::traceGLMessage(GLMessage *msg) {
202 mBufferedOutputStream->send(msg);
204 GLMessage_Function func = msg->function();
205 if (func == GLMessage::eglSwapBuffers
206 || func == GLMessage::glDrawArrays
207 || func == GLMessage::glDrawElements) {
208 mBufferedOutputStream->flush();
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) {
219 mElementArrayBuffers.add(bufferId, new ElementArrayBuffer(data, size));
222 void GLTraceContext::getBuffer(GLuint bufferId, GLvoid **data, GLsizeiptr *size) {
223 ElementArrayBuffer *buffer = mElementArrayBuffers.valueFor(bufferId);
224 if (buffer == NULL) {
228 *data = buffer->getBuffer();
229 *size = buffer->getSize();
233 void GLTraceContext::updateBufferSubData(GLuint bufferId, GLintptr offset, GLvoid *data,
235 ElementArrayBuffer *buffer = mElementArrayBuffers.valueFor(bufferId);
236 if (buffer != NULL) {
237 buffer->updateSubBuffer(offset, data, size);
241 void GLTraceContext::deleteBuffer(GLuint bufferId) {
242 ElementArrayBuffer *buffer = mElementArrayBuffers.valueFor(bufferId);
243 if (buffer != NULL) {
245 mElementArrayBuffers.removeItem(bufferId);
249 ElementArrayBuffer::ElementArrayBuffer(GLvoid *buf, GLsizeiptr size) {
254 memcpy(mBuf, buf, size);
258 ElementArrayBuffer::~ElementArrayBuffer() {
267 void ElementArrayBuffer::updateSubBuffer(GLintptr offset, const GLvoid* data, GLsizeiptr size) {
268 if (offset + size <= mSize) {
269 memcpy((char*)mBuf + offset, data, size);
273 GLvoid *ElementArrayBuffer::getBuffer() {
277 GLsizeiptr ElementArrayBuffer::getSize() {
281 }; // namespace gltrace
282 }; // namespace android