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