2006-07-18 23:21:48 +08:00
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2005-06-16 19:45:50 +08:00
*
* This library is open source and may be redistributed and / or modified under
* the terms of the OpenSceneGraph Public License ( OSGPL ) version 0.0 or
* ( at your option ) any later version . The full license is in LICENSE file
* included with this distribution , and on the openscenegraph . org website .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* OpenSceneGraph Public License for more details .
*/
// initial FBO support written by Marco Jez, June 2005.
2005-06-16 19:42:59 +08:00
# include <osg/FrameBufferObject>
# include <osg/State>
# include <osg/GLExtensions>
# include <osg/Texture1D>
# include <osg/Texture2D>
# include <osg/Texture3D>
2007-09-07 19:21:02 +08:00
# include <osg/Texture2DArray>
2005-06-16 19:42:59 +08:00
# include <osg/TextureCubeMap>
# include <osg/TextureRectangle>
# include <osg/Notify>
2005-11-24 23:18:12 +08:00
# include <osg/Timer>
2005-06-16 19:42:59 +08:00
using namespace osg ;
2007-01-17 22:40:03 +08:00
static buffered_object < ref_ptr < FBOExtensions > > s_extensions ;
2005-06-16 19:42:59 +08:00
2006-01-03 18:44:14 +08:00
FBOExtensions * FBOExtensions : : instance ( unsigned contextID , bool createIfNotInitalized )
{
if ( ! s_extensions [ contextID ] & & createIfNotInitalized ) s_extensions [ contextID ] = new FBOExtensions ( contextID ) ;
return s_extensions [ contextID ] . get ( ) ;
}
2005-06-16 19:42:59 +08:00
/**************************************************************************
* FBOExtensions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-09-10 23:19:23 +08:00
# define LOAD_FBO_EXT(name) setGLExtensionFuncPtr(name, (#name))
2005-06-16 19:42:59 +08:00
FBOExtensions : : FBOExtensions ( unsigned int contextID )
2008-06-18 22:09:11 +08:00
: _supported ( false ) ,
glBindRenderbufferEXT ( 0 ) ,
glGenRenderbuffersEXT ( 0 ) ,
glDeleteRenderbuffersEXT ( 0 ) ,
glRenderbufferStorageEXT ( 0 ) ,
glRenderbufferStorageMultisampleEXT ( 0 ) ,
glRenderbufferStorageMultisampleCoverageNV ( 0 ) ,
glBindFramebufferEXT ( 0 ) ,
glDeleteFramebuffersEXT ( 0 ) ,
glGenFramebuffersEXT ( 0 ) ,
glCheckFramebufferStatusEXT ( 0 ) ,
glFramebufferTexture1DEXT ( 0 ) ,
glFramebufferTexture2DEXT ( 0 ) ,
glFramebufferTexture3DEXT ( 0 ) ,
glFramebufferTextureLayerEXT ( 0 ) ,
glFramebufferRenderbufferEXT ( 0 ) ,
glGenerateMipmapEXT ( 0 ) ,
glBlitFramebufferEXT ( 0 )
2005-06-16 19:42:59 +08:00
{
if ( ! isGLExtensionSupported ( contextID , " GL_EXT_framebuffer_object " ) )
return ;
LOAD_FBO_EXT ( glBindRenderbufferEXT ) ;
LOAD_FBO_EXT ( glGenRenderbuffersEXT ) ;
2005-11-24 23:18:12 +08:00
LOAD_FBO_EXT ( glDeleteRenderbuffersEXT ) ;
2005-06-16 19:42:59 +08:00
LOAD_FBO_EXT ( glRenderbufferStorageEXT ) ;
LOAD_FBO_EXT ( glBindFramebufferEXT ) ;
2005-11-24 23:18:12 +08:00
LOAD_FBO_EXT ( glDeleteFramebuffersEXT ) ;
2005-06-16 19:42:59 +08:00
LOAD_FBO_EXT ( glGenFramebuffersEXT ) ;
LOAD_FBO_EXT ( glCheckFramebufferStatusEXT ) ;
LOAD_FBO_EXT ( glFramebufferTexture1DEXT ) ;
LOAD_FBO_EXT ( glFramebufferTexture2DEXT ) ;
LOAD_FBO_EXT ( glFramebufferTexture3DEXT ) ;
2007-09-07 19:21:02 +08:00
LOAD_FBO_EXT ( glFramebufferTextureLayerEXT ) ;
2005-06-16 19:42:59 +08:00
LOAD_FBO_EXT ( glFramebufferRenderbufferEXT ) ;
LOAD_FBO_EXT ( glGenerateMipmapEXT ) ;
_supported =
glBindRenderbufferEXT ! = 0 & &
2005-11-24 23:18:12 +08:00
glDeleteRenderbuffersEXT ! = 0 & &
2005-06-16 19:42:59 +08:00
glGenRenderbuffersEXT ! = 0 & &
glRenderbufferStorageEXT ! = 0 & &
glBindFramebufferEXT ! = 0 & &
2005-11-24 23:18:12 +08:00
glDeleteFramebuffersEXT ! = 0 & &
2005-06-16 19:42:59 +08:00
glGenFramebuffersEXT ! = 0 & &
glCheckFramebufferStatusEXT ! = 0 & &
glFramebufferTexture1DEXT ! = 0 & &
glFramebufferTexture2DEXT ! = 0 & &
glFramebufferTexture3DEXT ! = 0 & &
glFramebufferRenderbufferEXT ! = 0 & &
glGenerateMipmapEXT ! = 0 ;
2008-06-18 22:09:11 +08:00
if ( ! isGLExtensionSupported ( contextID , " GL_EXT_framebuffer_blit " ) )
return ;
LOAD_FBO_EXT ( glBlitFramebufferEXT ) ;
if ( isGLExtensionSupported ( contextID , " GL_EXT_framebuffer_multisample " ) )
{
LOAD_FBO_EXT ( glRenderbufferStorageMultisampleEXT ) ;
}
if ( isGLExtensionSupported ( contextID , " GL_NV_framebuffer_multisample_coverage " ) )
{
LOAD_FBO_EXT ( glRenderbufferStorageMultisampleCoverageNV ) ;
}
2005-06-16 19:42:59 +08:00
}
/**************************************************************************
* RenderBuffer
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-11-24 23:18:12 +08:00
///////////////////////////////////////////////////////////////////////////
// static cache of glRenderbuffers flagged for deletion, which will actually
// be deleted in the correct GL context.
typedef std : : list < GLuint > RenderBufferHandleList ;
2006-07-26 23:29:26 +08:00
typedef osg : : buffered_object < RenderBufferHandleList > DeletedRenderBufferCache ;
2005-11-24 23:18:12 +08:00
static OpenThreads : : Mutex s_mutex_deletedRenderBufferCache ;
static DeletedRenderBufferCache s_deletedRenderBufferCache ;
void RenderBuffer : : deleteRenderBuffer ( unsigned int contextID , GLuint rb )
{
if ( rb )
{
OpenThreads : : ScopedLock < OpenThreads : : Mutex > lock ( s_mutex_deletedRenderBufferCache ) ;
// add glProgram to the cache for the appropriate context.
s_deletedRenderBufferCache [ contextID ] . push_back ( rb ) ;
}
}
void RenderBuffer : : flushDeletedRenderBuffers ( unsigned int contextID , double /*currentTime*/ , double & availableTime )
{
// if no time available don't try to flush objects.
if ( availableTime < = 0.0 ) return ;
2006-01-03 18:44:14 +08:00
const FBOExtensions * extensions = FBOExtensions : : instance ( contextID , true ) ;
2005-11-24 23:18:12 +08:00
if ( ! extensions | | ! extensions - > isSupported ( ) ) return ;
const osg : : Timer & timer = * osg : : Timer : : instance ( ) ;
osg : : Timer_t start_tick = timer . tick ( ) ;
double elapsedTime = 0.0 ;
{
OpenThreads : : ScopedLock < OpenThreads : : Mutex > lock ( s_mutex_deletedRenderBufferCache ) ;
2006-07-26 23:29:26 +08:00
RenderBufferHandleList & pList = s_deletedRenderBufferCache [ contextID ] ;
for ( RenderBufferHandleList : : iterator titr = pList . begin ( ) ;
titr ! = pList . end ( ) & & elapsedTime < availableTime ;
)
2005-11-24 23:18:12 +08:00
{
2006-07-26 23:29:26 +08:00
extensions - > glDeleteRenderbuffersEXT ( 1 , & ( * titr ) ) ;
titr = pList . erase ( titr ) ;
elapsedTime = timer . delta_s ( start_tick , timer . tick ( ) ) ;
2005-11-24 23:18:12 +08:00
}
}
availableTime - = elapsedTime ;
}
2008-01-08 21:24:29 +08:00
void RenderBuffer : : discardDeletedRenderBuffers ( unsigned int contextID )
{
OpenThreads : : ScopedLock < OpenThreads : : Mutex > lock ( s_mutex_deletedRenderBufferCache ) ;
RenderBufferHandleList & pList = s_deletedRenderBufferCache [ contextID ] ;
pList . clear ( ) ;
}
2005-11-24 23:18:12 +08:00
2005-06-16 19:42:59 +08:00
RenderBuffer : : RenderBuffer ( )
: Object ( ) ,
_internalFormat ( GL_DEPTH_COMPONENT24 ) ,
_width ( 512 ) ,
2008-06-18 22:09:11 +08:00
_height ( 512 ) ,
_samples ( 0 ) ,
_colorSamples ( 0 )
2005-06-16 19:42:59 +08:00
{
}
2008-06-18 22:09:11 +08:00
RenderBuffer : : RenderBuffer ( int width , int height , GLenum internalFormat , int samples , int colorSamples )
2005-06-16 19:42:59 +08:00
: Object ( ) ,
_internalFormat ( internalFormat ) ,
_width ( width ) ,
2008-06-18 22:09:11 +08:00
_height ( height ) ,
_samples ( samples ) ,
_colorSamples ( colorSamples )
2005-06-16 19:42:59 +08:00
{
}
RenderBuffer : : RenderBuffer ( const RenderBuffer & copy , const CopyOp & copyop )
: Object ( copy , copyop ) ,
_internalFormat ( copy . _internalFormat ) ,
_width ( copy . _width ) ,
2008-06-18 22:09:11 +08:00
_height ( copy . _height ) ,
_samples ( copy . _samples ) ,
_colorSamples ( copy . _colorSamples )
2005-06-16 19:42:59 +08:00
{
}
2005-11-24 23:18:12 +08:00
RenderBuffer : : ~ RenderBuffer ( )
{
for ( unsigned i = 0 ; i < _objectID . size ( ) ; + + i )
{
if ( _objectID [ i ] ) deleteRenderBuffer ( i , _objectID [ i ] ) ;
}
}
2008-06-19 04:24:12 +08:00
int RenderBuffer : : getMaxSamples ( unsigned int contextID , const FBOExtensions * ext )
{
static osg : : buffered_value < GLint > maxSamplesList ;
GLint & maxSamples = maxSamplesList [ contextID ] ;
if ( ! maxSamples & & ext - > isMultisampleSupported ( ) )
{
glGetIntegerv ( GL_MAX_SAMPLES_EXT , & maxSamples ) ;
}
return maxSamples ;
}
2005-06-16 19:42:59 +08:00
GLuint RenderBuffer : : getObjectID ( unsigned int contextID , const FBOExtensions * ext ) const
{
GLuint & objectID = _objectID [ contextID ] ;
int & dirty = _dirty [ contextID ] ;
if ( objectID = = 0 )
{
ext - > glGenRenderbuffersEXT ( 1 , & objectID ) ;
if ( objectID = = 0 )
return 0 ;
dirty = 1 ;
}
if ( dirty )
{
// bind and configure
ext - > glBindRenderbufferEXT ( GL_RENDERBUFFER_EXT , objectID ) ;
2008-06-18 22:09:11 +08:00
// framebuffer_multisample_coverage specification requires that coverage
// samples must be >= color samples.
if ( _samples < _colorSamples )
{
notify ( WARN ) < < " Coverage samples must be greater than or equal to color samples. "
" Setting coverage samples equal to color samples. " < < std : : endl ;
const_cast < RenderBuffer * > ( this ) - > setSamples ( _colorSamples ) ;
}
if ( _samples > 0 & & ext - > isMultisampleCoverageSupported ( ) )
{
2008-06-19 04:24:12 +08:00
int samples = minimum ( _samples , getMaxSamples ( contextID , ext ) ) ;
int colorSamples = minimum ( _colorSamples , samples ) ;
2008-06-18 22:09:11 +08:00
ext - > glRenderbufferStorageMultisampleCoverageNV ( GL_RENDERBUFFER_EXT ,
2008-06-19 04:24:12 +08:00
samples , colorSamples , _internalFormat , _width , _height ) ;
2008-06-18 22:09:11 +08:00
}
else if ( _samples > 0 & & ext - > isMultisampleSupported ( ) )
{
2008-06-19 04:24:12 +08:00
int samples = minimum ( _samples , getMaxSamples ( contextID , ext ) ) ;
2008-06-18 22:09:11 +08:00
ext - > glRenderbufferStorageMultisampleEXT ( GL_RENDERBUFFER_EXT ,
2008-06-19 04:24:12 +08:00
samples , _internalFormat , _width , _height ) ;
2008-06-18 22:09:11 +08:00
}
else
{
ext - > glRenderbufferStorageEXT ( GL_RENDERBUFFER_EXT , _internalFormat , _width , _height ) ;
}
2005-06-16 19:42:59 +08:00
dirty = 0 ;
}
return objectID ;
}
/**************************************************************************
2007-12-11 01:30:18 +08:00
* FrameBufferAttachment
2005-06-16 19:42:59 +08:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifndef GL_TEXTURE_CUBE_MAP_POSITIVE_X
# define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
# endif
struct FrameBufferAttachment : : Pimpl
{
enum TargetType
{
RENDERBUFFER ,
TEXTURE1D ,
TEXTURE2D ,
TEXTURE3D ,
TEXTURECUBE ,
2007-09-07 19:21:02 +08:00
TEXTURERECT ,
TEXTURE2DARRAY
2005-06-16 19:42:59 +08:00
} ;
TargetType targetType ;
ref_ptr < RenderBuffer > renderbufferTarget ;
ref_ptr < Texture > textureTarget ;
int cubeMapFace ;
int level ;
int zoffset ;
explicit Pimpl ( TargetType ttype = RENDERBUFFER , int lev = 0 )
: targetType ( ttype ) ,
cubeMapFace ( 0 ) ,
level ( lev ) ,
zoffset ( 0 )
{
}
Pimpl ( const Pimpl & copy )
: targetType ( copy . targetType ) ,
renderbufferTarget ( copy . renderbufferTarget ) ,
textureTarget ( copy . textureTarget ) ,
cubeMapFace ( copy . cubeMapFace ) ,
level ( copy . level ) ,
zoffset ( copy . zoffset )
{
}
} ;
FrameBufferAttachment : : FrameBufferAttachment ( )
{
_ximpl = new Pimpl ;
}
FrameBufferAttachment : : FrameBufferAttachment ( const FrameBufferAttachment & copy )
{
_ximpl = new Pimpl ( * copy . _ximpl ) ;
}
FrameBufferAttachment : : FrameBufferAttachment ( RenderBuffer * target )
{
_ximpl = new Pimpl ( Pimpl : : RENDERBUFFER ) ;
_ximpl - > renderbufferTarget = target ;
}
FrameBufferAttachment : : FrameBufferAttachment ( Texture1D * target , int level )
{
_ximpl = new Pimpl ( Pimpl : : TEXTURE1D , level ) ;
_ximpl - > textureTarget = target ;
}
FrameBufferAttachment : : FrameBufferAttachment ( Texture2D * target , int level )
{
_ximpl = new Pimpl ( Pimpl : : TEXTURE2D , level ) ;
_ximpl - > textureTarget = target ;
}
2008-03-04 23:29:47 +08:00
FrameBufferAttachment : : FrameBufferAttachment ( Texture3D * target , int zoffset , int level )
2005-06-16 19:42:59 +08:00
{
_ximpl = new Pimpl ( Pimpl : : TEXTURE3D , level ) ;
_ximpl - > textureTarget = target ;
_ximpl - > zoffset = zoffset ;
}
2007-09-07 19:21:02 +08:00
FrameBufferAttachment : : FrameBufferAttachment ( Texture2DArray * target , int layer , int level )
{
_ximpl = new Pimpl ( Pimpl : : TEXTURE2DARRAY , level ) ;
_ximpl - > textureTarget = target ;
_ximpl - > zoffset = layer ;
}
2005-06-16 19:42:59 +08:00
FrameBufferAttachment : : FrameBufferAttachment ( TextureCubeMap * target , int face , int level )
{
_ximpl = new Pimpl ( Pimpl : : TEXTURECUBE , level ) ;
_ximpl - > textureTarget = target ;
_ximpl - > cubeMapFace = face ;
}
FrameBufferAttachment : : FrameBufferAttachment ( TextureRectangle * target )
{
_ximpl = new Pimpl ( Pimpl : : TEXTURERECT ) ;
_ximpl - > textureTarget = target ;
}
2006-11-27 22:52:07 +08:00
FrameBufferAttachment : : FrameBufferAttachment ( Camera : : Attachment & attachment )
2005-07-20 00:30:55 +08:00
{
osg : : Texture * texture = attachment . _texture . get ( ) ;
2005-11-01 23:23:03 +08:00
if ( texture )
2005-07-20 00:30:55 +08:00
{
2005-11-01 23:23:03 +08:00
osg : : Texture1D * texture1D = dynamic_cast < osg : : Texture1D * > ( texture ) ;
if ( texture1D )
{
_ximpl = new Pimpl ( Pimpl : : TEXTURE1D , attachment . _level ) ;
_ximpl - > textureTarget = texture1D ;
return ;
}
osg : : Texture2D * texture2D = dynamic_cast < osg : : Texture2D * > ( texture ) ;
if ( texture2D )
{
_ximpl = new Pimpl ( Pimpl : : TEXTURE2D , attachment . _level ) ;
_ximpl - > textureTarget = texture2D ;
return ;
}
osg : : Texture3D * texture3D = dynamic_cast < osg : : Texture3D * > ( texture ) ;
if ( texture3D )
{
_ximpl = new Pimpl ( Pimpl : : TEXTURE3D , attachment . _level ) ;
_ximpl - > textureTarget = texture3D ;
_ximpl - > zoffset = attachment . _face ;
return ;
}
2007-09-07 19:21:02 +08:00
osg : : Texture2DArray * texture2DArray = dynamic_cast < osg : : Texture2DArray * > ( texture ) ;
if ( texture2DArray )
{
_ximpl = new Pimpl ( Pimpl : : TEXTURE2DARRAY , attachment . _level ) ;
_ximpl - > textureTarget = texture2DArray ;
_ximpl - > zoffset = attachment . _face ;
return ;
}
2005-11-01 23:23:03 +08:00
osg : : TextureCubeMap * textureCubeMap = dynamic_cast < osg : : TextureCubeMap * > ( texture ) ;
if ( textureCubeMap )
{
_ximpl = new Pimpl ( Pimpl : : TEXTURECUBE , attachment . _level ) ;
_ximpl - > textureTarget = textureCubeMap ;
_ximpl - > cubeMapFace = attachment . _face ;
return ;
}
osg : : TextureRectangle * textureRectangle = dynamic_cast < osg : : TextureRectangle * > ( texture ) ;
if ( textureRectangle )
{
_ximpl = new Pimpl ( Pimpl : : TEXTURERECT ) ;
_ximpl - > textureTarget = textureRectangle ;
return ;
}
2005-07-20 00:30:55 +08:00
}
2005-11-01 23:23:03 +08:00
osg : : Image * image = attachment . _image . get ( ) ;
if ( image )
2005-07-20 00:30:55 +08:00
{
2006-02-05 05:20:25 +08:00
if ( image - > s ( ) > 0 & & image - > t ( ) > 0 )
2005-11-01 23:23:03 +08:00
{
2006-02-05 05:20:25 +08:00
GLenum format = attachment . _image - > getInternalTextureFormat ( ) ;
if ( format = = 0 )
format = attachment . _internalFormat ;
2005-11-01 23:23:03 +08:00
_ximpl = new Pimpl ( Pimpl : : RENDERBUFFER ) ;
2006-02-05 05:20:25 +08:00
_ximpl - > renderbufferTarget = new osg : : RenderBuffer ( image - > s ( ) , image - > t ( ) , format ) ;
2005-11-01 23:23:03 +08:00
}
else
{
2006-11-27 22:52:07 +08:00
osg : : notify ( osg : : WARN ) < < " Error: FrameBufferAttachment::FrameBufferAttachment(Camera::Attachment&) passed an empty osg::Image, image must be allocated first. " < < std : : endl ;
2005-11-01 23:23:03 +08:00
}
2005-07-20 00:30:55 +08:00
return ;
}
2006-11-27 22:52:07 +08:00
osg : : notify ( osg : : WARN ) < < " Error: FrameBufferAttachment::FrameBufferAttachment(Camera::Attachment&) passed an unrecognised Texture type. " < < std : : endl ;
2005-07-20 00:30:55 +08:00
}
2005-06-16 19:42:59 +08:00
FrameBufferAttachment : : ~ FrameBufferAttachment ( )
{
delete _ximpl ;
}
FrameBufferAttachment & FrameBufferAttachment : : operator = ( const FrameBufferAttachment & copy )
{
delete _ximpl ;
_ximpl = new Pimpl ( * copy . _ximpl ) ;
return * this ;
}
2008-06-18 22:09:11 +08:00
bool FrameBufferAttachment : : isMultisample ( ) const
{
if ( _ximpl - > renderbufferTarget . valid ( ) )
{
return _ximpl - > renderbufferTarget - > getSamples ( ) > 0 ;
}
return false ;
}
2005-07-27 19:27:44 +08:00
void FrameBufferAttachment : : createRequiredTexturesAndApplyGenerateMipMap ( State & state , const FBOExtensions * ext ) const
2005-06-16 19:42:59 +08:00
{
unsigned int contextID = state . getContextID ( ) ;
// force compile texture if necessary
Texture : : TextureObject * tobj = 0 ;
if ( _ximpl - > textureTarget . valid ( ) )
{
tobj = _ximpl - > textureTarget - > getTextureObject ( contextID ) ;
if ( ! tobj | | tobj - > _id = = 0 )
{
_ximpl - > textureTarget - > compileGLObjects ( state ) ;
tobj = _ximpl - > textureTarget - > getTextureObject ( contextID ) ;
}
if ( ! tobj | | tobj - > _id = = 0 )
return ;
2005-07-27 19:27:44 +08:00
Texture : : FilterMode minFilter = _ximpl - > textureTarget - > getFilter ( Texture : : MIN_FILTER ) ;
if ( minFilter = = Texture : : LINEAR_MIPMAP_LINEAR | |
minFilter = = Texture : : LINEAR_MIPMAP_NEAREST | |
minFilter = = Texture : : NEAREST_MIPMAP_LINEAR | |
minFilter = = Texture : : NEAREST_MIPMAP_NEAREST )
{
2006-02-05 05:20:25 +08:00
state . setActiveTextureUnit ( 0 ) ;
state . applyTextureAttribute ( 0 , _ximpl - > textureTarget . get ( ) ) ;
2005-07-27 19:27:44 +08:00
ext - > glGenerateMipmapEXT ( _ximpl - > textureTarget - > getTextureTarget ( ) ) ;
}
2005-06-16 19:42:59 +08:00
}
2005-07-27 19:27:44 +08:00
}
2008-06-18 22:09:11 +08:00
void FrameBufferAttachment : : attach ( State & state , GLenum target , GLenum attachment_point , const FBOExtensions * ext ) const
2005-07-27 19:27:44 +08:00
{
unsigned int contextID = state . getContextID ( ) ;
Texture : : TextureObject * tobj = 0 ;
if ( _ximpl - > textureTarget . valid ( ) )
{
tobj = _ximpl - > textureTarget - > getTextureObject ( contextID ) ;
if ( ! tobj | | tobj - > _id = = 0 )
{
_ximpl - > textureTarget - > compileGLObjects ( state ) ;
tobj = _ximpl - > textureTarget - > getTextureObject ( contextID ) ;
2005-06-16 19:42:59 +08:00
2005-07-27 19:27:44 +08:00
}
if ( ! tobj | | tobj - > _id = = 0 )
return ;
}
2005-06-16 19:42:59 +08:00
switch ( _ximpl - > targetType )
{
default :
case Pimpl : : RENDERBUFFER :
2008-06-18 22:09:11 +08:00
ext - > glFramebufferRenderbufferEXT ( target , attachment_point , GL_RENDERBUFFER_EXT , _ximpl - > renderbufferTarget - > getObjectID ( contextID , ext ) ) ;
2005-06-16 19:42:59 +08:00
break ;
case Pimpl : : TEXTURE1D :
2008-06-18 22:09:11 +08:00
ext - > glFramebufferTexture1DEXT ( target , attachment_point , GL_TEXTURE_1D , tobj - > _id , _ximpl - > level ) ;
2005-06-16 19:42:59 +08:00
break ;
case Pimpl : : TEXTURE2D :
2008-06-18 22:09:11 +08:00
ext - > glFramebufferTexture2DEXT ( target , attachment_point , GL_TEXTURE_2D , tobj - > _id , _ximpl - > level ) ;
2005-06-16 19:42:59 +08:00
break ;
case Pimpl : : TEXTURE3D :
2008-06-18 22:09:11 +08:00
ext - > glFramebufferTexture3DEXT ( target , attachment_point , GL_TEXTURE_3D , tobj - > _id , _ximpl - > level , _ximpl - > zoffset ) ;
2005-06-16 19:42:59 +08:00
break ;
2007-09-07 19:21:02 +08:00
case Pimpl : : TEXTURE2DARRAY :
2008-06-18 22:09:11 +08:00
ext - > glFramebufferTextureLayerEXT ( target , attachment_point , tobj - > _id , _ximpl - > level , _ximpl - > zoffset ) ;
2007-09-07 19:21:02 +08:00
break ;
2005-06-16 19:42:59 +08:00
case Pimpl : : TEXTURERECT :
2008-06-18 22:09:11 +08:00
ext - > glFramebufferTexture2DEXT ( target , attachment_point , GL_TEXTURE_RECTANGLE , tobj - > _id , 0 ) ;
2005-06-16 19:42:59 +08:00
break ;
case Pimpl : : TEXTURECUBE :
2008-06-18 22:09:11 +08:00
ext - > glFramebufferTexture2DEXT ( target , attachment_point , GL_TEXTURE_CUBE_MAP_POSITIVE_X + _ximpl - > cubeMapFace , tobj - > _id , _ximpl - > level ) ;
2005-06-16 19:42:59 +08:00
break ;
}
}
int FrameBufferAttachment : : compare ( const FrameBufferAttachment & fa ) const
{
if ( & fa = = this ) return 0 ;
if ( _ximpl - > targetType < fa . _ximpl - > targetType ) return - 1 ;
if ( _ximpl - > targetType > fa . _ximpl - > targetType ) return 1 ;
if ( _ximpl - > renderbufferTarget . get ( ) < fa . _ximpl - > renderbufferTarget . get ( ) ) return - 1 ;
if ( _ximpl - > renderbufferTarget . get ( ) > fa . _ximpl - > renderbufferTarget . get ( ) ) return 1 ;
if ( _ximpl - > textureTarget . get ( ) < fa . _ximpl - > textureTarget . get ( ) ) return - 1 ;
if ( _ximpl - > textureTarget . get ( ) > fa . _ximpl - > textureTarget . get ( ) ) return 1 ;
if ( _ximpl - > cubeMapFace < fa . _ximpl - > cubeMapFace ) return - 1 ;
if ( _ximpl - > cubeMapFace > fa . _ximpl - > cubeMapFace ) return 1 ;
if ( _ximpl - > level < fa . _ximpl - > level ) return - 1 ;
if ( _ximpl - > level > fa . _ximpl - > level ) return 1 ;
if ( _ximpl - > zoffset < fa . _ximpl - > zoffset ) return - 1 ;
if ( _ximpl - > zoffset > fa . _ximpl - > zoffset ) return 1 ;
return 0 ;
}
/**************************************************************************
* FrameBufferObject
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-11-24 23:18:12 +08:00
///////////////////////////////////////////////////////////////////////////
// static cache of glRenderbuffers flagged for deletion, which will actually
// be deleted in the correct GL context.
typedef std : : list < GLuint > FrameBufferObjectHandleList ;
2006-07-26 23:29:26 +08:00
typedef osg : : buffered_object < FrameBufferObjectHandleList > DeletedFrameBufferObjectCache ;
2005-11-24 23:18:12 +08:00
static OpenThreads : : Mutex s_mutex_deletedFrameBufferObjectCache ;
static DeletedFrameBufferObjectCache s_deletedFrameBufferObjectCache ;
void FrameBufferObject : : deleteFrameBufferObject ( unsigned int contextID , GLuint rb )
{
if ( rb )
{
OpenThreads : : ScopedLock < OpenThreads : : Mutex > lock ( s_mutex_deletedFrameBufferObjectCache ) ;
// add glProgram to the cache for the appropriate context.
s_deletedFrameBufferObjectCache [ contextID ] . push_back ( rb ) ;
}
}
void FrameBufferObject : : flushDeletedFrameBufferObjects ( unsigned int contextID , double /*currentTime*/ , double & availableTime )
{
// if no time available don't try to flush objects.
if ( availableTime < = 0.0 ) return ;
2006-01-03 18:44:14 +08:00
const FBOExtensions * extensions = FBOExtensions : : instance ( contextID , true ) ;
2005-11-24 23:18:12 +08:00
if ( ! extensions | | ! extensions - > isSupported ( ) ) return ;
const osg : : Timer & timer = * osg : : Timer : : instance ( ) ;
osg : : Timer_t start_tick = timer . tick ( ) ;
double elapsedTime = 0.0 ;
{
OpenThreads : : ScopedLock < OpenThreads : : Mutex > lock ( s_mutex_deletedFrameBufferObjectCache ) ;
2006-07-26 23:29:26 +08:00
FrameBufferObjectHandleList & pList = s_deletedFrameBufferObjectCache [ contextID ] ;
for ( FrameBufferObjectHandleList : : iterator titr = pList . begin ( ) ;
titr ! = pList . end ( ) & & elapsedTime < availableTime ;
)
2005-11-24 23:18:12 +08:00
{
2006-07-26 23:29:26 +08:00
extensions - > glDeleteFramebuffersEXT ( 1 , & ( * titr ) ) ;
titr = pList . erase ( titr ) ;
elapsedTime = timer . delta_s ( start_tick , timer . tick ( ) ) ;
2005-11-24 23:18:12 +08:00
}
}
availableTime - = elapsedTime ;
}
2008-01-08 21:24:29 +08:00
void FrameBufferObject : : discardDeletedFrameBufferObjects ( unsigned int contextID )
{
OpenThreads : : ScopedLock < OpenThreads : : Mutex > lock ( s_mutex_deletedFrameBufferObjectCache ) ;
FrameBufferObjectHandleList & pList = s_deletedFrameBufferObjectCache [ contextID ] ;
pList . clear ( ) ;
}
2005-11-24 23:18:12 +08:00
2005-06-16 19:42:59 +08:00
FrameBufferObject : : FrameBufferObject ( )
: StateAttribute ( )
{
}
FrameBufferObject : : FrameBufferObject ( const FrameBufferObject & copy , const CopyOp & copyop )
: StateAttribute ( copy , copyop ) ,
2008-04-16 03:36:40 +08:00
_attachments ( copy . _attachments ) ,
_drawBuffers ( copy . _drawBuffers )
2005-06-16 19:42:59 +08:00
{
}
2005-11-24 23:18:12 +08:00
FrameBufferObject : : ~ FrameBufferObject ( )
{
for ( unsigned i = 0 ; i < _fboID . size ( ) ; + + i )
{
if ( _fboID [ i ] ) deleteFrameBufferObject ( i , _fboID [ i ] ) ;
}
}
2008-04-16 03:36:40 +08:00
void FrameBufferObject : : setAttachment ( GLenum attachment_point , const FrameBufferAttachment & attachment )
{
2008-04-18 21:25:14 +08:00
setAttachment ( convertGLenumToBufferComponent ( attachment_point ) , attachment ) ;
}
void FrameBufferObject : : setAttachment ( BufferComponent attachment_point , const FrameBufferAttachment & attachment )
{
GLenum gl_attachment = convertBufferComponentToGLenum ( attachment_point ) ;
2008-04-16 03:36:40 +08:00
_attachments [ attachment_point ] = attachment ;
2008-04-18 21:25:14 +08:00
updateDrawBuffers ( ) ;
dirtyAll ( ) ;
}
GLenum FrameBufferObject : : convertBufferComponentToGLenum ( BufferComponent attachment_point ) const
{
switch ( attachment_point )
{
case ( Camera : : DEPTH_BUFFER ) : return GL_DEPTH_ATTACHMENT_EXT ;
case ( Camera : : STENCIL_BUFFER ) : return GL_STENCIL_ATTACHMENT_EXT ;
case ( Camera : : COLOR_BUFFER ) : return GL_COLOR_ATTACHMENT0_EXT ;
default : return GLenum ( GL_COLOR_ATTACHMENT0_EXT + ( attachment_point - Camera : : COLOR_BUFFER0 ) ) ;
}
}
FrameBufferObject : : BufferComponent FrameBufferObject : : convertGLenumToBufferComponent ( GLenum attachment_point ) const
{
switch ( attachment_point )
{
case ( GL_DEPTH_ATTACHMENT_EXT ) : return Camera : : DEPTH_BUFFER ;
case ( GL_STENCIL_ATTACHMENT_EXT ) : return Camera : : STENCIL_BUFFER ;
case ( GL_COLOR_ATTACHMENT0_EXT ) : return Camera : : COLOR_BUFFER ;
default : return BufferComponent ( Camera : : COLOR_BUFFER0 + ( attachment_point - GL_COLOR_ATTACHMENT0_EXT ) ) ;
}
}
void FrameBufferObject : : updateDrawBuffers ( )
{
2008-04-16 03:36:40 +08:00
_drawBuffers . clear ( ) ;
// create textures and mipmaps before we bind the frame buffer object
for ( AttachmentMap : : const_iterator i = _attachments . begin ( ) ; i ! = _attachments . end ( ) ; + + i )
{
const FrameBufferAttachment & fa = i - > second ;
// setup draw buffers based on the attachment definition
2008-04-18 21:25:14 +08:00
if ( i - > first > = Camera : : COLOR_BUFFER0 & & i - > first < = Camera : : COLOR_BUFFER15 )
_drawBuffers . push_back ( convertBufferComponentToGLenum ( i - > first ) ) ;
2008-04-16 03:36:40 +08:00
}
}
2005-06-16 19:42:59 +08:00
void FrameBufferObject : : apply ( State & state ) const
2008-06-18 22:09:11 +08:00
{
apply ( state , READ_DRAW_FRAMEBUFFER ) ;
}
void FrameBufferObject : : apply ( State & state , BindTarget target ) const
2005-06-16 19:42:59 +08:00
{
unsigned int contextID = state . getContextID ( ) ;
if ( _unsupported [ contextID ] )
return ;
2005-06-16 22:01:38 +08:00
2005-11-02 18:29:38 +08:00
2006-01-03 18:44:14 +08:00
FBOExtensions * ext = FBOExtensions : : instance ( contextID , true ) ;
2005-06-16 19:42:59 +08:00
if ( ! ext - > isSupported ( ) )
{
_unsupported [ contextID ] = 1 ;
notify ( WARN ) < < " Warning: EXT_framebuffer_object is not supported " < < std : : endl ;
return ;
}
if ( _attachments . empty ( ) )
{
2008-06-18 22:09:11 +08:00
ext - > glBindFramebufferEXT ( target , 0 ) ;
2005-06-16 19:42:59 +08:00
return ;
}
int & dirtyAttachmentList = _dirtyAttachmentList [ contextID ] ;
GLuint & fboID = _fboID [ contextID ] ;
if ( fboID = = 0 )
{
ext - > glGenFramebuffersEXT ( 1 , & fboID ) ;
if ( fboID = = 0 )
{
notify ( WARN ) < < " Warning: FrameBufferObject: could not create the FBO " < < std : : endl ;
return ;
}
2005-07-27 19:27:44 +08:00
2005-06-16 19:42:59 +08:00
dirtyAttachmentList = 1 ;
2005-07-27 19:27:44 +08:00
2005-06-16 19:42:59 +08:00
}
2005-07-27 19:27:44 +08:00
if ( dirtyAttachmentList )
{
2007-12-11 01:30:18 +08:00
// the set of of attachments appears to be thread sensitive, it shouldn't be because
2005-11-23 21:44:27 +08:00
// OpenGL FBO handles osg::FrameBufferObject has are multi-buffered...
// so as a temporary fix will stick in a mutex to ensure that only one thread passes through here
// at one time.
static OpenThreads : : Mutex s_mutex ;
OpenThreads : : ScopedLock < OpenThreads : : Mutex > lock ( s_mutex ) ;
2005-07-27 19:27:44 +08:00
// create textures and mipmaps before we bind the frame buffer object
for ( AttachmentMap : : const_iterator i = _attachments . begin ( ) ; i ! = _attachments . end ( ) ; + + i )
{
const FrameBufferAttachment & fa = i - > second ;
fa . createRequiredTexturesAndApplyGenerateMipMap ( state , ext ) ;
}
}
2007-09-07 19:21:02 +08:00
2008-06-18 22:09:11 +08:00
ext - > glBindFramebufferEXT ( target , fboID ) ;
2005-06-16 19:42:59 +08:00
2008-04-16 03:36:40 +08:00
// enable drawing buffers to render the result to fbo
if ( _drawBuffers . size ( ) > 0 )
{
GL2Extensions * gl2e = GL2Extensions : : Get ( state . getContextID ( ) , true ) ;
if ( gl2e )
{
gl2e - > glDrawBuffers ( _drawBuffers . size ( ) , & ( _drawBuffers [ 0 ] ) ) ;
}
}
2005-06-16 19:42:59 +08:00
if ( dirtyAttachmentList )
{
for ( AttachmentMap : : const_iterator i = _attachments . begin ( ) ; i ! = _attachments . end ( ) ; + + i )
{
const FrameBufferAttachment & fa = i - > second ;
2008-06-18 22:09:11 +08:00
fa . attach ( state , target , convertBufferComponentToGLenum ( i - > first ) , ext ) ;
2005-06-16 19:42:59 +08:00
}
dirtyAttachmentList = 0 ;
}
2005-11-23 21:44:27 +08:00
2005-06-16 19:42:59 +08:00
}
2008-06-18 22:09:11 +08:00
bool FrameBufferObject : : isMultisample ( ) const
{
if ( _attachments . size ( ) )
{
// If the FBO is correctly set up then all attachments will be either
// multisampled or single sampled. Therefore we can just return the
// result of the first attachment.
return _attachments . begin ( ) - > second . isMultisample ( ) ;
}
return false ;
}
2005-06-16 19:42:59 +08:00
int FrameBufferObject : : compare ( const StateAttribute & sa ) const
{
COMPARE_StateAttribute_Types ( FrameBufferObject , sa ) ;
COMPARE_StateAttribute_Parameter ( _attachments . size ( ) ) ;
AttachmentMap : : const_iterator i = _attachments . begin ( ) ;
AttachmentMap : : const_iterator j = rhs . _attachments . begin ( ) ;
for ( ; i ! = _attachments . end ( ) ; + + i , + + j )
{
int cmp = i - > second . compare ( j - > second ) ;
if ( cmp ! = 0 ) return cmp ;
}
return 0 ;
}