From 014f13f774cba4275f30dcb929bed539d73da40b Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 8 Nov 2012 11:19:31 +0000 Subject: [PATCH] Refactored ImageSequence to better handle random access usage. --- .../osgimagesequence/osgimagesequence.cpp | 4 +- include/osg/ImageSequence | 48 ++-- include/osg/NodeVisitor | 2 +- include/osg/PagedLOD | 6 +- include/osgDB/ImagePager | 12 +- src/osg/ImageSequence.cpp | 207 +++++++++--------- src/osgDB/ImagePager.cpp | 33 ++- src/osgDB/Registry.cpp | 7 +- src/osgPlugins/ive/ImageSequence.cpp | 18 +- src/osgPresentation/SlideShowConstructor.cpp | 28 ++- .../deprecated-dotosg/osg/ImageSequence.cpp | 26 +-- .../serializers/osg/ImageSequence.cpp | 28 +-- 12 files changed, 228 insertions(+), 191 deletions(-) diff --git a/examples/osgimagesequence/osgimagesequence.cpp b/examples/osgimagesequence/osgimagesequence.cpp index d4c2a6eed..7246d6d73 100644 --- a/examples/osgimagesequence/osgimagesequence.cpp +++ b/examples/osgimagesequence/osgimagesequence.cpp @@ -130,9 +130,7 @@ osg::StateSet* createState(osg::ArgumentParser& arguments) } else { - unsigned int maxNum = osg::maximum(imageSequence->getFileNames().size(), - imageSequence->getImages().size()); - + unsigned int maxNum = imageSequence->getNumImageData(); imageSequence->setLength(double(maxNum)*(1.0/fps)); } } diff --git a/include/osg/ImageSequence b/include/osg/ImageSequence index 9cc4a0bfa..5ab254946 100644 --- a/include/osg/ImageSequence +++ b/include/osg/ImageSequence @@ -48,8 +48,18 @@ class OSG_EXPORT ImageSequence : public ImageStream virtual void setTimeMultiplier(double tm) { _timeMultiplier = tm; } virtual double getTimeMultiplier() const { return _timeMultiplier; } - typedef std::vector< osg::ref_ptr > Images; - typedef std::vector< std::string > FileNames; + struct OSG_EXPORT ImageData + { + ImageData(); + ImageData(const ImageData& id); + ImageData& operator = (const ImageData& id); + + std::string _filename; + osg::ref_ptr _image; + osg::ref_ptr _imageRequest; + }; + + typedef std::vector ImageDataList; virtual void seek(double time); @@ -78,11 +88,6 @@ class OSG_EXPORT ImageSequence : public ImageStream void setImageFile(unsigned int pos, const std::string& fileName); std::string getImageFile(unsigned int pos) const; - unsigned int getNumImageFiles() const { return _fileNames.size(); } - - FileNames& getFileNames() { return _fileNames; } - const FileNames& getFileNames() const { return _fileNames; } - void addImage(osg::Image* image); void setImage(int s,int t,int r, @@ -96,24 +101,35 @@ class OSG_EXPORT ImageSequence : public ImageStream Image* getImage(unsigned int pos); const Image* getImage(unsigned int pos) const; - unsigned int getNumImages() const { return _images.size(); } + unsigned int getNumImageData() const { return _imageDataList.size(); } - Images& getImages() { return _images; } - const Images& getImages() const { return _images; } + ImageDataList& getImageDataList() { return _imageDataList; } + const ImageDataList& getImageDataList() const { return _imageDataList; } + /** ImageSequence requires a call to update(NodeVisitor*) during the update traversal so return true.*/ virtual bool requiresUpdateCall() const { return true; } /** update method for osg::Image subclasses that update themselves during the update traversal.*/ virtual void update(NodeVisitor* nv); - protected: + + /** Set the optional osgDB::Options object to use when reading images.*/ + void setReadOptions(osg::Referenced* options) { _readOptions = options; } + + /** Get the optional osgDB::Options object used when reading images.*/ + osg::Referenced* getReadOptions() { return _readOptions.get(); } + + /** Get the optional osgDB::Options object used when reading images.*/ + const osg::Referenced* getReadOptions() const { return _readOptions.get(); } + +protected: virtual ~ImageSequence() {} virtual void applyLoopingMode(); - void setImageToChild(const osg::Image* image); + void setImageToChild(int pos); void computeTimePerImage(); @@ -129,12 +145,8 @@ class OSG_EXPORT ImageSequence : public ImageStream double _timePerImage; mutable OpenThreads::Mutex _mutex; - FileNames _fileNames; - Images _images; - - typedef std::set< std::string > FilesRequested; - FilesRequested _filesRequested; + ImageDataList _imageDataList; int _previousAppliedImageIndex; @@ -142,7 +154,7 @@ class OSG_EXPORT ImageSequence : public ImageStream bool _seekTimeSet; double _seekTime; - + osg::ref_ptr _readOptions; }; diff --git a/include/osg/NodeVisitor b/include/osg/NodeVisitor index 7e8a7e5c7..14e9aef9a 100644 --- a/include/osg/NodeVisitor +++ b/include/osg/NodeVisitor @@ -308,7 +308,7 @@ class OSG_EXPORT NodeVisitor : public virtual Referenced virtual osg::Image* readImageFile(const std::string& fileName) = 0; - virtual void requestImageFile(const std::string& fileName,osg::Object* attachmentPoint, int attachmentIndex, double timeToMergeBy, const FrameStamp* framestamp) = 0; + virtual void requestImageFile(const std::string& fileName,osg::Object* attachmentPoint, int attachmentIndex, double timeToMergeBy, const FrameStamp* framestamp, osg::ref_ptr& imageRequest, const osg::Referenced* options=0) = 0; protected: virtual ~ImageRequestHandler() {} diff --git a/include/osg/PagedLOD b/include/osg/PagedLOD index 17b2cd626..b88c76c6f 100644 --- a/include/osg/PagedLOD +++ b/include/osg/PagedLOD @@ -44,13 +44,13 @@ class OSG_EXPORT PagedLOD : public LOD virtual bool removeChildren(unsigned int pos,unsigned int numChildrenToRemove=1); - /** Set the optional database osgDB::Options object to use when loaded children.*/ + /** Set the optional database osgDB::Options object to use when reading children.*/ void setDatabaseOptions(osg::Referenced* options) { _databaseOptions = options; } - /** Get the optional database osgDB::Options object used when loaded children.*/ + /** Get the optional database osgDB::Options object used when reading children.*/ osg::Referenced* getDatabaseOptions() { return _databaseOptions.get(); } - /** Get the optional database osgDB::Options object used when loaded children.*/ + /** Get the optional database osgDB::Options object used when reading children.*/ const osg::Referenced* getDatabaseOptions() const { return _databaseOptions.get(); } diff --git a/include/osgDB/ImagePager b/include/osgDB/ImagePager index 0564112f7..cd3245f2a 100644 --- a/include/osgDB/ImagePager +++ b/include/osgDB/ImagePager @@ -60,10 +60,10 @@ class OSGDB_EXPORT ImagePager : public osg::NodeVisitor::ImageRequestHandler virtual ~ImageThread(); - bool _done; - Mode _mode; - ImagePager* _pager; - std::string _name; + bool _done; + Mode _mode; + ImagePager* _pager; + std::string _name; }; @@ -79,8 +79,7 @@ class OSGDB_EXPORT ImagePager : public osg::NodeVisitor::ImageRequestHandler virtual osg::Image* readImageFile(const std::string& fileName); - virtual void requestImageFile(const std::string& fileName,osg::Object* attachmentPoint, int attachmentIndex, double timeToMergeBy, const osg::FrameStamp* framestamp); - + virtual void requestImageFile(const std::string& fileName, osg::Object* attachmentPoint, int attachmentIndex, double timeToMergeBy, const osg::FrameStamp* framestamp, osg::ref_ptr& imageRequest, const osg::Referenced* options); /** Return true if there are pending updates to the scene graph that require a call to updateSceneGraph(double). */ virtual bool requiresUpdateSceneGraph() const; @@ -113,6 +112,7 @@ class OSGDB_EXPORT ImagePager : public osg::NodeVisitor::ImageRequestHandler int _attachmentIndex; osg::ref_ptr _loadedImage; RequestQueue* _requestQueue; + osg::ref_ptr _readOptions; }; diff --git a/src/osg/ImageSequence.cpp b/src/osg/ImageSequence.cpp index 68639bf0a..6a349d4f4 100644 --- a/src/osg/ImageSequence.cpp +++ b/src/osg/ImageSequence.cpp @@ -22,6 +22,28 @@ using namespace osg; +ImageSequence::ImageData::ImageData() +{ +} + +ImageSequence::ImageData::ImageData(const ImageData& id): + _filename(id._filename), + _image(id._image), + _imageRequest(id._imageRequest) +{ +} + +ImageSequence::ImageData& ImageSequence::ImageData::operator = (const ImageSequence::ImageData& rhs) +{ + if (&rhs!=this) + { + _filename = rhs._filename; + _image = rhs._image; + _imageRequest = rhs._imageRequest; + } + return *this; +} + ImageSequence::ImageSequence() { _referenceTime = DBL_MAX; @@ -96,8 +118,7 @@ void ImageSequence::setLength(double length) void ImageSequence::computeTimePerImage() { - if (!_fileNames.empty()) _timePerImage = _length / double(_fileNames.size()); - else if (!_images.empty()) _timePerImage = _length / double(_images.size()); + if (!_imageDataList.empty()) _timePerImage = _length / double(_imageDataList.size()); else _timePerImage = _length; } @@ -105,20 +126,21 @@ void ImageSequence::setImageFile(unsigned int pos, const std::string& fileName) { OpenThreads::ScopedLock lock(_mutex); - if (pos>=_fileNames.size()) _fileNames.resize(pos); - _fileNames[pos] = fileName; + if (pos>=_imageDataList.size()) _imageDataList.resize(pos); + _imageDataList[pos]._filename = fileName; } std::string ImageSequence::getImageFile(unsigned int pos) const { OpenThreads::ScopedLock lock(_mutex); - return pos<_fileNames.size() ? _fileNames[pos] : std::string(); + return pos<_imageDataList.size() ? _imageDataList[pos]._filename : std::string(); } void ImageSequence::addImageFile(const std::string& fileName) { OpenThreads::ScopedLock lock(_mutex); - _fileNames.push_back(fileName); + _imageDataList.push_back(ImageData()); + _imageDataList.back()._filename = fileName; computeTimePerImage(); } @@ -126,27 +148,22 @@ void ImageSequence::setImage(unsigned int pos, osg::Image* image) { OpenThreads::ScopedLock lock(_mutex); - OSG_INFO<<"ImageSequence::setImage("<getFileName()<<")"<=_imageDataList.size()) _imageDataList.resize(pos+1); - if (pos>=_images.size()) _images.resize(pos+1); - - _images[pos] = image; - - // prune from file requested list. - FilesRequested::iterator itr = _filesRequested.find(image->getFileName()); - if (itr!=_filesRequested.end()) _filesRequested.erase(itr); + _imageDataList[pos]._image = image; + _imageDataList[pos]._filename = image->getFileName(); } Image* ImageSequence::getImage(unsigned int pos) { OpenThreads::ScopedLock lock(_mutex); - return pos<_images.size() ? _images[pos].get() : 0; + return pos<_imageDataList.size() ? _imageDataList[pos]._image.get() : 0; } const Image* ImageSequence::getImage(unsigned int pos) const { OpenThreads::ScopedLock lock(_mutex); - return pos<_images.size() ? _images[pos].get() : 0; + return pos<_imageDataList.size() ? _imageDataList[pos]._image.get() : 0; } void ImageSequence::addImage(osg::Image* image) @@ -156,24 +173,56 @@ void ImageSequence::addImage(osg::Image* image) OpenThreads::ScopedLock lock(_mutex); // OSG_NOTICE<<"merging image in order expected : "<getFileName()<=0 && pos(_imageDataList.size())) ? _imageDataList[pos]._image.get() : 0; if (image==0) return; // check to see if data is changing, if not don't apply - if (image->data() == data()) return; + if (image->data() == data()) + { + return; + } + + + if (_mode==PAGE_AND_DISCARD_USED_IMAGES && _previousAppliedImageIndex>=0) + { + if (_previousAppliedImageIndexpos) + { + OSG_INFO<<"Moving back from "<<_previousAppliedImageIndex<<" to "<pos) + { + _imageDataList[_previousAppliedImageIndex]._image = 0; + OSG_INFO<<" deleting "<<_previousAppliedImageIndex<s(),image->t(),image->r(), image->getInternalTextureFormat(), @@ -197,7 +246,7 @@ int ImageSequence::imageIndex(double time) if (time<0.0) return 0; int index = int(time/_timePerImage); - if (index>=int(_images.size())) return int(_images.size())-1; + if (index>=int(_imageDataList.size())) return int(_imageDataList.size())-1; return index; } @@ -222,6 +271,7 @@ void ImageSequence::update(osg::NodeVisitor* nv) if (_seekTimeSet || _status==PAUSED || _status==INVALID) { time = _seekTime; + useDirectTimeRequest = true; _referenceTime = fs->getSimulationTime() - time/_timeMultiplier; } else @@ -247,51 +297,33 @@ void ImageSequence::update(osg::NodeVisitor* nv) _seekTime = time; _seekTimeSet = false; - bool pruneOldImages = false; - - switch(_mode) + if (irh && _mode==PRE_LOAD_ALL_IMAGES) { - case(PRE_LOAD_ALL_IMAGES): + for(ImageDataList::iterator itr = _imageDataList.begin(); + itr != _imageDataList.end(); + ++itr) { - if (irh && _fileNames.size()>_images.size()) + if (!(itr->_image) && !(itr->_filename.empty())) { - FileNames::iterator itr = _fileNames.begin(); - for(unsigned int i=0;i<_images.size();++i) ++itr; - - for(; itr!=_fileNames.end(); ++itr) - { - osg::Image* image = irh->readImageFile(*itr); - _images.push_back(image); - } + itr->_image = irh->readImageFile(itr->_filename); } - - irh = 0; - break; - } - case(PAGE_AND_RETAIN_IMAGES): - { - break; - } - case(PAGE_AND_DISCARD_USED_IMAGES): - { - pruneOldImages = true; - break; } } int index = int(time/_timePerImage); // OSG_NOTICE<<"time= "<=0 && !_images[index].valid()) + while (index>=0 && !_imageDataList[index]._image.valid()) { --index; } @@ -299,34 +331,16 @@ void ImageSequence::update(osg::NodeVisitor* nv) else if (_previousAppliedImageIndex>index) { OSG_DEBUG<<"ImageSequence::update(..) Moving back by "<<_previousAppliedImageIndex-index<(_images.size()) && !_images[index].valid()) + while (index(_imageDataList.size()) && !_imageDataList[index]._image.valid()) { ++index; } } - else - { - // OSG_NOTICE<<"ImageSequence::update(..) Same index."<=0) + + if (index>=0 && index!=_previousAppliedImageIndex) { - // OSG_NOTICE<<"at time "<_fileName<<"), size()="<<_requestList.size()< image = osgDB::readImageFile(imageRequest->_fileName); + // OSG_NOTICE<<"doing readImageFile("<_fileName<<") index to assign = "<_attachmentIndex< image = osgDB::readImageFile(imageRequest->_fileName, imageRequest->_readOptions.get()); if (image.valid()) { + // OSG_NOTICE<<" successful readImageFile("<_fileName<<") index to assign = "<_attachmentIndex<(imageRequest->_attachmentPoint.get()); if (is) { @@ -266,12 +269,13 @@ ImagePager::ImagePager(): _readQueue = new ReadQueue(this,"Image Queue"); _completedQueue = new RequestQueue; _imageThreads.push_back(new ImageThread(this, ImageThread::HANDLE_ALL_REQUESTS, "Image Thread 1")); +#if 1 _imageThreads.push_back(new ImageThread(this, ImageThread::HANDLE_ALL_REQUESTS, "Image Thread 2")); _imageThreads.push_back(new ImageThread(this, ImageThread::HANDLE_ALL_REQUESTS, "Image Thread 3")); _imageThreads.push_back(new ImageThread(this, ImageThread::HANDLE_ALL_REQUESTS, "Image Thread 4")); _imageThreads.push_back(new ImageThread(this, ImageThread::HANDLE_ALL_REQUESTS, "Image Thread 5")); _imageThreads.push_back(new ImageThread(this, ImageThread::HANDLE_ALL_REQUESTS, "Image Thread 6")); - +#endif // 1 second _preLoadTime = 1.0; } @@ -314,9 +318,21 @@ osg::Image* ImagePager::readImageFile(const std::string& fileName) return osgDB::readImageFile(fileName); } -void ImagePager::requestImageFile(const std::string& fileName,osg::Object* attachmentPoint, int attachmentIndex, double timeToMergeBy, const osg::FrameStamp*) +void ImagePager::requestImageFile(const std::string& fileName, osg::Object* attachmentPoint, int attachmentIndex, double timeToMergeBy, const osg::FrameStamp* framestamp, osg::ref_ptr& imageRequest, const osg::Referenced* options) { - OSG_INFO<<"ImagePager::requestNodeFile("<(const_cast(options)); + if (!readOptions) + { + readOptions = Registry::instance()->getOptions(); + } + + bool alreadyAssigned = dynamic_cast(imageRequest.get()) && (imageRequest->referenceCount()>1); + if (alreadyAssigned) + { + // OSG_NOTICE<<"ImagePager::requestImageFile("< request = new ImageRequest; request->_timeToMergeBy = timeToMergeBy; @@ -324,6 +340,11 @@ void ImagePager::requestImageFile(const std::string& fileName,osg::Object* attac request->_attachmentPoint = attachmentPoint; request->_attachmentIndex = attachmentIndex; request->_requestQueue = _readQueue.get(); + request->_readOptions = readOptions; + + imageRequest = request; + + // OSG_NOTICE<<"ImagePager::requestImageFile("<add(request.get()); diff --git a/src/osgDB/Registry.cpp b/src/osgDB/Registry.cpp index 2aae0f56c..15e144a55 100644 --- a/src/osgDB/Registry.cpp +++ b/src/osgDB/Registry.cpp @@ -1299,6 +1299,7 @@ ReaderWriter::ReadResult Registry::readImplementation(const ReadFunctor& readFun const Options* options=readFunctor._options; useObjectCache=options ? (options->getObjectCacheHint()&cacheHint)!=0: false; } + if (useObjectCache) { // search for entry in the object cache. @@ -1307,7 +1308,7 @@ ReaderWriter::ReadResult Registry::readImplementation(const ReadFunctor& readFun ObjectCache::iterator oitr=_objectCache.find(file); if (oitr!=_objectCache.end()) { - OSG_NOTIFY(INFO)<<"returning cached instanced of "<second.first.get())) return ReaderWriter::ReadResult(oitr->second.first.get(), ReaderWriter::ReadResult::FILE_LOADED_FROM_CACHE); else return ReaderWriter::ReadResult("Error file does not contain an osg::Object"); } @@ -1317,12 +1318,12 @@ ReaderWriter::ReadResult Registry::readImplementation(const ReadFunctor& readFun if (rr.validObject()) { // update cache with new entry. - OSG_NOTIFY(INFO)<<"Adding to object cache "<writeInt(getMode()); out->writeDouble(getLength()); - out->writeUInt(getFileNames().size()); - for(FileNames::iterator itr = getFileNames().begin(); - itr != getFileNames().end(); + out->writeUInt(getImageDataList().size()); + for(ImageDataList::iterator itr = getImageDataList().begin(); + itr != getImageDataList().end(); ++itr) { - out->writeString(*itr); + out->writeString(itr->_filename); } - if (getFileNames().empty()) + if (getImageDataList().empty()) { - out->writeUInt(getImages().size()); - for(Images::iterator itr = getImages().begin(); - itr != getImages().end(); - ++itr) - { - out->writeImage(itr->get()); - } + out->writeUInt(0); } } diff --git a/src/osgPresentation/SlideShowConstructor.cpp b/src/osgPresentation/SlideShowConstructor.cpp index 13aa95940..2fbcec08a 100644 --- a/src/osgPresentation/SlideShowConstructor.cpp +++ b/src/osgPresentation/SlideShowConstructor.cpp @@ -999,15 +999,37 @@ osg::Image* SlideShowConstructor::readImage(const std::string& filename, const I } } +#if 0 + if (imageSequence->getMode()==osg::ImageSequence::PAGE_AND_DISCARD_USED_IMAGES) + { + + if (_options.valid()) + { + OSG_NOTICE<<"Object cache usage _options "<getObjectCacheHint()< options = _options.valid() ? _options->cloneOptions() : (new osgDB::Options); + if (!imageData.options.empty()) + { + options->setOptionString(imageData.options); + } + OSG_NOTICE<<"Disabling object cache usage"<setObjectCacheHint(osgDB::Options::CACHE_NONE); + imageSequence->setReadOptions(options); + } +#endif if (imageData.duration>0.0) { imageSequence->setLength(imageData.duration); } else { - unsigned int maxNum = osg::maximum(imageSequence->getFileNames().size(), - imageSequence->getImages().size()); - + unsigned int maxNum = imageSequence->getNumImageData(); imageSequence->setLength(double(maxNum)*(1.0/imageData.fps)); } diff --git a/src/osgWrappers/deprecated-dotosg/osg/ImageSequence.cpp b/src/osgWrappers/deprecated-dotosg/osg/ImageSequence.cpp index 50bd891d2..004be7e05 100644 --- a/src/osgWrappers/deprecated-dotosg/osg/ImageSequence.cpp +++ b/src/osgWrappers/deprecated-dotosg/osg/ImageSequence.cpp @@ -107,33 +107,17 @@ bool ImageSequence_writeLocalData(const Object& obj, Output& fw) fw.indent()<<"Length "<0) { fw.indent()<<"FileNames {"<getFileName().empty()) fw.indent()<getFileName())<_filename)<0; + return image.getNumImageData()>0; } static bool readFileNames( osgDB::InputStream& is, osg::ImageSequence& image ) @@ -23,12 +23,13 @@ static bool readFileNames( osgDB::InputStream& is, osg::ImageSequence& image ) static bool writeFileNames( osgDB::OutputStream& os, const osg::ImageSequence& image ) { - const osg::ImageSequence::FileNames& files = image.getFileNames(); - os.writeSize(files.size()); os << os.BEGIN_BRACKET << std::endl; - for ( osg::ImageSequence::FileNames::const_iterator itr=files.begin(); - itr!=files.end(); ++itr ) + const osg::ImageSequence::ImageDataList& imageDataList = image.getImageDataList(); + os.writeSize(imageDataList.size()); os << os.BEGIN_BRACKET << std::endl; + for ( osg::ImageSequence::ImageDataList::const_iterator itr=imageDataList.begin(); + itr!=imageDataList.end(); + ++itr ) { - os.writeWrappedString( *itr ); + os.writeWrappedString( itr->_filename ); os << std::endl; } os << os.END_BRACKET << std::endl; @@ -38,7 +39,7 @@ static bool writeFileNames( osgDB::OutputStream& os, const osg::ImageSequence& i // _images static bool checkImages( const osg::ImageSequence& image ) { - return image.getNumImages()>0; + return false; } static bool readImages( osgDB::InputStream& is, osg::ImageSequence& image ) @@ -53,14 +54,15 @@ static bool readImages( osgDB::InputStream& is, osg::ImageSequence& image ) return true; } -static bool writeImages( osgDB::OutputStream& os, const osg::ImageSequence& image ) +static bool writeImages( osgDB::OutputStream& os, const osg::ImageSequence& image) { - const osg::ImageSequence::Images& images = image.getImages(); - os.writeSize(images.size()); os << os.BEGIN_BRACKET << std::endl; - for ( osg::ImageSequence::Images::const_iterator itr=images.begin(); - itr!=images.end(); ++itr ) + const osg::ImageSequence::ImageDataList& imageDataList = image.getImageDataList(); + os.writeSize(imageDataList.size()); os << os.BEGIN_BRACKET << std::endl; + for ( osg::ImageSequence::ImageDataList::const_iterator itr=imageDataList.begin(); + itr!=imageDataList.end(); + ++itr ) { - os.writeObject( (*itr).get() ); + os.writeObject( (*itr)._image.get() ); } os << os.END_BRACKET << std::endl; return true;