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 = cb;
    462         m_colorbuffers[ret].refcount = 1;
    463     }
    464     return ret;
    465 }
    466 
    467 HandleType FrameBuffer::createRenderContext(int p_config, HandleType p_share,
    468                                             bool p_isGL2)
    469 {
    470     android::Mutex::Autolock mutex(m_lock);
    471     HandleType ret = 0;
    472 
    473     RenderContextPtr share(NULL);
    474     if (p_share != 0) {
    475         RenderContextMap::iterator s( m_contexts.find(p_share) );
    476         if (s == m_contexts.end()) {
    477             return 0;
    478         }
    479         share = (*s).second;
    480     }
    481 
    482     RenderContextPtr rctx( RenderContext::create(p_config, share, p_isGL2) );
    483     if (rctx.Ptr() != NULL) {
    484         ret = genHandle();
    485         m_contexts[ret] = rctx;
    486     }
    487     return ret;
    488 }
    489 
    490 HandleType FrameBuffer::createWindowSurface(int p_config, int p_width, int p_height)
    491 {
    492     android::Mutex::Autolock mutex(m_lock);
    493 
    494     HandleType ret = 0;
    495     WindowSurfacePtr win( WindowSurface::create(p_config, p_width, p_height) );
    496     if (win.Ptr() != NULL) {
    497         ret = genHandle();
    498         m_windows[ret] = win;
    499     }
    500 
    501     return ret;
    502 }
    503 
    504 void FrameBuffer::DestroyRenderContext(HandleType p_context)
    505 {
    506     android::Mutex::Autolock mutex(m_lock);
    507     m_contexts.erase(p_context);
    508 }
    509 
    510 void FrameBuffer::DestroyWindowSurface(HandleType p_surface)
    511 {
    512     android::Mutex::Autolock mutex(m_lock);
    513     m_windows.erase(p_surface);
    514 }
    515 
    516 void FrameBuffer::openColorBuffer(HandleType p_colorbuffer)
    517 {
    518     android::Mutex::Autolock mutex(m_lock);
    519     ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
    520     if (c == m_colorbuffers.end()) {
    521         // bad colorbuffer handle
    522         return;
    523     }
    524     (*c).second.refcount++;
    525 }
    526 
    527 void FrameBuffer::closeColorBuffer(HandleType p_colorbuffer)
    528 {
    529     android::Mutex::Autolock mutex(m_lock);
    530     ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
    531     if (c == m_colorbuffers.end()) {
    532         // bad colorbuffer handle
    533         return;
    534     }
    535     if (--(*c).second.refcount == 0) {
    536         m_colorbuffers.erase(c);
    537     }
    538 }
    539 
    540 bool FrameBuffer::flushWindowSurfaceColorBuffer(HandleType p_surface)
    541 {
    542     android::Mutex::Autolock mutex(m_lock);
    543 
    544     WindowSurfaceMap::iterator w( m_windows.find(p_surface) );
    545     if (w == m_windows.end()) {
    546         // bad surface handle
    547         return false;
    548     }
    549 
    550     (*w).second->flushColorBuffer();
    551 
    552     return true;
    553 }
    554 
    555 bool FrameBuffer::setWindowSurfaceColorBuffer(HandleType p_surface,
    556                                               HandleType p_colorbuffer)
    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     ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) );
    567     if (c == m_colorbuffers.end()) {
    568         // bad colorbuffer handle
    569         return false;
    570     }
    571 
    572     (*w).second->setColorBuffer( (*c).second.cb );
    573 
    574     return true;
    575 }
    576 
    577 bool FrameBuffer::updateColorBuffer(HandleType p_colorbuffer,
    578                                     int x, int y, int width, int height,
    579                                     GLenum format, GLenum type, void *pixels)
    580 {
    581     android::Mutex::Autolock mutex(m_lock);
    582 
    583     ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) );
    584     if (c == m_colorbuffers.end()) {
    585         // bad colorbuffer handle
    586         return false;
    587     }
    588 
    589     (*c).second.cb->subUpdate(x, y, width, height, format, type, pixels);
    590 
    591     return true;
    592 }
    593 
    594 bool FrameBuffer::bindColorBufferToTexture(HandleType p_colorbuffer)
    595 {
    596     android::Mutex::Autolock mutex(m_lock);
    597 
    598     ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) );
    599     if (c == m_colorbuffers.end()) {
    600         // bad colorbuffer handle
    601         return false;
    602     }
    603 
    604     return (*c).second.cb->bindToTexture();
    605 }
    606 
    607 bool FrameBuffer::bindColorBufferToRenderbuffer(HandleType p_colorbuffer)
    608 {
    609     android::Mutex::Autolock mutex(m_lock);
    610 
    611     ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) );
    612     if (c == m_colorbuffers.end()) {
    613         // bad colorbuffer handle
    614         return false;
    615     }
    616 
    617     return (*c).second.cb->bindToRenderbuffer();
    618 }
    619 
    620 bool FrameBuffer::bindContext(HandleType p_context,
    621                               HandleType p_drawSurface,
    622                               HandleType p_readSurface)
    623 {
    624     android::Mutex::Autolock mutex(m_lock);
    625 
    626     WindowSurfacePtr draw(NULL), read(NULL);
    627     RenderContextPtr ctx(NULL);
    628 
    629     //
    630     // if this is not an unbind operation - make sure all handles are good
    631     //
    632     if (p_context || p_drawSurface || p_readSurface) {
    633         RenderContextMap::iterator r( m_contexts.find(p_context) );
    634         if (r == m_contexts.end()) {
    635             // bad context handle
    636             return false;
    637         }
    638 
    639         ctx = (*r).second;
    640         WindowSurfaceMap::iterator w( m_windows.find(p_drawSurface) );
    641         if (w == m_windows.end()) {
    642             // bad surface handle
    643             return false;
    644         }
    645         draw = (*w).second;
    646 
    647         if (p_readSurface != p_drawSurface) {
    648             WindowSurfaceMap::iterator w( m_windows.find(p_readSurface) );
    649             if (w == m_windows.end()) {
    650                 // bad surface handle
    651                 return false;
    652             }
    653             read = (*w).second;
    654         }
    655         else {
    656             read = draw;
    657         }
    658     }
    659 
    660     if (!s_egl.eglMakeCurrent(m_eglDisplay,
    661                               draw ? draw->getEGLSurface() : EGL_NO_SURFACE,
    662                               read ? read->getEGLSurface() : EGL_NO_SURFACE,
    663                               ctx ? ctx->getEGLContext() : EGL_NO_CONTEXT)) {
    664         // MakeCurrent failed
    665         return false;
    666     }
    667 
    668     //
    669     // Bind the surface(s) to the context
    670     //
    671     RenderThreadInfo *tinfo = getRenderThreadInfo();
    672     if (draw.Ptr() == NULL && read.Ptr() == NULL) {
    673         // if this is an unbind operation - make sure the current bound
    674         // surfaces get unbound from the context.
    675         draw = tinfo->currDrawSurf;
    676         read = tinfo->currReadSurf;
    677     }
    678 
    679     if (draw.Ptr() != NULL && read.Ptr() != NULL) {
    680         if (p_readSurface != p_drawSurface) {
    681             draw->bind( ctx, SURFACE_BIND_DRAW );
    682             read->bind( ctx, SURFACE_BIND_READ );
    683         }
    684         else {
    685             draw->bind( ctx, SURFACE_BIND_READDRAW );
    686         }
    687     }
    688 
    689     //
    690     // update thread info with current bound context
    691     //
    692     tinfo->currContext = ctx;
    693     tinfo->currDrawSurf = draw;
    694     tinfo->currReadSurf = read;
    695     if (ctx) {
    696         if (ctx->isGL2()) tinfo->m_gl2Dec.setContextData(&ctx->decoderContextData());
    697         else tinfo->m_glDec.setContextData(&ctx->decoderContextData());
    698     }
    699     else {
    700         tinfo->m_glDec.setContextData(NULL);
    701         tinfo->m_gl2Dec.setContextData(NULL);
    702     }
    703     return true;
    704 }
    705 
    706 //
    707 // The framebuffer lock should be held when calling this function !
    708 //
    709 bool FrameBuffer::bind_locked()
    710 {
    711     EGLContext prevContext = s_egl.eglGetCurrentContext();
    712     EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ);
    713     EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW);
    714 
    715     if (!s_egl.eglMakeCurrent(m_eglDisplay, m_pbufSurface,
    716                               m_pbufSurface, m_pbufContext)) {
    717         ERR("eglMakeCurrent failed\n");
    718         return false;
    719     }
    720 
    721     m_prevContext = prevContext;
    722     m_prevReadSurf = prevReadSurf;
    723     m_prevDrawSurf = prevDrawSurf;
    724     return true;
    725 }
    726 
    727 bool FrameBuffer::bindSubwin_locked()
    728 {
    729     EGLContext prevContext = s_egl.eglGetCurrentContext();
    730     EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ);
    731     EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW);
    732 
    733     if (!s_egl.eglMakeCurrent(m_eglDisplay, m_eglSurface,
    734                               m_eglSurface, m_eglContext)) {
    735         ERR("eglMakeCurrent failed\n");
    736         return false;
    737     }
    738 
    739     //
    740     // initialize GL state in eglContext if not yet initilaized
    741     //
    742     if (!m_eglContextInitialized) {
    743         initGLState();
    744         m_eglContextInitialized = true;
    745     }
    746 
    747     m_prevContext = prevContext;
    748     m_prevReadSurf = prevReadSurf;
    749     m_prevDrawSurf = prevDrawSurf;
    750     return true;
    751 }
    752 
    753 bool FrameBuffer::unbind_locked()
    754 {
    755     if (!s_egl.eglMakeCurrent(m_eglDisplay, m_prevDrawSurf,
    756                               m_prevReadSurf, m_prevContext)) {
    757         return false;
    758     }
    759 
    760     m_prevContext = EGL_NO_CONTEXT;
    761     m_prevReadSurf = EGL_NO_SURFACE;
    762     m_prevDrawSurf = EGL_NO_SURFACE;
    763     return true;
    764 }
    765 
    766 bool FrameBuffer::post(HandleType p_colorbuffer, bool needLock)
    767 {
    768     if (needLock) m_lock.lock();
    769     bool ret = false;
    770 
    771     ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) );
    772     if (c != m_colorbuffers.end()) {
    773 
    774         m_lastPostedColorBuffer = p_colorbuffer;
    775         if (!m_subWin) {
    776             // no subwindow created for the FB output
    777             // cannot post the colorbuffer
    778             if (needLock) m_lock.unlock();
    779             return ret;
    780         }
    781 
    782 
    783         // bind the subwindow eglSurface
    784         if (!bindSubwin_locked()) {
    785             ERR("FrameBuffer::post eglMakeCurrent failed\n");
    786             if (needLock) m_lock.unlock();
    787             return false;
    788         }
    789 
    790         //
    791         // render the color buffer to the window
    792         //
    793         s_gl.glPushMatrix();
    794         s_gl.glRotatef(m_zRot, 0.0f, 0.0f, 1.0f);
    795         if (m_zRot != 0.0f) {
    796             s_gl.glClear(GL_COLOR_BUFFER_BIT);
    797         }
    798         ret = (*c).second.cb->post();
    799         s_gl.glPopMatrix();
    800 
    801         if (ret) {
    802 
    803             //
    804             // output FPS statistics
    805             //
    806             if (m_fpsStats) {
    807                 long long currTime = GetCurrentTimeMS();
    808                 m_statsNumFrames++;
    809                 if (currTime - m_statsStartTime >= 1000) {
    810                     float dt = (float)(currTime - m_statsStartTime) / 1000.0f;
    811                     printf("FPS: %5.3f\n", (float)m_statsNumFrames / dt);
    812                     m_statsStartTime = currTime;
    813                     m_statsNumFrames = 0;
    814                 }
    815             }
    816 
    817             s_egl.eglSwapBuffers(m_eglDisplay, m_eglSurface);
    818         }
    819 
    820         // restore previous binding
    821         unbind_locked();
    822     }
    823 
    824     if (needLock) m_lock.unlock();
    825     return ret;
    826 }
    827 
    828 bool FrameBuffer::repost()
    829 {
    830     if (m_lastPostedColorBuffer) {
    831         return post( m_lastPostedColorBuffer );
    832     }
    833     return false;
    834 }
    835 
    836 void FrameBuffer::initGLState()
    837 {
    838     s_gl.glMatrixMode(GL_PROJECTION);
    839     s_gl.glLoadIdentity();
    840     s_gl.glOrthof(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
    841     s_gl.glMatrixMode(GL_MODELVIEW);
    842     s_gl.glLoadIdentity();
    843 }
    844