From 3171be0ff771400b190fddfb453613abbf72a9b6 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 8 Jun 2009 16:50:50 +0000 Subject: [PATCH] From Gustav Haapalahti and Robert Osfield, First Submission email from Gustav: "This submission adds a --cache option to osgconv and osgviewer that enables setObjectCacheHint(osgDB::Options::CACHE_ALL); It greatly reduces memory usage when a .osg file has lots of external references with ProxyNode:s that points to the same file. Options are also added to the osg plugin. The code was already mostly implemented but there was no way to change the options. includeExternalReferences writeExternalReferenceFiles A counter is added to keep track if an external file has already been written down to avoid writing the same file over and over again. If it has already been written once then it is not written again. The counter is added to the Output class in osgDB. " Second Submission email from Gustav: "This is a continuation to my previous submission. I noticed that the same problem that I fixed in ProxyNode.cpp for the osg plugin (external files being written over and over again) also existed in the ive plugin. I attached a submission where the ive plugin remembers which external files that have already been written and do not write them again." Changes to the above done by Robert Osfield, changed command line parameter to --enable-object-cache changed set/get methods in osgDB::Output and ive/DataOutputStream.cpp to be s/getExternalFileWritten(const std::string&) cleaned up set up of osgDB::Options. --- applications/osgconv/osgconv.cpp | 9 +++++++++ include/osgDB/Output | 8 +++++++- src/osgDB/Output.cpp | 11 +++++++++++ src/osgPlugins/ive/DataOutputStream.cpp | 12 ++++++++++++ src/osgPlugins/ive/DataOutputStream.h | 7 +++++++ src/osgPlugins/ive/ProxyNode.cpp | 12 ++++++++++-- src/osgPlugins/osg/ProxyNode.cpp | 21 +++++++++++++++++++-- src/osgPlugins/osg/ReaderWriterOSG.cpp | 2 ++ src/osgViewer/Viewer.cpp | 8 ++++++++ 9 files changed, 85 insertions(+), 5 deletions(-) diff --git a/applications/osgconv/osgconv.cpp b/applications/osgconv/osgconv.cpp index c967b3335..cac7b56fa 100644 --- a/applications/osgconv/osgconv.cpp +++ b/applications/osgconv/osgconv.cpp @@ -516,6 +516,7 @@ static void usage( const char *prog, const char *msg ) osg::notify(osg::NOTICE)<<" --addMissingColors - Adding a white color value to all geometry that don't have\n" " their own color values (--addMissingColours also accepted)."<< std::endl; osg::notify(osg::NOTICE)<<" --overallNormal - Replace normals with a single overall normal."<< std::endl; + osg::notify(osg::NOTICE)<<" --enable-object-cache - Enable caching of objects, images, etc."<< std::endl; osg::notify( osg::NOTICE ) << std::endl; osg::notify( osg::NOTICE ) << @@ -731,6 +732,9 @@ int main( int argc, char **argv ) bool do_overallNormal = false; while(arguments.read("--overallNormal") || arguments.read("--overallNormal")) { do_overallNormal = true; } + bool enableObjectCache = false; + while(arguments.read("--enable-object-cache")) { enableObjectCache = true; } + // any option left unread are converted into errors to write out later. arguments.reportRemainingOptionsAsUnrecognized(); @@ -749,6 +753,11 @@ int main( int argc, char **argv ) } } + if (enableObjectCache) + { + if (osgDB::Registry::instance()->getOptions()==0) osgDB::Registry::instance()->setOptions(new osgDB::Options()); + osgDB::Registry::instance()->getOptions()->setObjectCacheHint(osgDB::Options::CACHE_ALL); + } std::string fileNameOut("converted.osg"); if (fileNames.size()>1) diff --git a/include/osgDB/Output b/include/osgDB/Output index 0617ed88f..1efedcdb7 100644 --- a/include/osgDB/Output +++ b/include/osgDB/Output @@ -100,7 +100,10 @@ class OSGDB_EXPORT Output : public osgDB::ofstream bool getOutputShaderFiles() const { return _outputShaderFiles; } virtual std::string getShaderFileNameForOutput(); - + + void setExternalFileWritten(const std::string& filename, bool hasBeenWritten=true); + bool getExternalFileWritten(const std::string& filename) const; + protected: @@ -127,6 +130,9 @@ class OSGDB_EXPORT Output : public osgDB::ofstream unsigned int _shaderFileNameNumber; bool _writeOutDefaultValues; + + typedef std::map ExternalFileWrittenMap; + ExternalFileWrittenMap _externalFileWritten; }; } diff --git a/src/osgDB/Output.cpp b/src/osgDB/Output.cpp index 8d30f8e86..cd214faf3 100644 --- a/src/osgDB/Output.cpp +++ b/src/osgDB/Output.cpp @@ -245,3 +245,14 @@ std::string Output::getShaderFileNameForOutput() return fileName; } +void Output::setExternalFileWritten(const std::string& filename, bool hasBeenWritten) +{ + _externalFileWritten[filename] = hasBeenWritten; +} + +bool Output::getExternalFileWritten(const std::string& filename) const +{ + ExternalFileWrittenMap::const_iterator itr = _externalFileWritten.find(filename); + if (itr != _externalFileWritten.end()) return itr->second; + return false; +} diff --git a/src/osgPlugins/ive/DataOutputStream.cpp b/src/osgPlugins/ive/DataOutputStream.cpp index 06ce0f3e9..52cc272c6 100644 --- a/src/osgPlugins/ive/DataOutputStream.cpp +++ b/src/osgPlugins/ive/DataOutputStream.cpp @@ -1835,3 +1835,15 @@ void DataOutputStream::writeObject(const osg::Object* object) // fallback, osg::Object type not supported, so can't write out writeInt(-1); } + +void DataOutputStream::setExternalFileWritten(const std::string& filename, bool hasBeenWritten) +{ + _externalFileWritten[filename] = hasBeenWritten; +} + +bool DataOutputStream::getExternalFileWritten(const std::string& filename) const +{ + ExternalFileWrittenMap::const_iterator itr = _externalFileWritten.find(filename); + if (itr != _externalFileWritten.end()) return itr->second; + return false; +} diff --git a/src/osgPlugins/ive/DataOutputStream.h b/src/osgPlugins/ive/DataOutputStream.h index ccc12c876..8639aecd3 100644 --- a/src/osgPlugins/ive/DataOutputStream.h +++ b/src/osgPlugins/ive/DataOutputStream.h @@ -138,6 +138,10 @@ public: bool compress(std::ostream& fout, const std::string& source) const; + + void setExternalFileWritten(const std::string& filename, bool hasBeenWritten=true); + bool getExternalFileWritten(const std::string& filename) const; + private: std::ostream* _ostream; @@ -182,6 +186,9 @@ private: IncludeImageMode _includeImageMode; osg::ref_ptr _options; + + typedef std::map ExternalFileWrittenMap; + ExternalFileWrittenMap _externalFileWritten; }; } diff --git a/src/osgPlugins/ive/ProxyNode.cpp b/src/osgPlugins/ive/ProxyNode.cpp index 82b7af889..7928f3b13 100644 --- a/src/osgPlugins/ive/ProxyNode.cpp +++ b/src/osgPlugins/ive/ProxyNode.cpp @@ -120,12 +120,20 @@ void ProxyNode::write(DataOutputStream* out) { if(!writeOutExternalIVEFIles) { - osgDB::writeNodeFile(*getChild(i), getFileName(i)); + if (!out->getExternalFileWritten(getFileName(i))) + { + osgDB::writeNodeFile(*getChild(i), getFileName(i)); + out->setExternalFileWritten(getFileName(i), true); + } } else { std::string ivename = writeDirectory + osgDB::getStrippedName(getFileName(i)) +".ive"; - osgDB::writeNodeFile(*getChild(i), ivename); + if (!out->getExternalFileWritten(getFileName(i))) + { + osgDB::writeNodeFile(*getChild(i), ivename); + out->setExternalFileWritten(ivename, true); + } } } } diff --git a/src/osgPlugins/osg/ProxyNode.cpp b/src/osgPlugins/osg/ProxyNode.cpp index c03e51e8c..83469ca3c 100644 --- a/src/osgPlugins/osg/ProxyNode.cpp +++ b/src/osgPlugins/osg/ProxyNode.cpp @@ -164,6 +164,14 @@ bool ProxyNode_writeLocalData(const Object& obj, Output& fw) bool includeExternalReferences = false; bool useOriginalExternalReferences = true; bool writeExternalReferenceFiles = false; + std::string optionsString = fw.getOptions()->getOptionString(); + includeExternalReferences = optionsString.find("includeExternalReferences")!=std::string::npos; + bool newExternals = optionsString.find("writeExternalReferenceFiles")!=std::string::npos; + if (newExternals) + { + useOriginalExternalReferences = false; + writeExternalReferenceFiles = true; + } const ProxyNode& proxyNode = static_cast(obj); @@ -238,14 +246,23 @@ bool ProxyNode_writeLocalData(const Object& obj, Output& fw) { if(useOriginalExternalReferences) //out->getUseOriginalExternalReferences()) { - osgDB::writeNodeFile(*proxyNode.getChild(i), proxyNode.getFileName(i)); + std::string origname = proxyNode.getFileName(i); + if (!fw.getExternalFileWritten(origname)) + { + osgDB::writeNodeFile(*proxyNode.getChild(i), origname); + fw.setExternalFileWritten(proxyNode.getFileName(i), true); + } } else { std::string path = osgDB::getFilePath(fw.getFileName()); std::string new_filename = osgDB::getStrippedName(proxyNode.getFileName(i)) +".osg"; std::string osgname = path.empty() ? new_filename : (path +"/"+ new_filename) ; - osgDB::writeNodeFile(*proxyNode.getChild(i), osgname); + if (!fw.getExternalFileWritten(osgname)) + { + osgDB::writeNodeFile(*proxyNode.getChild(i), osgname); + fw.setExternalFileWritten(osgname, true); + } } } } diff --git a/src/osgPlugins/osg/ReaderWriterOSG.cpp b/src/osgPlugins/osg/ReaderWriterOSG.cpp index a1e24f7d4..f9b290f68 100644 --- a/src/osgPlugins/osg/ReaderWriterOSG.cpp +++ b/src/osgPlugins/osg/ReaderWriterOSG.cpp @@ -110,6 +110,8 @@ class OSGReaderWriter : public ReaderWriter supportsExtension("osgs","Psuedo OpenSceneGraph file loaded, with file encoded in filename string"); supportsOption("precision","Set the floating point precision when writing out files"); supportsOption("OutputTextureFiles","Write out the texture images to file"); + supportsOption("includeExternalReferences","Export option"); + supportsOption("writeExternalReferenceFiles","Export option"); } virtual const char* className() const { return "OSG Reader/Writer"; } diff --git a/src/osgViewer/Viewer.cpp b/src/osgViewer/Viewer.cpp index bdd14ac61..d4f5fe5eb 100644 --- a/src/osgViewer/Viewer.cpp +++ b/src/osgViewer/Viewer.cpp @@ -57,6 +57,7 @@ Viewer::Viewer(osg::ArgumentParser& arguments) arguments.getApplicationUsage()->addCommandLineOption("--run-on-demand","Set the run methods frame rate management to only rendering frames when required."); arguments.getApplicationUsage()->addCommandLineOption("--run-continuous","Set the run methods frame rate management to rendering frames continuously."); arguments.getApplicationUsage()->addCommandLineOption("--run-max-frame-rate","Set the run methods maximum permissable frame rate, 0.0 is default and switching off frame rate capping."); + arguments.getApplicationUsage()->addCommandLineOption("--enable-object-cache","Enable caching of objects, images, etc."); // FIXME: Uncomment these lines when the options have been documented properly //arguments.getApplicationUsage()->addCommandLineOption("--3d-sd",""); @@ -72,6 +73,13 @@ Viewer::Viewer(osg::ArgumentParser& arguments) readConfig = readConfiguration(filename) || readConfig; } + // Enable caching? + while (arguments.read("--enable-object-cache")) + { + if (osgDB::Registry::instance()->getOptions()==0) osgDB::Registry::instance()->setOptions(new osgDB::Options()); + osgDB::Registry::instance()->getOptions()->setObjectCacheHint(osgDB::Options::CACHE_ALL); + } + while (arguments.read("--SingleThreaded")) setThreadingModel(SingleThreaded); while (arguments.read("--CullDrawThreadPerContext")) setThreadingModel(CullDrawThreadPerContext); while (arguments.read("--DrawThreadPerContext")) setThreadingModel(DrawThreadPerContext);