OSDN Git Service

65b7662e648c6ca8827ba43f9ddc1c3294a80546
[android-x86/frameworks-native.git] / opengl / libs / GLES_trace / src / gltrace_context.cpp
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
34 void createTLSKey() {
35     pthread_key_create(&sTLSKey, NULL);
36 }
37
38 GLTraceContext *getGLTraceContext() {
39     return (GLTraceContext*) pthread_getspecific(sTLSKey);
40 }
41
42 void setGLTraceContext(GLTraceContext *c) {
43     pthread_setspecific(sTLSKey, c);
44 }
45
46 void setupTraceContextThreadSpecific(GLTraceContext *context) {
47     pthread_once(&sPthreadOnceKey, createTLSKey);
48     setGLTraceContext(context);
49 }
50
51 void releaseContext() {
52     GLTraceContext *c = getGLTraceContext();
53     if (c != NULL) {
54         delete c;
55         setGLTraceContext(NULL);
56     }
57 }
58
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
69 GLTraceState::~GLTraceState() {
70     if (mStream) {
71         mStream->closeStream();
72         mStream = NULL;
73     }
74 }
75
76 TCPStream *GLTraceState::getStream() {
77     return mStream;
78 }
79
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
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
93 void GLTraceState::setCollectFbOnEglSwap(bool en) {
94     safeSetValue(&mCollectFbOnEglSwap, en, &mTraceOptionsRwLock);
95 }
96
97 void GLTraceState::setCollectFbOnGlDraw(bool en) {
98     safeSetValue(&mCollectFbOnGlDraw, en, &mTraceOptionsRwLock);
99 }
100
101 void GLTraceState::setCollectTextureDataOnGlTexImage(bool en) {
102     safeSetValue(&mCollectTextureDataOnGlTexImage, en, &mTraceOptionsRwLock);
103 }
104
105 bool GLTraceState::shouldCollectFbOnEglSwap() {
106     return safeGetValue(&mCollectFbOnEglSwap, &mTraceOptionsRwLock);
107 }
108
109 bool GLTraceState::shouldCollectFbOnGlDraw() {
110     return safeGetValue(&mCollectFbOnGlDraw, &mTraceOptionsRwLock);
111 }
112
113 bool GLTraceState::shouldCollectTextureDataOnGlTexImage() {
114     return safeGetValue(&mCollectTextureDataOnGlTexImage, &mTraceOptionsRwLock);
115 }
116
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, this, stream);
123     mPerContextState[eglContext] = traceContext;
124
125     return traceContext;
126 }
127
128 GLTraceContext *GLTraceState::getTraceContext(EGLContext c) {
129     return mPerContextState[c];
130 }
131
132 GLTraceContext::GLTraceContext(int id, GLTraceState *state, BufferedOutputStream *stream) {
133     mId = id;
134     mState = state;
135
136     fbcontents = fbcompressed = NULL;
137     fbcontentsSize = 0;
138     mBufferedOutputStream = stream;
139 }
140
141 int GLTraceContext::getId() {
142     return mId;
143 }
144
145 GLTraceState *GLTraceContext::getGlobalTraceState() {
146     return mState;
147 }
148
149 void 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 */
166 void GLTraceContext::getCompressedFB(void **fb, unsigned *fbsize, unsigned *fbwidth, 
167                             unsigned *fbheight, FBBinding fbToRead) {
168     int viewport[4] = {};
169     hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport);
170     unsigned fbContentsSize = viewport[2] * viewport[3] * 4;
171
172     resizeFBMemory(fbContentsSize);
173
174     // 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
186     hooks->gl.glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3],
187                                         GL_RGBA, GL_UNSIGNED_BYTE, fbcontents);
188
189     // switch back to previously bound buffer if necessary
190     if (fbSwitched) {
191         hooks->gl.glBindFramebuffer(GL_FRAMEBUFFER, currentFb);
192     }
193
194     *fbsize = lzf_compress(fbcontents, fbContentsSize, fbcompressed, fbContentsSize);
195     *fb = fbcompressed;
196     *fbwidth = viewport[2];
197     *fbheight = viewport[3];
198 }
199
200 void 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
211 }; // namespace gltrace
212 }; // namespace android