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