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
getGLES2ExtensionString(EGLDisplay p_dpy)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 
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     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 
FrameBuffer(int p_width,int p_height)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 
~FrameBuffer()389 FrameBuffer::~FrameBuffer()
390 {
391     free(m_fbImage);
392 }
393 
setPostCallback(OnPostFn onPost,void * onPostContext)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 
setupSubWindow(FBNativeWindowType p_window,int p_x,int p_y,int p_width,int p_height,float zRot)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 
removeSubWindow()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 
genHandle()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 
createColorBuffer(int p_width,int p_height,GLenum p_internalFormat)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 
createRenderContext(int p_config,HandleType p_share,bool p_isGL2)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 
createWindowSurface(int p_config,int p_width,int p_height)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 
DestroyRenderContext(HandleType p_context)542 void FrameBuffer::DestroyRenderContext(HandleType p_context)
543 {
544     emugl::Mutex::AutoLock mutex(m_lock);
545     m_contexts.erase(p_context);
546 }
547 
DestroyWindowSurface(HandleType p_surface)548 void FrameBuffer::DestroyWindowSurface(HandleType p_surface)
549 {
550     emugl::Mutex::AutoLock mutex(m_lock);
551     m_windows.erase(p_surface);
552 }
553 
openColorBuffer(HandleType p_colorbuffer)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 
closeColorBuffer(HandleType p_colorbuffer)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 
flushWindowSurfaceColorBuffer(HandleType p_surface)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 
setWindowSurfaceColorBuffer(HandleType p_surface,HandleType p_colorbuffer)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 
updateColorBuffer(HandleType p_colorbuffer,int x,int y,int width,int height,GLenum format,GLenum type,void * pixels)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 
bindColorBufferToTexture(HandleType p_colorbuffer)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 
bindColorBufferToRenderbuffer(HandleType p_colorbuffer)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 
bindContext(HandleType p_context,HandleType p_drawSurface,HandleType p_readSurface)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 //
bind_locked()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 
bindSubwin_locked()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 
unbind_locked()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 
post(HandleType p_colorbuffer,bool needLock)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 
repost()882 bool FrameBuffer::repost()
883 {
884     if (m_lastPostedColorBuffer) {
885         return post( m_lastPostedColorBuffer );
886     }
887     return false;
888 }
889 
initGLState()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