diff --git a/.gitmodules b/.gitmodules index 9699d65..0a93188 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,7 @@ [submodule "ext/ayon-cpp-api"] path = ext/ayon-cpp-api url = https://github.com/ynput/ayon-cpp-api.git + +[submodule "ext/ayon-cpp-dev-tools"] + path = ext/ayon-cpp-dev-tools + url = https://github.com/ynput/ayon-cpp-dev-tools.git diff --git a/BuildPlugins/AyonUsdLinux/AyonUsd23_5_Py39_Linux.cmake b/BuildPlugins/AyonUsdLinux/AyonUsd23_5_Py39_Linux.cmake index ffd7c92..8e7a0a8 100644 --- a/BuildPlugins/AyonUsdLinux/AyonUsd23_5_Py39_Linux.cmake +++ b/BuildPlugins/AyonUsdLinux/AyonUsd23_5_Py39_Linux.cmake @@ -32,6 +32,7 @@ execute_process( OUTPUT_VARIABLE Python_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE ) + if (NOT ${Python_VERSION} STREQUAL 3.9) # Check if System Installed Python version is 3.9 message(FATAL_ERROR "Python version: ${Python_VERSION}") endif() @@ -42,6 +43,7 @@ set(AR_PYTHON_LIB_NUMBER python39) set(AR_PYTHON_LIB_DIR ${Python_Base_Dir}) set(AR_PYTHON_INCLUDE_DIR ${Python_Base_Dir}/python3.9) + # setting up boost add_compile_definitions(BOOST_ALL_NO_LIB) set(AR_BOOST_NAMESPACE boost) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f71f49..71fa6b0 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,6 +38,8 @@ set(AR_AYONUSDRESOLVER_TARGET_LIB ayonUsdResolver) set(AR_AYONUSDRESOLVER_TARGET_PYTHON _${AR_AYONUSDRESOLVER_TARGET_LIB}) set(AR_AYONUSDRESOLVER_INSTALL_PREFIX ${AR_PROJECT_NAME}/${AR_AYONUSDRESOLVER_USD_PLUGIN_NAME}) +set(MACRO_REMOVE_SDF_FORMAT_ARGS 1) + # shared library setup commands if (WIN32) @@ -104,12 +106,26 @@ if(NOT DEFINED BOOST_LIB_DIR) message(FATAL_ERROR "BOOST_LIB_DIR is not defined. Please set it before continuing.") endif() +message(STATUS "AR_PXR_INCLUDE_DIR path: ${AR_PXR_INCLUDE_DIR}") +message(STATUS "AR_PXR_LIB_DIR path: ${AR_PXR_LIB_DIR}") +message(STATUS "AR_PXR_LIB_PREFIX path: ${AR_PXR_LIB_PREFIX}") +message(STATUS "AR_PYTHON_LIB_NUMBER path: ${AR_PYTHON_LIB_NUMBER}") +message(STATUS "AR_PYTHON_LIB_DIR path: ${AR_PYTHON_LIB_DIR}") +message(STATUS "AR_PYTHON_INCLUDE_DIR path: ${AR_PYTHON_INCLUDE_DIR}") +message(STATUS "AR_BOOST_INCLUDE_DIR path: ${AR_BOOST_INCLUDE_DIR}") +message(STATUS "BOOST_LIB_DIR path: ${BOOST_LIB_DIR}") + +message(STATUS "SDF_FORMAT_ARGS = ${MACRO_REMOVE_SDF_FORMAT_ARGS}") +add_compile_definitions(MACRO_REMOVE_SDF_FORMAT_ARGS=${MACRO_REMOVE_SDF_FORMAT_ARGS}) + +# Include AyonDevTools +add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/ext/ayon-cpp-dev-tools") -message(STATUS "Enable SDF_FORMAT_ARGS Remove Macro = ${MACRO_REMOVE_SDF_FORMAT_ARGS}") # Include AyonCppApi add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/ext/ayon-cpp-api") include_directories("${CMAKE_CURRENT_SOURCE_DIR}/ext/ayon-cpp-api") + # setting CXX11ABI infos if(DEFINED GLIBCXX_USE_CXX11_ABI) message(STATUS "Setting Up CXX11_ABI linking") diff --git a/Docs/src/md/Getting_Started.md b/Docs/src/md/Getting_Started.md index 0c451ed..e542da3 100644 --- a/Docs/src/md/Getting_Started.md +++ b/Docs/src/md/Getting_Started.md @@ -142,6 +142,7 @@ from usdAssetResolver import AyonUsdResolver Ar.SetPreferredResolver("AyonUsdResolver") ``` + > **note** > When you get a resolver via `Usd.Ar` API you will need to get an explicit context to > edit the global context as `Ar.GetResolver` will return a higher order class and @@ -219,6 +220,7 @@ duplicates in the keys but the Cache stores the data as an Unordered_Map so it will end up deduplicating the Keys. But you can't have spaces in the list as they are not removed and will be interpreted as part of the Key or Value. + **example**\n setup the resolver for pinning support. we empty all the AYON c++ api keys just for example you can simply not set them. @@ -247,6 +249,7 @@ print(stage.ExportToString()) PS: its interesting to know that when you generate a pinning file via the AYON-USD addon the json file will have a key named + `ayon_pinning_data_entry_scene`.\n This should always be the path used to open the stage Otherwise the pinning file might not have the correct AssetIdentifier stored.\n @@ -258,12 +261,14 @@ local path the resolver wont be able to resolve. `context = AyonUsdResolver.ResolverContext()` there are multiple ways to control the cache of a resolver. but if your resolver uses the global cache you can simply create a new ResolverContext and access the cache control functions to + affect the global cache.\n This does not work if you disconnected the Global cache from your resolver. `context.deleteFromCache(AssetIdentifier)` delete an individual cached entry. `context.clearCache()` clear the connected cache. + > **note** > It is important to understand that by default a Resolver will be connected to the global cache > and this call will delete all entries in the global cache not just the ones that @@ -276,6 +281,7 @@ global cache and have a Resolver local cache instead. `explicit_resolver = AyonUsdResolver.Resolver()` if you need to create an explicit resolver because you want to e.g pass a specific instance into a stage or you want to disconnect from the Global Cache you should access the Context + connected to this specific resolver.\n `explicit_resolver_context = explicit_resolver.GetConnectedContext()` all the other functions stay the same. @@ -307,5 +313,3 @@ explicit_resolver_context.dropCache() # Delete from cache and clearCache will also work with an explicit_resolver_context ``` - - diff --git a/README.md b/README.md index 9e42c86..6c13108 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ ## Introduction + The [AYON](https://ynput.io/ayon/) USD Resolver is [an asset resolver plugin](https://openusd.org/release/api/ar_page_front.html#ar_uri_resolvers) for [Pixar's USD](https://openusd.org). It's designed to turn URIs with the @@ -12,20 +13,31 @@ AYON compatible entity URIs through the [AyonCppApi](<(https://github.com/ynput/ayon-cpp-api/)>). > [!IMPORTANT]\ -> This repository uses Git Submodules. Make -> sure to use the correct `git clone` commands accordingly. +> This repository uses Git Submodules. Make sure to use the correct `git clone` +> commands accordingly.\ +> `git clone --recurse-submodules https://github.com/ynput/ayon-usd-resolver.git`\ +> `git submodule update --init --recursive` > [!IMPORTANT]\ -> The [AYON](https://ynput.io/ayon/) USD Resolver is a +> The [AYON](https://ynput.io/ayon/) USD Resolver is an > [AR2.0](https://openusd.org/release/wp_ar2.html) resolver and will not support -> packages that only support AR1.0 +> AR1.0 resolution. Make sure that your software package is compatible with the +> AR2.0 standard or use the **defaults** we provide in the +> [AYON Usd Addon](https://github.com/ynput/ayon-usd) + +> **NOTE**\ +> **Admin** and **Dev** docs can be found under `/Docs/Ayon_Docs/` + +# Repository Docs + ### Requirements: - C++ Compiler - Cmake -- GitHub public key setup (this is because the sub-modules are linked via git@) - Target DCC / SDK installed +- python3 development files (Optional when building Against AYON Usd) + ### Tested Platforms: @@ -34,10 +46,9 @@ AYON compatible entity URIs through the - Hou 19.5.900 - Hou 20.0.590 - Hou 20.0.630 + - Maya 2024.2(UsdAddon_0.25.0) + - Unreal5.4 - AyonUsd23_5_py39 (System Python install) - - Maya2024_2 - - Maya2025_2 - - Unreal5_4 - Windows 10 - Hou 19.5.805 diff --git a/scripts/build.py b/scripts/build.py new file mode 100644 index 0000000..7df0074 --- /dev/null +++ b/scripts/build.py @@ -0,0 +1,169 @@ +import subprocess +import argparse +import os +import shutil +import multiprocessing +import time +import platform + +compile_plugin = os.environ.get("COMPILEPLUGIN") +script_dir = os.path.dirname(__file__) +prj_root_dir = os.path.dirname(script_dir) +build_dir = os.path.join(prj_root_dir, "build") +resolvers_dir = os.path.join(prj_root_dir, "Resolvers") +current_resolver_dir = os.path.join(resolvers_dir, str(compile_plugin)) +max_cores = multiprocessing.cpu_count() + +bin_package_path = os.path.join(resolvers_dir, "AyonUsdResolverBin") +temp_dir_for_zip = os.path.join(resolvers_dir, "temp") + +zip_sub_path = f"{str(compile_plugin)}_{platform.system()}_{platform.machine()}" +zip_path = os.path.join(bin_package_path, zip_sub_path) + + +def generate_named_zip(resolver_source_path: str): + zip_inner_foulder_name = os.path.basename(zip_path) + zip_inner_foulder_path = os.path.join(temp_dir_for_zip, zip_inner_foulder_name) + + if os.path.exists(temp_dir_for_zip): + shutil.rmtree(temp_dir_for_zip) + os.makedirs(zip_inner_foulder_path) + + shutil.copytree(resolver_source_path, zip_inner_foulder_path, dirs_exist_ok=True) + os.makedirs(bin_package_path, exist_ok=True) + shutil.make_archive(zip_path, "zip", temp_dir_for_zip) + + shutil.rmtree(temp_dir_for_zip) + + +def cmake_get_vars(): + vars_dict = {} + process = subprocess.run( + ["cmake", "-LAH", ".", "-B", "build"], + stdout=subprocess.PIPE, + text=True, + universal_newlines=True, + # check=True, + ) + for i in process.stdout.split("//"): + for x in i.split("\n"): + if ":" in x: + key_val = x.split(":") + vars_dict[key_val[0]] = key_val[1] + return vars_dict + + +def cmake(*args): + command = ["cmake"] + command.extend(*args) + subprocess.run( + command, + check=True, + ) + + +class _StoreDictKeyPair(argparse.Action): + def __call__(self, parser, namespace, values, option_string=None): + extra_env_var_dict = {} + for kv in values.split(","): + k, v = kv.split("=") + extra_env_var_dict[k] = v + setattr(namespace, self.dest, extra_env_var_dict) + + +def main(): + cmd_args = argparse.ArgumentParser( + description="Ayon Usd Resolver main Build Script" + ) + cmd_args.add_argument( + "--DEV", help="Enable/Disable development build", type=int, default=0 + ) + cmd_args.add_argument( + "--JTRACE", help="Enable/Disable json tracing", type=int, default=0 + ) + cmd_args.add_argument( + "--Clean", + action="store_true", + help="delet build foulder for non cached build also adds --clean-first to cmake args", + ) + cmd_args.add_argument( + "--CompilePlugin", + type=str, + default=0, + help="select a compile plugin, this can be scipped if you set COMPILEPLUGIN env variable ", + ) + cmd_args.add_argument( + "--extra_env_vars", + dest="extra_env_var_dict", + action=_StoreDictKeyPair, + metavar="KEY1=VAL1,KEY2=VAL2...", + ) + cmd_args = cmd_args.parse_args() + + if cmd_args.extra_env_var_dict: + for key in cmd_args.extra_env_var_dict: + val = cmd_args.extra_env_var_dict[key] + os.environ[key] = val + + if cmd_args.CompilePlugin: + os.environ["COMPILEPLUGIN"] = cmd_args.CompilePlugin + global compile_plugin + global current_resolver_dir + compile_plugin = os.environ.get("COMPILEPLUGIN") + current_resolver_dir = os.path.join(resolvers_dir, compile_plugin) + + if not compile_plugin: + raise RuntimeError("No Compile plugin selected") + + prior_compile_vars = cmake_get_vars() + last_compile_plugin = str(prior_compile_vars.get("SelectedCompilePlugin")).split( + "=" + )[-1] + if not compile_plugin == last_compile_plugin: + + print( + "Last Selected Compile plgin is not the same as the current", + compile_plugin, + last_compile_plugin, + ) + cmd_args.Clean = True + + if cmd_args.Clean: + print("Running Clean Build") + if os.path.exists(build_dir): + shutil.rmtree(build_dir) + os.makedirs(build_dir, exist_ok=True) + if os.path.exists(current_resolver_dir): + shutil.rmtree(current_resolver_dir) + + construct_command = [ + ".", + "-B", + "build", + f"-DDEV={cmd_args.DEV}", + f"-DJTRACE={cmd_args.JTRACE}", + ] + cmake(construct_command) + + build_comand = ["--build", "build"] + if cmd_args.DEV: + build_comand.extend(["--config", "Debug"]) + else: + build_comand.extend(["--config", "Release"]) + if cmd_args.Clean: + build_comand.extend(["--clean-first"]) + build_comand.extend(["--parallel", str(max_cores)]) + cmake(build_comand) + + install_command = ["--install", "build"] + cmake(install_command) + + +if __name__ == "__main__": + os.chdir(prj_root_dir) + start_time = time.time() + main() + generate_named_zip(current_resolver_dir) + end_time = time.time() + build_time = end_time - start_time + print("build took", build_time, "seconds") diff --git a/scripts/old/build.bat b/scripts/old/build.bat new file mode 100644 index 0000000..ce88921 --- /dev/null +++ b/scripts/old/build.bat @@ -0,0 +1,7 @@ +cd ../ + +rmdir /s /q build + +cmake -S . -B build -DDEV=0 -DJTRACE=0 -DCMAKE_BUILD_TYPE=Release +cmake --build build --clean-first --config Release +cmake --install build diff --git a/scripts/old/build.sh b/scripts/old/build.sh new file mode 100755 index 0000000..96e55c3 --- /dev/null +++ b/scripts/old/build.sh @@ -0,0 +1,42 @@ +#!/bin/bash +set -e # Exit on error +cd ../ #move to root dir +#----------- Build Script Paths ------------ +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" + +echo $SCRIPT_DIR +if [ -z "$HOUDINI_INSTALL_DIR" ]; then + HOUDINI_INSTALL_DIR="/opt/hfs" # if you didn't set the Install dir variable we assume your Houdini is installed in the default directory +fi +export HFS="${HOUDINI_INSTALL_DIR}${HOU_VER}" + +CLEAN_BUILD=0 +DEV=0 +JTRACE=0 + +if [[ " $@ " =~ " Debug " ]]; then + echo "Build running in debug mode" + DEV=1 + + source devOpVars.sh + echo " dev var is set to $DEV" +fi + +if [[ " $@ " =~ " Clean " ]]; then + echo "Running Clean Build" + CLEAN_BUILD=1 + + rm -rf build + rm -rf Resolvers/${COMPILEPLUGIN} + mkdir build +fi + + + +cmake . -B build -DDEV=$DEV -DJTRACE=$JTRACE +if [ "$CLEAN_BUILD" -eq 1 ]; then + cmake --build build --clean-first +else + cmake --build build +fi +cmake --install build diff --git a/scripts/build.bat b/scripts/old/buildAyonUsd.bat similarity index 100% rename from scripts/build.bat rename to scripts/old/buildAyonUsd.bat diff --git a/src/AyonUsdResolver/CMakeLists.txt b/src/AyonUsdResolver/CMakeLists.txt index 97216e1..6fdcbad 100644 --- a/src/AyonUsdResolver/CMakeLists.txt +++ b/src/AyonUsdResolver/CMakeLists.txt @@ -4,14 +4,16 @@ endif() ### Targets ### add_library(${AR_AYONUSDRESOLVER_TARGET_LIB} SHARED - assetIdentDef.cpp - debugCodes.cpp + cache/assetIdentDef.cpp + codes/debugCodes.cpp + resolver.cpp resolverContext.cpp - resolverTokens.cpp + Wrappers_Tokens/resolverTokens.cpp - resolverContextCache.cpp - resolutionFunctions.cpp + cache/resolverContextCache.cpp + helpers/resolutionFunctions.cpp + ) target_compile_definitions(${AR_AYONUSDRESOLVER_TARGET_LIB} @@ -52,6 +54,7 @@ target_compile_definitions(${AR_AYONUSDRESOLVER_TARGET_LIB} ) target_link_libraries(${AR_AYONUSDRESOLVER_TARGET_LIB} AyonCppApi) +target_link_libraries(${AR_AYONUSDRESOLVER_TARGET_LIB} AyonCppDevToolsLib) # Install configure_file(plugInfo.json.in plugInfo.json) @@ -61,12 +64,13 @@ install(TARGETS ${AR_AYONUSDRESOLVER_TARGET_LIB} DESTINATION ${AR_AYONUSDRESOLVE add_library(${AR_AYONUSDRESOLVER_TARGET_PYTHON} SHARED - module.cpp - moduleDeps.cpp - wrapResolver.cpp - wrapResolverContext.cpp - wrapResolverTokens.cpp - resolverTokens.cpp + pluginData/module.cpp + pluginData/moduleDeps.cpp + Wrappers_Tokens/wrapResolver.cpp + Wrappers_Tokens/wrapResolverContext.cpp + Wrappers_Tokens/wrapResolverTokens.cpp + Wrappers_Tokens/resolverTokens.cpp + ) add_dependencies(${AR_AYONUSDRESOLVER_TARGET_PYTHON} ${AR_AYONUSDRESOLVER_TARGET_LIB}) set_boost_namespace(${AR_AYONUSDRESOLVER_TARGET_PYTHON}) @@ -77,6 +81,8 @@ target_link_libraries(${AR_AYONUSDRESOLVER_TARGET_PYTHON} ) target_link_libraries(${AR_AYONUSDRESOLVER_TARGET_PYTHON} AyonCppApi) +target_link_libraries(${AR_AYONUSDRESOLVER_TARGET_PYTHON} AyonCppDevToolsLib) + # Headers target_include_directories(${AR_AYONUSDRESOLVER_TARGET_PYTHON} PUBLIC diff --git a/src/AyonUsdResolver/resolverTokens.cpp b/src/AyonUsdResolver/Wrappers_Tokens/resolverTokens.cpp similarity index 100% rename from src/AyonUsdResolver/resolverTokens.cpp rename to src/AyonUsdResolver/Wrappers_Tokens/resolverTokens.cpp diff --git a/src/AyonUsdResolver/resolverTokens.h b/src/AyonUsdResolver/Wrappers_Tokens/resolverTokens.h similarity index 94% rename from src/AyonUsdResolver/resolverTokens.h rename to src/AyonUsdResolver/Wrappers_Tokens/resolverTokens.h index 7083937..43437e3 100644 --- a/src/AyonUsdResolver/resolverTokens.h +++ b/src/AyonUsdResolver/Wrappers_Tokens/resolverTokens.h @@ -1,7 +1,7 @@ #ifndef AR_AYONUSDRESOLVER_TOKENS_H #define AR_AYONUSDRESOLVER_TOKENS_H -#include "api.h" +#include "../pluginData/api.h" #include #include diff --git a/src/AyonUsdResolver/wrapResolver.cpp b/src/AyonUsdResolver/Wrappers_Tokens/wrapResolver.cpp similarity index 61% rename from src/AyonUsdResolver/wrapResolver.cpp rename to src/AyonUsdResolver/Wrappers_Tokens/wrapResolver.cpp index 7dc7668..0bf4efe 100644 --- a/src/AyonUsdResolver/wrapResolver.cpp +++ b/src/AyonUsdResolver/Wrappers_Tokens/wrapResolver.cpp @@ -1,4 +1,4 @@ -#include "resolver.h" +#include "../resolver.h" #include #include @@ -6,7 +6,9 @@ #include "boost_include_wrapper.h" // clang-format off #include BOOST_INCLUDE(python/class.hpp) +#include BOOST_INCLUDE(python/operators.hpp) #include BOOST_INCLUDE(python/return_value_policy.hpp) +#include BOOST_INCLUDE(python/copy_const_reference.hpp) // clang-format on using namespace AR_BOOST_NAMESPACE::python; @@ -16,7 +18,6 @@ void wrapResolver() { using This = AyonUsdResolver; - class_, AR_BOOST_NAMESPACE::noncopyable>("Resolver", no_init) - - ; + class_, AR_BOOST_NAMESPACE::noncopyable>("Resolver") + .def("GetConnectedContext", &This::GetConnectedContext, return_value_policy(), ""); } diff --git a/src/AyonUsdResolver/wrapResolverContext.cpp b/src/AyonUsdResolver/Wrappers_Tokens/wrapResolverContext.cpp similarity index 93% rename from src/AyonUsdResolver/wrapResolverContext.cpp rename to src/AyonUsdResolver/Wrappers_Tokens/wrapResolverContext.cpp index dee2dd5..f93f09f 100644 --- a/src/AyonUsdResolver/wrapResolverContext.cpp +++ b/src/AyonUsdResolver/Wrappers_Tokens/wrapResolverContext.cpp @@ -1,4 +1,4 @@ -#include "resolverContext.h" +#include "../resolverContext.h" #include "pxr/base/tf/pyUtils.h" #include "pxr/pxr.h" @@ -30,8 +30,7 @@ void wrapResolverContext() { using This = AyonUsdResolverContext; - class_("ResolverContext", no_init) - .def(init<>()) + class_("ResolverContext") .def(self == self) .def(self != self) .def("__hash__", _Hash) diff --git a/src/AyonUsdResolver/wrapResolverTokens.cpp b/src/AyonUsdResolver/Wrappers_Tokens/wrapResolverTokens.cpp similarity index 100% rename from src/AyonUsdResolver/wrapResolverTokens.cpp rename to src/AyonUsdResolver/Wrappers_Tokens/wrapResolverTokens.cpp diff --git a/src/AyonUsdResolver/cache/assetIdentDef.cpp b/src/AyonUsdResolver/cache/assetIdentDef.cpp new file mode 100644 index 0000000..d30ba48 --- /dev/null +++ b/src/AyonUsdResolver/cache/assetIdentDef.cpp @@ -0,0 +1,105 @@ +#include "assetIdentDef.h" +#include +#include +#include +#include + +PXR_NAMESPACE_USING_DIRECTIVE + +ArResolvedPath +assetIdent::getResolvedAssetPath() const { + return m_resolvedAssetPath; +}; + +bool +assetIdent::setResolvedAssetPath(const ArResolvedPath &inResolvedAssetPath) { + if (!this->is_modifiable()) { + return false; + } + this->m_resolvedAssetPath = inResolvedAssetPath; + return true; +}; +bool +assetIdent::setResolvedAssetPath(const std::string &inResolvedAssetPath) { + if (!this->is_modifiable()) { + return false; + } + this->m_resolvedAssetPath = ArResolvedPath(inResolvedAssetPath); + return true; +}; + +std::string +assetIdent::getAssetIdentifier() const { + return m_assetIdentifier; +}; + +bool +assetIdent::setAssetIdentifier(const std::string inAssetIdentifier) { + if (!this->is_modifiable()) { + return false; + } + this->m_assetIdentifier = inAssetIdentifier; + return true; +}; + +bool +assetIdent::is_empty() const { + if (this->m_assetIdentifier.empty() && this->m_resolvedAssetPath.empty()) { + return true; + } + + return false; +}; + +bool +assetIdent::is_valid() const { + return !this->m_invalidated; +} + +void +assetIdent::invalidate() { + if (!this->is_modifiable()) { + return; + }; + + this->m_invalidated = true; +}; + +void +assetIdent::validate() { + if (!this->is_modifiable()) { + return; + }; + + this->m_invalidated = false; +}; + +bool +assetIdent::is_modifiable() const { + return !this->m_static; +}; + +void +assetIdent::printInfo() const { + std::ostringstream oss; + oss << static_cast(this); + std::cout << "Static; " << this->m_static << " invalidated; " << this->m_invalidated << " AssetIdentifier; " + << this->m_assetIdentifier << " ResolvedPath; " << this->m_resolvedAssetPath.GetPathString().c_str() + << " Instance_m_Pose; " << oss.str().c_str() << " Instance_m_Size; " + << std::to_string(sizeof(*this)).c_str() << std::endl; +}; + +bool +assetIdent::operator==(const assetIdent &other) const { + return m_assetIdentifier == other.m_assetIdentifier; +}; + +assetIdent & +assetIdent::operator=(const assetIdent &other) { + if (this != &other) { + m_resolvedAssetPath = other.m_resolvedAssetPath; + m_assetIdentifier = other.m_assetIdentifier; + m_invalidated = other.m_invalidated; + } + return *this; +} diff --git a/src/AyonUsdResolver/cache/assetIdentDef.h b/src/AyonUsdResolver/cache/assetIdentDef.h new file mode 100644 index 0000000..4e96d9b --- /dev/null +++ b/src/AyonUsdResolver/cache/assetIdentDef.h @@ -0,0 +1,123 @@ +#ifndef ASSET_IDENT_DEF +#define ASSET_IDENT_DEF + +#include +#include "pxr/pxr.h" +#include "pxr/usd/ar/resolvedPath.h" + +/** + * @brief cache element class used to represent an Usd asset in cache for the resolver + * + * @param is_static + * @return + */ +PXR_NAMESPACE_USING_DIRECTIVE + +class assetIdent { + public: + assetIdent(): m_static(false) { + } + assetIdent(bool is_static): m_static(is_static) { + } + assetIdent(const std::string &assetIdentifier): m_assetIdentifier(assetIdentifier), m_static(false) { + } + assetIdent(const ArResolvedPath &path, const std::string &identifier, bool is_static): + m_resolvedAssetPath(path), + m_assetIdentifier(identifier), + m_static(is_static) { + } + + /** + * @brief returns the ResolvedAssetPath for this assetIdent + * + * @return Pxr ArResolvedPath + */ + ArResolvedPath getResolvedAssetPath() const; + /** + * @brief allows setting the ResolvedAssetPath + * + * @param inResolvedAssetPath + * @return false if assetIdent can't be modified (eg. is_valid) + */ + bool setResolvedAssetPath(const ArResolvedPath &inResolvedAssetPath); + bool setResolvedAssetPath(const std::string &inResolvedAssetPath); + + /** + * @brief returns the asset identifier + */ + std::string getAssetIdentifier() const; + + /** + * @brief allows you to set the internal m_assetIdentifier + * + * @param assetIdentifier + * @return + */ + bool setAssetIdentifier(const std::string inAssetIdentifier); + + /** + * @brief can be used to know if given assetIdent has data in it + * + * @return bool: true if neither m_resolvedAssetPath or m_assetIdentifier have any data in them + */ + bool is_empty() const; + /** + * @brief this function allows you to know if an given assetIdent's cache is still valid. This can be use full + * for TTL or cache invalidation as we use lazy reaching for cached objects + * + * @return true if the current data can safely be used. false if the data is out of data or should in be + * re-cached + */ + bool is_valid() const; + + /** + * @brief allows you to invalidate this assetIdent. It is not possible to invalidate an assetIdent that is not + * modifiable in this case the function will simply return + */ + void invalidate(); + + /** + * @brief allows you to validate this assetIdent. This function will return while doing nothing if is_modifiable + * returns false + */ + void validate(); + + /** + * @brief allows you to know if you can modify the data in this assetIdent it is also used in getAssetIdentifier + * and getResolvedAssetPath to keep you from modifying data you should not touch. This will be the case if this + * assetIdent is marked as static + * + * @return true if you are allowed to modify the assetIdent, false if the modification is not allowed for what + * ever reason + */ + bool is_modifiable() const; + + /** + * @brief this function will print out all debug info about this assetIdent instance + */ + void printInfo() const; + + bool operator==(const assetIdent &other) const; + + assetIdent &operator=(const assetIdent &other); + + private: + const bool m_static; + bool m_invalidated; + ArResolvedPath m_resolvedAssetPath; + std::string m_assetIdentifier; +}; + +struct assetIdentHash { + size_t + operator()(const assetIdent &instance) const { + return std::hash()(instance.getAssetIdentifier()); + } + + size_t + operator()(const std::string &str) const { + return std::hash()(str); + } +}; + +#endif // !ASSET_IDENT_DEF diff --git a/src/AyonUsdResolver/cache/resolverContextCache.cpp b/src/AyonUsdResolver/cache/resolverContextCache.cpp new file mode 100644 index 0000000..ef951c0 --- /dev/null +++ b/src/AyonUsdResolver/cache/resolverContextCache.cpp @@ -0,0 +1,369 @@ +#include "resolverContextCache.h" +#include "../config.h" +#include "../codes/debugCodes.h" +#include "nlohmann/json_fwd.hpp" +#include "../helpers/resolutionFunctions.h" + +#include "pxr/usd/ar/resolvedPath.h" +#include "pxr/base/arch/systemInfo.h" +#include "pxr/base/tf/pathUtils.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +PXR_NAMESPACE_USING_DIRECTIVE +// TODO pinning file hanlder should construct its cache directly at construction getAssetData should not call +// rootReplace +pinningFileHandler::pinningFileHandler(const std::string &pinningFilePath, + const std::unordered_map &rootReplaceData): + m_pinningFilePath(pinningFilePath), + m_rootReplaceData(rootReplaceData) { + std::ifstream pinningFile(this->m_pinningFilePath); + + if (!pinningFile.is_open()) { + throw std::runtime_error("pinningFileHandler was not able to open PinningFile: " + + this->m_pinningFilePath.string()); + } + + nlohmann::json raw_pinning_file; + try { + raw_pinning_file = nlohmann::json::parse(pinningFile); + } + catch (const nlohmann::json::parse_error &e) { + throw std::runtime_error("The pining File is not in the Correct Format: "); + } + + nlohmann::json pinningData = raw_pinning_file.at("ayon_resolver_pinning_data"); + pinningData.erase("ayon_pinning_data_entry_scene"); + + for (auto &entry: pinningData.items()) { + std::string pathed_key = ynput::tool::ayon::rootReplace(entry.key(), this->m_rootReplaceData); + std::string pathed_val = ynput::tool::ayon::rootReplace(entry.value(), this->m_rootReplaceData); + this->m_pinningFileData[pathed_key] = pathed_val; + } +}; + +/** + * @brief return assetIdent populated with root rootReplaceData from the pinning file using the pinning file data loaded + * at construction and the PROJECT_ROOTS env variable. + * this is not a cached function it will reconstruct the assetIdent. it will not reload the file or the env var however. + * + * @param resolveKey UsdAssetIdent + * @return populated assetIdent if key was found in pinning file. Empty assetIdent if key was not found + */ +assetIdent +pinningFileHandler::getAssetData(const std::string &resolveKey) { + assetIdent assetEntry; + + std::string pinnedAssetPath; + try { + pinnedAssetPath = this->m_pinningFileData.at(resolveKey); + } + catch (const nlohmann::json::out_of_range &e) { + return assetEntry; + // TODO decide if we should crash the resolver incase the UsdAssetIdent cant be found in the pinning file. Usd + // default is return empty path if you cant resolve it throw std::runtime_error("resolver was not able to find + // key in PinningFile key: " + resolveKey); + } + + if (!pinnedAssetPath.empty()) { + assetEntry.setAssetIdentifier(resolveKey); + assetEntry.setResolvedAssetPath(pinnedAssetPath); + } + + return assetEntry; +}; + +resolverContextCache::resolverContextCache(): m_AyonCache(), m_CommonCache(), m_PreCache(), m_static_cache(true) { + m_PreCache.reserve(PRECACHE_SIZE); + TF_DEBUG(AYONUSDRESOLVER_RESOLVER_CONTEXT).Msg("resolverContextCache::resolverContextCache() \n"); + + const char* enable_static_env_var = std::getenv(ENABLE_STATIC_GLOBAL_CACHE_ENV_KEY); + if (enable_static_env_var == nullptr || std::strcmp(enable_static_env_var, "false") == 0) { + m_ayon.emplace(); + this->m_static_cache = false; + } + else { + std::map projectRootsEnvMap = ynput::core::iostd::getEnvMap(PROJECT_ROOTS_ENV_KEY); + std::unordered_map projectRootsEnvUMap( + std::make_move_iterator(projectRootsEnvMap.begin()), std::make_move_iterator(projectRootsEnvMap.end())); + this->m_pinningFileHandler.emplace(ynput::core::iostd::getEnvKey(PINNING_FILE_PATH_ENV_KEY), + projectRootsEnvUMap); + } +}; + +resolverContextCache::~resolverContextCache() { + TF_DEBUG(AYONUSDRESOLVER_RESOLVER_CONTEXT).Msg("resolverContextCache::~resolverContextCache() \n"); +}; + +// TODO when ayonLogger.h has the header guards then we can import it and use logging from there +void +resolverContextCache::printCache() const { + TF_DEBUG(AYONUSDRESOLVER_RESOLVER_CONTEXT).Msg("resolverContextCache::printCache \n"); + + std::shared_lock PreCacheReadLock(this->m_PreCachesharedMutex); + std::shared_lock AyonCacheReadLock(this->m_AyonCachesharedMutex); + std::shared_lock CommonCacheReadLock(this->m_CommonCachesharedMutex); + std::cout << "Printing out the Cache Entries \n"; + + std::cout << "PreCache size: " << this->m_PreCache.size() << "\n"; + for (const auto &assetIdentInstance: this->m_PreCache) { + assetIdentInstance.printInfo(); + } + std::cout << "AyonCache size: " << m_AyonCache.size() << "\n"; + for (const auto &assetIdentInstance: m_AyonCache) { + assetIdentInstance.printInfo(); + } + std::cout << "CommonCache size: " << m_CommonCache.size() << "\n"; + for (const auto &assetIdentInstance: m_CommonCache) { + assetIdentInstance.printInfo(); + } + std::ostringstream oss; + oss << static_cast(this); + std::cout << "resolverContextCache infos;" << " Instance_M_Pose; " << oss.str().c_str() << " Instance_m_Size; " + << std::to_string(sizeof(*this)).c_str() << "\n"; + + std::cout << "-----------------------------------------------------\n" << std::endl; +}; + +void +resolverContextCache::insert(assetIdent &sourceAssetIdent) { + TF_DEBUG(AYONUSDRESOLVER_RESOLVER_CONTEXT) + .Msg("resolverContextCache::insert(%s) \n", sourceAssetIdent.getAssetIdentifier().c_str()); + if (m_PreCache.size() == PRECACHE_SIZE) { + migratePreCacheIntoAyonCache(); + } + + std::unique_lock PreCacheWriteLock(this->m_PreCachesharedMutex); + std::unique_lock AyonCacheWriteLock(this->m_AyonCachesharedMutex); + + this->m_PreCache.insert(std::move(sourceAssetIdent)); +}; + +void +resolverContextCache::migratePreCacheIntoAyonCache() { + TF_DEBUG(AYONUSDRESOLVER_RESOLVER_CONTEXT).Msg("resolverContextCache::migratePreCacheIntoAyonCache \n"); + std::unique_lock PreCacheWriteLock(this->m_PreCachesharedMutex); + std::unique_lock AyonCacheWriteLock(this->m_AyonCachesharedMutex); + + m_AyonCache.reserve(m_AyonCache.size() + m_PreCache.size()); + m_AyonCache.insert(std::make_move_iterator(m_PreCache.begin()), std::make_move_iterator(m_PreCache.end())); + m_PreCache.clear(); +}; + +assetIdent +resolverContextCache::getAsset(const std::string &assetIdentifier, + const cacheName &selectedCache, + const bool &isAyonPath) { + TF_DEBUG(AYONUSDRESOLVER_RESOLVER_CONTEXT).Msg("resolverContextCache::getAsset: (%s) \n", assetIdentifier.c_str()); + + assetIdent asset; + + if (assetIdentifier.empty()) { + return asset; + } + if (this->m_static_cache) { + return this->m_pinningFileHandler->getAssetData(assetIdentifier); + } + + std::unordered_set::iterator hit; + + std::shared_lock PreCachesharedLock(m_PreCachesharedMutex); + hit = m_PreCache.find(assetIdentifier); + if (hit != m_PreCache.end()) { + asset = *hit; + PreCachesharedLock.unlock(); + + TF_DEBUG(AYONUSDRESOLVER_RESOLVER_CONTEXT) + .Msg("resolverContextCache::getAsset: PreCache Hit on (%s) with (%s) \n", + asset.getAssetIdentifier().c_str(), asset.getResolvedAssetPath().GetPathString().c_str()); + return asset; + } + PreCachesharedLock.unlock(); + + switch (selectedCache) { + case AYONCACHE: + { + std::shared_lock AyonCacheSharedLock(m_AyonCachesharedMutex); + hit = m_AyonCache.find(assetIdentifier); + if (hit != m_AyonCache.end()) { + asset = *hit; + TF_DEBUG(AYONUSDRESOLVER_RESOLVER_CONTEXT).Msg("resolverContextCache::getAsset: AyonCache Hit \n"); + } + + AyonCacheSharedLock.unlock(); + break; + } + + case COMMONCACHE: + { + std::shared_lock CommonCacheSharedLock(m_CommonCachesharedMutex); + hit = m_CommonCache.find(assetIdentifier); + if (hit != m_CommonCache.end()) { + asset = *hit; + TF_DEBUG(AYONUSDRESOLVER_RESOLVER_CONTEXT) + .Msg("resolverContextCache::getAsset: CommonCache Hit \n"); + } + + CommonCacheSharedLock.unlock(); + break; + } + } + if (!asset.is_empty()) { + TF_DEBUG(AYONUSDRESOLVER_RESOLVER_CONTEXT) + .Msg("resolverContextCache::getAsset: Cache Hit with (%s) with (%s) \n", asset.getAssetIdentifier().c_str(), + asset.getResolvedAssetPath().GetPathString().c_str()); + return asset; + } + + TF_DEBUG(AYONUSDRESOLVER_RESOLVER_CONTEXT).Msg("resolverContextCache::getAsset: No Cache Hit \n"); + if (isAyonPath) { + std::pair resolvedAsset = m_ayon->resolvePath(assetIdentifier); + asset.setAssetIdentifier(std::move(resolvedAsset.first)); + asset.setResolvedAssetPath(std::move(resolvedAsset.second)); + + TF_DEBUG(AYONUSDRESOLVER_RESOLVER_CONTEXT).Msg("resolverContextCache::getAsset: called ayon.resolvePath() \n"); + this->insert(asset); + } + else { + if (_IsRelativePath(assetIdentifier)) { + asset.setResolvedAssetPath(_ResolveAnchored(ArchGetCwd(), assetIdentifier)); + } + else { + asset.setResolvedAssetPath(ArResolvedPath(TfNormPath(TfAbsPath(assetIdentifier)))); + } + if (!asset.getResolvedAssetPath().empty()) { + asset.setAssetIdentifier(assetIdentifier); + + std::shared_lock CommonCacheSharedLock(m_CommonCachesharedMutex); + + TF_DEBUG(AYONUSDRESOLVER_RESOLVER_CONTEXT) + .Msg("resolverContextCache::getAsset: insert into CommonCache \n"); + m_CommonCache.insert(asset); + } + } + + return asset; +}; + +void +resolverContextCache::removeCachedObject(const std::string &key) { + TF_DEBUG(AYONUSDRESOLVER_RESOLVER_CONTEXT).Msg("resolverContextCache::removeCachedObject (%s) \n", key.c_str()); + + std::unordered_set::iterator hit; + + std::unique_lock PreCachesharedWriteLock(m_PreCachesharedMutex); + + hit = m_PreCache.find(key); + if (hit != m_PreCache.end()) { + m_PreCache.erase(hit); + PreCachesharedWriteLock.unlock(); + TF_DEBUG(AYONUSDRESOLVER_RESOLVER_CONTEXT) + .Msg("resolverContextCache::removeCachedObject removed object from PreCache"); + return; + } + + std::unique_lock AyonCachesharedWriteLock(m_AyonCachesharedMutex); + + hit = m_AyonCache.find(key); + if (hit != m_AyonCache.end()) { + m_AyonCache.erase(hit); + AyonCachesharedWriteLock.unlock(); + TF_DEBUG(AYONUSDRESOLVER_RESOLVER_CONTEXT) + .Msg("resolverContextCache::removeCachedObject removed object from AyonCache"); + return; + } + + std::unique_lock CommonCachesharedWriteLock(m_CommonCachesharedMutex); + hit = m_CommonCache.find(key); + if (hit != m_CommonCache.end()) { + m_CommonCache.erase(hit); + CommonCachesharedWriteLock.unlock(); + TF_DEBUG(AYONUSDRESOLVER_RESOLVER_CONTEXT) + .Msg("resolverContextCache::removeCachedObject removed object from CommonCache"); + return; + } + + TF_DEBUG(AYONUSDRESOLVER_RESOLVER_CONTEXT) + .Msg("resolverContextCache::removeCachedObject the object could not be found"); +}; + +void +resolverContextCache::removeCachedObject(const std::string &key, const cacheName &selectedCache) { + TF_DEBUG(AYONUSDRESOLVER_RESOLVER_CONTEXT).Msg("resolverContextCache::removeCachedObject (%s) \n", key.c_str()); + + std::unordered_set::iterator hit; + + std::unique_lock PreCachesharedDellLock(m_PreCachesharedMutex); + hit = m_PreCache.find(key); + if (hit != m_PreCache.end()) { + m_PreCache.erase(hit); + PreCachesharedDellLock.unlock(); + TF_DEBUG(AYONUSDRESOLVER_RESOLVER_CONTEXT) + .Msg("resolverContextCache::removeCachedObject removed object from PreCache"); + + return; + } + else { + switch (selectedCache) { + case AYONCACHE: + { + std::unique_lock AyonCachesharedDellLock(m_AyonCachesharedMutex); + + hit = m_AyonCache.find(key); + if (hit != m_AyonCache.end()) { + m_AyonCache.erase(hit); + AyonCachesharedDellLock.unlock(); + TF_DEBUG(AYONUSDRESOLVER_RESOLVER_CONTEXT) + .Msg("resolverContextCache::removeCachedObject removed object from AyonCache"); + return; + } + break; + } + case COMMONCACHE: + { + std::unique_lock CommonCachesharedDellLock(m_CommonCachesharedMutex); + hit = m_CommonCache.find(key); + if (hit != m_CommonCache.end()) { + m_CommonCache.erase(hit); + CommonCachesharedDellLock.unlock(); + TF_DEBUG(AYONUSDRESOLVER_RESOLVER_CONTEXT) + .Msg("resolverContextCache::removeCachedObject removed object from CommonCache"); + return; + } + break; + } + } + } + + TF_DEBUG(AYONUSDRESOLVER_RESOLVER_CONTEXT) + .Msg("resolverContextCache::removeCachedObject the object could not be found"); +}; + +void +resolverContextCache::clearCache() { + TF_DEBUG(AYONUSDRESOLVER_RESOLVER_CONTEXT).Msg("resolverContextCache::clearCache \n"); + + std::unique_lock PreCachesharedMutexLock(m_PreCachesharedMutex); + std::unique_lock AyonCachesharedMutexLock(m_AyonCachesharedMutex); + std::unique_lock CommonCachesharedMutexLock(m_CommonCachesharedMutex); + m_CommonCache.clear(); + m_AyonCache.clear(); + m_PreCache.clear(); +}; + +bool +resolverContextCache::isCacheStatic() const { + return this->m_static_cache; +}; diff --git a/src/AyonUsdResolver/resolverContextCache.h b/src/AyonUsdResolver/cache/resolverContextCache.h similarity index 79% rename from src/AyonUsdResolver/resolverContextCache.h rename to src/AyonUsdResolver/cache/resolverContextCache.h index 14cda87..a8e6c15 100644 --- a/src/AyonUsdResolver/resolverContextCache.h +++ b/src/AyonUsdResolver/cache/resolverContextCache.h @@ -1,17 +1,35 @@ #ifndef AR_AYONUSDRESOLVER_RESOLVER_CONTEXT_CACHE_H #define AR_AYONUSDRESOLVER_RESOLVER_CONTEXT_CACHE_H +#include +#include #include #include -#include +#include #include "AyonCppApi.h" -#include "assetIdentDef.h" +#include "../cache/assetIdentDef.h" +#include PXR_NAMESPACE_USING_DIRECTIVE enum cacheName { AYONCACHE, COMMONCACHE }; +class pinningFileHandler { + public: + pinningFileHandler(const std::string &pinningFilePath, + const std::unordered_map &rootReplaceData); + ~pinningFileHandler() = default; + + assetIdent getAssetData(const std::string &resolveKey); + + private: + std::filesystem::path m_pinningFilePath; + nlohmann::json m_pinningFileData; + + std::unordered_map m_rootReplaceData; +}; + /** * @class resolverContextCache * @brief this class handles everything related to asset caching @@ -79,19 +97,21 @@ class resolverContextCache { */ void printCache() const; + bool isCacheStatic() const; + private: std::unordered_set m_PreCache; std::unordered_set m_AyonCache; std::unordered_set m_CommonCache; - // std::vector m_AyonCache; - // std::vector m_CommonCache; - // std::array m_PreCache; mutable std::shared_mutex m_PreCachesharedMutex; mutable std::shared_mutex m_AyonCachesharedMutex; mutable std::shared_mutex m_CommonCachesharedMutex; - AyonApi m_ayon; + std::optional m_ayon; + bool m_static_cache; + + std::optional m_pinningFileHandler; }; #endif // AR_AYONUSDRESOLVER_RESOLVER_CONTEXT_CACHE_H diff --git a/src/AyonUsdResolver/debugCodes.cpp b/src/AyonUsdResolver/codes/debugCodes.cpp similarity index 100% rename from src/AyonUsdResolver/debugCodes.cpp rename to src/AyonUsdResolver/codes/debugCodes.cpp diff --git a/src/AyonUsdResolver/debugCodes.h b/src/AyonUsdResolver/codes/debugCodes.h similarity index 100% rename from src/AyonUsdResolver/debugCodes.h rename to src/AyonUsdResolver/codes/debugCodes.h diff --git a/src/AyonUsdResolver/config.h b/src/AyonUsdResolver/config.h index 17f1052..68cc69d 100644 --- a/src/AyonUsdResolver/config.h +++ b/src/AyonUsdResolver/config.h @@ -5,7 +5,12 @@ #include #include -#define PRECACHE_SIZE 64 +#define PRECACHE_SIZE 64 + +#define ENABLE_STATIC_GLOBAL_CACHE_ENV_KEY "ENABLE_STATIC_GLOBAL_CACHE" + +#define PROJECT_ROOTS_ENV_KEY "PROJECT_ROOTS" +#define PINNING_FILE_PATH_ENV_KEY "PINNING_FILE_PATH" namespace Config { diff --git a/src/AyonUsdResolver/devMacros.h b/src/AyonUsdResolver/helpers/devMacros.h similarity index 100% rename from src/AyonUsdResolver/devMacros.h rename to src/AyonUsdResolver/helpers/devMacros.h diff --git a/src/AyonUsdResolver/resolutionFunctions.cpp b/src/AyonUsdResolver/helpers/resolutionFunctions.cpp similarity index 97% rename from src/AyonUsdResolver/resolutionFunctions.cpp rename to src/AyonUsdResolver/helpers/resolutionFunctions.cpp index 36b6b67..c0f2912 100644 --- a/src/AyonUsdResolver/resolutionFunctions.cpp +++ b/src/AyonUsdResolver/helpers/resolutionFunctions.cpp @@ -1,10 +1,12 @@ #include +#include + #include #include #include "resolutionFunctions.h" -#include "debugCodes.h" -#include "config.h" +#include "../codes/debugCodes.h" +#include "../config.h" #include "pxr/base/tf/debug.h" #include "pxr/usd/ar/resolvedPath.h" diff --git a/src/AyonUsdResolver/resolutionFunctions.h b/src/AyonUsdResolver/helpers/resolutionFunctions.h similarity index 100% rename from src/AyonUsdResolver/resolutionFunctions.h rename to src/AyonUsdResolver/helpers/resolutionFunctions.h diff --git a/src/AyonUsdResolver/pluginData/api.h b/src/AyonUsdResolver/pluginData/api.h new file mode 100644 index 0000000..dbb7a6b --- /dev/null +++ b/src/AyonUsdResolver/pluginData/api.h @@ -0,0 +1,24 @@ +#ifndef AR_AYONUSDRESOLVER_API_H +#define AR_AYONUSDRESOLVER_API_H + +#include "pxr/base/arch/export.h" + +#if defined(PXR_STATIC) + #define AR_AYONUSDRESOLVER_API + #define AR_AYONUSDRESOLVER_API_TEMPLATE_CLASS(...) + #define AR_AYONUSDRESOLVER_API_TEMPLATE_STRUCT(...) + #define AR_AYONUSDRESOLVER_LOCAL +#else + #if defined(AR_AYONUSDRESOLVER_EXPORTS) + #define AR_AYONUSDRESOLVER_API ARCH_EXPORT + #define AR_AYONUSDRESOLVER_API_TEMPLATE_CLASS(...) ARCH_EXPORT_TEMPLATE(class, __VA_ARGS__) + #define AR_AYONUSDRESOLVER_API_TEMPLATE_STRUCT(...) ARCH_EXPORT_TEMPLATE(struct, __VA_ARGS__) + #else + #define AR_AYONUSDRESOLVER_API ARCH_IMPORT + #define AR_AYONUSDRESOLVER_API_TEMPLATE_CLASS(...) ARCH_IMPORT_TEMPLATE(class, __VA_ARGS__) + #define AR_AYONUSDRESOLVER_API_TEMPLATE_STRUCT(...) ARCH_IMPORT_TEMPLATE(struct, __VA_ARGS__) + #endif + #define AR_AYONUSDRESOLVER_LOCAL ARCH_HIDDEN +#endif + +#endif // AR_AYONUSDRESOLVER_API_H diff --git a/src/AyonUsdResolver/module.cpp b/src/AyonUsdResolver/pluginData/module.cpp similarity index 75% rename from src/AyonUsdResolver/module.cpp rename to src/AyonUsdResolver/pluginData/module.cpp index e877f9c..476ec6c 100644 --- a/src/AyonUsdResolver/module.cpp +++ b/src/AyonUsdResolver/pluginData/module.cpp @@ -1,9 +1,7 @@ -#include "pxr/pxr.h" #include "pxr/base/tf/pyModule.h" -TF_WRAP_MODULE -{ +TF_WRAP_MODULE { TF_WRAP(Resolver); TF_WRAP(ResolverContext); TF_WRAP(ResolverTokens); -} \ No newline at end of file +} diff --git a/src/AyonUsdResolver/moduleDeps.cpp b/src/AyonUsdResolver/pluginData/moduleDeps.cpp similarity index 100% rename from src/AyonUsdResolver/moduleDeps.cpp rename to src/AyonUsdResolver/pluginData/moduleDeps.cpp diff --git a/src/AyonUsdResolver/resolver.cpp b/src/AyonUsdResolver/resolver.cpp index 5aaf4b8..f7c3869 100644 --- a/src/AyonUsdResolver/resolver.cpp +++ b/src/AyonUsdResolver/resolver.cpp @@ -1,9 +1,10 @@ +#include #include -#include "debugCodes.h" +#include "codes/debugCodes.h" #include "pxr/base/tf/debug.h" #include "pxr/usd/ar/resolvedPath.h" -#include "resolverContextCache.h" -#include "resolutionFunctions.h" +#include "cache/resolverContextCache.h" +#include "helpers/resolutionFunctions.h" #define CONVERT_STRING(string) #string #define DEFINE_STRING(string) CONVERT_STRING(string) @@ -20,8 +21,6 @@ #include "pxr/usd/sdf/layer.h" -#include - PXR_NAMESPACE_OPEN_SCOPE AR_DEFINE_RESOLVER(AyonUsdResolver, ArResolver); @@ -58,6 +57,7 @@ AyonUsdResolver::_CreateIdentifier(const std::string &assetPath, const ArResolve if (_IsNotFilePath(assetPath) && Resolve(anchoredAssetPath).empty()) { return TfNormPath(assetPath); } + return TfNormPath(anchoredAssetPath); } @@ -72,6 +72,10 @@ AyonUsdResolver::_CreateIdentifierForNewAsset(const std::string &assetPath, return assetPath; } + if (_IsAyonPath(assetPath)) { + return assetPath; + } + if (_IsRelativePath(assetPath)) { return TfNormPath(anchorAssetPath ? _AnchorRelativePath(anchorAssetPath, assetPath) : TfAbsPath(assetPath)); } @@ -93,26 +97,35 @@ AyonUsdResolver::_Resolve(const std::string &assetPath) const { return ArResolvedPath(assetPath); } + const AyonUsdResolverContext* activeContext = nullptr; + const AyonUsdResolverContext* contexts[2] = {this->_GetCurrentContextPtr(), &_fallbackContext}; + for (const AyonUsdResolverContext* ctx: contexts) { + if (ctx) { + activeContext = ctx; + break; + } + } + + if (activeContext->getCachePtr()->isCacheStatic()) { + ArResolvedPath cachedPath + = activeContext->getCachePtr()->getAsset(assetPath, cacheName::AYONCACHE, true).getResolvedAssetPath(); + return cachedPath; + } if (_IsAyonPath(assetPath)) { - const AyonUsdResolverContext* contexts[2] = {this->_GetCurrentContextPtr(), &_fallbackContext}; - for (const AyonUsdResolverContext* ctx: contexts) { - if (ctx) { - std::pair test; - assetIdent asset; + if (activeContext) { + std::pair test; + assetIdent asset; - std::shared_ptr resolverCache = ctx->getCachePtr(); + std::shared_ptr resolverCache = activeContext->getCachePtr(); - asset = resolverCache->getAsset(assetPath, cacheName::AYONCACHE, true); + asset = resolverCache->getAsset(assetPath, cacheName::AYONCACHE, true); - ArResolvedPath resolvedPath(asset.getResolvedAssetPath()); + ArResolvedPath resolvedPath(asset.getResolvedAssetPath()); - if (resolvedPath) { - TF_DEBUG(AYONUSDRESOLVER_RESOLVER) - .Msg("Resolver::_Resolve( '%s' ) resolved \n", resolvedPath.GetPathString().c_str()); - return resolvedPath; - } - // Only try the first valid context. - break; + if (resolvedPath) { + TF_DEBUG(AYONUSDRESOLVER_RESOLVER) + .Msg("Resolver::_Resolve( '%s' ) resolved \n", resolvedPath.GetPathString().c_str()); + return resolvedPath; } } return ArResolvedPath(); @@ -202,4 +215,10 @@ AyonUsdResolver::_GetCurrentContextPtr() const { return _GetCurrentContextObject(); } +const AyonUsdResolverContext* +AyonUsdResolver::GetConnectedContext() const { + // TODO test if this implementation is valid as this->_GetCurrentContextPtr() causes a new context to be created. + return &_fallbackContext; +}; + PXR_NAMESPACE_CLOSE_SCOPE diff --git a/src/AyonUsdResolver/resolver.h b/src/AyonUsdResolver/resolver.h index f8d0245..95996da 100644 --- a/src/AyonUsdResolver/resolver.h +++ b/src/AyonUsdResolver/resolver.h @@ -1,13 +1,13 @@ #ifndef AR_AYONUSDRESOLVER_RESOLVER_H #define AR_AYONUSDRESOLVER_RESOLVER_H -#include "api.h" +#include "pluginData/api.h" #include "pxr/pxr.h" #include "pxr/usd/ar/resolvedPath.h" #include "pxr/usd/ar/resolver.h" #include "resolverContext.h" -#include "resolutionFunctions.h" +#include "helpers/resolutionFunctions.h" #include #include @@ -47,6 +47,8 @@ class AyonUsdResolver final: public ArResolver { std::shared_ptr _OpenAssetForWrite(const ArResolvedPath &resolvedPath, WriteMode writeMode) const final; + AR_AYONUSDRESOLVER_API const AyonUsdResolverContext* GetConnectedContext() const; + private: const AyonUsdResolverContext* _GetCurrentContextPtr() const; AyonUsdResolverContext _fallbackContext; diff --git a/src/AyonUsdResolver/resolverContext.cpp b/src/AyonUsdResolver/resolverContext.cpp index 17a9e14..0f9e73c 100644 --- a/src/AyonUsdResolver/resolverContext.cpp +++ b/src/AyonUsdResolver/resolverContext.cpp @@ -1,28 +1,18 @@ #include #include -#include -#include "debugCodes.h" + +#include "codes/debugCodes.h" #define CONVERT_STRING(string) #string #define DEFINE_STRING(string) CONVERT_STRING(string) -#include "resolver.h" #include "resolverContext.h" -#include "resolverTokens.h" -#include "pxr/base/tf/getenv.h" -#include "pxr/base/tf/pathUtils.h" #include "pxr/pxr.h" -#include "pxr/usd/sdf/layer.h" -#include "pxr/usd/usd/collectionMembershipQuery.h" -#include -#include -#include #include PXR_NAMESPACE_USING_DIRECTIVE -// TODO find a better way to make the cache Global, this is not optimal at all. std::shared_ptr GlobalCache = std::make_shared(); bool @@ -46,9 +36,8 @@ getStringEndswithStrings(const std::string &value, const std::vectorInitialize(); } @@ -92,6 +81,7 @@ AyonUsdResolverContext::ClearAndReinitialize() { void AyonUsdResolverContext::dropCache() { TF_DEBUG(AYONUSDRESOLVER_RESOLVER_CONTEXT).Msg("ResolverContext::dropCache()\n"); + this->cache = std::make_shared(); }; void @@ -108,5 +98,5 @@ AyonUsdResolverContext::clearCache() { std::shared_ptr AyonUsdResolverContext::getCachePtr() const { - return cache; + return this->cache; }; diff --git a/src/AyonUsdResolver/resolverContext.h b/src/AyonUsdResolver/resolverContext.h index df61880..80ecc59 100644 --- a/src/AyonUsdResolver/resolverContext.h +++ b/src/AyonUsdResolver/resolverContext.h @@ -1,14 +1,13 @@ #ifndef AR_AYONUSDRESOLVER_RESOLVER_CONTEXT_H #define AR_AYONUSDRESOLVER_RESOLVER_CONTEXT_H -#include "api.h" +#include "pluginData/api.h" #include "pxr/pxr.h" #include "pxr/usd/ar/defineResolverContext.h" -#include "resolverContextCache.h" +#include "cache/resolverContextCache.h" -#include #include class AyonUsdResolverContext {