Files
OpenSceneGraph/include/osg/BufferObject

540 lines
21 KiB
C++

/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* 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.
*/
#ifndef OSG_BUFFEROBJECT
#define OSG_BUFFEROBJECT 1
#include <osg/GL>
#include <osg/Object>
#include <osg/buffered_value>
#ifndef GL_ARB_vertex_buffer_object
#define GL_ARB_vertex_buffer_object
// for compatibility with gl.h headers that don't support VBO,
#if defined(_WIN64)
typedef __int64 GLintptrARB;
typedef __int64 GLsizeiptrARB;
#elif defined(__ia64__) || defined(__x86_64__)
typedef long int GLintptrARB;
typedef long int GLsizeiptrARB;
#else
typedef int GLintptrARB;
typedef int GLsizeiptrARB;
#endif
#define GL_ARRAY_BUFFER_ARB 0x8892
#define GL_ELEMENT_ARRAY_BUFFER_ARB 0x8893
#define GL_ARRAY_BUFFER_BINDING_ARB 0x8894
#define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895
#define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896
#define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897
#define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898
#define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899
#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A
#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B
#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C
#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D
#define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E
#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F
#define GL_STREAM_DRAW_ARB 0x88E0
#define GL_STREAM_READ_ARB 0x88E1
#define GL_STREAM_COPY_ARB 0x88E2
#define GL_STATIC_DRAW_ARB 0x88E4
#define GL_STATIC_READ_ARB 0x88E5
#define GL_STATIC_COPY_ARB 0x88E6
#define GL_DYNAMIC_DRAW_ARB 0x88E8
#define GL_DYNAMIC_READ_ARB 0x88E9
#define GL_DYNAMIC_COPY_ARB 0x88EA
#define GL_READ_ONLY_ARB 0x88B8
#define GL_WRITE_ONLY_ARB 0x88B9
#define GL_READ_WRITE_ARB 0x88BA
#define GL_BUFFER_SIZE_ARB 0x8764
#define GL_BUFFER_USAGE_ARB 0x8765
#define GL_BUFFER_ACCESS_ARB 0x88BB
#define GL_BUFFER_MAPPED_ARB 0x88BC
#define GL_BUFFER_MAP_POINTER_ARB 0x88BD
#endif
#ifndef GL_VERSION_1_5
#define GL_STREAM_DRAW 0x88E0
#define GL_STREAM_READ 0x88E1
#define GL_STREAM_COPY 0x88E2
#define GL_STATIC_DRAW 0x88E4
#define GL_STATIC_READ 0x88E5
#define GL_STATIC_COPY 0x88E6
#define GL_DYNAMIC_DRAW 0x88E8
#define GL_DYNAMIC_READ 0x88E9
#define GL_DYNAMIC_COPY 0x88EA
#endif
#ifndef GL_VERSION_2_1
#define GL_PIXEL_PACK_BUFFER 0x88EB
#define GL_PIXEL_UNPACK_BUFFER 0x88EC
#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED
#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF
#endif
#ifndef GL_ARB_pixel_buffer_object
#define GL_PIXEL_PACK_BUFFER_ARB 0x88EB
#define GL_PIXEL_UNPACK_BUFFER_ARB 0x88EC
#define GL_PIXEL_PACK_BUFFER_BINDING_ARB 0x88ED
#define GL_PIXEL_UNPACK_BUFFER_BINDING_ARB 0x88EF
#endif
namespace osg
{
class State;
class BufferData;
class BufferObject;
class OSG_EXPORT GLBufferObject : public Referenced
{
public:
GLBufferObject(unsigned int contextID, BufferObject* bufferObject=0);
void setBufferObject(BufferObject* bufferObject);
BufferObject* getBufferObject() { return _bufferObject; }
struct BufferEntry
{
BufferEntry(): modifiedCount(0),dataSize(0),offset(0),dataSource(0) {}
BufferEntry(const BufferEntry& rhs):
modifiedCount(rhs.modifiedCount),
dataSize(rhs.dataSize),
offset(rhs.offset),
dataSource(rhs.dataSource) {}
BufferEntry& operator = (const BufferEntry& rhs)
{
if (&rhs==this) return *this;
modifiedCount = rhs.modifiedCount;
dataSize = rhs.dataSize;
offset = rhs.offset;
dataSource = rhs.dataSource;
return *this;
}
unsigned int modifiedCount;
GLsizeiptrARB dataSize;
GLsizeiptrARB offset;
BufferData* dataSource;
};
inline unsigned int getContextID() const { return _contextID; }
inline GLuint& getGLObjectID() { return _glObjectID; }
inline GLuint getGLObjectID() const { return _glObjectID; }
inline GLsizeiptrARB getOffset(unsigned int i) const { return _bufferEntries[i].offset; }
inline void bindBuffer() const
{
_extensions->glBindBuffer(_target,_glObjectID);
}
inline void unbindBuffer() const
{
_extensions->glBindBuffer(_target,0);
}
inline bool isDirty() const { return _dirty; }
void dirty() { _dirty = true; }
void clear();
void compileBuffer();
void deleteGLObject();
void assign(BufferObject* bufferObject);
bool isPBOSupported() const { return _extensions->isPBOSupported(); }
static GLBufferObject* createGLBufferObject(unsigned int contextID, const BufferObject* bufferObject);
/** Use deleteVertexBufferObject instead of glDeleteBuffers to allow
* OpenGL buffer objects to be cached until they can be deleted
* by the OpenGL context in which they were created, specified
* by contextID.*/
static void deleteBufferObject(unsigned int contextID,GLuint globj);
/** flush all the cached display list which need to be deleted
* in the OpenGL context related to contextID.*/
static void flushDeletedBufferObjects(unsigned int contextID,double /*currentTime*/, double& availableTime);
/** dicard all the cached display list which need to be deleted
* in the OpenGL context related to contextID.
* Note, unlike flush no OpenGL calls are made, instead the handles are all removed.
* this call is useful for when an OpenGL context has been destroyed. */
static void discardDeletedBufferObjects(unsigned int contextID);
/** Extensions class which encapsulates the querying of extensions and
* associated function pointers, and provide convenience wrappers to
* check for the extensions or use the associated functions.*/
class OSG_EXPORT Extensions : public osg::Referenced
{
public:
Extensions(unsigned int contextID);
Extensions(const Extensions& rhs);
void lowestCommonDenominator(const Extensions& rhs);
void setupGLExtensions(unsigned int contextID);
bool isBufferObjectSupported() const { return _glGenBuffers!=0; }
bool isPBOSupported() const { return _isPBOSupported; }
void glGenBuffers (GLsizei n, GLuint *buffers) const;
void glBindBuffer (GLenum target, GLuint buffer) const;
void glBufferData (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage) const;
void glBufferSubData (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data) const;
void glDeleteBuffers (GLsizei n, const GLuint *buffers) const;
GLboolean glIsBuffer (GLuint buffer) const;
void glGetBufferSubData (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data) const;
GLvoid* glMapBuffer (GLenum target, GLenum access) const;
GLboolean glUnmapBuffer (GLenum target) const;
void glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params) const;
void glGetBufferPointerv (GLenum target, GLenum pname, GLvoid* *params) const;
protected:
typedef void (APIENTRY * GenBuffersProc) (GLsizei n, GLuint *buffers);
typedef void (APIENTRY * BindBufferProc) (GLenum target, GLuint buffer);
typedef void (APIENTRY * BufferDataProc) (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage);
typedef void (APIENTRY * BufferSubDataProc) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data);
typedef void (APIENTRY * DeleteBuffersProc) (GLsizei n, const GLuint *buffers);
typedef GLboolean (APIENTRY * IsBufferProc) (GLuint buffer);
typedef void (APIENTRY * GetBufferSubDataProc) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data);
typedef GLvoid* (APIENTRY * MapBufferProc) (GLenum target, GLenum access);
typedef GLboolean (APIENTRY * UnmapBufferProc) (GLenum target);
typedef void (APIENTRY * GetBufferParameterivProc) (GLenum target, GLenum pname, GLint *params);
typedef void (APIENTRY * GetBufferPointervProc) (GLenum target, GLenum pname, GLvoid* *params);
GenBuffersProc _glGenBuffers;
BindBufferProc _glBindBuffer;
BufferDataProc _glBufferData;
BufferSubDataProc _glBufferSubData;
DeleteBuffersProc _glDeleteBuffers;
IsBufferProc _glIsBuffer;
GetBufferSubDataProc _glGetBufferSubData;
MapBufferProc _glMapBuffer;
UnmapBufferProc _glUnmapBuffer;
GetBufferParameterivProc _glGetBufferParameteriv;
GetBufferPointervProc _glGetBufferPointerv;
bool _isPBOSupported;
};
/** Function to call to get the extension of a specified context.
* If the Extension object for that context has not yet been created
* and the 'createIfNotInitalized' flag been set to false then returns NULL.
* If 'createIfNotInitalized' is true then the Extensions object is
* automatically created. However, in this case the extension object is
* only created with the graphics context associated with ContextID..*/
static Extensions* getExtensions(unsigned int contextID,bool createIfNotInitalized);
/** setExtensions allows users to override the extensions across graphics contexts.
* typically used when you have different extensions supported across graphics pipes
* but need to ensure that they all use the same low common denominator extensions.*/
static void setExtensions(unsigned int contextID,Extensions* extensions);
protected:
virtual ~GLBufferObject();
unsigned int _contextID;
GLuint _glObjectID;
GLenum _target;
GLenum _usage;
bool _dirty;
mutable unsigned int _totalSize;
typedef std::vector<BufferEntry> BufferEntries;
BufferEntries _bufferEntries;
BufferObject* _bufferObject;
public:
Extensions* _extensions;
};
class OSG_EXPORT BufferObject : public Object
{
public:
BufferObject();
/** Copy constructor using CopyOp to manage deep vs shallow copy.*/
BufferObject(const BufferObject& bo,const CopyOp& copyop=CopyOp::SHALLOW_COPY);
virtual bool isSameKindAs(const Object* obj) const { return dynamic_cast<const BufferObject*>(obj)!=NULL; }
virtual const char* libraryName() const { return "osg"; }
virtual const char* className() const { return "BufferObject"; }
void setTarget(GLenum target) { _target = target; }
GLenum getTarget() const { return _target; }
/** Set what type of usage the buffer object will have. Options are:
* GL_STREAM_DRAW, GL_STREAM_READ, GL_STREAM_COPY,
* GL_STATIC_DRAW, GL_STATIC_READ, GL_STATIC_COPY,
* GL_DYNAMIC_DRAW, GL_DYNAMIC_READ, or GL_DYNAMIC_COPY.
*/
void setUsage(GLenum usage) { _usage = usage; }
/** Get the type of usage the buffer object has been set up for.*/
GLenum getUsage() const { return _usage; }
void dirty();
/** Resize any per context GLObject buffers to specified size. */
virtual void resizeGLObjectBuffers(unsigned int maxSize);
/** If State is non-zero, this function releases OpenGL objects for
* the specified graphics context. Otherwise, releases OpenGL objects
* for all graphics contexts. */
void releaseGLObjects(State* state=0) const;
unsigned int addBufferData(BufferData* bd);
void removeBufferData(unsigned int index);
void removeBufferData(BufferData* bd);
void setBufferData(unsigned int index, BufferData* bd);
BufferData* getBufferData(unsigned int index) { return _bufferDataList[index]; }
const BufferData* getBufferData(unsigned int index) const { return _bufferDataList[index]; }
unsigned int getNumBufferData() const { return _bufferDataList.size(); }
GLBufferObject* getGLBufferObject(unsigned int contextID) const { return _glBufferObjects[contextID].get(); }
GLBufferObject* getOrCreateGLBufferObject(unsigned int contextID) const
{
if (!_glBufferObjects[contextID]) _glBufferObjects[contextID] = GLBufferObject::createGLBufferObject(contextID, this);
return _glBufferObjects[contextID].get();
}
protected:
~BufferObject();
typedef std::vector< BufferData* > BufferDataList;
typedef osg::buffered_object< osg::ref_ptr<GLBufferObject> > GLBufferObjects;
GLenum _target;
GLenum _usage;
BufferDataList _bufferDataList;
mutable GLBufferObjects _glBufferObjects;
};
class BufferData : public Object
{
public:
BufferData():
Object(true),
_modifiedCount(0),
_bufferIndex(0) {}
/** Copy constructor using CopyOp to manage deep vs shallow copy.*/
BufferData(const BufferData& bd,const CopyOp& copyop=CopyOp::SHALLOW_COPY):
osg::Object(bd,copyop),
_modifiedCount(0),
_bufferIndex(0) {}
virtual bool isSameKindAs(const Object* obj) const { return dynamic_cast<const BufferData*>(obj)!=NULL; }
virtual const char* libraryName() const { return "osg"; }
virtual const char* className() const { return "BufferData"; }
virtual const GLvoid* getDataPointer() const = 0;
virtual unsigned int getTotalDataSize() const = 0;
void setBufferObject(BufferObject* bufferObject);
BufferObject* getBufferObject() { return _bufferObject.get(); }
const BufferObject* getBufferObject() const { return _bufferObject.get(); }
void setBufferIndex(unsigned int index) { _bufferIndex = index; }
unsigned int getBufferIndex() const { return _bufferIndex; }
GLBufferObject* getGLBufferObject(unsigned int contextID) const { return _bufferObject.valid() ? _bufferObject->getGLBufferObject(contextID) : 0; }
GLBufferObject* getOrCreateGLBufferObject(unsigned int contextID) const { return _bufferObject.valid() ? _bufferObject->getOrCreateGLBufferObject(contextID) : 0; }
/** Dirty the primitive, which increments the modified count, to force buffer objects to update. */
inline void dirty() { ++_modifiedCount; if (_bufferObject.valid()) _bufferObject->dirty(); }
/** Set the modified count value.*/
inline void setModifiedCount(unsigned int value) { _modifiedCount=value; }
/** Get modified count value.*/
inline unsigned int getModifiedCount() const { return _modifiedCount; }
protected:
virtual ~BufferData();
unsigned int _modifiedCount;
unsigned int _bufferIndex;
osg::ref_ptr<BufferObject> _bufferObject;
};
class Array;
class OSG_EXPORT VertexBufferObject : public BufferObject
{
public:
VertexBufferObject();
/** Copy constructor using CopyOp to manage deep vs shallow copy.*/
VertexBufferObject(const VertexBufferObject& vbo,const CopyOp& copyop=CopyOp::SHALLOW_COPY);
META_Object(osg,VertexBufferObject);
unsigned int addArray(osg::Array* array);
void removeArray(osg::Array* array);
void setArray(unsigned int i, Array* array);
Array* getArray(unsigned int i);
const Array* getArray(unsigned int i) const;
protected:
virtual ~VertexBufferObject();
};
class DrawElements;
class OSG_EXPORT ElementBufferObject : public BufferObject
{
public:
ElementBufferObject();
/** Copy constructor using CopyOp to manage deep vs shallow copy.*/
ElementBufferObject(const ElementBufferObject& pbo,const CopyOp& copyop=CopyOp::SHALLOW_COPY);
META_Object(osg,ElementBufferObject);
unsigned int addDrawElements(osg::DrawElements* PrimitiveSet);
void removeDrawElements(osg::DrawElements* PrimitiveSet);
void setDrawElements(unsigned int i, DrawElements* PrimitiveSet);
DrawElements* getDrawElements(unsigned int i);
const DrawElements* getDrawElements(unsigned int i) const;
protected:
virtual ~ElementBufferObject();
};
class Image;
class OSG_EXPORT PixelBufferObject : public BufferObject
{
public:
PixelBufferObject(osg::Image* image=0);
/** Copy constructor using CopyOp to manage deep vs shallow copy.*/
PixelBufferObject(const PixelBufferObject& pbo,const CopyOp& copyop=CopyOp::SHALLOW_COPY);
META_Object(osg,PixelBufferObject);
void setImage(osg::Image* image);
Image* getImage();
const Image* getImage() const;
bool isPBOSupported(unsigned int contextID) const { return _glBufferObjects[contextID]->isPBOSupported(); }
protected:
virtual ~PixelBufferObject();
};
/**
* This object represent a general class of pixel buffer objects,
* which are capable of allocating buffer object (memory)
* on the GPU. The memory can then be used either for CPU-GPU
* pixel transfer or directly for GPU-GPU transfer, without CPU intervention.
**/
class OSG_EXPORT PixelDataBufferObject : public BufferObject
{
public:
PixelDataBufferObject();
PixelDataBufferObject(const PixelDataBufferObject& pbo, const CopyOp& copyop=CopyOp::SHALLOW_COPY);
META_Object(osg, PixelDataBufferObject);
//! Set new size of the buffer object. This will reallocate the memory on the next compile
inline void setDataSize(unsigned int size) { _dataSize = size; dirty(); }
//! Get data size of the used buffer
inline unsigned int getDataSize() const { return _dataSize; }
//! Compile the buffer (reallocate the memory if buffer is dirty)
virtual void compileBuffer(State& state) const;
//! Bind the buffer in read mode, which means that data can be downloaded from the buffer (note: GL_PIXEL_UNPACK_BUFFER_ARB)
virtual void bindBufferInReadMode(State& state);
//! Bind the buffer in write mode, which means following OpenGL instructions will write data into the buffer (note: GL_PIXEL_PACK_BUFFER_ARB)
virtual void bindBufferInWriteMode(State& state);
//! Unbind the buffer
virtual void unbindBuffer(unsigned int contextID) const;
/** Resize any per context GLObject buffers to specified size. */
virtual void resizeGLObjectBuffers(unsigned int maxSize);
enum Mode
{
//! A normal mode of this data buffer
NONE = 0,
//! Buffer is in read mode (@see bindBufferInReadMode)
READ = 1,
//! Buffer is in write mode (@see bindBufferInWriteMode)
WRITE = 2
};
Mode getMode(unsigned int contextID) const { return (Mode)_mode[contextID]; }
protected:
virtual ~PixelDataBufferObject();
unsigned int _dataSize;
typedef osg::buffered_value<unsigned int> ModeList;
mutable ModeList _mode;
};
}
#endif