/* -*-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 #include #include #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 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(obj)!=NULL; } virtual const char* libraryName() const { return "osg"; } virtual const char* className() const { return "BufferObject"; } /** 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; } struct BufferEntry { BufferEntry(): dataSize(0),offset(0) {} BufferEntry(const BufferEntry& be): modifiedCount(be.modifiedCount),dataSize(be.dataSize),offset(be.offset) {} BufferEntry& operator = (const BufferEntry& be) { modifiedCount=be.modifiedCount; dataSize=be.dataSize; offset=be.offset; return *this; } mutable buffered_value modifiedCount; mutable unsigned int dataSize; mutable unsigned int offset; }; inline bool isBufferObjectSupported(unsigned int contextID) const { return getExtensions(contextID,true)->isBufferObjectSupported(); } inline bool isPBOSupported(unsigned int contextID) const { return getExtensions(contextID,true)->isPBOSupported(); } inline GLuint& buffer(unsigned int contextID) const { return _bufferObjectList[contextID]; } inline void bindBuffer(unsigned int contextID) const { Extensions* extensions = getExtensions(contextID,true); extensions->glBindBuffer(_target,_bufferObjectList[contextID]); } virtual void unbindBuffer(unsigned int contextID) const { Extensions* extensions = getExtensions(contextID,true); extensions->glBindBuffer(_target,0); } inline void dirty() { _compiledList.setAllElementsTo(0); } bool isDirty(unsigned int contextID) const { return _compiledList[contextID]==0; } virtual void compileBuffer(State& state) const = 0; /** 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; /** 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 ~BufferObject(); typedef osg::buffered_value GLObjectList; typedef osg::buffered_value CompiledList; mutable GLObjectList _bufferObjectList; mutable CompiledList _compiledList; GLenum _target; GLenum _usage; mutable unsigned int _totalSize; }; 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); typedef std::pair< BufferEntry, Array* > BufferEntryArrayPair; typedef std::vector< BufferEntryArrayPair > BufferEntryArrayPairs; unsigned int addArray(osg::Array* array); void removeArray(osg::Array* array); void setArray(unsigned int i, Array* array); Array* getArray(unsigned int i) { return _bufferEntryArrayPairs[i].second; } const Array* getArray(unsigned int i) const { return _bufferEntryArrayPairs[i].second; } const GLvoid* getOffset(unsigned int i) const { return (const GLvoid*)(((char *)0)+(_bufferEntryArrayPairs[i].first.offset)); } virtual void compileBuffer(State& state) const; /** Resize any per context GLObject buffers to specified size. */ virtual void resizeGLObjectBuffers(unsigned int maxSize); protected: virtual ~VertexBufferObject(); BufferEntryArrayPairs _bufferEntryArrayPairs; }; 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); typedef std::pair< BufferEntry, DrawElements* > BufferEntryDrawElementsPair; typedef std::vector< BufferEntryDrawElementsPair > BufferEntryDrawElementsPairs; unsigned int addDrawElements(osg::DrawElements* PrimitiveSet); void removeDrawElements(osg::DrawElements* PrimitiveSet); void setDrawElements(unsigned int i, DrawElements* PrimitiveSet); DrawElements* getDrawElements(unsigned int i) { return _bufferEntryDrawElementsPairs[i].second; } const DrawElements* getDrawElements(unsigned int i) const { return _bufferEntryDrawElementsPairs[i].second; } const GLvoid* getOffset(unsigned int i) const { return (const GLvoid*)(((char *)0)+(_bufferEntryDrawElementsPairs[i].first.offset)); } virtual void compileBuffer(State& state) const; /** Resize any per context GLObject buffers to specified size. */ virtual void resizeGLObjectBuffers(unsigned int maxSize); protected: virtual ~ElementBufferObject(); BufferEntryDrawElementsPairs _bufferEntryDrawElementsPairs; }; 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); typedef std::pair< BufferEntry, Image* > BufferEntryImagePair; void setImage(osg::Image* image); Image* getImage() { return _bufferEntryImagePair.second; } const Image* getImage() const { return _bufferEntryImagePair.second; } unsigned int offset() const { return _bufferEntryImagePair.first.offset; } virtual void compileBuffer(State& state) const; /** Resize any per context GLObject buffers to specified size. */ virtual void resizeGLObjectBuffers(unsigned int maxSize); protected: virtual ~PixelBufferObject(); BufferEntryImagePair _bufferEntryImagePair; }; /** * 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) { _bufferData.dataSize = size; dirty(); } //! Get data size of the used buffer inline unsigned int getDataSize() { return _bufferData.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(); BufferEntry _bufferData; typedef osg::buffered_value ModeList; mutable ModeList _mode; }; } #endif