Skip to content

Commit f3dc728

Browse files
committed
USDScene : Cache the reading of ShaderNetworks
Typically many prims will all reference the same UsdShadeMaterial, and we want to avoid loading the same material over and over again. This change gives a 10x speedup when loading the Moana island scene in Gaffer.
1 parent 6c53c7a commit f3dc728

File tree

1 file changed

+67
-12
lines changed

1 file changed

+67
-12
lines changed

contrib/IECoreUSD/src/IECoreUSD/USDScene.cpp

Lines changed: 67 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141

4242
#include "IECoreScene/ShaderNetwork.h"
4343

44+
#include "IECore/LRUCache.h"
4445
#include "IECore/MessageHandler.h"
4546
#include "IECore/SimpleTypedData.h"
4647
#include "IECore/VectorTypedData.h"
@@ -389,6 +390,62 @@ void populateMaterial( pxr::UsdShadeMaterial &mat, const std::map< const Interne
389390
}
390391
}
391392

393+
/// SdfPath is the appropriate cache key for _storage_, but we need a
394+
/// `UsdShadeOutput` for computation. This struct provides the implicit
395+
/// conversion that LRUCache needs to make that possible.
396+
struct ShaderNetworkCacheGetterKey : public pxr::UsdShadeOutput
397+
{
398+
ShaderNetworkCacheGetterKey( const pxr::UsdShadeOutput &output )
399+
: pxr::UsdShadeOutput( output )
400+
{
401+
}
402+
403+
operator pxr::SdfPath () const
404+
{
405+
return GetAttr().GetPath();
406+
}
407+
};
408+
409+
class ShaderNetworkCache : public LRUCache<pxr::SdfPath, IECoreScene::ConstShaderNetworkPtr, LRUCachePolicy::Parallel, ShaderNetworkCacheGetterKey>
410+
{
411+
412+
public :
413+
414+
ShaderNetworkCache( size_t maxBytes )
415+
: LRUCache<pxr::SdfPath, IECoreScene::ConstShaderNetworkPtr, LRUCachePolicy::Parallel, ShaderNetworkCacheGetterKey>( getter, maxBytes )
416+
{
417+
}
418+
419+
private :
420+
421+
static IECoreScene::ConstShaderNetworkPtr getter( const ShaderNetworkCacheGetterKey &key, size_t &cost )
422+
{
423+
IECoreScene::ConstShaderNetworkPtr result;
424+
425+
/// \todo I'm pretty sure that the `readShaderNetwork()` signature is overly complex,
426+
/// and it should just be passed a single `UsdShadeOutput &` like this function.
427+
/// I suspect that `writeShaderNetwork()` could take a single `UsdShadeOutput &` too,
428+
/// for symmetry between the two functions.
429+
430+
pxr::UsdShadeConnectableAPI source;
431+
pxr::TfToken sourceName;
432+
pxr::UsdShadeAttributeType sourceType;
433+
if( key.GetConnectedSource( &source, &sourceName, &sourceType ) )
434+
{
435+
pxr::UsdShadeShader s( source.GetPrim() );
436+
result = ShaderAlgo::readShaderNetwork( source.GetPrim().GetParent().GetPath(), s, sourceName );
437+
}
438+
else
439+
{
440+
result = new IECoreScene::ShaderNetwork();
441+
}
442+
443+
cost = result->Object::memoryUsage();
444+
return result;
445+
}
446+
447+
};
448+
392449
} // namespace
393450

394451
class USDScene::Location : public RefCounted
@@ -411,7 +468,8 @@ class USDScene::IO : public RefCounted
411468
IO( const std::string &fileName, const pxr::UsdStageRefPtr &stage, IndexedIO::OpenMode openMode )
412469
: m_fileName( fileName ), m_openMode( openMode ), m_stage( stage ),
413470
m_rootPrim( m_stage->GetPseudoRoot() ),
414-
m_timeCodesPerSecond( m_stage->GetTimeCodesPerSecond() )
471+
m_timeCodesPerSecond( m_stage->GetTimeCodesPerSecond() ),
472+
m_shaderNetworkCache( 10 * 1024 * 1024 ) // 10Mb
415473
{
416474
}
417475

@@ -489,6 +547,11 @@ class USDScene::IO : public RefCounted
489547
);
490548
}
491549

550+
IECoreScene::ConstShaderNetworkPtr readShaderNetwork( const pxr::UsdShadeOutput &output )
551+
{
552+
return m_shaderNetworkCache.get( output );
553+
}
554+
492555
private :
493556

494557
static pxr::UsdStageRefPtr makeStage( const std::string &fileName, IndexedIO::OpenMode openMode )
@@ -522,6 +585,8 @@ class USDScene::IO : public RefCounted
522585
pxr::UsdShadeMaterialBindingAPI::BindingsCache m_usdBindingsCache;
523586
pxr::UsdShadeMaterialBindingAPI::CollectionQueryCache m_usdCollectionQueryCache;
524587

588+
ShaderNetworkCache m_shaderNetworkCache;
589+
525590
};
526591

527592
USDScene::USDScene( const std::string &fileName, IndexedIO::OpenMode openMode )
@@ -910,17 +975,7 @@ ConstObjectPtr USDScene::readAttribute( const SceneInterface::Name &name, double
910975
pxr::UsdShadeOutput o = mat.GetOutput( n );
911976
if( o && pxr::UsdAttribute( o ).IsAuthored() )
912977
{
913-
{
914-
pxr::UsdShadeConnectableAPI source;
915-
pxr::TfToken sourceName;
916-
pxr::UsdShadeAttributeType sourceType;
917-
if( o.GetConnectedSource( &source, &sourceName, &sourceType ) )
918-
{
919-
pxr::UsdShadeShader s( source.GetPrim() );
920-
return ShaderAlgo::readShaderNetwork( source.GetPrim().GetParent().GetPath(), s, sourceName );
921-
}
922-
}
923-
return new IECoreScene::ShaderNetwork();
978+
return m_root->readShaderNetwork( o );
924979
}
925980
}
926981
}

0 commit comments

Comments
 (0)