From a0b43f426e2861bd4c4f554c0e53dadc8d62c3ae Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 11 Apr 2015 23:01:37 +0200 Subject: [PATCH] Avoid setting DYNAMIC DataVariance on StateSets --- components/nifosg/controller.cpp | 16 ++++++++++++---- components/nifosg/controller.hpp | 19 +++++++++++++++---- components/nifosg/nifloader.cpp | 4 ---- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 5916359c8..59ba9ad4f 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -291,7 +291,7 @@ void UVController::operator()(osg::Node* node, osg::NodeVisitor* nv) { if (hasInput()) { - osg::StateSet* stateset = node->getStateSet(); + osg::StateSet* stateset = getWritableStateSet(node); float value = getInputValue(nv); float uTrans = interpKey(mUTrans->mKeys, value, 0.0f); float vTrans = interpKey(mVTrans->mKeys, value, 0.0f); @@ -372,7 +372,7 @@ void AlphaController::operator () (osg::Node* node, osg::NodeVisitor* nv) { if (hasInput()) { - osg::StateSet* stateset = node->getStateSet(); + osg::StateSet* stateset = getWritableStateSet(node); float value = interpKey(mData->mKeys, getInputValue(nv)); osg::Material* mat = dynamic_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); if (mat) @@ -404,7 +404,7 @@ void MaterialColorController::operator() (osg::Node* node, osg::NodeVisitor* nv) { if (hasInput()) { - osg::StateSet* stateset = node->getStateSet(); + osg::StateSet* stateset = getWritableStateSet(node); osg::Vec3f value = interpKey(mData->mKeys, getInputValue(nv)); osg::Material* mat = dynamic_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); if (mat) @@ -441,7 +441,7 @@ void FlipController::operator() (osg::Node* node, osg::NodeVisitor* nv) { if (hasInput() && mDelta != 0) { - osg::StateSet* stateset = node->getStateSet(); + osg::StateSet* stateset = getWritableStateSet(node); int curTexture = int(getInputValue(nv) / mDelta) % mTextures.size(); stateset->setTextureAttribute(mTexSlot, mTextures[curTexture]); } @@ -507,4 +507,12 @@ void SourcedKeyframeController::operator ()(osg::Node* node, osg::NodeVisitor* n traverse(node, nv); } +osg::StateSet *StateSetController::getWritableStateSet(osg::Node *node) +{ + osg::StateSet* orig = node->getOrCreateStateSet(); + osg::StateSet* cloned = new osg::StateSet(*orig, osg::CopyOp::SHALLOW_COPY); + node->setStateSet(cloned); + return cloned; +} + } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 80e6090e4..1a90b8759 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -189,8 +189,19 @@ namespace NifOsg bool mEnabled; }; + class StateSetController + { + protected: + // Clones a StateSet to make it "writable". This is to prevent race conditions when the OSG draw thread of the last frame + // queues up a StateSet that we want to modify. Note, we could also set the StateSet to DYNAMIC data variance but that would + // undo all the benefits of the threading model - having the cull and draw traversals run in parallel can yield up to 200% framerates. + // If the StateSet allocations per frame are proving too much of an overhead we could "reuse" StateSets from previous frames, + // kind of like a double buffering scheme. + osg::StateSet* getWritableStateSet(osg::Node* node); + }; + // Note we're using NodeCallback instead of StateSet::Callback because the StateSet callback doesn't support nesting - struct UVController : public osg::NodeCallback, public Controller, public ValueInterpolator + class UVController : public osg::NodeCallback, public Controller, public StateSetController, public ValueInterpolator { public: UVController(); @@ -226,7 +237,7 @@ namespace NifOsg virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); }; - class AlphaController : public osg::NodeCallback, public Controller, public ValueInterpolator + class AlphaController : public osg::NodeCallback, public Controller, public StateSetController, public ValueInterpolator { private: Nif::FloatKeyMapPtr mData; @@ -241,7 +252,7 @@ namespace NifOsg META_Object(NifOsg, AlphaController) }; - class MaterialColorController : public osg::NodeCallback, public Controller, public ValueInterpolator + class MaterialColorController : public osg::NodeCallback, public Controller, public StateSetController, public ValueInterpolator { private: Nif::Vector3KeyMapPtr mData; @@ -256,7 +267,7 @@ namespace NifOsg virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); }; - class FlipController : public osg::NodeCallback, public Controller + class FlipController : public osg::NodeCallback, public Controller, public StateSetController { private: int mTexSlot; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a5c9b6e2a..a85847351 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -881,7 +881,6 @@ namespace NifOsg osg::ref_ptr ctrl = new UVController(uvctrl->data.getPtr(), texUnits); setupController(uvctrl, ctrl, animflags); - transformNode->getOrCreateStateSet()->setDataVariance(osg::StateSet::DYNAMIC); transformNode->addUpdateCallback(ctrl); } @@ -927,7 +926,6 @@ namespace NifOsg const Nif::NiAlphaController* alphactrl = static_cast(ctrl.getPtr()); osg::ref_ptr ctrl(new AlphaController(alphactrl->data.getPtr())); setupController(alphactrl, ctrl, animflags); - stateset->setDataVariance(osg::StateSet::DYNAMIC); node->addUpdateCallback(ctrl); } else if (ctrl->recType == Nif::RC_NiMaterialColorController) @@ -935,7 +933,6 @@ namespace NifOsg const Nif::NiMaterialColorController* matctrl = static_cast(ctrl.getPtr()); osg::ref_ptr ctrl(new MaterialColorController(matctrl->data.getPtr())); setupController(matctrl, ctrl, animflags); - stateset->setDataVariance(osg::StateSet::DYNAMIC); node->addUpdateCallback(ctrl); } else @@ -975,7 +972,6 @@ namespace NifOsg } osg::ref_ptr callback(new FlipController(flipctrl, textures)); setupController(ctrl.getPtr(), callback, animflags); - stateset->setDataVariance(osg::StateSet::DYNAMIC); node->addUpdateCallback(callback); } else