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
initLibrary(void)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
initOpenGLRenderer(int width,int height,int portNum,OnPostFn onPost,void * onPostContext)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
stopOpenGLRenderer()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
createOpenGLSubwindow(FBNativeWindowType window,int x,int y,int width,int height,float zRot)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
destroyOpenGLSubwindow()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
setOpenGLDisplayRotation(float zRot)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
repaintOpenGLDisplay()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
createRenderThread(int p_stream_buffer_size,unsigned int clientFlags)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
setStreamMode(int mode)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