• 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 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