root/OpenSceneGraph/trunk/src/osg/FrameBufferObject.cpp @ 13041

Revision 13041, 30.2 kB (checked in by robert, 3 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14// initial FBO support written by Marco Jez, June 2005.
15
16#include <osg/FrameBufferObject>
17#include <osg/State>
18#include <osg/GLExtensions>
19#include <osg/Texture1D>
20#include <osg/Texture2D>
21#include <osg/Texture2DMultisample>
22#include <osg/Texture3D>
23#include <osg/Texture2DArray>
24#include <osg/TextureCubeMap>
25#include <osg/TextureRectangle>
26#include <osg/Notify>
27#include <osg/Timer>
28
29using namespace osg;
30
31static buffered_object< ref_ptr<FBOExtensions> > s_extensions;
32
33FBOExtensions* FBOExtensions::instance(unsigned contextID, bool createIfNotInitalized)
34{
35    if (!s_extensions[contextID] && createIfNotInitalized) s_extensions[contextID] = new FBOExtensions(contextID);
36    return s_extensions[contextID].get();
37}
38
39/**************************************************************************
40 * FBOExtensions
41 **************************************************************************/
42#if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE)
43    #if defined(OSG_GLES1_AVAILABLE)
44        #define LOAD_FBO_EXT(name) setGLExtensionFuncPtr(name, (#name), (std::string(#name)+std::string("OES") ).c_str() )
45    #else
46        #define LOAD_FBO_EXT(name) setGLExtensionFuncPtr(name, (#name), std::string(#name).c_str() )
47    #endif
48#else
49    #define LOAD_FBO_EXT(name) setGLExtensionFuncPtr(name, (#name), (std::string(#name)+std::string("EXT") ).c_str() )
50#endif
51
52FBOExtensions::FBOExtensions(unsigned int contextID)
53:   glBindRenderbuffer(0),
54    glGenRenderbuffers(0),
55    glDeleteRenderbuffers(0),
56    glRenderbufferStorage(0),
57    glRenderbufferStorageMultisample(0),
58    glRenderbufferStorageMultisampleCoverageNV(0),
59    glBindFramebuffer(0),
60    glDeleteFramebuffers(0),
61    glGenFramebuffers(0),
62    glCheckFramebufferStatus(0),
63    glFramebufferTexture1D(0),
64    glFramebufferTexture2D(0),
65    glFramebufferTexture3D(0),
66    glFramebufferTexture(0),
67    glFramebufferTextureLayer(0),
68    glFramebufferRenderbuffer(0),
69    glGenerateMipmap(0),
70    glBlitFramebuffer(0),
71    _supported(false),
72    _packed_depth_stencil_supported(false)
73{
74    LOAD_FBO_EXT(glBindRenderbuffer);
75    LOAD_FBO_EXT(glGenRenderbuffers);
76    LOAD_FBO_EXT(glDeleteRenderbuffers);
77    LOAD_FBO_EXT(glRenderbufferStorage);
78    LOAD_FBO_EXT(glBindFramebuffer);
79    LOAD_FBO_EXT(glDeleteFramebuffers);
80    LOAD_FBO_EXT(glGenFramebuffers);
81    LOAD_FBO_EXT(glCheckFramebufferStatus);
82    LOAD_FBO_EXT(glFramebufferTexture1D);
83    LOAD_FBO_EXT(glFramebufferTexture2D);
84    LOAD_FBO_EXT(glFramebufferTexture3D);
85    LOAD_FBO_EXT(glFramebufferTexture);
86    LOAD_FBO_EXT(glFramebufferTextureLayer);
87    LOAD_FBO_EXT(glFramebufferRenderbuffer);
88    LOAD_FBO_EXT(glGenerateMipmap);
89    LOAD_FBO_EXT(glGetRenderbufferParameteriv);
90
91    _supported =
92        glBindRenderbuffer != 0 &&
93        glDeleteRenderbuffers != 0 &&
94        glGenRenderbuffers != 0 &&
95        glRenderbufferStorage != 0 &&
96        glBindFramebuffer != 0 &&
97        glDeleteFramebuffers != 0 &&
98        glGenFramebuffers != 0 &&
99        glCheckFramebufferStatus != 0 &&
100        glFramebufferTexture2D != 0 &&
101        glFramebufferRenderbuffer != 0 &&
102        glGenerateMipmap != 0 &&
103        glGetRenderbufferParameteriv != 0;
104
105#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE)
106    _supported = _supported &&
107        glFramebufferTexture1D != 0 &&
108        glFramebufferTexture3D != 0;
109#endif
110
111    LOAD_FBO_EXT(glBlitFramebuffer);
112    LOAD_FBO_EXT(glRenderbufferStorageMultisample);
113    LOAD_FBO_EXT(glRenderbufferStorageMultisampleCoverageNV);
114
115    _packed_depth_stencil_supported = OSG_GL3_FEATURES ||
116        (isGLExtensionSupported(contextID, "GL_EXT_packed_depth_stencil"));
117}
118
119
120/**************************************************************************
121 * RenderBuffer
122 **************************************************************************/
123
124///////////////////////////////////////////////////////////////////////////
125// static cache of glRenderbuffers flagged for deletion, which will actually
126// be deleted in the correct GL context.
127
128typedef std::list<GLuint> RenderBufferHandleList;
129typedef osg::buffered_object<RenderBufferHandleList> DeletedRenderBufferCache;
130
131static OpenThreads::Mutex    s_mutex_deletedRenderBufferCache;
132static DeletedRenderBufferCache s_deletedRenderBufferCache;
133
134void RenderBuffer::deleteRenderBuffer(unsigned int contextID, GLuint rb)
135{
136    if( rb )
137    {
138        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedRenderBufferCache);
139
140        // add glProgram to the cache for the appropriate context.
141        s_deletedRenderBufferCache[contextID].push_back(rb);
142    }
143}
144
145void RenderBuffer::flushDeletedRenderBuffers(unsigned int contextID,double /*currentTime*/, double& availableTime)
146{
147    // if no time available don't try to flush objects.
148    if (availableTime<=0.0) return;
149
150    const FBOExtensions* extensions = FBOExtensions::instance(contextID,true);
151    if(!extensions || !extensions->isSupported() ) return;
152
153    const osg::Timer& timer = *osg::Timer::instance();
154    osg::Timer_t start_tick = timer.tick();
155    double elapsedTime = 0.0;
156
157    {
158        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedRenderBufferCache);
159
160        RenderBufferHandleList& pList = s_deletedRenderBufferCache[contextID];
161        for(RenderBufferHandleList::iterator titr=pList.begin();
162            titr!=pList.end() && elapsedTime<availableTime;
163            )
164        {
165            extensions->glDeleteRenderbuffers(1, &(*titr) );
166            titr = pList.erase( titr );
167            elapsedTime = timer.delta_s(start_tick,timer.tick());
168        }
169    }
170
171    availableTime -= elapsedTime;
172}
173
174void RenderBuffer::discardDeletedRenderBuffers(unsigned int contextID)
175{
176    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedRenderBufferCache);
177    RenderBufferHandleList& pList = s_deletedRenderBufferCache[contextID];
178    pList.clear();
179}
180
181
182RenderBuffer::RenderBuffer()
183:    Object(),
184    _internalFormat(GL_DEPTH_COMPONENT24),
185    _width(512),
186    _height(512),
187    _samples(0),
188    _colorSamples(0)
189{
190}
191
192RenderBuffer::RenderBuffer(int width, int height, GLenum internalFormat, int samples, int colorSamples)
193:    Object(),
194    _internalFormat(internalFormat),
195    _width(width),
196    _height(height),
197    _samples(samples),
198    _colorSamples(colorSamples)
199{
200}
201
202RenderBuffer::RenderBuffer(const RenderBuffer &copy, const CopyOp &copyop)
203:    Object(copy, copyop),
204    _internalFormat(copy._internalFormat),
205    _width(copy._width),
206    _height(copy._height),
207    _samples(copy._samples),
208    _colorSamples(copy._colorSamples)
209{
210}
211
212RenderBuffer::~RenderBuffer()
213{
214    for(unsigned i=0; i<_objectID.size(); ++i)
215    {
216        if (_objectID[i]) deleteRenderBuffer(i, _objectID[i]);
217    }
218}
219
220int RenderBuffer::getMaxSamples(unsigned int contextID, const FBOExtensions *ext)
221{
222    static osg::buffered_value<GLint> maxSamplesList;
223
224    GLint& maxSamples = maxSamplesList[contextID];
225
226    if (!maxSamples && ext->isMultisampleSupported())
227    {
228        glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSamples);
229    }
230
231    return maxSamples;
232}
233
234GLuint RenderBuffer::getObjectID(unsigned int contextID, const FBOExtensions *ext) const
235{
236    GLuint &objectID = _objectID[contextID];
237
238    int &dirty = _dirty[contextID];
239
240    if (objectID == 0)
241    {
242        ext->glGenRenderbuffers(1, &objectID);
243        if (objectID == 0)
244            return 0;
245        dirty = 1;
246    }
247
248    if (dirty)
249    {
250        // bind and configure
251        ext->glBindRenderbuffer(GL_RENDERBUFFER_EXT, objectID);
252
253        // framebuffer_multisample_coverage specification requires that coverage
254        // samples must be >= color samples.
255        if (_samples < _colorSamples)
256        {
257            OSG_WARN << "Coverage samples must be greater than or equal to color samples."
258                " Setting coverage samples equal to color samples." << std::endl;
259            const_cast<RenderBuffer*>(this)->setSamples(_colorSamples);
260        }
261
262        if (_samples > 0 && ext->isMultisampleCoverageSupported())
263        {
264            int samples = minimum(_samples, getMaxSamples(contextID, ext));
265            int colorSamples = minimum(_colorSamples, samples);
266
267            ext->glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT,
268                samples, colorSamples, _internalFormat, _width, _height);
269        }
270        else if (_samples > 0 && ext->isMultisampleSupported())
271        {
272            int samples = minimum(_samples, getMaxSamples(contextID, ext));
273
274            ext->glRenderbufferStorageMultisample(GL_RENDERBUFFER_EXT,
275                samples, _internalFormat, _width, _height);
276        }
277        else
278        {
279            ext->glRenderbufferStorage(GL_RENDERBUFFER_EXT, _internalFormat, _width, _height);
280        }
281        dirty = 0;
282    }
283
284    return objectID;
285}
286
287void RenderBuffer::resizeGLObjectBuffers(unsigned int maxSize)
288{
289    _objectID.resize(maxSize);
290    _dirty.resize(maxSize);
291}
292
293void RenderBuffer::releaseGLObjects(osg::State* state) const
294{
295    if (state)
296    {
297        unsigned int contextID = state->getContextID();
298        if (_objectID[contextID])
299        {
300            deleteRenderBuffer(contextID, _objectID[contextID]);
301            _objectID[contextID] = 0;
302        }
303    }
304    else
305    {
306        for(unsigned i=0; i<_objectID.size(); ++i)
307        {
308            if (_objectID[i])
309            {
310                deleteRenderBuffer(i, _objectID[i]);
311                _objectID[i] = 0;
312            }
313        }
314    }
315}
316
317/**************************************************************************
318 * FrameBufferAttachment
319 **************************************************************************/
320
321#ifndef GL_TEXTURE_CUBE_MAP_POSITIVE_X
322#define GL_TEXTURE_CUBE_MAP_POSITIVE_X  0x8515
323#endif
324
325struct FrameBufferAttachment::Pimpl
326{
327    enum TargetType
328    {
329        RENDERBUFFER,
330        TEXTURE1D,
331        TEXTURE2D,
332        TEXTURE3D,
333        TEXTURECUBE,
334        TEXTURERECT,
335        TEXTURE2DARRAY,
336        TEXTURE2DMULTISAMPLE
337    };
338
339    TargetType targetType;
340    ref_ptr<RenderBuffer> renderbufferTarget;
341    ref_ptr<Texture> textureTarget;
342    unsigned int cubeMapFace;
343    unsigned int level;
344    unsigned int zoffset;
345
346    explicit Pimpl(TargetType ttype = RENDERBUFFER, unsigned int lev = 0)
347    :    targetType(ttype),
348        cubeMapFace(0),
349        level(lev),
350        zoffset(0)
351    {
352    }
353
354    Pimpl(const Pimpl &copy)
355    :    targetType(copy.targetType),
356        renderbufferTarget(copy.renderbufferTarget),
357        textureTarget(copy.textureTarget),
358        cubeMapFace(copy.cubeMapFace),
359        level(copy.level),
360        zoffset(copy.zoffset)
361    {
362    }
363};
364
365FrameBufferAttachment::FrameBufferAttachment()
366{
367    _ximpl = new Pimpl;
368}
369
370FrameBufferAttachment::FrameBufferAttachment(const FrameBufferAttachment &copy)
371{
372    _ximpl = new Pimpl(*copy._ximpl);
373}
374
375FrameBufferAttachment::FrameBufferAttachment(RenderBuffer* target)
376{
377    _ximpl = new Pimpl(Pimpl::RENDERBUFFER);
378    _ximpl->renderbufferTarget = target;
379}
380
381FrameBufferAttachment::FrameBufferAttachment(Texture1D* target, unsigned int level)
382{
383    _ximpl = new Pimpl(Pimpl::TEXTURE1D, level);
384    _ximpl->textureTarget = target;
385}
386
387FrameBufferAttachment::FrameBufferAttachment(Texture2D* target, unsigned int level)
388{
389    _ximpl = new Pimpl(Pimpl::TEXTURE2D, level);
390    _ximpl->textureTarget = target;
391}
392
393FrameBufferAttachment::FrameBufferAttachment(Texture2DMultisample* target, unsigned int level)
394{
395    _ximpl = new Pimpl(Pimpl::TEXTURE2DMULTISAMPLE, level);
396    _ximpl->textureTarget = target;
397}
398
399FrameBufferAttachment::FrameBufferAttachment(Texture3D* target, unsigned int zoffset, unsigned int level)
400{
401    _ximpl = new Pimpl(Pimpl::TEXTURE3D, level);
402    _ximpl->textureTarget = target;
403    _ximpl->zoffset = zoffset;
404}
405
406FrameBufferAttachment::FrameBufferAttachment(Texture2DArray* target, unsigned int layer, unsigned int level)
407{
408    _ximpl = new Pimpl(Pimpl::TEXTURE2DARRAY, level);
409    _ximpl->textureTarget = target;
410    _ximpl->zoffset = layer;
411}
412
413FrameBufferAttachment::FrameBufferAttachment(TextureCubeMap* target, unsigned int face, unsigned int level)
414{
415    _ximpl = new Pimpl(Pimpl::TEXTURECUBE, level);
416    _ximpl->textureTarget = target;
417    _ximpl->cubeMapFace = face;
418}
419
420FrameBufferAttachment::FrameBufferAttachment(TextureRectangle* target)
421{
422    _ximpl = new Pimpl(Pimpl::TEXTURERECT);
423    _ximpl->textureTarget = target;
424}
425
426FrameBufferAttachment::FrameBufferAttachment(Camera::Attachment& attachment)
427{
428    osg::Texture* texture = attachment._texture.get();
429
430    if (texture)
431    {
432        osg::Texture1D* texture1D = dynamic_cast<osg::Texture1D*>(texture);
433        if (texture1D)
434        {
435            _ximpl = new Pimpl(Pimpl::TEXTURE1D, attachment._level);
436            _ximpl->textureTarget = texture1D;
437            return;
438        }
439
440        osg::Texture2D* texture2D = dynamic_cast<osg::Texture2D*>(texture);
441        if (texture2D)
442        {
443            _ximpl = new Pimpl(Pimpl::TEXTURE2D, attachment._level);
444            _ximpl->textureTarget = texture2D;
445            return;
446        }
447
448        osg::Texture2DMultisample* texture2DMS = dynamic_cast<osg::Texture2DMultisample*>(texture);
449        if (texture2DMS)
450        {
451            _ximpl = new Pimpl(Pimpl::TEXTURE2DMULTISAMPLE, attachment._level);
452            _ximpl->textureTarget = texture2DMS;
453            return;
454        }
455
456        osg::Texture3D* texture3D = dynamic_cast<osg::Texture3D*>(texture);
457        if (texture3D)
458        {
459            _ximpl = new Pimpl(Pimpl::TEXTURE3D, attachment._level);
460            _ximpl->textureTarget = texture3D;
461            _ximpl->zoffset = attachment._face;
462            return;
463        }
464
465        osg::Texture2DArray* texture2DArray = dynamic_cast<osg::Texture2DArray*>(texture);
466        if (texture2DArray)
467        {
468            _ximpl = new Pimpl(Pimpl::TEXTURE2DARRAY, attachment._level);
469            _ximpl->textureTarget = texture2DArray;
470            _ximpl->zoffset = attachment._face;
471            return;
472        }
473
474        osg::TextureCubeMap* textureCubeMap = dynamic_cast<osg::TextureCubeMap*>(texture);
475        if (textureCubeMap)
476        {
477            _ximpl = new Pimpl(Pimpl::TEXTURECUBE, attachment._level);
478            _ximpl->textureTarget = textureCubeMap;
479            _ximpl->cubeMapFace = attachment._face;
480            return;
481        }
482
483        osg::TextureRectangle* textureRectangle = dynamic_cast<osg::TextureRectangle*>(texture);
484        if (textureRectangle)
485        {
486            _ximpl = new Pimpl(Pimpl::TEXTURERECT);
487            _ximpl->textureTarget = textureRectangle;
488            return;
489        }
490    }
491
492    osg::Image* image = attachment._image.get();
493    if (image)
494    {
495        if (image->s()>0 && image->t()>0)
496        {
497            GLenum format = attachment._image->getInternalTextureFormat();
498            if (format == 0)
499                format = attachment._internalFormat;
500            _ximpl = new Pimpl(Pimpl::RENDERBUFFER);
501            _ximpl->renderbufferTarget = new osg::RenderBuffer(image->s(), image->t(), format);
502            return;
503        }
504        else
505        {
506            OSG_WARN<<"Error: FrameBufferAttachment::FrameBufferAttachment(Camera::Attachment&) passed an empty osg::Image, image must be allocated first."<<std::endl;
507        }
508    }
509    else
510    {
511        OSG_WARN<<"Error: FrameBufferAttachment::FrameBufferAttachment(Camera::Attachment&) passed an unrecognised Texture type."<<std::endl;
512    }
513
514    // provide all fallback
515    _ximpl = new Pimpl();
516}
517
518
519FrameBufferAttachment::~FrameBufferAttachment()
520{
521    delete _ximpl;
522}
523
524FrameBufferAttachment &FrameBufferAttachment::operator = (const FrameBufferAttachment &copy)
525{
526    delete _ximpl;
527    _ximpl = new Pimpl(*copy._ximpl);
528    return *this;
529}
530
531bool FrameBufferAttachment::isMultisample() const
532{
533    if (_ximpl->renderbufferTarget.valid())
534    {
535        return _ximpl->renderbufferTarget->getSamples() > 0;
536    }
537
538    return false;
539}
540
541void FrameBufferAttachment::createRequiredTexturesAndApplyGenerateMipMap(State &state, const FBOExtensions* ext) const
542{
543    unsigned int contextID = state.getContextID();
544
545    // force compile texture if necessary
546    Texture::TextureObject *tobj = 0;
547    if (_ximpl->textureTarget.valid())
548    {
549        tobj = _ximpl->textureTarget->getTextureObject(contextID);
550        if (!tobj || tobj->id() == 0)
551        {
552            _ximpl->textureTarget->compileGLObjects(state);
553            tobj = _ximpl->textureTarget->getTextureObject(contextID);
554        }
555        if (!tobj || tobj->id() == 0)
556            return;
557
558        Texture::FilterMode minFilter = _ximpl->textureTarget->getFilter(Texture::MIN_FILTER);
559        if (minFilter==Texture::LINEAR_MIPMAP_LINEAR ||
560            minFilter==Texture::LINEAR_MIPMAP_NEAREST ||
561            minFilter==Texture::NEAREST_MIPMAP_LINEAR ||
562            minFilter==Texture::NEAREST_MIPMAP_NEAREST)
563        {
564            state.setActiveTextureUnit(0);
565            state.applyTextureAttribute(0, _ximpl->textureTarget.get());
566            ext->glGenerateMipmap(_ximpl->textureTarget->getTextureTarget());
567        }
568
569    }
570}
571
572void FrameBufferAttachment::attach(State &state, GLenum target, GLenum attachment_point, const FBOExtensions* ext) const
573{
574    unsigned int contextID = state.getContextID();
575
576    Texture::TextureObject *tobj = 0;
577    if (_ximpl->textureTarget.valid())
578    {
579        tobj = _ximpl->textureTarget->getTextureObject(contextID);
580        if (!tobj || tobj->id() == 0)
581        {
582            _ximpl->textureTarget->compileGLObjects(state);
583            tobj = _ximpl->textureTarget->getTextureObject(contextID);
584
585        }
586        if (!tobj || tobj->id() == 0)
587            return;
588    }
589
590    switch (_ximpl->targetType)
591    {
592    default:
593    case Pimpl::RENDERBUFFER:
594        ext->glFramebufferRenderbuffer(target, attachment_point, GL_RENDERBUFFER_EXT, _ximpl->renderbufferTarget->getObjectID(contextID, ext));
595        break;
596    case Pimpl::TEXTURE1D:
597        ext->glFramebufferTexture1D(target, attachment_point, GL_TEXTURE_1D, tobj->id(), _ximpl->level);
598        break;
599    case Pimpl::TEXTURE2D:
600        ext->glFramebufferTexture2D(target, attachment_point, GL_TEXTURE_2D, tobj->id(), _ximpl->level);
601        break;
602    case Pimpl::TEXTURE2DMULTISAMPLE:
603        ext->glFramebufferTexture2D(target, attachment_point, GL_TEXTURE_2D_MULTISAMPLE, tobj->id(), _ximpl->level);
604        break;
605    case Pimpl::TEXTURE3D:
606        if (_ximpl->zoffset == Camera::FACE_CONTROLLED_BY_GEOMETRY_SHADER)
607        {
608            if (ext->glFramebufferTexture)
609            {
610                ext->glFramebufferTexture(target, attachment_point, tobj->id(), _ximpl->level);
611            }
612        }
613        else
614            ext->glFramebufferTexture3D(target, attachment_point, GL_TEXTURE_3D, tobj->id(), _ximpl->level, _ximpl->zoffset);
615        break;
616    case Pimpl::TEXTURE2DARRAY:
617        if (_ximpl->zoffset == Camera::FACE_CONTROLLED_BY_GEOMETRY_SHADER)
618        {
619            if (ext->glFramebufferTexture)
620            {
621                ext->glFramebufferTexture(target, attachment_point, tobj->id(), _ximpl->level);
622            }
623        }
624        else
625            ext->glFramebufferTextureLayer(target, attachment_point, tobj->id(), _ximpl->level, _ximpl->zoffset);
626        break;
627    case Pimpl::TEXTURERECT:
628        ext->glFramebufferTexture2D(target, attachment_point, GL_TEXTURE_RECTANGLE, tobj->id(), 0);
629        break;
630    case Pimpl::TEXTURECUBE:
631        if (_ximpl->cubeMapFace == Camera::FACE_CONTROLLED_BY_GEOMETRY_SHADER)
632        {
633            if (ext->glFramebufferTexture)
634            {
635                ext->glFramebufferTexture(target, attachment_point, tobj->id(), _ximpl->level);
636            }
637        }
638        else
639            ext->glFramebufferTexture2D(target, attachment_point, GL_TEXTURE_CUBE_MAP_POSITIVE_X + _ximpl->cubeMapFace, tobj->id(), _ximpl->level);
640        break;
641    }
642}
643
644int FrameBufferAttachment::compare(const FrameBufferAttachment &fa) const
645{
646    if (&fa == this) return 0;
647    if (_ximpl->targetType < fa._ximpl->targetType) return -1;
648    if (_ximpl->targetType > fa._ximpl->targetType) return 1;
649    if (_ximpl->renderbufferTarget.get() < fa._ximpl->renderbufferTarget.get()) return -1;
650    if (_ximpl->renderbufferTarget.get() > fa._ximpl->renderbufferTarget.get()) return 1;
651    if (_ximpl->textureTarget.get() < fa._ximpl->textureTarget.get()) return -1;
652    if (_ximpl->textureTarget.get() > fa._ximpl->textureTarget.get()) return 1;
653    if (_ximpl->cubeMapFace < fa._ximpl->cubeMapFace) return -1;
654    if (_ximpl->cubeMapFace > fa._ximpl->cubeMapFace) return 1;
655    if (_ximpl->level < fa._ximpl->level) return -1;
656    if (_ximpl->level > fa._ximpl->level) return 1;
657    if (_ximpl->zoffset < fa._ximpl->zoffset) return -1;
658    if (_ximpl->zoffset > fa._ximpl->zoffset) return 1;
659    return 0;
660}
661
662RenderBuffer* FrameBufferAttachment::getRenderBuffer()
663{
664    return _ximpl->renderbufferTarget.get();
665}
666
667Texture* FrameBufferAttachment::getTexture()
668{
669    return _ximpl->textureTarget.get();
670}
671
672const RenderBuffer* FrameBufferAttachment::getRenderBuffer() const
673{
674    return _ximpl->renderbufferTarget.get();
675}
676
677const Texture* FrameBufferAttachment::getTexture() const
678{
679    return _ximpl->textureTarget.get();
680}
681
682unsigned int FrameBufferAttachment::getCubeMapFace() const
683{
684    return _ximpl->cubeMapFace;
685}
686
687unsigned int FrameBufferAttachment::getTextureLevel() const
688{
689    return _ximpl->level;
690}
691
692unsigned int FrameBufferAttachment::getTexture3DZOffset() const
693{
694    return _ximpl->zoffset;
695}
696
697unsigned int FrameBufferAttachment::getTextureArrayLayer() const
698{
699    return _ximpl->zoffset;
700}
701
702/**************************************************************************
703 * FrameBufferObject
704 **************************************************************************/
705
706///////////////////////////////////////////////////////////////////////////
707// static cache of glRenderbuffers flagged for deletion, which will actually
708// be deleted in the correct GL context.
709
710typedef std::list<GLuint> FrameBufferObjectHandleList;
711typedef osg::buffered_object<FrameBufferObjectHandleList> DeletedFrameBufferObjectCache;
712
713static OpenThreads::Mutex    s_mutex_deletedFrameBufferObjectCache;
714static DeletedFrameBufferObjectCache s_deletedFrameBufferObjectCache;
715
716void FrameBufferObject::deleteFrameBufferObject(unsigned int contextID, GLuint rb)
717{
718    if( rb )
719    {
720        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedFrameBufferObjectCache);
721
722        // add glProgram to the cache for the appropriate context.
723        s_deletedFrameBufferObjectCache[contextID].push_back(rb);
724    }
725}
726
727void FrameBufferObject::flushDeletedFrameBufferObjects(unsigned int contextID,double /*currentTime*/, double& availableTime)
728{
729    // if no time available don't try to flush objects.
730    if (availableTime<=0.0) return;
731
732    const FBOExtensions* extensions = FBOExtensions::instance(contextID,true);
733    if(!extensions || !extensions->isSupported() ) return;
734
735    const osg::Timer& timer = *osg::Timer::instance();
736    osg::Timer_t start_tick = timer.tick();
737    double elapsedTime = 0.0;
738
739    {
740        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedFrameBufferObjectCache);
741
742        FrameBufferObjectHandleList& pList = s_deletedFrameBufferObjectCache[contextID];
743        for(FrameBufferObjectHandleList::iterator titr=pList.begin();
744            titr!=pList.end() && elapsedTime<availableTime;
745            )
746        {
747            extensions->glDeleteFramebuffers(1, &(*titr) );
748            titr = pList.erase( titr );
749            elapsedTime = timer.delta_s(start_tick,timer.tick());
750        }
751    }
752
753    availableTime -= elapsedTime;
754}
755
756void FrameBufferObject::discardDeletedFrameBufferObjects(unsigned int contextID)
757{
758    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedFrameBufferObjectCache);
759    FrameBufferObjectHandleList& pList = s_deletedFrameBufferObjectCache[contextID];
760
761    pList.clear();
762}
763
764
765
766FrameBufferObject::FrameBufferObject()
767:    StateAttribute()
768{
769}
770
771FrameBufferObject::FrameBufferObject(const FrameBufferObject &copy, const CopyOp &copyop)
772:    StateAttribute(copy, copyop),
773    _attachments(copy._attachments),
774    _drawBuffers(copy._drawBuffers)
775{
776}
777
778FrameBufferObject::~FrameBufferObject()
779{
780    for(unsigned i=0; i<_fboID.size(); ++i)
781    {
782        if (_fboID[i]) deleteFrameBufferObject(i, _fboID[i]);
783    }
784}
785
786void FrameBufferObject::resizeGLObjectBuffers(unsigned int maxSize)
787{
788    _fboID.resize(maxSize);
789    _unsupported.resize(maxSize);
790    _fboID.resize(maxSize);
791}
792
793void FrameBufferObject::releaseGLObjects(osg::State* state) const
794{
795    if (state)
796    {
797        unsigned int contextID = state->getContextID();
798        if (_fboID[contextID])
799        {
800            deleteFrameBufferObject(contextID, _fboID[contextID]);
801            _fboID[contextID] = 0;
802        }
803    }
804    else
805    {
806        for(unsigned int i=0; i<_fboID.size(); ++i)
807        {
808            if (_fboID[i])
809            {
810                deleteFrameBufferObject(i, _fboID[i]);
811                _fboID[i] = 0;
812            }
813        }
814    }
815}
816
817void FrameBufferObject::setAttachment(BufferComponent attachment_point, const FrameBufferAttachment &attachment)
818{
819    _attachments[attachment_point] = attachment;
820
821    updateDrawBuffers();
822    dirtyAll();
823}
824
825
826GLenum FrameBufferObject::convertBufferComponentToGLenum(BufferComponent attachment_point) const
827{
828    switch(attachment_point)
829    {
830        case(Camera::DEPTH_BUFFER): return GL_DEPTH_ATTACHMENT_EXT;
831        case(Camera::STENCIL_BUFFER): return GL_STENCIL_ATTACHMENT_EXT;
832        case(Camera::COLOR_BUFFER): return GL_COLOR_ATTACHMENT0_EXT;
833        default: return GLenum(GL_COLOR_ATTACHMENT0_EXT + (attachment_point-Camera::COLOR_BUFFER0));
834    }
835}
836
837void FrameBufferObject::updateDrawBuffers()
838{
839    _drawBuffers.clear();
840
841    // create textures and mipmaps before we bind the frame buffer object
842    for (AttachmentMap::const_iterator i=_attachments.begin(); i!=_attachments.end(); ++i)
843    {
844        // setup draw buffers based on the attachment definition
845        if (i->first >= Camera::COLOR_BUFFER0 && i->first <= Camera::COLOR_BUFFER15)
846            _drawBuffers.push_back(convertBufferComponentToGLenum(i->first));
847    }
848}
849
850void FrameBufferObject::apply(State &state) const
851{
852    apply(state, READ_DRAW_FRAMEBUFFER);
853}
854
855void FrameBufferObject::apply(State &state, BindTarget target) const
856{
857    unsigned int contextID = state.getContextID();
858
859    if (_unsupported[contextID])
860        return;
861
862
863    FBOExtensions* ext = FBOExtensions::instance(contextID,true);
864    if (!ext->isSupported())
865    {
866        _unsupported[contextID] = 1;
867        OSG_WARN << "Warning: EXT_framebuffer_object is not supported" << std::endl;
868        return;
869    }
870
871    if (_attachments.empty())
872    {
873        ext->glBindFramebuffer(target, 0);
874        return;
875    }
876
877    int &dirtyAttachmentList = _dirtyAttachmentList[contextID];
878
879    GLuint &fboID = _fboID[contextID];
880    if (fboID == 0)
881    {
882        ext->glGenFramebuffers(1, &fboID);
883        if (fboID == 0)
884        {
885            OSG_WARN << "Warning: FrameBufferObject: could not create the FBO" << std::endl;
886            return;
887        }
888
889        dirtyAttachmentList = 1;
890
891    }
892
893    if (dirtyAttachmentList)
894    {
895        // the set of of attachments appears to be thread sensitive, it shouldn't be because
896        // OpenGL FBO handles osg::FrameBufferObject has are multi-buffered...
897        // so as a temporary fix will stick in a mutex to ensure that only one thread passes through here
898        // at one time.
899        static OpenThreads::Mutex s_mutex;
900        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex);
901
902        // create textures and mipmaps before we bind the frame buffer object
903        for (AttachmentMap::const_iterator i=_attachments.begin(); i!=_attachments.end(); ++i)
904        {
905            const FrameBufferAttachment &fa = i->second;
906            fa.createRequiredTexturesAndApplyGenerateMipMap(state, ext);
907        }
908
909    }
910
911
912    ext->glBindFramebuffer(target, fboID);
913
914    // enable drawing buffers to render the result to fbo
915    if (_drawBuffers.size() > 0)
916    {
917        GL2Extensions *gl2e = GL2Extensions::Get(state.getContextID(), true );
918        if (gl2e)
919        {
920            gl2e->glDrawBuffers(_drawBuffers.size(), &(_drawBuffers[0]));
921        }
922    }
923
924    if (dirtyAttachmentList)
925    {
926        for (AttachmentMap::const_iterator i=_attachments.begin(); i!=_attachments.end(); ++i)
927        {
928            const FrameBufferAttachment &fa = i->second;
929            switch(i->first)
930            {
931                case(Camera::PACKED_DEPTH_STENCIL_BUFFER):
932                    if (ext->isPackedDepthStencilSupported())
933                    {
934                        fa.attach(state, target, GL_DEPTH_ATTACHMENT_EXT, ext);
935                        fa.attach(state, target, GL_STENCIL_ATTACHMENT_EXT, ext);
936                    }
937                    else
938                    {
939                        OSG_WARN <<
940                            "Warning: FrameBufferObject: could not attach PACKED_DEPTH_STENCIL_BUFFER, "
941                            "EXT_packed_depth_stencil is not supported !" << std::endl;
942                    }
943                    break;
944
945                default:
946                    fa.attach(state, target, convertBufferComponentToGLenum(i->first), ext);
947                    break;
948            }
949        }
950        dirtyAttachmentList = 0;
951    }
952
953}
954
955bool FrameBufferObject::isMultisample() const
956{
957    if (_attachments.size())
958    {
959        // If the FBO is correctly set up then all attachments will be either
960        // multisampled or single sampled. Therefore we can just return the
961        // result of the first attachment.
962        return _attachments.begin()->second.isMultisample();
963    }
964
965    return false;
966}
967
968int FrameBufferObject::compare(const StateAttribute &sa) const
969{
970    COMPARE_StateAttribute_Types(FrameBufferObject, sa);
971    COMPARE_StateAttribute_Parameter(_attachments.size());
972    AttachmentMap::const_iterator i = _attachments.begin();
973    AttachmentMap::const_iterator j = rhs._attachments.begin();
974    for (; i!=_attachments.end(); ++i, ++j)
975    {
976        int cmp = i->second.compare(j->second);
977        if (cmp != 0) return cmp;
978    }
979    return 0;
980}
Note: See TracBrowser for help on using the browser.