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, OnPostFn onPost, void* onPostContext)
    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, onPost, onPostContext);
    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     //
    338     // Allocate space for the onPost framebuffer image
    339     //
    340     if (onPost) {
    341         fb->m_fbImage = (unsigned char*)malloc(4 * width * height);
    342         if (!fb->m_fbImage) {
    343             delete fb;
    344             return false;
    345         }
    346     }
    347 
    348     // release the FB context
    349     fb->unbind_locked();
    350 
    351     //
    352     // Keep the singleton framebuffer pointer
    353     //
    354     s_theFrameBuffer = fb;
    355     return true;
    356 }
    357 
    358 FrameBuffer::FrameBuffer(int p_width, int p_height,
    359         OnPostFn onPost, void* onPostContext) :
    360     m_width(p_width),
    361     m_height(p_height),
    362     m_eglDisplay(EGL_NO_DISPLAY),
    363     m_eglSurface(EGL_NO_SURFACE),
    364     m_eglContext(EGL_NO_CONTEXT),
    365     m_pbufContext(EGL_NO_CONTEXT),
    366     m_prevContext(EGL_NO_CONTEXT),
    367     m_prevReadSurf(EGL_NO_SURFACE),
    368     m_prevDrawSurf(EGL_NO_SURFACE),
    369     m_subWin(NULL),
    370     m_subWinDisplay(NULL),
    371     m_lastPostedColorBuffer(0),
    372     m_zRot(0.0f),
    373     m_eglContextInitialized(false),
    374     m_statsNumFrames(0),
    375     m_statsStartTime(0LL),
    376     m_onPost(onPost),
    377     m_onPostContext(onPostContext),
    378     m_fbImage(NULL)
    379 {
    380     m_fpsStats = getenv("SHOW_FPS_STATS") != NULL;
    381 }
    382 
    383 FrameBuffer::~FrameBuffer()
    384 {
    385     free(m_fbImage);
    386 }
    387 
    388 bool FrameBuffer::setupSubWindow(FBNativeWindowType p_window,
    389                                   int p_x, int p_y,
    390                                   int p_width, int p_height, float zRot)
    391 {
    392     bool success = false;
    393 
    394     if (s_theFrameBuffer) {
    395         s_theFrameBuffer->m_lock.lock();
    396         FrameBuffer *fb = s_theFrameBuffer;
    397         if (!fb->m_subWin) {
    398 
    399             // create native subwindow for FB display output
    400             fb->m_subWin = createSubWindow(p_window,
    401                                            &fb->m_subWinDisplay,
    402                                            p_x,p_y,p_width,p_height);
    403             if (fb->m_subWin) {
    404                 fb->m_nativeWindow = p_window;
    405 
    406                 // create EGLSurface from the generated subwindow
    407                 fb->m_eglSurface = s_egl.eglCreateWindowSurface(fb->m_eglDisplay,
    408                                                     fb->m_eglConfig,
    409                                                     fb->m_subWin,
    410                                                     NULL);
    411 
    412                 if (fb->m_eglSurface == EGL_NO_SURFACE) {
    413                     ERR("Failed to create surface\n");
    414                     destroySubWindow(fb->m_subWinDisplay, fb->m_subWin);
    415                     fb->m_subWin = NULL;
    416                 }
    417                 else if (fb->bindSubwin_locked()) {
    418                     // Subwin creation was successfull,
    419                     // update viewport and z rotation and draw
    420                     // the last posted color buffer.
    421                     s_gl.glViewport(0, 0, p_width, p_height);
    422                     fb->m_zRot = zRot;
    423                     fb->post( fb->m_lastPostedColorBuffer, false );
    424                     fb->unbind_locked();
    425                     success = true;
    426                 }
    427              }
    428         }
    429         s_theFrameBuffer->m_lock.unlock();
    430      }
    431 
    432     return success;
    433 }
    434 
    435 bool FrameBuffer::removeSubWindow()
    436 {
    437     bool removed = false;
    438     if (s_theFrameBuffer) {
    439         s_theFrameBuffer->m_lock.lock();
    440         if (s_theFrameBuffer->m_subWin) {
    441             s_egl.eglMakeCurrent(s_theFrameBuffer->m_eglDisplay, NULL, NULL, NULL);
    442             s_egl.eglDestroySurface(s_theFrameBuffer->m_eglDisplay,
    443                                     s_theFrameBuffer->m_eglSurface);
    444             destroySubWindow(s_theFrameBuffer->m_subWinDisplay,
    445                              s_theFrameBuffer->m_subWin);
    446 
    447             s_theFrameBuffer->m_eglSurface = EGL_NO_SURFACE;
    448             s_theFrameBuffer->m_subWin = NULL;
    449             removed = true;
    450         }
    451         s_theFrameBuffer->m_lock.unlock();
    452     }
    453     return removed;
    454 }
    455 
    456 HandleType FrameBuffer::genHandle()
    457 {
    458     HandleType id;
    459     do {
    460         id = ++s_nextHandle;
    461     } while( id == 0 ||
    462              m_contexts.find(id) != m_contexts.end() ||
    463              m_windows.find(id) != m_windows.end() );
    464 
    465     return id;
    466 }
    467 
    468 HandleType FrameBuffer::createColorBuffer(int p_width, int p_height,
    469                                           GLenum p_internalFormat)
    470 {
    471     android::Mutex::Autolock mutex(m_lock);
    472     HandleType ret = 0;
    473 
    474     ColorBufferPtr cb( ColorBuffer::create(p_width, p_height, p_internalFormat) );
    475     if (cb.Ptr() != NULL) {
    476         ret = genHandle();
    477         m_colorbuffers[ret].cb = cb;
    478         m_colorbuffers[ret].refcount = 1;
    479     }
    480     return ret;
    481 }
    482 
    483 HandleType FrameBuffer::createRenderContext(int p_config, HandleType p_share,
    484                                             bool p_isGL2)
    485 {
    486     android::Mutex::Autolock mutex(m_lock);
    487     HandleType ret = 0;
    488 
    489     RenderContextPtr share(NULL);
    490     if (p_share != 0) {
    491         RenderContextMap::iterator s( m_contexts.find(p_share) );
    492         if (s == m_contexts.end()) {
    493             return 0;
    494         }
    495         share = (*s).second;
    496     }
    497 
    498     RenderContextPtr rctx( RenderContext::create(p_config, share, p_isGL2) );
    499     if (rctx.Ptr() != NULL) {
    500         ret = genHandle();
    501         m_contexts[ret] = rctx;
    502     }
    503     return ret;
    504 }
    505 
    506 HandleType FrameBuffer::createWindowSurface(int p_config, int p_width, int p_height)
    507 {
    508     android::Mutex::Autolock mutex(m_lock);
    509 
    510     HandleType ret = 0;
    511     WindowSurfacePtr win( WindowSurface::create(p_config, p_width, p_height) );
    512     if (win.Ptr() != NULL) {
    513         ret = genHandle();
    514         m_windows[ret] = win;
    515     }
    516 
    517     return ret;
    518 }
    519 
    520 void FrameBuffer::DestroyRenderContext(HandleType p_context)
    521 {
    522     android::Mutex::Autolock mutex(m_lock);
    523     m_contexts.erase(p_context);
    524 }
    525 
    526 void FrameBuffer::DestroyWindowSurface(HandleType p_surface)
    527 {
    528     android::Mutex::Autolock mutex(m_lock);
    529     m_windows.erase(p_surface);
    530 }
    531 
    532 void FrameBuffer::openColorBuffer(HandleType p_colorbuffer)
    533 {
    534     android::Mutex::Autolock mutex(m_lock);
    535     ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
    536     if (c == m_colorbuffers.end()) {
    537         // bad colorbuffer handle
    538         return;
    539     }
    540     (*c).second.refcount++;
    541 }
    542 
    543 void FrameBuffer::closeColorBuffer(HandleType p_colorbuffer)
    544 {
    545     android::Mutex::Autolock mutex(m_lock);
    546     ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
    547     if (c == m_colorbuffers.end()) {
    548         // bad colorbuffer handle
    549         return;
    550     }
    551     if (--(*c).second.refcount == 0) {
    552         m_colorbuffers.erase(c);
    553     }
    554 }
    555 
    556 bool FrameBuffer::flushWindowSurfaceColorBuffer(HandleType p_surface)
    557 {
    558     android::Mutex::Autolock mutex(m_lock);
    559 
    560     WindowSurfaceMap::iterator w( m_windows.find(p_surface) );
    561     if (w == m_windows.end()) {
    562         // bad surface handle
    563         return false;
    564     }
    565 
    566     (*w).second->flushColorBuffer();
    567 
    568     return true;
    569 }
    570 
    571 bool FrameBuffer::setWindowSurfaceColorBuffer(HandleType p_surface,
    572                                               HandleType p_colorbuffer)
    573 {
    574     android::Mutex::Autolock mutex(m_lock);
    575 
    576     WindowSurfaceMap::iterator w( m_windows.find(p_surface) );
    577     if (w == m_windows.end()) {
    578         // bad surface handle
    579         return false;
    580     }
    581 
    582     ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) );
    583     if (c == m_colorbuffers.end()) {
    584         // bad colorbuffer handle
    585         return false;
    586     }
    587 
    588     (*w).second->setColorBuffer( (*c).second.cb );
    589 
    590     return true;
    591 }
    592 
    593 bool FrameBuffer::updateColorBuffer(HandleType p_colorbuffer,
    594                                     int x, int y, int width, int height,
    595                                     GLenum format, GLenum type, void *pixels)
    596 {
    597     android::Mutex::Autolock mutex(m_lock);
    598 
    599     ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) );
    600     if (c == m_colorbuffers.end()) {
    601         // bad colorbuffer handle
    602         return false;
    603     }
    604 
    605     (*c).second.cb->subUpdate(x, y, width, height, format, type, pixels);
    606 
    607     return true;
    608 }
    609 
    610 bool FrameBuffer::bindColorBufferToTexture(HandleType p_colorbuffer)
    611 {
    612     android::Mutex::Autolock mutex(m_lock);
    613 
    614     ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) );
    615     if (c == m_colorbuffers.end()) {
    616         // bad colorbuffer handle
    617         return false;
    618     }
    619 
    620     return (*c).second.cb->bindToTexture();
    621 }
    622 
    623 bool FrameBuffer::bindColorBufferToRenderbuffer(HandleType p_colorbuffer)
    624 {
    625     android::Mutex::Autolock mutex(m_lock);
    626 
    627     ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) );
    628     if (c == m_colorbuffers.end()) {
    629         // bad colorbuffer handle
    630         return false;
    631     }
    632 
    633     return (*c).second.cb->bindToRenderbuffer();
    634 }
    635 
    636 bool FrameBuffer::bindContext(HandleType p_context,
    637                               HandleType p_drawSurface,
    638                               HandleType p_readSurface)
    639 {
    640     android::Mutex::Autolock mutex(m_lock);
    641 
    642     WindowSurfacePtr draw(NULL), read(NULL);
    643     RenderContextPtr ctx(NULL);
    644 
    645     //
    646     // if this is not an unbind operation - make sure all handles are good
    647     //
    648     if (p_context || p_drawSurface || p_readSurface) {
    649         RenderContextMap::iterator r( m_contexts.find(p_context) );
    650         if (r == m_contexts.end()) {
    651             // bad context handle
    652             return false;
    653         }
    654 
    655         ctx = (*r).second;
    656         WindowSurfaceMap::iterator w( m_windows.find(p_drawSurface) );
    657         if (w == m_windows.end()) {
    658             // bad surface handle
    659             return false;
    660         }
    661         draw = (*w).second;
    662 
    663         if (p_readSurface != p_drawSurface) {
    664             WindowSurfaceMap::iterator w( m_windows.find(p_readSurface) );
    665             if (w == m_windows.end()) {
    666                 // bad surface handle
    667                 return false;
    668             }
    669             read = (*w).second;
    670         }
    671         else {
    672             read = draw;
    673         }
    674     }
    675 
    676     if (!s_egl.eglMakeCurrent(m_eglDisplay,
    677                               draw ? draw->getEGLSurface() : EGL_NO_SURFACE,
    678                               read ? read->getEGLSurface() : EGL_NO_SURFACE,
    679                               ctx ? ctx->getEGLContext() : EGL_NO_CONTEXT)) {
    680         // MakeCurrent failed
    681         return false;
    682     }
    683 
    684     //
    685     // Bind the surface(s) to the context
    686     //
    687     RenderThreadInfo *tinfo = getRenderThreadInfo();
    688     if (draw.Ptr() == NULL && read.Ptr() == NULL) {
    689         // if this is an unbind operation - make sure the current bound
    690         // surfaces get unbound from the context.
    691         draw = tinfo->currDrawSurf;
    692         read = tinfo->currReadSurf;
    693     }
    694 
    695     if (draw.Ptr() != NULL && read.Ptr() != NULL) {
    696         if (p_readSurface != p_drawSurface) {
    697             draw->bind( ctx, SURFACE_BIND_DRAW );
    698             read->bind( ctx, SURFACE_BIND_READ );
    699         }
    700         else {
    701             draw->bind( ctx, SURFACE_BIND_READDRAW );
    702         }
    703     }
    704 
    705     //
    706     // update thread info with current bound context
    707     //
    708     tinfo->currContext = ctx;
    709     tinfo->currDrawSurf = draw;
    710     tinfo->currReadSurf = read;
    711     if (ctx) {
    712         if (ctx->isGL2()) tinfo->m_gl2Dec.setContextData(&ctx->decoderContextData());
    713         else tinfo->m_glDec.setContextData(&ctx->decoderContextData());
    714     }
    715     else {
    716         tinfo->m_glDec.setContextData(NULL);
    717         tinfo->m_gl2Dec.setContextData(NULL);
    718     }
    719     return true;
    720 }
    721 
    722 //
    723 // The framebuffer lock should be held when calling this function !
    724 //
    725 bool FrameBuffer::bind_locked()
    726 {
    727     EGLContext prevContext = s_egl.eglGetCurrentContext();
    728     EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ);
    729     EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW);
    730 
    731     if (!s_egl.eglMakeCurrent(m_eglDisplay, m_pbufSurface,
    732                               m_pbufSurface, m_pbufContext)) {
    733         ERR("eglMakeCurrent failed\n");
    734         return false;
    735     }
    736 
    737     m_prevContext = prevContext;
    738     m_prevReadSurf = prevReadSurf;
    739     m_prevDrawSurf = prevDrawSurf;
    740     return true;
    741 }
    742 
    743 bool FrameBuffer::bindSubwin_locked()
    744 {
    745     EGLContext prevContext = s_egl.eglGetCurrentContext();
    746     EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ);
    747     EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW);
    748 
    749     if (!s_egl.eglMakeCurrent(m_eglDisplay, m_eglSurface,
    750                               m_eglSurface, m_eglContext)) {
    751         ERR("eglMakeCurrent failed\n");
    752         return false;
    753     }
    754 
    755     //
    756     // initialize GL state in eglContext if not yet initilaized
    757     //
    758     if (!m_eglContextInitialized) {
    759         initGLState();
    760         m_eglContextInitialized = true;
    761     }
    762 
    763     m_prevContext = prevContext;
    764     m_prevReadSurf = prevReadSurf;
    765     m_prevDrawSurf = prevDrawSurf;
    766     return true;
    767 }
    768 
    769 bool FrameBuffer::unbind_locked()
    770 {
    771     if (!s_egl.eglMakeCurrent(m_eglDisplay, m_prevDrawSurf,
    772                               m_prevReadSurf, m_prevContext)) {
    773         return false;
    774     }
    775 
    776     m_prevContext = EGL_NO_CONTEXT;
    777     m_prevReadSurf = EGL_NO_SURFACE;
    778     m_prevDrawSurf = EGL_NO_SURFACE;
    779     return true;
    780 }
    781 
    782 bool FrameBuffer::post(HandleType p_colorbuffer, bool needLock)
    783 {
    784     if (needLock) m_lock.lock();
    785     bool ret = false;
    786 
    787     ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) );
    788     if (c != m_colorbuffers.end()) {
    789 
    790         m_lastPostedColorBuffer = p_colorbuffer;
    791         if (!m_subWin) {
    792             // no subwindow created for the FB output
    793             // cannot post the colorbuffer
    794             if (needLock) m_lock.unlock();
    795             return ret;
    796         }
    797 
    798 
    799         // bind the subwindow eglSurface
    800         if (!bindSubwin_locked()) {
    801             ERR("FrameBuffer::post eglMakeCurrent failed\n");
    802             if (needLock) m_lock.unlock();
    803             return false;
    804         }
    805 
    806         //
    807         // render the color buffer to the window
    808         //
    809         s_gl.glPushMatrix();
    810         s_gl.glRotatef(m_zRot, 0.0f, 0.0f, 1.0f);
    811         if (m_zRot != 0.0f) {
    812             s_gl.glClear(GL_COLOR_BUFFER_BIT);
    813         }
    814         ret = (*c).second.cb->post();
    815         s_gl.glPopMatrix();
    816 
    817         if (ret) {
    818             //
    819             // Send framebuffer (without FPS overlay) to callback
    820             //
    821             if (m_onPost) {
    822                 s_gl.glReadPixels(0, 0, m_width, m_height,
    823                         GL_RGBA, GL_UNSIGNED_BYTE, m_fbImage);
    824                 m_onPost(m_onPostContext, m_width, m_height, -1,
    825                         GL_RGBA, GL_UNSIGNED_BYTE, m_fbImage);
    826             }
    827 
    828             //
    829             // output FPS statistics
    830             //
    831             if (m_fpsStats) {
    832                 long long currTime = GetCurrentTimeMS();
    833                 m_statsNumFrames++;
    834                 if (currTime - m_statsStartTime >= 1000) {
    835                     float dt = (float)(currTime - m_statsStartTime) / 1000.0f;
    836                     printf("FPS: %5.3f\n", (float)m_statsNumFrames / dt);
    837                     m_statsStartTime = currTime;
    838                     m_statsNumFrames = 0;
    839                 }
    840             }
    841 
    842             s_egl.eglSwapBuffers(m_eglDisplay, m_eglSurface);
    843         }
    844 
    845         // restore previous binding
    846         unbind_locked();
    847     }
    848 
    849     if (needLock) m_lock.unlock();
    850     return ret;
    851 }
    852 
    853 bool FrameBuffer::repost()
    854 {
    855     if (m_lastPostedColorBuffer) {
    856         return post( m_lastPostedColorBuffer );
    857     }
    858     return false;
    859 }
    860 
    861 void FrameBuffer::initGLState()
    862 {
    863     s_gl.glMatrixMode(GL_PROJECTION);
    864     s_gl.glLoadIdentity();
    865     s_gl.glOrthof(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
    866     s_gl.glMatrixMode(GL_MODELVIEW);
    867     s_gl.glLoadIdentity();
    868 }
    869