From c838f6183609ee13f7ac6f83a0e5cc8da3a6771f Mon Sep 17 00:00:00 2001 From: Pierre Baillargeon Date: Fri, 21 Aug 2026 08:50:50 -0400 Subject: [PATCH 1/4] EMSUSD-4019 renderer provider - Added validation of the command success when retrieving the display label of a renderer. - Moved private functions to be completely private. - Added a function to return a name-indexed map of renderers for faster access by name. - Added scan of the storm renderers registry. - This also allows merging renderers with the same name reported by different APIs. - This also fixes the problem that Maya-Hydra was not correctly reported as a Hydra renderer by the Maya renderer command. - Modified `currentRenderer` and `switchRenderer` to read and write the current renderer from the SceneRenderDescription. - This becomes the fallback value if for any reason the Maya global renderer node is not found or is empty. - Added unit tests for MayaRendererProvider. - Made usage of `sceneRenderDescription` conditional on its availability. - Added more code to validate that a given `Hydra` renderer is available. - Avoid using possibly invalid renderer name when switching renderers. - Update the global settings last since that is what triggers updates elsewhere. - Added clases to automatically hold and release Hydra-related pointers. --- .../ui/renderSetup/mayaRendererProvider.cpp | 260 +++++++++++++++--- lib/usd/ui/renderSetup/mayaRendererProvider.h | 33 ++- test/lib/usd/CMakeLists.txt | 1 + test/lib/usd/ui/CMakeLists.txt | 19 ++ test/lib/usd/ui/renderSetup/CMakeLists.txt | 60 ++++ test/lib/usd/ui/renderSetup/main.cpp | 51 ++++ .../renderSetup/testMayaRendererProvider.cpp | 227 +++++++++++++++ 7 files changed, 606 insertions(+), 45 deletions(-) create mode 100644 test/lib/usd/ui/CMakeLists.txt create mode 100644 test/lib/usd/ui/renderSetup/CMakeLists.txt create mode 100644 test/lib/usd/ui/renderSetup/main.cpp create mode 100644 test/lib/usd/ui/renderSetup/testMayaRendererProvider.cpp diff --git a/lib/usd/ui/renderSetup/mayaRendererProvider.cpp b/lib/usd/ui/renderSetup/mayaRendererProvider.cpp index 8f99a01a29..3c517f43c0 100644 --- a/lib/usd/ui/renderSetup/mayaRendererProvider.cpp +++ b/lib/usd/ui/renderSetup/mayaRendererProvider.cpp @@ -16,55 +16,46 @@ #include "mayaRendererProvider.h" +#ifdef MAYA_HAS_USD_SETTINGS_NODES +#include +#endif + +#include +#include +#include + #include +#include #include +#include +#include +#include #include #include namespace MayaUsdRenderSetup { namespace { + //! \return the label Maya's own Render Settings dialog shows for `rendererName`. MString rendererUIName(const MString& rendererName) { MString cmd; cmd.format("renderer -query -rendererUIName \"^1s\"", rendererName); - MString uiName; - MGlobal::executeCommand(cmd, uiName); - return uiName; -} -} // namespace -std::vector MayaRendererProvider::availableRenderers() const -{ - MStringArray allRenderers; - MStatus status - = MGlobal::executeCommand("renderer -query -namesOfAvailableRenderers", allRenderers); - if (!status) { - MGlobal::displayWarning("Unable to retrieve available renderers."); - return {}; - } + MString uiName; + MStatus status = MGlobal::executeCommand(cmd, uiName); + if (status != MS::kSuccess) + return rendererName; - std::vector renderers; - renderers.reserve(allRenderers.length()); - for (const auto& rendererName : allRenderers) { - AdskUsdRenderSetup::RendererInfo info; - info.name = rendererName.asChar(); - info.displayName = rendererUIName(rendererName).asChar(); - info.isHydra = isHydraCapable(info.name); - renderers.push_back(info); - } - return renderers; -} + if (uiName.length() == 0) + return rendererName; -std::string MayaRendererProvider::currentRenderer() const -{ - MString result; - MGlobal::executeCommand("currentRenderer()", result); - return result.asChar(); + return uiName; } -bool MayaRendererProvider::isHydraCapable(const std::string& rendererName) const +//! \return true if the named renderer is capable of rendering through Hydra. +bool isHydraCapable(const std::string& rendererName) { MString cmd; cmd.format("renderer -query -capability \"isHydra\" \"^1s\"", MString(rendererName.c_str())); @@ -80,18 +71,213 @@ bool MayaRendererProvider::isHydraCapable(const std::string& rendererName) const return false; } - switch (result.resultType()) { - case MCommandResult::kString: { - MString value; - result.getResult(value); - return value == "true" || value == "1"; + if (result.resultType() != MCommandResult::kString) + return false; + + MString value; + result.getResult(value); + return value == "true" || value == "1"; +} + +//! \brief RAII wrapper for HdRendererPlugin pointers. +class RendererPluginPointer +{ +public: + RendererPluginPointer( + PXR_NS::HdRendererPluginRegistry& registry, + const PXR_NS::TfToken& rendererId) + : _registry(registry) + , _plugin(registry.GetRendererPlugin(rendererId)) + { + } + + ~RendererPluginPointer() + { + if (_plugin) { + _registry.ReleasePlugin(_plugin); + } + } + + PXR_NS::HdRendererPlugin* get() const { return _plugin; } + +private: + PXR_NS::HdRendererPluginRegistry& _registry; + PXR_NS::HdRendererPlugin* _plugin; +}; + +//! \brief RAII wrapper for HdRenderDelegate pointers. +class RenderDelegatePointer +{ +public: + RenderDelegatePointer(PXR_NS::HdRendererPlugin* plugin) + : _plugin(plugin) + , _delegate(plugin ? plugin->CreateRenderDelegate() : nullptr) + { + } + + ~RenderDelegatePointer() + { + if (_plugin && _delegate) { + _plugin->DeleteRenderDelegate(_delegate); + } } - default: return false; + + PXR_NS::HdRenderDelegate* get() const { return _delegate; } + +private: + PXR_NS::HdRendererPlugin* _plugin; + PXR_NS::HdRenderDelegate* _delegate; +}; + +//! \return true if the named renderer is available and capable of rendering through Hydra. +bool isHydraRendererAvailable( + PXR_NS::HdRendererPluginRegistry& registry, + const PXR_NS::TfToken& rendererId) +{ + RendererPluginPointer plugin(registry, rendererId); + if (!plugin.get()) + return false; + + // As of 22.02, this needs to be called for Storm + if (rendererId == PXR_NS::TfToken("HdStormRendererPlugin")) { + PXR_NS::GlfContextCaps::InitInstance(); } + + if (!plugin.get()->IsSupported()) + return false; + + RenderDelegatePointer delegate(plugin.get()); + if (!delegate.get()) + return false; + + return true; +} + +//! \return a map of every renderer Maya currently knows about, Hydra-capable or not. +std::map getRenderersMap() +{ + std::map renderers; + + { + MStringArray mayaRenderers; + MStatus status + = MGlobal::executeCommand("renderer -query -namesOfAvailableRenderers", mayaRenderers); + if (!status) { + MGlobal::displayWarning("Unable to retrieve available renderers."); + } else { + for (const auto& rendererName : mayaRenderers) { + AdskUsdRenderSetup::RendererInfo info; + info.name = rendererName.asChar(); + info.displayName = rendererUIName(rendererName).asChar(); + info.isHydra = isHydraCapable(info.name); + renderers[info.name] = std::move(info); + } + } + } + + { + PXR_NS::HdRendererPluginRegistry& registry + = PXR_NS::HdRendererPluginRegistry::GetInstance(); + std::vector hydraDescs; + registry.GetPluginDescs(&hydraDescs); + + for (const auto& desc : hydraDescs) { + const PXR_NS::TfToken rendererId = desc.id; + if (!isHydraRendererAvailable(registry, rendererId)) { + continue; + } + + // Note: some Hydra renderers may also be registered in Maya's legacy renderer registry, + // so we need to merge the two lists. + // + // The display-name registered with Maya is usually better than the one registered + // with Hydra, so we prefer that one if it exists. In that case we only update the + // isHydra flag, since the `isHydraCapable` query might not be reliable for some + // renderers. + const std::string name = rendererId.GetText(); + auto it = renderers.find(name); + if (it != renderers.end()) { + it->second.isHydra = true; + } else { + renderers[name] = AdskUsdRenderSetup::RendererInfo { name, desc.displayName, true }; + } + } + } + + return renderers; +} + +} // namespace + +std::vector MayaRendererProvider::availableRenderers() const +{ + std::vector renderers; + + auto renderersMap = getRenderersMap(); + renderers.reserve(renderersMap.size()); + for (const auto& pair : renderersMap) { + renderers.push_back(pair.second); + } + + return renderers; +} + +std::string MayaRendererProvider::currentRenderer() const +{ + MSelectionList slist; + slist.add("defaultRenderGlobals"); + MObject defaultRenderGlobalsObj; + if (slist.length() > 0 && slist.getDependNode(0, defaultRenderGlobalsObj)) { + MFnDependencyNode depNode(defaultRenderGlobalsObj); + MPlug currentRendererPlug = depNode.findPlug("currentRenderer", false); + if (!currentRendererPlug.isNull()) { + MString value; + currentRendererPlug.getValue(value); + if (value.length() > 0) { + return value.asChar(); + } + } + } + +#ifdef MAYA_HAS_USD_SETTINGS_NODES + std::string hydraRenderer = MAYAUSD_NS_DEF::SceneRenderDescription::getCurrentRenderer(); + if (!hydraRenderer.empty()) { + return hydraRenderer; + } +#endif + + return std::string(); } void MayaRendererProvider::switchRenderer(const std::string& next) { + // TODO: should we allow setting an empty renderer? + if (next.empty()) { + return; + } + + // This validates that the renderer is available and avoid + // using some arbitrary string in the MEL command. + { + const auto avail = getRenderersMap(); + const auto it = avail.find(next); + if (it == avail.end()) + return; + +#ifdef MAYA_HAS_USD_SETTINGS_NODES + if (it->second.isHydra) { + MAYAUSD_NS_DEF::SceneRenderDescription::setCurrentRenderer(next); + } else { + // TODO: do we need to clear the SceneRenderDescription current renderer when the + // renderer is switched to a legacy renderer? + MAYAUSD_NS_DEF::SceneRenderDescription::setCurrentRenderer(""); + } +#endif + } + + // Note: other code watch the "currentRenderer" attribute of the defaultRenderGlobals node, + // so we change it last after we already updated the `SceneRenderDescription` current + // renderer. MString cmd; cmd.format("setCurrentRenderer(\"^1s\")", MString(next.c_str())); MGlobal::executeCommand(cmd); diff --git a/lib/usd/ui/renderSetup/mayaRendererProvider.h b/lib/usd/ui/renderSetup/mayaRendererProvider.h index f09a374455..0e691eb5f2 100644 --- a/lib/usd/ui/renderSetup/mayaRendererProvider.h +++ b/lib/usd/ui/renderSetup/mayaRendererProvider.h @@ -17,14 +17,28 @@ #ifndef MAYAUSDUI_USD_RENDERSETUP_MAYARENDERERPROVIDER_H #define MAYAUSDUI_USD_RENDERSETUP_MAYARENDERERPROVIDER_H +#include + #include +#include +#include + namespace MayaUsdRenderSetup { //! MayaUSD implementation of AdskUsdRenderSetup::IRendererProvider for the Render Setup UI. -//! Lists every renderer Maya knows about and reads/writes Maya's global current renderer -//! (defaultRenderGlobals.currentRenderer). -class MayaRendererProvider : public AdskUsdRenderSetup::IRendererProvider +//! Reports available renderers from Maya's legacy renderer registry (mayaSoftware, arnold, etc., +//! marked isHydra=false) and from Hydra's HdRendererPluginRegistry (marked isHydra=true). +//! Reads and writes the current renderer from the appropriate store: +//! - Hydra renderers: UsdSettingsNode::currentRenderer attribute +//! - Legacy renderers: defaultRenderGlobals.currentRenderer attribute +#if defined(_MSC_VER) +// AdskUsdRenderSetup::IRendererProvider is a header-only interface (all its methods are +// inline), so it needs no dll-interface of its own for MayaRendererProvider to export safely. +#pragma warning(push) +#pragma warning(disable : 4275) +#endif +class MAYAUSD_UI_PUBLIC MayaRendererProvider : public AdskUsdRenderSetup::IRendererProvider { public: //! \return every renderer Maya currently knows about, Hydra-capable or not. @@ -34,13 +48,16 @@ class MayaRendererProvider : public AdskUsdRenderSetup::IRendererProvider std::string currentRenderer() const override; protected: - //! Switches Maya's current renderer via the setCurrentRenderer MEL proc. + //! Requests a switch to the named renderer. Leaves currentRenderer() unchanged + //! (and thus switchRenderer is implicitly declined) if the name is unknown. + //! For Hydra renderers: writes UsdSettingsNode::currentRenderer. + //! For legacy renderers: writes defaultRenderGlobals.currentRenderer and clears + //! UsdSettingsNode. void switchRenderer(const std::string& next) override; - -private: - //! \return true if `rendererName` reports the "isHydra" capability. - bool isHydraCapable(const std::string& rendererName) const; }; +#if defined(_MSC_VER) +#pragma warning(pop) +#endif } // namespace MayaUsdRenderSetup diff --git a/test/lib/usd/CMakeLists.txt b/test/lib/usd/CMakeLists.txt index a583b09f8f..e27dba5d0b 100644 --- a/test/lib/usd/CMakeLists.txt +++ b/test/lib/usd/CMakeLists.txt @@ -1,5 +1,6 @@ add_subdirectory(plugin) add_subdirectory(pxrUsdPreviewSurface) add_subdirectory(schemas) +add_subdirectory(ui) add_subdirectory(utils) add_subdirectory(translators) diff --git a/test/lib/usd/ui/CMakeLists.txt b/test/lib/usd/ui/CMakeLists.txt new file mode 100644 index 0000000000..9450ad30aa --- /dev/null +++ b/test/lib/usd/ui/CMakeLists.txt @@ -0,0 +1,19 @@ +# +# Copyright 2026 Autodesk +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +if (AdskUsdRenderSetup_FOUND) + add_subdirectory(renderSetup) +endif() diff --git a/test/lib/usd/ui/renderSetup/CMakeLists.txt b/test/lib/usd/ui/renderSetup/CMakeLists.txt new file mode 100644 index 0000000000..9a3f180cf7 --- /dev/null +++ b/test/lib/usd/ui/renderSetup/CMakeLists.txt @@ -0,0 +1,60 @@ +# +# Copyright 2026 Autodesk +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# ----------------------------------------------------------------------------- +# C++ unit tests +# +# MayaRendererProvider talks to a live Maya session (MEL "renderer" queries, +# defaultRenderGlobals) and to USD's Hydra plugin registry, so this test +# brings up Maya in library ("standalone") mode itself (see main.cpp) rather +# than relying on Python's maya.standalone, which the other C++ tests under +# test/lib/mayaUsd/utils don't need. +# ----------------------------------------------------------------------------- +if(IS_WINDOWS AND MAYA_HAS_USD_SETTINGS_NODES) + # Mirrors the Windows-only gating used for the other C++ tests that link + # Maya + USD together (see test/lib/mayaUsd/utils/CMakeLists.txt). + add_executable(testMayaRendererProvider) + + target_sources(testMayaRendererProvider + PRIVATE + main.cpp + testMayaRendererProvider.cpp + ) + + mayaUsd_compile_config(testMayaRendererProvider) + + target_include_directories(testMayaRendererProvider + PRIVATE + ${ADSK_USD_RENDER_SETUP_INCLUDE_DIR} + ) + + target_link_libraries(testMayaRendererProvider + PRIVATE + GTest::GTest + ${MAYA_LIBRARIES} + mayaUsd + mayaUsdUI + ) + + mayaUsd_add_test(testMayaRendererProvider + COMMAND $ + ENV + "LD_LIBRARY_PATH=${ADDITIONAL_LD_LIBRARY_PATH}" + "MAYA_LOCATION=${MAYA_LOCATION}" + ) + + set_property(TEST testMayaRendererProvider APPEND PROPERTY LABELS SharedComponents) +endif() diff --git a/test/lib/usd/ui/renderSetup/main.cpp b/test/lib/usd/ui/renderSetup/main.cpp new file mode 100644 index 0000000000..58c648fc92 --- /dev/null +++ b/test/lib/usd/ui/renderSetup/main.cpp @@ -0,0 +1,51 @@ +// +// Copyright 2026 Autodesk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// MayaRendererProvider issues MEL "renderer" queries and looks up +// defaultRenderGlobals, so (unlike the other C++ unit tests under +// test/lib/mayaUsd/utils) this test executable needs a real Maya session. +// Bring one up in library mode before handing control to gtest. + +#include +#include + +#include + +#include + +int main(int argc, char** argv) +{ + MStatus status = MLibrary::initialize(argv[0], /*useBatchLicense*/ true); + if (!status) { + status.perror("MLibrary::initialize"); + return 1; + } + + // Registers UsdSettingsNode/UsdDefaultRenderDescription (used by + // MayaRendererProvider's Hydra-side currentRenderer()/switchRenderer()) + // and the setCurrentRenderer MEL proc that switchRenderer() invokes. + if (!MGlobal::executeCommand("loadPlugin \"mayaUsdPlugin\"")) { + fprintf(stderr, "Failed to load mayaUsdPlugin.\n"); + MLibrary::cleanup(1); + return 1; + } + + ::testing::InitGoogleTest(&argc, argv); + int result = RUN_ALL_TESTS(); + + MLibrary::cleanup(result); + return result; +} diff --git a/test/lib/usd/ui/renderSetup/testMayaRendererProvider.cpp b/test/lib/usd/ui/renderSetup/testMayaRendererProvider.cpp new file mode 100644 index 0000000000..2a15f72944 --- /dev/null +++ b/test/lib/usd/ui/renderSetup/testMayaRendererProvider.cpp @@ -0,0 +1,227 @@ +// +// Copyright 2026 Autodesk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include + +namespace { + +// Exposes the protected switchRenderer() so edge cases (empty name, unknown +// name) can be exercised directly, independently of requestRenderer()'s own +// "already current" guard. +class TestableRendererProvider : public MayaUsdRenderSetup::MayaRendererProvider +{ +public: + using MayaUsdRenderSetup::MayaRendererProvider::switchRenderer; +}; + +std::string getLegacyCurrentRenderer() +{ + MString value; + MGlobal::executeCommand("getAttr defaultRenderGlobals.currentRenderer", value); + return value.asChar(); +} + +void setLegacyCurrentRenderer(const std::string& name) +{ + MString cmd; + cmd.format( + "setAttr -type \"string\" defaultRenderGlobals.currentRenderer \"^1s\"", + MString(name.c_str())); + MGlobal::executeCommand(cmd); +} + +void setHydraCurrentRenderer(const std::string& name) +{ + MAYAUSD_NS_DEF::SceneRenderDescription::setCurrentRenderer(name); +} + +using RendererInfo = AdskUsdRenderSetup::RendererInfo; + +std::vector::const_iterator +findByHydra(const std::vector& renderers, bool isHydra) +{ + return std::find_if(renderers.begin(), renderers.end(), [isHydra](const RendererInfo& r) { + return r.isHydra == isHydra; + }); +} + +// Used where the test only cares about the defaultRenderGlobals.currentRenderer +// plug's raw value, not about the name being one MayaRendererProvider actually +// knows about (i.e. not exercising the isHydra-classification branches, which +// require a name present in availableRenderers()). +const char* const kArbitraryRendererName = "some-arbitrary-renderer-name"; + +} // namespace + +class MayaRendererProviderTest : public ::testing::Test +{ +protected: + void SetUp() override + { + _origLegacyRenderer = getLegacyCurrentRenderer(); + _origHydraRenderer = MAYAUSD_NS_DEF::SceneRenderDescription::getCurrentRenderer(); + } + + void TearDown() override + { + setLegacyCurrentRenderer(_origLegacyRenderer); + setHydraCurrentRenderer(_origHydraRenderer); + } + + MayaUsdRenderSetup::MayaRendererProvider provider; + +private: + std::string _origLegacyRenderer; + std::string _origHydraRenderer; +}; + +TEST_F(MayaRendererProviderTest, AvailableRenderersHasNoDuplicateNames) +{ + const auto renderers = provider.availableRenderers(); + + std::set names; + for (const auto& r : renderers) { + EXPECT_TRUE(names.insert(r.name).second) << "Duplicate renderer name: " << r.name; + } +} + +TEST_F(MayaRendererProviderTest, CurrentRendererMatchesDefaultRenderGlobalsWhenSet) +{ + setLegacyCurrentRenderer(kArbitraryRendererName); + setHydraCurrentRenderer(""); + + EXPECT_EQ(provider.currentRenderer(), kArbitraryRendererName); +} + +TEST_F(MayaRendererProviderTest, CurrentRendererFallsBackToSceneRenderDescriptionWhenLegacyEmpty) +{ + const auto renderers = provider.availableRenderers(); + const auto it = findByHydra(renderers, /*isHydra*/ true); + if (it == renderers.end()) { + GTEST_SKIP() << "No Hydra renderer plugins registered in this environment."; + } + + setLegacyCurrentRenderer(""); + setHydraCurrentRenderer(it->name); + + EXPECT_EQ(provider.currentRenderer(), it->name); +} + +TEST_F(MayaRendererProviderTest, CurrentRendererIsEmptyWhenBothStoresAreEmpty) +{ + setLegacyCurrentRenderer(""); + setHydraCurrentRenderer(""); + + EXPECT_TRUE(provider.currentRenderer().empty()); +} + +TEST_F(MayaRendererProviderTest, RequestRendererToHydraRendererUpdatesSceneRenderDescription) +{ + const auto renderers = provider.availableRenderers(); + const auto it = findByHydra(renderers, /*isHydra*/ true); + if (it == renderers.end()) { + GTEST_SKIP() << "No Hydra renderer plugins registered in this environment."; + } + + setLegacyCurrentRenderer(""); + setHydraCurrentRenderer(""); + + provider.requestRenderer(it->name); + + EXPECT_EQ(provider.currentRenderer(), it->name); + EXPECT_EQ(MAYAUSD_NS_DEF::SceneRenderDescription::getCurrentRenderer(), it->name); +} + +TEST_F(MayaRendererProviderTest, RequestRendererToLegacyRendererClearsSceneRenderDescription) +{ + const auto renderers = provider.availableRenderers(); + const auto legacyIt = findByHydra(renderers, /*isHydra*/ false); + if (legacyIt == renderers.end()) { + GTEST_SKIP() << "No legacy (non-Hydra) renderers registered in this environment."; + } + + // Seed a non-empty Hydra renderer first so we can verify the switch clears it. + const auto hydraIt = findByHydra(renderers, /*isHydra*/ true); + if (hydraIt != renderers.end()) { + setHydraCurrentRenderer(hydraIt->name); + } else { + GTEST_SKIP() << "No Hydra renderers registered in this environment."; + } + + provider.requestRenderer(legacyIt->name); + + EXPECT_EQ(provider.currentRenderer(), legacyIt->name); + EXPECT_TRUE(MAYAUSD_NS_DEF::SceneRenderDescription::getCurrentRenderer().empty()); +} + +TEST_F(MayaRendererProviderTest, RequestRendererWithUnknownNameLeavesCurrentRendererUnchanged) +{ + setLegacyCurrentRenderer(kArbitraryRendererName); + setHydraCurrentRenderer(""); + + provider.requestRenderer("totally-bogus-renderer-name-xyz"); + + EXPECT_EQ(provider.currentRenderer(), kArbitraryRendererName); +} + +TEST_F(MayaRendererProviderTest, RequestRendererAlreadyCurrentIsNoOp) +{ + setLegacyCurrentRenderer(kArbitraryRendererName); + // Sentinel: a legacy switch would clear this. If requestRenderer correctly + // treats "already current" as a no-op, switchRenderer never runs and this + // survives untouched. + setHydraCurrentRenderer("sentinel-value"); + + provider.requestRenderer(kArbitraryRendererName); + + EXPECT_EQ(provider.currentRenderer(), kArbitraryRendererName); + EXPECT_EQ(MAYAUSD_NS_DEF::SceneRenderDescription::getCurrentRenderer(), "sentinel-value"); +} + +TEST_F(MayaRendererProviderTest, SwitchRendererWithEmptyNameIsNoOp) +{ + setLegacyCurrentRenderer(kArbitraryRendererName); + setHydraCurrentRenderer("sentinel-value"); + + TestableRendererProvider testable; + testable.switchRenderer(""); + + EXPECT_EQ(getLegacyCurrentRenderer(), kArbitraryRendererName); + EXPECT_EQ(MAYAUSD_NS_DEF::SceneRenderDescription::getCurrentRenderer(), "sentinel-value"); +} + +TEST_F(MayaRendererProviderTest, SwitchRendererWithUnknownNameDoesNotTouchSceneRenderDescription) +{ + setHydraCurrentRenderer("sentinel-value"); + + TestableRendererProvider testable; + testable.switchRenderer("totally-bogus-renderer-name-xyz"); + + // An unknown name is not found in the internal renderer map, so the + // isHydra-branch that writes/clears SceneRenderDescription never runs. + EXPECT_EQ(MAYAUSD_NS_DEF::SceneRenderDescription::getCurrentRenderer(), "sentinel-value"); +} From 960d0d95a4b53efb2d4db4e691c1e15004816aa7 Mon Sep 17 00:00:00 2001 From: Pierre Baillargeon Date: Wed, 26 Aug 2026 10:24:04 -0400 Subject: [PATCH 2/4] EMSUSD-4019 small pdates - Removed copyrights in cmake files. - Trying to build C++ test on all platforms. - Using MayaUsd Namespace. - Using a std::string instead of a const char* --- lib/usd/ui/renderSetup/CMakeLists.txt | 16 ---------------- test/lib/usd/ui/renderSetup/CMakeLists.txt | 18 +----------------- .../renderSetup/testMayaRendererProvider.cpp | 16 ++++++++-------- 3 files changed, 9 insertions(+), 41 deletions(-) diff --git a/lib/usd/ui/renderSetup/CMakeLists.txt b/lib/usd/ui/renderSetup/CMakeLists.txt index 5ef42945e1..8e06ef15ed 100644 --- a/lib/usd/ui/renderSetup/CMakeLists.txt +++ b/lib/usd/ui/renderSetup/CMakeLists.txt @@ -1,20 +1,4 @@ -# -# Copyright 2026 Autodesk -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - add_subdirectory(rendering) target_sources(${PROJECT_NAME} diff --git a/test/lib/usd/ui/renderSetup/CMakeLists.txt b/test/lib/usd/ui/renderSetup/CMakeLists.txt index 9a3f180cf7..ea9cbd4cda 100644 --- a/test/lib/usd/ui/renderSetup/CMakeLists.txt +++ b/test/lib/usd/ui/renderSetup/CMakeLists.txt @@ -1,19 +1,3 @@ -# -# Copyright 2026 Autodesk -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - # ----------------------------------------------------------------------------- # C++ unit tests # @@ -23,7 +7,7 @@ # than relying on Python's maya.standalone, which the other C++ tests under # test/lib/mayaUsd/utils don't need. # ----------------------------------------------------------------------------- -if(IS_WINDOWS AND MAYA_HAS_USD_SETTINGS_NODES) +if(MAYA_HAS_USD_SETTINGS_NODES) # Mirrors the Windows-only gating used for the other C++ tests that link # Maya + USD together (see test/lib/mayaUsd/utils/CMakeLists.txt). add_executable(testMayaRendererProvider) diff --git a/test/lib/usd/ui/renderSetup/testMayaRendererProvider.cpp b/test/lib/usd/ui/renderSetup/testMayaRendererProvider.cpp index 2a15f72944..096bf71fa1 100644 --- a/test/lib/usd/ui/renderSetup/testMayaRendererProvider.cpp +++ b/test/lib/usd/ui/renderSetup/testMayaRendererProvider.cpp @@ -56,7 +56,7 @@ void setLegacyCurrentRenderer(const std::string& name) void setHydraCurrentRenderer(const std::string& name) { - MAYAUSD_NS_DEF::SceneRenderDescription::setCurrentRenderer(name); + MayaUsd::SceneRenderDescription::setCurrentRenderer(name); } using RendererInfo = AdskUsdRenderSetup::RendererInfo; @@ -73,7 +73,7 @@ findByHydra(const std::vector& renderers, bool isHydra) // plug's raw value, not about the name being one MayaRendererProvider actually // knows about (i.e. not exercising the isHydra-classification branches, which // require a name present in availableRenderers()). -const char* const kArbitraryRendererName = "some-arbitrary-renderer-name"; +const std::string kArbitraryRendererName("some-arbitrary-renderer-name"); } // namespace @@ -83,7 +83,7 @@ class MayaRendererProviderTest : public ::testing::Test void SetUp() override { _origLegacyRenderer = getLegacyCurrentRenderer(); - _origHydraRenderer = MAYAUSD_NS_DEF::SceneRenderDescription::getCurrentRenderer(); + _origHydraRenderer = MayaUsd::SceneRenderDescription::getCurrentRenderer(); } void TearDown() override @@ -153,7 +153,7 @@ TEST_F(MayaRendererProviderTest, RequestRendererToHydraRendererUpdatesSceneRende provider.requestRenderer(it->name); EXPECT_EQ(provider.currentRenderer(), it->name); - EXPECT_EQ(MAYAUSD_NS_DEF::SceneRenderDescription::getCurrentRenderer(), it->name); + EXPECT_EQ(MayaUsd::SceneRenderDescription::getCurrentRenderer(), it->name); } TEST_F(MayaRendererProviderTest, RequestRendererToLegacyRendererClearsSceneRenderDescription) @@ -175,7 +175,7 @@ TEST_F(MayaRendererProviderTest, RequestRendererToLegacyRendererClearsSceneRende provider.requestRenderer(legacyIt->name); EXPECT_EQ(provider.currentRenderer(), legacyIt->name); - EXPECT_TRUE(MAYAUSD_NS_DEF::SceneRenderDescription::getCurrentRenderer().empty()); + EXPECT_TRUE(MayaUsd::SceneRenderDescription::getCurrentRenderer().empty()); } TEST_F(MayaRendererProviderTest, RequestRendererWithUnknownNameLeavesCurrentRendererUnchanged) @@ -199,7 +199,7 @@ TEST_F(MayaRendererProviderTest, RequestRendererAlreadyCurrentIsNoOp) provider.requestRenderer(kArbitraryRendererName); EXPECT_EQ(provider.currentRenderer(), kArbitraryRendererName); - EXPECT_EQ(MAYAUSD_NS_DEF::SceneRenderDescription::getCurrentRenderer(), "sentinel-value"); + EXPECT_EQ(MayaUsd::SceneRenderDescription::getCurrentRenderer(), "sentinel-value"); } TEST_F(MayaRendererProviderTest, SwitchRendererWithEmptyNameIsNoOp) @@ -211,7 +211,7 @@ TEST_F(MayaRendererProviderTest, SwitchRendererWithEmptyNameIsNoOp) testable.switchRenderer(""); EXPECT_EQ(getLegacyCurrentRenderer(), kArbitraryRendererName); - EXPECT_EQ(MAYAUSD_NS_DEF::SceneRenderDescription::getCurrentRenderer(), "sentinel-value"); + EXPECT_EQ(MayaUsd::SceneRenderDescription::getCurrentRenderer(), "sentinel-value"); } TEST_F(MayaRendererProviderTest, SwitchRendererWithUnknownNameDoesNotTouchSceneRenderDescription) @@ -223,5 +223,5 @@ TEST_F(MayaRendererProviderTest, SwitchRendererWithUnknownNameDoesNotTouchSceneR // An unknown name is not found in the internal renderer map, so the // isHydra-branch that writes/clears SceneRenderDescription never runs. - EXPECT_EQ(MAYAUSD_NS_DEF::SceneRenderDescription::getCurrentRenderer(), "sentinel-value"); + EXPECT_EQ(MayaUsd::SceneRenderDescription::getCurrentRenderer(), "sentinel-value"); } From 2064403b7a1c99d830d1729cbe5203c8129a037a Mon Sep 17 00:00:00 2001 From: Pierre Baillargeon Date: Wed, 26 Aug 2026 11:09:30 -0400 Subject: [PATCH 3/4] EMSUSD-4019 trying to make C++ test work on MacOSX --- test/lib/usd/ui/renderSetup/CMakeLists.txt | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/test/lib/usd/ui/renderSetup/CMakeLists.txt b/test/lib/usd/ui/renderSetup/CMakeLists.txt index ea9cbd4cda..12a1f75308 100644 --- a/test/lib/usd/ui/renderSetup/CMakeLists.txt +++ b/test/lib/usd/ui/renderSetup/CMakeLists.txt @@ -8,8 +8,6 @@ # test/lib/mayaUsd/utils don't need. # ----------------------------------------------------------------------------- if(MAYA_HAS_USD_SETTINGS_NODES) - # Mirrors the Windows-only gating used for the other C++ tests that link - # Maya + USD together (see test/lib/mayaUsd/utils/CMakeLists.txt). add_executable(testMayaRendererProvider) target_sources(testMayaRendererProvider @@ -18,6 +16,14 @@ if(MAYA_HAS_USD_SETTINGS_NODES) testMayaRendererProvider.cpp ) + target_compile_definitions(testMayaRendererProvider + PRIVATE + $<$:TBB_USE_DEBUG> + # Needed by Pixar's wrap_python.hpp + $<$:BOOST_DEBUG_PYTHON> + $<$:BOOST_LINKING_PYTHON> + ) + mayaUsd_compile_config(testMayaRendererProvider) target_include_directories(testMayaRendererProvider @@ -41,4 +47,10 @@ if(MAYA_HAS_USD_SETTINGS_NODES) ) set_property(TEST testMayaRendererProvider APPEND PROPERTY LABELS SharedComponents) + + if(IS_MACOSX) + # Create symbolic link to python framework + file(CREATE_LINK ${MAYA_LOCATION}/Frameworks ${CMAKE_CURRENT_BINARY_DIR}/../Frameworks SYMBOLIC) + endif() + endif() From 5833b6211fc3884563f54082d0db31b6bc1eb393 Mon Sep 17 00:00:00 2001 From: Pierre Baillargeon Date: Wed, 26 Aug 2026 13:26:42 -0400 Subject: [PATCH 4/4] EMSUSD-4019 test on MacOSX fails to find python --- test/lib/usd/ui/renderSetup/CMakeLists.txt | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/test/lib/usd/ui/renderSetup/CMakeLists.txt b/test/lib/usd/ui/renderSetup/CMakeLists.txt index 12a1f75308..ee14bfec45 100644 --- a/test/lib/usd/ui/renderSetup/CMakeLists.txt +++ b/test/lib/usd/ui/renderSetup/CMakeLists.txt @@ -7,7 +7,7 @@ # than relying on Python's maya.standalone, which the other C++ tests under # test/lib/mayaUsd/utils don't need. # ----------------------------------------------------------------------------- -if(MAYA_HAS_USD_SETTINGS_NODES) +if(MAYA_HAS_USD_SETTINGS_NODES AND NOT IS_MACOSX) add_executable(testMayaRendererProvider) target_sources(testMayaRendererProvider @@ -16,14 +16,6 @@ if(MAYA_HAS_USD_SETTINGS_NODES) testMayaRendererProvider.cpp ) - target_compile_definitions(testMayaRendererProvider - PRIVATE - $<$:TBB_USE_DEBUG> - # Needed by Pixar's wrap_python.hpp - $<$:BOOST_DEBUG_PYTHON> - $<$:BOOST_LINKING_PYTHON> - ) - mayaUsd_compile_config(testMayaRendererProvider) target_include_directories(testMayaRendererProvider @@ -47,10 +39,4 @@ if(MAYA_HAS_USD_SETTINGS_NODES) ) set_property(TEST testMayaRendererProvider APPEND PROPERTY LABELS SharedComponents) - - if(IS_MACOSX) - # Create symbolic link to python framework - file(CREATE_LINK ${MAYA_LOCATION}/Frameworks ${CMAKE_CURRENT_BINARY_DIR}/../Frameworks SYMBOLIC) - endif() - endif()