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