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