Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/RenderSystems/GL/src/OgreGLFBORenderTexture.cpp @ 1

Last change on this file since 1 was 1, checked in by landauf, 17 years ago
File size: 19.0 KB
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2006 Torus Knot Software Ltd
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23
24You may alternatively use this source under the terms of a specific version of
25the OGRE Unrestricted License provided you have obtained such a license from
26Torus Knot Software Ltd.
27-----------------------------------------------------------------------------
28*/
29
30#include "OgreGLFBORenderTexture.h"
31#include "OgreGLPixelFormat.h"
32#include "OgreLogManager.h"
33#include "OgreStringConverter.h"
34#include "OgreRoot.h"
35#include "OgreGLHardwarePixelBuffer.h"
36#include "OgreGLFBOMultiRenderTarget.h"
37
38namespace Ogre {
39
40//-----------------------------------------------------------------------------   
41    GLFBORenderTexture::GLFBORenderTexture(GLFBOManager *manager, const String &name,
42        const GLSurfaceDesc &target):
43        GLRenderTexture(name, target),
44        mFB(manager)
45    {
46        // Bind target to surface 0 and initialise
47        mFB.bindSurface(0, target);
48        // Get attributes
49        mWidth = mFB.getWidth();
50        mHeight = mFB.getHeight();
51    }
52
53    void GLFBORenderTexture::getCustomAttribute(const String& name, void* pData)
54    {
55        if(name=="FBO")
56        {
57            *static_cast<GLFrameBufferObject **>(pData) = &mFB;
58        }
59    }
60   
61/// Size of probe texture
62#define PROBE_SIZE 16
63
64/// Stencil and depth formats to be tried
65static const GLenum stencilFormats[] =
66{
67    GL_NONE,                    // No stencil
68    GL_STENCIL_INDEX1_EXT,
69    GL_STENCIL_INDEX4_EXT,
70    GL_STENCIL_INDEX8_EXT,
71    GL_STENCIL_INDEX16_EXT
72};
73static const size_t stencilBits[] =
74{
75    0, 1, 4, 8, 16
76};
77#define STENCILFORMAT_COUNT (sizeof(stencilFormats)/sizeof(GLenum))
78
79static const GLenum depthFormats[] =
80{
81    GL_NONE,
82    GL_DEPTH_COMPONENT16,
83    GL_DEPTH_COMPONENT24,    // Prefer 24 bit depth
84    GL_DEPTH_COMPONENT32,
85    GL_DEPTH24_STENCIL8_EXT // packed depth / stencil
86};
87static const size_t depthBits[] =
88{
89    0,16,24,32,24
90};
91#define DEPTHFORMAT_COUNT (sizeof(depthFormats)/sizeof(GLenum))
92
93        GLFBOManager::GLFBOManager(bool atimode):
94                mATIMode(atimode)
95    {
96        detectFBOFormats();
97       
98        glGenFramebuffersEXT(1, &mTempFBO);
99    }
100
101        GLFBOManager::~GLFBOManager()
102        {
103                if(!mRenderBufferMap.empty())
104                {
105                        LogManager::getSingleton().logMessage("GL: Warning! GLFBOManager destructor called, but not all renderbuffers were released.");
106                }
107       
108        glDeleteFramebuffersEXT(1, &mTempFBO);     
109        }
110
111    /** Try a certain FBO format, and return the status. Also sets mDepthRB and mStencilRB.
112        @returns true    if this combo is supported
113                 false   if this combo is not supported
114    */
115    GLuint GLFBOManager::_tryFormat(GLenum depthFormat, GLenum stencilFormat)
116    {
117        GLuint status, depthRB = 0, stencilRB = 0;
118        bool failed = false; // flag on GL errors
119
120        if(depthFormat != GL_NONE)
121        {
122            /// Generate depth renderbuffer
123            glGenRenderbuffersEXT(1, &depthRB);
124            /// Bind it to FBO
125            glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthRB);
126           
127            /// Allocate storage for depth buffer
128            glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, depthFormat,
129                                PROBE_SIZE, PROBE_SIZE);
130           
131            /// Attach depth
132            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
133                                    GL_RENDERBUFFER_EXT, depthRB);
134        }
135
136        if(stencilFormat != GL_NONE)
137        {
138            /// Generate stencil renderbuffer
139            glGenRenderbuffersEXT(1, &stencilRB);
140            /// Bind it to FBO
141            glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, stencilRB);
142            glGetError(); // NV hack
143            /// Allocate storage for stencil buffer
144            glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, stencilFormat,
145                                PROBE_SIZE, PROBE_SIZE); 
146            if(glGetError() != GL_NO_ERROR) // NV hack
147                failed = true;
148            /// Attach stencil
149            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
150                            GL_RENDERBUFFER_EXT, stencilRB);
151            if(glGetError() != GL_NO_ERROR) // NV hack
152                failed = true;
153        }
154       
155        status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
156        /// If status is negative, clean up
157        // Detach and destroy
158        glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
159        glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
160        if (depthRB)
161            glDeleteRenderbuffersEXT(1, &depthRB);
162        if (stencilRB)
163            glDeleteRenderbuffersEXT(1, &stencilRB);
164       
165        return status == GL_FRAMEBUFFER_COMPLETE_EXT && !failed;
166    }
167   
168    /** Try a certain packed depth/stencil format, and return the status.
169        @returns true    if this combo is supported
170                 false   if this combo is not supported
171    */
172    bool GLFBOManager::_tryPackedFormat(GLenum packedFormat)
173    {
174        GLuint packedRB;
175        bool failed = false; // flag on GL errors
176
177        /// Generate renderbuffer
178        glGenRenderbuffersEXT(1, &packedRB);
179
180        /// Bind it to FBO
181        glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, packedRB);
182
183        /// Allocate storage for buffer
184        glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, packedFormat, PROBE_SIZE, PROBE_SIZE);
185        glGetError(); // NV hack
186
187        /// Attach depth
188        glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
189            GL_RENDERBUFFER_EXT, packedRB);
190        if(glGetError() != GL_NO_ERROR) // NV hack
191            failed = true;
192
193        /// Attach stencil
194        glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
195            GL_RENDERBUFFER_EXT, packedRB);
196        if(glGetError() != GL_NO_ERROR) // NV hack
197            failed = true;
198
199        GLuint status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
200
201        /// Detach and destroy
202        glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
203        glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
204        glDeleteRenderbuffersEXT(1, &packedRB);
205
206        return status == GL_FRAMEBUFFER_COMPLETE_EXT && !failed;
207    }
208
209    /** Detect which internal formats are allowed as RTT
210        Also detect what combinations of stencil and depth are allowed with this internal
211        format.
212    */
213    void GLFBOManager::detectFBOFormats()
214    {
215        // Try all formats, and report which ones work as target
216        GLuint fb, tid;
217        GLint old_drawbuffer, old_readbuffer;
218        GLenum target = GL_TEXTURE_2D;
219
220        glGetIntegerv (GL_DRAW_BUFFER, &old_drawbuffer);
221        glGetIntegerv (GL_READ_BUFFER, &old_readbuffer);
222
223        for(size_t x=0; x<PF_COUNT; ++x)
224        {
225            mProps[x].valid = false;
226
227                        // Fetch GL format token
228                        GLenum fmt = GLPixelUtil::getGLInternalFormat((PixelFormat)x);
229            if(fmt == GL_NONE && x!=0)
230                continue;
231
232                        // No test for compressed formats
233                        if(PixelUtil::isCompressed((PixelFormat)x))
234                                continue;
235
236                        // Buggy ATI cards *crash* on non-RGB(A) formats
237                        int depths[4];
238                        PixelUtil::getBitDepths((PixelFormat)x, depths);
239                        if(fmt!=GL_NONE && mATIMode && (!depths[0] || !depths[1] || !depths[2]))
240                                continue;
241
242            // Create and attach framebuffer
243            glGenFramebuffersEXT(1, &fb);
244            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);
245            if (fmt!=GL_NONE)
246            {
247                                // Create and attach texture
248                                glGenTextures(1, &tid);
249                                glBindTexture(target, tid);
250                               
251                // Set some default parameters so it won't fail on NVidia cards         
252                glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, 0);
253                glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
254                glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
255                glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
256                glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
257                           
258                                glTexImage2D(target, 0, fmt, PROBE_SIZE, PROBE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
259                                glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
260                                target, tid, 0);
261            }
262                        else
263                        {
264                                // Draw to nowhere -- stencil/depth only
265                                glDrawBuffer(GL_NONE);
266                                glReadBuffer(GL_NONE);
267                        }
268            // Check status
269            GLuint status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
270
271                        // Ignore status in case of fmt==GL_NONE, because no implementation will accept
272                        // a buffer without *any* attachment. Buffers with only stencil and depth attachment
273                        // might still be supported, so we must continue probing.
274            if(fmt == GL_NONE || status == GL_FRAMEBUFFER_COMPLETE_EXT)
275            {
276                mProps[x].valid = true;
277                                StringUtil::StrStreamType str;
278                                str << "FBO " << PixelUtil::getFormatName((PixelFormat)x) 
279                                        << " depth/stencil support: ";
280
281                // For each depth/stencil formats
282                for (size_t depth = 0; depth < DEPTHFORMAT_COUNT; ++depth)
283                {
284                    if (depthFormats[depth] != GL_DEPTH24_STENCIL8_EXT)
285                    {
286                        // General depth/stencil combination
287
288                        for (size_t stencil = 0; stencil < STENCILFORMAT_COUNT; ++stencil)
289                        {
290                            //StringUtil::StrStreamType l;
291                            //l << "Trying " << PixelUtil::getFormatName((PixelFormat)x)
292                            //  << " D" << depthBits[depth]
293                            //  << "S" << stencilBits[stencil];
294                            //LogManager::getSingleton().logMessage(l.str());
295
296                            if (_tryFormat(depthFormats[depth], stencilFormats[stencil]))
297                            {
298                                /// Add mode to allowed modes
299                                str << "D" << depthBits[depth] << "S" << stencilBits[stencil] << " ";
300                                FormatProperties::Mode mode;
301                                mode.depth = depth;
302                                mode.stencil = stencil;
303                                mProps[x].modes.push_back(mode);
304                            }
305                        }
306                    }
307                    else
308                    {
309                        // Packed depth/stencil format
310
311#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX
312                        // Only query packed depth/stencil formats for 32-bit
313                        // non-floating point formats (ie not R32!)
314                        // Linux nVidia driver segfaults if you query others
315                        if (PixelUtil::getNumElemBits((PixelFormat)x) != 32 ||
316                            PixelUtil::isFloatingPoint((PixelFormat)x))
317                        {
318                            continue;
319                        }
320#endif
321
322                        if (_tryPackedFormat(depthFormats[depth]))
323                        {
324                            /// Add mode to allowed modes
325                            str << "Packed-D" << depthBits[depth] << "S" << 8 << " ";
326                            FormatProperties::Mode mode;
327                            mode.depth = depth;
328                            mode.stencil = 0;   // unuse
329                            mProps[x].modes.push_back(mode);
330                        }
331                    }
332                }
333
334                LogManager::getSingleton().logMessage(str.str());
335
336            }
337            // Delete texture and framebuffer
338            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
339            glDeleteFramebuffersEXT(1, &fb);
340            if (fmt!=GL_NONE)
341                glDeleteTextures(1, &tid);
342        }
343
344        // It seems a bug in nVidia driver: glBindFramebufferEXT should restore
345        // draw and read buffers, but in some unclear circumstances it won't.
346        glDrawBuffer(old_drawbuffer);
347        glReadBuffer(old_readbuffer);
348
349        std::string fmtstring;
350        for(size_t x=0; x<PF_COUNT; ++x)
351        {
352            if(mProps[x].valid)
353                fmtstring += PixelUtil::getFormatName((PixelFormat)x)+" ";
354        }
355        LogManager::getSingleton().logMessage("[GL] : Valid FBO targets " + fmtstring);
356    }
357    void GLFBOManager::getBestDepthStencil(GLenum internalFormat, GLenum *depthFormat, GLenum *stencilFormat)
358    {
359        const FormatProperties &props = mProps[internalFormat];
360        /// Decide what stencil and depth formats to use
361        /// [best supported for internal format]
362        size_t bestmode=0;
363        int bestscore=-1;
364        for(size_t mode=0; mode<props.modes.size(); mode++)
365        {
366#if 0
367            /// Always prefer D24S8
368            if(stencilBits[props.modes[mode].stencil]==8 &&
369                depthBits[props.modes[mode].depth]==24)
370            {
371                bestmode = mode;
372                break;
373            }
374#endif
375            int desirability = 0;
376            /// Find most desirable mode
377            /// desirability == 0            if no depth, no stencil
378            /// desirability == 1000...2000  if no depth, stencil
379            /// desirability == 2000...3000  if depth, no stencil
380            /// desirability == 3000+        if depth and stencil
381            /// beyond this, the total numer of bits (stencil+depth) is maximised
382            if(props.modes[mode].stencil)
383                desirability += 1000;
384            if(props.modes[mode].depth)
385                desirability += 2000;
386            if(depthBits[props.modes[mode].depth]==24) // Prefer 24 bit for now
387                desirability += 500;
388                        if(depthFormats[props.modes[mode].depth]==GL_DEPTH24_STENCIL8_EXT) // Prefer 24/8 packed
389                                desirability += 5000;
390            desirability += stencilBits[props.modes[mode].stencil] + depthBits[props.modes[mode].depth];
391           
392            if(desirability>bestscore)
393            {
394                bestscore = desirability;
395                bestmode = mode;
396            }
397        }
398        *depthFormat = depthFormats[props.modes[bestmode].depth];
399        *stencilFormat = stencilFormats[props.modes[bestmode].stencil];
400    }
401
402    GLFBORenderTexture *GLFBOManager::createRenderTexture(const String &name, const GLSurfaceDesc &target)
403    {
404        GLFBORenderTexture *retval = new GLFBORenderTexture(this, name, target);
405        return retval;
406    }
407        MultiRenderTarget *GLFBOManager::createMultiRenderTarget(const String & name)
408        {
409                return new GLFBOMultiRenderTarget(this, name);
410        }
411
412    GLFrameBufferObject *GLFBOManager::createFrameBufferObject()
413    {
414        return new GLFrameBufferObject(this);
415    }
416
417    void GLFBOManager::destroyFrameBufferObject(GLFrameBufferObject * x)
418    {
419        delete x;
420    }
421    void GLFBOManager::bind(RenderTarget *target)
422    {
423        /// Check if the render target is in the rendertarget->FBO map
424        GLFrameBufferObject *fbo = 0;
425        target->getCustomAttribute("FBO", &fbo);
426        if(fbo)
427            fbo->bind();
428        else
429            // Old style context (window/pbuffer) or copying render texture
430            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
431    }
432   
433    GLSurfaceDesc GLFBOManager::requestRenderBuffer(GLenum format, size_t width, size_t height)
434    {
435        GLSurfaceDesc retval;
436        retval.buffer = 0; // Return 0 buffer if GL_NONE is requested
437        if(format != GL_NONE)
438        {
439            RBFormat key(format, width, height);
440            RenderBufferMap::iterator it = mRenderBufferMap.find(key);
441            if(it != mRenderBufferMap.end())
442            {
443                retval.buffer = it->second.buffer;
444                retval.zoffset = 0;
445                // Increase refcount
446                ++it->second.refcount;
447            }
448            else
449            {
450                // New one
451                GLRenderBuffer *rb = new GLRenderBuffer(format, width, height);
452                mRenderBufferMap[key] = RBRef(rb);
453                retval.buffer = rb;
454                retval.zoffset = 0;
455            }
456        }
457        //std::cerr << "Requested renderbuffer with format " << std::hex << format << std::dec << " of " << width << "x" << height << " :" << retval.buffer << std::endl;
458        return retval;
459    }
460    //-----------------------------------------------------------------------
461    void GLFBOManager::requestRenderBuffer(const GLSurfaceDesc &surface)
462    {
463        if(surface.buffer == 0)
464            return;
465        RBFormat key(surface.buffer->getGLFormat(), surface.buffer->getWidth(), surface.buffer->getHeight());
466        RenderBufferMap::iterator it = mRenderBufferMap.find(key);
467        assert(it != mRenderBufferMap.end());
468        if (it != mRenderBufferMap.end())   // Just in case
469        {
470            assert(it->second.buffer == surface.buffer);
471            // Increase refcount
472            ++it->second.refcount;
473        }
474    }
475    //-----------------------------------------------------------------------
476    void GLFBOManager::releaseRenderBuffer(const GLSurfaceDesc &surface)
477    {
478        if(surface.buffer == 0)
479            return;
480        RBFormat key(surface.buffer->getGLFormat(), surface.buffer->getWidth(), surface.buffer->getHeight());
481        RenderBufferMap::iterator it = mRenderBufferMap.find(key);
482        if(it != mRenderBufferMap.end())
483                {
484                        // Decrease refcount
485                        --it->second.refcount;
486                        if(it->second.refcount==0)
487                        {
488                                // If refcount reaches zero, delete buffer and remove from map
489                                delete it->second.buffer;
490                                mRenderBufferMap.erase(it);
491                                //std::cerr << "Destroyed renderbuffer of format " << std::hex << key.format << std::dec
492                                //        << " of " << key.width << "x" << key.height << std::endl;
493                        }
494                }
495    }
496}
Note: See TracBrowser for help on using the repository browser.