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 char s_renderAddr[256]; 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 int 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 int initOpenGLRenderer(int width, int height, char* addr, size_t addrLen) 80 { 81 82 // 83 // Fail if renderer is already initialized 84 // 85 if (s_renderProc || s_renderThread) { 86 return false; 87 } 88 89 #ifdef RENDER_API_USE_THREAD // should be defined for mac 90 // 91 // initialize the renderer and listen to connections 92 // on a thread in the current process. 93 // 94 bool inited = FrameBuffer::initialize(width, height); 95 if (!inited) { 96 return false; 97 } 98 99 s_renderThread = RenderServer::create(addr, addrLen); 100 if (!s_renderThread) { 101 return false; 102 } 103 strncpy(s_renderAddr, addr, sizeof(s_renderAddr)); 104 105 s_renderThread->start(); 106 107 #else 108 if (onPost) { 109 // onPost callback not supported with separate renderer process. 110 // 111 // If we ever revive separate process support, we could make the choice 112 // between thread and process at runtime instead of compile time, and 113 // choose the thread path if an onPost callback is requested. Or, the 114 // callback could be supported with a separate process using shmem or 115 // other IPC mechanism. 116 return false; 117 } 118 119 // 120 // Launch emulator_renderer 121 // 122 char cmdLine[128]; 123 snprintf(cmdLine, 128, "emulator_renderer -windowid %d -port %d -x %d -y %d -width %d -height %d", 124 (int)window, portNum, x, y, width, height); 125 126 s_renderProc = osUtils::childProcess::create(cmdLine, NULL); 127 if (!s_renderProc) { 128 return false; 129 } 130 131 // 132 // try to connect to the renderer in order to check it 133 // was successfully initialized. 134 // 135 int nTrys = 0; 136 IOStream *dummy = NULL; 137 do { 138 ++nTrys; 139 140 // 141 // Wait a bit to make the renderer process a chance to be 142 // initialized. 143 // On Windows we need during this time to handle windows 144 // events since the renderer generates a subwindow of this 145 // process's window, we need to be responsive for windows 146 // during this time to let the renderer generates this subwindow. 147 // 148 #ifndef _WIN32 149 TimeSleepMS(300); 150 #else 151 long long t0 = GetCurrentTimeMS(); 152 while( (GetCurrentTimeMS() - t0) < 300 ) { 153 MSG msg; 154 int n = 0; 155 while( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) 156 { 157 n++; 158 TranslateMessage( &msg ); 159 DispatchMessage( &msg ); 160 } 161 if (n == 0) TimeSleepMS(10); 162 } 163 #endif 164 165 dummy = createRenderThread(8, 0); 166 167 if (!dummy) { 168 // stop if the process is no longer running 169 if (!osUtils::isProcessRunning(s_renderProc->getPID())) { 170 break; 171 } 172 } 173 } while(!dummy && nTrys < 10); // give up after 3 seconds, XXX: ??? 174 175 if (!dummy) { 176 // 177 // Failed - make sure the process is killed 178 // 179 osUtils::KillProcess(s_renderProc->getPID(), true); 180 delete s_renderProc; 181 s_renderProc = NULL; 182 return false; 183 } 184 185 // destroy the dummy connection 186 delete dummy; 187 #endif 188 189 return true; 190 } 191 192 void setPostCallback(OnPostFn onPost, void* onPostContext) 193 { 194 #ifdef RENDER_API_USE_THREAD // should be defined for mac 195 FrameBuffer* fb = FrameBuffer::getFB(); 196 if (fb) { 197 fb->setPostCallback(onPost, onPostContext); 198 } 199 #else 200 if (onPost) { 201 // onPost callback not supported with separate renderer process. 202 // 203 // If we ever revive separate process support, we could make the choice 204 // between thread and process at runtime instead of compile time, and 205 // choose the thread path if an onPost callback is requested. Or, the 206 // callback could be supported with a separate process using shmem or 207 // other IPC mechanism. 208 return false; 209 } 210 #endif 211 } 212 213 void getHardwareStrings(const char** vendor, const char** renderer, const char** version) 214 { 215 FrameBuffer* fb = FrameBuffer::getFB(); 216 if (fb) { 217 fb->getGLStrings(vendor, renderer, version); 218 } else { 219 *vendor = *renderer = *version = NULL; 220 } 221 } 222 223 int stopOpenGLRenderer(void) 224 { 225 bool ret = false; 226 227 // open a dummy connection to the renderer to make it 228 // realize the exit request. 229 // (send the exit request in clientFlags) 230 IOStream *dummy = createRenderThread(8, IOSTREAM_CLIENT_EXIT_SERVER); 231 if (!dummy) return false; 232 233 if (s_renderProc) { 234 // 235 // wait for the process to exit 236 // 237 int exitStatus; 238 ret = s_renderProc->wait(&exitStatus); 239 240 delete s_renderProc; 241 s_renderProc = NULL; 242 } 243 else if (s_renderThread) { 244 245 // wait for the thread to exit 246 int status; 247 ret = s_renderThread->wait(&status); 248 249 delete s_renderThread; 250 s_renderThread = NULL; 251 } 252 253 return ret; 254 } 255 256 int createOpenGLSubwindow(FBNativeWindowType window, 257 int x, int y, int width, int height, float zRot) 258 { 259 if (s_renderThread) { 260 return FrameBuffer::setupSubWindow(window,x,y,width,height, zRot); 261 } 262 else { 263 // 264 // XXX: should be implemented by sending the renderer process 265 // a request 266 ERR("%s not implemented for separate renderer process !!!\n", 267 __FUNCTION__); 268 } 269 return false; 270 } 271 272 int destroyOpenGLSubwindow(void) 273 { 274 if (s_renderThread) { 275 return FrameBuffer::removeSubWindow(); 276 } 277 else { 278 // 279 // XXX: should be implemented by sending the renderer process 280 // a request 281 ERR("%s not implemented for separate renderer process !!!\n", 282 __FUNCTION__); 283 return false; 284 } 285 } 286 287 void setOpenGLDisplayRotation(float zRot) 288 { 289 if (s_renderThread) { 290 FrameBuffer *fb = FrameBuffer::getFB(); 291 if (fb) { 292 fb->setDisplayRotation(zRot); 293 } 294 } 295 else { 296 // 297 // XXX: should be implemented by sending the renderer process 298 // a request 299 ERR("%s not implemented for separate renderer process !!!\n", 300 __FUNCTION__); 301 } 302 } 303 304 void repaintOpenGLDisplay(void) 305 { 306 if (s_renderThread) { 307 FrameBuffer *fb = FrameBuffer::getFB(); 308 if (fb) { 309 fb->repost(); 310 } 311 } 312 else { 313 // 314 // XXX: should be implemented by sending the renderer process 315 // a request 316 ERR("%s not implemented for separate renderer process !!!\n", 317 __FUNCTION__); 318 } 319 } 320 321 322 /* NOTE: For now, always use TCP mode by default, until the emulator 323 * has been updated to support Unix and Win32 pipes 324 */ 325 #define DEFAULT_STREAM_MODE STREAM_MODE_TCP 326 327 int gRendererStreamMode = DEFAULT_STREAM_MODE; 328 329 IOStream *createRenderThread(int p_stream_buffer_size, unsigned int clientFlags) 330 { 331 SocketStream* stream = NULL; 332 333 if (gRendererStreamMode == STREAM_MODE_TCP) { 334 stream = new TcpStream(p_stream_buffer_size); 335 } else { 336 #ifdef _WIN32 337 stream = new Win32PipeStream(p_stream_buffer_size); 338 #else /* !_WIN32 */ 339 stream = new UnixStream(p_stream_buffer_size); 340 #endif 341 } 342 343 if (!stream) { 344 ERR("createRenderThread failed to create stream\n"); 345 return NULL; 346 } 347 if (stream->connect(s_renderAddr) < 0) { 348 ERR("createRenderThread failed to connect\n"); 349 delete stream; 350 return NULL; 351 } 352 353 // 354 // send clientFlags to the renderer 355 // 356 unsigned int *pClientFlags = 357 (unsigned int *)stream->allocBuffer(sizeof(unsigned int)); 358 *pClientFlags = clientFlags; 359 stream->commitBuffer(sizeof(unsigned int)); 360 361 return stream; 362 } 363 364 int 365 setStreamMode(int mode) 366 { 367 switch (mode) { 368 case STREAM_MODE_DEFAULT: 369 mode = DEFAULT_STREAM_MODE; 370 break; 371 372 case STREAM_MODE_TCP: 373 break; 374 375 #ifndef _WIN32 376 case STREAM_MODE_UNIX: 377 break; 378 #else /* _WIN32 */ 379 case STREAM_MODE_PIPE: 380 break; 381 #endif /* _WIN32 */ 382 default: 383 // Invalid stream mode 384 return false; 385 } 386 gRendererStreamMode = mode; 387 return true; 388 } 389