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 "FrameBuffer.h"
     17 #include "NativeSubWindow.h"
     18 #include "FBConfig.h"
     19 #include "EGLDispatch.h"
     20 #include "GLDispatch.h"
     21 #include "GL2Dispatch.h"
     22 #include "ThreadInfo.h"
     23 #include <stdio.h>
     24 #include "TimeUtils.h"
     25 
     26 FrameBuffer *FrameBuffer::s_theFrameBuffer = NULL;
     27 HandleType FrameBuffer::s_nextHandle = 0;
     28 
     29 #ifdef WITH_GLES2
     30 static const char *getGLES2ExtensionString(EGLDisplay p_dpy)
     31 {
     32     EGLConfig config;
     33     EGLSurface surface;
     34 
     35     GLint configAttribs[] = {
     36         EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
     37         EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
     38         EGL_NONE
     39     };
     40 
     41     int n;
     42     if (!s_egl.eglChooseConfig(p_dpy, configAttribs,
     43                                &config, 1, &n)) {
     44         return NULL;
     45     }
     46 
     47     EGLint pbufAttribs[] = {
     48         EGL_WIDTH, 1,
     49         EGL_HEIGHT, 1,
     50         EGL_NONE
     51     };
     52 
     53     surface = s_egl.eglCreatePbufferSurface(p_dpy, config, pbufAttribs);
     54     if (surface == EGL_NO_SURFACE) {
     55         return NULL;
     56     }
     57 
     58     GLint gl2ContextAttribs[] = {
     59         EGL_CONTEXT_CLIENT_VERSION, 2,
     60         EGL_NONE
     61     };
     62 
     63     EGLContext ctx = s_egl.eglCreateContext(p_dpy, config,
     64                                             EGL_NO_CONTEXT,
     65                                             gl2ContextAttribs);
     66     if (ctx == EGL_NO_CONTEXT) {
     67         s_egl.eglDestroySurface(p_dpy, surface);
     68         return NULL;
     69     }
     70 
     71     if (!s_egl.eglMakeCurrent(p_dpy, surface, surface, ctx)) {
     72         s_egl.eglDestroySurface(p_dpy, surface);
     73         s_egl.eglDestroyContext(p_dpy, ctx);
     74         return NULL;
     75     }
     76 
     77     const char *extString = (const char *)s_gl2.glGetString(GL_EXTENSIONS);
     78     if (!extString) {
     79         extString = "";
     80     }
     81 
     82     s_egl.eglMakeCurrent(p_dpy, NULL, NULL, NULL);
     83     s_egl.eglDestroyContext(p_dpy, ctx);
     84     s_egl.eglDestroySurface(p_dpy, surface);
     85 
     86     return extString;
     87 }
     88 #endif
     89 
     90 void FrameBuffer::finalize(){
     91     if(s_theFrameBuffer){
     92         s_theFrameBuffer->removeSubWindow();
     93         s_theFrameBuffer->m_colorbuffers.clear();
     94         s_theFrameBuffer->m_windows.clear();
     95         s_theFrameBuffer->m_contexts.clear();
     96         s_egl.eglMakeCurrent(s_theFrameBuffer->m_eglDisplay, NULL, NULL, NULL);
     97         s_egl.eglDestroyContext(s_theFrameBuffer->m_eglDisplay,s_theFrameBuffer->m_eglContext);
     98         s_egl.eglDestroyContext(s_theFrameBuffer->m_eglDisplay,s_theFrameBuffer->m_pbufContext);
     99         s_egl.eglDestroySurface(s_theFrameBuffer->m_eglDisplay,s_theFrameBuffer->m_pbufSurface);
    100         s_theFrameBuffer = NULL;
    101     }
    102 }
    103 
    104 bool FrameBuffer::initialize(int width, int height)
    105 {
    106     if (s_theFrameBuffer != NULL) {
    107         return true;
    108     }
    109 
    110     //
    111     // allocate space for the FrameBuffer object
    112     //
    113     FrameBuffer *fb = new FrameBuffer(width, height);
    114     if (!fb) {
    115         ERR("Failed to create fb\n");
    116         return false;
    117     }
    118 
    119 #ifdef WITH_GLES2
    120     //
    121     // Try to load GLES2 Plugin, not mandatory
    122     //
    123     if (getenv("ANDROID_NO_GLES2")) {
    124         fb->m_caps.hasGL2 = false;
    125     }
    126     else {
    127         fb->m_caps.hasGL2 = s_gl2_enabled;
    128     }
    129 #else
    130     fb->m_caps.hasGL2 = false;
    131 #endif
    132 
    133     //
    134     // Initialize backend EGL display
    135     //
    136     fb->m_eglDisplay = s_egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
    137     if (fb->m_eglDisplay == EGL_NO_DISPLAY) {
    138         ERR("Failed to Initialize backend EGL display\n");
    139         delete fb;
    140         return false;
    141     }
    142 
    143     if (!s_egl.eglInitialize(fb->m_eglDisplay, &fb->m_caps.eglMajor, &fb->m_caps.eglMinor)) {
    144         ERR("Failed to eglInitialize\n");
    145         delete fb;
    146         return false;
    147     }
    148 
    149     DBG("egl: %d %d\n", fb->m_caps.eglMajor, fb->m_caps.eglMinor);
    150     s_egl.eglBindAPI(EGL_OPENGL_ES_API);
    151 
    152     //
    153     // if GLES2 plugin has loaded - try to make GLES2 context and
    154     // get GLES2 extension string
    155     //
    156     const char *gl2Extensions = NULL;
    157 #ifdef WITH_GLES2
    158     if (fb->m_caps.hasGL2) {
    159         gl2Extensions = getGLES2ExtensionString(fb->m_eglDisplay);
    160         if (!gl2Extensions) {
    161             // Could not create GLES2 context - drop GL2 capability
    162             fb->m_caps.hasGL2 = false;
    163         }
    164     }
    165 #endif
    166 
    167     //
    168     // Create EGL context for framebuffer post rendering.
    169     //
    170 #if 0
    171     GLint configAttribs[] = {
    172         EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
    173         EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
    174         EGL_NONE
    175     };
    176 #else
    177     GLint configAttribs[] = {
    178         EGL_RED_SIZE, 1,
    179         EGL_GREEN_SIZE, 1,
    180         EGL_BLUE_SIZE, 1,
    181         EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
    182         EGL_NONE
    183     };
    184 #endif
    185 
    186     int n;
    187     if (!s_egl.eglChooseConfig(fb->m_eglDisplay, configAttribs,
    188                                &fb->m_eglConfig, 1, &n)) {
    189         ERR("Failed on eglChooseConfig\n");
    190         delete fb;
    191         return false;
    192     }
    193 
    194     GLint glContextAttribs[] = {
    195         EGL_CONTEXT_CLIENT_VERSION, 1,
    196         EGL_NONE
    197     };
    198 
    199     fb->m_eglContext = s_egl.eglCreateContext(fb->m_eglDisplay, fb->m_eglConfig,
    200                                               EGL_NO_CONTEXT,
    201                                               glContextAttribs);
    202     if (fb->m_eglContext == EGL_NO_CONTEXT) {
    203         printf("Failed to create Context 0x%x\n", s_egl.eglGetError());
    204         delete fb;
    205         return false;
    206     }
    207 
    208     //
    209     // Create another context which shares with the eglContext to be used
    210     // when we bind the pbuffer. That prevent switching drawable binding
    211     // back and forth on framebuffer context.
    212     // The main purpose of it is to solve a "blanking" behaviour we see on
    213     // on Mac platform when switching binded drawable for a context however
    214     // it is more efficient on other platforms as well.
    215     //
    216     fb->m_pbufContext = s_egl.eglCreateContext(fb->m_eglDisplay, fb->m_eglConfig,
    217                                                fb->m_eglContext,
    218                                                glContextAttribs);
    219     if (fb->m_pbufContext == EGL_NO_CONTEXT) {
    220         printf("Failed to create Pbuffer Context 0x%x\n", s_egl.eglGetError());
    221         delete fb;
    222         return false;
    223     }
    224 
    225     //
    226     // create a 1x1 pbuffer surface which will be used for binding
    227     // the FB context.
    228     // The FB output will go to a subwindow, if one exist.
    229     //
    230     EGLint pbufAttribs[] = {
    231         EGL_WIDTH, 1,
    232         EGL_HEIGHT, 1,
    233         EGL_NONE
    234     };
    235 
    236     fb->m_pbufSurface = s_egl.eglCreatePbufferSurface(fb->m_eglDisplay,
    237                                                   fb->m_eglConfig,
    238                                                   pbufAttribs);
    239     if (fb->m_pbufSurface == EGL_NO_SURFACE) {
    240         printf("Failed to create pbuf surface for FB 0x%x\n", s_egl.eglGetError());
    241         delete fb;
    242         return false;
    243     }
    244 
    245     // Make the context current
    246     if (!fb->bind_locked()) {
    247         ERR("Failed to make current\n");
    248         delete fb;
    249         return false;
    250     }
    251 
    252     //
    253     // Initilize framebuffer capabilities
    254     //
    255     const char *glExtensions = (const char *)s_gl.glGetString(GL_EXTENSIONS);
    256     bool has_gl_oes_image = false;
    257     if (glExtensions) {
    258         has_gl_oes_image = strstr(glExtensions, "GL_OES_EGL_image") != NULL;
    259     }
    260 
    261     if (fb->m_caps.hasGL2 && has_gl_oes_image) {
    262         has_gl_oes_image &= (strstr(gl2Extensions, "GL_OES_EGL_image") != NULL);
    263     }
    264 
    265     const char *eglExtensions = s_egl.eglQueryString(fb->m_eglDisplay,
    266                                                      EGL_EXTENSIONS);
    267 
    268     if (eglExtensions && has_gl_oes_image) {
    269         fb->m_caps.has_eglimage_texture_2d =
    270              strstr(eglExtensions, "EGL_KHR_gl_texture_2D_image") != NULL;
    271         fb->m_caps.has_eglimage_renderbuffer =
    272              strstr(eglExtensions, "EGL_KHR_gl_renderbuffer_image") != NULL;
    273     }
    274     else {
    275         fb->m_caps.has_eglimage_texture_2d = false;
    276         fb->m_caps.has_eglimage_renderbuffer = false;
    277     }
    278 
    279     //
    280     // Fail initialization if not all of the following extensions
    281     // exist:
    282     //     EGL_KHR_gl_texture_2d_image
    283     //     GL_OES_EGL_IMAGE (by both GLES implementations [1 and 2])
    284     //
    285     if (!fb->m_caps.has_eglimage_texture_2d) {
    286         ERR("Failed: Missing egl_image related extension(s)\n");
    287         delete fb;
    288         return false;
    289     }
    290 
    291     //
    292     // Initialize set of configs
    293     //
    294     InitConfigStatus configStatus = FBConfig::initConfigList(fb);
    295     if (configStatus == INIT_CONFIG_FAILED) {
    296         ERR("Failed: Initialize set of configs\n");
    297         delete fb;
    298         return false;
    299     }
    300 
    301     //
    302     // Check that we have config for each GLES and GLES2
    303     //
    304     int nConfigs = FBConfig::getNumConfigs();
    305     int nGLConfigs = 0;
    306     int nGL2Configs = 0;
    307     for (int i=0; i<nConfigs; i++) {
    308         GLint rtype = FBConfig::get(i)->getRenderableType();
    309         if (0 != (rtype & EGL_OPENGL_ES_BIT)) {
    310             nGLConfigs++;
    311         }
    312         if (0 != (rtype & EGL_OPENGL_ES2_BIT)) {
    313             nGL2Configs++;
    314         }
    315     }
    316 
    317     //
    318     // Fail initialization if no GLES configs exist
    319     //
    320     if (nGLConfigs == 0) {
    321         delete fb;
    322         return false;
    323     }
    324 
    325     //
    326     // If no GLES2 configs exist - not GLES2 capability
    327     //
    328     if (nGL2Configs == 0) {
    329         fb->m_caps.hasGL2 = false;
    330     }
    331 
    332     //
    333     // Initialize some GL state in the pbuffer context
    334     //
    335     fb->initGLState();
    336 
    337     // release the FB context
    338     fb->unbind_locked();
    339 
    340     //
    341     // Keep the singleton framebuffer pointer
    342     //
    343     s_theFrameBuffer = fb;
    344     return true;
    345 }
    346 
    347 FrameBuffer::FrameBuffer(int p_width, int p_height) :
    348     m_width(p_width),
    349     m_height(p_height),
    350     m_eglDisplay(EGL_NO_DISPLAY),
    351     m_eglSurface(EGL_NO_SURFACE),
    352     m_eglContext(EGL_NO_CONTEXT),
    353     m_pbufContext(EGL_NO_CONTEXT),
    354     m_prevContext(EGL_NO_CONTEXT),
    355     m_prevReadSurf(EGL_NO_SURFACE),
    356     m_prevDrawSurf(EGL_NO_SURFACE),
    357     m_subWin(NULL),
    358     m_subWinDisplay(NULL),
    359     m_lastPostedColorBuffer(0),
    360     m_zRot(0.0f),
    361     m_eglContextInitialized(false),
    362     m_statsNumFrames(0),
    363     m_statsStartTime(0LL)
    364 {
    365     m_fpsStats = getenv("SHOW_FPS_STATS") != NULL;
    366 }
    367 
    368 FrameBuffer::~FrameBuffer()
    369 {
    370 }
    371 
    372 bool FrameBuffer::setupSubWindow(FBNativeWindowType p_window,
    373                                   int p_x, int p_y,
    374                                   int p_width, int p_height, float zRot)
    375 {
    376     bool success = false;
    377 
    378     if (s_theFrameBuffer) {
    379         s_theFrameBuffer->m_lock.lock();
    380         FrameBuffer *fb = s_theFrameBuffer;
    381         if (!fb->m_subWin) {
    382 
    383             // create native subwindow for FB display output
    384             fb->m_subWin = createSubWindow(p_window,
    385                                            &fb->m_subWinDisplay,
    386                                            p_x,p_y,p_width,p_height);
    387             if (fb->m_subWin) {
    388                 fb->m_nativeWindow = p_window;
    389 
    390                 // create EGLSurface from the generated subwindow
    391                 fb->m_eglSurface = s_egl.eglCreateWindowSurface(fb->m_eglDisplay,
    392                                                     fb->m_eglConfig,
    393                                                     fb->m_subWin,
    394                                                     NULL);
    395 
    396                 if (fb->m_eglSurface == EGL_NO_SURFACE) {
    397                     ERR("Failed to create surface\n");
    398                     destroySubWindow(fb->m_subWinDisplay, fb->m_subWin);
    399                     fb->m_subWin = NULL;
    400                 }
    401                 else if (fb->bindSubwin_locked()) {
    402                     // Subwin creation was successfull,
    403                     // update viewport and z rotation and draw
    404                     // the last posted color buffer.
    405                     s_gl.glViewport(0, 0, p_width, p_height);
    406                     fb->m_zRot = zRot;
    407                     fb->post( fb->m_lastPostedColorBuffer, false );
    408                     fb->unbind_locked();
    409                     success = true;
    410                 }
    411              }
    412         }
    413         s_theFrameBuffer->m_lock.unlock();
    414      }
    415 
    416     return success;
    417 }
    418 
    419 bool FrameBuffer::removeSubWindow()
    420 {
    421     bool removed = false;
    422     if (s_theFrameBuffer) {
    423         s_theFrameBuffer->m_lock.lock();
    424         if (s_theFrameBuffer->m_subWin) {
    425             s_egl.eglMakeCurrent(s_theFrameBuffer->m_eglDisplay, NULL, NULL, NULL);
    426             s_egl.eglDestroySurface(s_theFrameBuffer->m_eglDisplay,
    427                                     s_theFrameBuffer->m_eglSurface);
    428             destroySubWindow(s_theFrameBuffer->m_subWinDisplay,
    429                              s_theFrameBuffer->m_subWin);
    430 
    431             s_theFrameBuffer->m_eglSurface = EGL_NO_SURFACE;
    432             s_theFrameBuffer->m_subWin = NULL;
    433             removed = true;
    434         }
    435         s_theFrameBuffer->m_lock.unlock();
    436     }
    437     return removed;
    438 }
    439 
    440 HandleType FrameBuffer::genHandle()
    441 {
    442     HandleType id;
    443     do {
    444         id = ++s_nextHandle;
    445     } while( id == 0 ||
    446              m_contexts.find(id) != m_contexts.end() ||
    447              m_windows.find(id) != m_windows.end() );
    448 
    449     return id;
    450 }
    451 
    452 HandleType FrameBuffer::createColorBuffer(int p_width, int p_height,
    453                                           GLenum p_internalFormat)
    454 {
    455     android::Mutex::Autolock mutex(m_lock);
    456     HandleType ret = 0;
    457 
    458     ColorBufferPtr cb( ColorBuffer::create(p_width, p_height, p_internalFormat) );
    459     if (cb.Ptr() != NULL) {
    460         ret = genHandle();
    461         m_colorbuffers[ret] = cb;
    462     }
    463     return ret;
    464 }
    465 
    466 HandleType FrameBuffer::createRenderContext(int p_config, HandleType p_share,
    467                                             bool p_isGL2)
    468 {
    469     android::Mutex::Autolock mutex(m_lock);
    470     HandleType ret = 0;
    471 
    472     RenderContextPtr share(NULL);
    473     if (p_share != 0) {
    474         RenderContextMap::iterator s( m_contexts.find(p_share) );
    475         if (s == m_contexts.end()) {
    476             return 0;
    477         }
    478         share = (*s).second;
    479     }
    480 
    481     RenderContextPtr rctx( RenderContext::create(p_config, share, p_isGL2) );
    482     if (rctx.Ptr() != NULL) {
    483         ret = genHandle();
    484         m_contexts[ret] = rctx;
    485     }
    486     return ret;
    487 }
    488 
    489 HandleType FrameBuffer::createWindowSurface(int p_config, int p_width, int p_height)
    490 {
    491     android::Mutex::Autolock mutex(m_lock);
    492 
    493     HandleType ret = 0;
    494     WindowSurfacePtr win( WindowSurface::create(p_config, p_width, p_height) );
    495     if (win.Ptr() != NULL) {
    496         ret = genHandle();
    497         m_windows[ret] = win;
    498     }
    499 
    500     return ret;
    501 }
    502 
    503 void FrameBuffer::DestroyRenderContext(HandleType p_context)
    504 {
    505     android::Mutex::Autolock mutex(m_lock);
    506     m_contexts.erase(p_context);
    507 }
    508 
    509 void FrameBuffer::DestroyWindowSurface(HandleType p_surface)
    510 {
    511     android::Mutex::Autolock mutex(m_lock);
    512     m_windows.erase(p_surface);
    513 }
    514 
    515 void FrameBuffer::DestroyColorBuffer(HandleType p_colorbuffer)
    516 {
    517     android::Mutex::Autolock mutex(m_lock);
    518     m_colorbuffers.erase(p_colorbuffer);
    519 }
    520 
    521 bool FrameBuffer::flushWindowSurfaceColorBuffer(HandleType p_surface)
    522 {
    523     android::Mutex::Autolock mutex(m_lock);
    524 
    525     WindowSurfaceMap::iterator w( m_windows.find(p_surface) );
    526     if (w == m_windows.end()) {
    527         // bad surface handle
    528         return false;
    529     }
    530 
    531     (*w).second->flushColorBuffer();
    532 
    533     return true;
    534 }
    535 
    536 bool FrameBuffer::setWindowSurfaceColorBuffer(HandleType p_surface,
    537                                               HandleType p_colorbuffer)
    538 {
    539     android::Mutex::Autolock mutex(m_lock);
    540 
    541     WindowSurfaceMap::iterator w( m_windows.find(p_surface) );
    542     if (w == m_windows.end()) {
    543         // bad surface handle
    544         return false;
    545     }
    546 
    547     ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) );
    548     if (c == m_colorbuffers.end()) {
    549         // bad colorbuffer handle
    550         return false;
    551     }
    552 
    553     (*w).second->setColorBuffer( (*c).second );
    554 
    555     return true;
    556 }
    557 
    558 bool FrameBuffer::updateColorBuffer(HandleType p_colorbuffer,
    559                                     int x, int y, int width, int height,
    560                                     GLenum format, GLenum type, void *pixels)
    561 {
    562     android::Mutex::Autolock mutex(m_lock);
    563 
    564     ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) );
    565     if (c == m_colorbuffers.end()) {
    566         // bad colorbuffer handle
    567         return false;
    568     }
    569 
    570     (*c).second->subUpdate(x, y, width, height, format, type, pixels);
    571 
    572     return true;
    573 }
    574 
    575 bool FrameBuffer::bindColorBufferToTexture(HandleType p_colorbuffer)
    576 {
    577     android::Mutex::Autolock mutex(m_lock);
    578 
    579     ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) );
    580     if (c == m_colorbuffers.end()) {
    581         // bad colorbuffer handle
    582         return false;
    583     }
    584 
    585     return (*c).second->bindToTexture();
    586 }
    587 
    588 bool FrameBuffer::bindColorBufferToRenderbuffer(HandleType p_colorbuffer)
    589 {
    590     android::Mutex::Autolock mutex(m_lock);
    591 
    592     ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) );
    593     if (c == m_colorbuffers.end()) {
    594         // bad colorbuffer handle
    595         return false;
    596     }
    597 
    598     return (*c).second->bindToRenderbuffer();
    599 }
    600 
    601 bool FrameBuffer::bindContext(HandleType p_context,
    602                               HandleType p_drawSurface,
    603                               HandleType p_readSurface)
    604 {
    605     android::Mutex::Autolock mutex(m_lock);
    606 
    607     WindowSurfacePtr draw(NULL), read(NULL);
    608     RenderContextPtr ctx(NULL);
    609 
    610     //
    611     // if this is not an unbind operation - make sure all handles are good
    612     //
    613     if (p_context || p_drawSurface || p_readSurface) {
    614         RenderContextMap::iterator r( m_contexts.find(p_context) );
    615         if (r == m_contexts.end()) {
    616             // bad context handle
    617             return false;
    618         }
    619 
    620         ctx = (*r).second;
    621         WindowSurfaceMap::iterator w( m_windows.find(p_drawSurface) );
    622         if (w == m_windows.end()) {
    623             // bad surface handle
    624             return false;
    625         }
    626         draw = (*w).second;
    627 
    628         if (p_readSurface != p_drawSurface) {
    629             WindowSurfaceMap::iterator w( m_windows.find(p_readSurface) );
    630             if (w == m_windows.end()) {
    631                 // bad surface handle
    632                 return false;
    633             }
    634             read = (*w).second;
    635         }
    636         else {
    637             read = draw;
    638         }
    639     }
    640 
    641     if (!s_egl.eglMakeCurrent(m_eglDisplay,
    642                               draw ? draw->getEGLSurface() : EGL_NO_SURFACE,
    643                               read ? read->getEGLSurface() : EGL_NO_SURFACE,
    644                               ctx ? ctx->getEGLContext() : EGL_NO_CONTEXT)) {
    645         // MakeCurrent failed
    646         return false;
    647     }
    648 
    649     //
    650     // Bind the surface(s) to the context
    651     //
    652     RenderThreadInfo *tinfo = getRenderThreadInfo();
    653     if (draw.Ptr() == NULL && read.Ptr() == NULL) {
    654         // if this is an unbind operation - make sure the current bound
    655         // surfaces get unbound from the context.
    656         draw = tinfo->currDrawSurf;
    657         read = tinfo->currReadSurf;
    658     }
    659 
    660     if (draw.Ptr() != NULL && read.Ptr() != NULL) {
    661         if (p_readSurface != p_drawSurface) {
    662             draw->bind( ctx, SURFACE_BIND_DRAW );
    663             read->bind( ctx, SURFACE_BIND_READ );
    664         }
    665         else {
    666             draw->bind( ctx, SURFACE_BIND_READDRAW );
    667         }
    668     }
    669 
    670     //
    671     // update thread info with current bound context
    672     //
    673     tinfo->currContext = ctx;
    674     tinfo->currDrawSurf = draw;
    675     tinfo->currReadSurf = read;
    676     if (ctx) {
    677         if (ctx->isGL2()) tinfo->m_gl2Dec.setContextData(&ctx->decoderContextData());
    678         else tinfo->m_glDec.setContextData(&ctx->decoderContextData());
    679     }
    680     else {
    681         tinfo->m_glDec.setContextData(NULL);
    682         tinfo->m_gl2Dec.setContextData(NULL);
    683     }
    684     return true;
    685 }
    686 
    687 //
    688 // The framebuffer lock should be held when calling this function !
    689 //
    690 bool FrameBuffer::bind_locked()
    691 {
    692     EGLContext prevContext = s_egl.eglGetCurrentContext();
    693     EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ);
    694     EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW);
    695 
    696     if (!s_egl.eglMakeCurrent(m_eglDisplay, m_pbufSurface,
    697                               m_pbufSurface, m_pbufContext)) {
    698         ERR("eglMakeCurrent failed\n");
    699         return false;
    700     }
    701 
    702     m_prevContext = prevContext;
    703     m_prevReadSurf = prevReadSurf;
    704     m_prevDrawSurf = prevDrawSurf;
    705     return true;
    706 }
    707 
    708 bool FrameBuffer::bindSubwin_locked()
    709 {
    710     EGLContext prevContext = s_egl.eglGetCurrentContext();
    711     EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ);
    712     EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW);
    713 
    714     if (!s_egl.eglMakeCurrent(m_eglDisplay, m_eglSurface,
    715                               m_eglSurface, m_eglContext)) {
    716         ERR("eglMakeCurrent failed\n");
    717         return false;
    718     }
    719 
    720     //
    721     // initialize GL state in eglContext if not yet initilaized
    722     //
    723     if (!m_eglContextInitialized) {
    724         initGLState();
    725         m_eglContextInitialized = true;
    726     }
    727 
    728     m_prevContext = prevContext;
    729     m_prevReadSurf = prevReadSurf;
    730     m_prevDrawSurf = prevDrawSurf;
    731     return true;
    732 }
    733 
    734 bool FrameBuffer::unbind_locked()
    735 {
    736     if (!s_egl.eglMakeCurrent(m_eglDisplay, m_prevDrawSurf,
    737                               m_prevReadSurf, m_prevContext)) {
    738         return false;
    739     }
    740 
    741     m_prevContext = EGL_NO_CONTEXT;
    742     m_prevReadSurf = EGL_NO_SURFACE;
    743     m_prevDrawSurf = EGL_NO_SURFACE;
    744     return true;
    745 }
    746 
    747 bool FrameBuffer::post(HandleType p_colorbuffer, bool needLock)
    748 {
    749     if (needLock) m_lock.lock();
    750     bool ret = false;
    751 
    752     ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) );
    753     if (c != m_colorbuffers.end()) {
    754 
    755         m_lastPostedColorBuffer = p_colorbuffer;
    756         if (!m_subWin) {
    757             // no subwindow created for the FB output
    758             // cannot post the colorbuffer
    759             if (needLock) m_lock.unlock();
    760             return ret;
    761         }
    762 
    763 
    764         // bind the subwindow eglSurface
    765         if (!bindSubwin_locked()) {
    766             ERR("FrameBuffer::post eglMakeCurrent failed\n");
    767             if (needLock) m_lock.unlock();
    768             return false;
    769         }
    770 
    771         //
    772         // render the color buffer to the window
    773         //
    774         s_gl.glPushMatrix();
    775         s_gl.glRotatef(m_zRot, 0.0f, 0.0f, 1.0f);
    776         if (m_zRot != 0.0f) {
    777             s_gl.glClear(GL_COLOR_BUFFER_BIT);
    778         }
    779         ret = (*c).second->post();
    780         s_gl.glPopMatrix();
    781 
    782         if (ret) {
    783 
    784             //
    785             // output FPS statistics
    786             //
    787             if (m_fpsStats) {
    788                 long long currTime = GetCurrentTimeMS();
    789                 m_statsNumFrames++;
    790                 if (currTime - m_statsStartTime >= 1000) {
    791                     float dt = (float)(currTime - m_statsStartTime) / 1000.0f;
    792                     printf("FPS: %5.3f\n", (float)m_statsNumFrames / dt);
    793                     m_statsStartTime = currTime;
    794                     m_statsNumFrames = 0;
    795                 }
    796             }
    797 
    798             s_egl.eglSwapBuffers(m_eglDisplay, m_eglSurface);
    799         }
    800 
    801         // restore previous binding
    802         unbind_locked();
    803     }
    804 
    805     if (needLock) m_lock.unlock();
    806     return ret;
    807 }
    808 
    809 bool FrameBuffer::repost()
    810 {
    811     if (m_lastPostedColorBuffer) {
    812         return post( m_lastPostedColorBuffer );
    813     }
    814     return false;
    815 }
    816 
    817 void FrameBuffer::initGLState()
    818 {
    819     s_gl.glMatrixMode(GL_PROJECTION);
    820     s_gl.glLoadIdentity();
    821     s_gl.glOrthof(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
    822     s_gl.glMatrixMode(GL_MODELVIEW);
    823     s_gl.glLoadIdentity();
    824 }
    825