Add sharing for more State Attributes, most notably BlendFunc and AlphaFunc, to improve the state tracking in osg::State and reduce the number of GL calls

pull/137/head
scrawl 8 years ago
parent 960d4a96c3
commit 9180089a3b

@ -1551,7 +1551,7 @@ namespace NifOsg
case Nif::RC_NiStencilProperty: case Nif::RC_NiStencilProperty:
{ {
const Nif::NiStencilProperty* stencilprop = static_cast<const Nif::NiStencilProperty*>(property); const Nif::NiStencilProperty* stencilprop = static_cast<const Nif::NiStencilProperty*>(property);
osg::FrontFace* frontFace = new osg::FrontFace; osg::ref_ptr<osg::FrontFace> frontFace = new osg::FrontFace;
switch (stencilprop->data.drawMode) switch (stencilprop->data.drawMode)
{ {
case 2: case 2:
@ -1563,6 +1563,7 @@ namespace NifOsg
frontFace->setMode(osg::FrontFace::COUNTER_CLOCKWISE); frontFace->setMode(osg::FrontFace::COUNTER_CLOCKWISE);
break; break;
} }
frontFace = shareAttribute(frontFace);
osg::StateSet* stateset = node->getOrCreateStateSet(); osg::StateSet* stateset = node->getOrCreateStateSet();
stateset->setAttribute(frontFace, osg::StateAttribute::ON); stateset->setAttribute(frontFace, osg::StateAttribute::ON);
@ -1571,11 +1572,12 @@ namespace NifOsg
if (stencilprop->data.enabled != 0) if (stencilprop->data.enabled != 0)
{ {
osg::Stencil* stencil = new osg::Stencil; osg::ref_ptr<osg::Stencil> stencil = new osg::Stencil;
stencil->setFunction(getStencilFunction(stencilprop->data.compareFunc), stencilprop->data.stencilRef, stencilprop->data.stencilMask); stencil->setFunction(getStencilFunction(stencilprop->data.compareFunc), stencilprop->data.stencilRef, stencilprop->data.stencilMask);
stencil->setStencilFailOperation(getStencilOperation(stencilprop->data.failAction)); stencil->setStencilFailOperation(getStencilOperation(stencilprop->data.failAction));
stencil->setStencilPassAndDepthFailOperation(getStencilOperation(stencilprop->data.zFailAction)); stencil->setStencilPassAndDepthFailOperation(getStencilOperation(stencilprop->data.zFailAction));
stencil->setStencilPassAndDepthPassOperation(getStencilOperation(stencilprop->data.zPassAction)); stencil->setStencilPassAndDepthPassOperation(getStencilOperation(stencilprop->data.zPassAction));
stencil = shareAttribute(stencil);
stateset->setAttributeAndModes(stencil, osg::StateAttribute::ON); stateset->setAttributeAndModes(stencil, osg::StateAttribute::ON);
} }
@ -1584,9 +1586,10 @@ namespace NifOsg
case Nif::RC_NiWireframeProperty: case Nif::RC_NiWireframeProperty:
{ {
const Nif::NiWireframeProperty* wireprop = static_cast<const Nif::NiWireframeProperty*>(property); const Nif::NiWireframeProperty* wireprop = static_cast<const Nif::NiWireframeProperty*>(property);
osg::PolygonMode* mode = new osg::PolygonMode; osg::ref_ptr<osg::PolygonMode> mode = new osg::PolygonMode;
mode->setMode(osg::PolygonMode::FRONT_AND_BACK, wireprop->flags == 0 ? osg::PolygonMode::FILL mode->setMode(osg::PolygonMode::FRONT_AND_BACK, wireprop->flags == 0 ? osg::PolygonMode::FILL
: osg::PolygonMode::LINE); : osg::PolygonMode::LINE);
mode = shareAttribute(mode);
node->getOrCreateStateSet()->setAttributeAndModes(mode, osg::StateAttribute::ON); node->getOrCreateStateSet()->setAttributeAndModes(mode, osg::StateAttribute::ON);
break; break;
} }
@ -1594,8 +1597,12 @@ namespace NifOsg
{ {
const Nif::NiZBufferProperty* zprop = static_cast<const Nif::NiZBufferProperty*>(property); const Nif::NiZBufferProperty* zprop = static_cast<const Nif::NiZBufferProperty*>(property);
// VER_MW doesn't support a DepthFunction according to NifSkope // VER_MW doesn't support a DepthFunction according to NifSkope
osg::Depth* depth = new osg::Depth; static osg::ref_ptr<osg::Depth> depth;
depth->setWriteMask((zprop->flags>>1)&1); if (!depth)
{
depth = new osg::Depth;
depth->setWriteMask((zprop->flags>>1)&1);
}
node->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); node->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON);
break; break;
} }
@ -1632,23 +1639,25 @@ namespace NifOsg
} }
} }
struct CompareMaterial struct CompareStateAttribute
{ {
bool operator() (const osg::ref_ptr<osg::Material>& left, const osg::ref_ptr<osg::Material>& right) const bool operator() (const osg::ref_ptr<osg::StateAttribute>& left, const osg::ref_ptr<osg::StateAttribute>& right) const
{ {
return left->compare(*right) < 0; return left->compare(*right) < 0;
} }
}; };
osg::Material* shareMaterial(osg::Material* mat) // global sharing of State Attributes will reduce the number of GL calls as the osg::State will check by pointer to see if state is the same
template <class Attribute>
Attribute* shareAttribute(const osg::ref_ptr<Attribute>& attr)
{ {
typedef std::set<osg::ref_ptr<osg::Material>, CompareMaterial> MatCache; typedef std::set<osg::ref_ptr<Attribute>, CompareStateAttribute> Cache;
static MatCache sMats; static Cache sCache;
static OpenThreads::Mutex sMutex; static OpenThreads::Mutex sMutex;
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(sMutex); OpenThreads::ScopedLock<OpenThreads::Mutex> lock(sMutex);
MatCache::iterator found = sMats.find(mat); typename Cache::iterator found = sCache.find(attr);
if (found == sMats.end()) if (found == sCache.end())
found = sMats.insert(mat).first; found = sCache.insert(attr).first;
return *found; return *found;
} }
@ -1715,9 +1724,10 @@ namespace NifOsg
const Nif::NiAlphaProperty* alphaprop = static_cast<const Nif::NiAlphaProperty*>(property); const Nif::NiAlphaProperty* alphaprop = static_cast<const Nif::NiAlphaProperty*>(property);
if (alphaprop->flags&1) if (alphaprop->flags&1)
{ {
stateset->setAttributeAndModes(new osg::BlendFunc(getBlendMode((alphaprop->flags>>1)&0xf), osg::ref_ptr<osg::BlendFunc> blendFunc (new osg::BlendFunc(getBlendMode((alphaprop->flags>>1)&0xf),
getBlendMode((alphaprop->flags>>5)&0xf)), getBlendMode((alphaprop->flags>>5)&0xf)));
osg::StateAttribute::ON); blendFunc = shareAttribute(blendFunc);
stateset->setAttributeAndModes(blendFunc, osg::StateAttribute::ON);
bool noSort = (alphaprop->flags>>13)&1; bool noSort = (alphaprop->flags>>13)&1;
if (!noSort) if (!noSort)
@ -1734,8 +1744,9 @@ namespace NifOsg
if((alphaprop->flags>>9)&1) if((alphaprop->flags>>9)&1)
{ {
stateset->setAttributeAndModes(new osg::AlphaFunc(getTestMode((alphaprop->flags>>10)&0x7), osg::ref_ptr<osg::AlphaFunc> alphaFunc (new osg::AlphaFunc(getTestMode((alphaprop->flags>>10)&0x7), alphaprop->data.threshold/255.f));
alphaprop->data.threshold/255.f), osg::StateAttribute::ON); alphaFunc = shareAttribute(alphaFunc);
stateset->setAttributeAndModes(alphaFunc, osg::StateAttribute::ON);
} }
else else
{ {
@ -1767,9 +1778,7 @@ namespace NifOsg
return; return;
} }
// TODO: this could be replaced by a more generic mechanism of sharing any type of State Attribute mat = shareAttribute(mat);
// apply only for Materials for now
mat = shareMaterial(mat);
stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); stateset->setAttributeAndModes(mat, osg::StateAttribute::ON);
} }

Loading…
Cancel
Save