I am confused about how to use PBOs in OSG. I browsed the forum quite a bit but still can't make my code work.
1) GPU -> CPU pixel transfers
As I understand it, an osg::Image with an osg::PixelBufferObject cannot be used (yet) to read FBO contents. I have actually checked that and could see that glReadPixels() still uses a client-side memory pointer. I believe this scenario is not supported yet. Not a big deal.
I understand it is possible to do this manually and follow for instance what is done in the osgscreencapture sample. This sample doesn't make use of osg::PixelBufferObject, and instead manually creates a GL PBO, manually calls glReadBuffer with a bound pixel buffer object.
2) CPU -> GPU pixel transfers
I gave this a go but cannot make it work yet. To see if the PBO is effectively used this time in my GL tracer I look at a current bound PBO and the last parameter of glTexImage2D, which would reflect an offset and not a client side pointer.
My code to create my texture, image and PBO is the following:
Code:
Image *image = osgDB:readImageFile(filePath);
// PBO image binding method 1 - this line has no effect for me
PixelBufferObject *pbo = new PixelBufferObject(image);
// PBO image binding method 2 - I get a crash in BufferObject::computeRequiredBufferSize here
image->setPixelBufferObject(new PixelBufferObject());
Texture2D *texture = new Texture2D(image);
geode->getOrCreateStateSet()->setTextureAttributeAndMode(0, texture, StateSet::ON);
I don't see any PBO created in the GL trace, and glTexImage2D still reads image data off a client side pointer.
What I am doing wrong?
Cheers,
Fred
------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=34527#34527
_______________________________________________
osg-users mailing list
osg-...@lists.openscenegraph.org
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
This looks like a bug to me. The following code works:
> Image *image = new Image();
> image->allocate(256, 256, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1);
> image->setPixelBufferObject(new PixelBufferObject(image));
> Texture2D *texture = new Texture2D();
> texture->setImage(image);
>
The following doesn't work:
> Image *image = osgDB::readImageFile(...);
> image->setPixelBufferObject(new PixelBufferObject(image));
> // I've tried image->dirty(); here, too
> Texture2D *texture = new Texture2D();
> texture->setImage(image);
>
In the second case, a GL tracer shows that glGenBuffers(1, ...); is called, but nothing is done beyond that.
Long story short, if you create an Image with osgDB::readImageFile(), things don't work. Surprisingly enough, dirty() makes no difference.
Cheers,
Fred
------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=34534#34534
The PBO support built into osg::Texture/osg::Image for passing image
data from the osg::Image to the texture, and does not presently
support reading the result back.
When doing read back using PBO's the situation is a little more
convoluted than when passing data from main memory to the GPU, it's
less of an API issue and more of performance issue. PBO's enable
async data transfer to the GPU, which is where the performance benefit
comes from. Copying data back from the GPU is different though, it
still has to be synchronous unless you double buffer the PBO's and get
the result not in the current frame, but the following frame. This
double buffering and handling of a frame latency requires a high level
management of the operations. Without the double buffering and
retrieving the results in the next frame PBO's don't offer any
performance benefit or straight glReadPixels.
If osgscreencapture examples has code paths to using PBO's and double
buffering so go have a look at how it does things. I'm afraid it's a
lot more complicated than just adding a PBO to an osg::Image, and it
won't be possible ever to implement in such a straight forward maner.
Robert.
Let's leave GPU -> CPU transfers aside. I don't mind if they are slow.
You usually have to use 2 PBOs.
If I use a single PBO to upload texture data to the GPU, performance will be very low.
It seems to me I have two ways to do CPU -> GPU transfers efficiently.
1) Use 2 differents PBOs. Let glTexImage2D do its job with the first PBO, while I'm loading up new data into the second PBO with the CPU.
2) Use 1 PBO and the method below (feedback?)
Code:
// Bind PBO
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbo);
Label1:
// Request new buffer data (third parameter = NULL)
// This call will return immediately. **The GPU will complete any transfer in progress with the previous buffer data**.
// As far as the client side is concerned, the new buffer data is immediately available.
glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, DATA_SIZE, NULL, GL_STREAM_DRAW_ARB);
// Load up new pixels into the same pbo, but into its new buffer data (requested above), not the previous one
glMapBuffer // returns immediately, because the GPU isn't doing anything with the new buffer
updatePixels
glUnmapBuffer
// Issue asynchronous transfer to texture
glTexImage2D(......, 0);
goto Label1;
This method above which should work (I think!) will most likely not be supported by OSG at all. I'll have to do things manually.
However perhaps I can resort to method 1 and do something by fiddling with two osg::PixelBufferObject objects, two osg::Image objects, creating as many osg::Textures as I want, alternating osg::Texture::setImage(image1) and osg::Texture::setImage(image2), to be sure I am doing CPU and GPU work in parrallel.
Thanks,
Fred
------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=34554#34554
I have too much other work on right now to go chasing supports threads
at a low level, I have time to point users in roughly the right
direction, but then have to get back to work - I have 3.0 to get out
the door.
Robert.
what bandwidth are you trying to achieve? We've had no issues with
updating multiple osg Images from camera input with just a PBO attached
as per e.g.:
osg_image_buffer[i]->setPixelBufferObject(new
osg::PixelBufferObject(osg_image_buffer[i].get()));
where osg_image_buffer[i] is a ref_ptr to osg::Image.
jp
--
This message is subject to the CSIR's copyright terms and conditions, e-mail legal notice, and implemented Open Document Format (ODF) standard.
The full disclaimer details can be found at http://www.csir.co.za/disclaimer.html.
This message has been scanned for viruses and dangerous content by MailScanner,
and is believed to be clean. MailScanner thanks Transtec Computers for their support.
Let's say you have 1000 textures. You can't create 1000 PBOs as this would consume far too much memory.
What you do is play with 2 PBOs. Have a look at the diagram here, in the figure called "Streaming texture uploads with 2 PBOs":
http://www.songho.ca/opengl/gl_pbo.html#unpack
You load data into a first PBO with the CPU while the GPU loads texture data from another PBO.
Now have a look at this thread:
This is the second method I mentionned above. It is called buffer orphaning by some people. People use this method to avoid fiddling with two PBOs. This method feels more natural to me.
How can I implement this using multiple texture objects and only one osg::PixelBufferObject?
Cheers,
Fred
NB: the songho.ca page uses buffer orphaning too - the thread on opengl.org is all about saying, providing you use orphaning, using only one PBO is sufficient
------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=34633#34633
On 08/12/10 20:22, Fred Smith wrote:
> Hi J.P.,
>
> Let's say you have 1000 textures. You can't create 1000 PBOs as this
> would consume far too much memory.
Can you explain at a higher level what you want to do. Do you just have
1000 textures you want to upload once? Or do you have 1000 textures you
want to update every frame? Are they the same size?
>
> What you do is play with 2 PBOs. Have a look at the diagram here, in
> the figure called "Streaming texture uploads with 2 PBOs":
> http://www.songho.ca/opengl/gl_pbo.html#unpack
>
> You load data into a first PBO with the CPU while the GPU loads
> texture data from another PBO.
Yes, I know this concept, we use it for downloading data from GPU to
CPU, but not for 1000s of textures.
>
> Now have a look at this thread:
>
> http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=276595&Searchpage=1&Main=53356&Words=orphan&Search=true#Post276595
>
> This is the second method I mentionned above. It is called buffer
> orphaning by some people. People use this method to avoid fiddling
> with two PBOs. This method feels more natural to me.
>
> How can I implement this using multiple texture objects and only one
> osg::PixelBufferObject?
I suppose you can just do all of this in a callback with just some of
your own OpenGL code. Have a look at osg::PixelDataBufferObject. AFAIR
it was created by Art Tevs for osgPPU for fast transfers. You can also
look at osgPPU for examples of its use. You will have to look at code to
see if it does orphaning correctly or if you can use one buffers object
for multiple textures.
See below for a snippet for reading back we use. Maybe something similar
for upload can be done.
Good luck
jp
--8<--
struct GPURegionOfInterestCallback : public osg::Camera::DrawCallback
{
GPURegionOfInterestCallback(ImageFormat& imf,
osg::Image *osg_im,
osg::TextureRectangle *tex) :
ImageFormat_(imf),
osg_im_(osg_im),
trect_(tex)
{
pdbo_ = new osg::PixelDataBufferObject();
pdbo_->setDataSize(ImageFormat_.getBytesPerImage());
}
virtual void operator() (osg::RenderInfo& renderInfo) const
{
// first get the texture into the pbo
pdbo_->bindBufferInWriteMode(*renderInfo.getState());
renderInfo.getState()->applyTextureAttribute(0, //unit
trect_);
glGetTexImage(trect_->getTextureTarget(),
0, //level
GL_LUMINANCE,
GL_UNSIGNED_BYTE,
NULL);
// now copy to cpu
osg::GLBufferObject::Extensions* ext =
osg::GLBufferObject::getExtensions(renderInfo.getState()->getContextID(), true);
GLubyte* src =
(GLubyte*)ext->glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB,
GL_READ_ONLY_ARB);
if(src)
{
memcpy(osg_im_->data(), src,
osg_im_->getTotalSizeInBytes());
ext->glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB);
}
pdbo_->unbindBuffer(renderInfo.getState()->getContextID());
/*
// direct to image from texture
renderInfo.getState()->applyTextureAttribute(0, //unit
trect_);
glGetTexImage(trect_->getTextureTarget(),
0, //level
GL_LUMINANCE,
GL_UNSIGNED_BYTE,
osg_im_->data());
*/
}
ImageFormat ImageFormat_;
osg::Image* osg_im_;
osg::TextureRectangle* trect_;
osg::ref_ptr<osg::PixelDataBufferObject> pdbo_;
};
--8<--
>
> Cheers, Fred
>
> NB: the songho.ca page uses buffer orphaning too - the thread on
> opengl.org is all about saying, providing you use orphaning, using
> only one PBO is sufficient
>
> ------------------ Read this topic online here:
> http://forum.openscenegraph.org/viewtopic.php?p=34633#34633
>
>
>
>
>
> _______________________________________________ osg-users mailing
> list osg-...@lists.openscenegraph.org
> http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
>
--
This message is subject to the CSIR's copyright terms and conditions, e-mail legal notice, and implemented Open Document Format (ODF) standard.
The full disclaimer details can be found at http://www.csir.co.za/disclaimer.html.
This message has been scanned for viruses and dangerous content by MailScanner,
and is believed to be clean. MailScanner thanks Transtec Computers for their support.
_______________________________________________