• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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