diff --git a/include/osg/BufferObject b/include/osg/BufferObject index e14d383f2..8bcf492da 100644 --- a/include/osg/BufferObject +++ b/include/osg/BufferObject @@ -146,7 +146,7 @@ class OSG_EXPORT BufferObject : public Object extensions->glBindBuffer(_target,_bufferObjectList[contextID]); } - inline void unbindBuffer(unsigned int contextID) const + virtual void unbindBuffer(unsigned int contextID) const { Extensions* extensions = getExtensions(contextID,true); extensions->glBindBuffer(_target,0); @@ -374,6 +374,67 @@ class OSG_EXPORT PixelBufferObject : public BufferObject 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; + +}; + } diff --git a/src/osg/BufferObject.cpp b/src/osg/BufferObject.cpp index bea417475..fe1994057 100644 --- a/src/osg/BufferObject.cpp +++ b/src/osg/BufferObject.cpp @@ -724,3 +724,103 @@ void PixelBufferObject::resizeGLObjectBuffers(unsigned int maxSize) _bufferEntryImagePair.first.modifiedCount.resize(maxSize); } + + +////////////////////////////////////////////////////////////////////////////////// +// +// PixelDataBufferObject +// +//-------------------------------------------------------------------------------- +PixelDataBufferObject::PixelDataBufferObject() +{ + _target = GL_ARRAY_BUFFER; + _usage = GL_DYNAMIC_DRAW_ARB; + _bufferData.dataSize = 0; +} + +//-------------------------------------------------------------------------------- +PixelDataBufferObject::PixelDataBufferObject(const PixelDataBufferObject& buffer,const CopyOp& copyop): + BufferObject(buffer,copyop), + _bufferData(buffer._bufferData) +{ +} + +//-------------------------------------------------------------------------------- +PixelDataBufferObject::~PixelDataBufferObject() +{ +} + +//-------------------------------------------------------------------------------- +void PixelDataBufferObject::compileBuffer(State& state) const +{ + unsigned int contextID = state.getContextID(); + if (!isDirty(contextID) || _bufferData.dataSize == 0) return; + + Extensions* extensions = getExtensions(contextID,true); + + GLuint& pbo = buffer(contextID); + if (pbo == 0) + { + extensions->glGenBuffers(1, &pbo); + } + + extensions->glBindBuffer(_target, pbo); + extensions->glBufferData(_target, _bufferData.dataSize, NULL, _usage); + extensions->glBindBuffer(_target, 0); + + _compiledList[contextID] = 1; +} + +//-------------------------------------------------------------------------------- +void PixelDataBufferObject::bindBufferInReadMode(State& state) +{ + unsigned int contextID = state.getContextID(); + if (isDirty(contextID)) compileBuffer(state); + + Extensions* extensions = getExtensions(contextID,true); + + extensions->glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, buffer(contextID)); + _mode[contextID] = READ; +} + +//-------------------------------------------------------------------------------- +void PixelDataBufferObject::bindBufferInWriteMode(State& state) +{ + unsigned int contextID = state.getContextID(); + if (isDirty(contextID)) compileBuffer(state); + + Extensions* extensions = getExtensions(contextID,true); + + extensions->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, buffer(contextID)); + _mode[contextID] = WRITE; +} + +//-------------------------------------------------------------------------------- +void PixelDataBufferObject::unbindBuffer(unsigned int contextID) const +{ + Extensions* extensions = getExtensions(contextID,true); + + switch(_mode[contextID]) + { + case READ: + extensions->glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB,0); + break; + case WRITE: + extensions->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB,0); + break; + default: + extensions->glBindBuffer(_target,0); + break; + } + + _mode[contextID] = NONE; +} + +//-------------------------------------------------------------------------------- +void PixelDataBufferObject::resizeGLObjectBuffers(unsigned int maxSize) +{ + BufferObject::resizeGLObjectBuffers(maxSize); + + _mode.resize(maxSize); +} +