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