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 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
getId()147 int GLTraceContext::getId() {
148 return mId;
149 }
150
getVersion()151 int GLTraceContext::getVersion() {
152 return mVersion;
153 }
154
getVersionMajor()155 int GLTraceContext::getVersionMajor() {
156 if (!mVersionParsed) {
157 parseGlesVersion();
158 mVersionParsed = true;
159 }
160 return mVersionMajor;
161 }
162
getVersionMinor()163 int GLTraceContext::getVersionMinor() {
164 if (!mVersionParsed) {
165 parseGlesVersion();
166 mVersionParsed = true;
167 }
168 return mVersionMinor;
169 }
170
getGlobalTraceState()171 GLTraceState *GLTraceContext::getGlobalTraceState() {
172 return mState;
173 }
174
parseGlesVersion()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
resizeFBMemory(unsigned minSize)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 */
getCompressedFB(void ** fb,unsigned * fbsize,unsigned * fbwidth,unsigned * fbheight,FBBinding fbToRead)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, ¤tFb);
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
traceGLMessage(GLMessage * msg)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
bindBuffer(GLuint bufferId,GLvoid * data,GLsizeiptr size)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
getBuffer(GLuint bufferId,GLvoid ** data,GLsizeiptr * size)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
updateBufferSubData(GLuint bufferId,GLintptr offset,GLvoid * data,GLsizeiptr size)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
deleteBuffer(GLuint bufferId)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
ElementArrayBuffer(GLvoid * buf,GLsizeiptr size)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
~ElementArrayBuffer()299 ElementArrayBuffer::~ElementArrayBuffer() {
300 if (mBuf != NULL) {
301 free(mBuf);
302 mSize = 0;
303 }
304
305 mBuf = NULL;
306 }
307
updateSubBuffer(GLintptr offset,const GLvoid * data,GLsizeiptr size)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
getBuffer()314 GLvoid *ElementArrayBuffer::getBuffer() {
315 return mBuf;
316 }
317
getSize()318 GLsizeiptr ElementArrayBuffer::getSize() {
319 return mSize;
320 }
321
322 }; // namespace gltrace
323 }; // namespace android
324