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