source: OGRE/trunk/ogrenew/RenderSystems/GL/src/OgreGLFBORenderTexture.cpp @ 692

Revision 692, 15.2 KB checked in by mattausch, 18 years ago (diff)

adding ogre 1.2 and dependencies

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-2005 The OGRE Team
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-----------------------------------------------------------------------------
24*/
25
26#include "OgreGLFBORenderTexture.h"
27#include "OgreGLPixelFormat.h"
28#include "OgreLogManager.h"
29#include "OgreStringConverter.h"
30#include "OgreRoot.h"
31#include "OgreGLHardwarePixelBuffer.h"
32#include "OgreGLFBOMultiRenderTarget.h"
33
34namespace Ogre {
35
36//-----------------------------------------------------------------------------   
37    GLFBORenderTexture::GLFBORenderTexture(GLFBOManager *manager, const String &name,
38        const GLSurfaceDesc &target):
39        GLRenderTexture(name, target),
40        mFB(manager)
41    {
42        // Bind target to surface 0 and initialise
43        mFB.bindSurface(0, target);
44        // Get attributes
45        mWidth = mFB.getWidth();
46        mHeight = mFB.getHeight();
47    }
48
49    void GLFBORenderTexture::getCustomAttribute(const String& name, void* pData)
50    {
51        if(name=="FBO")
52        {
53            *static_cast<GLFrameBufferObject **>(pData) = &mFB;
54        }
55    }
56   
57/// Size of probe texture
58#define PROBE_SIZE 256
59/// Stencil and depth formats to be tried
60GLenum stencilFormats[]={
61    GL_NONE,                    // No stencil
62    GL_STENCIL_INDEX1_EXT,
63    GL_STENCIL_INDEX4_EXT,
64    GL_STENCIL_INDEX8_EXT,
65    GL_STENCIL_INDEX16_EXT
66};
67size_t stencilBits[] = {
68    0, 1, 4, 8, 16
69};
70#define STENCILFORMAT_COUNT (sizeof(stencilFormats)/sizeof(GLenum))
71GLenum depthFormats[]={
72    GL_NONE,
73    GL_DEPTH_COMPONENT16,
74    GL_DEPTH_COMPONENT24,    // Prefer 24 bit depth
75    GL_DEPTH_COMPONENT32,
76    GL_DEPTH24_STENCIL8_EXT // packed depth / stencil
77};
78size_t depthBits[] = {
79    0,16,24,32,24
80};
81
82
83#define DEPTHFORMAT_COUNT (sizeof(depthFormats)/sizeof(GLenum))
84   
85        GLFBOManager::GLFBOManager(bool atimode):
86                mATIMode(atimode)
87    {
88        detectFBOFormats();
89       
90        glGenFramebuffersEXT(1, &mTempFBO);
91    }
92
93        GLFBOManager::~GLFBOManager()
94        {
95                if(!mRenderBufferMap.empty())
96                {
97                        LogManager::getSingleton().logMessage("GL: Warning! GLFBOManager destructor called, but not all renderbuffers were released.");
98                }
99       
100        glDeleteFramebuffersEXT(1, &mTempFBO);     
101        }
102
103    /** Try a certain FBO format, and return the status. Also sets mDepthRB and mStencilRB.
104        @returns true    if this combo is supported
105                 false   if this combo is not supported
106    */
107    GLuint GLFBOManager::_tryFormat(GLenum depthFormat, GLenum stencilFormat)
108    {
109        GLuint status, depthRB, stencilRB;
110        bool failed = false; // flag on GL errors
111
112        if(depthFormat != GL_NONE)
113        {
114            /// Generate depth renderbuffer
115            glGenRenderbuffersEXT(1, &depthRB);
116            /// Bind it to FBO
117            glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthRB);
118           
119            /// Allocate storage for depth buffer
120            glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, depthFormat,
121                                PROBE_SIZE, PROBE_SIZE);
122           
123            /// Attach depth
124            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
125                                    GL_RENDERBUFFER_EXT, depthRB);
126        }
127
128        if(stencilFormat != GL_NONE)
129        {
130            /// Generate stencil renderbuffer
131            glGenRenderbuffersEXT(1, &stencilRB);
132            /// Bind it to FBO
133            glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, stencilRB);
134            glGetError(); // NV hack
135            /// Allocate storage for stencil buffer
136            glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, stencilFormat,
137                                PROBE_SIZE, PROBE_SIZE);
138            if(glGetError() != GL_NO_ERROR) // NV hack
139                failed = true;
140            /// Attach stencil
141            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
142                            GL_RENDERBUFFER_EXT, stencilRB);
143            if(glGetError() != GL_NO_ERROR) // NV hack
144                failed = true;
145        }
146       
147        status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
148        /// If status is negative, clean up
149        // Detach and destroy
150        glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_NONE, 0);
151        glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_NONE, 0);
152        glDeleteRenderbuffersEXT(1, &depthRB);
153        glDeleteRenderbuffersEXT(1, &stencilRB);
154       
155        return status == GL_FRAMEBUFFER_COMPLETE_EXT && !failed;
156    }
157   
158    /** Detect which internal formats are allowed as RTT
159        Also detect what combinations of stencil and depth are allowed with this internal
160        format.
161    */
162    void GLFBOManager::detectFBOFormats()
163    {
164        // Try all formats, and report which ones work as target
165        GLuint fb, tid;
166        GLenum target = GL_TEXTURE_2D;
167       
168        for(size_t x=0; x<PF_COUNT; ++x)
169        {
170            mProps[x].valid = false;
171
172                        // Fetch GL format token
173                        GLenum fmt = GLPixelUtil::getGLInternalFormat((PixelFormat)x);
174            if(fmt == GL_NONE && x!=0)
175                continue;
176
177                        // No test for compressed formats
178                        if(PixelUtil::isCompressed((PixelFormat)x))
179                                continue;
180
181                        // Buggy ATI cards *crash* on non-RGB(A) formats
182                        int depths[4];
183                        PixelUtil::getBitDepths((PixelFormat)x, depths);
184                        if(fmt!=GL_NONE && mATIMode && (!depths[0] || !depths[1] || !depths[2]))
185                                continue;
186
187            // Create and attach framebuffer
188            glGenFramebuffersEXT(1, &fb);
189            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);
190            if(fmt!=GL_NONE)
191            {
192                                // Create and attach texture
193                                glGenTextures(1, &tid);
194                                glBindTexture(target, tid);
195                               
196                // Set some default parameters so it won't fail on NVidia cards         
197                glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, 0);
198                glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
199                glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
200                glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
201                glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
202                           
203                                glTexImage2D(target, 0, fmt, PROBE_SIZE, PROBE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
204                                glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
205                                target, tid, 0);
206            }
207                        else
208                        {
209                                // Draw to nowhere -- stencil/depth only
210                                tid = 0;
211                                glDrawBuffer(GL_NONE);
212                                glReadBuffer(GL_NONE);
213                        }
214            // Check status
215            GLuint status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
216
217                        // Ignore status in case of fmt==GL_NONE, because no implementation will accept
218                        // a buffer without *any* attachment. Buffers with only stencil and depth attachment
219                        // might still be supported, so we must continue probing.
220            if(fmt == GL_NONE || status == GL_FRAMEBUFFER_COMPLETE_EXT)
221            {
222                mProps[x].valid = true;
223                                StringUtil::StrStreamType str;
224                                str << "FBO " << PixelUtil::getFormatName((PixelFormat)x)
225                                        << " depth/stencil support: ";
226               
227                // Continue detection
228                size_t depth=0, stencil=0;
229                               
230                while(true)
231                {
232                                        //StringUtil::StrStreamType l;
233                                        //l << "Trying " << PixelUtil::getFormatName((PixelFormat)x)
234                                        //      << " D" << depthBits[depth]
235                                        //      << "S" << stencilBits[stencil];
236                                        //LogManager::getSingleton().logMessage(l.str());
237
238                                        // Only query packed depth/stencil formats for 32-bit
239                                        // non-floating point formats (ie not R32!)
240                                        // Linux nVidia driver segfaults if you query others
241                    if((depthFormats[depth] != GL_DEPTH24_STENCIL8_EXT ||
242                                                (PixelUtil::getNumElemBits((PixelFormat)x) == 32) &&
243                                                 !PixelUtil::isFloatingPoint((PixelFormat)x)) &&
244                                                _tryFormat(depthFormats[depth], stencilFormats[stencil]))
245                    {
246                        /// Add mode to allowed modes
247                        str << "D" << depthBits[depth] << "S" <<
248                                                        (depthFormats[depth] == GL_DEPTH24_STENCIL8_EXT ? 8 : stencilBits[stencil])
249                                                        << " ";
250                        FormatProperties::Mode mode;
251                        mode.depth = depth;
252                        mode.stencil = stencil;
253                        mProps[x].modes.push_back(mode);
254                    }
255                    /// Try next combo
256                    stencil++;
257                    if(stencil == STENCILFORMAT_COUNT)
258                    {
259                        stencil = 0;
260                        depth ++;
261                        if(depth == DEPTHFORMAT_COUNT)
262                        {
263                            // We're done
264                            break;
265                        }
266                    }
267                }
268                                LogManager::getSingleton().logMessage(str.str());
269
270            }
271            // Delete texture and framebuffer
272            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
273            glDeleteFramebuffersEXT(1, &fb);
274            glDeleteTextures(1, &tid);
275        }
276       
277        std::string fmtstring;
278        for(size_t x=0; x<PF_COUNT; ++x)
279        {
280            if(mProps[x].valid)
281                fmtstring += PixelUtil::getFormatName((PixelFormat)x)+" ";
282        }
283        LogManager::getSingleton().logMessage("[GL] : Valid FBO targets " + fmtstring);
284    }
285    void GLFBOManager::getBestDepthStencil(GLenum internalFormat, GLenum *depthFormat, GLenum *stencilFormat)
286    {
287        const FormatProperties &props = mProps[internalFormat];
288        /// Decide what stencil and depth formats to use
289        /// [best supported for internal format]
290        size_t bestmode=0;
291        int bestscore=-1;
292        for(size_t mode=0; mode<props.modes.size(); mode++)
293        {
294#if 0
295            /// Always prefer D24S8
296            if(stencilBits[props.modes[mode].stencil]==8 &&
297                depthBits[props.modes[mode].depth]==24)
298            {
299                bestmode = mode;
300                break;
301            }
302#endif
303            int desirability = 0;
304            /// Find most desirable mode
305            /// desirability == 0            if no depth, no stencil
306            /// desirability == 1000...2000  if no depth, stencil
307            /// desirability == 2000...3000  if depth, no stencil
308            /// desirability == 3000+        if depth and stencil
309            /// beyond this, the total numer of bits (stencil+depth) is maximised
310            if(props.modes[mode].stencil)
311                desirability += 1000;
312            if(props.modes[mode].depth)
313                desirability += 2000;
314            if(depthBits[props.modes[mode].depth]==24) // Prefer 24 bit for now
315                desirability += 500;
316                        if(depthFormats[props.modes[mode].depth]==GL_DEPTH24_STENCIL8_EXT) // Prefer 24/8 packed
317                                desirability += 5000;
318            desirability += stencilBits[props.modes[mode].stencil] + depthBits[props.modes[mode].depth];
319           
320            if(desirability>bestscore)
321            {
322                bestscore = desirability;
323                bestmode = mode;
324            }
325        }
326        *depthFormat = depthFormats[props.modes[bestmode].depth];
327        *stencilFormat = stencilFormats[props.modes[bestmode].stencil];
328    }
329
330    GLFBORenderTexture *GLFBOManager::createRenderTexture(const String &name, const GLSurfaceDesc &target)
331    {
332        GLFBORenderTexture *retval = new GLFBORenderTexture(this, name, target);
333        return retval;
334    }
335        MultiRenderTarget *GLFBOManager::createMultiRenderTarget(const String & name)
336        {
337                return new GLFBOMultiRenderTarget(this, name);
338        }
339
340    GLFrameBufferObject *GLFBOManager::createFrameBufferObject()
341    {
342        return new GLFrameBufferObject(this);
343    }
344
345    void GLFBOManager::destroyFrameBufferObject(GLFrameBufferObject * x)
346    {
347        delete x;
348    }
349    void GLFBOManager::bind(RenderTarget *target)
350    {
351        /// Check if the render target is in the rendertarget->FBO map
352        GLFrameBufferObject *fbo = 0;
353        target->getCustomAttribute("FBO", &fbo);
354        if(fbo)
355            fbo->bind();
356        else
357            // Old style context (window/pbuffer) or copying render texture
358            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
359    }
360   
361    GLSurfaceDesc GLFBOManager::requestRenderBuffer(GLenum format, size_t width, size_t height)
362    {
363        GLSurfaceDesc retval;
364        retval.buffer = 0; // Return 0 buffer if GL_NONE is requested
365        if(format != GL_NONE)
366        {
367            RBFormat key(format, width, height);
368            RenderBufferMap::iterator it = mRenderBufferMap.find(key);
369            if(it != mRenderBufferMap.end())
370            {
371                retval.buffer = it->second.buffer;
372                retval.zoffset = 0;
373                // Increase refcount
374                ++it->second.refcount;
375            }
376            else
377            {
378                // New one
379                GLRenderBuffer *rb = new GLRenderBuffer(format, width, height);
380                mRenderBufferMap[key] = RBRef(rb);
381                retval.buffer = rb;
382                retval.zoffset = 0;
383            }
384        }
385        //std::cerr << "Requested renderbuffer with format " << std::hex << format << std::dec << " of " << width << "x" << height << " :" << retval.buffer << std::endl;
386        return retval;
387    }
388    void GLFBOManager::releaseRenderBuffer(const GLSurfaceDesc &surface)
389    {
390        if(surface.buffer == 0)
391            return;
392        RBFormat key(surface.buffer->getGLFormat(), surface.buffer->getWidth(), surface.buffer->getHeight());
393        RenderBufferMap::iterator it = mRenderBufferMap.find(key);
394        if(it != mRenderBufferMap.end())
395                {
396                        // Decrease refcount
397                        --it->second.refcount;
398                        if(it->second.refcount==0)
399                        {
400                                // If refcount reaches zero, delete buffer and remove from map
401                                delete it->second.buffer;
402                                mRenderBufferMap.erase(it);
403                                //std::cerr << "Destroyed renderbuffer of format " << std::hex << key.format << std::dec
404                                //        << " of " << key.width << "x" << key.height << std::endl;
405                        }
406                }
407    }
408}
Note: See TracBrowser for help on using the repository browser.