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 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 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 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 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 389 FrameBuffer::~FrameBuffer() 390 { 391 free(m_fbImage); 392 } 393 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 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 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 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 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 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 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 542 void FrameBuffer::DestroyRenderContext(HandleType p_context) 543 { 544 emugl::Mutex::AutoLock mutex(m_lock); 545 m_contexts.erase(p_context); 546 } 547 548 void FrameBuffer::DestroyWindowSurface(HandleType p_surface) 549 { 550 emugl::Mutex::AutoLock mutex(m_lock); 551 m_windows.erase(p_surface); 552 } 553 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 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 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 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 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 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 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 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 // 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 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 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 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 882 bool FrameBuffer::repost() 883 { 884 if (m_lastPostedColorBuffer) { 885 return post( m_lastPostedColorBuffer ); 886 } 887 return false; 888 } 889 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