From Art Tevs, "here is a submission of an additional class of PixelBufferObejct, which implements more general way of handling with PBOs. Current osg implementation of PBO does use an attached osg::Image to copy data from. This is somehow only one way of using it and doesn't provide full functionality of PBOs.

--------------------------------------------
Descripton:

The patch does provide a new class PixelDataBufferObject which is capable of allocating memory on the GPU side (PBO memory) of arbitrary size. The memory can then further be used to be enabled into read mode (GL_PIXEL_UNPACK_BUFFER_ARB) or in write mode (GL_PIXEL_PACK_BUFFER_ARB). Enabling the buffer into write mode will force the driver to write data from bounded textures into that buffer (i.e. glGetTexImage). Using buffer in read mode give you the possibility to read data from the buffer into a texture with e.g. glTexSubImage or other instuctions. Hence no data is copied over the CPU (host memory), all the operations are done in the GPU memory.


--------------------------------------------
Compatibility:

The new class require the unbindBuffer method from the base class BufferObject to be virtual, which shouldn't break any functionality of already existing classes. Except of this the new class is fully orthogonal to existing one, hence can be safely added into already existing osg system.

--------------------------------------------
Testing:

The new class was tested in the current svn version of osgPPU. I am using the new class to copy data from textures into the PBO and hence provide them to CUDA kernels. Also reading the results back from CUDA is implemented using the provided patch. The given patch gives a possibility of easy interoperability between CUDA and osg (osgPPU ;) )


--------------------------------------------
I think in general it is a better way to derive the PixelBufferObject class from PixelDataBufferObject, since the second one is a generalization of the first one. However this could break the current functionality, hence I haven't implemented it in such a way. However I would push that on a stack of wished osg 3.x features, since this will reflect the OpenGL PBO functionality through the classes better.
"
This commit is contained in:
Robert Osfield 2008-12-01 13:28:13 +00:00
parent 5178a0ec66
commit f2c1a3ea8a
2 changed files with 162 additions and 1 deletions

View File

@ -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<unsigned int> ModeList;
mutable ModeList _mode;
};
}

View File

@ -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);
}