Added single buffered and double buffered PBO support, and --no-pbo,

--single-pbo and --double-pbo command line parameters
This commit is contained in:
Robert Osfield 2008-05-23 16:26:03 +00:00
parent f9f1aab67d
commit 90308d22aa

View File

@ -36,11 +36,19 @@ class WindowCaptureCallback : public osg::Camera::DrawCallback
{
public:
enum Mode
{
READ_PIXELS,
SINGLE_PBO,
DOUBLE_PBO
};
struct ContextData : public osg::Referenced
{
ContextData(osg::GraphicsContext* gc, const std::string& name):
ContextData(osg::GraphicsContext* gc, Mode mode, const std::string& name):
_gc(gc),
_mode(mode),
_fileName(name),
_pixelFormat(GL_RGB),
_type(GL_UNSIGNED_BYTE),
@ -57,8 +65,23 @@ class WindowCaptureCallback : public osg::Camera::DrawCallback
_imageBuffer.push_back(new osg::Image);
// double buffer PBO.
_pboBuffer.push_back(new osg::PixelBufferObject);
_pboBuffer.push_back(new osg::PixelBufferObject);
switch(_mode)
{
case(READ_PIXELS):
osg::notify(osg::NOTICE)<<"Reading window usig glReadPixels, with out PixelBufferObject."<<std::endl;
break;
case(SINGLE_PBO):
osg::notify(osg::NOTICE)<<"Reading window usig glReadPixels, with a single PixelBufferObject."<<std::endl;
_pboBuffer.push_back(0);
break;
case(DOUBLE_PBO):
osg::notify(osg::NOTICE)<<"Reading window usig glReadPixels, with a double buffer PixelBufferObject."<<std::endl;
_pboBuffer.push_back(0);
_pboBuffer.push_back(0);
break;
default:
break;
}
}
void getSize(osg::GraphicsContext* gc, int& width, int& height)
@ -72,39 +95,36 @@ class WindowCaptureCallback : public osg::Camera::DrawCallback
void read()
{
std::cout<<"Read to "<<_fileName<<" image "<<_currentImageIndex<<" "<<_currentPboIndex<<std::endl;
unsigned int nextImageIndex = (_currentImageIndex+1)%_imageBuffer.size();
unsigned int nextPboIndex = (_currentPboIndex+1)%_pboBuffer.size();
osg::BufferObject::Extensions* ext = osg::BufferObject::getExtensions(_gc->getState()->getContextID(),true);
int width=0, height=0;
getSize(_gc, width, height);
if (width!=_width || _height!=height)
if (ext->isPBOSupported() && !_pboBuffer.empty())
{
std::cout<<" Window resized "<<width<<", "<<height<<std::endl;
_width = width;
_height = height;
if (_pboBuffer.size()==1)
{
singlePBO(ext);
}
else
{
multiPBO(ext);
}
}
osg::Image* image = _imageBuffer[_currentImageIndex].get();
image->readPixels(0,0,_width,_height,
_pixelFormat,_type);
if (!_fileName.empty())
else
{
osgDB::writeImageFile(*image, _fileName);
readPixels();
}
_currentImageIndex = nextImageIndex;
_currentPboIndex = nextPboIndex;
}
void readPixels();
void singlePBO(osg::BufferObject::Extensions* ext);
void multiPBO(osg::BufferObject::Extensions* ext);
typedef std::vector< osg::ref_ptr<osg::Image> > ImageBuffer;
typedef std::vector< osg::ref_ptr<osg::PixelBufferObject> > PBOBuffer;
typedef std::vector< GLuint > PBOBuffer;
osg::GraphicsContext* _gc;
Mode _mode;
std::string _fileName;
GLenum _pixelFormat;
@ -119,7 +139,8 @@ class WindowCaptureCallback : public osg::Camera::DrawCallback
PBOBuffer _pboBuffer;
};
WindowCaptureCallback()
WindowCaptureCallback(Mode mode):
_mode(mode)
{
}
@ -127,7 +148,7 @@ class WindowCaptureCallback : public osg::Camera::DrawCallback
{
std::stringstream filename;
filename << "test_"<<_contextDataMap.size()<<".jpg";
return new ContextData(gc,filename.str());
return new ContextData(gc, _mode, filename.str());
}
ContextData* getContextData(osg::GraphicsContext* gc) const
@ -142,19 +163,200 @@ class WindowCaptureCallback : public osg::Camera::DrawCallback
virtual void operator () (osg::RenderInfo& renderInfo) const
{
osg::GraphicsContext* gc = renderInfo.getState()->getGraphicsContext();
osg::notify(osg::NOTICE)<<"Capture screen image "<<gc<<std::endl;
osg::ref_ptr<ContextData> cd = getContextData(gc);
cd->read();
}
typedef std::map<osg::GraphicsContext*, osg::ref_ptr<ContextData> > ContextDataMap;
Mode _mode;
mutable OpenThreads::Mutex _mutex;
mutable ContextDataMap _contextDataMap;
};
void WindowCaptureCallback::ContextData::readPixels()
{
// std::cout<<"readPixels("<<_fileName<<" image "<<_currentImageIndex<<" "<<_currentPboIndex<<std::endl;
unsigned int nextImageIndex = (_currentImageIndex+1)%_imageBuffer.size();
unsigned int nextPboIndex = _pboBuffer.empty() ? 0 : (_currentPboIndex+1)%_pboBuffer.size();
int width=0, height=0;
getSize(_gc, width, height);
if (width!=_width || _height!=height)
{
std::cout<<" Window resized "<<width<<", "<<height<<std::endl;
_width = width;
_height = height;
}
osg::Image* image = _imageBuffer[_currentImageIndex].get();
image->readPixels(0,0,_width,_height,
_pixelFormat,_type);
if (!_fileName.empty())
{
// osgDB::writeImageFile(*image, _fileName);
}
_currentImageIndex = nextImageIndex;
_currentPboIndex = nextPboIndex;
}
void WindowCaptureCallback::ContextData::singlePBO(osg::BufferObject::Extensions* ext)
{
// std::cout<<"singelPBO( "<<_fileName<<" image "<<_currentImageIndex<<" "<<_currentPboIndex<<std::endl;
unsigned int nextImageIndex = (_currentImageIndex+1)%_imageBuffer.size();
int width=0, height=0;
getSize(_gc, width, height);
if (width!=_width || _height!=height)
{
std::cout<<" Window resized "<<width<<", "<<height<<std::endl;
_width = width;
_height = height;
}
GLuint& pbo = _pboBuffer[0];
osg::Image* image = _imageBuffer[_currentImageIndex].get();
if (image->s() != _width ||
image->t() != _height)
{
osg::notify(osg::NOTICE)<<"Allocating image "<<std::endl;
image->allocateImage(_width, _height, 1, _pixelFormat, _type);
if (pbo!=0)
{
osg::notify(osg::NOTICE)<<"deleting pbo "<<pbo<<std::endl;
ext->glDeleteBuffers (1, &pbo);
pbo = 0;
}
}
if (pbo==0)
{
ext->glGenBuffers(1, &pbo);
ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, pbo);
ext->glBufferData(GL_PIXEL_PACK_BUFFER_ARB, image->getTotalSizeInBytes(), 0, GL_STREAM_READ);
osg::notify(osg::NOTICE)<<"Generating pbo "<<pbo<<std::endl;
}
else
{
ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, pbo);
}
glReadPixels(0, 0, _width, _height, _pixelFormat, _type, 0);
GLubyte* src = (GLubyte*)ext->glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB,
GL_READ_ONLY_ARB);
if(src)
{
memcpy(image->data(), src, image->getTotalSizeInBytes());
ext->glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB);
}
if (!_fileName.empty())
{
// osgDB::writeImageFile(*image, _fileName);
}
ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);
_currentImageIndex = nextImageIndex;
}
void WindowCaptureCallback::ContextData::multiPBO(osg::BufferObject::Extensions* ext)
{
// std::cout<<"multiPBO( "<<_fileName<<" image "<<_currentImageIndex<<" "<<_currentPboIndex<<std::endl;
unsigned int nextImageIndex = (_currentImageIndex+1)%_imageBuffer.size();
unsigned int nextPboIndex = (_currentPboIndex+1)%_pboBuffer.size();
int width=0, height=0;
getSize(_gc, width, height);
if (width!=_width || _height!=height)
{
std::cout<<" Window resized "<<width<<", "<<height<<std::endl;
_width = width;
_height = height;
}
GLuint& copy_pbo = _pboBuffer[_currentPboIndex];
GLuint& read_pbo = _pboBuffer[nextPboIndex];
osg::Image* image = _imageBuffer[_currentImageIndex].get();
if (image->s() != _width ||
image->t() != _height)
{
osg::notify(osg::NOTICE)<<"Allocating image "<<std::endl;
image->allocateImage(_width, _height, 1, _pixelFormat, _type);
if (read_pbo!=0)
{
osg::notify(osg::NOTICE)<<"deleting pbo "<<read_pbo<<std::endl;
ext->glDeleteBuffers (1, &read_pbo);
read_pbo = 0;
}
if (copy_pbo!=0)
{
osg::notify(osg::NOTICE)<<"deleting pbo "<<copy_pbo<<std::endl;
ext->glDeleteBuffers (1, &copy_pbo);
copy_pbo = 0;
}
}
if (read_pbo==0)
{
ext->glGenBuffers(1, &read_pbo);
ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, read_pbo);
ext->glBufferData(GL_PIXEL_PACK_BUFFER_ARB, image->getTotalSizeInBytes(), 0, GL_STREAM_READ);
osg::notify(osg::NOTICE)<<"Generating pbo "<<read_pbo<<std::endl;
}
else
{
ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, read_pbo);
}
glReadPixels(0, 0, _width, _height, _pixelFormat, _type, 0);
if (copy_pbo!=0)
{
ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, copy_pbo);
GLubyte* src = (GLubyte*)ext->glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB,
GL_READ_ONLY_ARB);
if(src)
{
memcpy(image->data(), src, image->getTotalSizeInBytes());
ext->glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB);
}
if (!_fileName.empty())
{
// osgDB::writeImageFile(*image, _fileName);
}
}
ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);
_currentImageIndex = nextImageIndex;
_currentPboIndex = nextPboIndex;
}
void addCallbackToViewer(osgViewer::ViewerBase& viewer, WindowCaptureCallback* callback)
{
osgViewer::ViewerBase::Windows windows;
@ -281,6 +483,11 @@ int main(int argc, char** argv)
// add the LOD Scale handler
viewer.addEventHandler(new osgViewer::LODScaleHandler);
WindowCaptureCallback::Mode mode = WindowCaptureCallback::DOUBLE_PBO;
while (arguments.read("--no-pbo")) mode = WindowCaptureCallback::READ_PIXELS;
while (arguments.read("--single-pbo")) mode = WindowCaptureCallback::SINGLE_PBO;
while (arguments.read("--double-pbo")) mode = WindowCaptureCallback::DOUBLE_PBO;
// load the data
osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
if (!loadedModel)
@ -308,7 +515,7 @@ int main(int argc, char** argv)
viewer.realize();
addCallbackToViewer(viewer, new WindowCaptureCallback);
addCallbackToViewer(viewer, new WindowCaptureCallback(mode));
return viewer.run();