Home | History | Annotate | Download | only in libOpenglRender
      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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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
    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