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 // release the FB context 338 fb->unbind_locked(); 339 340 // 341 // Keep the singleton framebuffer pointer 342 // 343 s_theFrameBuffer = fb; 344 return true; 345 } 346 347 FrameBuffer::FrameBuffer(int p_width, int p_height) : 348 m_width(p_width), 349 m_height(p_height), 350 m_eglDisplay(EGL_NO_DISPLAY), 351 m_eglSurface(EGL_NO_SURFACE), 352 m_eglContext(EGL_NO_CONTEXT), 353 m_pbufContext(EGL_NO_CONTEXT), 354 m_prevContext(EGL_NO_CONTEXT), 355 m_prevReadSurf(EGL_NO_SURFACE), 356 m_prevDrawSurf(EGL_NO_SURFACE), 357 m_subWin(NULL), 358 m_subWinDisplay(NULL), 359 m_lastPostedColorBuffer(0), 360 m_zRot(0.0f), 361 m_eglContextInitialized(false), 362 m_statsNumFrames(0), 363 m_statsStartTime(0LL) 364 { 365 m_fpsStats = getenv("SHOW_FPS_STATS") != NULL; 366 } 367 368 FrameBuffer::~FrameBuffer() 369 { 370 } 371 372 bool FrameBuffer::setupSubWindow(FBNativeWindowType p_window, 373 int p_x, int p_y, 374 int p_width, int p_height, float zRot) 375 { 376 bool success = false; 377 378 if (s_theFrameBuffer) { 379 s_theFrameBuffer->m_lock.lock(); 380 FrameBuffer *fb = s_theFrameBuffer; 381 if (!fb->m_subWin) { 382 383 // create native subwindow for FB display output 384 fb->m_subWin = createSubWindow(p_window, 385 &fb->m_subWinDisplay, 386 p_x,p_y,p_width,p_height); 387 if (fb->m_subWin) { 388 fb->m_nativeWindow = p_window; 389 390 // create EGLSurface from the generated subwindow 391 fb->m_eglSurface = s_egl.eglCreateWindowSurface(fb->m_eglDisplay, 392 fb->m_eglConfig, 393 fb->m_subWin, 394 NULL); 395 396 if (fb->m_eglSurface == EGL_NO_SURFACE) { 397 ERR("Failed to create surface\n"); 398 destroySubWindow(fb->m_subWinDisplay, fb->m_subWin); 399 fb->m_subWin = NULL; 400 } 401 else if (fb->bindSubwin_locked()) { 402 // Subwin creation was successfull, 403 // update viewport and z rotation and draw 404 // the last posted color buffer. 405 s_gl.glViewport(0, 0, p_width, p_height); 406 fb->m_zRot = zRot; 407 fb->post( fb->m_lastPostedColorBuffer, false ); 408 fb->unbind_locked(); 409 success = true; 410 } 411 } 412 } 413 s_theFrameBuffer->m_lock.unlock(); 414 } 415 416 return success; 417 } 418 419 bool FrameBuffer::removeSubWindow() 420 { 421 bool removed = false; 422 if (s_theFrameBuffer) { 423 s_theFrameBuffer->m_lock.lock(); 424 if (s_theFrameBuffer->m_subWin) { 425 s_egl.eglMakeCurrent(s_theFrameBuffer->m_eglDisplay, NULL, NULL, NULL); 426 s_egl.eglDestroySurface(s_theFrameBuffer->m_eglDisplay, 427 s_theFrameBuffer->m_eglSurface); 428 destroySubWindow(s_theFrameBuffer->m_subWinDisplay, 429 s_theFrameBuffer->m_subWin); 430 431 s_theFrameBuffer->m_eglSurface = EGL_NO_SURFACE; 432 s_theFrameBuffer->m_subWin = NULL; 433 removed = true; 434 } 435 s_theFrameBuffer->m_lock.unlock(); 436 } 437 return removed; 438 } 439 440 HandleType FrameBuffer::genHandle() 441 { 442 HandleType id; 443 do { 444 id = ++s_nextHandle; 445 } while( id == 0 || 446 m_contexts.find(id) != m_contexts.end() || 447 m_windows.find(id) != m_windows.end() ); 448 449 return id; 450 } 451 452 HandleType FrameBuffer::createColorBuffer(int p_width, int p_height, 453 GLenum p_internalFormat) 454 { 455 android::Mutex::Autolock mutex(m_lock); 456 HandleType ret = 0; 457 458 ColorBufferPtr cb( ColorBuffer::create(p_width, p_height, p_internalFormat) ); 459 if (cb.Ptr() != NULL) { 460 ret = genHandle(); 461 m_colorbuffers[ret].cb = cb; 462 m_colorbuffers[ret].refcount = 1; 463 } 464 return ret; 465 } 466 467 HandleType FrameBuffer::createRenderContext(int p_config, HandleType p_share, 468 bool p_isGL2) 469 { 470 android::Mutex::Autolock mutex(m_lock); 471 HandleType ret = 0; 472 473 RenderContextPtr share(NULL); 474 if (p_share != 0) { 475 RenderContextMap::iterator s( m_contexts.find(p_share) ); 476 if (s == m_contexts.end()) { 477 return 0; 478 } 479 share = (*s).second; 480 } 481 482 RenderContextPtr rctx( RenderContext::create(p_config, share, p_isGL2) ); 483 if (rctx.Ptr() != NULL) { 484 ret = genHandle(); 485 m_contexts[ret] = rctx; 486 } 487 return ret; 488 } 489 490 HandleType FrameBuffer::createWindowSurface(int p_config, int p_width, int p_height) 491 { 492 android::Mutex::Autolock mutex(m_lock); 493 494 HandleType ret = 0; 495 WindowSurfacePtr win( WindowSurface::create(p_config, p_width, p_height) ); 496 if (win.Ptr() != NULL) { 497 ret = genHandle(); 498 m_windows[ret] = win; 499 } 500 501 return ret; 502 } 503 504 void FrameBuffer::DestroyRenderContext(HandleType p_context) 505 { 506 android::Mutex::Autolock mutex(m_lock); 507 m_contexts.erase(p_context); 508 } 509 510 void FrameBuffer::DestroyWindowSurface(HandleType p_surface) 511 { 512 android::Mutex::Autolock mutex(m_lock); 513 m_windows.erase(p_surface); 514 } 515 516 void FrameBuffer::openColorBuffer(HandleType p_colorbuffer) 517 { 518 android::Mutex::Autolock mutex(m_lock); 519 ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer)); 520 if (c == m_colorbuffers.end()) { 521 // bad colorbuffer handle 522 return; 523 } 524 (*c).second.refcount++; 525 } 526 527 void FrameBuffer::closeColorBuffer(HandleType p_colorbuffer) 528 { 529 android::Mutex::Autolock mutex(m_lock); 530 ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer)); 531 if (c == m_colorbuffers.end()) { 532 // bad colorbuffer handle 533 return; 534 } 535 if (--(*c).second.refcount == 0) { 536 m_colorbuffers.erase(c); 537 } 538 } 539 540 bool FrameBuffer::flushWindowSurfaceColorBuffer(HandleType p_surface) 541 { 542 android::Mutex::Autolock mutex(m_lock); 543 544 WindowSurfaceMap::iterator w( m_windows.find(p_surface) ); 545 if (w == m_windows.end()) { 546 // bad surface handle 547 return false; 548 } 549 550 (*w).second->flushColorBuffer(); 551 552 return true; 553 } 554 555 bool FrameBuffer::setWindowSurfaceColorBuffer(HandleType p_surface, 556 HandleType p_colorbuffer) 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 ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) ); 567 if (c == m_colorbuffers.end()) { 568 // bad colorbuffer handle 569 return false; 570 } 571 572 (*w).second->setColorBuffer( (*c).second.cb ); 573 574 return true; 575 } 576 577 bool FrameBuffer::updateColorBuffer(HandleType p_colorbuffer, 578 int x, int y, int width, int height, 579 GLenum format, GLenum type, void *pixels) 580 { 581 android::Mutex::Autolock mutex(m_lock); 582 583 ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) ); 584 if (c == m_colorbuffers.end()) { 585 // bad colorbuffer handle 586 return false; 587 } 588 589 (*c).second.cb->subUpdate(x, y, width, height, format, type, pixels); 590 591 return true; 592 } 593 594 bool FrameBuffer::bindColorBufferToTexture(HandleType p_colorbuffer) 595 { 596 android::Mutex::Autolock mutex(m_lock); 597 598 ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) ); 599 if (c == m_colorbuffers.end()) { 600 // bad colorbuffer handle 601 return false; 602 } 603 604 return (*c).second.cb->bindToTexture(); 605 } 606 607 bool FrameBuffer::bindColorBufferToRenderbuffer(HandleType p_colorbuffer) 608 { 609 android::Mutex::Autolock mutex(m_lock); 610 611 ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) ); 612 if (c == m_colorbuffers.end()) { 613 // bad colorbuffer handle 614 return false; 615 } 616 617 return (*c).second.cb->bindToRenderbuffer(); 618 } 619 620 bool FrameBuffer::bindContext(HandleType p_context, 621 HandleType p_drawSurface, 622 HandleType p_readSurface) 623 { 624 android::Mutex::Autolock mutex(m_lock); 625 626 WindowSurfacePtr draw(NULL), read(NULL); 627 RenderContextPtr ctx(NULL); 628 629 // 630 // if this is not an unbind operation - make sure all handles are good 631 // 632 if (p_context || p_drawSurface || p_readSurface) { 633 RenderContextMap::iterator r( m_contexts.find(p_context) ); 634 if (r == m_contexts.end()) { 635 // bad context handle 636 return false; 637 } 638 639 ctx = (*r).second; 640 WindowSurfaceMap::iterator w( m_windows.find(p_drawSurface) ); 641 if (w == m_windows.end()) { 642 // bad surface handle 643 return false; 644 } 645 draw = (*w).second; 646 647 if (p_readSurface != p_drawSurface) { 648 WindowSurfaceMap::iterator w( m_windows.find(p_readSurface) ); 649 if (w == m_windows.end()) { 650 // bad surface handle 651 return false; 652 } 653 read = (*w).second; 654 } 655 else { 656 read = draw; 657 } 658 } 659 660 if (!s_egl.eglMakeCurrent(m_eglDisplay, 661 draw ? draw->getEGLSurface() : EGL_NO_SURFACE, 662 read ? read->getEGLSurface() : EGL_NO_SURFACE, 663 ctx ? ctx->getEGLContext() : EGL_NO_CONTEXT)) { 664 // MakeCurrent failed 665 return false; 666 } 667 668 // 669 // Bind the surface(s) to the context 670 // 671 RenderThreadInfo *tinfo = getRenderThreadInfo(); 672 if (draw.Ptr() == NULL && read.Ptr() == NULL) { 673 // if this is an unbind operation - make sure the current bound 674 // surfaces get unbound from the context. 675 draw = tinfo->currDrawSurf; 676 read = tinfo->currReadSurf; 677 } 678 679 if (draw.Ptr() != NULL && read.Ptr() != NULL) { 680 if (p_readSurface != p_drawSurface) { 681 draw->bind( ctx, SURFACE_BIND_DRAW ); 682 read->bind( ctx, SURFACE_BIND_READ ); 683 } 684 else { 685 draw->bind( ctx, SURFACE_BIND_READDRAW ); 686 } 687 } 688 689 // 690 // update thread info with current bound context 691 // 692 tinfo->currContext = ctx; 693 tinfo->currDrawSurf = draw; 694 tinfo->currReadSurf = read; 695 if (ctx) { 696 if (ctx->isGL2()) tinfo->m_gl2Dec.setContextData(&ctx->decoderContextData()); 697 else tinfo->m_glDec.setContextData(&ctx->decoderContextData()); 698 } 699 else { 700 tinfo->m_glDec.setContextData(NULL); 701 tinfo->m_gl2Dec.setContextData(NULL); 702 } 703 return true; 704 } 705 706 // 707 // The framebuffer lock should be held when calling this function ! 708 // 709 bool FrameBuffer::bind_locked() 710 { 711 EGLContext prevContext = s_egl.eglGetCurrentContext(); 712 EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ); 713 EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW); 714 715 if (!s_egl.eglMakeCurrent(m_eglDisplay, m_pbufSurface, 716 m_pbufSurface, m_pbufContext)) { 717 ERR("eglMakeCurrent failed\n"); 718 return false; 719 } 720 721 m_prevContext = prevContext; 722 m_prevReadSurf = prevReadSurf; 723 m_prevDrawSurf = prevDrawSurf; 724 return true; 725 } 726 727 bool FrameBuffer::bindSubwin_locked() 728 { 729 EGLContext prevContext = s_egl.eglGetCurrentContext(); 730 EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ); 731 EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW); 732 733 if (!s_egl.eglMakeCurrent(m_eglDisplay, m_eglSurface, 734 m_eglSurface, m_eglContext)) { 735 ERR("eglMakeCurrent failed\n"); 736 return false; 737 } 738 739 // 740 // initialize GL state in eglContext if not yet initilaized 741 // 742 if (!m_eglContextInitialized) { 743 initGLState(); 744 m_eglContextInitialized = true; 745 } 746 747 m_prevContext = prevContext; 748 m_prevReadSurf = prevReadSurf; 749 m_prevDrawSurf = prevDrawSurf; 750 return true; 751 } 752 753 bool FrameBuffer::unbind_locked() 754 { 755 if (!s_egl.eglMakeCurrent(m_eglDisplay, m_prevDrawSurf, 756 m_prevReadSurf, m_prevContext)) { 757 return false; 758 } 759 760 m_prevContext = EGL_NO_CONTEXT; 761 m_prevReadSurf = EGL_NO_SURFACE; 762 m_prevDrawSurf = EGL_NO_SURFACE; 763 return true; 764 } 765 766 bool FrameBuffer::post(HandleType p_colorbuffer, bool needLock) 767 { 768 if (needLock) m_lock.lock(); 769 bool ret = false; 770 771 ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) ); 772 if (c != m_colorbuffers.end()) { 773 774 m_lastPostedColorBuffer = p_colorbuffer; 775 if (!m_subWin) { 776 // no subwindow created for the FB output 777 // cannot post the colorbuffer 778 if (needLock) m_lock.unlock(); 779 return ret; 780 } 781 782 783 // bind the subwindow eglSurface 784 if (!bindSubwin_locked()) { 785 ERR("FrameBuffer::post eglMakeCurrent failed\n"); 786 if (needLock) m_lock.unlock(); 787 return false; 788 } 789 790 // 791 // render the color buffer to the window 792 // 793 s_gl.glPushMatrix(); 794 s_gl.glRotatef(m_zRot, 0.0f, 0.0f, 1.0f); 795 if (m_zRot != 0.0f) { 796 s_gl.glClear(GL_COLOR_BUFFER_BIT); 797 } 798 ret = (*c).second.cb->post(); 799 s_gl.glPopMatrix(); 800 801 if (ret) { 802 803 // 804 // output FPS statistics 805 // 806 if (m_fpsStats) { 807 long long currTime = GetCurrentTimeMS(); 808 m_statsNumFrames++; 809 if (currTime - m_statsStartTime >= 1000) { 810 float dt = (float)(currTime - m_statsStartTime) / 1000.0f; 811 printf("FPS: %5.3f\n", (float)m_statsNumFrames / dt); 812 m_statsStartTime = currTime; 813 m_statsNumFrames = 0; 814 } 815 } 816 817 s_egl.eglSwapBuffers(m_eglDisplay, m_eglSurface); 818 } 819 820 // restore previous binding 821 unbind_locked(); 822 } 823 824 if (needLock) m_lock.unlock(); 825 return ret; 826 } 827 828 bool FrameBuffer::repost() 829 { 830 if (m_lastPostedColorBuffer) { 831 return post( m_lastPostedColorBuffer ); 832 } 833 return false; 834 } 835 836 void FrameBuffer::initGLState() 837 { 838 s_gl.glMatrixMode(GL_PROJECTION); 839 s_gl.glLoadIdentity(); 840 s_gl.glOrthof(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); 841 s_gl.glMatrixMode(GL_MODELVIEW); 842 s_gl.glLoadIdentity(); 843 } 844