diff --git a/CMakeLists.txt b/CMakeLists.txt index e3550e0777..94d9799970 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,8 @@ project(maya-usd) option(BUILD_TESTS "Build tests." ON) option(BUILD_STRICT_MODE "Enforce all warnings as errors." ON) option(BUILD_SHARED_LIBS "Build libraries as shared or static." ON) +option(CODE_COVERAGE "Build and collect code coverage info." OFF) + if(APPLE) option(BUILD_UB2 "Build Universal Binary 2 (UB2) Intel64+arm64" OFF) endif() @@ -158,8 +160,13 @@ if(MAYA_APP_VERSION VERSION_GREATER 2024) set(WANT_QT_VERSION 6.5) find_package(Qt6 ${WANT_QT_VERSION} COMPONENTS Core Widgets QUIET) if (Qt6_FOUND) - message(STATUS "Found Qt ${Qt6_VERSION} in Maya devkit. Hydra Scene Browser will be built.") - set(BUILD_HDSB_PLUGIN TRUE) + if (CODE_COVERAGE) + set(BUILD_HDSB_PLUGIN FALSE) + message(STATUS "Code coverage enabled, Hydra Scene Browser will not be built.") + else() + set(BUILD_HDSB_PLUGIN TRUE) + message(STATUS "Found Qt ${Qt6_VERSION} in Maya devkit. Hydra Scene Browser will be built.") + endif() else() message(WARNING "Could not find Qt ${WANT_QT_VERSION} in Maya devkit directory: ${MAYA_DEVKIT_LOCATION}. \ You must extract Qt.tar.gz. Hydra Scene Browser will not be built.") diff --git a/build.py b/build.py index 7f9150c7b2..0ebc464ec0 100755 --- a/build.py +++ b/build.py @@ -202,6 +202,8 @@ def BuildVariant(context): return "Debug" elif context.buildRelease: return "Release" + elif context.buildCoverage: + return "Coverage" elif context.buildRelWithDebug: return "RelWithDebInfo" return "RelWithDebInfo" @@ -258,7 +260,6 @@ def CurrentWorkingDirectory(dir): def RunCMake(context, extraArgs=None, stages=None): """Invoke CMake to configure, build, and install a library whose source code is located in the current working directory.""" - srcDir = os.getcwd() instDir = context.instDir buildDir = context.buildDir @@ -293,27 +294,40 @@ def RunCMake(context, extraArgs=None, stages=None): if generator and 'Visual Studio' in generator and IsVisualStudio2019OrGreater(): generator = generator + " -A x64" + add_coverage_flags = False + + if (context.buildCoverage): + # Use RelWithDebInfo as underlying variant to build + context.buildCoverage = False + add_coverage_flags = True + + # get build variant variant= BuildVariant(context) - + with CurrentWorkingDirectory(buildDir): # recreate build_log.txt everytime the script runs if os.path.isfile(context.logFileLocation): os.remove(context.logFileLocation) - if 'configure' in stages: Run(context, 'cmake ' '-DCMAKE_INSTALL_PREFIX="{instDir}" ' '-DCMAKE_BUILD_TYPE={variant} ' '-DCMAKE_EXPORT_COMPILE_COMMANDS=ON ' + '{codeCoverageCompilerCpp} ' + '{codeCoverageCompilerC} ' '{generator} ' + '{codeCoverageOption} ' '{extraArgs} ' '"{srcDir}"' .format(instDir=instDir, variant=variant, srcDir=srcDir, + codeCoverageCompilerCpp=("-DCMAKE_CXX_COMPILER=clang++" if add_coverage_flags else ""), + codeCoverageCompilerC=("-DCMAKE_C_COMPILER=clang" if add_coverage_flags else ""), generator=(generator or ""), + codeCoverageOption=("-DCODE_COVERAGE=ON" if add_coverage_flags else ""), extraArgs=(" ".join(extraArgs) if extraArgs else ""))) installArg = "" @@ -571,6 +585,9 @@ def Package(context): varGroup.add_argument("--build-release", dest="build_release", action="store_true", help="Build in Release mode (default: %(default)s)") +varGroup.add_argument("--build-coverage", dest="build_coverage", action="store_true", + help="Build in Coverage mode (default: %(default)s)") + varGroup.add_argument("--build-relwithdebug", dest="build_relwithdebug", action="store_true", default=True, help="Build in RelWithDebInfo mode (default: %(default)s)") @@ -605,7 +622,6 @@ def Package(context): # InstallContext class InstallContext: def __init__(self, args): - # Assume the project's top level cmake is in the current source directory self.mayaHydraSrcDir = os.path.normpath( os.path.join(os.path.abspath(os.path.dirname(__file__)))) @@ -615,6 +631,7 @@ def __init__(self, args): self.buildDebug = args.build_debug self.buildRelease = args.build_release self.buildRelWithDebug = args.build_relwithdebug + self.buildCoverage = args.build_coverage self.debugPython = args.debug_python @@ -684,6 +701,7 @@ def __init__(self, args): # Redirect output stream to file self.redirectOutstreamFile = args.redirect_outstream_file + try: context = InstallContext(args) except Exception as e: diff --git a/cmake/compiler_config.cmake b/cmake/compiler_config.cmake index a383e7c00b..51379258b0 100644 --- a/cmake/compiler_config.cmake +++ b/cmake/compiler_config.cmake @@ -20,6 +20,18 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") ) endif() +set(CLANG_FLAGS + -MP + -frtti +) + +if (CODE_COVERAGE) + list(APPEND CLANG_FLAGS + -fprofile-instr-generate + -fcoverage-mapping + ) +endif() + set(MSVC_FLAGS # we want to be as strict as possible /W3 @@ -59,6 +71,22 @@ set(MSVC_FLAGS /we4189 ) +set(CLANG_DEFINITIONS + # Make sure WinDef.h does not define min and max macros which + # will conflict with std::min() and std::max(). + NOMINMAX + + _CRT_SECURE_NO_WARNINGS + _SCL_SECURE_NO_WARNINGS +) + +if (CODE_COVERAGE) + list(APPEND CLANG_DEFINITIONS + CODE_COVERAGE + CODE_COVERAGE_WORKAROUND + ) +endif() + set(MSVC_DEFINITIONS # Make sure WinDef.h does not define min and max macros which # will conflict with std::min() and std::max(). @@ -99,7 +127,7 @@ function(mayaHydra_compile_config TARGET) cxx_std_11 ) endif() - if(IS_GNU OR IS_CLANG) + if(IS_GNU) target_compile_options(${TARGET} PRIVATE ${GNU_CLANG_FLAGS} @@ -120,6 +148,15 @@ function(mayaHydra_compile_config TARGET) BOOST_NO_CXX98_FUNCTION_BASE ) endif() + elseif(IS_CLANG) + target_compile_options(${TARGET} + PRIVATE + ${CLANG_FLAGS} + ) + target_compile_definitions(${TARGET} + PRIVATE + ${CLANG_DEFINITIONS} + ) elseif(IS_MSVC) target_compile_options(${TARGET} PRIVATE diff --git a/cmake/modules/FindMaya.cmake b/cmake/modules/FindMaya.cmake index b25458caf7..f29bd6d872 100644 --- a/cmake/modules/FindMaya.cmake +++ b/cmake/modules/FindMaya.cmake @@ -59,8 +59,13 @@ macro(maya_set_plugin_properties target) PREFIX "") elseif(WIN32) set(_MAYA_DEFINES "${_MAYA_DEFINES}" _AFXDLL _MBCS NT_PLUGIN) - set_target_properties( ${target} PROPERTIES - LINK_FLAGS "/export:initializePlugin /export:uninitializePlugin") + if(IS_CLANG) + set_target_properties( ${target} PROPERTIES + LINK_FLAGS "-Wl,-export:initializePlugin -Wl,-export:uninitializePlugin") + else() + set_target_properties( ${target} PROPERTIES + LINK_FLAGS "/export:initializePlugin /export:uninitializePlugin") + endif() else() set(_MAYA_DEFINES "${_MAYA_DEFINES}" LINUX LINUX_64) set_target_properties( ${target} PROPERTIES diff --git a/cmake/utils.cmake b/cmake/utils.cmake index 1c106386ac..c264d7b8d5 100644 --- a/cmake/utils.cmake +++ b/cmake/utils.cmake @@ -27,7 +27,7 @@ endif() # compiler type if (CMAKE_COMPILER_IS_GNUCXX) set(IS_GNU TRUE) -elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") +elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") set(IS_CLANG TRUE) elseif(MSVC) set(IS_MSVC TRUE) diff --git a/lib/flowViewport/API/interfacesImp/fvpFilteringSceneIndexInterfaceImp.cpp b/lib/flowViewport/API/interfacesImp/fvpFilteringSceneIndexInterfaceImp.cpp index eee2610bc4..6631138a2a 100644 --- a/lib/flowViewport/API/interfacesImp/fvpFilteringSceneIndexInterfaceImp.cpp +++ b/lib/flowViewport/API/interfacesImp/fvpFilteringSceneIndexInterfaceImp.cpp @@ -27,7 +27,19 @@ namespace std::mutex sceneFilteringClient_mutex; //Set of scene Filtering scene index data, they belong to the Fpv::FilteringSceneIndexClient::Category::kSceneFiltering - std::set sceneFilteringSceneIndicesData; + std::set& sceneFilteringSceneIndicesData() { + static std::set +#ifdef CODE_COVERAGE_WORKAROUND + *data{nullptr}; + if (!data) { + data = new std::set; + } + return *data; +#else + data; + return data; +#endif + } //Set of selection highlighting Filtering scene index data, they belong to the Fpv::FilteringSceneIndexClient::Category::kSelectionHighlighting std::set selectionHighlightFilteringSceneIndicesData; @@ -83,15 +95,15 @@ bool FilteringSceneIndexInterfaceImp::_CreateSceneFilteringSceneIndicesData(cons { std::lock_guard lock(sceneFilteringClient_mutex); - auto findResult = std::find_if(sceneFilteringSceneIndicesData.cbegin(), sceneFilteringSceneIndicesData.cend(), + auto findResult = std::find_if(sceneFilteringSceneIndicesData().cbegin(), sceneFilteringSceneIndicesData().cend(), [&client](const PXR_NS::FVP_NS_DEF::FilteringSceneIndexDataBaseRefPtr& filteringSIData) { return filteringSIData->getClient() == client;}); - if (findResult != sceneFilteringSceneIndicesData.cend()){ + if (findResult != sceneFilteringSceneIndicesData().cend()){ return false; } //Call the abstract scene index data factory to create a subclass of FilteringSceneIndexDataBase PXR_NS::FVP_NS_DEF::FilteringSceneIndexDataBaseRefPtr data = sceneIndexDataFactory->createFilteringSceneIndexDataBase(client); - sceneFilteringSceneIndicesData.insert(data); + sceneFilteringSceneIndicesData().insert(data); bNeedToUpdateViewportsFilteringSceneIndicesChain = true; } @@ -136,15 +148,15 @@ void FilteringSceneIndexInterfaceImp::_DestroySceneFilteringSceneIndicesData(con { std::lock_guard lock(sceneFilteringClient_mutex); - auto findResult = std::find_if(sceneFilteringSceneIndicesData.cbegin(), sceneFilteringSceneIndicesData.cend(), + auto findResult = std::find_if(sceneFilteringSceneIndicesData().cbegin(), sceneFilteringSceneIndicesData().cend(), [&client](const PXR_NS::FVP_NS_DEF::FilteringSceneIndexDataBaseRefPtr& filteringSIData) { return filteringSIData->getClient() == client;}); - if (findResult != sceneFilteringSceneIndicesData.cend()){ + if (findResult != sceneFilteringSceneIndicesData().cend()){ const auto& filteringSIData = (*findResult); rendererNames = (filteringSIData) ? filteringSIData->getClient()->getRendererNames() : FvpViewportAPITokens->allRenderers; - sceneFilteringSceneIndicesData.erase(findResult);//This also decreases ref count + sceneFilteringSceneIndicesData().erase(findResult);//This also decreases ref count bNeedToUpdateViewportsFilteringSceneIndicesChain = true; } @@ -190,7 +202,7 @@ void FilteringSceneIndexInterfaceImp::unregisterFilteringSceneIndexClient(const const std::set& FilteringSceneIndexInterfaceImp::getSceneFilteringSceneIndicesData()const { std::lock_guard lock(sceneFilteringClient_mutex); - return sceneFilteringSceneIndicesData; + return sceneFilteringSceneIndicesData(); } const std::set& FilteringSceneIndexInterfaceImp::getSelectionHighlightFilteringSceneIndicesData() const diff --git a/lib/flowViewport/API/perViewportSceneIndicesData/fvpDataProducerSceneIndexDataBase.cpp b/lib/flowViewport/API/perViewportSceneIndicesData/fvpDataProducerSceneIndexDataBase.cpp index 260b28d35e..dde4c93c8b 100644 --- a/lib/flowViewport/API/perViewportSceneIndicesData/fvpDataProducerSceneIndexDataBase.cpp +++ b/lib/flowViewport/API/perViewportSceneIndicesData/fvpDataProducerSceneIndexDataBase.cpp @@ -22,6 +22,10 @@ #include "fvpDataProducerSceneIndexDataBase.h" #include "flowViewport/API/fvpViewportAPITokens.h" +#ifdef CODE_COVERAGE_WORKAROUND +#include +#endif + //Hydra headers #include #include @@ -59,6 +63,13 @@ DataProducerSceneIndexDataBase::DataProducerSceneIndexDataBase(const CreationPar _dccNode = params._dccNode; } +DataProducerSceneIndexDataBase::~DataProducerSceneIndexDataBase() +{ +#ifdef CODE_COVERAGE_WORKAROUND + Fvp::leakSceneIndex(_rootOverridesSceneIndex); +#endif +} + void DataProducerSceneIndexDataBase::UpdateHydraTransformFromParentPath() { if (! _rootOverridesSceneIndex){ @@ -140,4 +151,4 @@ void DataProducerSceneIndexDataBase::_CreateSceneIndexChainForDataProducerSceneI }//end of namespace FVP_NS_DEF -PXR_NAMESPACE_CLOSE_SCOPE \ No newline at end of file +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/lib/flowViewport/API/perViewportSceneIndicesData/fvpDataProducerSceneIndexDataBase.h b/lib/flowViewport/API/perViewportSceneIndicesData/fvpDataProducerSceneIndexDataBase.h index 7ae34069a4..fba5cb1114 100644 --- a/lib/flowViewport/API/perViewportSceneIndicesData/fvpDataProducerSceneIndexDataBase.h +++ b/lib/flowViewport/API/perViewportSceneIndicesData/fvpDataProducerSceneIndexDataBase.h @@ -74,7 +74,7 @@ TF_DECLARE_WEAK_AND_REF_PTRS(DataProducerSceneIndexDataBase);//Be able to use Re void* _dccNode; }; - ~DataProducerSceneIndexDataBase() override = default; + ~DataProducerSceneIndexDataBase() override; //Used to set the usd stage scene indices void SetDataProducerSceneIndex(const HdSceneIndexBaseRefPtr& sceneIndex) {_dataProducerSceneIndex = sceneIndex;} diff --git a/lib/flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndicesChainManager.cpp b/lib/flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndicesChainManager.cpp index b804ac1a60..27c3dfdb39 100644 --- a/lib/flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndicesChainManager.cpp +++ b/lib/flowViewport/API/perViewportSceneIndicesData/fvpFilteringSceneIndicesChainManager.cpp @@ -16,6 +16,9 @@ //Local headers #include "fvpFilteringSceneIndicesChainManager.h" +#ifdef CODE_COVERAGE_WORKAROUND +#include +#endif #include "flowViewport/sceneIndex/fvpRenderIndexProxy.h" #include "flowViewport/API/interfacesImp/fvpFilteringSceneIndexInterfaceImp.h" #include "flowViewport/API/perViewportSceneIndicesData/fvpViewportInformationAndSceneIndicesPerViewportDataManager.h" @@ -86,6 +89,9 @@ void FilteringSceneIndicesChainManager::destroyFilteringSceneIndicesChain(Viewpo renderIndex->RemoveSceneIndex(lastSceneIndex);//Remove the whole chain from the render index //Remove a ref on it which should cascade the same on its references +#ifdef CODE_COVERAGE_WORKAROUND + Fvp::leakSceneIndex(lastSceneIndex); +#endif lastSceneIndex.Reset(); } @@ -166,4 +172,4 @@ void FilteringSceneIndicesChainManager::setEnabled(bool enable) updateFilteringSceneIndicesChain(FvpViewportAPITokens->allRenderers); } -}//End of namespace FVP_NS_DEF \ No newline at end of file +}//End of namespace FVP_NS_DEF diff --git a/lib/flowViewport/API/perViewportSceneIndicesData/fvpViewportInformationAndSceneIndicesPerViewportDataManager.cpp b/lib/flowViewport/API/perViewportSceneIndicesData/fvpViewportInformationAndSceneIndicesPerViewportDataManager.cpp index 9393c23fde..7f3b61024e 100644 --- a/lib/flowViewport/API/perViewportSceneIndicesData/fvpViewportInformationAndSceneIndicesPerViewportDataManager.cpp +++ b/lib/flowViewport/API/perViewportSceneIndicesData/fvpViewportInformationAndSceneIndicesPerViewportDataManager.cpp @@ -31,6 +31,20 @@ namespace { std::mutex viewportInformationAndSceneIndicesPerViewportData_mutex; std::set dummyEmptyArray; + +#ifdef CODE_COVERAGE_WORKAROUND +void leakViewportData(const Fvp::ViewportInformationAndSceneIndicesPerViewportDataVector& vpDataVec) { + // Must place the leaked data vector on the heap, as a by-value + // vector will have its destructor called at process exit, which calls + // the vector element destructors and triggers the crash. + static std::vector* leakedVpData{nullptr}; + if (!leakedVpData) { + leakedVpData = new std::vector; + } + leakedVpData->push_back(vpDataVec); +} +#endif + } PXR_NAMESPACE_USING_DIRECTIVE @@ -182,6 +196,10 @@ void ViewportInformationAndSceneIndicesPerViewportDataManager::RemoveAllViewport } } +#ifdef CODE_COVERAGE_WORKAROUND + leakViewportData(_viewportsInformationAndSceneIndicesPerViewportData); +#endif + _viewportsInformationAndSceneIndicesPerViewportData.clear();//Delete all of them } diff --git a/lib/flowViewport/API/samples/fvpDataProducerSceneIndexExample.cpp b/lib/flowViewport/API/samples/fvpDataProducerSceneIndexExample.cpp index ee2ec04eda..4b5bdefd7e 100644 --- a/lib/flowViewport/API/samples/fvpDataProducerSceneIndexExample.cpp +++ b/lib/flowViewport/API/samples/fvpDataProducerSceneIndexExample.cpp @@ -22,6 +22,10 @@ //Local headers #include "fvpDataProducerSceneIndexExample.h" +#ifdef CODE_COVERAGE_WORKAROUND +#include +#endif + //USD headers #include #include @@ -132,6 +136,10 @@ DataProducerSceneIndexExample::DataProducerSceneIndexExample() : DataProducerSceneIndexExample::~DataProducerSceneIndexExample() { +#ifdef CODE_COVERAGE_WORKAROUND + Fvp::leakSceneIndex(_retainedSceneIndex); +#endif + removeDataProducerSceneIndex(); _hydraInterface = nullptr; } diff --git a/lib/flowViewport/API/samples/fvpFilteringSceneIndexExample.cpp b/lib/flowViewport/API/samples/fvpFilteringSceneIndexExample.cpp index 68b384cd96..e7e62a4b0f 100644 --- a/lib/flowViewport/API/samples/fvpFilteringSceneIndexExample.cpp +++ b/lib/flowViewport/API/samples/fvpFilteringSceneIndexExample.cpp @@ -73,7 +73,7 @@ bool FilteringSceneIndexExample::IsFiltered(const SdfPath& primPath) const void FilteringSceneIndexExample::UpdateFilteringStatus(const SdfPath& primPath) { - if (ShouldBeFiltered(_GetInputSceneIndex()->GetPrim(primPath))) { + if (ShouldBeFiltered(GetInputSceneIndex()->GetPrim(primPath))) { _filteredPrims.insert(primPath); } else { _filteredPrims.erase(primPath); @@ -81,7 +81,7 @@ void FilteringSceneIndexExample::UpdateFilteringStatus(const SdfPath& primPath) } FilteringSceneIndexExample::FilteringSceneIndexExample(const HdSceneIndexBaseRefPtr& inputSceneIndex) - : ParentClass(inputSceneIndex) + : ParentClass(inputSceneIndex), InputSceneIndexUtils(inputSceneIndex) { std::stack primPathsToTraverse({ SdfPath::AbsoluteRootPath() }); while (!primPathsToTraverse.empty()) { @@ -96,7 +96,7 @@ FilteringSceneIndexExample::FilteringSceneIndexExample(const HdSceneIndexBaseRef HdSceneIndexPrim FilteringSceneIndexExample::GetPrim(const SdfPath& primPath) const { - return IsFiltered(primPath) ? HdSceneIndexPrim() : _GetInputSceneIndex()->GetPrim(primPath); + return IsFiltered(primPath) ? HdSceneIndexPrim() : GetInputSceneIndex()->GetPrim(primPath); } SdfPathVector FilteringSceneIndexExample::GetChildPrimPaths(const SdfPath& primPath) const { @@ -112,7 +112,7 @@ SdfPathVector FilteringSceneIndexExample::GetChildPrimPaths(const SdfPath& primP // to a filtered child prim, as a filtered prim should not exist at all (and // we might have sent a PrimsRemoved notification prior). Thus, remove all // child paths to filtered prims before returning. - SdfPathVector childPaths = _GetInputSceneIndex()->GetChildPrimPaths(primPath); + SdfPathVector childPaths = GetInputSceneIndex()->GetChildPrimPaths(primPath); childPaths.erase( std::remove_if( childPaths.begin(), @@ -171,7 +171,7 @@ void FilteringSceneIndexExample::_PrimsDirtied( // Filtering status changed, send a different notification instead if (wasPreviouslyFiltered) { newlyUnfilteredEntries.emplace_back( - entry.primPath, _GetInputSceneIndex()->GetPrim(entry.primPath).primType); + entry.primPath, GetInputSceneIndex()->GetPrim(entry.primPath).primType); } else { newlyFilteredEntries.emplace_back(entry.primPath); } @@ -184,4 +184,4 @@ void FilteringSceneIndexExample::_PrimsDirtied( }//end of namespace FVP_NS_DEF -PXR_NAMESPACE_CLOSE_SCOPE \ No newline at end of file +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/lib/flowViewport/API/samples/fvpFilteringSceneIndexExample.h b/lib/flowViewport/API/samples/fvpFilteringSceneIndexExample.h index 32b3e2df46..cf03aad6ea 100644 --- a/lib/flowViewport/API/samples/fvpFilteringSceneIndexExample.h +++ b/lib/flowViewport/API/samples/fvpFilteringSceneIndexExample.h @@ -19,6 +19,8 @@ //Local headers #include "flowViewport/api.h" +#include "flowViewport/sceneIndex/fvpSceneIndexUtils.h" + //Hydra headers #include #include @@ -37,9 +39,11 @@ class FilteringSceneIndexExample; TF_DECLARE_WEAK_AND_REF_PTRS(FilteringSceneIndexExample); class FilteringSceneIndexExample : public HdSingleInputFilteringSceneIndexBase + , public Fvp::InputSceneIndexUtils { public: using ParentClass = HdSingleInputFilteringSceneIndexBase; + using PXR_NS::HdSingleInputFilteringSceneIndexBase::_GetInputSceneIndex; static FilteringSceneIndexExampleRefPtr New(const HdSceneIndexBaseRefPtr& inputSceneIndex){ return TfCreateRefPtr(new FilteringSceneIndexExample(inputSceneIndex)); @@ -79,4 +83,3 @@ class FilteringSceneIndexExample : public HdSingleInputFilteringSceneIndexBase PXR_NAMESPACE_CLOSE_SCOPE #endif //FLOW_VIEWPORT_EXAMPLES_FILTERING_SCENE_INDEX_EXAMPLE_H - diff --git a/lib/flowViewport/CMakeLists.txt b/lib/flowViewport/CMakeLists.txt index 52c426838c..536dba03cf 100644 --- a/lib/flowViewport/CMakeLists.txt +++ b/lib/flowViewport/CMakeLists.txt @@ -8,6 +8,7 @@ add_library(${TARGET_NAME} SHARED) target_sources(${TARGET_NAME} PRIVATE debugCodes.cpp + fvpUtils.cpp global.cpp tokens.cpp ) @@ -15,6 +16,7 @@ target_sources(${TARGET_NAME} set(HEADERS api.h debugCodes.h + fvpUtils.h global.h tokens.h ) @@ -92,8 +94,10 @@ install(FILES ${CMAKE_BINARY_DIR}/include/flowViewport/flowViewport.h ) if(IS_WINDOWS) - install(FILES $ - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib OPTIONAL) + if (NOT CODE_COVERAGE) + install(FILES $ + DESTINATION ${CMAKE_INSTALL_PREFIX}/lib OPTIONAL) + endif() endif() # ----------------------------------------------------------------------------- diff --git a/lib/flowViewport/fvpUtils.cpp b/lib/flowViewport/fvpUtils.cpp new file mode 100644 index 0000000000..b82b1466a6 --- /dev/null +++ b/lib/flowViewport/fvpUtils.cpp @@ -0,0 +1,33 @@ +// Copyright 2024 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 "fvpUtils.h" + +namespace FVP_NS_DEF { + +#ifdef CODE_COVERAGE_WORKAROUND +void leakSceneIndex(const PXR_NS::HdSceneIndexBaseRefPtr& si) { + // Must place the leaked scene index vector on the heap, as a by-value + // vector will have its destructor called at process exit, which calls + // the vector element destructors and triggers the crash. + static std::vector* leakedSi{nullptr}; + if (!leakedSi) { + leakedSi = new std::vector; + } + leakedSi->push_back(si); +} +#endif + +} // namespace FVP_NS_DEF diff --git a/lib/flowViewport/fvpUtils.h b/lib/flowViewport/fvpUtils.h new file mode 100644 index 0000000000..8c917916d8 --- /dev/null +++ b/lib/flowViewport/fvpUtils.h @@ -0,0 +1,40 @@ +// Copyright 2024 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. +// +#ifndef FVP_UTILS_H +#define FVP_UTILS_H + +#include + +#ifdef CODE_COVERAGE_WORKAROUND +#include +#endif + +namespace FVP_NS_DEF { + +// At time of writing, the last reference removal causing destruction of a +// scene index crashes on Windows with clang code coverage compilation here: +// +// usd_tf!std::_Atomic_storage::compare_exchange_strong+0x38 [inlined in usd_tf!pxrInternal_v0_23__pxrReserved__::Tf_RefPtr_UniqueChangedCounter::_RemoveRef+0x62] +// +// To work around this, leak the scene index to avoid its destruction. +// PPT, 24-Jan-2024. + +#ifdef CODE_COVERAGE_WORKAROUND +void FVP_API leakSceneIndex(const PXR_NS::HdSceneIndexBaseRefPtr& si); +#endif + +} // namespace FVP_NS_DEF + +#endif // FVP_UTILS_H diff --git a/lib/flowViewport/sceneIndex/CMakeLists.txt b/lib/flowViewport/sceneIndex/CMakeLists.txt index ed1553fc99..8f5a030c43 100644 --- a/lib/flowViewport/sceneIndex/CMakeLists.txt +++ b/lib/flowViewport/sceneIndex/CMakeLists.txt @@ -7,6 +7,7 @@ target_sources(${TARGET_NAME} fvpPathInterface.cpp fvpPathInterfaceSceneIndex.cpp fvpRenderIndexProxy.cpp + fvpSceneIndexUtils.cpp fvpSelectionSceneIndex.cpp fvpWireframeSelectionHighlightSceneIndex.cpp ) @@ -17,6 +18,7 @@ set(HEADERS fvpPathInterfaceSceneIndex.h fvpRenderIndexProxy.h fvpRenderIndexProxyFwd.h + fvpSceneIndexUtils.h fvpSelectionSceneIndex.h fvpWireframeSelectionHighlightSceneIndex.h ) diff --git a/lib/flowViewport/sceneIndex/fvpPathInterfaceSceneIndex.cpp b/lib/flowViewport/sceneIndex/fvpPathInterfaceSceneIndex.cpp index d0807f782b..1455b1908d 100644 --- a/lib/flowViewport/sceneIndex/fvpPathInterfaceSceneIndex.cpp +++ b/lib/flowViewport/sceneIndex/fvpPathInterfaceSceneIndex.cpp @@ -23,18 +23,19 @@ namespace FVP_NS_DEF { PathInterfaceSceneIndexBase:: PathInterfaceSceneIndexBase(HdSceneIndexBaseRefPtr const &inputSceneIndex) : HdSingleInputFilteringSceneIndexBase(inputSceneIndex) + , InputSceneIndexUtils(inputSceneIndex) {} HdSceneIndexPrim PathInterfaceSceneIndexBase::GetPrim(const SdfPath &primPath) const { - return _GetInputSceneIndex()->GetPrim(primPath); + return GetInputSceneIndex()->GetPrim(primPath); } SdfPathVector PathInterfaceSceneIndexBase::GetChildPrimPaths(const SdfPath &primPath) const { - return _GetInputSceneIndex()->GetChildPrimPaths(primPath); + return GetInputSceneIndex()->GetChildPrimPaths(primPath); } void diff --git a/lib/flowViewport/sceneIndex/fvpPathInterfaceSceneIndex.h b/lib/flowViewport/sceneIndex/fvpPathInterfaceSceneIndex.h index 193d865662..9ea5a62db2 100644 --- a/lib/flowViewport/sceneIndex/fvpPathInterfaceSceneIndex.h +++ b/lib/flowViewport/sceneIndex/fvpPathInterfaceSceneIndex.h @@ -17,6 +17,7 @@ #include "flowViewport/api.h" #include "flowViewport/sceneIndex/fvpPathInterface.h" +#include "flowViewport/sceneIndex/fvpSceneIndexUtils.h" #include @@ -29,9 +30,12 @@ namespace FVP_NS_DEF { /// PathInterface::SceneIndexPath() virtual. /// class PathInterfaceSceneIndexBase - : public PXR_NS::HdSingleInputFilteringSceneIndexBase, public PathInterface + : public PXR_NS::HdSingleInputFilteringSceneIndexBase + , public PathInterface + , public Fvp::InputSceneIndexUtils { public: + using PXR_NS::HdSingleInputFilteringSceneIndexBase::_GetInputSceneIndex; FVP_API PXR_NS::HdSceneIndexPrim GetPrim(const PXR_NS::SdfPath &primPath) const override; diff --git a/lib/flowViewport/sceneIndex/fvpSceneIndexUtils.cpp b/lib/flowViewport/sceneIndex/fvpSceneIndexUtils.cpp new file mode 100644 index 0000000000..c5c4aa68ce --- /dev/null +++ b/lib/flowViewport/sceneIndex/fvpSceneIndexUtils.cpp @@ -0,0 +1,16 @@ +// Copyright 2023 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 "flowViewport/sceneIndex/fvpSceneIndexUtils.h" diff --git a/lib/flowViewport/sceneIndex/fvpSceneIndexUtils.h b/lib/flowViewport/sceneIndex/fvpSceneIndexUtils.h new file mode 100644 index 0000000000..536ecf9571 --- /dev/null +++ b/lib/flowViewport/sceneIndex/fvpSceneIndexUtils.h @@ -0,0 +1,61 @@ +// Copyright 2024 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. +// +#ifndef FVP_SCENE_INDEX_UTILS_H +#define FVP_SCENE_INDEX_UTILS_H + +#include + +#include + +namespace FVP_NS_DEF { + +/// \class InputSceneIndexUtils +/// +/// Utility class to factor out common single input scene index functionality. +/// +template +class InputSceneIndexUtils +{ +public: + + InputSceneIndexUtils( + const PXR_NS::HdSceneIndexBaseRefPtr& inputSceneIndex + ) +#ifdef CODE_COVERAGE_WORKAROUND + : _inputSceneIndex(inputSceneIndex) +#endif + {} + + // At time of writing directly accessing _GetInputSceneIndex() from + // clang coverage build causes crash. PPT, 24-Jan-2024. + const PXR_NS::HdSceneIndexBaseRefPtr& GetInputSceneIndex() const + { +#ifdef CODE_COVERAGE_WORKAROUND + return _inputSceneIndex; +#else + return static_cast(this)->_GetInputSceneIndex(); +#endif + } + +private: + +#ifdef CODE_COVERAGE_WORKAROUND + const PXR_NS::HdSceneIndexBaseRefPtr _inputSceneIndex; +#endif +}; + +} + +#endif diff --git a/lib/flowViewport/sceneIndex/fvpSelectionSceneIndex.cpp b/lib/flowViewport/sceneIndex/fvpSelectionSceneIndex.cpp index 23da925531..5503d72a3a 100644 --- a/lib/flowViewport/sceneIndex/fvpSelectionSceneIndex.cpp +++ b/lib/flowViewport/sceneIndex/fvpSelectionSceneIndex.cpp @@ -1,307 +1,308 @@ -// -// Copyright 2022 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -// Copyright 2023 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 "flowViewport/sceneIndex/fvpSelectionSceneIndex.h" -#include "flowViewport/sceneIndex/fvpPathInterface.h" -#include "flowViewport/selection/fvpSelection.h" - -#include "flowViewport/debugCodes.h" - -#include "pxr/imaging/hd/retainedDataSource.h" -#include "pxr/imaging/hd/selectionSchema.h" -#include "pxr/imaging/hd/selectionsSchema.h" - -#include -#include - -PXR_NAMESPACE_USING_DIRECTIVE - -namespace { -const HdDataSourceLocatorSet selectionsSchemaDefaultLocator{HdSelectionsSchema::GetDefaultLocator()}; -} - -namespace FVP_NS_DEF { - -class _PrimSource : public HdContainerDataSource -{ -public: - HD_DECLARE_DATASOURCE(_PrimSource); - - _PrimSource(HdContainerDataSourceHandle const &inputSource, - const SelectionConstPtr& selection, - const SdfPath &primPath) - : _inputSource(inputSource) - , _selection(selection) - , _primPath(primPath) - { - } - - TfTokenVector GetNames() override - { - TfTokenVector names = _inputSource->GetNames(); - if (_selection->IsFullySelected(_primPath)) { - names.push_back(HdSelectionsSchemaTokens->selections); - } - return names; - } - - HdDataSourceBaseHandle Get(const TfToken &name) override - { - if (name == HdSelectionsSchemaTokens->selections) { - return _selection->GetVectorDataSource(_primPath); - } - - return _inputSource->Get(name); - } - -private: - HdContainerDataSourceHandle const _inputSource; - const SelectionConstPtr _selection; - const SdfPath _primPath; -}; - -SelectionSceneIndexRefPtr -SelectionSceneIndex::New( - const HdSceneIndexBaseRefPtr& inputSceneIndex, - const SelectionPtr& selection -) -{ - TF_DEBUG(FVP_SELECTION_SCENE_INDEX) - .Msg("SelectionSceneIndex::New() called.\n"); - return TfCreateRefPtr(new SelectionSceneIndex(inputSceneIndex, selection)); -} - -SelectionSceneIndex:: -SelectionSceneIndex( - const HdSceneIndexBaseRefPtr& inputSceneIndex, - const SelectionPtr& selection -) - : HdSingleInputFilteringSceneIndexBase(inputSceneIndex) - , _selection(selection) - , _inputSceneIndexPathInterface(dynamic_cast(&*_GetInputSceneIndex())) -{ - TF_DEBUG(FVP_SELECTION_SCENE_INDEX) - .Msg("SelectionSceneIndex::SelectionSceneIndex() called.\n"); - - TF_AXIOM(_inputSceneIndexPathInterface); -} - -HdSceneIndexPrim -SelectionSceneIndex::GetPrim(const SdfPath &primPath) const -{ - TF_DEBUG(FVP_SELECTION_SCENE_INDEX) - .Msg("SelectionSceneIndex::GetPrim() called.\n"); - - HdSceneIndexPrim result = _GetInputSceneIndex()->GetPrim(primPath); - if (!result.dataSource) { - return result; - } - - result.dataSource = _PrimSource::New( - result.dataSource, _selection, primPath); - - return result; -} - -SdfPathVector -SelectionSceneIndex::GetChildPrimPaths(const SdfPath &primPath) const -{ - TF_DEBUG(FVP_SELECTION_SCENE_INDEX) - .Msg("SelectionSceneIndex::GetChildPrimPaths() called.\n"); - - return _GetInputSceneIndex()->GetChildPrimPaths(primPath); -} - -void -SelectionSceneIndex::AddSelection(const Ufe::Path& appPath) -{ - TF_DEBUG(FVP_SELECTION_SCENE_INDEX) - .Msg("SelectionSceneIndex::AddSelection(const Ufe::Path& %s) called.\n", Ufe::PathString::string(appPath).c_str()); - - // Call our input scene index to convert the application path to a scene - // index path. - auto sceneIndexPath = SceneIndexPath(appPath); - - TF_DEBUG(FVP_SELECTION_SCENE_INDEX) - .Msg(" Adding %s to the Hydra selection.\n", sceneIndexPath.GetText()); - - if (_selection->Add(sceneIndexPath)) { - _SendPrimsDirtied({{sceneIndexPath, selectionsSchemaDefaultLocator}}); - } -} - -void SelectionSceneIndex::RemoveSelection(const Ufe::Path& appPath) -{ - TF_DEBUG(FVP_SELECTION_SCENE_INDEX) - .Msg("SelectionSceneIndex::RemoveSelection(const Ufe::Path& %s) called.\n", Ufe::PathString::string(appPath).c_str()); - - // Call our input scene index to convert the application path to a scene - // index path. - auto sceneIndexPath = SceneIndexPath(appPath); - - if (_selection->Remove(sceneIndexPath)) { - _SendPrimsDirtied({{sceneIndexPath, selectionsSchemaDefaultLocator}}); - } -} - -void -SelectionSceneIndex::ClearSelection() -{ - TF_DEBUG(FVP_SELECTION_SCENE_INDEX) - .Msg("SelectionSceneIndex::ClearSelection() called.\n"); - - if (_selection->IsEmpty()) { - return; - } - - HdSceneIndexObserver::DirtiedPrimEntries entries; - auto paths = _selection->GetFullySelectedPaths(); - entries.reserve(paths.size()); - for (const auto& path : paths) { - entries.emplace_back(path, selectionsSchemaDefaultLocator); - } - - _selection->Clear(); - - _SendPrimsDirtied(entries); -} - -void SelectionSceneIndex::ReplaceSelection(const Ufe::Selection& selection) -{ - TF_DEBUG(FVP_SELECTION_SCENE_INDEX) - .Msg("SelectionSceneIndex::ReplaceSelection() called.\n"); - - // Process the selection replace by performing dirty notification of the - // existing selection state. We could do this more efficiently by - // accounting for overlapping previous and new selections. - HdSceneIndexObserver::DirtiedPrimEntries entries; - auto paths = _selection->GetFullySelectedPaths(); - entries.reserve(paths.size() + selection.size()); - for (const auto& path : paths) { - entries.emplace_back(path, selectionsSchemaDefaultLocator); - } - - _selection->Clear(); - - SdfPathVector sceneIndexSn; - sceneIndexSn.reserve(selection.size()); - for (const auto& snItem : selection) { - // Call our input scene index to convert the application path to a scene - // index path. - auto sceneIndexPath = SceneIndexPath(snItem->path()); - - if (sceneIndexPath.IsEmpty()) { - continue; - } - - sceneIndexSn.emplace_back(sceneIndexPath); - TF_DEBUG(FVP_SELECTION_SCENE_INDEX) - .Msg(" Adding %s to the Hydra selection.\n", sceneIndexPath.GetText()); - entries.emplace_back(sceneIndexPath, selectionsSchemaDefaultLocator); - } - - _selection->Replace(sceneIndexSn); - _SendPrimsDirtied(entries); -} - -bool SelectionSceneIndex::IsFullySelected(const SdfPath& primPath) const -{ - return _selection->IsFullySelected(primPath); -} - -bool SelectionSceneIndex::HasFullySelectedAncestorInclusive(const SdfPath& primPath) const -{ - return _selection->HasFullySelectedAncestorInclusive(primPath); -} - -SdfPath SelectionSceneIndex::SceneIndexPath(const Ufe::Path& appPath) const -{ - auto sceneIndexPath = _inputSceneIndexPathInterface->SceneIndexPath(appPath); - - if (sceneIndexPath.IsEmpty()) { - TF_WARN("SelectionSceneIndex::SceneIndexPath(%s) returned an empty path, Hydra selection will be incorrect", Ufe::PathString::string(appPath).c_str()); - } - - return sceneIndexPath; -} - -SdfPathVector SelectionSceneIndex::GetFullySelectedPaths() const -{ - return _selection->GetFullySelectedPaths(); -} - -void -SelectionSceneIndex::_PrimsAdded( - const HdSceneIndexBase &sender, - const HdSceneIndexObserver::AddedPrimEntries &entries) -{ - TF_DEBUG(FVP_SELECTION_SCENE_INDEX) - .Msg("SelectionSceneIndex::_PrimsAdded() called.\n"); - - _SendPrimsAdded(entries); -} - -void -SelectionSceneIndex::_PrimsDirtied( - const HdSceneIndexBase &sender, - const HdSceneIndexObserver::DirtiedPrimEntries &entries) -{ - TF_DEBUG(FVP_SELECTION_SCENE_INDEX) - .Msg("SelectionSceneIndex::_PrimsDirtied() called.\n"); - - _SendPrimsDirtied(entries); -} - -void -SelectionSceneIndex::_PrimsRemoved( - const HdSceneIndexBase &sender, - const HdSceneIndexObserver::RemovedPrimEntries &entries) -{ - TF_DEBUG(FVP_SELECTION_SCENE_INDEX) - .Msg("SelectionSceneIndex::_PrimsRemoved() called.\n"); - - if (!_selection->IsEmpty()) { - for (const auto &entry : entries) { - _selection->RemoveHierarchy(entry.primPath); - } - } - - _SendPrimsRemoved(entries); -} - -} +// +// Copyright 2022 Pixar +// +// Licensed under the Apache License, Version 2.0 (the "Apache License") +// with the following modification; you may not use this file except in +// compliance with the Apache License and the following modification to it: +// Section 6. Trademarks. is deleted and replaced with: +// +// 6. Trademarks. This License does not grant permission to use the trade +// names, trademarks, service marks, or product names of the Licensor +// and its affiliates, except as required to comply with Section 4(c) of +// the License and to reproduce the content of the NOTICE file. +// +// You may obtain a copy of the Apache License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the Apache License with the above modification is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the Apache License for the specific +// language governing permissions and limitations under the Apache License. +// +// Copyright 2023 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 "flowViewport/sceneIndex/fvpSelectionSceneIndex.h" +#include "flowViewport/sceneIndex/fvpPathInterface.h" +#include "flowViewport/selection/fvpSelection.h" + +#include "flowViewport/debugCodes.h" + +#include "pxr/imaging/hd/retainedDataSource.h" +#include "pxr/imaging/hd/selectionSchema.h" +#include "pxr/imaging/hd/selectionsSchema.h" + +#include +#include + +PXR_NAMESPACE_USING_DIRECTIVE + +namespace { +const HdDataSourceLocatorSet selectionsSchemaDefaultLocator{HdSelectionsSchema::GetDefaultLocator()}; +} + +namespace FVP_NS_DEF { + +class _PrimSource : public HdContainerDataSource +{ +public: + HD_DECLARE_DATASOURCE(_PrimSource); + + _PrimSource(HdContainerDataSourceHandle const &inputSource, + const SelectionConstPtr& selection, + const SdfPath &primPath) + : _inputSource(inputSource) + , _selection(selection) + , _primPath(primPath) + { + } + + TfTokenVector GetNames() override + { + TfTokenVector names = _inputSource->GetNames(); + if (_selection->IsFullySelected(_primPath)) { + names.push_back(HdSelectionsSchemaTokens->selections); + } + return names; + } + + HdDataSourceBaseHandle Get(const TfToken &name) override + { + if (name == HdSelectionsSchemaTokens->selections) { + return _selection->GetVectorDataSource(_primPath); + } + + return _inputSource->Get(name); + } + +private: + HdContainerDataSourceHandle const _inputSource; + const SelectionConstPtr _selection; + const SdfPath _primPath; +}; + +SelectionSceneIndexRefPtr +SelectionSceneIndex::New( + const HdSceneIndexBaseRefPtr& inputSceneIndex, + const SelectionPtr& selection +) +{ + TF_DEBUG(FVP_SELECTION_SCENE_INDEX) + .Msg("SelectionSceneIndex::New() called.\n"); + return TfCreateRefPtr(new SelectionSceneIndex(inputSceneIndex, selection)); +} + +SelectionSceneIndex:: +SelectionSceneIndex( + const HdSceneIndexBaseRefPtr& inputSceneIndex, + const SelectionPtr& selection +) + : HdSingleInputFilteringSceneIndexBase(inputSceneIndex) + , InputSceneIndexUtils(inputSceneIndex) + , _selection(selection) + , _inputSceneIndexPathInterface(dynamic_cast(&*inputSceneIndex)) +{ + TF_DEBUG(FVP_SELECTION_SCENE_INDEX) + .Msg("SelectionSceneIndex::SelectionSceneIndex() called.\n"); + + TF_AXIOM(_inputSceneIndexPathInterface); +} + +HdSceneIndexPrim +SelectionSceneIndex::GetPrim(const SdfPath &primPath) const +{ + TF_DEBUG(FVP_SELECTION_SCENE_INDEX) + .Msg("SelectionSceneIndex::GetPrim() called.\n"); + + HdSceneIndexPrim result = GetInputSceneIndex()->GetPrim(primPath); + if (!result.dataSource) { + return result; + } + + result.dataSource = _PrimSource::New( + result.dataSource, _selection, primPath); + + return result; +} + +SdfPathVector +SelectionSceneIndex::GetChildPrimPaths(const SdfPath &primPath) const +{ + TF_DEBUG(FVP_SELECTION_SCENE_INDEX) + .Msg("SelectionSceneIndex::GetChildPrimPaths() called.\n"); + + return GetInputSceneIndex()->GetChildPrimPaths(primPath); +} + +void +SelectionSceneIndex::AddSelection(const Ufe::Path& appPath) +{ + TF_DEBUG(FVP_SELECTION_SCENE_INDEX) + .Msg("SelectionSceneIndex::AddSelection(const Ufe::Path& %s) called.\n", Ufe::PathString::string(appPath).c_str()); + + // Call our input scene index to convert the application path to a scene + // index path. + auto sceneIndexPath = SceneIndexPath(appPath); + + TF_DEBUG(FVP_SELECTION_SCENE_INDEX) + .Msg(" Adding %s to the Hydra selection.\n", sceneIndexPath.GetText()); + + if (_selection->Add(sceneIndexPath)) { + _SendPrimsDirtied({{sceneIndexPath, selectionsSchemaDefaultLocator}}); + } +} + +void SelectionSceneIndex::RemoveSelection(const Ufe::Path& appPath) +{ + TF_DEBUG(FVP_SELECTION_SCENE_INDEX) + .Msg("SelectionSceneIndex::RemoveSelection(const Ufe::Path& %s) called.\n", Ufe::PathString::string(appPath).c_str()); + + // Call our input scene index to convert the application path to a scene + // index path. + auto sceneIndexPath = SceneIndexPath(appPath); + + if (_selection->Remove(sceneIndexPath)) { + _SendPrimsDirtied({{sceneIndexPath, selectionsSchemaDefaultLocator}}); + } +} + +void +SelectionSceneIndex::ClearSelection() +{ + TF_DEBUG(FVP_SELECTION_SCENE_INDEX) + .Msg("SelectionSceneIndex::ClearSelection() called.\n"); + + if (_selection->IsEmpty()) { + return; + } + + HdSceneIndexObserver::DirtiedPrimEntries entries; + auto paths = _selection->GetFullySelectedPaths(); + entries.reserve(paths.size()); + for (const auto& path : paths) { + entries.emplace_back(path, selectionsSchemaDefaultLocator); + } + + _selection->Clear(); + + _SendPrimsDirtied(entries); +} + +void SelectionSceneIndex::ReplaceSelection(const Ufe::Selection& selection) +{ + TF_DEBUG(FVP_SELECTION_SCENE_INDEX) + .Msg("SelectionSceneIndex::ReplaceSelection() called.\n"); + + // Process the selection replace by performing dirty notification of the + // existing selection state. We could do this more efficiently by + // accounting for overlapping previous and new selections. + HdSceneIndexObserver::DirtiedPrimEntries entries; + auto paths = _selection->GetFullySelectedPaths(); + entries.reserve(paths.size() + selection.size()); + for (const auto& path : paths) { + entries.emplace_back(path, selectionsSchemaDefaultLocator); + } + + _selection->Clear(); + + SdfPathVector sceneIndexSn; + sceneIndexSn.reserve(selection.size()); + for (const auto& snItem : selection) { + // Call our input scene index to convert the application path to a scene + // index path. + auto sceneIndexPath = SceneIndexPath(snItem->path()); + + if (sceneIndexPath.IsEmpty()) { + continue; + } + + sceneIndexSn.emplace_back(sceneIndexPath); + TF_DEBUG(FVP_SELECTION_SCENE_INDEX) + .Msg(" Adding %s to the Hydra selection.\n", sceneIndexPath.GetText()); + entries.emplace_back(sceneIndexPath, selectionsSchemaDefaultLocator); + } + + _selection->Replace(sceneIndexSn); + _SendPrimsDirtied(entries); +} + +bool SelectionSceneIndex::IsFullySelected(const SdfPath& primPath) const +{ + return _selection->IsFullySelected(primPath); +} + +bool SelectionSceneIndex::HasFullySelectedAncestorInclusive(const SdfPath& primPath) const +{ + return _selection->HasFullySelectedAncestorInclusive(primPath); +} + +SdfPath SelectionSceneIndex::SceneIndexPath(const Ufe::Path& appPath) const +{ + auto sceneIndexPath = _inputSceneIndexPathInterface->SceneIndexPath(appPath); + + if (sceneIndexPath.IsEmpty()) { + TF_WARN("SelectionSceneIndex::SceneIndexPath(%s) returned an empty path, Hydra selection will be incorrect", Ufe::PathString::string(appPath).c_str()); + } + + return sceneIndexPath; +} + +SdfPathVector SelectionSceneIndex::GetFullySelectedPaths() const +{ + return _selection->GetFullySelectedPaths(); +} + +void +SelectionSceneIndex::_PrimsAdded( + const HdSceneIndexBase &sender, + const HdSceneIndexObserver::AddedPrimEntries &entries) +{ + TF_DEBUG(FVP_SELECTION_SCENE_INDEX) + .Msg("SelectionSceneIndex::_PrimsAdded() called.\n"); + + _SendPrimsAdded(entries); +} + +void +SelectionSceneIndex::_PrimsDirtied( + const HdSceneIndexBase &sender, + const HdSceneIndexObserver::DirtiedPrimEntries &entries) +{ + TF_DEBUG(FVP_SELECTION_SCENE_INDEX) + .Msg("SelectionSceneIndex::_PrimsDirtied() called.\n"); + + _SendPrimsDirtied(entries); +} + +void +SelectionSceneIndex::_PrimsRemoved( + const HdSceneIndexBase &sender, + const HdSceneIndexObserver::RemovedPrimEntries &entries) +{ + TF_DEBUG(FVP_SELECTION_SCENE_INDEX) + .Msg("SelectionSceneIndex::_PrimsRemoved() called.\n"); + + if (!_selection->IsEmpty()) { + for (const auto &entry : entries) { + _selection->RemoveHierarchy(entry.primPath); + } + } + + _SendPrimsRemoved(entries); +} + +} diff --git a/lib/flowViewport/sceneIndex/fvpSelectionSceneIndex.h b/lib/flowViewport/sceneIndex/fvpSelectionSceneIndex.h index 8cc9d21a2b..f9f806a444 100644 --- a/lib/flowViewport/sceneIndex/fvpSelectionSceneIndex.h +++ b/lib/flowViewport/sceneIndex/fvpSelectionSceneIndex.h @@ -1,148 +1,152 @@ -// -// Copyright 2022 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -// Copyright 2023 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. -// -#ifndef FVP_SELECTION_SCENE_INDEX_H -#define FVP_SELECTION_SCENE_INDEX_H - -#include "flowViewport/api.h" -#include "flowViewport/selection/fvpSelectionFwd.h" -#include "flowViewport/sceneIndex/fvpPathInterface.h" - -#include - -#include - -#include - -UFE_NS_DEF { -class Path; -class Selection; -} - -namespace FVP_NS_DEF { - -class PathInterface; -class Selection; - -// Pixar declarePtrs.h TF_DECLARE_REF_PTRS macro unusable, places resulting -// type in PXR_NS. -class SelectionSceneIndex; -typedef PXR_NS::TfRefPtr SelectionSceneIndexRefPtr; -typedef PXR_NS::TfRefPtr SelectionSceneIndexConstRefPtr; - -/// \class SelectionSceneIndex -/// -/// A simple scene index adding HdSelectionsSchema to all prims selected -/// in the application. -/// -class SelectionSceneIndex final - : public PXR_NS::HdSingleInputFilteringSceneIndexBase - , public PathInterface -{ -public: - FVP_API - static SelectionSceneIndexRefPtr New( - PXR_NS::HdSceneIndexBaseRefPtr const &inputSceneIndex, - const std::shared_ptr& selection - ); - - FVP_API - PXR_NS::HdSceneIndexPrim GetPrim(const PXR_NS::SdfPath &primPath) const override; - - FVP_API - PXR_NS::SdfPathVector GetChildPrimPaths(const PXR_NS::SdfPath &primPath) const override; - - /// Given a path (including usd proxy path inside a native instance) of - /// a USD prim, determine the corresponding prim in the Usd scene index - /// (filtered by the UsdImagingNiPrototypePropagatingSceneIndex) and - /// populate its selections data source. - FVP_API - void AddSelection(const Ufe::Path& appPath); - - FVP_API - void RemoveSelection(const Ufe::Path& appPath); - - FVP_API - void ReplaceSelection(const Ufe::Selection& selection); - - /// Reset the scene index selection state. - FVP_API - void ClearSelection(); - - FVP_API - bool IsFullySelected(const PXR_NS::SdfPath& primPath) const; - - FVP_API - bool HasFullySelectedAncestorInclusive(const PXR_NS::SdfPath& primPath) const; - - //! Path interface override. Forwards the call to the input scene index, - //! and warns about empty return paths. - //@{ - FVP_API - PXR_NS::SdfPath SceneIndexPath(const Ufe::Path& appPath) const override; - //@} - - FVP_API - PXR_NS::SdfPathVector GetFullySelectedPaths() const; - -protected: - void _PrimsAdded( - const PXR_NS::HdSceneIndexBase &sender, - const PXR_NS::HdSceneIndexObserver::AddedPrimEntries &entries) override; - - void _PrimsRemoved( - const PXR_NS::HdSceneIndexBase &sender, - const PXR_NS::HdSceneIndexObserver::RemovedPrimEntries &entries) override; - - void _PrimsDirtied( - const PXR_NS::HdSceneIndexBase &sender, - const PXR_NS::HdSceneIndexObserver::DirtiedPrimEntries &entries) override; - - -private: - SelectionSceneIndex( - const PXR_NS::HdSceneIndexBaseRefPtr &inputSceneIndex, - const std::shared_ptr& selection); - - const SelectionPtr _selection; - - const PathInterface* const _inputSceneIndexPathInterface; -}; - -} - -#endif +// +// Copyright 2022 Pixar +// +// Licensed under the Apache License, Version 2.0 (the "Apache License") +// with the following modification; you may not use this file except in +// compliance with the Apache License and the following modification to it: +// Section 6. Trademarks. is deleted and replaced with: +// +// 6. Trademarks. This License does not grant permission to use the trade +// names, trademarks, service marks, or product names of the Licensor +// and its affiliates, except as required to comply with Section 4(c) of +// the License and to reproduce the content of the NOTICE file. +// +// You may obtain a copy of the Apache License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the Apache License with the above modification is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the Apache License for the specific +// language governing permissions and limitations under the Apache License. +// +// Copyright 2023 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. +// +#ifndef FVP_SELECTION_SCENE_INDEX_H +#define FVP_SELECTION_SCENE_INDEX_H + +#include "flowViewport/api.h" +#include "flowViewport/selection/fvpSelectionFwd.h" +#include "flowViewport/sceneIndex/fvpPathInterface.h" +#include "flowViewport/sceneIndex/fvpSceneIndexUtils.h" + +#include + +#include + +#include + +UFE_NS_DEF { +class Path; +class Selection; +} + +namespace FVP_NS_DEF { + +class PathInterface; +class Selection; + +// Pixar declarePtrs.h TF_DECLARE_REF_PTRS macro unusable, places resulting +// type in PXR_NS. +class SelectionSceneIndex; +typedef PXR_NS::TfRefPtr SelectionSceneIndexRefPtr; +typedef PXR_NS::TfRefPtr SelectionSceneIndexConstRefPtr; + +/// \class SelectionSceneIndex +/// +/// A simple scene index adding HdSelectionsSchema to all prims selected +/// in the application. +/// +class SelectionSceneIndex final + : public PXR_NS::HdSingleInputFilteringSceneIndexBase + , public PathInterface + , public Fvp::InputSceneIndexUtils +{ +public: + using PXR_NS::HdSingleInputFilteringSceneIndexBase::_GetInputSceneIndex; + + FVP_API + static SelectionSceneIndexRefPtr New( + PXR_NS::HdSceneIndexBaseRefPtr const &inputSceneIndex, + const std::shared_ptr& selection + ); + + FVP_API + PXR_NS::HdSceneIndexPrim GetPrim(const PXR_NS::SdfPath &primPath) const override; + + FVP_API + PXR_NS::SdfPathVector GetChildPrimPaths(const PXR_NS::SdfPath &primPath) const override; + + /// Given a path (including usd proxy path inside a native instance) of + /// a USD prim, determine the corresponding prim in the Usd scene index + /// (filtered by the UsdImagingNiPrototypePropagatingSceneIndex) and + /// populate its selections data source. + FVP_API + void AddSelection(const Ufe::Path& appPath); + + FVP_API + void RemoveSelection(const Ufe::Path& appPath); + + FVP_API + void ReplaceSelection(const Ufe::Selection& selection); + + /// Reset the scene index selection state. + FVP_API + void ClearSelection(); + + FVP_API + bool IsFullySelected(const PXR_NS::SdfPath& primPath) const; + + FVP_API + bool HasFullySelectedAncestorInclusive(const PXR_NS::SdfPath& primPath) const; + + //! Path interface override. Forwards the call to the input scene index, + //! and warns about empty return paths. + //@{ + FVP_API + PXR_NS::SdfPath SceneIndexPath(const Ufe::Path& appPath) const override; + //@} + + FVP_API + PXR_NS::SdfPathVector GetFullySelectedPaths() const; + +protected: + void _PrimsAdded( + const PXR_NS::HdSceneIndexBase &sender, + const PXR_NS::HdSceneIndexObserver::AddedPrimEntries &entries) override; + + void _PrimsRemoved( + const PXR_NS::HdSceneIndexBase &sender, + const PXR_NS::HdSceneIndexObserver::RemovedPrimEntries &entries) override; + + void _PrimsDirtied( + const PXR_NS::HdSceneIndexBase &sender, + const PXR_NS::HdSceneIndexObserver::DirtiedPrimEntries &entries) override; + + +private: + SelectionSceneIndex( + const PXR_NS::HdSceneIndexBaseRefPtr &inputSceneIndex, + const std::shared_ptr& selection); + + const SelectionPtr _selection; + + const PathInterface* const _inputSceneIndexPathInterface; +}; + +} + +#endif diff --git a/lib/flowViewport/sceneIndex/fvpWireframeSelectionHighlightSceneIndex.cpp b/lib/flowViewport/sceneIndex/fvpWireframeSelectionHighlightSceneIndex.cpp index 88474ebaff..75ed0e9355 100644 --- a/lib/flowViewport/sceneIndex/fvpWireframeSelectionHighlightSceneIndex.cpp +++ b/lib/flowViewport/sceneIndex/fvpWireframeSelectionHighlightSceneIndex.cpp @@ -69,8 +69,9 @@ WireframeSelectionHighlightSceneIndex( const HdSceneIndexBaseRefPtr& inputSceneIndex, const SelectionConstPtr& selection ) - : HdSingleInputFilteringSceneIndexBase(inputSceneIndex), - _selection(selection) + : HdSingleInputFilteringSceneIndexBase(inputSceneIndex) + , InputSceneIndexUtils(inputSceneIndex) + , _selection(selection) {} HdSceneIndexPrim @@ -79,7 +80,7 @@ WireframeSelectionHighlightSceneIndex::GetPrim(const SdfPath &primPath) const TF_DEBUG(FVP_WIREFRAME_SELECTION_HIGHLIGHT_SCENE_INDEX) .Msg("WireframeSelectionHighlightSceneIndex::GetPrim(%s) called.\n", primPath.GetText()); - auto prim = _GetInputSceneIndex()->GetPrim(primPath); + auto prim = GetInputSceneIndex()->GetPrim(primPath); // If prim is in excluded hierarchy, don't provide selection highlighting // for it. Selection highlighting is done only on meshes. HYDRA-569: this @@ -98,7 +99,7 @@ WireframeSelectionHighlightSceneIndex::GetPrim(const SdfPath &primPath) const SdfPathVector WireframeSelectionHighlightSceneIndex::GetChildPrimPaths(const SdfPath &primPath) const { - return _GetInputSceneIndex()->GetChildPrimPaths(primPath); + return GetInputSceneIndex()->GetChildPrimPaths(primPath); } void diff --git a/lib/flowViewport/sceneIndex/fvpWireframeSelectionHighlightSceneIndex.h b/lib/flowViewport/sceneIndex/fvpWireframeSelectionHighlightSceneIndex.h index 1738af67f0..d24d269532 100644 --- a/lib/flowViewport/sceneIndex/fvpWireframeSelectionHighlightSceneIndex.h +++ b/lib/flowViewport/sceneIndex/fvpWireframeSelectionHighlightSceneIndex.h @@ -17,6 +17,7 @@ #include "flowViewport/api.h" #include "flowViewport/selection/fvpSelectionFwd.h" +#include "flowViewport/sceneIndex/fvpSceneIndexUtils.h" #include #include @@ -40,8 +41,10 @@ typedef PXR_NS::TfRefPtr WireframeS /// class WireframeSelectionHighlightSceneIndex : public PXR_NS::HdSingleInputFilteringSceneIndexBase + , public Fvp::InputSceneIndexUtils { public: + using PXR_NS::HdSingleInputFilteringSceneIndexBase::_GetInputSceneIndex; FVP_API static PXR_NS::HdSceneIndexBaseRefPtr New( diff --git a/lib/mayaHydra/flowViewportAPIExamples/flowViewportAPIMayaLocator/CMakeLists.txt b/lib/mayaHydra/flowViewportAPIExamples/flowViewportAPIMayaLocator/CMakeLists.txt index b66f690bea..1f93f3e196 100644 --- a/lib/mayaHydra/flowViewportAPIExamples/flowViewportAPIMayaLocator/CMakeLists.txt +++ b/lib/mayaHydra/flowViewportAPIExamples/flowViewportAPIMayaLocator/CMakeLists.txt @@ -93,8 +93,10 @@ install(TARGETS ${TARGET_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/maya) if(IS_WINDOWS) - install(FILES $ + if (NOT CODE_COVERAGE) + install(FILES $ DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/maya OPTIONAL) + endif() endif() set(LIBFILENAME ${CMAKE_SHARED_LIBRARY_PREFIX}${TARGET_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX}) diff --git a/lib/mayaHydra/hydraExtensions/CMakeLists.txt b/lib/mayaHydra/hydraExtensions/CMakeLists.txt index f23563c06a..94f4b776a1 100644 --- a/lib/mayaHydra/hydraExtensions/CMakeLists.txt +++ b/lib/mayaHydra/hydraExtensions/CMakeLists.txt @@ -190,8 +190,10 @@ install(FILES ${HEADERS} ) if(IS_WINDOWS) - install(FILES $ - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib OPTIONAL) + if (NOT CODE_COVERAGE) + install(FILES $ + DESTINATION ${CMAKE_INSTALL_PREFIX}/lib OPTIONAL) + endif() endif() # ----------------------------------------------------------------------------- diff --git a/lib/mayaHydra/hydraExtensions/mayaHydraSceneProducer.cpp b/lib/mayaHydra/hydraExtensions/mayaHydraSceneProducer.cpp index 5b716c93bf..25586d209d 100644 --- a/lib/mayaHydra/hydraExtensions/mayaHydraSceneProducer.cpp +++ b/lib/mayaHydra/hydraExtensions/mayaHydraSceneProducer.cpp @@ -104,6 +104,16 @@ MayaHydraSceneProducer::~MayaHydraSceneProducer() _delegates.clear(); } +#ifdef CODE_COVERAGE_WORKAROUND +void MayaHydraSceneProducer::Cleanup() +{ + if (enableMayaNativeSceneIndex()) + { + _sceneIndex->RemoveCallbacksAndDeleteAdapters(); + } +} +#endif + void MayaHydraSceneProducer::HandleCompleteViewportScene(const MDataServerOperation::MViewportScene& scene, MFrameContext::DisplayStyle ds) { if (enableMayaNativeSceneIndex()) diff --git a/lib/mayaHydra/hydraExtensions/mayaHydraSceneProducer.h b/lib/mayaHydra/hydraExtensions/mayaHydraSceneProducer.h index acb4752a0d..51c5c029bf 100644 --- a/lib/mayaHydra/hydraExtensions/mayaHydraSceneProducer.h +++ b/lib/mayaHydra/hydraExtensions/mayaHydraSceneProducer.h @@ -188,6 +188,10 @@ class MAYAHYDRALIB_API MayaHydraSceneProducer return nSamples; } +#ifdef CODE_COVERAGE_WORKAROUND + void Cleanup(); +#endif + private: // diff --git a/lib/mayaHydra/hydraExtensions/sceneIndex/mhMayaUsdProxyShapeSceneIndex.cpp b/lib/mayaHydra/hydraExtensions/sceneIndex/mhMayaUsdProxyShapeSceneIndex.cpp index 77f94f5af5..8a037b76e6 100644 --- a/lib/mayaHydra/hydraExtensions/sceneIndex/mhMayaUsdProxyShapeSceneIndex.cpp +++ b/lib/mayaHydra/hydraExtensions/sceneIndex/mhMayaUsdProxyShapeSceneIndex.cpp @@ -33,6 +33,7 @@ MayaUsdProxyShapeSceneIndex::MayaUsdProxyShapeSceneIndex(const MAYAUSDAPI_NS::Pr const UsdImagingStageSceneIndexRefPtr& usdImagingStageSceneIndex, const MObjectHandle& dagNodeHandle) : ParentClass(sceneIndexChainLastElement) + , InputSceneIndexUtils(sceneIndexChainLastElement) , _usdImagingStageSceneIndex(usdImagingStageSceneIndex) , _proxyStage(proxyStage) , _dagNodeHandle(dagNodeHandle) @@ -122,12 +123,12 @@ Ufe::Path MayaUsdProxyShapeSceneIndex::InterpretRprimPath( // satisfying HdSceneIndexBase HdSceneIndexPrim MayaUsdProxyShapeSceneIndex::GetPrim(const SdfPath& primPath) const { - return _GetInputSceneIndex()->GetPrim(primPath); + return GetInputSceneIndex()->GetPrim(primPath); } SdfPathVector MayaUsdProxyShapeSceneIndex::GetChildPrimPaths(const SdfPath& primPath) const { - return _GetInputSceneIndex()->GetChildPrimPaths(primPath); + return GetInputSceneIndex()->GetChildPrimPaths(primPath); } } // namespace MAYAUSD_NS_DEF diff --git a/lib/mayaHydra/hydraExtensions/sceneIndex/mhMayaUsdProxyShapeSceneIndex.h b/lib/mayaHydra/hydraExtensions/sceneIndex/mhMayaUsdProxyShapeSceneIndex.h index 5d85abd186..342bb46eda 100644 --- a/lib/mayaHydra/hydraExtensions/sceneIndex/mhMayaUsdProxyShapeSceneIndex.h +++ b/lib/mayaHydra/hydraExtensions/sceneIndex/mhMayaUsdProxyShapeSceneIndex.h @@ -25,6 +25,9 @@ #include #include +// Flow Viewport Toolkit headers. +#include "flowViewport/sceneIndex/fvpSceneIndexUtils.h" + //Usd/Hydra headers #include #include @@ -51,8 +54,10 @@ TF_DECLARE_WEAK_AND_REF_PTRS(MayaUsdProxyShapeSceneIndex); /// Simply wraps single stage scene index for initial stage assignment and population /// class MayaUsdProxyShapeSceneIndex : public HdSingleInputFilteringSceneIndexBase + , public Fvp::InputSceneIndexUtils { public: + using PXR_NS::HdSingleInputFilteringSceneIndexBase::_GetInputSceneIndex; using ParentClass = HdSingleInputFilteringSceneIndexBase; static MayaUsdProxyShapeSceneIndexRefPtr @@ -110,4 +115,4 @@ PXR_NAMESPACE_CLOSE_SCOPE #endif //MAYAHYDRALIB_MAYAUSDAPI_ENABLED -#endif //MAYA_HYDRA_MAYAUSD_PROXY_SHAPE_SCENE_INDEX_PLUGIN_H \ No newline at end of file +#endif //MAYA_HYDRA_MAYAUSD_PROXY_SHAPE_SCENE_INDEX_PLUGIN_H diff --git a/lib/mayaHydra/hydraExtensions/sceneIndex/registration.cpp b/lib/mayaHydra/hydraExtensions/sceneIndex/registration.cpp index db2e52ee50..74e585450b 100644 --- a/lib/mayaHydra/hydraExtensions/sceneIndex/registration.cpp +++ b/lib/mayaHydra/hydraExtensions/sceneIndex/registration.cpp @@ -21,6 +21,9 @@ #include #include #include +#ifdef CODE_COVERAGE_WORKAROUND +#include +#endif #include #include @@ -197,6 +200,9 @@ bool MayaHydraSceneIndexRegistry::_RemoveSceneIndexForNode(const MObject& dagNod dataProducerSceneIndexInterface.removeViewportDataProducerSceneIndex(registration->rootSceneIndex); _registrationsByObjectHandle.erase(dagNodeHandle); _registrations.erase(registration->sceneIndexPathPrefix); +#ifdef CODE_COVERAGE_WORKAROUND + Fvp::leakSceneIndex(registration->rootSceneIndex); +#endif return true; } return false; diff --git a/lib/mayaHydra/mayaPlugin/CMakeLists.txt b/lib/mayaHydra/mayaPlugin/CMakeLists.txt index d06d73e95b..fe94a51b20 100644 --- a/lib/mayaHydra/mayaPlugin/CMakeLists.txt +++ b/lib/mayaHydra/mayaPlugin/CMakeLists.txt @@ -111,8 +111,10 @@ install(FILES ${HEADERS} ) if(IS_WINDOWS) - install(FILES $ - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/maya OPTIONAL) + if (NOT CODE_COVERAGE) + install(FILES $ + DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/maya OPTIONAL) + endif() endif() # install top level plugInfo.json that includes the configured plugInfo.json diff --git a/lib/mayaHydra/mayaPlugin/renderOverride.cpp b/lib/mayaHydra/mayaPlugin/renderOverride.cpp index 82ef6b4bc6..2a9b938e25 100644 --- a/lib/mayaHydra/mayaPlugin/renderOverride.cpp +++ b/lib/mayaHydra/mayaPlugin/renderOverride.cpp @@ -32,6 +32,9 @@ #include #include +#ifdef CODE_COVERAGE_WORKAROUND +#include +#endif #include #include #include @@ -832,7 +835,14 @@ void MtohRenderOverride::ClearHydraResources(bool fullReset) _sceneIndexRegistry.reset(); } +#ifdef CODE_COVERAGE_WORKAROUND + // Leak the Maya scene index, as its base class HdRetainedSceneIndex + // destructor crashes under Windows clang code coverage build. + _mayaHydraSceneProducer->Cleanup(); + _mayaHydraSceneProducer.release(); +#else _mayaHydraSceneProducer.reset(); +#endif _selectionSceneIndex.Reset(); _selection.reset(); @@ -847,7 +857,11 @@ void MtohRenderOverride::ClearHydraResources(bool fullReset) if (_renderIndex != nullptr) { GetMayaHydraLibInterface().UnregisterTerminalSceneIndex(_renderIndex->GetTerminalSceneIndex()); +#ifndef CODE_COVERAGE_WORKAROUND + // Leak the render index, as its destructor crashes under Windows clang + // code coverage build. delete _renderIndex; +#endif _renderIndex = nullptr; } @@ -889,6 +903,10 @@ void MtohRenderOverride::_CreateSceneIndicesChainAfterMergingSceneIndex() // selection highlighting. wfSi->addExcludedSceneRoot(_ID); _lastFilteringSceneIndexBeforeCustomFiltering = wfSi; + +#ifdef CODE_COVERAGE_WORKAROUND + Fvp::leakSceneIndex(_lastFilteringSceneIndexBeforeCustomFiltering); +#endif // Set the initial selection onto the selection scene index. _selectionSceneIndex->ReplaceSelection(*Ufe::GlobalSelection::get()); diff --git a/lib/mayaHydra/ufeExtensions/CMakeLists.txt b/lib/mayaHydra/ufeExtensions/CMakeLists.txt index 45f9ce560e..c1e4bc80c7 100644 --- a/lib/mayaHydra/ufeExtensions/CMakeLists.txt +++ b/lib/mayaHydra/ufeExtensions/CMakeLists.txt @@ -104,6 +104,8 @@ install(FILES ${HEADERS} ) if(IS_WINDOWS) - install(FILES $ - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib OPTIONAL) + if (NOT CODE_COVERAGE) + install(FILES $ + DESTINATION ${CMAKE_INSTALL_PREFIX}/lib OPTIONAL) + endif() endif() diff --git a/test/lib/mayaUsd/render/mayaToHydra/testMeshes.py b/test/lib/mayaUsd/render/mayaToHydra/testMeshes.py index 9b6e51682f..1e59d3cf3c 100644 --- a/test/lib/mayaUsd/render/mayaToHydra/testMeshes.py +++ b/test/lib/mayaUsd/render/mayaToHydra/testMeshes.py @@ -21,6 +21,7 @@ from testUtils import PluginLoaded import unittest +import os class TestMeshes(mtohUtils.MayaHydraBaseTestCase): # MayaHydraBaseTestCase.setUpClass requirement. @@ -29,6 +30,27 @@ class TestMeshes(mtohUtils.MayaHydraBaseTestCase): def matchingRprims(self, rprims, matching): return len([rprim for rprim in rprims if matching in rprim]) + # Override the base class method to provide a suffix to setUpClass(). + # + # This test is run twice, with different values for the + # MAYA_HYDRA_USE_MESH_ADAPTER environment variable. This requires creating + # two different output directories, otherwise the two test runs will clash + # when run in parallel, typically when trying to clear out the output + # directory before the test runs: + # File "[...]\maya\builds\master\maya\build\RelWithDebInfo\runTime\Python\Lib\shutil.py", line 624, in _rmtree_unsafe + # os.rmdir(path) + # PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: '[...]\\maya-hydra-4\\build\\Coverage\\test\\lib\\mayaUsd\\render\\mayaToHydra\\testMeshesOutput' + @classmethod + def setUpClass(cls): + if cls._file is None: + raise ValueError("Subclasses of MayaHydraBaseTestCase must " + "define `_file = __file__`") + + meshAdapter = os.getenv('MAYA_HYDRA_USE_MESH_ADAPTER', 0) + fixturesUtils.setUpClass(cls._file, 'mayaHydra', + initializeStandalone=False, + suffix='_meshAdapter' if meshAdapter else '') + @unittest.skipUnless(mayaUtils.hydraFixLevel() > 0, "Requires Data Server render item lifescope fix.") def test_sweepMesh(self): self.setHdStormRenderer() diff --git a/test/testUtils/mtohUtils.py b/test/testUtils/mtohUtils.py index b5cc0145b3..79a145fc56 100644 --- a/test/testUtils/mtohUtils.py +++ b/test/testUtils/mtohUtils.py @@ -54,7 +54,8 @@ def setUpClass(cls): if cls._file is None: raise ValueError("Subclasses of MayaHydraBaseTestCase must " "define `_file = __file__`") - fixturesUtils.readOnlySetUpClass(cls._file, 'mayaHydra', + # Set up all tests with their own test directory to write out test-specific coverage information + fixturesUtils.setUpClass(cls._file, 'mayaHydra', initializeStandalone=False) def setUp(self):