Skip to content

Commit 31f8216

Browse files
authored
Merge pull request #1253 from johnhaddon/usdMaterialSpeedups
USDScene : Cache the reading of ShaderNetworks
2 parents d687050 + 69e9781 commit 31f8216

File tree

2 files changed

+95
-39
lines changed

2 files changed

+95
-39
lines changed

contrib/IECoreUSD/src/IECoreUSD/USDScene.cpp

Lines changed: 91 additions & 39 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
@@ -404,31 +461,16 @@ class USDScene::IO : public RefCounted
404461
public :
405462

406463
IO( const std::string &fileName, IndexedIO::OpenMode openMode )
407-
: m_fileName( fileName ), m_openMode( openMode )
464+
: IO( fileName, makeStage( fileName, openMode ), openMode )
408465
{
409-
switch( m_openMode )
410-
{
411-
case IndexedIO::Read :
412-
m_stage = pxr::UsdStage::Open( fileName );
413-
if( !m_stage )
414-
{
415-
throw IECore::Exception( boost::str( boost::format( "USDScene : Failed to open USD file: '%1%'" ) % fileName ) );
416-
}
417-
break;
418-
case IndexedIO::Write :
419-
m_stage = pxr::UsdStage::CreateNew( fileName );
420-
break;
421-
default:
422-
throw Exception( "Unsupported OpenMode" );
423-
}
424-
425-
initStage();
426466
}
427467

428-
IO( const pxr::UsdStageRefPtr &stage, IndexedIO::OpenMode openMode )
429-
: m_fileName( "" ), m_openMode( openMode ), m_stage( stage )
468+
IO( const std::string &fileName, const pxr::UsdStageRefPtr &stage, IndexedIO::OpenMode openMode )
469+
: m_fileName( fileName ), m_openMode( openMode ), m_stage( stage ),
470+
m_rootPrim( m_stage->GetPseudoRoot() ),
471+
m_timeCodesPerSecond( m_stage->GetTimeCodesPerSecond() ),
472+
m_shaderNetworkCache( 10 * 1024 * 1024 ) // 10Mb
430473
{
431-
initStage();
432474
}
433475

434476
~IO() override
@@ -443,12 +485,6 @@ class USDScene::IO : public RefCounted
443485
}
444486
}
445487

446-
void initStage()
447-
{
448-
m_timeCodesPerSecond = m_stage->GetTimeCodesPerSecond();
449-
m_rootPrim = m_stage->GetPseudoRoot();
450-
}
451-
452488
const std::string &fileName() const
453489
{
454490
return m_fileName;
@@ -511,8 +547,32 @@ class USDScene::IO : public RefCounted
511547
);
512548
}
513549

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

557+
static pxr::UsdStageRefPtr makeStage( const std::string &fileName, IndexedIO::OpenMode openMode )
558+
{
559+
switch( openMode )
560+
{
561+
case IndexedIO::Read : {
562+
pxr::UsdStageRefPtr stage = pxr::UsdStage::Open( fileName );
563+
if( !stage )
564+
{
565+
throw IECore::Exception( boost::str( boost::format( "USDScene : Failed to open USD file: '%1%'" ) % fileName ) );
566+
}
567+
return stage;
568+
}
569+
case IndexedIO::Write :
570+
return pxr::UsdStage::CreateNew( fileName );
571+
default:
572+
throw Exception( "Unsupported OpenMode" );
573+
}
574+
}
575+
516576
std::string m_fileName;
517577
IndexedIO::OpenMode m_openMode;
518578
pxr::UsdStageRefPtr m_stage;
@@ -525,6 +585,8 @@ class USDScene::IO : public RefCounted
525585
pxr::UsdShadeMaterialBindingAPI::BindingsCache m_usdBindingsCache;
526586
pxr::UsdShadeMaterialBindingAPI::CollectionQueryCache m_usdCollectionQueryCache;
527587

588+
ShaderNetworkCache m_shaderNetworkCache;
589+
528590
};
529591

530592
USDScene::USDScene( const std::string &fileName, IndexedIO::OpenMode openMode )
@@ -534,7 +596,7 @@ USDScene::USDScene( const std::string &fileName, IndexedIO::OpenMode openMode )
534596
}
535597

536598
USDScene::USDScene( const pxr::UsdStageRefPtr &stage, IndexedIO::OpenMode openMode )
537-
: m_root( new IO( stage, openMode ) ),
599+
: m_root( new IO( "", stage, openMode ) ),
538600
m_location( new Location( m_root->root() ) )
539601
{
540602
}
@@ -913,17 +975,7 @@ ConstObjectPtr USDScene::readAttribute( const SceneInterface::Name &name, double
913975
pxr::UsdShadeOutput o = mat.GetOutput( n );
914976
if( o && pxr::UsdAttribute( o ).IsAuthored() )
915977
{
916-
{
917-
pxr::UsdShadeConnectableAPI source;
918-
pxr::TfToken sourceName;
919-
pxr::UsdShadeAttributeType sourceType;
920-
if( o.GetConnectedSource( &source, &sourceName, &sourceType ) )
921-
{
922-
pxr::UsdShadeShader s( source.GetPrim() );
923-
return ShaderAlgo::readShaderNetwork( source.GetPrim().GetParent().GetPath(), s, sourceName );
924-
}
925-
}
926-
return new IECoreScene::ShaderNetwork();
978+
return m_root->readShaderNetwork( o );
927979
}
928980
}
929981
}

contrib/IECoreUSD/src/IECoreUSD/USDScene.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@
4242

4343
#include "IECore/PathMatcherData.h"
4444

45+
// Included here to avoid it being included indirectly via `stage.h`, inside the
46+
// scope of IECORE_PUSH_DEFAULT_VISIBILITY.
47+
#include "boost/function/function_base.hpp"
48+
4549
IECORE_PUSH_DEFAULT_VISIBILITY
4650
#include "pxr/usd/usd/stage.h"
4751
IECORE_POP_DEFAULT_VISIBILITY

0 commit comments

Comments
 (0)