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; 462 } 463 return ret; 464 } 465 466 HandleType FrameBuffer::createRenderContext(int p_config, HandleType p_share, 467 bool p_isGL2) 468 { 469 android::Mutex::Autolock mutex(m_lock); 470 HandleType ret = 0; 471 472 RenderContextPtr share(NULL); 473 if (p_share != 0) { 474 RenderContextMap::iterator s( m_contexts.find(p_share) ); 475 if (s == m_contexts.end()) { 476 return 0; 477 } 478 share = (*s).second; 479 } 480 481 RenderContextPtr rctx( RenderContext::create(p_config, share, p_isGL2) ); 482 if (rctx.Ptr() != NULL) { 483 ret = genHandle(); 484 m_contexts[ret] = rctx; 485 } 486 return ret; 487 } 488 489 HandleType FrameBuffer::createWindowSurface(int p_config, int p_width, int p_height) 490 { 491 android::Mutex::Autolock mutex(m_lock); 492 493 HandleType ret = 0; 494 WindowSurfacePtr win( WindowSurface::create(p_config, p_width, p_height) ); 495 if (win.Ptr() != NULL) { 496 ret = genHandle(); 497 m_windows[ret] = win; 498 } 499 500 return ret; 501 } 502 503 void FrameBuffer::DestroyRenderContext(HandleType p_context) 504 { 505 android::Mutex::Autolock mutex(m_lock); 506 m_contexts.erase(p_context); 507 } 508 509 void FrameBuffer::DestroyWindowSurface(HandleType p_surface) 510 { 511 android::Mutex::Autolock mutex(m_lock); 512 m_windows.erase(p_surface); 513 } 514 515 void FrameBuffer::DestroyColorBuffer(HandleType p_colorbuffer) 516 { 517 android::Mutex::Autolock mutex(m_lock); 518 m_colorbuffers.erase(p_colorbuffer); 519 } 520 521 bool FrameBuffer::flushWindowSurfaceColorBuffer(HandleType p_surface) 522 { 523 android::Mutex::Autolock mutex(m_lock); 524 525 WindowSurfaceMap::iterator w( m_windows.find(p_surface) ); 526 if (w == m_windows.end()) { 527 // bad surface handle 528 return false; 529 } 530 531 (*w).second->flushColorBuffer(); 532 533 return true; 534 } 535 536 bool FrameBuffer::setWindowSurfaceColorBuffer(HandleType p_surface, 537 HandleType p_colorbuffer) 538 { 539 android::Mutex::Autolock mutex(m_lock); 540 541 WindowSurfaceMap::iterator w( m_windows.find(p_surface) ); 542 if (w == m_windows.end()) { 543 // bad surface handle 544 return false; 545 } 546 547 ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) ); 548 if (c == m_colorbuffers.end()) { 549 // bad colorbuffer handle 550 return false; 551 } 552 553 (*w).second->setColorBuffer( (*c).second ); 554 555 return true; 556 } 557 558 bool FrameBuffer::updateColorBuffer(HandleType p_colorbuffer, 559 int x, int y, int width, int height, 560 GLenum format, GLenum type, void *pixels) 561 { 562 android::Mutex::Autolock mutex(m_lock); 563 564 ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) ); 565 if (c == m_colorbuffers.end()) { 566 // bad colorbuffer handle 567 return false; 568 } 569 570 (*c).second->subUpdate(x, y, width, height, format, type, pixels); 571 572 return true; 573 } 574 575 bool FrameBuffer::bindColorBufferToTexture(HandleType p_colorbuffer) 576 { 577 android::Mutex::Autolock mutex(m_lock); 578 579 ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) ); 580 if (c == m_colorbuffers.end()) { 581 // bad colorbuffer handle 582 return false; 583 } 584 585 return (*c).second->bindToTexture(); 586 } 587 588 bool FrameBuffer::bindColorBufferToRenderbuffer(HandleType p_colorbuffer) 589 { 590 android::Mutex::Autolock mutex(m_lock); 591 592 ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) ); 593 if (c == m_colorbuffers.end()) { 594 // bad colorbuffer handle 595 return false; 596 } 597 598 return (*c).second->bindToRenderbuffer(); 599 } 600 601 bool FrameBuffer::bindContext(HandleType p_context, 602 HandleType p_drawSurface, 603 HandleType p_readSurface) 604 { 605 android::Mutex::Autolock mutex(m_lock); 606 607 WindowSurfacePtr draw(NULL), read(NULL); 608 RenderContextPtr ctx(NULL); 609 610 // 611 // if this is not an unbind operation - make sure all handles are good 612 // 613 if (p_context || p_drawSurface || p_readSurface) { 614 RenderContextMap::iterator r( m_contexts.find(p_context) ); 615 if (r == m_contexts.end()) { 616 // bad context handle 617 return false; 618 } 619 620 ctx = (*r).second; 621 WindowSurfaceMap::iterator w( m_windows.find(p_drawSurface) ); 622 if (w == m_windows.end()) { 623 // bad surface handle 624 return false; 625 } 626 draw = (*w).second; 627 628 if (p_readSurface != p_drawSurface) { 629 WindowSurfaceMap::iterator w( m_windows.find(p_readSurface) ); 630 if (w == m_windows.end()) { 631 // bad surface handle 632 return false; 633 } 634 read = (*w).second; 635 } 636 else { 637 read = draw; 638 } 639 } 640 641 if (!s_egl.eglMakeCurrent(m_eglDisplay, 642 draw ? draw->getEGLSurface() : EGL_NO_SURFACE, 643 read ? read->getEGLSurface() : EGL_NO_SURFACE, 644 ctx ? ctx->getEGLContext() : EGL_NO_CONTEXT)) { 645 // MakeCurrent failed 646 return false; 647 } 648 649 // 650 // Bind the surface(s) to the context 651 // 652 RenderThreadInfo *tinfo = getRenderThreadInfo(); 653 if (draw.Ptr() == NULL && read.Ptr() == NULL) { 654 // if this is an unbind operation - make sure the current bound 655 // surfaces get unbound from the context. 656 draw = tinfo->currDrawSurf; 657 read = tinfo->currReadSurf; 658 } 659 660 if (draw.Ptr() != NULL && read.Ptr() != NULL) { 661 if (p_readSurface != p_drawSurface) { 662 draw->bind( ctx, SURFACE_BIND_DRAW ); 663 read->bind( ctx, SURFACE_BIND_READ ); 664 } 665 else { 666 draw->bind( ctx, SURFACE_BIND_READDRAW ); 667 } 668 } 669 670 // 671 // update thread info with current bound context 672 // 673 tinfo->currContext = ctx; 674 tinfo->currDrawSurf = draw; 675 tinfo->currReadSurf = read; 676 if (ctx) { 677 if (ctx->isGL2()) tinfo->m_gl2Dec.setContextData(&ctx->decoderContextData()); 678 else tinfo->m_glDec.setContextData(&ctx->decoderContextData()); 679 } 680 else { 681 tinfo->m_glDec.setContextData(NULL); 682 tinfo->m_gl2Dec.setContextData(NULL); 683 } 684 return true; 685 } 686 687 // 688 // The framebuffer lock should be held when calling this function ! 689 // 690 bool FrameBuffer::bind_locked() 691 { 692 EGLContext prevContext = s_egl.eglGetCurrentContext(); 693 EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ); 694 EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW); 695 696 if (!s_egl.eglMakeCurrent(m_eglDisplay, m_pbufSurface, 697 m_pbufSurface, m_pbufContext)) { 698 ERR("eglMakeCurrent failed\n"); 699 return false; 700 } 701 702 m_prevContext = prevContext; 703 m_prevReadSurf = prevReadSurf; 704 m_prevDrawSurf = prevDrawSurf; 705 return true; 706 } 707 708 bool FrameBuffer::bindSubwin_locked() 709 { 710 EGLContext prevContext = s_egl.eglGetCurrentContext(); 711 EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ); 712 EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW); 713 714 if (!s_egl.eglMakeCurrent(m_eglDisplay, m_eglSurface, 715 m_eglSurface, m_eglContext)) { 716 ERR("eglMakeCurrent failed\n"); 717 return false; 718 } 719 720 // 721 // initialize GL state in eglContext if not yet initilaized 722 // 723 if (!m_eglContextInitialized) { 724 initGLState(); 725 m_eglContextInitialized = true; 726 } 727 728 m_prevContext = prevContext; 729 m_prevReadSurf = prevReadSurf; 730 m_prevDrawSurf = prevDrawSurf; 731 return true; 732 } 733 734 bool FrameBuffer::unbind_locked() 735 { 736 if (!s_egl.eglMakeCurrent(m_eglDisplay, m_prevDrawSurf, 737 m_prevReadSurf, m_prevContext)) { 738 return false; 739 } 740 741 m_prevContext = EGL_NO_CONTEXT; 742 m_prevReadSurf = EGL_NO_SURFACE; 743 m_prevDrawSurf = EGL_NO_SURFACE; 744 return true; 745 } 746 747 bool FrameBuffer::post(HandleType p_colorbuffer, bool needLock) 748 { 749 if (needLock) m_lock.lock(); 750 bool ret = false; 751 752 ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) ); 753 if (c != m_colorbuffers.end()) { 754 755 m_lastPostedColorBuffer = p_colorbuffer; 756 if (!m_subWin) { 757 // no subwindow created for the FB output 758 // cannot post the colorbuffer 759 if (needLock) m_lock.unlock(); 760 return ret; 761 } 762 763 764 // bind the subwindow eglSurface 765 if (!bindSubwin_locked()) { 766 ERR("FrameBuffer::post eglMakeCurrent failed\n"); 767 if (needLock) m_lock.unlock(); 768 return false; 769 } 770 771 // 772 // render the color buffer to the window 773 // 774 s_gl.glPushMatrix(); 775 s_gl.glRotatef(m_zRot, 0.0f, 0.0f, 1.0f); 776 if (m_zRot != 0.0f) { 777 s_gl.glClear(GL_COLOR_BUFFER_BIT); 778 } 779 ret = (*c).second->post(); 780 s_gl.glPopMatrix(); 781 782 if (ret) { 783 784 // 785 // output FPS statistics 786 // 787 if (m_fpsStats) { 788 long long currTime = GetCurrentTimeMS(); 789 m_statsNumFrames++; 790 if (currTime - m_statsStartTime >= 1000) { 791 float dt = (float)(currTime - m_statsStartTime) / 1000.0f; 792 printf("FPS: %5.3f\n", (float)m_statsNumFrames / dt); 793 m_statsStartTime = currTime; 794 m_statsNumFrames = 0; 795 } 796 } 797 798 s_egl.eglSwapBuffers(m_eglDisplay, m_eglSurface); 799 } 800 801 // restore previous binding 802 unbind_locked(); 803 } 804 805 if (needLock) m_lock.unlock(); 806 return ret; 807 } 808 809 bool FrameBuffer::repost() 810 { 811 if (m_lastPostedColorBuffer) { 812 return post( m_lastPostedColorBuffer ); 813 } 814 return false; 815 } 816 817 void FrameBuffer::initGLState() 818 { 819 s_gl.glMatrixMode(GL_PROJECTION); 820 s_gl.glLoadIdentity(); 821 s_gl.glOrthof(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); 822 s_gl.glMatrixMode(GL_MODELVIEW); 823 s_gl.glLoadIdentity(); 824 } 825