diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 83b2028ab3..20d108f783 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -33,7 +33,8 @@ jobs: linux-gcc11, linux-debug-gcc11, windows, - windows-debug + windows-debug, + macos-arm64 ] include: @@ -76,6 +77,15 @@ jobs: publish: false jobs: 4 + - name: macos-arm64 + os: macos-14 + buildType: RELEASE + options: .github/workflows/main/options.posix + dependenciesURL: https://github.com/GafferHQ/dependencies/releases/download/10.0.0/gafferDependencies-10.0.0-macos-arm64.tar.gz + tests: testCore testCorePython testScene testImage testAlembic testUSD testVDB + publish: true + jobs: 3 + runs-on: ${{ matrix.os }} container: ${{ matrix.containerImage }} diff --git a/.github/workflows/main/options.posix b/.github/workflows/main/options.posix index 6eaca8cd17..826a6ca678 100644 --- a/.github/workflows/main/options.posix +++ b/.github/workflows/main/options.posix @@ -63,4 +63,5 @@ ENV_VARS_TO_IMPORT = "PATH CI" if platform.system() == "Darwin" : os.environ["DYLD_FRAMEWORK_PATH"] = libs - ENV_VARS_TO_IMPORT += " DYLD_FRAMEWORK_PATH" + os.environ["PYTHONHOME"] = libs + "/Python.framework/Versions/" + pythonABIVersion + ENV_VARS_TO_IMPORT += " DYLD_FRAMEWORK_PATH PYTHONHOME" diff --git a/Changes b/Changes index ea551fb21d..80b9caf689 100644 --- a/Changes +++ b/Changes @@ -48,10 +48,23 @@ Breaking Changes - Removed support for `IECORE_RTLD_GLOBAL` environment variable. - SmoothSkinningData : Removed, along with all associated Ops and Parameters. -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) ======== +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) ========= 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; diff --git a/contrib/IECoreUSD/src/IECoreUSD/SceneCacheFileFormat.cpp b/contrib/IECoreUSD/src/IECoreUSD/SceneCacheFileFormat.cpp index e811ea4446..b01e0425b7 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 ); @@ -370,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; 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; } diff --git a/contrib/IECoreUSD/test/IECoreUSD/SceneCacheFileFormatTest.py b/contrib/IECoreUSD/test/IECoreUSD/SceneCacheFileFormatTest.py index f943a2706d..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 ) ) @@ -939,6 +954,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 )