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