blob: 65b7662e648c6ca8827ba43f9ddc1c3294a80546 [file] [log] [blame]
Siva Velusamydb974682011-11-30 15:05:37 -08001/*
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>
Siva Velusamy1e81e712011-12-14 12:19:56 -080018#include <cutils/log.h>
Siva Velusamydb974682011-11-30 15:05:37 -080019
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
Siva Velusamy1e81e712011-12-14 12:19:56 -080046void setupTraceContextThreadSpecific(GLTraceContext *context) {
Siva Velusamydb974682011-11-30 15:05:37 -080047 pthread_once(&sPthreadOnceKey, createTLSKey);
Siva Velusamydb974682011-11-30 15:05:37 -080048 setGLTraceContext(context);
49}
50
51void releaseContext() {
52 GLTraceContext *c = getGLTraceContext();
53 if (c != NULL) {
54 delete c;
55 setGLTraceContext(NULL);
56 }
57}
58
Siva Velusamy1e81e712011-12-14 12:19:56 -080059GLTraceState::GLTraceState(TCPStream *stream) {
60 mTraceContextIds = 0;
61 mStream = stream;
Siva Velusamy157fea642012-01-03 14:39:31 -080062
63 mCollectFbOnEglSwap = false;
64 mCollectFbOnGlDraw = false;
65 mCollectTextureDataOnGlTexImage = false;
66 pthread_rwlock_init(&mTraceOptionsRwLock, NULL);
Siva Velusamy1e81e712011-12-14 12:19:56 -080067}
68
69GLTraceState::~GLTraceState() {
70 if (mStream) {
71 mStream->closeStream();
72 mStream = NULL;
73 }
74}
75
76TCPStream *GLTraceState::getStream() {
77 return mStream;
78}
79
Siva Velusamy157fea642012-01-03 14:39:31 -080080void 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
Siva Velusamy1e81e712011-12-14 12:19:56 -0800117GLTraceContext *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);
Siva Velusamy157fea642012-01-03 14:39:31 -0800122 GLTraceContext *traceContext = new GLTraceContext(id, this, stream);
Siva Velusamy1e81e712011-12-14 12:19:56 -0800123 mPerContextState[eglContext] = traceContext;
124
125 return traceContext;
126}
127
128GLTraceContext *GLTraceState::getTraceContext(EGLContext c) {
129 return mPerContextState[c];
130}
131
Siva Velusamy157fea642012-01-03 14:39:31 -0800132GLTraceContext::GLTraceContext(int id, GLTraceState *state, BufferedOutputStream *stream) {
Siva Velusamy1e81e712011-12-14 12:19:56 -0800133 mId = id;
Siva Velusamy157fea642012-01-03 14:39:31 -0800134 mState = state;
Siva Velusamy1e81e712011-12-14 12:19:56 -0800135
Siva Velusamydb974682011-11-30 15:05:37 -0800136 fbcontents = fbcompressed = NULL;
137 fbcontentsSize = 0;
Siva Velusamy1e81e712011-12-14 12:19:56 -0800138 mBufferedOutputStream = stream;
139}
140
141int GLTraceContext::getId() {
142 return mId;
Siva Velusamydb974682011-11-30 15:05:37 -0800143}
144
Siva Velusamy157fea642012-01-03 14:39:31 -0800145GLTraceState *GLTraceContext::getGlobalTraceState() {
146 return mState;
147}
148
Siva Velusamydb974682011-11-30 15:05:37 -0800149void GLTraceContext::resizeFBMemory(unsigned minSize) {
150 if (fbcontentsSize >= minSize) {
151 return;
152 }
153
154 if (fbcontents != NULL) {
155 free(fbcontents);
156 free(fbcompressed);
157 }
158
159 fbcontents = malloc(minSize);
160 fbcompressed = malloc(minSize);
161
162 fbcontentsSize = minSize;
163}
164
165/** obtain a pointer to the compressed framebuffer image */
166void GLTraceContext::getCompressedFB(void **fb, unsigned *fbsize, unsigned *fbwidth,
Siva Velusamy1598ef92011-12-07 16:00:58 -0800167 unsigned *fbheight, FBBinding fbToRead) {
Siva Velusamydb974682011-11-30 15:05:37 -0800168 int viewport[4] = {};
169 hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport);
170 unsigned fbContentsSize = viewport[2] * viewport[3] * 4;
171
172 resizeFBMemory(fbContentsSize);
173
Siva Velusamy1598ef92011-12-07 16:00:58 -0800174 // switch current framebuffer binding if necessary
175 GLint currentFb = -1;
176 bool fbSwitched = false;
177 if (fbToRead != CURRENTLY_BOUND_FB) {
178 hooks->gl.glGetIntegerv(GL_FRAMEBUFFER_BINDING, &currentFb);
179
180 if (currentFb != 0) {
181 hooks->gl.glBindFramebuffer(GL_FRAMEBUFFER, 0);
182 fbSwitched = true;
183 }
184 }
185
Siva Velusamydb974682011-11-30 15:05:37 -0800186 hooks->gl.glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3],
187 GL_RGBA, GL_UNSIGNED_BYTE, fbcontents);
Siva Velusamy1598ef92011-12-07 16:00:58 -0800188
189 // switch back to previously bound buffer if necessary
190 if (fbSwitched) {
191 hooks->gl.glBindFramebuffer(GL_FRAMEBUFFER, currentFb);
192 }
193
Siva Velusamydb974682011-11-30 15:05:37 -0800194 *fbsize = lzf_compress(fbcontents, fbContentsSize, fbcompressed, fbContentsSize);
195 *fb = fbcompressed;
196 *fbwidth = viewport[2];
197 *fbheight = viewport[3];
198}
199
Siva Velusamy1e81e712011-12-14 12:19:56 -0800200void GLTraceContext::traceGLMessage(GLMessage *msg) {
201 mBufferedOutputStream->send(msg);
202
203 GLMessage_Function func = msg->function();
204 if (func == GLMessage::eglSwapBuffers
205 || func == GLMessage::glDrawArrays
206 || func == GLMessage::glDrawElements) {
207 mBufferedOutputStream->flush();
208 }
209}
210
Siva Velusamydb974682011-11-30 15:05:37 -0800211}; // namespace gltrace
212}; // namespace android