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 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 90 void FrameBuffer::finalize(){ 91 if(s_theFrameBuffer){ 92 s_theFrameBuffer->removeSubWindow(); 93 s_theFrameBuffer->m_colorbuffers.clear(); 94 s_theFrameBuffer->m_windows.clear(); 95 s_theFrameBuffer->m_contexts.clear(); 96 s_egl.eglMakeCurrent(s_theFrameBuffer->m_eglDisplay, NULL, NULL, NULL); 97 s_egl.eglDestroyContext(s_theFrameBuffer->m_eglDisplay,s_theFrameBuffer->m_eglContext); 98 s_egl.eglDestroyContext(s_theFrameBuffer->m_eglDisplay,s_theFrameBuffer->m_pbufContext); 99 s_egl.eglDestroySurface(s_theFrameBuffer->m_eglDisplay,s_theFrameBuffer->m_pbufSurface); 100 s_theFrameBuffer = NULL; 101 } 102 } 103 104 bool FrameBuffer::initialize(int width, int height) 105 { 106 if (s_theFrameBuffer != NULL) { 107 return true; 108 } 109 110 // 111 // allocate space for the FrameBuffer object 112 // 113 FrameBuffer *fb = new FrameBuffer(width, height); 114 if (!fb) { 115 ERR("Failed to create fb\n"); 116 return false; 117 } 118 119 #ifdef WITH_GLES2 120 // 121 // Try to load GLES2 Plugin, not mandatory 122 // 123 if (getenv("ANDROID_NO_GLES2")) { 124 fb->m_caps.hasGL2 = false; 125 } 126 else { 127 fb->m_caps.hasGL2 = s_gl2_enabled; 128 } 129 #else 130 fb->m_caps.hasGL2 = false; 131 #endif 132 133 // 134 // Initialize backend EGL display 135 // 136 fb->m_eglDisplay = s_egl.eglGetDisplay(EGL_DEFAULT_DISPLAY); 137 if (fb->m_eglDisplay == EGL_NO_DISPLAY) { 138 ERR("Failed to Initialize backend EGL display\n"); 139 delete fb; 140 return false; 141 } 142 143 if (!s_egl.eglInitialize(fb->m_eglDisplay, &fb->m_caps.eglMajor, &fb->m_caps.eglMinor)) { 144 ERR("Failed to eglInitialize\n"); 145 delete fb; 146 return false; 147 } 148 149 DBG("egl: %d %d\n", fb->m_caps.eglMajor, fb->m_caps.eglMinor); 150 s_egl.eglBindAPI(EGL_OPENGL_ES_API); 151 152 // 153 // if GLES2 plugin has loaded - try to make GLES2 context and 154 // get GLES2 extension string 155 // 156 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 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 382 FrameBuffer::~FrameBuffer() 383 { 384 free(m_fbImage); 385 } 386 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 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 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 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 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 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 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 535 void FrameBuffer::DestroyRenderContext(HandleType p_context) 536 { 537 android::Mutex::Autolock mutex(m_lock); 538 m_contexts.erase(p_context); 539 } 540 541 void FrameBuffer::DestroyWindowSurface(HandleType p_surface) 542 { 543 android::Mutex::Autolock mutex(m_lock); 544 m_windows.erase(p_surface); 545 } 546 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 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 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 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 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 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 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 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 ERR("eglMakeCurrent failed\n"); 696 return false; 697 } 698 699 // 700 // Bind the surface(s) to the context 701 // 702 RenderThreadInfo *tinfo = RenderThreadInfo::get(); 703 WindowSurfacePtr bindDraw, bindRead; 704 if (draw.Ptr() == NULL && read.Ptr() == NULL) { 705 // Unbind the current read and draw surfaces from the context 706 bindDraw = tinfo->currDrawSurf; 707 bindRead = tinfo->currReadSurf; 708 } else { 709 bindDraw = draw; 710 bindRead = read; 711 } 712 713 if (bindDraw.Ptr() != NULL && bindRead.Ptr() != NULL) { 714 if (bindDraw.Ptr() != bindRead.Ptr()) { 715 bindDraw->bind(ctx, SURFACE_BIND_DRAW); 716 bindRead->bind(ctx, SURFACE_BIND_READ); 717 } 718 else { 719 bindDraw->bind(ctx, SURFACE_BIND_READDRAW); 720 } 721 } 722 723 // 724 // update thread info with current bound context 725 // 726 tinfo->currContext = ctx; 727 tinfo->currDrawSurf = draw; 728 tinfo->currReadSurf = read; 729 if (ctx) { 730 if (ctx->isGL2()) tinfo->m_gl2Dec.setContextData(&ctx->decoderContextData()); 731 else tinfo->m_glDec.setContextData(&ctx->decoderContextData()); 732 } 733 else { 734 tinfo->m_glDec.setContextData(NULL); 735 tinfo->m_gl2Dec.setContextData(NULL); 736 } 737 return true; 738 } 739 740 // 741 // The framebuffer lock should be held when calling this function ! 742 // 743 bool FrameBuffer::bind_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_pbufSurface, 750 m_pbufSurface, m_pbufContext)) { 751 ERR("eglMakeCurrent failed\n"); 752 return false; 753 } 754 755 m_prevContext = prevContext; 756 m_prevReadSurf = prevReadSurf; 757 m_prevDrawSurf = prevDrawSurf; 758 return true; 759 } 760 761 bool FrameBuffer::bindSubwin_locked() 762 { 763 EGLContext prevContext = s_egl.eglGetCurrentContext(); 764 EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ); 765 EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW); 766 767 if (!s_egl.eglMakeCurrent(m_eglDisplay, m_eglSurface, 768 m_eglSurface, m_eglContext)) { 769 ERR("eglMakeCurrent failed\n"); 770 return false; 771 } 772 773 // 774 // initialize GL state in eglContext if not yet initilaized 775 // 776 if (!m_eglContextInitialized) { 777 initGLState(); 778 m_eglContextInitialized = true; 779 } 780 781 m_prevContext = prevContext; 782 m_prevReadSurf = prevReadSurf; 783 m_prevDrawSurf = prevDrawSurf; 784 return true; 785 } 786 787 bool FrameBuffer::unbind_locked() 788 { 789 if (!s_egl.eglMakeCurrent(m_eglDisplay, m_prevDrawSurf, 790 m_prevReadSurf, m_prevContext)) { 791 return false; 792 } 793 794 m_prevContext = EGL_NO_CONTEXT; 795 m_prevReadSurf = EGL_NO_SURFACE; 796 m_prevDrawSurf = EGL_NO_SURFACE; 797 return true; 798 } 799 800 bool FrameBuffer::post(HandleType p_colorbuffer, bool needLock) 801 { 802 if (needLock) m_lock.lock(); 803 bool ret = false; 804 805 ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) ); 806 if (c != m_colorbuffers.end()) { 807 808 m_lastPostedColorBuffer = p_colorbuffer; 809 if (!m_subWin) { 810 // no subwindow created for the FB output 811 // cannot post the colorbuffer 812 if (needLock) m_lock.unlock(); 813 return ret; 814 } 815 816 817 // bind the subwindow eglSurface 818 if (!bindSubwin_locked()) { 819 ERR("FrameBuffer::post eglMakeCurrent failed\n"); 820 if (needLock) m_lock.unlock(); 821 return false; 822 } 823 824 // 825 // render the color buffer to the window 826 // 827 s_gl.glPushMatrix(); 828 s_gl.glRotatef(m_zRot, 0.0f, 0.0f, 1.0f); 829 if (m_zRot != 0.0f) { 830 s_gl.glClear(GL_COLOR_BUFFER_BIT); 831 } 832 ret = (*c).second.cb->post(); 833 s_gl.glPopMatrix(); 834 835 if (ret) { 836 // 837 // output FPS statistics 838 // 839 if (m_fpsStats) { 840 long long currTime = GetCurrentTimeMS(); 841 m_statsNumFrames++; 842 if (currTime - m_statsStartTime >= 1000) { 843 float dt = (float)(currTime - m_statsStartTime) / 1000.0f; 844 printf("FPS: %5.3f\n", (float)m_statsNumFrames / dt); 845 m_statsStartTime = currTime; 846 m_statsNumFrames = 0; 847 } 848 } 849 850 s_egl.eglSwapBuffers(m_eglDisplay, m_eglSurface); 851 } 852 853 // restore previous binding 854 unbind_locked(); 855 856 // 857 // Send framebuffer (without FPS overlay) to callback 858 // 859 if (m_onPost) { 860 (*c).second.cb->readback(m_fbImage); 861 m_onPost(m_onPostContext, m_width, m_height, -1, 862 GL_RGBA, GL_UNSIGNED_BYTE, m_fbImage); 863 } 864 865 } 866 867 if (needLock) m_lock.unlock(); 868 return ret; 869 } 870 871 bool FrameBuffer::repost() 872 { 873 if (m_lastPostedColorBuffer) { 874 return post( m_lastPostedColorBuffer ); 875 } 876 return false; 877 } 878 879 void FrameBuffer::initGLState() 880 { 881 s_gl.glMatrixMode(GL_PROJECTION); 882 s_gl.glLoadIdentity(); 883 s_gl.glOrthof(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); 884 s_gl.glMatrixMode(GL_MODELVIEW); 885 s_gl.glLoadIdentity(); 886 } 887