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
initLibrary(void)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
initOpenGLRenderer(int width,int height,char * addr,size_t addrLen)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
setPostCallback(OnPostFn onPost,void * onPostContext)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
getHardwareStrings(const char ** vendor,const char ** renderer,const char ** version)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
stopOpenGLRenderer(void)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
createOpenGLSubwindow(FBNativeWindowType window,int x,int y,int width,int height,float zRot)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
destroyOpenGLSubwindow(void)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
setOpenGLDisplayRotation(float zRot)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
repaintOpenGLDisplay(void)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
createRenderThread(int p_stream_buffer_size,unsigned int clientFlags)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
setStreamMode(int mode)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