From Michael Platings and Paul Palumbo, multi-sample FBO support
This commit is contained in:
@@ -332,14 +332,18 @@ class OSG_EXPORT Camera : public Transform, public CullSettings
|
||||
/** Attach a buffer with specified OpenGL internal format.*/
|
||||
void attach(BufferComponent buffer, GLenum internalFormat);
|
||||
|
||||
/** Attach a Texture to specified buffer component.
|
||||
* The level parameter controls the mip map level of the texture that is attached.
|
||||
* The face parameter controls the face of texture cube map or z level of 3d texture.
|
||||
/** Attach a Texture to specified buffer component.
|
||||
* The level parameter controls the mip map level of the texture that is attached.
|
||||
* The face parameter controls the face of texture cube map or z level of 3d texture.
|
||||
* The mipMapGeneration flag controls whether mipmap generation should be done for texture.*/
|
||||
void attach(BufferComponent buffer, osg::Texture* texture, unsigned int level = 0, unsigned int face=0, bool mipMapGeneration=false);
|
||||
void attach(BufferComponent buffer, osg::Texture* texture, unsigned int level = 0, unsigned int face=0, bool mipMapGeneration=false,
|
||||
unsigned int multisampleSamples = 0,
|
||||
unsigned int multisampleColorSamples = 0);
|
||||
|
||||
/** Attach a Image to specified buffer component.*/
|
||||
void attach(BufferComponent buffer, osg::Image* image);
|
||||
void attach(BufferComponent buffer, osg::Image* image,
|
||||
unsigned int multisampleSamples = 0,
|
||||
unsigned int multisampleColorSamples = 0);
|
||||
|
||||
/** Detach specified buffer component.*/
|
||||
void detach(BufferComponent buffer);
|
||||
@@ -350,7 +354,9 @@ class OSG_EXPORT Camera : public Transform, public CullSettings
|
||||
_internalFormat(GL_NONE),
|
||||
_level(0),
|
||||
_face(0),
|
||||
_mipMapGeneration(false) {}
|
||||
_mipMapGeneration(false),
|
||||
_multisampleSamples(0),
|
||||
_multisampleColorSamples(0) {}
|
||||
|
||||
int width() const
|
||||
{
|
||||
@@ -379,6 +385,8 @@ class OSG_EXPORT Camera : public Transform, public CullSettings
|
||||
unsigned int _level;
|
||||
unsigned int _face;
|
||||
bool _mipMapGeneration;
|
||||
unsigned int _multisampleSamples;
|
||||
unsigned int _multisampleColorSamples;
|
||||
};
|
||||
|
||||
typedef std::map< BufferComponent, Attachment> BufferAttachmentMap;
|
||||
@@ -388,8 +396,8 @@ class OSG_EXPORT Camera : public Transform, public CullSettings
|
||||
|
||||
/** Get the const BufferAttachmentMap, used to configure frame buffer objects, pbuffers and texture reads.*/
|
||||
const BufferAttachmentMap& getBufferAttachmentMap() const { return _bufferAttachmentMap; }
|
||||
|
||||
|
||||
|
||||
|
||||
/** Create a operation thread for this camera.*/
|
||||
void createCameraThread();
|
||||
|
||||
@@ -442,11 +450,11 @@ class OSG_EXPORT Camera : public Transform, public CullSettings
|
||||
DrawCallback(const DrawCallback&,const CopyOp&) {}
|
||||
|
||||
META_Object(osg,DrawCallback)
|
||||
|
||||
/** Functor method called by rendering thread. Users will typically override this method to carry tasks such as screen capture.*/
|
||||
|
||||
/** Functor method called by rendering thread. Users will typically override this method to carry tasks such as screen capture.*/
|
||||
virtual void operator () (osg::RenderInfo& renderInfo) const;
|
||||
|
||||
/** Functor method, provided for backwards compatibility, called by operator() (osg::RenderInfo& renderInfo) method.*/
|
||||
/** Functor method, provided for backwards compatibility, called by operator() (osg::RenderInfo& renderInfo) method.*/
|
||||
virtual void operator () (const osg::Camera& /*camera*/) const {}
|
||||
};
|
||||
|
||||
|
||||
@@ -79,6 +79,14 @@
|
||||
#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506
|
||||
#endif
|
||||
|
||||
#ifndef GL_EXT_framebuffer_blit
|
||||
#define GL_EXT_framebuffer_blit 1
|
||||
#define GL_DRAW_FRAMEBUFFER_BINDING_EXT 0x8CA6
|
||||
#define GL_READ_FRAMEBUFFER_EXT 0x8CA8
|
||||
#define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9
|
||||
#define GL_READ_FRAMEBUFFER_BINDING_EXT 0x8CAA
|
||||
#endif
|
||||
|
||||
#ifndef GL_VERSION_1_4
|
||||
#define GL_DEPTH_COMPONENT16 0x81A5
|
||||
#define GL_DEPTH_COMPONENT24 0x81A6
|
||||
@@ -99,6 +107,8 @@ namespace osg
|
||||
typedef void APIENTRY TglDeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers);
|
||||
typedef void APIENTRY TglGenRenderbuffersEXT(GLsizei, GLuint *);
|
||||
typedef void APIENTRY TglRenderbufferStorageEXT(GLenum, GLenum, GLsizei, GLsizei);
|
||||
typedef void APIENTRY TglRenderbufferStorageMultisampleEXT(GLenum, GLsizei, GLenum, GLsizei, GLsizei);
|
||||
typedef void APIENTRY TglRenderbufferStorageMultisampleCoverageNV(GLenum, GLsizei, GLsizei, GLenum, GLsizei, GLsizei);
|
||||
typedef void APIENTRY TglBindFramebufferEXT(GLenum, GLuint);
|
||||
typedef void APIENTRY TglDeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers);
|
||||
typedef void APIENTRY TglGenFramebuffersEXT(GLsizei, GLuint *);
|
||||
@@ -109,12 +119,13 @@ namespace osg
|
||||
typedef void APIENTRY TglFramebufferTextureLayerEXT(GLenum, GLenum, GLuint, GLint, GLint);
|
||||
typedef void APIENTRY TglFramebufferRenderbufferEXT(GLenum, GLenum, GLenum, GLuint);
|
||||
typedef void APIENTRY TglGenerateMipmapEXT(GLenum);
|
||||
typedef void APIENTRY TglRenderbufferStorageMultisampleCoverageNV(GLenum, GLuint, GLuint, GLenum, GLuint, GLuint);
|
||||
|
||||
typedef void APIENTRY TglBlitFramebufferEXT(GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLbitfield, GLenum);
|
||||
|
||||
TglBindRenderbufferEXT* glBindRenderbufferEXT;
|
||||
TglGenRenderbuffersEXT* glGenRenderbuffersEXT;
|
||||
TglDeleteRenderbuffersEXT* glDeleteRenderbuffersEXT;
|
||||
TglRenderbufferStorageEXT* glRenderbufferStorageEXT;
|
||||
TglRenderbufferStorageMultisampleEXT* glRenderbufferStorageMultisampleEXT;
|
||||
TglRenderbufferStorageMultisampleCoverageNV* glRenderbufferStorageMultisampleCoverageNV;
|
||||
TglBindFramebufferEXT* glBindFramebufferEXT;
|
||||
TglDeleteFramebuffersEXT* glDeleteFramebuffersEXT;
|
||||
@@ -126,10 +137,13 @@ namespace osg
|
||||
TglFramebufferTextureLayerEXT* glFramebufferTextureLayerEXT;
|
||||
TglFramebufferRenderbufferEXT* glFramebufferRenderbufferEXT;
|
||||
TglGenerateMipmapEXT* glGenerateMipmapEXT;
|
||||
TglBlitFramebufferEXT* glBlitFramebufferEXT;
|
||||
|
||||
static FBOExtensions* instance(unsigned contextID, bool createIfNotInitalized);
|
||||
|
||||
bool isSupported() const { return _supported; }
|
||||
bool isMultisampleSupported() const { return glRenderbufferStorageMultisampleEXT != 0; }
|
||||
bool isMultisampleCoverageSupported() const { return glRenderbufferStorageMultisampleCoverageNV != 0; }
|
||||
|
||||
protected:
|
||||
FBOExtensions(unsigned int contextID);
|
||||
@@ -146,7 +160,7 @@ namespace osg
|
||||
{
|
||||
public:
|
||||
RenderBuffer();
|
||||
RenderBuffer(int width, int height, GLenum internalFormat);
|
||||
RenderBuffer(int width, int height, GLenum internalFormat, int samples=0, int colorSamples=0);
|
||||
RenderBuffer(const RenderBuffer& copy, const CopyOp& copyop = CopyOp::SHALLOW_COPY);
|
||||
|
||||
META_Object(osg, RenderBuffer);
|
||||
@@ -158,6 +172,10 @@ namespace osg
|
||||
inline void setSize(int w, int h);
|
||||
inline GLenum getInternalFormat() const;
|
||||
inline void setInternalFormat(GLenum format);
|
||||
inline int getSamples() const;
|
||||
inline int getColorSamples() const;
|
||||
inline void setSamples(int samples);
|
||||
inline void setColorSamples(int colorSamples);
|
||||
|
||||
GLuint getObjectID(unsigned int contextID, const FBOExtensions *ext) const;
|
||||
inline int compare(const RenderBuffer &rb) const;
|
||||
@@ -185,9 +203,14 @@ namespace osg
|
||||
private:
|
||||
mutable buffered_value<GLuint> _objectID;
|
||||
mutable buffered_value<int> _dirty;
|
||||
|
||||
GLenum _internalFormat;
|
||||
int _width;
|
||||
int _height;
|
||||
// "samples" in the framebuffer_multisample extension is equivalent to
|
||||
// "coverageSamples" in the framebuffer_multisample_coverage extension.
|
||||
int _samples;
|
||||
int _colorSamples;
|
||||
};
|
||||
|
||||
// INLINE METHODS
|
||||
@@ -232,6 +255,28 @@ namespace osg
|
||||
dirtyAll();
|
||||
}
|
||||
|
||||
inline int RenderBuffer::getSamples() const
|
||||
{
|
||||
return _samples;
|
||||
}
|
||||
|
||||
inline int RenderBuffer::getColorSamples() const
|
||||
{
|
||||
return _colorSamples;
|
||||
}
|
||||
|
||||
inline void RenderBuffer::setSamples(int samples)
|
||||
{
|
||||
_samples = samples;
|
||||
dirtyAll();
|
||||
}
|
||||
|
||||
inline void RenderBuffer::setColorSamples(int colorSamples)
|
||||
{
|
||||
_colorSamples = colorSamples;
|
||||
dirtyAll();
|
||||
}
|
||||
|
||||
inline void RenderBuffer::dirtyAll() const
|
||||
{
|
||||
_dirty.setAllElementsTo(1);
|
||||
@@ -278,8 +323,9 @@ namespace osg
|
||||
|
||||
FrameBufferAttachment&operator = (const FrameBufferAttachment& copy);
|
||||
|
||||
bool isMultisample() const;
|
||||
void createRequiredTexturesAndApplyGenerateMipMap(State& state, const FBOExtensions* ext) const;
|
||||
void attach(State &state, GLenum attachment_point, const FBOExtensions* ext) const;
|
||||
void attach(State &state, GLenum target, GLenum attachment_point, const FBOExtensions* ext) const;
|
||||
int compare(const FrameBufferAttachment &fa) const;
|
||||
|
||||
private:
|
||||
@@ -323,10 +369,22 @@ namespace osg
|
||||
inline bool hasMultipleRenderingTargets() const { return !_drawBuffers.empty(); }
|
||||
inline const MultipleRenderingTargets& getMultipleRenderingTargets() const { return _drawBuffers; }
|
||||
|
||||
bool isMultisample() const;
|
||||
|
||||
int compare(const StateAttribute &sa) const;
|
||||
|
||||
void apply(State &state) const;
|
||||
|
||||
enum BindTarget
|
||||
{
|
||||
READ_FRAMEBUFFER = GL_READ_FRAMEBUFFER_EXT,
|
||||
DRAW_FRAMEBUFFER = GL_DRAW_FRAMEBUFFER_EXT,
|
||||
READ_DRAW_FRAMEBUFFER = GL_FRAMEBUFFER_EXT
|
||||
};
|
||||
|
||||
/** Bind the FBO as either the read or draw target, or both. */
|
||||
void apply(State &state, BindTarget target) const;
|
||||
|
||||
/** Mark internal FBO for deletion.
|
||||
* Deletion requests are queued until they can be executed
|
||||
* in the proper GL context. */
|
||||
|
||||
@@ -138,11 +138,28 @@ class OSGUTIL_EXPORT RenderStage : public RenderBin
|
||||
void setImageReadPixelDataType(GLenum type) { _imageReadPixelDataType = type; }
|
||||
GLenum getImageReadPixelDataType() const { return _imageReadPixelDataType; }
|
||||
|
||||
|
||||
/** Set a framebuffer object to render into. It is permissible for the
|
||||
* framebuffer object to be multisampled, in which case you should also
|
||||
* set a resolve framebuffer object - see setMultisampleResolveFramebufferObject(). */
|
||||
void setFrameBufferObject(osg::FrameBufferObject* fbo) { _fbo = fbo; }
|
||||
osg::FrameBufferObject* getFrameBufferObject() { return _fbo.get(); }
|
||||
const osg::FrameBufferObject* getFrameBufferObject() const { return _fbo.get(); }
|
||||
|
||||
|
||||
/** Sets the destination framebuffer object for glBlitFramebufferEXT to
|
||||
* resolve a multisampled framebuffer object after the RenderStage is
|
||||
* drawn. The resolve framebuffer object must not be multisampled. The
|
||||
* resolve framebuffer object is only necessary if the primary framebuffer
|
||||
* object is multisampled, if not then leave it set to null. */
|
||||
void setMultisampleResolveFramebufferObject(osg::FrameBufferObject* fbo);
|
||||
osg::FrameBufferObject* getMultisampleResolveFramebufferObject() { return _resolveFbo.get(); }
|
||||
const osg::FrameBufferObject* getMultisampleResolveFramebufferObject() const { return _resolveFbo.get(); }
|
||||
|
||||
/** Set whether the framebuffer object should be unbound after
|
||||
* rendering. By default this is set to true. Set it to false if the
|
||||
* unbinding is not required. */
|
||||
void setDisableFboAfterRender(bool disable) {_disableFboAfterRender = disable;}
|
||||
bool getDisableFboAfterRender() const {return _disableFboAfterRender;}
|
||||
|
||||
void setGraphicsContext(osg::GraphicsContext* context) { _graphicsContext = context; }
|
||||
osg::GraphicsContext* getGraphicsContext() { return _graphicsContext.get(); }
|
||||
const osg::GraphicsContext* getGraphicsContext() const { return _graphicsContext.get(); }
|
||||
@@ -247,7 +264,9 @@ class OSGUTIL_EXPORT RenderStage : public RenderBin
|
||||
std::map< osg::Camera::BufferComponent, Attachment> _bufferAttachmentMap;
|
||||
|
||||
osg::ref_ptr<osg::FrameBufferObject> _fbo;
|
||||
osg::ref_ptr<osg::FrameBufferObject> _resolveFbo;
|
||||
osg::ref_ptr<osg::GraphicsContext> _graphicsContext;
|
||||
bool _disableFboAfterRender;
|
||||
|
||||
mutable osg::Matrix _inheritedPositionalStateContainerMatrix;
|
||||
mutable osg::ref_ptr<PositionalStateContainer> _inheritedPositionalStateContainer;
|
||||
|
||||
@@ -258,17 +258,25 @@ void Camera::attach(BufferComponent buffer, GLenum internalFormat)
|
||||
_bufferAttachmentMap[buffer]._internalFormat = internalFormat;
|
||||
}
|
||||
|
||||
void Camera::attach(BufferComponent buffer, osg::Texture* texture, unsigned int level, unsigned int face, bool mipMapGeneration)
|
||||
void Camera::attach(BufferComponent buffer, osg::Texture* texture, unsigned int level, unsigned int face, bool mipMapGeneration,
|
||||
unsigned int multisampleSamples,
|
||||
unsigned int multisampleColorSamples)
|
||||
{
|
||||
_bufferAttachmentMap[buffer]._texture = texture;
|
||||
_bufferAttachmentMap[buffer]._level = level;
|
||||
_bufferAttachmentMap[buffer]._face = face;
|
||||
_bufferAttachmentMap[buffer]._mipMapGeneration = mipMapGeneration;
|
||||
_bufferAttachmentMap[buffer]._multisampleSamples = multisampleSamples;
|
||||
_bufferAttachmentMap[buffer]._multisampleColorSamples = multisampleColorSamples;
|
||||
}
|
||||
|
||||
void Camera::attach(BufferComponent buffer, osg::Image* image)
|
||||
void Camera::attach(BufferComponent buffer, osg::Image* image,
|
||||
unsigned int multisampleSamples,
|
||||
unsigned int multisampleColorSamples)
|
||||
{
|
||||
_bufferAttachmentMap[buffer]._image = image;
|
||||
_bufferAttachmentMap[buffer]._multisampleSamples = multisampleSamples;
|
||||
_bufferAttachmentMap[buffer]._multisampleColorSamples = multisampleColorSamples;
|
||||
}
|
||||
|
||||
void Camera::detach(BufferComponent buffer)
|
||||
|
||||
@@ -41,7 +41,24 @@ FBOExtensions* FBOExtensions::instance(unsigned contextID, bool createIfNotInita
|
||||
#define LOAD_FBO_EXT(name) setGLExtensionFuncPtr(name, (#name))
|
||||
|
||||
FBOExtensions::FBOExtensions(unsigned int contextID)
|
||||
: _supported(false)
|
||||
: _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)
|
||||
{
|
||||
if (!isGLExtensionSupported(contextID, "GL_EXT_framebuffer_object"))
|
||||
return;
|
||||
@@ -75,6 +92,21 @@ FBOExtensions::FBOExtensions(unsigned int contextID)
|
||||
glFramebufferTexture3DEXT != 0 &&
|
||||
glFramebufferRenderbufferEXT != 0 &&
|
||||
glGenerateMipmapEXT != 0;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -144,15 +176,19 @@ RenderBuffer::RenderBuffer()
|
||||
: Object(),
|
||||
_internalFormat(GL_DEPTH_COMPONENT24),
|
||||
_width(512),
|
||||
_height(512)
|
||||
_height(512),
|
||||
_samples(0),
|
||||
_colorSamples(0)
|
||||
{
|
||||
}
|
||||
|
||||
RenderBuffer::RenderBuffer(int width, int height, GLenum internalFormat)
|
||||
RenderBuffer::RenderBuffer(int width, int height, GLenum internalFormat, int samples, int colorSamples)
|
||||
: Object(),
|
||||
_internalFormat(internalFormat),
|
||||
_width(width),
|
||||
_height(height)
|
||||
_height(height),
|
||||
_samples(samples),
|
||||
_colorSamples(colorSamples)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -160,7 +196,9 @@ RenderBuffer::RenderBuffer(const RenderBuffer ©, const CopyOp ©op)
|
||||
: Object(copy, copyop),
|
||||
_internalFormat(copy._internalFormat),
|
||||
_width(copy._width),
|
||||
_height(copy._height)
|
||||
_height(copy._height),
|
||||
_samples(copy._samples),
|
||||
_colorSamples(copy._colorSamples)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -190,7 +228,30 @@ GLuint RenderBuffer::getObjectID(unsigned int contextID, const FBOExtensions *ex
|
||||
{
|
||||
// bind and configure
|
||||
ext->glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, objectID);
|
||||
ext->glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, _internalFormat, _width, _height);
|
||||
|
||||
// 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())
|
||||
{
|
||||
ext->glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT,
|
||||
_samples, _colorSamples, _internalFormat, _width, _height);
|
||||
}
|
||||
else if (_samples > 0 && ext->isMultisampleSupported())
|
||||
{
|
||||
ext->glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT,
|
||||
_samples, _internalFormat, _width, _height);
|
||||
}
|
||||
else
|
||||
{
|
||||
ext->glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, _internalFormat, _width, _height);
|
||||
}
|
||||
dirty = 0;
|
||||
}
|
||||
|
||||
@@ -391,6 +452,16 @@ FrameBufferAttachment &FrameBufferAttachment::operator = (const FrameBufferAttac
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool FrameBufferAttachment::isMultisample() const
|
||||
{
|
||||
if (_ximpl->renderbufferTarget.valid())
|
||||
{
|
||||
return _ximpl->renderbufferTarget->getSamples() > 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void FrameBufferAttachment::createRequiredTexturesAndApplyGenerateMipMap(State &state, const FBOExtensions* ext) const
|
||||
{
|
||||
unsigned int contextID = state.getContextID();
|
||||
@@ -422,7 +493,7 @@ void FrameBufferAttachment::createRequiredTexturesAndApplyGenerateMipMap(State &
|
||||
}
|
||||
}
|
||||
|
||||
void FrameBufferAttachment::attach(State &state, GLenum attachment_point, const FBOExtensions* ext) const
|
||||
void FrameBufferAttachment::attach(State &state, GLenum target, GLenum attachment_point, const FBOExtensions* ext) const
|
||||
{
|
||||
unsigned int contextID = state.getContextID();
|
||||
|
||||
@@ -444,25 +515,25 @@ void FrameBufferAttachment::attach(State &state, GLenum attachment_point, const
|
||||
{
|
||||
default:
|
||||
case Pimpl::RENDERBUFFER:
|
||||
ext->glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attachment_point, GL_RENDERBUFFER_EXT, _ximpl->renderbufferTarget->getObjectID(contextID, ext));
|
||||
ext->glFramebufferRenderbufferEXT(target, attachment_point, GL_RENDERBUFFER_EXT, _ximpl->renderbufferTarget->getObjectID(contextID, ext));
|
||||
break;
|
||||
case Pimpl::TEXTURE1D:
|
||||
ext->glFramebufferTexture1DEXT(GL_FRAMEBUFFER_EXT, attachment_point, GL_TEXTURE_1D, tobj->_id, _ximpl->level);
|
||||
ext->glFramebufferTexture1DEXT(target, attachment_point, GL_TEXTURE_1D, tobj->_id, _ximpl->level);
|
||||
break;
|
||||
case Pimpl::TEXTURE2D:
|
||||
ext->glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment_point, GL_TEXTURE_2D, tobj->_id, _ximpl->level);
|
||||
ext->glFramebufferTexture2DEXT(target, attachment_point, GL_TEXTURE_2D, tobj->_id, _ximpl->level);
|
||||
break;
|
||||
case Pimpl::TEXTURE3D:
|
||||
ext->glFramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT, attachment_point, GL_TEXTURE_3D, tobj->_id, _ximpl->level, _ximpl->zoffset);
|
||||
ext->glFramebufferTexture3DEXT(target, attachment_point, GL_TEXTURE_3D, tobj->_id, _ximpl->level, _ximpl->zoffset);
|
||||
break;
|
||||
case Pimpl::TEXTURE2DARRAY:
|
||||
ext->glFramebufferTextureLayerEXT(GL_FRAMEBUFFER_EXT, attachment_point, tobj->_id, _ximpl->level, _ximpl->zoffset);
|
||||
ext->glFramebufferTextureLayerEXT(target, attachment_point, tobj->_id, _ximpl->level, _ximpl->zoffset);
|
||||
break;
|
||||
case Pimpl::TEXTURERECT:
|
||||
ext->glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment_point, GL_TEXTURE_RECTANGLE, tobj->_id, 0);
|
||||
ext->glFramebufferTexture2DEXT(target, attachment_point, GL_TEXTURE_RECTANGLE, tobj->_id, 0);
|
||||
break;
|
||||
case Pimpl::TEXTURECUBE:
|
||||
ext->glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment_point, GL_TEXTURE_CUBE_MAP_POSITIVE_X + _ximpl->cubeMapFace, tobj->_id, _ximpl->level);
|
||||
ext->glFramebufferTexture2DEXT(target, attachment_point, GL_TEXTURE_CUBE_MAP_POSITIVE_X + _ximpl->cubeMapFace, tobj->_id, _ximpl->level);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -622,6 +693,11 @@ void FrameBufferObject::updateDrawBuffers()
|
||||
}
|
||||
|
||||
void FrameBufferObject::apply(State &state) const
|
||||
{
|
||||
apply(state, READ_DRAW_FRAMEBUFFER);
|
||||
}
|
||||
|
||||
void FrameBufferObject::apply(State &state, BindTarget target) const
|
||||
{
|
||||
unsigned int contextID = state.getContextID();
|
||||
|
||||
@@ -639,7 +715,7 @@ void FrameBufferObject::apply(State &state) const
|
||||
|
||||
if (_attachments.empty())
|
||||
{
|
||||
ext->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
ext->glBindFramebufferEXT(target, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -678,7 +754,7 @@ void FrameBufferObject::apply(State &state) const
|
||||
}
|
||||
|
||||
|
||||
ext->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboID);
|
||||
ext->glBindFramebufferEXT(target, fboID);
|
||||
|
||||
// enable drawing buffers to render the result to fbo
|
||||
if (_drawBuffers.size() > 0)
|
||||
@@ -695,13 +771,26 @@ void FrameBufferObject::apply(State &state) const
|
||||
for (AttachmentMap::const_iterator i=_attachments.begin(); i!=_attachments.end(); ++i)
|
||||
{
|
||||
const FrameBufferAttachment &fa = i->second;
|
||||
fa.attach(state, convertBufferComponentToGLenum(i->first), ext);
|
||||
fa.attach(state, target, convertBufferComponentToGLenum(i->first), ext);
|
||||
}
|
||||
dirtyAttachmentList = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int FrameBufferObject::compare(const StateAttribute &sa) const
|
||||
{
|
||||
COMPARE_StateAttribute_Types(FrameBufferObject, sa);
|
||||
|
||||
@@ -33,7 +33,8 @@ using namespace osgUtil;
|
||||
//RegisterRenderBinProxy<RenderStage> s_registerRenderStageProxy;
|
||||
|
||||
RenderStage::RenderStage():
|
||||
RenderBin(getDefaultRenderBinSortMode())
|
||||
RenderBin(getDefaultRenderBinSortMode()),
|
||||
_disableFboAfterRender(true)
|
||||
{
|
||||
// point RenderBin's _stage to this to ensure that references to
|
||||
// stage don't go tempted away to any other stage.
|
||||
@@ -59,7 +60,8 @@ RenderStage::RenderStage():
|
||||
}
|
||||
|
||||
RenderStage::RenderStage(SortMode mode):
|
||||
RenderBin(mode)
|
||||
RenderBin(mode),
|
||||
_disableFboAfterRender(true)
|
||||
{
|
||||
// point RenderBin's _stage to this to ensure that references to
|
||||
// stage don't go tempted away to any other stage.
|
||||
@@ -104,7 +106,8 @@ RenderStage::RenderStage(const RenderStage& rhs,const osg::CopyOp& copyop):
|
||||
_face(rhs._face),
|
||||
_imageReadPixelFormat(rhs._imageReadPixelFormat),
|
||||
_imageReadPixelDataType(rhs._imageReadPixelDataType),
|
||||
_renderStageLighting(rhs._renderStageLighting)
|
||||
_renderStageLighting(rhs._renderStageLighting),
|
||||
_disableFboAfterRender(rhs._disableFboAfterRender)
|
||||
{
|
||||
_stage = this;
|
||||
}
|
||||
@@ -327,10 +330,37 @@ void RenderStage::runCameraSetUp(osg::RenderInfo& renderInfo)
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*(_camera->getDataChangeMutex()));
|
||||
|
||||
osg::ref_ptr<osg::FrameBufferObject> fbo = new osg::FrameBufferObject;
|
||||
|
||||
osg::ref_ptr<osg::FrameBufferObject> fbo_multisample;
|
||||
|
||||
bool colorAttached = false;
|
||||
bool depthAttached = false;
|
||||
bool stencilAttached = false;
|
||||
unsigned samples = 0;
|
||||
unsigned colorSamples = 0;
|
||||
|
||||
if (fbo_ext->isMultisampleSupported())
|
||||
{
|
||||
for(osg::Camera::BufferAttachmentMap::iterator itr = bufferAttachments.begin();
|
||||
itr != bufferAttachments.end();
|
||||
++itr)
|
||||
{
|
||||
osg::Camera::Attachment& attachment = itr->second;
|
||||
samples = maximum(samples, attachment._multisampleSamples);
|
||||
colorSamples = maximum(samples, attachment._multisampleColorSamples);
|
||||
}
|
||||
|
||||
if (colorSamples > samples)
|
||||
{
|
||||
osg::notify(WARN) << "Multisample color samples must be less than or "
|
||||
"equal to samples. Setting color samples equal to samples." << std::endl;
|
||||
colorSamples = samples;
|
||||
}
|
||||
|
||||
if (samples)
|
||||
{
|
||||
fbo_multisample = new osg::FrameBufferObject;
|
||||
}
|
||||
}
|
||||
|
||||
for(osg::Camera::BufferAttachmentMap::iterator itr = bufferAttachments.begin();
|
||||
itr != bufferAttachments.end();
|
||||
@@ -344,6 +374,30 @@ void RenderStage::runCameraSetUp(osg::RenderInfo& renderInfo)
|
||||
fbo->setAttachment(buffer, osg::FrameBufferAttachment(attachment));
|
||||
else
|
||||
fbo->setAttachment(buffer, osg::FrameBufferAttachment(new osg::RenderBuffer(width, height, attachment._internalFormat)));
|
||||
|
||||
if (fbo_multisample.valid())
|
||||
{
|
||||
GLenum internalFormat = attachment._internalFormat;
|
||||
if (!internalFormat)
|
||||
{
|
||||
switch (buffer)
|
||||
{
|
||||
case Camera::DEPTH_BUFFER:
|
||||
internalFormat = GL_DEPTH_COMPONENT24;
|
||||
break;
|
||||
case Camera::STENCIL_BUFFER:
|
||||
internalFormat = GL_STENCIL_INDEX8_EXT;
|
||||
break;
|
||||
default:
|
||||
internalFormat = GL_RGBA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fbo_multisample->setAttachment(buffer,
|
||||
osg::FrameBufferAttachment(new osg::RenderBuffer(
|
||||
width, height, internalFormat,
|
||||
samples, colorSamples)));
|
||||
}
|
||||
|
||||
if (buffer==osg::Camera::DEPTH_BUFFER) depthAttached = true;
|
||||
else if (buffer==osg::Camera::STENCIL_BUFFER) stencilAttached = true;
|
||||
@@ -353,11 +407,23 @@ void RenderStage::runCameraSetUp(osg::RenderInfo& renderInfo)
|
||||
if (!depthAttached)
|
||||
{
|
||||
fbo->setAttachment(osg::Camera::DEPTH_BUFFER, osg::FrameBufferAttachment(new osg::RenderBuffer(width, height, GL_DEPTH_COMPONENT24)));
|
||||
if (fbo_multisample.valid())
|
||||
{
|
||||
fbo_multisample->setAttachment(osg::Camera::DEPTH_BUFFER,
|
||||
osg::FrameBufferAttachment(new osg::RenderBuffer(width,
|
||||
height, GL_DEPTH_COMPONENT24, samples, colorSamples)));
|
||||
}
|
||||
}
|
||||
|
||||
if (!colorAttached)
|
||||
{
|
||||
fbo->setAttachment(osg::Camera::COLOR_BUFFER, osg::FrameBufferAttachment(new osg::RenderBuffer(width, height, GL_RGB)));
|
||||
if (fbo_multisample.valid())
|
||||
{
|
||||
fbo_multisample->setAttachment(osg::Camera::COLOR_BUFFER,
|
||||
osg::FrameBufferAttachment(new osg::RenderBuffer(width,
|
||||
height, GL_RGB, samples, colorSamples)));
|
||||
}
|
||||
}
|
||||
|
||||
fbo->apply(state);
|
||||
@@ -386,6 +452,39 @@ void RenderStage::runCameraSetUp(osg::RenderInfo& renderInfo)
|
||||
setReadBuffer(GL_NONE);
|
||||
|
||||
_fbo = fbo;
|
||||
|
||||
if (fbo_multisample.valid())
|
||||
{
|
||||
fbo_multisample->apply(state);
|
||||
|
||||
GLenum status = fbo_ext->glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
|
||||
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
|
||||
{
|
||||
notify(NOTICE) << "RenderStage::runCameraSetUp(), "
|
||||
"multisample FBO setup failed, FBO status = 0x"
|
||||
<< std::hex << status << std::endl;
|
||||
|
||||
fbo->apply(state);
|
||||
fbo_multisample = 0;
|
||||
_resolveFbo = 0;
|
||||
|
||||
// clean up.
|
||||
double availableTime = 100.0f;
|
||||
double currentTime = state.getFrameStamp()?state.getFrameStamp()->getReferenceTime():0.0;
|
||||
osg::RenderBuffer::flushDeletedRenderBuffers(state.getContextID(),currentTime,availableTime);
|
||||
osg::FrameBufferObject::flushDeletedFrameBufferObjects(state.getContextID(),currentTime,availableTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
_resolveFbo.swap(_fbo);
|
||||
_fbo = fbo_multisample;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_resolveFbo = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -680,6 +779,27 @@ void RenderStage::copyTexture(osg::RenderInfo& renderInfo)
|
||||
|
||||
void RenderStage::drawInner(osg::RenderInfo& renderInfo,RenderLeaf*& previous, bool& doCopyTexture)
|
||||
{
|
||||
struct SubFunc
|
||||
{
|
||||
static void applyReadFBO(bool& apply_read_fbo,
|
||||
const FrameBufferObject* read_fbo, osg::State& state)
|
||||
{
|
||||
if (read_fbo->isMultisample())
|
||||
{
|
||||
osg::notify(osg::WARN) << "Attempting to read from a"
|
||||
" multisampled framebuffer object. Set a resolve"
|
||||
" framebuffer on the RenderStage to fix this." << std::endl;
|
||||
}
|
||||
|
||||
if (apply_read_fbo)
|
||||
{
|
||||
// Bind the monosampled FBO to read from
|
||||
read_fbo->apply(state, FrameBufferObject::READ_FRAMEBUFFER);
|
||||
apply_read_fbo = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
osg::State& state = *renderInfo.getState();
|
||||
|
||||
osg::FBOExtensions* fbo_ext = _fbo.valid() ? osg::FBOExtensions::instance(state.getContextID(),true) : 0;
|
||||
@@ -722,67 +842,115 @@ void RenderStage::drawInner(osg::RenderInfo& renderInfo,RenderLeaf*& previous, b
|
||||
}
|
||||
}
|
||||
|
||||
const FrameBufferObject* read_fbo = _fbo.get();
|
||||
bool apply_read_fbo = false;
|
||||
|
||||
if (fbo_supported && _resolveFbo.valid() && fbo_ext->glBlitFramebufferEXT)
|
||||
{
|
||||
GLbitfield blitMask = 0;
|
||||
|
||||
//find which buffer types should be copied
|
||||
for (FrameBufferObject::AttachmentMap::const_iterator
|
||||
it = _resolveFbo->getAttachmentMap().begin(),
|
||||
end =_resolveFbo->getAttachmentMap().end(); it != end; ++it)
|
||||
{
|
||||
switch (it->first)
|
||||
{
|
||||
case Camera::DEPTH_BUFFER:
|
||||
blitMask |= GL_DEPTH_BUFFER_BIT;
|
||||
break;
|
||||
case Camera::STENCIL_BUFFER:
|
||||
blitMask |= GL_STENCIL_BUFFER_BIT;
|
||||
break;
|
||||
default:
|
||||
blitMask |= GL_COLOR_BUFFER_BIT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Bind the resolve framebuffer to blit into.
|
||||
_resolveFbo->apply(state, FrameBufferObject::DRAW_FRAMEBUFFER);
|
||||
|
||||
// Blit to the resolve framebuffer.
|
||||
// Note that (with nvidia 175.16 windows drivers at least) if the read
|
||||
// framebuffer is multisampled then the dimension arguments are ignored
|
||||
// and the whole framebuffer is always copied.
|
||||
fbo_ext->glBlitFramebufferEXT(
|
||||
0, 0, static_cast<GLint>(_viewport->width()), static_cast<GLint>(_viewport->height()),
|
||||
0, 0, static_cast<GLint>(_viewport->width()), static_cast<GLint>(_viewport->height()),
|
||||
blitMask, GL_NEAREST);
|
||||
|
||||
apply_read_fbo = true;
|
||||
read_fbo = _resolveFbo.get();
|
||||
|
||||
using_multiple_render_targets = read_fbo->hasMultipleRenderingTargets();
|
||||
}
|
||||
|
||||
// now copy the rendered image to attached texture.
|
||||
if (doCopyTexture)
|
||||
{
|
||||
SubFunc::applyReadFBO(apply_read_fbo, read_fbo, state);
|
||||
copyTexture(renderInfo);
|
||||
}
|
||||
|
||||
|
||||
std::map< osg::Camera::BufferComponent, Attachment>::const_iterator itr;
|
||||
for(itr = _bufferAttachmentMap.begin();
|
||||
itr != _bufferAttachmentMap.end();
|
||||
++itr)
|
||||
{
|
||||
if (itr->second._image.valid())
|
||||
{
|
||||
if (using_multiple_render_targets)
|
||||
{
|
||||
int attachment=itr->first;
|
||||
if (attachment==osg::Camera::DEPTH_BUFFER || attachment==osg::Camera::STENCIL_BUFFER) {
|
||||
// assume first buffer rendered to is the one we want
|
||||
glReadBuffer(_fbo->getMultipleRenderingTargets()[0]);
|
||||
} else {
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + (attachment - osg::Camera::COLOR_BUFFER0));
|
||||
}
|
||||
} else {
|
||||
if (_readBuffer != GL_NONE)
|
||||
{
|
||||
glReadBuffer(_readBuffer);
|
||||
}
|
||||
}
|
||||
if (itr->second._image.valid())
|
||||
{
|
||||
SubFunc::applyReadFBO(apply_read_fbo, read_fbo, state);
|
||||
|
||||
GLenum pixelFormat = itr->second._image->getPixelFormat();
|
||||
if (pixelFormat==0) pixelFormat = _imageReadPixelFormat;
|
||||
if (pixelFormat==0) pixelFormat = GL_RGB;
|
||||
if (using_multiple_render_targets)
|
||||
{
|
||||
int attachment=itr->first;
|
||||
if (attachment==osg::Camera::DEPTH_BUFFER || attachment==osg::Camera::STENCIL_BUFFER) {
|
||||
// assume first buffer rendered to is the one we want
|
||||
glReadBuffer(read_fbo->getMultipleRenderingTargets()[0]);
|
||||
} else {
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + (attachment - osg::Camera::COLOR_BUFFER0));
|
||||
}
|
||||
} else {
|
||||
if (_readBuffer != GL_NONE)
|
||||
{
|
||||
glReadBuffer(_readBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
GLenum dataType = itr->second._image->getDataType();
|
||||
if (dataType==0) dataType = _imageReadPixelDataType;
|
||||
if (dataType==0) dataType = GL_UNSIGNED_BYTE;
|
||||
GLenum pixelFormat = itr->second._image->getPixelFormat();
|
||||
if (pixelFormat==0) pixelFormat = _imageReadPixelFormat;
|
||||
if (pixelFormat==0) pixelFormat = GL_RGB;
|
||||
|
||||
itr->second._image->readPixels(static_cast<int>(_viewport->x()),
|
||||
static_cast<int>(_viewport->y()),
|
||||
static_cast<int>(_viewport->width()),
|
||||
static_cast<int>(_viewport->height()),
|
||||
pixelFormat, dataType);
|
||||
GLenum dataType = itr->second._image->getDataType();
|
||||
if (dataType==0) dataType = _imageReadPixelDataType;
|
||||
if (dataType==0) dataType = GL_UNSIGNED_BYTE;
|
||||
|
||||
itr->second._image->readPixels(static_cast<int>(_viewport->x()),
|
||||
static_cast<int>(_viewport->y()),
|
||||
static_cast<int>(_viewport->width()),
|
||||
static_cast<int>(_viewport->height()),
|
||||
pixelFormat, dataType);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (fbo_supported)
|
||||
{
|
||||
// switch of the frame buffer object
|
||||
fbo_ext->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
if (getDisableFboAfterRender())
|
||||
{
|
||||
// switch off the frame buffer object
|
||||
fbo_ext->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
}
|
||||
|
||||
doCopyTexture = true;
|
||||
}
|
||||
|
||||
|
||||
if (fbo_supported && _camera)
|
||||
{
|
||||
// now generate mipmaps if they are required.
|
||||
const osg::Camera::BufferAttachmentMap& bufferAttachements = _camera->getBufferAttachmentMap();
|
||||
for(osg::Camera::BufferAttachmentMap::const_iterator itr = bufferAttachements.begin();
|
||||
itr != bufferAttachements.end();
|
||||
const osg::Camera::BufferAttachmentMap& bufferAttachments = _camera->getBufferAttachmentMap();
|
||||
for(osg::Camera::BufferAttachmentMap::const_iterator itr = bufferAttachments.begin();
|
||||
itr != bufferAttachments.end();
|
||||
++itr)
|
||||
{
|
||||
if (itr->second._texture.valid() && itr->second._mipMapGeneration)
|
||||
@@ -1142,3 +1310,13 @@ unsigned int RenderStage::computeNumberOfDynamicRenderLeaves() const
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
void osgUtil::RenderStage::setMultisampleResolveFramebufferObject(osg::FrameBufferObject* fbo)
|
||||
{
|
||||
if (fbo && fbo->isMultisample())
|
||||
{
|
||||
osg::notify(osg::WARN) << "Resolve framebuffer must not be"
|
||||
" multisampled." << std::endl;
|
||||
}
|
||||
_resolveFbo = fbo;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user