Refactored IncrementalCompileOperation to make it more flexible.

This commit is contained in:
Robert Osfield
2010-12-24 19:19:48 +00:00
parent 149200f0e9
commit 0d814bb6b8
2 changed files with 401 additions and 562 deletions

View File

@@ -19,29 +19,6 @@
namespace osgUtil {
class CompileData : public osg::Referenced
{
public:
CompileData() {}
typedef std::set< osg::ref_ptr<osg::Drawable> > Drawables;
typedef std::set< osg::ref_ptr<osg::Texture> > Textures;
typedef std::set< osg::ref_ptr<osg::Program> > Programs;
bool empty() const { return _drawables.empty() && _textures.empty() && _programs.empty(); }
void reset()
{
_drawables.clear();
_textures.clear();
_programs.clear();
}
Drawables _drawables;
Textures _textures;
Programs _programs;
};
class OSGUTIL_EXPORT CompileStats : public osg::Referenced
{
@@ -111,52 +88,6 @@ class OSGUTIL_EXPORT CompileStats : public osg::Referenced
StatsMap _statsMap;
};
class OSGUTIL_EXPORT CompileOperator : public osg::Referenced
{
public:
CompileOperator();
/** Assign a geometry and associated StateSet than is applied after each texture compile to atttempt to force the OpenGL
* drive to download the texture object to OpenGL graphics card.*/
void assignForceTextureDownloadGeometry();
/** Set the osg::Geometry to apply after each texture compile to atttempt to force the OpenGL
* drive to download the texture object to OpenGL graphics card.*/
void setForceTextureDownloadGeometry(osg::Geometry* geom) { _forceTextureDownloadGeometry = geom; }
osg::Geometry* getForceTextureDownloadGeometry() { return _forceTextureDownloadGeometry.get(); }
const osg::Geometry* getForceTextureDownloadGeometry() const { return _forceTextureDownloadGeometry.get(); }
/** Compile as many elements in the CompileData container as possible within specified time.
* return true if all have been compiled. */
virtual bool compile(osg::RenderInfo& renderInfo, CompileData& compileData, unsigned int& maxNumObjectsToCompile, double& availableTime);
/** Compile all the elements in the CompileData container. */
void compileAll(osg::RenderInfo& renderInfo, CompileData& compileData)
{
unsigned int maxNumObjectsToCompile = 32768;
double availableTime = DBL_MAX;
compile(renderInfo, compileData, maxNumObjectsToCompile, availableTime);
}
CompileStats* getCompileStats() { return _compileStats.get(); }
const CompileStats* getCompileStats() const { return _compileStats.get(); }
protected:
void runTimingTests(osg::RenderInfo& renderInfo);
double timeCompile(osg::RenderInfo& renderInfo, osg::Geometry* geometry) const;
double timeCompile(osg::RenderInfo& renderInfo, osg::StateSet* stateset) const;
osg::Geometry* createTestGeometry(unsigned int numVertices, bool vbo) const;
osg::StateSet* createTestStateSet(unsigned int imageSize, bool mipmapped) const;
osg::ref_ptr<osg::Geometry> _forceTextureDownloadGeometry;
osg::ref_ptr<CompileStats> _compileStats;
bool _timingTestsCompleted;
};
class OSGUTIL_EXPORT IncrementalCompileOperation : public osg::GraphicsOperation
{
public:
@@ -211,6 +142,18 @@ class OSGUTIL_EXPORT IncrementalCompileOperation : public osg::GraphicsOperation
void setConservativeTimeRatio(double ratio) { _conservativeTimeRatio = ratio; }
double getConservativeTimeRatio() const { return _conservativeTimeRatio; }
/** Assign a geometry and associated StateSet than is applied after each texture compile to atttempt to force the OpenGL
* drive to download the texture object to OpenGL graphics card.*/
void assignForceTextureDownloadGeometry();
/** Set the osg::Geometry to apply after each texture compile to atttempt to force the OpenGL
* drive to download the texture object to OpenGL graphics card.*/
void setForceTextureDownloadGeometry(osg::Geometry* geom) { _forceTextureDownloadGeometry = geom; }
osg::Geometry* getForceTextureDownloadGeometry() { return _forceTextureDownloadGeometry.get(); }
const osg::Geometry* getForceTextureDownloadGeometry() const { return _forceTextureDownloadGeometry.get(); }
CompileStats* getCompileStats() { return _compileStats.get(); }
const CompileStats* getCompileStats() const { return _compileStats.get(); }
typedef std::vector<osg::GraphicsContext*> Contexts;
@@ -225,12 +168,74 @@ class OSGUTIL_EXPORT IncrementalCompileOperation : public osg::GraphicsOperation
void mergeCompiledSubgraphs();
virtual void operator () (osg::GraphicsContext* context);
struct OSGUTIL_EXPORT CompileInfo : public osg::RenderInfo
{
CompileInfo(osg::GraphicsContext* context, IncrementalCompileOperation* ico);
double availableTime() { return allocatedTime - timer.elapsedTime(); }
IncrementalCompileOperation* incrementalCompileOperation;
unsigned int maxNumObjectsToCompile;
osg::ElapsedTime timer;
double allocatedTime;
};
struct CompileOp : public osg::Referenced
{
/** return an estimate for how many seconds the compile will take.*/
virtual double estimatedTimeForCompile(CompileInfo& compileInfo) const = 0;
/** compile associated objects, return true if object as been fully compiled and this CompileOp can be removed from the to compile list.*/
virtual bool compile(CompileInfo& compileInfo) = 0;
};
struct OSGUTIL_EXPORT CompileDrawableOp : public CompileOp
{
CompileDrawableOp(osg::Drawable* drawable);
double estimatedTimeForCompile(CompileInfo& compileInfo) const;
bool compile(CompileInfo& compileInfo);
osg::ref_ptr<osg::Drawable> _drawable;
};
struct OSGUTIL_EXPORT CompileTextureOp : public CompileOp
{
CompileTextureOp(osg::Texture* texture);
double estimatedTimeForCompile(CompileInfo& compileInfo) const;
bool compile(CompileInfo& compileInfo);
osg::ref_ptr<osg::Texture> _texture;
};
struct OSGUTIL_EXPORT CompileProgramOp : public CompileOp
{
CompileProgramOp(osg::Program* program);
double estimatedTimeForCompile(CompileInfo& compileInfo) const;
bool compile(CompileInfo& compileInfo);
osg::ref_ptr<osg::Program> _program;
};
class OSGUTIL_EXPORT CompileList
{
public:
CompileList();
~CompileList();
bool empty() const { return _compileOps.empty(); }
void add(CompileOp* compileOp);
void add(osg::Drawable* drawable) { add(new CompileDrawableOp(drawable)); }
void add(osg::Texture* texture) { add(new CompileTextureOp(texture)); }
void add(osg::Program* program) { add(new CompileProgramOp(program)); }
double estimatedTimeForCompile(CompileInfo& compileInfo) const;
bool compile(CompileInfo& compileInfo);
typedef std::list< osg::ref_ptr<CompileOp> > CompileOps;
CompileOps _compileOps;
};
class CompileSet;
typedef std::set<osg::GraphicsContext*> ContextSet;
typedef std::map<osg::GraphicsContext*, CompileData > CompileMap;
struct CompileCompletedCallback : public virtual osg::Referenced
{
@@ -242,36 +247,29 @@ class OSGUTIL_EXPORT IncrementalCompileOperation : public osg::GraphicsOperation
class OSGUTIL_EXPORT CompileSet : public osg::Referenced
{
public:
CompileSet() {}
CompileSet(osg::Node*subgraphToCompile):
_subgraphToCompile(subgraphToCompile) {}
CompileSet(osg::Group* attachmentPoint, osg::Node*subgraphToCompile):
CompileSet(osg::Group* attachmentPoint, osg::Node* subgraphToCompile):
_attachmentPoint(attachmentPoint),
_subgraphToCompile(subgraphToCompile) {}
void buildCompileMap(ContextSet& context, GLObjectsVisitor::Mode mode=GLObjectsVisitor::COMPILE_DISPLAY_LISTS|GLObjectsVisitor::COMPILE_STATE_ATTRIBUTES);
bool compileCompleted() const
{
for(CompileMap::const_iterator itr = _compileMap.begin();
itr != _compileMap.end();
++itr)
{
if (!(itr->second.empty())) return false;
}
return true;
}
bool compile(CompileInfo& compileInfo);
OpenThreads::Atomic _numberCompileListsToCompile;
osg::observer_ptr<osg::Group> _attachmentPoint;
osg::ref_ptr<osg::Node> _subgraphToCompile;
osg::ref_ptr<CompileCompletedCallback> _compileCompletedCallback;
typedef std::map<osg::GraphicsContext*, CompileList > CompileMap;
CompileMap _compileMap;
// protected:
protected:
virtual ~CompileSet() {}
};
@@ -297,14 +295,6 @@ class OSGUTIL_EXPORT IncrementalCompileOperation : public osg::GraphicsOperation
OpenThreads::Mutex* getCompiledMutex() { return &_compiledMutex; }
CompileSets& getCompiled() { return _compiled; }
void setCompileOperator(CompileOperator* compileOperator) { _compileOperator = compileOperator; }
CompileOperator* getCompileOperator() { return _compileOperator.get(); }
const CompileOperator* getCompileOperator() const { return _compileOperator.get(); }
/** Assign a geometry and associated StateSet than is applied after each texture compile to atttempt to force the OpenGL
* drive to download the texture object to OpenGL graphics card.*/
void assignForceTextureDownloadGeometry();
protected:
virtual ~IncrementalCompileOperation();
@@ -318,7 +308,8 @@ class OSGUTIL_EXPORT IncrementalCompileOperation : public osg::GraphicsOperation
double _flushTimeRatio;
double _conservativeTimeRatio;
osg::ref_ptr<CompileOperator> _compileOperator;
osg::ref_ptr<osg::Geometry> _forceTextureDownloadGeometry;
osg::ref_ptr<CompileStats> _compileStats;
OpenThreads::Mutex _toCompileMutex;
CompileSets _toCompile;

View File

@@ -47,6 +47,130 @@ namespace osgUtil
static osg::ApplicationUsageProxy ICO_e1(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_MINIMUM_COMPILE_TIME_PER_FRAME <float>","minimum compile time alloted to compiling OpenGL objects per frame in database pager.");
static osg::ApplicationUsageProxy UCO_e2(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_MAXIMUM_OBJECTS_TO_COMPILE_PER_FRAME <int>","maximum number of OpenGL objects to compile per frame in database pager.");
/////////////////////////////////////////////////////////////////
//
// CollectStateToCompile
//
class IncrementalCompileOperation::CollectStateToCompile : public osg::NodeVisitor
{
public:
CollectStateToCompile(GLObjectsVisitor::Mode mode):
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
_mode(mode) {}
GLObjectsVisitor::Mode _mode;
typedef std::set<osg::Drawable*> DrawableSet;
typedef std::set<osg::StateSet*> StateSetSet;
typedef std::set<osg::Texture*> TextureSet;
typedef std::set<osg::Program*> ProgramSet;
DrawableSet _drawablesHandled;
StateSetSet _statesetsHandled;
DrawableSet _drawables;
TextureSet _textures;
ProgramSet _programs;
void apply(osg::Node& node)
{
if (node.getStateSet())
{
apply(*(node.getStateSet()));
}
traverse(node);
}
void apply(osg::Geode& node)
{
if (node.getStateSet())
{
apply(*(node.getStateSet()));
}
for(unsigned int i=0;i<node.getNumDrawables();++i)
{
osg::Drawable* drawable = node.getDrawable(i);
if (drawable)
{
apply(*drawable);
if (drawable->getStateSet())
{
apply(*(drawable->getStateSet()));
}
}
}
}
void apply(osg::Drawable& drawable)
{
if (_drawablesHandled.count(&drawable)!=0) return;
_drawablesHandled.insert(&drawable);
if (_mode&GLObjectsVisitor::SWITCH_OFF_DISPLAY_LISTS)
{
drawable.setUseDisplayList(false);
}
if (_mode&GLObjectsVisitor::SWITCH_ON_DISPLAY_LISTS)
{
drawable.setUseDisplayList(true);
}
if (_mode&GLObjectsVisitor::SWITCH_ON_VERTEX_BUFFER_OBJECTS)
{
drawable.setUseVertexBufferObjects(true);
}
if (_mode&GLObjectsVisitor::SWITCH_OFF_VERTEX_BUFFER_OBJECTS)
{
drawable.setUseVertexBufferObjects(false);
}
if (_mode&GLObjectsVisitor::COMPILE_DISPLAY_LISTS &&
(drawable.getUseDisplayList() || drawable.getUseVertexBufferObjects()))
{
_drawables.insert(&drawable);
}
}
void apply(osg::StateSet& stateset)
{
if (_statesetsHandled.count(&stateset)!=0) return;
_statesetsHandled.insert(&stateset);
if (_mode & GLObjectsVisitor::COMPILE_STATE_ATTRIBUTES)
{
osg::Program* program = dynamic_cast<osg::Program*>(stateset.getAttribute(osg::StateAttribute::PROGRAM));
if (program)
{
_programs.insert(program);
}
osg::StateSet::TextureAttributeList& tal = stateset.getTextureAttributeList();
for(osg::StateSet::TextureAttributeList::iterator itr = tal.begin();
itr != tal.end();
++itr)
{
osg::StateSet::AttributeList& al = *itr;
osg::StateAttribute::TypeMemberPair tmp(osg::StateAttribute::TEXTURE,0);
osg::StateSet::AttributeList::iterator texItr = al.find(tmp);
if (texItr != al.end())
{
osg::Texture* texture = dynamic_cast<osg::Texture*>(texItr->second.first.get());
if (texture) _textures.insert(texture);
}
}
}
}
};
/////////////////////////////////////////////////////////////////
//
// CompileStats
@@ -140,329 +264,185 @@ void CompileStats::Values::add(double size, double time)
/////////////////////////////////////////////////////////////////
//
// CompileOperator
// CompileOps
//
CompileOperator::CompileOperator():
_timingTestsCompleted(false)
IncrementalCompileOperation::CompileDrawableOp::CompileDrawableOp(osg::Drawable* drawable):
_drawable(drawable)
{
_compileStats = new CompileStats;
}
void CompileOperator::assignForceTextureDownloadGeometry()
double IncrementalCompileOperation::CompileDrawableOp::estimatedTimeForCompile(CompileInfo& compileInfo) const
{
osg::Geometry* geometry = new osg::Geometry;
osg::Vec3Array* vertices = new osg::Vec3Array;
vertices->push_back(osg::Vec3(0.0f,0.0f,0.0f));
geometry->setVertexArray(vertices);
osg::Vec4Array* texcoords = new osg::Vec4Array;
texcoords->push_back(osg::Vec4(0.0f,0.0f,0.0f,0.0f));
geometry->setTexCoordArray(0, texcoords);
geometry->addPrimitiveSet(new osg::DrawArrays(GL_POINTS,0,1));
osg::StateSet* stateset = geometry->getOrCreateStateSet();
stateset->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON);
osg::Depth* depth = new osg::Depth;
depth->setWriteMask(false);
stateset->setAttribute(depth);
osg::ColorMask* colorMask = new osg::ColorMask(false,false,false,false);
stateset->setAttribute(colorMask);
_forceTextureDownloadGeometry = geometry;
return 0.0;
}
double CompileOperator::timeCompile(osg::RenderInfo& renderInfo, osg::Geometry* geometry) const
bool IncrementalCompileOperation::CompileDrawableOp::compile(CompileInfo& compileInfo)
{
osg::ElapsedTime timer;
geometry->compileGLObjects(renderInfo);
return timer.elapsedTime();
//OSG_NOTICE<<"CompileDrawableOp::compile(..)"<<std::endl;
_drawable->compileGLObjects(compileInfo);
return true;
}
double CompileOperator::timeCompile(osg::RenderInfo& renderInfo, osg::StateSet* stateset) const
IncrementalCompileOperation::CompileTextureOp::CompileTextureOp(osg::Texture* texture):
_texture(texture)
{
osg::ElapsedTime timer;
stateset->compileGLObjects(*renderInfo.getState());
return timer.elapsedTime();
}
osg::Geometry* CompileOperator::createTestGeometry(unsigned int numVertices, bool vbo) const
double IncrementalCompileOperation::CompileTextureOp::estimatedTimeForCompile(CompileInfo& compileInfo) const
{
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array(numVertices);
osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array(numVertices);
osg::ref_ptr<osg::Vec4Array> colours = new osg::Vec4Array(numVertices);
osg::ref_ptr<osg::Vec2Array> texcoords = new osg::Vec2Array(numVertices);
return 0.0;
}
geometry->setVertexArray(vertices.get());
geometry->setNormalArray(normals.get());
geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
geometry->setColorArray(colours.get());
geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
geometry->setTexCoordArray(0, texcoords.get());
for(unsigned int i=0; i<numVertices; ++i)
bool IncrementalCompileOperation::CompileTextureOp::compile(CompileInfo& compileInfo)
{
//OSG_NOTICE<<"CompileTextureOp::compile(..)"<<std::endl;
osg::Geometry* forceDownloadGeometry = compileInfo.incrementalCompileOperation->getForceTextureDownloadGeometry();
if (forceDownloadGeometry)
{
(*vertices)[i] = osg::Vec3(0.0f,0.0f,0.0f);
(*normals)[i] = osg::Vec3(0.0f,0.0f,0.0f);
(*colours)[i] = osg::Vec4(1.0f,1.0f,1.0f,1.0f);
(*texcoords)[i] = osg::Vec2(0.0f,0.0f);
}
geometry->addPrimitiveSet(new osg::DrawArrays(GL_POINTS, 0,numVertices));
geometry->setUseDisplayList(true);
geometry->setUseVertexBufferObjects(vbo);
return geometry.release();
}
osg::StateSet* CompileOperator::createTestStateSet(unsigned int imageSize, bool mipmapped) const
{
return 0;
}
void CompileOperator::runTimingTests(osg::RenderInfo& renderInfo)
{
_timingTestsCompleted = true;
return;
OSG_NOTICE<<"runTimingTests()"<<std::endl;
unsigned int mx = 18;
double Mbsec = 1.0/(1024.0*1024.0);
for(unsigned int j=0; j<4; ++j)
{
OSG_NOTICE<<"Using display lists"<<std::endl;
bool useVBO = false;
for(unsigned int i=0; i<mx; ++i)
if (forceDownloadGeometry->getStateSet())
{
unsigned int numVertices = pow(2.0,double(i));
osg::ref_ptr<osg::Geometry> geometry = createTestGeometry(numVertices, useVBO);
double size = geometry->getGLObjectSizeHint();
double time = timeCompile(renderInfo, geometry.get());
OSG_NOTICE<<" numVertices = "<<numVertices<<" size = "<<size<<", time = "<<time*1000.0<<"ms rate= "<<(size/time)*Mbsec<<"Mb/sec"<<std::endl;
compileInfo.getState()->apply(forceDownloadGeometry->getStateSet());
}
compileInfo.getState()->applyTextureMode(0, _texture->getTextureTarget(), true);
compileInfo.getState()->applyTextureAttribute(0, _texture.get());
forceDownloadGeometry->draw(compileInfo);
}
else
{
_texture->apply(*compileInfo.getState());
}
return true;
}
IncrementalCompileOperation::CompileProgramOp::CompileProgramOp(osg::Program* program):
_program(program)
{
}
double IncrementalCompileOperation::CompileProgramOp::estimatedTimeForCompile(CompileInfo& compileInfo) const
{
return 0.0;
}
bool IncrementalCompileOperation::CompileProgramOp::compile(CompileInfo& compileInfo)
{
//OSG_NOTICE<<"CompileProgramOp::compile(..)"<<std::endl;
_program->apply(*compileInfo.getState());
return true;
}
IncrementalCompileOperation::CompileInfo::CompileInfo(osg::GraphicsContext* context, IncrementalCompileOperation* ico)
{
setState(context->getState());
incrementalCompileOperation = ico;
}
/////////////////////////////////////////////////////////////////
//
// CompileList
//
IncrementalCompileOperation::CompileList::CompileList()
{
}
IncrementalCompileOperation::CompileList::~CompileList()
{
}
void IncrementalCompileOperation::CompileList::add(CompileOp* compileOp)
{
_compileOps.push_back(compileOp);
}
double IncrementalCompileOperation::CompileList::estimatedTimeForCompile(CompileInfo& compileInfo) const
{
double estimateTime = 0.0;
for(CompileOps::const_iterator itr = _compileOps.begin();
itr != _compileOps.begin();
++itr)
{
estimateTime += (*itr)->estimatedTimeForCompile(compileInfo);
}
return estimateTime;
}
bool IncrementalCompileOperation::CompileList::compile(CompileInfo& compileInfo)
{
for(CompileOps::iterator itr = _compileOps.begin();
itr != _compileOps.end() && compileInfo.availableTime()>0.0 && compileInfo.maxNumObjectsToCompile>0;
)
{
--compileInfo.maxNumObjectsToCompile;
CompileOps::iterator saved_itr(itr);
++itr;
if ((*saved_itr)->compile(compileInfo))
{
_compileOps.erase(saved_itr);
}
}
for(unsigned int j=0; j<4; ++j)
return empty();
}
/////////////////////////////////////////////////////////////////
//
// CompileSet
//
void IncrementalCompileOperation::CompileSet::buildCompileMap(ContextSet& contexts, GLObjectsVisitor::Mode mode)
{
if (contexts.empty() || !_subgraphToCompile) return;
CollectStateToCompile cstc(mode);
_subgraphToCompile->accept(cstc);
if (cstc._textures.empty() && cstc._programs.empty() && cstc._drawables.empty()) return;
for(ContextSet::iterator itr = contexts.begin();
itr != contexts.end();
++itr)
{
OSG_NOTICE<<"Using VBOs"<<std::endl;
bool useVBO = true;
for(unsigned int i=0; i<mx; ++i)
// increment the number of compile lists that will need to compile
++_numberCompileListsToCompile;
CompileList& cl = _compileMap[*itr];
for(CollectStateToCompile::DrawableSet::iterator ditr = cstc._drawables.begin();
ditr != cstc._drawables.end();
++ditr)
{
unsigned int numVertices = pow(2.0,double(i));
osg::ref_ptr<osg::Geometry> geometry = createTestGeometry(numVertices, useVBO);
double size = geometry->getGLObjectSizeHint();
double time = timeCompile(renderInfo, geometry.get());
OSG_NOTICE<<" numVertices = "<<numVertices<<" size = "<<size<<", time = "<<time*1000.0<<"ms rate= "<<(size/time)*Mbsec<<"Mb/sec"<<std::endl;
cl.add(*ditr);
}
for(CollectStateToCompile::TextureSet::iterator titr = cstc._textures.begin();
titr != cstc._textures.end();
++titr)
{
cl.add(*titr);
}
for(CollectStateToCompile::ProgramSet::iterator pitr = cstc._programs.begin();
pitr != cstc._programs.end();
++pitr)
{
cl.add(*pitr);
}
}
}
bool CompileOperator::compile(osg::RenderInfo& renderInfo, CompileData& cd, unsigned int& maxNumObjectsToCompile, double& compileTime)
bool IncrementalCompileOperation::CompileSet::compile(CompileInfo& compileInfo)
{
osg::NotifySeverity level = osg::INFO;
//osg::NotifySeverity level = osg::NOTICE;
OSG_NOTIFY(level)<<"compile(..,maxNumObjectsToCompile="<<maxNumObjectsToCompile<<", compileTime="<<compileTime<<")"<<std::endl;
osg::Timer_t startTick = osg::Timer::instance()->tick();
if (!_timingTestsCompleted)
CompileList& compileList = _compileMap[compileInfo.getState()->getGraphicsContext()];
if (!compileList.empty())
{
runTimingTests(renderInfo);
}
unsigned int totalDataSizeCompiled = 0;
unsigned int drawablesCompiled = 0;
unsigned int texturesCompiled = 0;
unsigned int programsCompiled = 0;
if (!cd.empty() && compileTime>0.0)
{
osg::Timer_t previousTick = osg::Timer::instance()->tick();
const std::string vboDrawablesName("VBO Drawables");
const std::string dlDawablesName("DisplayList Drawables");
while(!cd._drawables.empty() &&
maxNumObjectsToCompile>0 &&
osg::Timer::instance()->delta_s(startTick, previousTick) < compileTime)
if (compileList.compile(compileInfo))
{
CompileData::Drawables::iterator itr = cd._drawables.begin();
const osg::Drawable* drawable = itr->get();
unsigned int size = drawable->getGLObjectSizeHint();
const std::string& nameOfDrawableType = drawable->getUseVertexBufferObjects() ? vboDrawablesName : dlDawablesName;
#if 0
double estimatedTime = _compileStats->estimateTime(nameOfDrawableType, double(size));
double estimatedTime2 = _compileStats->estimateTime2(nameOfDrawableType, double(size));
double estimatedTime3 = _compileStats->estimateTime3(nameOfDrawableType, double(size));
double estimatedTime4 = _compileStats->estimateTime4(nameOfDrawableType, double(size));
#endif
drawable->compileGLObjects(renderInfo);
osg::Timer_t currTick = osg::Timer::instance()->tick();
double timeForCompile = osg::Timer::instance()->delta_s(previousTick, currTick);
previousTick = currTick;
#if 0
OSG_NOTIFY(level)<<"Drawable size = "<<size<<std::endl;
OSG_NOTIFY(level)<<" Estimated time ="<<estimatedTime<<", actual time="<<timeForCompile<<" ratio = "<<timeForCompile/estimatedTime<<std::endl;
OSG_NOTIFY(level)<<" Estimated time2="<<estimatedTime2<<", actual time="<<timeForCompile<<" ratio = "<<timeForCompile/estimatedTime2<<std::endl;
OSG_NOTIFY(level)<<" Estimated time3="<<estimatedTime3<<", actual time="<<timeForCompile<<" ratio = "<<timeForCompile/estimatedTime3<<std::endl;
OSG_NOTIFY(level)<<" Estimated time4="<<estimatedTime4<<", actual time="<<timeForCompile<<" ratio = "<<timeForCompile/estimatedTime4<<std::endl;
#endif
_compileStats->add(nameOfDrawableType, double(size), timeForCompile);
totalDataSizeCompiled += size;
// OSG_NOTIFY(level)<<"Compiled drawable, getGLObjectSizeHint()="<<(*itr)->getGLObjectSizeHint()<<std::endl;
++drawablesCompiled;
--maxNumObjectsToCompile;
cd._drawables.erase(itr);
}
while(!cd._textures.empty() &&
maxNumObjectsToCompile>0 &&
osg::Timer::instance()->delta_s(startTick, osg::Timer::instance()->tick()) < compileTime)
{
CompileData::Textures::iterator itr = cd._textures.begin();
osg::Texture* texture = itr->get();
osg::Texture::FilterMode minFilter = texture->getFilter(osg::Texture::MIN_FILTER);
bool textureMipmapped = (minFilter!=osg::Texture::LINEAR && minFilter!=osg::Texture::NEAREST);
bool textureCompressedFormat = texture->isCompressedInternalFormat();
bool needtoBuildMipmaps = false;
bool needtoCompress = false;
OSG_NOTIFY(level)<<" texture->isCompressedInternalFormat()="<<textureCompressedFormat<<std::endl;
for(unsigned int i=0; i<texture->getNumImages();++i)
{
osg::Image* image = texture->getImage(i);
if (image)
{
totalDataSizeCompiled += texture->getImage(i)->getTotalSizeInBytesIncludingMipmaps();
if (textureMipmapped && !image->isMipmap()) needtoBuildMipmaps = true;
if (textureCompressedFormat && !image->isCompressed()) needtoCompress = true;
}
}
OSG_NOTIFY(level)<<"compiling texture, textureMipmapped="<<textureMipmapped<<", needtoBuildMipmaps="<<needtoBuildMipmaps<<std::endl;
OSG_NOTIFY(level)<<" textureCompressedFormat="<<textureCompressedFormat<<", needtoCompress="<<needtoCompress<<std::endl;
// if (needtoBuildMipmaps) texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
if (_forceTextureDownloadGeometry.get())
{
if (_forceTextureDownloadGeometry->getStateSet())
{
renderInfo.getState()->apply(_forceTextureDownloadGeometry->getStateSet());
}
renderInfo.getState()->applyTextureMode(0, texture->getTextureTarget(), true);
renderInfo.getState()->applyTextureAttribute(0, texture);
_forceTextureDownloadGeometry->draw(renderInfo);
}
else
{
texture->apply(*renderInfo.getState());
}
++texturesCompiled;
--maxNumObjectsToCompile;
cd._textures.erase(itr);
}
if (!cd._programs.empty())
{
osg::GL2Extensions* extensions = osg::GL2Extensions::Get(renderInfo.getState()->getContextID(), true);
if (extensions && extensions->isGlslSupported())
{
// compile programs
while(!cd._programs.empty() &&
maxNumObjectsToCompile>0 &&
osg::Timer::instance()->delta_s(startTick, osg::Timer::instance()->tick()) < compileTime)
{
CompileData::Programs::iterator itr = cd._programs.begin();
(*itr)->apply(*renderInfo.getState());
++programsCompiled;
--maxNumObjectsToCompile;
cd._programs.erase(itr);
}
#if 0
// what shall we do about uniforms???
osg::Program* program = dynamic_cast<osg::Program*>(stateset.getAttribute(osg::StateAttribute::PROGRAM));
if (program) {
if( program->isFixedFunction() )
_lastCompiledProgram = NULL; // It does not make sense to apply uniforms on fixed pipe
else
_lastCompiledProgram = program;
}
if (_lastCompiledProgram.valid() && !stateset.getUniformList().empty())
{
osg::Program::PerContextProgram* pcp = _lastCompiledProgram->getPCP(_renderInfo.getState()->getContextID());
if (pcp)
{
pcp->useProgram();
_renderInfo.getState()->setLastAppliedProgramObject(pcp);
osg::StateSet::UniformList& ul = stateset.getUniformList();
for(osg::StateSet::UniformList::iterator itr = ul.begin();
itr != ul.end();
++itr)
{
pcp->apply(*(itr->second.first));
}
}
}
else if(_renderInfo.getState()->getLastAppliedProgramObject()){
osg::GL2Extensions* extensions = osg::GL2Extensions::Get(_renderInfo.getState()->getContextID(), true);
extensions->glUseProgram(0);
_renderInfo.getState()->setLastAppliedProgramObject(0);
}
#endif
// switch off Program,
extensions->glUseProgram(0);
renderInfo.getState()->setLastAppliedProgramObject(0);
}
--_numberCompileListsToCompile;
return _numberCompileListsToCompile==0;
}
}
double timeUsed = osg::Timer::instance()->delta_s(startTick, osg::Timer::instance()->tick());
OSG_NOTIFY(level)<<" texturesCompiled="<<texturesCompiled<<", drawablesCompiled="<<drawablesCompiled<<", programsCompiled="<<programsCompiled<<", timeUsed="<<timeUsed*1000.0<<" totalDataSizeCompiled="<<totalDataSizeCompiled<<" bytes, download rate="<<double(totalDataSizeCompiled)/(1024.0*1024*timeUsed)<<"Mb/sec"<<std::endl;
compileTime -= timeUsed;
return cd.empty();
return false;
}
/////////////////////////////////////////////////////////////////
@@ -488,7 +468,7 @@ IncrementalCompileOperation::IncrementalCompileOperation():
_maximumNumOfObjectsToCompilePerFrame = atoi(ptr);
}
_compileOperator = new CompileOperator;
_compileStats = new CompileStats;
// assignForceTextureDownloadGeometry();
}
@@ -499,7 +479,29 @@ IncrementalCompileOperation::~IncrementalCompileOperation()
void IncrementalCompileOperation::assignForceTextureDownloadGeometry()
{
_compileOperator->assignForceTextureDownloadGeometry();
osg::Geometry* geometry = new osg::Geometry;
osg::Vec3Array* vertices = new osg::Vec3Array;
vertices->push_back(osg::Vec3(0.0f,0.0f,0.0f));
geometry->setVertexArray(vertices);
osg::Vec4Array* texcoords = new osg::Vec4Array;
texcoords->push_back(osg::Vec4(0.0f,0.0f,0.0f,0.0f));
geometry->setTexCoordArray(0, texcoords);
geometry->addPrimitiveSet(new osg::DrawArrays(GL_POINTS,0,1));
osg::StateSet* stateset = geometry->getOrCreateStateSet();
stateset->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON);
osg::Depth* depth = new osg::Depth;
depth->setWriteMask(false);
stateset->setAttribute(depth);
osg::ColorMask* colorMask = new osg::ColorMask(false,false,false,false);
stateset->setAttribute(colorMask);
_forceTextureDownloadGeometry = geometry;
}
void IncrementalCompileOperation::assignContexts(Contexts& contexts)
@@ -634,147 +636,6 @@ void IncrementalCompileOperation::mergeCompiledSubgraphs()
_compiled.clear();
}
class IncrementalCompileOperation::CollectStateToCompile : public osg::NodeVisitor
{
public:
CollectStateToCompile(GLObjectsVisitor::Mode mode):
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
_mode(mode) {}
GLObjectsVisitor::Mode _mode;
typedef std::set<osg::Drawable*> DrawableSet;
typedef std::set<osg::StateSet*> StateSetSet;
typedef std::set<osg::Texture*> TextureSet;
typedef std::set<osg::Program*> ProgramSet;
DrawableSet _drawablesHandled;
StateSetSet _statesetsHandled;
DrawableSet _drawables;
TextureSet _textures;
ProgramSet _programs;
void apply(osg::Node& node)
{
if (node.getStateSet())
{
apply(*(node.getStateSet()));
}
traverse(node);
}
void apply(osg::Geode& node)
{
if (node.getStateSet())
{
apply(*(node.getStateSet()));
}
for(unsigned int i=0;i<node.getNumDrawables();++i)
{
osg::Drawable* drawable = node.getDrawable(i);
if (drawable)
{
apply(*drawable);
if (drawable->getStateSet())
{
apply(*(drawable->getStateSet()));
}
}
}
}
void apply(osg::Drawable& drawable)
{
if (_drawablesHandled.count(&drawable)!=0) return;
_drawablesHandled.insert(&drawable);
if (_mode&GLObjectsVisitor::SWITCH_OFF_DISPLAY_LISTS)
{
drawable.setUseDisplayList(false);
}
if (_mode&GLObjectsVisitor::SWITCH_ON_DISPLAY_LISTS)
{
drawable.setUseDisplayList(true);
}
if (_mode&GLObjectsVisitor::SWITCH_ON_VERTEX_BUFFER_OBJECTS)
{
drawable.setUseVertexBufferObjects(true);
}
if (_mode&GLObjectsVisitor::SWITCH_OFF_VERTEX_BUFFER_OBJECTS)
{
drawable.setUseVertexBufferObjects(false);
}
if (_mode&GLObjectsVisitor::COMPILE_DISPLAY_LISTS &&
(drawable.getUseDisplayList() || drawable.getUseVertexBufferObjects()))
{
_drawables.insert(&drawable);
}
}
void apply(osg::StateSet& stateset)
{
if (_statesetsHandled.count(&stateset)!=0) return;
_statesetsHandled.insert(&stateset);
if (_mode & GLObjectsVisitor::COMPILE_STATE_ATTRIBUTES)
{
osg::Program* program = dynamic_cast<osg::Program*>(stateset.getAttribute(osg::StateAttribute::PROGRAM));
if (program)
{
_programs.insert(program);
}
osg::StateSet::TextureAttributeList& tal = stateset.getTextureAttributeList();
for(osg::StateSet::TextureAttributeList::iterator itr = tal.begin();
itr != tal.end();
++itr)
{
osg::StateSet::AttributeList& al = *itr;
osg::StateAttribute::TypeMemberPair tmp(osg::StateAttribute::TEXTURE,0);
osg::StateSet::AttributeList::iterator texItr = al.find(tmp);
if (texItr != al.end())
{
osg::Texture* texture = dynamic_cast<osg::Texture*>(texItr->second.first.get());
if (texture) _textures.insert(texture);
}
}
}
}
};
void IncrementalCompileOperation::CompileSet::buildCompileMap(ContextSet& contexts, GLObjectsVisitor::Mode mode)
{
if (contexts.empty() || !_subgraphToCompile) return;
CollectStateToCompile cstc(mode);
_subgraphToCompile->accept(cstc);
if (cstc._textures.empty() && cstc._programs.empty() && cstc._drawables.empty()) return;
for(ContextSet::iterator itr = contexts.begin();
itr != contexts.end();
++itr)
{
CompileData& cd = _compileMap[*itr];
std::copy(cstc._drawables.begin(), cstc._drawables.end(), std::inserter(cd._drawables, cd._drawables.end()));
std::copy(cstc._textures.begin(), cstc._textures.end(), std::inserter(cd._textures, cd._textures.end()));
std::copy(cstc._programs.begin(), cstc._programs.end(), std::inserter(cd._programs, cd._programs.end()));
}
}
void IncrementalCompileOperation::operator () (osg::GraphicsContext* context)
{
@@ -821,8 +682,9 @@ void IncrementalCompileOperation::operator () (osg::GraphicsContext* context)
//level = osg::NOTICE;
osg::RenderInfo renderInfo;
renderInfo.setState(context->getState());
CompileInfo compileInfo(context, this);
compileInfo.maxNumObjectsToCompile = _maximumNumOfObjectsToCompilePerFrame;
compileInfo.allocatedTime = compileTime;
CompileSets toCompileCopy;
{
@@ -835,43 +697,29 @@ void IncrementalCompileOperation::operator () (osg::GraphicsContext* context)
++itr)
{
CompileSet* cs = itr->get();
CompileMap& cm = cs->_compileMap;
CompileData& cd = cm[context];
if (_compileOperator->compile(renderInfo, cd, maxNumOfObjectsToCompilePerFrame, compileTime))
if (cs->compile(compileInfo))
{
bool csCompleted = false;
{
OpenThreads::ScopedLock<OpenThreads::Mutex> toCompile_lock(_toCompileMutex);
if (cs->compileCompleted())
{
CompileSets::iterator cs_itr = std::find(_toCompile.begin(), _toCompile.end(), *itr);
if (cs_itr != _toCompile.end())
{
OSG_NOTIFY(level)<<"Erasing from list"<<std::endl;
CompileSets::iterator cs_itr = std::find(_toCompile.begin(), _toCompile.end(), *itr);
if (cs_itr != _toCompile.end())
{
OSG_NOTIFY(level)<<"Erasing from list"<<std::endl;
// remove from the _toCompile list, note cs won't be deleted here as the tempoary
// toCompile_Copy list will retain a reference.
_toCompile.erase(cs_itr);
// signal that we need to do clean up operations/pass cs on to _compile list.
csCompleted = true;
}
// remove from the _toCompile list, note cs won't be deleted here as the tempoary
// toCompile_Copy list will retain a reference.
_toCompile.erase(cs_itr);
}
}
if (csCompleted)
if (cs->_compileCompletedCallback.valid() && cs->_compileCompletedCallback->compileCompleted(cs))
{
if (cs->_compileCompletedCallback.valid() && cs->_compileCompletedCallback->compileCompleted(cs))
{
// callback will handle merging of subgraph so no need to place CompileSet in merge.
}
else
{
OpenThreads::ScopedLock<OpenThreads::Mutex> compilded_lock(_compiledMutex);
_compiled.push_back(cs);
}
// callback will handle merging of subgraph so no need to place CompileSet in merge.
}
else
{
OpenThreads::ScopedLock<OpenThreads::Mutex> compilded_lock(_compiledMutex);
_compiled.push_back(cs);
}
}
}