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, 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 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 383 FrameBuffer::~FrameBuffer() 384 { 385 free(m_fbImage); 386 } 387 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 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 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 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 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 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 520 void FrameBuffer::DestroyRenderContext(HandleType p_context) 521 { 522 android::Mutex::Autolock mutex(m_lock); 523 m_contexts.erase(p_context); 524 } 525 526 void FrameBuffer::DestroyWindowSurface(HandleType p_surface) 527 { 528 android::Mutex::Autolock mutex(m_lock); 529 m_windows.erase(p_surface); 530 } 531 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 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 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 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 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 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 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 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 // 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 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 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 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 853 bool FrameBuffer::repost() 854 { 855 if (m_lastPostedColorBuffer) { 856 return post( m_lastPostedColorBuffer ); 857 } 858 return false; 859 } 860 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