• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
createTLSKey()34 void createTLSKey() {
35     pthread_key_create(&sTLSKey, (void (*)(void*))&releaseContext);
36 }
37 
getGLTraceContext()38 GLTraceContext *getGLTraceContext() {
39     return (GLTraceContext*) pthread_getspecific(sTLSKey);
40 }
41 
setGLTraceContext(GLTraceContext * c)42 void setGLTraceContext(GLTraceContext *c) {
43     pthread_setspecific(sTLSKey, c);
44 }
45 
setupTraceContextThreadSpecific(GLTraceContext * context)46 void setupTraceContextThreadSpecific(GLTraceContext *context) {
47     pthread_once(&sPthreadOnceKey, createTLSKey);
48     setGLTraceContext(context);
49 }
50 
releaseContext()51 void releaseContext() {
52     GLTraceContext *c = getGLTraceContext();
53     if (c != NULL) {
54         delete c;
55         setGLTraceContext(NULL);
56     }
57 }
58 
GLTraceState(TCPStream * stream)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 
~GLTraceState()69 GLTraceState::~GLTraceState() {
70     if (mStream) {
71         mStream->closeStream();
72         mStream = NULL;
73     }
74 }
75 
getStream()76 TCPStream *GLTraceState::getStream() {
77     return mStream;
78 }
79 
safeSetValue(bool * ptr,bool value,pthread_rwlock_t * lock)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 
safeGetValue(bool * ptr,pthread_rwlock_t * lock)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 
setCollectFbOnEglSwap(bool en)93 void GLTraceState::setCollectFbOnEglSwap(bool en) {
94     safeSetValue(&mCollectFbOnEglSwap, en, &mTraceOptionsRwLock);
95 }
96 
setCollectFbOnGlDraw(bool en)97 void GLTraceState::setCollectFbOnGlDraw(bool en) {
98     safeSetValue(&mCollectFbOnGlDraw, en, &mTraceOptionsRwLock);
99 }
100 
setCollectTextureDataOnGlTexImage(bool en)101 void GLTraceState::setCollectTextureDataOnGlTexImage(bool en) {
102     safeSetValue(&mCollectTextureDataOnGlTexImage, en, &mTraceOptionsRwLock);
103 }
104 
shouldCollectFbOnEglSwap()105 bool GLTraceState::shouldCollectFbOnEglSwap() {
106     return safeGetValue(&mCollectFbOnEglSwap, &mTraceOptionsRwLock);
107 }
108 
shouldCollectFbOnGlDraw()109 bool GLTraceState::shouldCollectFbOnGlDraw() {
110     return safeGetValue(&mCollectFbOnGlDraw, &mTraceOptionsRwLock);
111 }
112 
shouldCollectTextureDataOnGlTexImage()113 bool GLTraceState::shouldCollectTextureDataOnGlTexImage() {
114     return safeGetValue(&mCollectTextureDataOnGlTexImage, &mTraceOptionsRwLock);
115 }
116 
createTraceContext(int version,EGLContext eglContext)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 
getTraceContext(EGLContext c)128 GLTraceContext *GLTraceState::getTraceContext(EGLContext c) {
129     return mPerContextState[c];
130 }
131 
GLTraceContext(int id,int version,GLTraceState * state,BufferedOutputStream * stream)132 GLTraceContext::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 
getId()144 int GLTraceContext::getId() {
145     return mId;
146 }
147 
getVersion()148 int GLTraceContext::getVersion() {
149     return mVersion;
150 }
151 
getGlobalTraceState()152 GLTraceState *GLTraceContext::getGlobalTraceState() {
153     return mState;
154 }
155 
resizeFBMemory(unsigned minSize)156 void 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 */
getCompressedFB(void ** fb,unsigned * fbsize,unsigned * fbwidth,unsigned * fbheight,FBBinding fbToRead)173 void 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 
traceGLMessage(GLMessage * msg)207 void GLTraceContext::traceGLMessage(GLMessage *msg) {
208     mBufferedOutputStream->send(msg);
209 
210     GLMessage_Function func = msg->function();
211     if (func == GLMessage::eglSwapBuffers
212         || func == GLMessage::eglCreateContext
213         || func == GLMessage::eglMakeCurrent
214         || func == GLMessage::glDrawArrays
215         || func == GLMessage::glDrawElements) {
216         mBufferedOutputStream->flush();
217     }
218 }
219 
bindBuffer(GLuint bufferId,GLvoid * data,GLsizeiptr size)220 void GLTraceContext::bindBuffer(GLuint bufferId, GLvoid *data, GLsizeiptr size) {
221     // free previously bound buffer if any
222     ElementArrayBuffer *oldBuffer = mElementArrayBuffers.valueFor(bufferId);
223     if (oldBuffer != NULL) {
224         delete oldBuffer;
225     }
226 
227     mElementArrayBuffers.add(bufferId, new ElementArrayBuffer(data, size));
228 }
229 
getBuffer(GLuint bufferId,GLvoid ** data,GLsizeiptr * size)230 void GLTraceContext::getBuffer(GLuint bufferId, GLvoid **data, GLsizeiptr *size) {
231     ElementArrayBuffer *buffer = mElementArrayBuffers.valueFor(bufferId);
232     if (buffer == NULL) {
233         *data = NULL;
234         *size = 0;
235     } else {
236         *data = buffer->getBuffer();
237         *size = buffer->getSize();
238     }
239 }
240 
updateBufferSubData(GLuint bufferId,GLintptr offset,GLvoid * data,GLsizeiptr size)241 void GLTraceContext::updateBufferSubData(GLuint bufferId, GLintptr offset, GLvoid *data,
242                                                             GLsizeiptr size) {
243     ElementArrayBuffer *buffer = mElementArrayBuffers.valueFor(bufferId);
244     if (buffer != NULL) {
245         buffer->updateSubBuffer(offset, data, size);
246     }
247 }
248 
deleteBuffer(GLuint bufferId)249 void GLTraceContext::deleteBuffer(GLuint bufferId) {
250     ElementArrayBuffer *buffer = mElementArrayBuffers.valueFor(bufferId);
251     if (buffer != NULL) {
252         delete buffer;
253         mElementArrayBuffers.removeItem(bufferId);
254     }
255 }
256 
ElementArrayBuffer(GLvoid * buf,GLsizeiptr size)257 ElementArrayBuffer::ElementArrayBuffer(GLvoid *buf, GLsizeiptr size) {
258     mBuf = malloc(size);
259     mSize = size;
260 
261     if (buf != NULL) {
262         memcpy(mBuf, buf, size);
263     }
264 }
265 
~ElementArrayBuffer()266 ElementArrayBuffer::~ElementArrayBuffer() {
267     if (mBuf != NULL) {
268         free(mBuf);
269         mSize = 0;
270     }
271 
272     mBuf = NULL;
273 }
274 
updateSubBuffer(GLintptr offset,const GLvoid * data,GLsizeiptr size)275 void ElementArrayBuffer::updateSubBuffer(GLintptr offset, const GLvoid* data, GLsizeiptr size) {
276     if (offset + size <= mSize) {
277         memcpy((char*)mBuf + offset, data, size);
278     }
279 }
280 
getBuffer()281 GLvoid *ElementArrayBuffer::getBuffer() {
282     return mBuf;
283 }
284 
getSize()285 GLsizeiptr ElementArrayBuffer::getSize() {
286     return mSize;
287 }
288 
289 }; // namespace gltrace
290 }; // namespace android
291