• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
getGLES2ExtensionString(EGLDisplay p_dpy)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 
finalize()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 
initialize(int width,int height)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 
FrameBuffer(int p_width,int p_height)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 
~FrameBuffer()382 FrameBuffer::~FrameBuffer()
383 {
384     free(m_fbImage);
385 }
386 
setPostCallback(OnPostFn onPost,void * onPostContext)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 
setupSubWindow(FBNativeWindowType p_window,int p_x,int p_y,int p_width,int p_height,float zRot)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 
removeSubWindow()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 
genHandle()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 
createColorBuffer(int p_width,int p_height,GLenum p_internalFormat)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 
createRenderContext(int p_config,HandleType p_share,bool p_isGL2)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 
createWindowSurface(int p_config,int p_width,int p_height)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 
DestroyRenderContext(HandleType p_context)535 void FrameBuffer::DestroyRenderContext(HandleType p_context)
536 {
537     android::Mutex::Autolock mutex(m_lock);
538     m_contexts.erase(p_context);
539 }
540 
DestroyWindowSurface(HandleType p_surface)541 void FrameBuffer::DestroyWindowSurface(HandleType p_surface)
542 {
543     android::Mutex::Autolock mutex(m_lock);
544     m_windows.erase(p_surface);
545 }
546 
openColorBuffer(HandleType p_colorbuffer)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 
closeColorBuffer(HandleType p_colorbuffer)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 
flushWindowSurfaceColorBuffer(HandleType p_surface)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 
setWindowSurfaceColorBuffer(HandleType p_surface,HandleType p_colorbuffer)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 
updateColorBuffer(HandleType p_colorbuffer,int x,int y,int width,int height,GLenum format,GLenum type,void * pixels)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 
bindColorBufferToTexture(HandleType p_colorbuffer)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 
bindColorBufferToRenderbuffer(HandleType p_colorbuffer)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 
bindContext(HandleType p_context,HandleType p_drawSurface,HandleType p_readSurface)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 //
bind_locked()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 
bindSubwin_locked()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 
unbind_locked()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 
post(HandleType p_colorbuffer,bool needLock)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 
repost()868 bool FrameBuffer::repost()
869 {
870     if (m_lastPostedColorBuffer) {
871         return post( m_lastPostedColorBuffer );
872     }
873     return false;
874 }
875 
initGLState()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