1 /* 2 * Copyright (C) 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 #include "libOpenglRender/render_api.h" 17 #include "IOStream.h" 18 #include "FrameBuffer.h" 19 #include "RenderServer.h" 20 #include "osProcess.h" 21 #include "TimeUtils.h" 22 23 #include "TcpStream.h" 24 #ifdef _WIN32 25 #include "Win32PipeStream.h" 26 #else 27 #include "UnixStream.h" 28 #endif 29 30 #include "EGLDispatch.h" 31 #include "GLDispatch.h" 32 #include "GL2Dispatch.h" 33 34 static osUtils::childProcess *s_renderProc = NULL; 35 static RenderServer *s_renderThread = NULL; 36 static int s_renderPort = 0; 37 38 static IOStream *createRenderThread(int p_stream_buffer_size, 39 unsigned int clientFlags); 40 41 // 42 // For now run the renderer as a thread inside the calling 43 // process instead as running it in a separate process for all 44 // platforms. 45 // at the future we want it to run as a seperate process except for 46 // Mac OS X since it is imposibble on this platform to make one process 47 // render to a window created by another process. 48 // 49 //#ifdef __APPLE__ 50 #define RENDER_API_USE_THREAD 51 //#endif 52 53 bool initLibrary(void) 54 { 55 // 56 // Load EGL Plugin 57 // 58 if (!init_egl_dispatch()) { 59 // Failed to load EGL 60 printf("Failed to init_egl_dispatch\n"); 61 return false; 62 } 63 64 // 65 // Load GLES Plugin 66 // 67 if (!init_gl_dispatch()) { 68 // Failed to load GLES 69 ERR("Failed to init_gl_dispatch\n"); 70 return false; 71 } 72 73 /* failure to init the GLES2 dispatch table is not fatal */ 74 init_gl2_dispatch(); 75 76 return true; 77 } 78 79 bool initOpenGLRenderer(int width, int height, int portNum, 80 OnPostFn onPost, void* onPostContext) 81 { 82 83 // 84 // Fail if renderer is already initialized 85 // 86 if (s_renderProc || s_renderThread) { 87 return false; 88 } 89 90 s_renderPort = portNum; 91 92 #ifdef RENDER_API_USE_THREAD // should be defined for mac 93 // 94 // initialize the renderer and listen to connections 95 // on a thread in the current process. 96 // 97 bool inited = FrameBuffer::initialize(width, height, onPost, onPostContext); 98 if (!inited) { 99 return false; 100 } 101 102 s_renderThread = RenderServer::create(portNum); 103 if (!s_renderThread) { 104 return false; 105 } 106 107 s_renderThread->start(); 108 109 #else 110 if (onPost) { 111 // onPost callback not supported with separate renderer process. 112 // 113 // If we ever revive separate process support, we could make the choice 114 // between thread and process at runtime instead of compile time, and 115 // choose the thread path if an onPost callback is requested. Or, the 116 // callback could be supported with a separate process using shmem or 117 // other IPC mechanism. 118 return false; 119 } 120 121 // 122 // Launch emulator_renderer 123 // 124 char cmdLine[128]; 125 snprintf(cmdLine, 128, "emulator_renderer -windowid %d -port %d -x %d -y %d -width %d -height %d", 126 (int)window, portNum, x, y, width, height); 127 128 s_renderProc = osUtils::childProcess::create(cmdLine, NULL); 129 if (!s_renderProc) { 130 return false; 131 } 132 133 // 134 // try to connect to the renderer in order to check it 135 // was successfully initialized. 136 // 137 int nTrys = 0; 138 IOStream *dummy = NULL; 139 do { 140 ++nTrys; 141 142 // 143 // Wait a bit to make the renderer process a chance to be 144 // initialized. 145 // On Windows we need during this time to handle windows 146 // events since the renderer generates a subwindow of this 147 // process's window, we need to be responsive for windows 148 // during this time to let the renderer generates this subwindow. 149 // 150 #ifndef _WIN32 151 TimeSleepMS(300); 152 #else 153 long long t0 = GetCurrentTimeMS(); 154 while( (GetCurrentTimeMS() - t0) < 300 ) { 155 MSG msg; 156 int n = 0; 157 while( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) 158 { 159 n++; 160 TranslateMessage( &msg ); 161 DispatchMessage( &msg ); 162 } 163 if (n == 0) TimeSleepMS(10); 164 } 165 #endif 166 167 dummy = createRenderThread(8, 0); 168 169 if (!dummy) { 170 // stop if the process is no longer running 171 if (!osUtils::isProcessRunning(s_renderProc->getPID())) { 172 break; 173 } 174 } 175 } while(!dummy && nTrys < 10); // give up after 3 seconds, XXX: ??? 176 177 if (!dummy) { 178 // 179 // Failed - make sure the process is killed 180 // 181 osUtils::KillProcess(s_renderProc->getPID(), true); 182 delete s_renderProc; 183 s_renderProc = NULL; 184 return false; 185 } 186 187 // destroy the dummy connection 188 delete dummy; 189 #endif 190 191 return true; 192 } 193 194 bool stopOpenGLRenderer() 195 { 196 bool ret = false; 197 198 // open a dummy connection to the renderer to make it 199 // realize the exit request. 200 // (send the exit request in clientFlags) 201 IOStream *dummy = createRenderThread(8, IOSTREAM_CLIENT_EXIT_SERVER); 202 if (!dummy) return false; 203 204 if (s_renderProc) { 205 // 206 // wait for the process to exit 207 // 208 int exitStatus; 209 ret = s_renderProc->wait(&exitStatus); 210 211 delete s_renderProc; 212 s_renderProc = NULL; 213 } 214 else if (s_renderThread) { 215 216 // wait for the thread to exit 217 int status; 218 ret = s_renderThread->wait(&status); 219 220 delete s_renderThread; 221 s_renderThread = NULL; 222 } 223 224 return ret; 225 } 226 227 bool createOpenGLSubwindow(FBNativeWindowType window, 228 int x, int y, int width, int height, float zRot) 229 { 230 if (s_renderThread) { 231 return FrameBuffer::setupSubWindow(window,x,y,width,height, zRot); 232 } 233 else { 234 // 235 // XXX: should be implemented by sending the renderer process 236 // a request 237 ERR("%s not implemented for separate renderer process !!!\n", 238 __FUNCTION__); 239 } 240 return false; 241 } 242 243 bool destroyOpenGLSubwindow() 244 { 245 if (s_renderThread) { 246 return FrameBuffer::removeSubWindow(); 247 } 248 else { 249 // 250 // XXX: should be implemented by sending the renderer process 251 // a request 252 ERR("%s not implemented for separate renderer process !!!\n", 253 __FUNCTION__); 254 return false; 255 } 256 } 257 258 void setOpenGLDisplayRotation(float zRot) 259 { 260 if (s_renderThread) { 261 FrameBuffer *fb = FrameBuffer::getFB(); 262 if (fb) { 263 fb->setDisplayRotation(zRot); 264 } 265 } 266 else { 267 // 268 // XXX: should be implemented by sending the renderer process 269 // a request 270 ERR("%s not implemented for separate renderer process !!!\n", 271 __FUNCTION__); 272 } 273 } 274 275 void repaintOpenGLDisplay() 276 { 277 if (s_renderThread) { 278 FrameBuffer *fb = FrameBuffer::getFB(); 279 if (fb) { 280 fb->repost(); 281 } 282 } 283 else { 284 // 285 // XXX: should be implemented by sending the renderer process 286 // a request 287 ERR("%s not implemented for separate renderer process !!!\n", 288 __FUNCTION__); 289 } 290 } 291 292 293 /* NOTE: For now, always use TCP mode by default, until the emulator 294 * has been updated to support Unix and Win32 pipes 295 */ 296 #define DEFAULT_STREAM_MODE STREAM_MODE_TCP 297 298 int gRendererStreamMode = DEFAULT_STREAM_MODE; 299 300 IOStream *createRenderThread(int p_stream_buffer_size, unsigned int clientFlags) 301 { 302 SocketStream* stream = NULL; 303 304 if (gRendererStreamMode == STREAM_MODE_TCP) { 305 stream = new TcpStream(p_stream_buffer_size); 306 } else { 307 #ifdef _WIN32 308 stream = new Win32PipeStream(p_stream_buffer_size); 309 #else /* !_WIN32 */ 310 stream = new UnixStream(p_stream_buffer_size); 311 #endif 312 } 313 314 if (!stream) { 315 ERR("createRenderThread failed to create stream\n"); 316 return NULL; 317 } 318 if (stream->connect(s_renderPort) < 0) { 319 ERR("createRenderThread failed to connect\n"); 320 delete stream; 321 return NULL; 322 } 323 324 // 325 // send clientFlags to the renderer 326 // 327 unsigned int *pClientFlags = 328 (unsigned int *)stream->allocBuffer(sizeof(unsigned int)); 329 *pClientFlags = clientFlags; 330 stream->commitBuffer(sizeof(unsigned int)); 331 332 return stream; 333 } 334 335 int 336 setStreamMode(int mode) 337 { 338 switch (mode) { 339 case STREAM_MODE_DEFAULT: 340 mode = DEFAULT_STREAM_MODE; 341 break; 342 343 case STREAM_MODE_TCP: 344 break; 345 346 #ifndef _WIN32 347 case STREAM_MODE_UNIX: 348 break; 349 #else /* _WIN32 */ 350 case STREAM_MODE_PIPE: 351 break; 352 #endif /* _WIN32 */ 353 default: 354 // Invalid stream mode 355 return -1; 356 } 357 gRendererStreamMode = mode; 358 return 0; 359 } 360