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