From dc9585a8cc13e4e3db44ef112139161495465456 Mon Sep 17 00:00:00 2001 From: Lucien Fostier Date: Wed, 3 Sep 2025 18:45:32 -0700 Subject: [PATCH 1/8] SceneCacheFileFormat: Handle invalid file path. Handle the exception to avoid crashing the application. --- .../IECoreUSD/src/IECoreUSD/SceneCacheFileFormat.cpp | 5 +++++ .../src/IECoreUSD/SdfFileFormatSharedSceneWriters.cpp | 11 ++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/contrib/IECoreUSD/src/IECoreUSD/SceneCacheFileFormat.cpp b/contrib/IECoreUSD/src/IECoreUSD/SceneCacheFileFormat.cpp index e811ea4446..cf75f70ddd 100644 --- a/contrib/IECoreUSD/src/IECoreUSD/SceneCacheFileFormat.cpp +++ b/contrib/IECoreUSD/src/IECoreUSD/SceneCacheFileFormat.cpp @@ -175,6 +175,11 @@ bool UsdSceneCacheFileFormat::WriteToFile( const SdfLayer& layer, const std::str SceneInterfacePtr outScene; outScene = SdfFileFormatSharedSceneWriters::get( filePath ); + if ( !outScene ) + { + IECore::msg( IECore::Msg::Error, "UsdSceneCacheFileFormat::WriteToFile", boost::format( "Invalid file path \"%s\" for layer \"%s\"." ) % filePath % layer.GetIdentifier() ); + return false; + } SceneInterface::NameList childNames; usdScene->childNames( childNames ); diff --git a/contrib/IECoreUSD/src/IECoreUSD/SdfFileFormatSharedSceneWriters.cpp b/contrib/IECoreUSD/src/IECoreUSD/SdfFileFormatSharedSceneWriters.cpp index 6cfc3f700a..8ced3db1f3 100644 --- a/contrib/IECoreUSD/src/IECoreUSD/SdfFileFormatSharedSceneWriters.cpp +++ b/contrib/IECoreUSD/src/IECoreUSD/SdfFileFormatSharedSceneWriters.cpp @@ -35,6 +35,7 @@ #include "SdfFileFormatSharedSceneWriters.h" #include "IECore/LRUCache.h" +#include "IECore/MessageHandler.h" using namespace IECore; using namespace IECoreScene; @@ -61,7 +62,15 @@ class Cache : public SceneLRUCache static SceneInterfacePtr fileCacheGetter( const std::string &fileName, size_t &cost ) { - SceneInterfacePtr result = SceneInterface::create( fileName, IECore::IndexedIO::Write ); + SceneInterfacePtr result = nullptr; + try + { + result = SceneInterface::create( fileName, IECore::IndexedIO::Write ); + } + catch ( ... ) + { + IECore::msg( IECore::Msg::Error, "SdfFileFormatSharedSceneWriters::SceneLRUCache", boost::format( "Unable to open file path \"%s\" for writing IndexedIo data." ) % fileName ); + } cost = 1; return result; } From a90a7e74e1cf4e3966ac7d07922fff8d499f3309 Mon Sep 17 00:00:00 2001 From: Lucien Fostier Date: Thu, 4 Sep 2025 17:25:27 -0700 Subject: [PATCH 2/8] SceneCacheFileFormatTest: Test invalid path. --- .../test/IECoreUSD/SceneCacheFileFormatTest.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/contrib/IECoreUSD/test/IECoreUSD/SceneCacheFileFormatTest.py b/contrib/IECoreUSD/test/IECoreUSD/SceneCacheFileFormatTest.py index f943a2706d..20a4748f8b 100644 --- a/contrib/IECoreUSD/test/IECoreUSD/SceneCacheFileFormatTest.py +++ b/contrib/IECoreUSD/test/IECoreUSD/SceneCacheFileFormatTest.py @@ -939,6 +939,17 @@ def testSceneWrite( self ): stage.Export( exportPath ) self.assertTrue( os.path.exists( exportPath ) ) + # invalid path + invalidExportPath = os.path.join( self.temporaryDirectory(), "invalid", "invalid.scc" ) + with IECore.CapturingMessageHandler() as mh : + stage.Export( invalidExportPath ) + + self.assertEqual( len( mh.messages ), 2 ) + self.assertEqual( mh.messages[0].level, IECore.Msg.Level.Error ) + self.assertEqual( mh.messages[0].context, "SdfFileFormatSharedSceneWriters::SceneLRUCache" ) + self.assertEqual( mh.messages[1].level, IECore.Msg.Level.Error ) + self.assertEqual( mh.messages[1].context, "UsdSceneCacheFileFormat::WriteToFile" ) + # root layer = pxr.Sdf.Layer.FindOrOpen( linkFileName ) From 2e0520dd60c369ba09372df6745d4615b20614f3 Mon Sep 17 00:00:00 2001 From: Lucien Fostier Date: Thu, 4 Sep 2025 15:44:01 -0700 Subject: [PATCH 3/8] SceneCacheData: Add support for root location tags added to the internal root. In USD, we can't add collections to the absolute root `/` so we leverage the internal root (used to work around the limitation with referencing layer in USD that get read of the file's pseudo root) to store the tags/collections. --- .../src/IECoreUSD/SceneCacheData.cpp | 24 +++++++++++++++++-- .../IECoreUSD/src/IECoreUSD/SceneCacheData.h | 2 +- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/contrib/IECoreUSD/src/IECoreUSD/SceneCacheData.cpp b/contrib/IECoreUSD/src/IECoreUSD/SceneCacheData.cpp index 3376906812..bc03f94f86 100644 --- a/contrib/IECoreUSD/src/IECoreUSD/SceneCacheData.cpp +++ b/contrib/IECoreUSD/src/IECoreUSD/SceneCacheData.cpp @@ -217,7 +217,7 @@ void SceneCacheData::addReference( ConstSceneInterfacePtr scene, SpecData& spec, addValueClip( spec, times, actives, linkFileName, linkRootPath.GetText() ); } -void SceneCacheData::addInternalRoot( TfTokenVector children ) +void SceneCacheData::addInternalRoot( TfTokenVector children, IECoreScene::ConstSceneInterfacePtr scene ) { // add transform for internal root. SdfPath internalRootPath = SdfPath::AbsoluteRootPath().AppendChild( SceneCacheDataAlgo::internalRootNameToken() ); @@ -237,6 +237,26 @@ void SceneCacheData::addInternalRoot( TfTokenVector children ) // steal root children internalRootSpec.fields.push_back( FieldValuePair( SdfChildrenKeys->PrimChildren, children ) ); + // add collection + FieldValuePair propertyChildren; + propertyChildren.first = SdfChildrenKeys->PropertyChildren; + TfTokenVector properties; + + // we don't want to keep children tags in this case. + m_collections.clear(); + + SceneInterface::NameList tags; + scene->readTags( tags ); + for ( auto& tag : tags ) + { + m_collections[tag].push_back( internalRootPath ); + } + + addCollections( internalRootSpec, properties, internalRootPath ); + + propertyChildren.second = properties; + internalRootSpec.fields.push_back( propertyChildren ); + m_data[internalRootPath] = internalRootSpec; } @@ -344,7 +364,7 @@ void SceneCacheData::loadSceneIntoCache( ConstSceneInterfacePtr scene ) // end timecode spec.fields.push_back( FieldValuePair( SdfFieldKeys->EndTimeCode, lastFrame ) ); - addInternalRoot( children ); + addInternalRoot( children, scene ); // add internal root as single child children.clear(); diff --git a/contrib/IECoreUSD/src/IECoreUSD/SceneCacheData.h b/contrib/IECoreUSD/src/IECoreUSD/SceneCacheData.h index 003e5878a9..632d5d0d98 100644 --- a/contrib/IECoreUSD/src/IECoreUSD/SceneCacheData.h +++ b/contrib/IECoreUSD/src/IECoreUSD/SceneCacheData.h @@ -179,7 +179,7 @@ class SceneCacheData : public SdfAbstractData void addCollections( SpecData& spec, TfTokenVector& properties, const SdfPath& primPath ); void addReference( IECoreScene::ConstSceneInterfacePtr scene, SpecData& spec, TfTokenVector& children ); void addValueClip( SpecData& spec, const VtVec2dArray times, const VtVec2dArray actives, const std::string& assetPath, const std::string& primPath); - void addInternalRoot( TfTokenVector children ); + void addInternalRoot( TfTokenVector children, IECoreScene::ConstSceneInterfacePtr scene ); VtValue getTimeSampleMap( const SdfPath& path, const TfToken& field, const VtValue& value ) const; From 35a1149befca0fe7d9191ffef5247b117d5d9cea Mon Sep 17 00:00:00 2001 From: Lucien Fostier Date: Wed, 3 Sep 2025 16:01:54 -0700 Subject: [PATCH 4/8] SceneCacheFileFormat: Add support for collection stored on the internalRoot. USD doesnt support writing collections on the absolute root prim (`/`) but IECoreScene does. We have some tags we want to be able to write out of Houdini that should be stored on root loacation (`/`), therefore we leverage the internal root to author the collections and map that to IECoreScene root loaction. Note that there is still a limitation for read tags from the root location and converting them to collections stored on the internal root but the current priority is to support writing out. --- .../IECoreUSD/src/IECoreUSD/SceneCacheFileFormat.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/contrib/IECoreUSD/src/IECoreUSD/SceneCacheFileFormat.cpp b/contrib/IECoreUSD/src/IECoreUSD/SceneCacheFileFormat.cpp index cf75f70ddd..b01e0425b7 100644 --- a/contrib/IECoreUSD/src/IECoreUSD/SceneCacheFileFormat.cpp +++ b/contrib/IECoreUSD/src/IECoreUSD/SceneCacheFileFormat.cpp @@ -375,6 +375,18 @@ void UsdSceneCacheFileFormat::writeLocation( } } } + // internal root is mapped to the SceneInterface root '/' + else + { + SceneInterface::NameList tags; + inChild->readTags( tags ); + // round trip internal tag name + for ( auto& tag : tags ) + { + tag = SceneCacheDataAlgo::fromInternalName( tag ); + } + outChild->writeTags( tags ); + } // recursion SceneInterface::NameList grandChildNames; From ddd1038655a28b95f100a39595ae076d74c027e8 Mon Sep 17 00:00:00 2001 From: Lucien Fostier Date: Thu, 4 Sep 2025 15:50:57 -0700 Subject: [PATCH 5/8] SceneCacheFileFormatTest: Test support for root location tags. --- .../test/IECoreUSD/SceneCacheFileFormatTest.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/contrib/IECoreUSD/test/IECoreUSD/SceneCacheFileFormatTest.py b/contrib/IECoreUSD/test/IECoreUSD/SceneCacheFileFormatTest.py index 20a4748f8b..3ce3692f85 100644 --- a/contrib/IECoreUSD/test/IECoreUSD/SceneCacheFileFormatTest.py +++ b/contrib/IECoreUSD/test/IECoreUSD/SceneCacheFileFormatTest.py @@ -320,6 +320,7 @@ def testTagsLoadedAsCollections( self ): # includes fileName = os.path.join( self.temporaryDirectory(), "testUSDTags.scc" ) m = IECoreScene.SceneCache( fileName, IECore.IndexedIO.OpenMode.Write ) + m.writeTags( ["geoId:chessy"] ) t = m.createChild( "t" ) s = t.createChild( "s" ) t.writeTags( ["t1", "all", "asset-(12)"] ) @@ -330,6 +331,16 @@ def testTagsLoadedAsCollections( self ): stage = pxr.Usd.Stage.Open( fileName ) root = stage.GetPseudoRoot() + tagInternalRootPrim = root.GetPrimAtPath( f"/{IECoreUSD.SceneCacheDataAlgo.internalRootName()}" ) + self.assertEqual( + tagInternalRootPrim.GetRelationship( + "collection:{}:includes".format( + IECoreUSD.SceneCacheDataAlgo.toInternalName( "geoId:chessy" ) + ) + ).GetTargets(), + [ pxr.Sdf.Path( f"/{IECoreUSD.SceneCacheDataAlgo.internalRootName()}" ) ] + ) + tagPrim = root.GetPrimAtPath( "/{}/t".format( IECoreUSD.SceneCacheDataAlgo.internalRootName() ) ) self.assertTrue( tagPrim ) @@ -346,6 +357,10 @@ def testTagsLoadedAsCollections( self ): stage.Export( exportPath ) scene = IECoreScene.SharedSceneInterfaces.get( exportPath ) + # check root tags + self.assertTrue( "geoId:chessy" in scene.readTags() ) + + # check children tags for tag, paths in tags.items(): for path in paths: child = scene.scene( IECoreScene.SceneInterface.stringToPath( path ) ) From 181255706aad501831665ba566e32aa650a2ea6e Mon Sep 17 00:00:00 2001 From: Lucien Fostier Date: Fri, 5 Sep 2025 11:10:03 -0700 Subject: [PATCH 6/8] Changes: Added changes for root tag improvements in IECoreUSD --- Changes | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Changes b/Changes index 372bb52f36..81a30e13c2 100644 --- a/Changes +++ b/Changes @@ -1,7 +1,15 @@ 10.5.x.x (relative to 10.5.15.3) ======== +Improvements +----- + +- IECoreUSD: Added support for root level tags (reading/writing) to our IECoreUSD::SceneCacheData plugin. + +Fixes +----- +- IECoreUSD: Fixed crash when using invalid file path with IECoreUSD::SceneCacheFileFormat. 10.5.15.3 (relative to 10.5.15.2) ========= From 53677862c40b729a6d85812bc07381a71a0e33ef Mon Sep 17 00:00:00 2001 From: Lucien Fostier Date: Mon, 8 Sep 2025 15:38:23 -0700 Subject: [PATCH 7/8] Bump version to 10.5.15.4 --- Changes | 3 +++ SConstruct | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Changes b/Changes index 81a30e13c2..b4318b0d7a 100644 --- a/Changes +++ b/Changes @@ -1,6 +1,9 @@ 10.5.x.x (relative to 10.5.15.3) ======== +10.5.15.4 (relative to 10.5.15.3) +======== + Improvements ----- diff --git a/SConstruct b/SConstruct index 27c06deb23..f4188a56d5 100644 --- a/SConstruct +++ b/SConstruct @@ -57,7 +57,7 @@ SConsignFile() ieCoreMilestoneVersion = 10 # for announcing major milestones - may contain all of the below ieCoreMajorVersion = 5 # backwards-incompatible changes ieCoreMinorVersion = 15 # new backwards-compatible features -ieCorePatchVersion = 3 # bug fixes +ieCorePatchVersion = 4 # bug fixes ieCoreVersionSuffix = "" # used for alpha/beta releases. Example: "a1", "b2", etc. ########################################################################################### From e717efcb89b6fc825b0c738c172ab631080a0118 Mon Sep 17 00:00:00 2001 From: Lucien Fostier Date: Mon, 8 Sep 2025 15:38:23 -0700 Subject: [PATCH 8/8] fix --- Changes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Changes b/Changes index b4318b0d7a..cfa6696709 100644 --- a/Changes +++ b/Changes @@ -1,4 +1,4 @@ -10.5.x.x (relative to 10.5.15.3) +10.5.x.x (relative to 10.5.15.4) ======== 10.5.15.4 (relative to 10.5.15.3)