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 <arpa/inet.h> 18 #include <stdlib.h> 19 #include <cutils/log.h> 20 #include <cutils/properties.h> 21 22 #include "hooks.h" 23 #include "glestrace.h" 24 25 #include "gltrace_context.h" 26 #include "gltrace_egl.h" 27 #include "gltrace_hooks.h" 28 #include "gltrace_transport.h" 29 30 namespace android { 31 32 using gltrace::GLTraceState; 33 using gltrace::GLTraceContext; 34 using gltrace::TCPStream; 35 36 static pthread_mutex_t sGlTraceStateLock = PTHREAD_MUTEX_INITIALIZER; 37 38 static int sGlTraceInProgress; 39 static GLTraceState *sGLTraceState; 40 static pthread_t sReceiveThreadId; 41 42 /** 43 * Task that monitors the control stream from the host and updates 44 * the trace status according to commands received from the host. 45 */ 46 static void *commandReceiveTask(void *arg) { 47 GLTraceState *state = (GLTraceState *)arg; 48 TCPStream *stream = state->getStream(); 49 50 // The control stream always receives an integer size of the 51 // command buffer, followed by the actual command buffer. 52 uint32_t cmdSize; 53 54 // Command Buffer 55 void *cmdBuf = NULL; 56 uint32_t cmdBufSize = 0; 57 58 enum TraceSettingsMasks { 59 READ_FB_ON_EGLSWAP_MASK = 1 << 0, 60 READ_FB_ON_GLDRAW_MASK = 1 << 1, 61 READ_TEXTURE_DATA_ON_GLTEXIMAGE_MASK = 1 << 2, 62 }; 63 64 while (true) { 65 // read command size 66 if (stream->receive(&cmdSize, sizeof(uint32_t)) < 0) { 67 break; 68 } 69 cmdSize = ntohl(cmdSize); 70 71 // ensure command buffer is of required size 72 if (cmdBufSize < cmdSize) { 73 free(cmdBuf); 74 cmdBufSize = cmdSize; 75 cmdBuf = malloc(cmdSize); 76 if (cmdBuf == NULL) 77 break; 78 } 79 80 // receive the command 81 if (stream->receive(cmdBuf, cmdSize) < 0) { 82 break; 83 } 84 85 if (cmdSize != sizeof(uint32_t)) { 86 // Currently, we only support commands that are a single integer, 87 // so we skip all other commands 88 continue; 89 } 90 91 uint32_t cmd = ntohl(*(uint32_t*)cmdBuf); 92 93 bool collectFbOnEglSwap = (cmd & READ_FB_ON_EGLSWAP_MASK) != 0; 94 bool collectFbOnGlDraw = (cmd & READ_FB_ON_GLDRAW_MASK) != 0; 95 bool collectTextureData = (cmd & READ_TEXTURE_DATA_ON_GLTEXIMAGE_MASK) != 0; 96 97 state->setCollectFbOnEglSwap(collectFbOnEglSwap); 98 state->setCollectFbOnGlDraw(collectFbOnGlDraw); 99 state->setCollectTextureDataOnGlTexImage(collectTextureData); 100 101 ALOGD("trace options: eglswap: %d, gldraw: %d, texImage: %d", 102 collectFbOnEglSwap, collectFbOnGlDraw, collectTextureData); 103 } 104 105 ALOGE("Stopping OpenGL Trace Command Receiver\n"); 106 107 free(cmdBuf); 108 return NULL; 109 } 110 111 /** 112 * Starts Trace Server and waits for connection from the host. 113 * Returns -1 in case of connection error, 0 otherwise. 114 */ 115 int GLTrace_start() { 116 int status = 0; 117 int clientSocket = -1; 118 TCPStream *stream = NULL; 119 120 pthread_mutex_lock(&sGlTraceStateLock); 121 122 if (sGlTraceInProgress) { 123 goto done; 124 } 125 126 char udsName[PROPERTY_VALUE_MAX]; 127 property_get("debug.egl.debug_portname", udsName, "gltrace"); 128 clientSocket = gltrace::acceptClientConnection(udsName); 129 if (clientSocket < 0) { 130 ALOGE("Error creating GLTrace server socket. Tracing disabled."); 131 status = -1; 132 goto done; 133 } 134 135 sGlTraceInProgress = 1; 136 137 // create communication channel to the host 138 stream = new TCPStream(clientSocket); 139 140 // initialize tracing state 141 sGLTraceState = new GLTraceState(stream); 142 143 pthread_create(&sReceiveThreadId, NULL, commandReceiveTask, sGLTraceState); 144 145 done: 146 pthread_mutex_unlock(&sGlTraceStateLock); 147 return status; 148 } 149 150 void GLTrace_stop() { 151 pthread_mutex_lock(&sGlTraceStateLock); 152 153 if (sGlTraceInProgress) { 154 sGlTraceInProgress = 0; 155 delete sGLTraceState; 156 sGLTraceState = NULL; 157 } 158 159 pthread_mutex_unlock(&sGlTraceStateLock); 160 } 161 162 void GLTrace_eglCreateContext(int version, EGLContext c) { 163 pthread_mutex_lock(&sGlTraceStateLock); 164 GLTraceState *state = sGLTraceState; 165 pthread_mutex_unlock(&sGlTraceStateLock); 166 167 if (state == NULL) return; 168 169 // update trace state for new EGL context 170 GLTraceContext *traceContext = state->createTraceContext(version, c); 171 gltrace::setupTraceContextThreadSpecific(traceContext); 172 173 // trace command through to the host 174 gltrace::GLTrace_eglCreateContext(version, traceContext->getId()); 175 } 176 177 void GLTrace_eglMakeCurrent(const unsigned version, gl_hooks_t *hooks, EGLContext c) { 178 pthread_mutex_lock(&sGlTraceStateLock); 179 GLTraceState *state = sGLTraceState; 180 pthread_mutex_unlock(&sGlTraceStateLock); 181 182 if (state == NULL) return; 183 184 // setup per context state 185 GLTraceContext *traceContext = state->getTraceContext(c); 186 if (traceContext == NULL) { 187 GLTrace_eglCreateContext(version, c); 188 traceContext = state->getTraceContext(c); 189 } 190 191 traceContext->hooks = hooks; 192 gltrace::setupTraceContextThreadSpecific(traceContext); 193 194 // trace command through to the host 195 gltrace::GLTrace_eglMakeCurrent(traceContext->getId()); 196 } 197 198 void GLTrace_eglReleaseThread() { 199 gltrace::releaseContext(); 200 } 201 202 void GLTrace_eglSwapBuffers(void *dpy, void *draw) { 203 gltrace::GLTrace_eglSwapBuffers(dpy, draw); 204 } 205 206 gl_hooks_t *GLTrace_getGLHooks() { 207 return gltrace::getGLHooks(); 208 } 209 210 } 211