From 5ec71099e5a4bc749f7e5a457bf88808581a8bd3 Mon Sep 17 00:00:00 2001 From: Sebastien Blaineau-Ortega Date: Mon, 11 Sep 2023 22:20:44 +0200 Subject: [PATCH] Refactoring to add support for cacheID in the hydra delegate #1664 --- libs/common/CMakeLists.txt | 1 + libs/common/SConscript | 1 + libs/common/procedural_reader.cpp | 103 ++++++++++++++++++++++++++++++ libs/common/procedural_reader.h | 22 ++++++- libs/render_delegate/reader.cpp | 57 ++--------------- libs/render_delegate/reader.h | 9 +-- libs/translator/reader/reader.cpp | 83 ------------------------ libs/translator/reader/reader.h | 15 +---- 8 files changed, 137 insertions(+), 154 deletions(-) create mode 100644 libs/common/procedural_reader.cpp diff --git a/libs/common/CMakeLists.txt b/libs/common/CMakeLists.txt index 029583b69f..0bf7f2a89a 100644 --- a/libs/common/CMakeLists.txt +++ b/libs/common/CMakeLists.txt @@ -4,6 +4,7 @@ set(COMMON_SRC "${CMAKE_CURRENT_SOURCE_DIR}/constant_strings.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/parameters_utils.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/rendersettings_utils.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/procedural_reader.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/shape_utils.cpp") set(COMMON_HDR diff --git a/libs/common/SConscript b/libs/common/SConscript index 8e0c9d2bd5..89300dffe3 100755 --- a/libs/common/SConscript +++ b/libs/common/SConscript @@ -24,6 +24,7 @@ source_files = [ 'parameters_utils.cpp', 'rendersettings_utils.cpp', 'shape_utils.cpp', + 'procedural_reader.cpp', ] if not system.IS_WINDOWS: diff --git a/libs/common/procedural_reader.cpp b/libs/common/procedural_reader.cpp new file mode 100644 index 0000000000..de0c165fe6 --- /dev/null +++ b/libs/common/procedural_reader.cpp @@ -0,0 +1,103 @@ +// +// SPDX-License-Identifier: Apache-2.0 +// + +#include "procedural_reader.h" +#include +#include +#include +#include +#include + +int s_anonymousOverrideCounter = 0; +static AtMutex s_overrideReaderMutex; + +PXR_NAMESPACE_USING_DIRECTIVE + +void ProceduralReader::Read(const std::string &filename, + AtArray *overrides, const std::string &path) +{ + // Nodes were already exported, should we skip here, + // or should we just append the new nodes ? + if (!GetNodes().empty()) { + return; + } + + SdfLayerRefPtr rootLayer = SdfLayer::FindOrOpen(filename); + _filename = filename; // Store the filename that is currently being read + _overrides = nullptr; + + if (overrides == nullptr || AiArrayGetNumElements(overrides) == 0) { + // Only open the usd file as a root layer + if (rootLayer == nullptr) { + AiMsgError("[usd] Failed to open file (%s)", filename.c_str()); + _overrides = nullptr; + return; + } + UsdStageRefPtr stage = UsdStage::Open(rootLayer, UsdStage::LoadAll); + ReadStage(stage, path); + } else { + _overrides = overrides; // Store the overrides that are currently being applied + auto getLayerName = []() -> std::string { + int counter; + { + std::lock_guard guard(s_overrideReaderMutex); + counter = s_anonymousOverrideCounter++; + } + std::stringstream ss; + ss << "anonymous__override__" << counter << ".usda"; + return ss.str(); + }; + + auto overrideLayer = SdfLayer::CreateAnonymous(getLayerName()); + const auto overrideCount = AiArrayGetNumElements(overrides); + + std::vector layerNames; + layerNames.reserve(overrideCount); + // Make sure they kep around after the loop scope ends. + std::vector layers; + layers.reserve(overrideCount); + + for (auto i = decltype(overrideCount){0}; i < overrideCount; ++i) { + auto layer = SdfLayer::CreateAnonymous(getLayerName()); + if (layer->ImportFromString(AiArrayGetStr(overrides, i).c_str())) { + layerNames.emplace_back(layer->GetIdentifier()); + layers.push_back(layer); + } + } + + overrideLayer->SetSubLayerPaths(layerNames); + // If there is no rootLayer for a usd file, we only pass the overrideLayer to prevent + // USD from crashing #235 + auto stage = rootLayer ? UsdStage::Open(rootLayer, overrideLayer, UsdStage::LoadAll) + : UsdStage::Open(overrideLayer, UsdStage::LoadAll); + + ReadStage(stage, path); + } + + _filename = ""; // finished reading, let's clear the filename + _overrides = nullptr; // clear the overrides pointer. Note that we don't own this array +} + +bool ProceduralReader::Read(int cacheId, const std::string &path) +{ + if (!GetNodes().empty()) { + return true; + } + _cacheId = cacheId; + // Load the USD stage in memory using a cache ID + UsdStageCache &stageCache = UsdUtilsStageCache::Get(); + UsdStageCache::Id id = UsdStageCache::Id::FromLongInt(cacheId); + + UsdStageRefPtr stage = (id.IsValid()) ? stageCache.Find(id) : nullptr; + if (!stage) { + AiMsgWarning("[usd] Cache ID not valid %d", cacheId); + _cacheId = 0; + return false; + } + ReadStage(stage, path); + return true; + +} + + diff --git a/libs/common/procedural_reader.h b/libs/common/procedural_reader.h index 8b281a6ed7..1dc2fc8350 100644 --- a/libs/common/procedural_reader.h +++ b/libs/common/procedural_reader.h @@ -3,7 +3,10 @@ // #pragma once +#include +#include +PXR_NAMESPACE_USING_DIRECTIVE /// @brief This is the base class for any arnold procedural reader class ProceduralReader { public: @@ -20,8 +23,21 @@ class ProceduralReader { virtual void SetUniverse(AtUniverse *universe) = 0; virtual void SetRenderSettings(const std::string &renderSettings) = 0; virtual void CreateViewportRegistry(AtProcViewportMode mode, const AtParamValueMap* params) = 0; - virtual void Read( - const std::string &filename, AtArray *overrides, const std::string &path = "") = 0; // read a USD file - virtual bool Read(int cacheId, const std::string &path = "") = 0; // read a USdStage from memory + virtual void ReadStage(UsdStageRefPtr stage, + const std::string &path) = 0; + virtual const std::vector &GetNodes() const = 0; + + const std::string &GetFilename() const { return _filename; } + const AtArray *GetOverrides() const { return _overrides; } + int GetCacheId() const {return _cacheId;} + + void Read(const std::string &filename, + AtArray *overrides, const std::string &path = ""); + + bool Read(int cacheId, const std::string &path = ""); +protected: + std::string _filename; + AtArray *_overrides = nullptr; + int _cacheId = 0; // usdStage cacheID used with a StageCache }; \ No newline at end of file diff --git a/libs/render_delegate/reader.cpp b/libs/render_delegate/reader.cpp index 92b570ef94..d47c8fed38 100644 --- a/libs/render_delegate/reader.cpp +++ b/libs/render_delegate/reader.cpp @@ -127,63 +127,20 @@ HydraArnoldReader::HydraArnoldReader(AtUniverse *universe) : _universe(universe) } const std::vector &HydraArnoldReader::GetNodes() const { return static_cast(_renderDelegate)->_nodes; } - -void HydraArnoldReader::Read(const std::string &filename, AtArray *overrides, - const std::string &path ) + +void HydraArnoldReader::ReadStage(UsdStageRefPtr stage, + const std::string &path) { HdArnoldRenderDelegate *arnoldRenderDelegate = static_cast(_renderDelegate); if (arnoldRenderDelegate == 0) return; - UsdStageRefPtr stage = nullptr; - SdfLayerRefPtr rootLayer = SdfLayer::FindOrOpen(filename); - - HydraArnoldAPI context(arnoldRenderDelegate); - if (overrides == nullptr || AiArrayGetNumElements(overrides) == 0) { - if (rootLayer == nullptr) { - AiMsgError("[usd] Failed to open file (%s)", filename.c_str()); - return; - } - stage = UsdStage::Open(rootLayer, UsdStage::LoadAll); - } else { - auto getLayerName = []() -> std::string { - int counter; - { - std::lock_guard guard(s_globalReaderMutex); - counter = s_anonymousOverrideCounter++; - } - std::stringstream ss; - ss << "anonymous__override__" << counter << ".usda"; - return ss.str(); - }; - - auto overrideLayer = SdfLayer::CreateAnonymous(getLayerName()); - const auto overrideCount = AiArrayGetNumElements(overrides); - - std::vector layerNames; - layerNames.reserve(overrideCount); - // Make sure they kep around after the loop scope ends. - std::vector layers; - layers.reserve(overrideCount); - - for (auto i = decltype(overrideCount){0}; i < overrideCount; ++i) { - auto layer = SdfLayer::CreateAnonymous(getLayerName()); - if (layer->ImportFromString(AiArrayGetStr(overrides, i).c_str())) { - layerNames.emplace_back(layer->GetIdentifier()); - layers.push_back(layer); - } - } - - overrideLayer->SetSubLayerPaths(layerNames); - // If there is no rootLayer for a usd file, we only pass the overrideLayer to prevent - // USD from crashing #235 - stage = rootLayer ? UsdStage::Open(rootLayer, overrideLayer, UsdStage::LoadAll) - : UsdStage::Open(overrideLayer, UsdStage::LoadAll); + if (stage == nullptr) { + AiMsgError("[usd] Unable to create USD stage from %s", _filename.c_str()); + return; } + HydraArnoldAPI context(arnoldRenderDelegate); - if (!stage) - return; - // if we have a procedural parent, we want to skip certain kind of prims int procMask = (arnoldRenderDelegate->GetProceduralParent()) ? (AI_NODE_CAMERA | AI_NODE_LIGHT | AI_NODE_SHAPE | AI_NODE_SHADER | AI_NODE_OPERATOR) diff --git a/libs/render_delegate/reader.h b/libs/render_delegate/reader.h index ed12a6d564..95bdf1066b 100644 --- a/libs/render_delegate/reader.h +++ b/libs/render_delegate/reader.h @@ -19,12 +19,9 @@ class HydraArnoldReader : public ProceduralReader { ~HydraArnoldReader(); const std::vector &GetNodes() const override; - void Read(const std::string &filename, AtArray *overrides, - const std::string &path = "") override; // read a USD file - - // TODO: what should the behavior in case we have a cacheId ? - bool Read(int cacheId, const std::string &path = "") override {return false;}; - + void ReadStage(UsdStageRefPtr stage, + const std::string &path) override; // read a specific UsdStage + void SetProceduralParent(AtNode *node) override; void SetUniverse(AtUniverse *universe) override; diff --git a/libs/translator/reader/reader.cpp b/libs/translator/reader/reader.cpp index 3b442f4bfa..7be72bf457 100644 --- a/libs/translator/reader/reader.cpp +++ b/libs/translator/reader/reader.cpp @@ -84,7 +84,6 @@ namespace { }; // global reader registry, will be used in the default case static UsdArnoldReaderRegistry *s_readerRegistry = nullptr; -static int s_anonymousOverrideCounter = 0; static int s_mustDeleteRegistry = 0; static AtMutex s_globalReaderMutex; @@ -101,88 +100,6 @@ UsdArnoldReader::~UsdArnoldReader() // Should we delete the created nodes in case there was no procParent ? } -void UsdArnoldReader::Read(const std::string &filename, AtArray *overrides, const std::string &path) -{ - // Nodes were already exported, should we skip here, - // or should we just append the new nodes ? - if (!_nodes.empty()) { - return; - } - - SdfLayerRefPtr rootLayer = SdfLayer::FindOrOpen(filename); - _filename = filename; // Store the filename that is currently being read - _overrides = overrides; // Store the overrides that are currently being applied - - if (overrides == nullptr || AiArrayGetNumElements(overrides) == 0) { - // Only open the usd file as a root layer - if (rootLayer == nullptr) { - AiMsgError("[usd] Failed to open file (%s)", filename.c_str()); - return; - } - UsdStageRefPtr stage = UsdStage::Open(rootLayer, UsdStage::LoadAll); - ReadStage(stage, path); - } else { - auto getLayerName = []() -> std::string { - int counter; - { - std::lock_guard guard(s_globalReaderMutex); - counter = s_anonymousOverrideCounter++; - } - std::stringstream ss; - ss << "anonymous__override__" << counter << ".usda"; - return ss.str(); - }; - - auto overrideLayer = SdfLayer::CreateAnonymous(getLayerName()); - const auto overrideCount = AiArrayGetNumElements(overrides); - - std::vector layerNames; - layerNames.reserve(overrideCount); - // Make sure they kep around after the loop scope ends. - std::vector layers; - layers.reserve(overrideCount); - - for (auto i = decltype(overrideCount){0}; i < overrideCount; ++i) { - auto layer = SdfLayer::CreateAnonymous(getLayerName()); - if (layer->ImportFromString(AiArrayGetStr(overrides, i).c_str())) { - layerNames.emplace_back(layer->GetIdentifier()); - layers.push_back(layer); - } - } - - overrideLayer->SetSubLayerPaths(layerNames); - // If there is no rootLayer for a usd file, we only pass the overrideLayer to prevent - // USD from crashing #235 - auto stage = rootLayer ? UsdStage::Open(rootLayer, overrideLayer, UsdStage::LoadAll) - : UsdStage::Open(overrideLayer, UsdStage::LoadAll); - - ReadStage(stage, path); - } - - _filename = ""; // finished reading, let's clear the filename - _overrides = nullptr; // clear the overrides pointer. Note that we don't own this array -} - -bool UsdArnoldReader::Read(int cacheId, const std::string &path) -{ - if (!_nodes.empty()) { - return true; - } - _cacheId = cacheId; - // Load the USD stage in memory using a cache ID - UsdStageCache &stageCache = UsdUtilsStageCache::Get(); - UsdStageCache::Id id = UsdStageCache::Id::FromLongInt(cacheId); - - UsdStageRefPtr stage = (id.IsValid()) ? stageCache.Find(id) : nullptr; - if (!stage) { - AiMsgWarning("[usd] Cache ID not valid %d", cacheId); - _cacheId = 0; - return false; - } - ReadStage(stage, path); - return true; -} - void UsdArnoldReader::TraverseStage(UsdPrim *rootPrim, UsdArnoldReaderContext &context, int threadId, int threadCount, bool doPointInstancer, bool doSkelData, AtArray *matrix) diff --git a/libs/translator/reader/reader.h b/libs/translator/reader/reader.h index d9b56b7b13..6419a0601e 100644 --- a/libs/translator/reader/reader.h +++ b/libs/translator/reader/reader.h @@ -56,8 +56,6 @@ class UsdArnoldReader : public ProceduralReader { _threadCount(1), _mask(AI_NODE_ALL), _defaultShader(nullptr), - _overrides(nullptr), - _cacheId(0), _hasRootPrim(false), _readStep(READ_NOT_STARTED), _purpose(UsdGeomTokens->render), @@ -66,11 +64,8 @@ class UsdArnoldReader : public ProceduralReader { } ~UsdArnoldReader(); - void Read(const std::string &filename, AtArray *overrides, - const std::string &path = "") override; // read a USD file - bool Read(int cacheId, const std::string &path = "") override; // read a USdStage from memory void ReadStage(UsdStageRefPtr stage, - const std::string &path = ""); // read a specific UsdStage + const std::string &path) override; // read a specific UsdStage void ReadPrimitive(const UsdPrim &prim, UsdArnoldReaderContext &context, bool isInstance = false, AtArray *parentMatrix = nullptr); void ClearNodes(); @@ -100,13 +95,11 @@ class UsdArnoldReader : public ProceduralReader { bool GetDebug() const { return _debug; } bool GetConvertPrimitives() const { return _convert; } const TimeSettings &GetTimeSettings() const { return _time; } - const std::string &GetFilename() const { return _filename; } - const AtArray *GetOverrides() const { return _overrides; } + unsigned int GetThreadCount() const { return _threadCount; } int GetMask() const { return _mask; } unsigned int GetId() const { return _id;} const TfToken &GetPurpose() const {return _purpose;} - int GetCacheId() const {return _cacheId;} const std::string &GetRenderSettings() const {return _renderSettings;} static unsigned int ReaderThread(void *data); @@ -231,9 +224,7 @@ class UsdArnoldReader : public ProceduralReader { std::unordered_map _shadowLinksMap; AtNode *_defaultShader; - std::string _filename; // usd filename that is currently being read - AtArray *_overrides; // usd overrides that are currently being applied on top of the usd file - int _cacheId; // usdStage cacheID used with a StageCache + bool _hasRootPrim; // are we reading this stage based on a root primitive UsdPrim _rootPrim; // eventual root primitive used to traverse the stage AtMutex _readerLock; // arnold mutex for multi-threaded translator