1 /* 2 ----------------------------------------------------------------------------- 3 This source file is part of OGRE 4 (Object-oriented Graphics Rendering Engine) 5 For the latest info, see http://www.ogre3d.org/ 6 7 Copyright (c) 2000-2013 Torus Knot Software Ltd 8 9 Permission is hereby granted, free of charge, to any person obtaining a copy 10 of this software and associated documentation files (the "Software"), to deal 11 in the Software without restriction, including without limitation the rights 12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 copies of the Software, and to permit persons to whom the Software is 14 furnished to do so, subject to the following conditions: 15 16 The above copyright notice and this permission notice shall be included in 17 all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 THE SOFTWARE. 26 ----------------------------------------------------------------------------- 27 */ 28 29 #include "OgreGLFBORenderTexture.h" 30 #include "OgreGLPixelFormat.h" 31 #include "OgreLogManager.h" 32 #include "OgreStringConverter.h" 33 #include "OgreRoot.h" 34 #include "OgreGLHardwarePixelBuffer.h" 35 #include "OgreGLFBOMultiRenderTarget.h" 36 37 namespace Ogre { 38 39 //----------------------------------------------------------------------------- GLFBORenderTexture(GLFBOManager * manager,const String & name,const GLSurfaceDesc & target,bool writeGamma,uint fsaa)40 GLFBORenderTexture::GLFBORenderTexture(GLFBOManager *manager, const String &name, 41 const GLSurfaceDesc &target, bool writeGamma, uint fsaa): 42 GLRenderTexture(name, target, writeGamma, fsaa), 43 mFB(manager, fsaa) 44 { 45 // Bind target to surface 0 and initialise 46 mFB.bindSurface(0, target); 47 // Get attributes 48 mWidth = mFB.getWidth(); 49 mHeight = mFB.getHeight(); 50 } 51 getCustomAttribute(const String & name,void * pData)52 void GLFBORenderTexture::getCustomAttribute(const String& name, void* pData) 53 { 54 if( name == GLRenderTexture::CustomAttributeString_FBO ) 55 { 56 *static_cast<GLFrameBufferObject **>(pData) = &mFB; 57 } 58 else if (name == "GL_FBOID") 59 { 60 *static_cast<GLuint*>(pData) = mFB.getGLFBOID(); 61 } 62 else if (name == "GL_MULTISAMPLEFBOID") 63 { 64 *static_cast<GLuint*>(pData) = mFB.getGLMultisampleFBOID(); 65 } 66 } 67 swapBuffers()68 void GLFBORenderTexture::swapBuffers() 69 { 70 mFB.swapBuffers(); 71 } 72 //----------------------------------------------------------------------------- attachDepthBuffer(DepthBuffer * depthBuffer)73 bool GLFBORenderTexture::attachDepthBuffer( DepthBuffer *depthBuffer ) 74 { 75 bool result; 76 if( (result = GLRenderTexture::attachDepthBuffer( depthBuffer )) ) 77 mFB.attachDepthBuffer( depthBuffer ); 78 79 return result; 80 } 81 //----------------------------------------------------------------------------- detachDepthBuffer()82 void GLFBORenderTexture::detachDepthBuffer() 83 { 84 mFB.detachDepthBuffer(); 85 GLRenderTexture::detachDepthBuffer(); 86 } 87 //----------------------------------------------------------------------------- _detachDepthBuffer()88 void GLFBORenderTexture::_detachDepthBuffer() 89 { 90 mFB.detachDepthBuffer(); 91 GLRenderTexture::_detachDepthBuffer(); 92 } 93 94 /// Size of probe texture 95 #define PROBE_SIZE 16 96 97 /// Stencil and depth formats to be tried 98 static const GLenum stencilFormats[] = 99 { 100 GL_NONE, // No stencil 101 GL_STENCIL_INDEX1_EXT, 102 GL_STENCIL_INDEX4_EXT, 103 GL_STENCIL_INDEX8_EXT, 104 GL_STENCIL_INDEX16_EXT 105 }; 106 static const size_t stencilBits[] = 107 { 108 0, 1, 4, 8, 16 109 }; 110 #define STENCILFORMAT_COUNT (sizeof(stencilFormats)/sizeof(GLenum)) 111 112 static const GLenum depthFormats[] = 113 { 114 GL_NONE, 115 GL_DEPTH_COMPONENT16, 116 GL_DEPTH_COMPONENT24, // Prefer 24 bit depth 117 GL_DEPTH_COMPONENT32, 118 GL_DEPTH24_STENCIL8_EXT // packed depth / stencil 119 }; 120 static const size_t depthBits[] = 121 { 122 0,16,24,32,24 123 }; 124 #define DEPTHFORMAT_COUNT (sizeof(depthFormats)/sizeof(GLenum)) 125 GLFBOManager(bool atimode)126 GLFBOManager::GLFBOManager(bool atimode): 127 mATIMode(atimode) 128 { 129 detectFBOFormats(); 130 131 glGenFramebuffersEXT(1, &mTempFBO); 132 } 133 ~GLFBOManager()134 GLFBOManager::~GLFBOManager() 135 { 136 if(!mRenderBufferMap.empty()) 137 { 138 LogManager::getSingleton().logMessage("GL: Warning! GLFBOManager destructor called, but not all renderbuffers were released.", LML_CRITICAL); 139 } 140 141 glDeleteFramebuffersEXT(1, &mTempFBO); 142 } 143 _createTempFramebuffer(GLuint fmt,GLuint & fb,GLuint & tid)144 void GLFBOManager::_createTempFramebuffer(GLuint fmt, GLuint &fb, GLuint &tid) 145 { 146 // NB we bypass state cache, this method is only called on startup and not after 147 // GLStateCacheManager::initializeCache 148 149 glGenFramebuffersEXT(1, &fb); 150 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb); 151 if (fmt != GL_NONE) 152 { 153 if (tid) 154 glDeleteTextures(1, &tid); 155 156 // Create and attach texture 157 glGenTextures(1, &tid); 158 glBindTexture(GL_TEXTURE_2D, tid); 159 160 // Set some default parameters so it won't fail on NVidia cards 161 if (GLEW_VERSION_1_2) 162 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); 163 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 164 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 165 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 166 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 167 168 glTexImage2D(GL_TEXTURE_2D, 0, fmt, PROBE_SIZE, PROBE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); 169 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, 170 GL_TEXTURE_2D, tid, 0); 171 } 172 else 173 { 174 // Draw to nowhere -- stencil/depth only 175 glDrawBuffer(GL_NONE); 176 glReadBuffer(GL_NONE); 177 } 178 } 179 180 /** Try a certain FBO format, and return the status. Also sets mDepthRB and mStencilRB. 181 @return true if this combo is supported 182 false if this combo is not supported 183 */ _tryFormat(GLenum depthFormat,GLenum stencilFormat)184 GLuint GLFBOManager::_tryFormat(GLenum depthFormat, GLenum stencilFormat) 185 { 186 GLuint status, depthRB = 0, stencilRB = 0; 187 bool failed = false; // flag on GL errors 188 189 if(depthFormat != GL_NONE) 190 { 191 /// Generate depth renderbuffer 192 glGenRenderbuffersEXT(1, &depthRB); 193 /// Bind it to FBO 194 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthRB); 195 196 /// Allocate storage for depth buffer 197 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, depthFormat, 198 PROBE_SIZE, PROBE_SIZE); 199 200 /// Attach depth 201 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, 202 GL_RENDERBUFFER_EXT, depthRB); 203 } 204 205 if(stencilFormat != GL_NONE) 206 { 207 /// Generate stencil renderbuffer 208 glGenRenderbuffersEXT(1, &stencilRB); 209 /// Bind it to FBO 210 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, stencilRB); 211 glGetError(); // NV hack 212 /// Allocate storage for stencil buffer 213 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, stencilFormat, 214 PROBE_SIZE, PROBE_SIZE); 215 if(glGetError() != GL_NO_ERROR) // NV hack 216 failed = true; 217 /// Attach stencil 218 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, 219 GL_RENDERBUFFER_EXT, stencilRB); 220 if(glGetError() != GL_NO_ERROR) // NV hack 221 failed = true; 222 } 223 224 status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); 225 /// If status is negative, clean up 226 // Detach and destroy 227 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0); 228 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0); 229 230 if (depthRB) 231 glDeleteRenderbuffersEXT(1, &depthRB); 232 if (stencilRB) 233 glDeleteRenderbuffersEXT(1, &stencilRB); 234 235 return status == GL_FRAMEBUFFER_COMPLETE_EXT && !failed; 236 } 237 238 /** Try a certain packed depth/stencil format, and return the status. 239 @return true if this combo is supported 240 false if this combo is not supported 241 */ _tryPackedFormat(GLenum packedFormat)242 bool GLFBOManager::_tryPackedFormat(GLenum packedFormat) 243 { 244 GLuint packedRB = 0; 245 bool failed = false; // flag on GL errors 246 247 /// Generate renderbuffer 248 glGenRenderbuffersEXT(1, &packedRB); 249 250 /// Bind it to FBO 251 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, packedRB); 252 253 /// Allocate storage for buffer 254 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, packedFormat, PROBE_SIZE, PROBE_SIZE); 255 glGetError(); // NV hack 256 257 /// Attach depth 258 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, 259 GL_RENDERBUFFER_EXT, packedRB); 260 if(glGetError() != GL_NO_ERROR) // NV hack 261 failed = true; 262 263 /// Attach stencil 264 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, 265 GL_RENDERBUFFER_EXT, packedRB); 266 if(glGetError() != GL_NO_ERROR) // NV hack 267 failed = true; 268 269 GLuint status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); 270 271 /// Detach and destroy 272 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0); 273 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0); 274 glDeleteRenderbuffersEXT(1, &packedRB); 275 276 return status == GL_FRAMEBUFFER_COMPLETE_EXT && !failed; 277 } 278 279 /** Detect which internal formats are allowed as RTT 280 Also detect what combinations of stencil and depth are allowed with this internal 281 format. 282 */ detectFBOFormats()283 void GLFBOManager::detectFBOFormats() 284 { 285 // Try all formats, and report which ones work as target 286 GLuint fb = 0, tid = 0; 287 GLint old_drawbuffer = 0, old_readbuffer = 0; 288 289 glGetIntegerv (GL_DRAW_BUFFER, &old_drawbuffer); 290 glGetIntegerv (GL_READ_BUFFER, &old_readbuffer); 291 292 for(size_t x=0; x<PF_COUNT; ++x) 293 { 294 mProps[x].valid = false; 295 296 // Fetch GL format token 297 GLenum fmt = GLPixelUtil::getGLInternalFormat((PixelFormat)x); 298 if(fmt == GL_NONE && x != 0) 299 continue; 300 301 // No test for compressed formats 302 if(PixelUtil::isCompressed((PixelFormat)x)) 303 continue; 304 305 // Buggy ATI cards *crash* on non-RGB(A) formats 306 int depths[4]; 307 PixelUtil::getBitDepths((PixelFormat)x, depths); 308 if(fmt!=GL_NONE && mATIMode && (!depths[0] || !depths[1] || !depths[2])) 309 continue; 310 311 // Create and attach framebuffer 312 _createTempFramebuffer(fmt, fb, tid); 313 314 // Check status 315 GLuint status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); 316 317 // Ignore status in case of fmt==GL_NONE, because no implementation will accept 318 // a buffer without *any* attachment. Buffers with only stencil and depth attachment 319 // might still be supported, so we must continue probing. 320 if(fmt == GL_NONE || status == GL_FRAMEBUFFER_COMPLETE_EXT) 321 { 322 mProps[x].valid = true; 323 StringUtil::StrStreamType str; 324 str << "FBO " << PixelUtil::getFormatName((PixelFormat)x) 325 << " depth/stencil support: "; 326 327 // For each depth/stencil formats 328 for (size_t depth = 0; depth < DEPTHFORMAT_COUNT; ++depth) 329 { 330 if (depthFormats[depth] != GL_DEPTH24_STENCIL8_EXT) 331 { 332 // General depth/stencil combination 333 334 for (size_t stencil = 0; stencil < STENCILFORMAT_COUNT; ++stencil) 335 { 336 //StringUtil::StrStreamType l; 337 //l << "Trying " << PixelUtil::getFormatName((PixelFormat)x) 338 // << " D" << depthBits[depth] 339 // << "S" << stencilBits[stencil]; 340 //LogManager::getSingleton().logMessage(l.str()); 341 342 if (_tryFormat(depthFormats[depth], stencilFormats[stencil])) 343 { 344 /// Add mode to allowed modes 345 str << "D" << depthBits[depth] << "S" << stencilBits[stencil] << " "; 346 FormatProperties::Mode mode; 347 mode.depth = depth; 348 mode.stencil = stencil; 349 mProps[x].modes.push_back(mode); 350 } 351 else 352 { 353 // There is a small edge case that FBO is trashed during the test 354 // on some drivers resulting in undefined behavior 355 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 356 glDeleteFramebuffersEXT(1, &fb); 357 358 // Workaround for NVIDIA / Linux 169.21 driver problem 359 // see http://www.ogre3d.org/phpBB2/viewtopic.php?t=38037&start=25 360 glFinish(); 361 362 _createTempFramebuffer(fmt, fb, tid); 363 } 364 } 365 } 366 else 367 { 368 // Packed depth/stencil format 369 370 // #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX 371 // It now seems as if this workaround now *breaks* nvidia cards on Linux with the 169.12 drivers on Linux 372 #if 0 373 // Only query packed depth/stencil formats for 32-bit 374 // non-floating point formats (ie not R32!) 375 // Linux nVidia driver segfaults if you query others 376 if (PixelUtil::getNumElemBits((PixelFormat)x) != 32 || 377 PixelUtil::isFloatingPoint((PixelFormat)x)) 378 { 379 continue; 380 } 381 #endif 382 383 if (_tryPackedFormat(depthFormats[depth])) 384 { 385 /// Add mode to allowed modes 386 str << "Packed-D" << depthBits[depth] << "S" << 8 << " "; 387 FormatProperties::Mode mode; 388 mode.depth = depth; 389 mode.stencil = 0; // unuse 390 mProps[x].modes.push_back(mode); 391 } 392 else 393 { 394 // There is a small edge case that FBO is trashed during the test 395 // on some drivers resulting in undefined behavior 396 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 397 glDeleteFramebuffersEXT(1, &fb); 398 399 // Workaround for NVIDIA / Linux 169.21 driver problem 400 // see http://www.ogre3d.org/phpBB2/viewtopic.php?t=38037&start=25 401 glFinish(); 402 403 _createTempFramebuffer(fmt, fb, tid); 404 } 405 } 406 } 407 408 LogManager::getSingleton().logMessage(str.str()); 409 410 } 411 // Delete texture and framebuffer 412 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 413 glDeleteFramebuffersEXT(1, &fb); 414 415 // Workaround for NVIDIA / Linux 169.21 driver problem 416 // see http://www.ogre3d.org/phpBB2/viewtopic.php?t=38037&start=25 417 glFinish(); 418 419 if (fmt != GL_NONE) 420 { 421 glDeleteTextures(1, &tid); 422 tid = 0; 423 } 424 } 425 426 // It seems a bug in nVidia driver: glBindFramebufferEXT should restore 427 // draw and read buffers, but in some unclear circumstances it won't. 428 glDrawBuffer(old_drawbuffer); 429 glReadBuffer(old_readbuffer); 430 431 String fmtstring = ""; 432 for(size_t x=0; x<PF_COUNT; ++x) 433 { 434 if(mProps[x].valid) 435 fmtstring += PixelUtil::getFormatName((PixelFormat)x)+" "; 436 } 437 LogManager::getSingleton().logMessage("[GL] : Valid FBO targets " + fmtstring); 438 } getBestDepthStencil(GLenum internalFormat,GLenum * depthFormat,GLenum * stencilFormat)439 void GLFBOManager::getBestDepthStencil(GLenum internalFormat, GLenum *depthFormat, GLenum *stencilFormat) 440 { 441 const FormatProperties &props = mProps[internalFormat]; 442 /// Decide what stencil and depth formats to use 443 /// [best supported for internal format] 444 size_t bestmode=0; 445 int bestscore=-1; 446 for(size_t mode=0; mode<props.modes.size(); mode++) 447 { 448 #if 0 449 /// Always prefer D24S8 450 if(stencilBits[props.modes[mode].stencil]==8 && 451 depthBits[props.modes[mode].depth]==24) 452 { 453 bestmode = mode; 454 break; 455 } 456 #endif 457 int desirability = 0; 458 /// Find most desirable mode 459 /// desirability == 0 if no depth, no stencil 460 /// desirability == 1000...2000 if no depth, stencil 461 /// desirability == 2000...3000 if depth, no stencil 462 /// desirability == 3000+ if depth and stencil 463 /// beyond this, the total numer of bits (stencil+depth) is maximised 464 if(props.modes[mode].stencil) 465 desirability += 1000; 466 if(props.modes[mode].depth) 467 desirability += 2000; 468 if(depthBits[props.modes[mode].depth]==24) // Prefer 24 bit for now 469 desirability += 500; 470 if(depthFormats[props.modes[mode].depth]==GL_DEPTH24_STENCIL8_EXT) // Prefer 24/8 packed 471 desirability += 5000; 472 desirability += stencilBits[props.modes[mode].stencil] + depthBits[props.modes[mode].depth]; 473 474 if(desirability>bestscore) 475 { 476 bestscore = desirability; 477 bestmode = mode; 478 } 479 } 480 *depthFormat = depthFormats[props.modes[bestmode].depth]; 481 *stencilFormat = stencilFormats[props.modes[bestmode].stencil]; 482 } 483 createRenderTexture(const String & name,const GLSurfaceDesc & target,bool writeGamma,uint fsaa)484 GLFBORenderTexture *GLFBOManager::createRenderTexture(const String &name, 485 const GLSurfaceDesc &target, bool writeGamma, uint fsaa) 486 { 487 GLFBORenderTexture *retval = new GLFBORenderTexture(this, name, target, writeGamma, fsaa); 488 return retval; 489 } createMultiRenderTarget(const String & name)490 MultiRenderTarget *GLFBOManager::createMultiRenderTarget(const String & name) 491 { 492 return new GLFBOMultiRenderTarget(this, name); 493 } 494 //--------------------------------------------------------------------- bind(RenderTarget * target)495 void GLFBOManager::bind(RenderTarget *target) 496 { 497 /// Check if the render target is in the rendertarget->FBO map 498 GLFrameBufferObject *fbo = 0; 499 target->getCustomAttribute(GLRenderTexture::CustomAttributeString_FBO, &fbo); 500 if(fbo) 501 fbo->bind(); 502 else 503 // Old style context (window/pbuffer) or copying render texture 504 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 505 } 506 requestRenderBuffer(GLenum format,uint32 width,uint32 height,uint fsaa)507 GLSurfaceDesc GLFBOManager::requestRenderBuffer(GLenum format, uint32 width, uint32 height, uint fsaa) 508 { 509 GLSurfaceDesc retval; 510 retval.buffer = 0; // Return 0 buffer if GL_NONE is requested 511 if(format != GL_NONE) 512 { 513 RBFormat key(format, width, height, fsaa); 514 RenderBufferMap::iterator it = mRenderBufferMap.find(key); 515 if(it != mRenderBufferMap.end() && (it->second.refcount == 0)) 516 { 517 retval.buffer = it->second.buffer; 518 retval.zoffset = 0; 519 retval.numSamples = fsaa; 520 // Increase refcount 521 ++it->second.refcount; 522 } 523 else 524 { 525 // New one 526 GLRenderBuffer *rb = new GLRenderBuffer(format, width, height, fsaa); 527 mRenderBufferMap[key] = RBRef(rb); 528 retval.buffer = rb; 529 retval.zoffset = 0; 530 retval.numSamples = fsaa; 531 } 532 } 533 //std::cerr << "Requested renderbuffer with format " << std::hex << format << std::dec << " of " << width << "x" << height << " :" << retval.buffer << std::endl; 534 return retval; 535 } 536 //----------------------------------------------------------------------- requestRenderBuffer(const GLSurfaceDesc & surface)537 void GLFBOManager::requestRenderBuffer(const GLSurfaceDesc &surface) 538 { 539 if(surface.buffer == 0) 540 return; 541 RBFormat key(surface.buffer->getGLFormat(), surface.buffer->getWidth(), surface.buffer->getHeight(), surface.numSamples); 542 RenderBufferMap::iterator it = mRenderBufferMap.find(key); 543 assert(it != mRenderBufferMap.end()); 544 if (it != mRenderBufferMap.end()) // Just in case 545 { 546 assert(it->second.buffer == surface.buffer); 547 // Increase refcount 548 ++it->second.refcount; 549 } 550 } 551 //----------------------------------------------------------------------- releaseRenderBuffer(const GLSurfaceDesc & surface)552 void GLFBOManager::releaseRenderBuffer(const GLSurfaceDesc &surface) 553 { 554 if(surface.buffer == 0) 555 return; 556 RBFormat key(surface.buffer->getGLFormat(), surface.buffer->getWidth(), surface.buffer->getHeight(), surface.numSamples); 557 RenderBufferMap::iterator it = mRenderBufferMap.find(key); 558 if(it != mRenderBufferMap.end()) 559 { 560 // Decrease refcount 561 --it->second.refcount; 562 if(it->second.refcount==0) 563 { 564 // If refcount reaches zero, delete buffer and remove from map 565 delete it->second.buffer; 566 mRenderBufferMap.erase(it); 567 //std::cerr << "Destroyed renderbuffer of format " << std::hex << key.format << std::dec 568 // << " of " << key.width << "x" << key.height << std::endl; 569 } 570 } 571 } 572 } 573