From 1bde036cfea9e581a6399f5b2d186016c739eebe Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Mon, 5 Feb 2024 14:20:46 +0100 Subject: [PATCH 01/10] First steps towards using SqliteCache No UI for maxiumum cache items yet. --- extern/CMakeLists.txt | 1 + src/core/CMakeLists.txt | 1 + src/core/src/Context.cpp | 68 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 69 insertions(+), 1 deletion(-) diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt index d4abf9711..e639fa9d9 100644 --- a/extern/CMakeLists.txt +++ b/extern/CMakeLists.txt @@ -30,6 +30,7 @@ add_external_project( webpdecoder turbojpeg meshoptimizer + sqlite3 OPTIONS CESIUM_TESTS_ENABLED=OFF CESIUM_COVERAGE_ENABLED=OFF diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index d5ef6c636..7f6226a08 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -60,6 +60,7 @@ setup_lib( webpdecoder turbojpeg meshoptimizer + sqlite3 cpr::cpr stb::stb ZLIB::ZLIB diff --git a/src/core/src/Context.cpp b/src/core/src/Context.cpp index ee3947dee..4f86c127d 100644 --- a/src/core/src/Context.cpp +++ b/src/core/src/Context.cpp @@ -22,6 +22,8 @@ #endif #include +#include +#include #include #include #include @@ -31,21 +33,85 @@ #include #endif +#include + +#if defined(__linux__) +#include +#include +#include + +#include +#endif + namespace cesium::omniverse { +namespace { +// Quite a lot of ceremony to get the home directory +std::string getCacheDatabaseName() { + std::string homeDir; +#if defined(__linux__) + if (char* cString = std::getenv("HOME")) { + homeDir = cString; + } else { + passwd pwd; + long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); + if (bufsize == -1) { + bufsize = 16384; + } + char* buf = new char[static_cast(bufsize)]; + passwd* result = nullptr; + int getResult = getpwuid_r(getuid(), &pwd, buf, static_cast(bufsize), &result); + if (getResult == 0) { + homeDir = pwd.pw_dir; + } + delete[] buf; + } +#elif defined(_WIN32) + if (char* cString = getenv("USERPROFILE")) { + homeDir = cString; + } +#endif + if (!homeDir.empty()) { + std::filesystem::path homeDirPath(homeDir); + auto cacheFilePath = homeDirPath / ".nvidia-omniverse" / "cesium-request-cache.sqlite"; + return cacheFilePath.generic_string(); + } + return {}; +} + +std::shared_ptr& getCacheDatabase(const std::shared_ptr& logger) { + // XXX Get max items from UI + const int MaxCacheItems = 4096; + static auto pCacheDatabase = [&]() -> std::shared_ptr { + if (auto dbName = getCacheDatabaseName(); !dbName.empty()) { + return std::make_shared(logger, getCacheDatabaseName(), MaxCacheItems); + } + logger->oneTimeWarning("could not get name for cache database"); + return {}; + }(); + return pCacheDatabase; +} +} // namespace + Context::Context(const std::filesystem::path& cesiumExtensionLocation) : _cesiumExtensionLocation(cesiumExtensionLocation.lexically_normal()) , _cesiumMdlPathToken(pxr::TfToken((_cesiumExtensionLocation / "mdl" / "cesium.mdl").generic_string())) , _pTaskProcessor(std::make_shared()) , _pAsyncSystem(std::make_unique(_pTaskProcessor)) - , _pAssetAccessor(std::make_shared()) , _pCreditSystem(std::make_shared()) , _pLogger(std::make_shared()) , _pAssetRegistry(std::make_unique(this)) , _pFabricResourceManager(std::make_unique(this)) , _pCesiumIonServerManager(std::make_unique(this)) , _pUsdNotificationHandler(std::make_unique(this)) { + auto database = getCacheDatabase(_pLogger); + if (database) { + _pAssetAccessor = std::make_shared( + _pLogger, std::make_shared(), database); + } else { + _pAssetAccessor = std::make_shared(); + } Cesium3DTilesContent::registerAllTileContentTypes(); #if CESIUM_TRACING_ENABLED From 79c6e868990f2c73187f0496abcc3af4e3c83315 Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Mon, 5 Feb 2024 17:03:30 +0100 Subject: [PATCH 02/10] Get SqliteCache max cache items value from persistent store --- src/core/include/cesium/omniverse/SettingsWrapper.h | 3 +++ src/core/src/Context.cpp | 12 ++++++++---- src/core/src/SettingsWrapper.cpp | 8 ++++++++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/core/include/cesium/omniverse/SettingsWrapper.h b/src/core/include/cesium/omniverse/SettingsWrapper.h index 943e4e62a..8664dc012 100644 --- a/src/core/include/cesium/omniverse/SettingsWrapper.h +++ b/src/core/include/cesium/omniverse/SettingsWrapper.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -15,4 +16,6 @@ void setAccessToken(const AccessToken& accessToken); void removeAccessToken(const std::string& ionApiUrl); void clearTokens(); +uint64_t getMaxCacheItems(); + } // namespace cesium::omniverse::Settings diff --git a/src/core/src/Context.cpp b/src/core/src/Context.cpp index 4f86c127d..a842e5fd0 100644 --- a/src/core/src/Context.cpp +++ b/src/core/src/Context.cpp @@ -10,6 +10,7 @@ #include "cesium/omniverse/OmniIonRasterOverlay.h" #include "cesium/omniverse/OmniTileset.h" #include "cesium/omniverse/RenderStatistics.h" +#include "cesium/omniverse/SettingsWrapper.h" #include "cesium/omniverse/TaskProcessor.h" #include "cesium/omniverse/TilesetStatistics.h" #include "cesium/omniverse/UrlAssetAccessor.h" @@ -80,11 +81,14 @@ std::string getCacheDatabaseName() { } std::shared_ptr& getCacheDatabase(const std::shared_ptr& logger) { - // XXX Get max items from UI - const int MaxCacheItems = 4096; + // lambda is used here so that real code can be run when the static is initialized. static auto pCacheDatabase = [&]() -> std::shared_ptr { - if (auto dbName = getCacheDatabaseName(); !dbName.empty()) { - return std::make_shared(logger, getCacheDatabaseName(), MaxCacheItems); + uint64_t maxCacheItems = Settings::getMaxCacheItems(); + if (maxCacheItems == 0) { + logger->oneTimeWarning("maxCacheItems set to 0, so disabling accessor cache"); + return {}; + } else if (auto dbName = getCacheDatabaseName(); !dbName.empty()) { + return std::make_shared(logger, getCacheDatabaseName(), maxCacheItems); } logger->oneTimeWarning("could not get name for cache database"); return {}; diff --git a/src/core/src/SettingsWrapper.cpp b/src/core/src/SettingsWrapper.cpp index 8d9f97b8b..3d7a2b0b7 100644 --- a/src/core/src/SettingsWrapper.cpp +++ b/src/core/src/SettingsWrapper.cpp @@ -12,6 +12,7 @@ const std::string_view SESSION_ION_SERVER_URL_BASE = "/persistent/exts/cesium.omniverse/sessions/session{}/ionServerUrl"; const std::string_view SESSION_USER_ACCESS_TOKEN_BASE = "/persistent/exts/cesium.omniverse/sessions/session{}/userAccessToken"; +const char* MAX_CACHE_ITEMS_PATH = "/persistent/exts/cesium.omniverse/maxCacheItems"; std::string getIonApiUrlSettingPath(const uint64_t index) { return fmt::format(SESSION_ION_SERVER_URL_BASE, index); @@ -113,4 +114,11 @@ void clearTokens() { } } +uint64_t getMaxCacheItems() { + const int64_t defaultMaxCacheItems = 4096; + const auto iSettings = carb::getCachedInterface(); + iSettings->setDefaultInt64(MAX_CACHE_ITEMS_PATH, defaultMaxCacheItems); + auto maxCacheItems = iSettings->getAsInt64(MAX_CACHE_ITEMS_PATH); + return static_cast(maxCacheItems); +} } // namespace cesium::omniverse::Settings From 46d0b091d19274696aba94164cd5e05a13666365 Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Thu, 8 Feb 2024 13:22:16 +0100 Subject: [PATCH 03/10] Add UI for setting accessor cache size --- .../cesium/omniverse/utils}/custom_fields.py | 0 .../georefhelper/georef_helper_window.py | 2 +- .../cesium/powertools/powertools_window.py | 2 + .../powertools/utils/asset_cache_window.py | 44 +++++++++++++++++++ 4 files changed, 47 insertions(+), 1 deletion(-) rename exts/{cesium.powertools/cesium/powertools/georefhelper => cesium.omniverse/cesium/omniverse/utils}/custom_fields.py (100%) create mode 100644 exts/cesium.powertools/cesium/powertools/utils/asset_cache_window.py diff --git a/exts/cesium.powertools/cesium/powertools/georefhelper/custom_fields.py b/exts/cesium.omniverse/cesium/omniverse/utils/custom_fields.py similarity index 100% rename from exts/cesium.powertools/cesium/powertools/georefhelper/custom_fields.py rename to exts/cesium.omniverse/cesium/omniverse/utils/custom_fields.py diff --git a/exts/cesium.powertools/cesium/powertools/georefhelper/georef_helper_window.py b/exts/cesium.powertools/cesium/powertools/georefhelper/georef_helper_window.py index e21b67a29..a71a7dc09 100644 --- a/exts/cesium.powertools/cesium/powertools/georefhelper/georef_helper_window.py +++ b/exts/cesium.powertools/cesium/powertools/georefhelper/georef_helper_window.py @@ -3,7 +3,7 @@ import omni.usd from .proj import epsg_to_ecef, epsg_to_wgs84, get_crs_name_from_epsg import math -from .custom_fields import string_field_with_label, int_field_with_label, float_field_with_label +from cesium.omniverse.utils.custom_fields import string_field_with_label, int_field_with_label, float_field_with_label from pxr import Sdf diff --git a/exts/cesium.powertools/cesium/powertools/powertools_window.py b/exts/cesium.powertools/cesium/powertools/powertools_window.py index 2b9f1edc7..f672da071 100644 --- a/exts/cesium.powertools/cesium/powertools/powertools_window.py +++ b/exts/cesium.powertools/cesium/powertools/powertools_window.py @@ -3,6 +3,7 @@ from typing import Callable, Optional, List from cesium.omniverse.ui import CesiumOmniverseDebugWindow from .georefhelper.georef_helper_window import CesiumGeorefHelperWindow +from .utils.asset_cache_window import CesiumAssetCacheWindow from .utils import ( extend_far_plane, save_carb_settings, @@ -48,6 +49,7 @@ def __init__(self, **kwargs): self._actions: List[PowertoolsAction] = [ PowertoolsAction("Open Cesium Debugging Window", CesiumOmniverseDebugWindow.show_window), PowertoolsAction("Open Cesium Georeference Helper Window", CesiumGeorefHelperWindow.create_window), + PowertoolsAction("Open Cesium Cache Window", CesiumAssetCacheWindow.create_window), PowertoolsAction("Extend Far Plane", extend_far_plane), PowertoolsAction("Save Carb Settings", partial(save_carb_settings, powertools_extension_location)), PowertoolsAction("Save Fabric Stage", partial(save_fabric_stage, powertools_extension_location)), diff --git a/exts/cesium.powertools/cesium/powertools/utils/asset_cache_window.py b/exts/cesium.powertools/cesium/powertools/utils/asset_cache_window.py new file mode 100644 index 000000000..2cfcca06b --- /dev/null +++ b/exts/cesium.powertools/cesium/powertools/utils/asset_cache_window.py @@ -0,0 +1,44 @@ +import logging +import carb.settings +import omni.ui as ui +from cesium.omniverse.utils.custom_fields import int_field_with_label + +class CesiumAssetCacheWindow(ui.Window): + WINDOW_NAME = "Cesium Asset Cache" + + _logger: logging.Logger + + def __init__(self, **kwargs): + super().__init__(CesiumAssetCacheWindow.WINDOW_NAME, **kwargs) + + self._logger = logging.getLogger(__name__) + + # Set the function that is called to build widgets when the window is visible + self.frame.set_build_fn(self._build_fn) + + self._cache_items_setting = "/persistent/exts/cesium.omniverse/maxCacheItems" + + def destroy(self): + # It will destroy all the children + super().destroy() + + def __del__(self): + self.destroy() + + @staticmethod + def create_window(): + return CesiumAssetCacheWindow(width=250, height=400) + + def _set_cache_parameters(self): + newval = self._cache_items_model.get_value_as_int() + carb.settings.get_settings().set(self._cache_items_setting, newval) + + def _build_fn(self): + """Builds out the UI buttons and their handlers.""" + + with ui.VStack(spacing=4): + label_style = {"Label": {"font_size": 16}} + cache_items = carb.settings.get_settings().get(self._cache_items_setting) + self._cache_items_model = ui.SimpleIntModel(cache_items) + int_field_with_label("Maximum cache items", model=self._cache_items_model) + ui.Button("Set cache parameters", height=20, clicked_fn=self._set_cache_parameters) From d12510ba1a6bee544fce41bb61322ad432e98b3b Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Thu, 8 Feb 2024 18:08:46 +0100 Subject: [PATCH 04/10] Add interface and functions to clear the accessor cache --- .../bindings/CesiumOmniversePythonBindings.pyi | 1 + .../cesium/powertools/utils/asset_cache_window.py | 6 ++++++ include/cesium/omniverse/CesiumOmniverse.h | 4 ++++ src/bindings/PythonBindings.cpp | 3 ++- src/core/include/cesium/omniverse/Context.h | 5 ++++- src/core/src/Context.cpp | 14 ++++++++++---- src/public/CesiumOmniverse.cpp | 4 ++++ 7 files changed, 31 insertions(+), 6 deletions(-) diff --git a/exts/cesium.omniverse/cesium/omniverse/bindings/CesiumOmniversePythonBindings.pyi b/exts/cesium.omniverse/cesium/omniverse/bindings/CesiumOmniversePythonBindings.pyi index 4385f1fb2..cc2cf0dc8 100644 --- a/exts/cesium.omniverse/cesium/omniverse/bindings/CesiumOmniversePythonBindings.pyi +++ b/exts/cesium.omniverse/cesium/omniverse/bindings/CesiumOmniversePythonBindings.pyi @@ -65,6 +65,7 @@ class Connection: class ICesiumOmniverseInterface: def __init__(self, *args, **kwargs) -> None: ... + def clear_accessor_cache(self) -> None: ... def connect_to_ion(self) -> None: ... def create_token(self, arg0: str) -> None: ... def credits_available(self) -> bool: ... diff --git a/exts/cesium.powertools/cesium/powertools/utils/asset_cache_window.py b/exts/cesium.powertools/cesium/powertools/utils/asset_cache_window.py index 2cfcca06b..0f9a4ba95 100644 --- a/exts/cesium.powertools/cesium/powertools/utils/asset_cache_window.py +++ b/exts/cesium.powertools/cesium/powertools/utils/asset_cache_window.py @@ -2,6 +2,7 @@ import carb.settings import omni.ui as ui from cesium.omniverse.utils.custom_fields import int_field_with_label +from cesium.omniverse.utils.cesium_interface import CesiumInterfaceManager class CesiumAssetCacheWindow(ui.Window): WINDOW_NAME = "Cesium Asset Cache" @@ -33,6 +34,10 @@ def _set_cache_parameters(self): newval = self._cache_items_model.get_value_as_int() carb.settings.get_settings().set(self._cache_items_setting, newval) + def _clear_cache(self): + with CesiumInterfaceManager() as interface: + interface.clear_accessor_cache() + def _build_fn(self): """Builds out the UI buttons and their handlers.""" @@ -42,3 +47,4 @@ def _build_fn(self): self._cache_items_model = ui.SimpleIntModel(cache_items) int_field_with_label("Maximum cache items", model=self._cache_items_model) ui.Button("Set cache parameters", height=20, clicked_fn=self._set_cache_parameters) + ui.Button("Clear cache", height = 20, clicked_fn=self._clear_cache) diff --git a/include/cesium/omniverse/CesiumOmniverse.h b/include/cesium/omniverse/CesiumOmniverse.h index 6c224d962..3058d2a33 100644 --- a/include/cesium/omniverse/CesiumOmniverse.h +++ b/include/cesium/omniverse/CesiumOmniverse.h @@ -158,6 +158,10 @@ class ICesiumOmniverseInterface { virtual void creditsStartNextFrame() noexcept = 0; virtual bool isTracingEnabled() noexcept = 0; + /** + * @brief Clear the asset accessor cache. + */ + virtual void clearAccessorCache() = 0; }; } // namespace cesium::omniverse diff --git a/src/bindings/PythonBindings.cpp b/src/bindings/PythonBindings.cpp index 36698f748..019ee593e 100644 --- a/src/bindings/PythonBindings.cpp +++ b/src/bindings/PythonBindings.cpp @@ -72,7 +72,8 @@ PYBIND11_MODULE(CesiumOmniversePythonBindings, m) { .def("credits_available", &ICesiumOmniverseInterface::creditsAvailable) .def("get_credits", &ICesiumOmniverseInterface::getCredits) .def("credits_start_next_frame", &ICesiumOmniverseInterface::creditsStartNextFrame) - .def("is_tracing_enabled", &ICesiumOmniverseInterface::isTracingEnabled); + .def("is_tracing_enabled", &ICesiumOmniverseInterface::isTracingEnabled) + .def("clear_accessor_cache", &ICesiumOmniverseInterface::clearAccessorCache); // clang-format on py::class_>(m, "CesiumIonSession") diff --git a/src/core/include/cesium/omniverse/Context.h b/src/core/include/cesium/omniverse/Context.h index 5f66c7011..ffba2a356 100644 --- a/src/core/include/cesium/omniverse/Context.h +++ b/src/core/include/cesium/omniverse/Context.h @@ -19,6 +19,7 @@ class CreditSystem; namespace CesiumAsync { class AsyncSystem; class IAssetAccessor; +class ICacheDatabase; } // namespace CesiumAsync namespace cesium::omniverse { @@ -58,6 +59,7 @@ class Context { void clearStage(); void reloadStage(); + void clearAccessorCache(); void onUpdateFrame(const gsl::span& viewports); void onUsdStageChanged(int64_t stageId); @@ -76,9 +78,10 @@ class Context { std::shared_ptr _pTaskProcessor; std::unique_ptr _pAsyncSystem; + std::shared_ptr _pLogger; std::shared_ptr _pAssetAccessor; + std::shared_ptr _pCacheDatabase; std::shared_ptr _pCreditSystem; - std::shared_ptr _pLogger; std::unique_ptr _pAssetRegistry; std::unique_ptr _pFabricResourceManager; std::unique_ptr _pCesiumIonServerManager; diff --git a/src/core/src/Context.cpp b/src/core/src/Context.cpp index a842e5fd0..bb71ed807 100644 --- a/src/core/src/Context.cpp +++ b/src/core/src/Context.cpp @@ -102,16 +102,16 @@ Context::Context(const std::filesystem::path& cesiumExtensionLocation) , _cesiumMdlPathToken(pxr::TfToken((_cesiumExtensionLocation / "mdl" / "cesium.mdl").generic_string())) , _pTaskProcessor(std::make_shared()) , _pAsyncSystem(std::make_unique(_pTaskProcessor)) - , _pCreditSystem(std::make_shared()) , _pLogger(std::make_shared()) + , _pCacheDatabase(getCacheDatabase(_pLogger)) + , _pCreditSystem(std::make_shared()) , _pAssetRegistry(std::make_unique(this)) , _pFabricResourceManager(std::make_unique(this)) , _pCesiumIonServerManager(std::make_unique(this)) , _pUsdNotificationHandler(std::make_unique(this)) { - auto database = getCacheDatabase(_pLogger); - if (database) { + if (_pCacheDatabase) { _pAssetAccessor = std::make_shared( - _pLogger, std::make_shared(), database); + _pLogger, std::make_shared(), _pCacheDatabase); } else { _pAssetAccessor = std::make_shared(); @@ -215,6 +215,12 @@ void Context::reloadStage() { } } +void Context::clearAccessorCache() { + if (_pCacheDatabase) { + _pCacheDatabase->clearAll(); + } +} + void Context::onUpdateFrame(const gsl::span& viewports) { _pUsdNotificationHandler->onUpdateFrame(); _pAssetRegistry->onUpdateFrame(viewports); diff --git a/src/public/CesiumOmniverse.cpp b/src/public/CesiumOmniverse.cpp index 9a7c709ef..617a8714c 100644 --- a/src/public/CesiumOmniverse.cpp +++ b/src/public/CesiumOmniverse.cpp @@ -185,6 +185,10 @@ class CesiumOmniversePlugin final : public ICesiumOmniverseInterface { #endif } + void clearAccessorCache() override { + _pContext->clearAccessorCache(); + } + private: std::unique_ptr _pContext; }; From 3308e8adddf9decabb858183ac60c389f2c1b791 Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Tue, 13 Feb 2024 18:04:59 +0100 Subject: [PATCH 05/10] Create cesium::omniverse::FilesystemUtil and use it. FilesystemUtil has functions for getting the user's home directory and the preferred directory for a cache. Change Context setup code to use these new functions. --- .../include/cesium/omniverse/FilesystemUtil.h | 8 ++ src/core/src/Context.cpp | 68 +++++------------ src/core/src/FilesystemUtil.cpp | 74 +++++++++++++++++++ 3 files changed, 99 insertions(+), 51 deletions(-) create mode 100644 src/core/include/cesium/omniverse/FilesystemUtil.h create mode 100644 src/core/src/FilesystemUtil.cpp diff --git a/src/core/include/cesium/omniverse/FilesystemUtil.h b/src/core/include/cesium/omniverse/FilesystemUtil.h new file mode 100644 index 000000000..3aa0382d1 --- /dev/null +++ b/src/core/include/cesium/omniverse/FilesystemUtil.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +namespace cesium::omniverse::FilesystemUtil { +std::string getCesiumCacheDirectory(); +std::string getUserHomeDirectory(); +} // namespace cesium::omniverse::FilesystemUtil diff --git a/src/core/src/Context.cpp b/src/core/src/Context.cpp index bb71ed807..6ab88503c 100644 --- a/src/core/src/Context.cpp +++ b/src/core/src/Context.cpp @@ -5,6 +5,7 @@ #include "cesium/omniverse/FabricResourceManager.h" #include "cesium/omniverse/FabricStatistics.h" #include "cesium/omniverse/FabricUtil.h" +#include "cesium/omniverse/FilesystemUtil.h" #include "cesium/omniverse/Logger.h" #include "cesium/omniverse/OmniData.h" #include "cesium/omniverse/OmniIonRasterOverlay.h" @@ -34,66 +35,31 @@ #include #endif -#include - -#if defined(__linux__) -#include -#include -#include - -#include -#endif - namespace cesium::omniverse { namespace { -// Quite a lot of ceremony to get the home directory + std::string getCacheDatabaseName() { - std::string homeDir; -#if defined(__linux__) - if (char* cString = std::getenv("HOME")) { - homeDir = cString; - } else { - passwd pwd; - long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); - if (bufsize == -1) { - bufsize = 16384; - } - char* buf = new char[static_cast(bufsize)]; - passwd* result = nullptr; - int getResult = getpwuid_r(getuid(), &pwd, buf, static_cast(bufsize), &result); - if (getResult == 0) { - homeDir = pwd.pw_dir; - } - delete[] buf; - } -#elif defined(_WIN32) - if (char* cString = getenv("USERPROFILE")) { - homeDir = cString; - } -#endif - if (!homeDir.empty()) { - std::filesystem::path homeDirPath(homeDir); - auto cacheFilePath = homeDirPath / ".nvidia-omniverse" / "cesium-request-cache.sqlite"; + std::string cacheDir = FilesystemUtil::getCesiumCacheDirectory(); + if (!cacheDir.empty()) { + std::filesystem::path cacheDirPath(cacheDir); + auto cacheFilePath = cacheDirPath / "cesium-request-cache.sqlite"; return cacheFilePath.generic_string(); } return {}; } -std::shared_ptr& getCacheDatabase(const std::shared_ptr& logger) { - // lambda is used here so that real code can be run when the static is initialized. - static auto pCacheDatabase = [&]() -> std::shared_ptr { - uint64_t maxCacheItems = Settings::getMaxCacheItems(); - if (maxCacheItems == 0) { - logger->oneTimeWarning("maxCacheItems set to 0, so disabling accessor cache"); - return {}; - } else if (auto dbName = getCacheDatabaseName(); !dbName.empty()) { - return std::make_shared(logger, getCacheDatabaseName(), maxCacheItems); - } - logger->oneTimeWarning("could not get name for cache database"); +std::shared_ptr makeCacheDatabase(const std::shared_ptr& logger) { + uint64_t maxCacheItems = Settings::getMaxCacheItems(); + if (maxCacheItems == 0) { + logger->oneTimeWarning("maxCacheItems set to 0, so disabling accessor cache"); return {}; - }(); - return pCacheDatabase; + } else if (auto dbName = getCacheDatabaseName(); !dbName.empty()) { + logger->oneTimeWarning(fmt::format("Cesium cache file: {}", dbName)); + return std::make_shared(logger, getCacheDatabaseName(), maxCacheItems); + } + logger->oneTimeWarning("could not get name for cache database"); + return {}; } } // namespace @@ -103,7 +69,7 @@ Context::Context(const std::filesystem::path& cesiumExtensionLocation) , _pTaskProcessor(std::make_shared()) , _pAsyncSystem(std::make_unique(_pTaskProcessor)) , _pLogger(std::make_shared()) - , _pCacheDatabase(getCacheDatabase(_pLogger)) + , _pCacheDatabase(makeCacheDatabase(_pLogger)) , _pCreditSystem(std::make_shared()) , _pAssetRegistry(std::make_unique(this)) , _pFabricResourceManager(std::make_unique(this)) diff --git a/src/core/src/FilesystemUtil.cpp b/src/core/src/FilesystemUtil.cpp new file mode 100644 index 000000000..73a31f477 --- /dev/null +++ b/src/core/src/FilesystemUtil.cpp @@ -0,0 +1,74 @@ +#include "cesium/omniverse/FilesystemUtil.h" + +#include +#include +#include + +#include +#include + +#if defined(__linux__) +#include +#include +#include + +#include +#endif + +namespace cesium::omniverse::FilesystemUtil { + +std::string getCesiumCacheDirectory() { + auto f = carb::getFramework(); + auto* tokensInterface = f->tryAcquireInterface(); + std::string cacheDir; + if (tokensInterface) { + cacheDir = carb::tokens::resolveString(tokensInterface, "${omni_global_cache}"); + } + if (!cacheDir.empty()) { + std::filesystem::path cacheDirPath(cacheDir); + if (exists(cacheDirPath)) { + return cacheDirPath.generic_string(); + } + // Should we create the directory if it doesn't exist? It's hard to believe that Omniverse + // won't have already created it. + } + std::string homeDir = getUserHomeDirectory(); + if (!homeDir.empty()) { + std::filesystem::path homeDirPath(homeDir); + auto cacheDirPath = homeDirPath / ".nvidia-omniverse"; + if (exists(cacheDirPath)) { + return cacheDirPath.generic_string(); + } + } + return {}; +} + +// Quite a lot of ceremony to get the home directory. + +std::string getUserHomeDirectory() { + std::string homeDir; +#if defined(__linux__) + if (char* cString = std::getenv("HOME")) { + homeDir = cString; + } else { + passwd pwd; + long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); + if (bufsize == -1) { + bufsize = 16384; + } + char* buf = new char[static_cast(bufsize)]; + passwd* result = nullptr; + int getResult = getpwuid_r(getuid(), &pwd, buf, static_cast(bufsize), &result); + if (getResult == 0) { + homeDir = pwd.pw_dir; + } + delete[] buf; + } +#elif defined(_WIN32) + if (char* cString = std::getenv("USERPROFILE")) { + homeDir = cString; + } +#endif + return homeDir; +} +} // namespace cesium::omniverse::FilesystemUtil From 80dc2c2a85f240574f075c2928e7a8e2aff4f740 Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Fri, 23 Feb 2024 15:19:26 +0100 Subject: [PATCH 06/10] Move cesium-native cache interface to a new settings window The window is accessable from the same menu as the other Cesium windows. --- .../cesium/omniverse/extension.py | 33 +++++++++++- .../cesium/omniverse/ui/settings_window.py | 52 +++++++++++++++++++ .../cesium/powertools/powertools_window.py | 2 - .../powertools/utils/asset_cache_window.py | 50 ------------------ 4 files changed, 84 insertions(+), 53 deletions(-) create mode 100644 exts/cesium.omniverse/cesium/omniverse/ui/settings_window.py delete mode 100644 exts/cesium.powertools/cesium/powertools/utils/asset_cache_window.py diff --git a/exts/cesium.omniverse/cesium/omniverse/extension.py b/exts/cesium.omniverse/cesium/omniverse/extension.py index 28a8c39c7..cc0dc0d85 100644 --- a/exts/cesium.omniverse/cesium/omniverse/extension.py +++ b/exts/cesium.omniverse/cesium/omniverse/extension.py @@ -12,6 +12,7 @@ from .ui.asset_window import CesiumOmniverseAssetWindow from .ui.debug_window import CesiumOmniverseDebugWindow from .ui.main_window import CesiumOmniverseMainWindow +from .ui.settings_window import CesiumOmniverseSettingsWindow from .ui.credits_viewport_frame import CesiumCreditsViewportFrame from .ui.fabric_modal import CesiumFabricModal from .models import AssetToAdd, RasterOverlayToAdd @@ -53,6 +54,7 @@ def __init__(self) -> None: self._main_window: Optional[CesiumOmniverseMainWindow] = None self._asset_window: Optional[CesiumOmniverseAssetWindow] = None self._debug_window: Optional[CesiumOmniverseDebugWindow] = None + self._settings_window: Optional[CesiumOmniverseSettingsWindow] = None self._credits_viewport_frames: List[CesiumCreditsViewportFrame] = [] self._on_stage_subscription: Optional[carb.events.ISubscription] = None self._on_update_subscription: Optional[carb.events.ISubscription] = None @@ -81,7 +83,10 @@ def on_startup(self): ui.Workspace.set_show_window_fn( CesiumOmniverseAssetWindow.WINDOW_NAME, partial(self.show_assets_window, None) ) - ui.Workspace.set_show_window_fn(CesiumOmniverseDebugWindow.WINDOW_NAME, partial(self.show_debug_window, None)) + ui.Workspace.set_show_window_fn( + CesiumOmniverseDebugWindow.WINDOW_NAME, partial(self.show_debug_window, None)) + ui.Workspace.set_show_window_fn( + CesiumOmniverseSettingsWindow.WINDOW_NAME, partial(self.show_settings_window, None)) settings = omni_settings.get_settings() show_on_startup = settings.get_as_bool("/exts/cesium.omniverse/showOnStartup") @@ -89,6 +94,7 @@ def on_startup(self): self._add_to_menu(CesiumOmniverseMainWindow.MENU_PATH, self.show_main_window, show_on_startup) self._add_to_menu(CesiumOmniverseAssetWindow.MENU_PATH, self.show_assets_window, False) self._add_to_menu(CesiumOmniverseDebugWindow.MENU_PATH, self.show_debug_window, False) + self._add_to_menu(CesiumOmniverseSettingsWindow.MENU_PATH, self.show_settings_window, False) self._logger.info("CesiumOmniverse startup") @@ -190,6 +196,10 @@ def on_shutdown(self): self._debug_window.destroy() self._debug_window = None + if self._settings_window is not None: + self._settings_window.destroy() + self._settings_window = None + if self._credits_viewport_controller is not None: self._credits_viewport_controller.destroy() self._credits_viewport_controller = None @@ -198,6 +208,7 @@ def on_shutdown(self): ui.Workspace.set_show_window_fn(CesiumOmniverseMainWindow.WINDOW_NAME, None) ui.Workspace.set_show_window_fn(CesiumOmniverseAssetWindow.WINDOW_NAME, None) ui.Workspace.set_show_window_fn(CesiumOmniverseDebugWindow.WINDOW_NAME, None) + ui.Workspace.set_show_window_fn(CesiumOmniverseSettingsWindow.WINDOW_NAME, None) if self._on_stage_subscription is not None: self._on_stage_subscription.unsubscribe() @@ -411,6 +422,10 @@ async def _destroy_window_async(self, path): if self._debug_window is not None: self._debug_window.destroy() self._debug_window = None + elif path is CesiumOmniverseSettingsWindow.MENU_PATH: + if self._settings_window is not None: + self._settings_window.destroy() + self._settings_window = None def _visibility_changed_fn(self, path, visible): # Called when the user pressed "X" @@ -470,6 +485,22 @@ def show_debug_window(self, _menu, value): elif self._debug_window is not None: self._debug_window.visible = False + def show_settings_window(self, _menu, value): + if _cesium_omniverse_interface is None: + logging.error("Cesium Omniverse Interface is not set.") + return + + if value: + self._settings_window = CesiumOmniverseSettingsWindow( + _cesium_omniverse_interface, CesiumOmniverseSettingsWindow.WINDOW_NAME, width=300, height=365 + ) + self._settings_window.set_visibility_changed_fn( + partial(self._visibility_changed_fn, CesiumOmniverseSettingsWindow.MENU_PATH) + ) + asyncio.ensure_future(dock_window_async(self._settings_window)) + elif self._settings_window is not None: + self._settings_window.visible = False + def _setup_credits_viewport_frames(self): self._destroy_credits_viewport_frames() self._credits_viewport_frames = [ diff --git a/exts/cesium.omniverse/cesium/omniverse/ui/settings_window.py b/exts/cesium.omniverse/cesium/omniverse/ui/settings_window.py new file mode 100644 index 000000000..865110995 --- /dev/null +++ b/exts/cesium.omniverse/cesium/omniverse/ui/settings_window.py @@ -0,0 +1,52 @@ +import logging +import carb.settings +from typing import Optional +import omni.ui as ui +from ..bindings import ICesiumOmniverseInterface +from cesium.omniverse.utils.custom_fields import int_field_with_label + +class CesiumOmniverseSettingsWindow(ui.Window): + WINDOW_NAME = "Cesium Settings" + MENU_PATH = f"Window/Cesium/{WINDOW_NAME}" + + _logger: logging.Logger + _cesium_omniverse_interface: Optional[ICesiumOmniverseInterface] = None + + def __init__(self, cesium_omniverse_interface: ICesiumOmniverseInterface, title: str, **kwargs): + super().__init__(title, **kwargs) + + self._logger = logging.getLogger(__name__) + self._cesium_omniverse_interface = cesium_omniverse_interface + self._cache_items_setting = "/persistent/exts/cesium.omniverse/maxCacheItems" + + # Set the function that is called to build widgets when the window is visible + self.frame.set_build_fn(self._build_fn) + + def destroy(self): + # It will destroy all the children + super().destroy() + + def __del__(self): + self.destroy() + + @staticmethod + def show_window(): + ui.Workspace.show_window(CesiumOmniverseSettingsWindow.WINDOW_NAME) + + def _build_fn(self): + """Builds out the UI buttons and their handlers.""" + + def set_cache_parameters(): + newval = self._cache_items_model.get_value_as_int() + carb.settings.get_settings().set(self._cache_items_setting, newval) + + def clear_cache(): + self._cesium_omniverse_interface.clear_accessor_cache() + + with ui.VStack(spacing=4): + label_style = {"Label": {"font_size": 16}} + cache_items = carb.settings.get_settings().get(self._cache_items_setting) + self._cache_items_model = ui.SimpleIntModel(cache_items) + int_field_with_label("Maximum cache items", model=self._cache_items_model) + ui.Button("Set cache parameters (requires restart)", height=20, clicked_fn=set_cache_parameters) + ui.Button("Clear cache", height = 20, clicked_fn=clear_cache) diff --git a/exts/cesium.powertools/cesium/powertools/powertools_window.py b/exts/cesium.powertools/cesium/powertools/powertools_window.py index 773acae32..beb086dd4 100644 --- a/exts/cesium.powertools/cesium/powertools/powertools_window.py +++ b/exts/cesium.powertools/cesium/powertools/powertools_window.py @@ -3,7 +3,6 @@ from typing import Callable, Optional, List from cesium.omniverse.ui import CesiumOmniverseDebugWindow from .georefhelper.georef_helper_window import CesiumGeorefHelperWindow -from .utils.asset_cache_window import CesiumAssetCacheWindow from .utils import ( extend_far_plane, save_carb_settings, @@ -50,7 +49,6 @@ def __init__(self, **kwargs): PowertoolsAction("Open Cesium Debugging Window", CesiumOmniverseDebugWindow.show_window), PowertoolsAction("Open Cesium Georeference Helper Window", CesiumGeorefHelperWindow.create_window), PowertoolsAction("Open Cesium Load Timer Window", CesiumLoadTimerWindow.create_window), - PowertoolsAction("Open Cesium Cache Window", CesiumAssetCacheWindow.create_window), PowertoolsAction("Extend Far Plane", extend_far_plane), PowertoolsAction("Save Carb Settings", partial(save_carb_settings, powertools_extension_location)), PowertoolsAction("Save Fabric Stage", partial(save_fabric_stage, powertools_extension_location)), diff --git a/exts/cesium.powertools/cesium/powertools/utils/asset_cache_window.py b/exts/cesium.powertools/cesium/powertools/utils/asset_cache_window.py deleted file mode 100644 index 0f9a4ba95..000000000 --- a/exts/cesium.powertools/cesium/powertools/utils/asset_cache_window.py +++ /dev/null @@ -1,50 +0,0 @@ -import logging -import carb.settings -import omni.ui as ui -from cesium.omniverse.utils.custom_fields import int_field_with_label -from cesium.omniverse.utils.cesium_interface import CesiumInterfaceManager - -class CesiumAssetCacheWindow(ui.Window): - WINDOW_NAME = "Cesium Asset Cache" - - _logger: logging.Logger - - def __init__(self, **kwargs): - super().__init__(CesiumAssetCacheWindow.WINDOW_NAME, **kwargs) - - self._logger = logging.getLogger(__name__) - - # Set the function that is called to build widgets when the window is visible - self.frame.set_build_fn(self._build_fn) - - self._cache_items_setting = "/persistent/exts/cesium.omniverse/maxCacheItems" - - def destroy(self): - # It will destroy all the children - super().destroy() - - def __del__(self): - self.destroy() - - @staticmethod - def create_window(): - return CesiumAssetCacheWindow(width=250, height=400) - - def _set_cache_parameters(self): - newval = self._cache_items_model.get_value_as_int() - carb.settings.get_settings().set(self._cache_items_setting, newval) - - def _clear_cache(self): - with CesiumInterfaceManager() as interface: - interface.clear_accessor_cache() - - def _build_fn(self): - """Builds out the UI buttons and their handlers.""" - - with ui.VStack(spacing=4): - label_style = {"Label": {"font_size": 16}} - cache_items = carb.settings.get_settings().get(self._cache_items_setting) - self._cache_items_model = ui.SimpleIntModel(cache_items) - int_field_with_label("Maximum cache items", model=self._cache_items_model) - ui.Button("Set cache parameters", height=20, clicked_fn=self._set_cache_parameters) - ui.Button("Clear cache", height = 20, clicked_fn=self._clear_cache) From 4b2ec9b3c17c3a38853043bf0b3d7305f78f9d9f Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Fri, 23 Feb 2024 16:42:53 +0100 Subject: [PATCH 07/10] Change file utility functions to return std::filesystem::path --- src/core/include/cesium/omniverse/FilesystemUtil.h | 6 +++--- src/core/src/Context.cpp | 7 +++---- src/core/src/FilesystemUtil.cpp | 8 ++++---- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/core/include/cesium/omniverse/FilesystemUtil.h b/src/core/include/cesium/omniverse/FilesystemUtil.h index 3aa0382d1..8d92dc647 100644 --- a/src/core/include/cesium/omniverse/FilesystemUtil.h +++ b/src/core/include/cesium/omniverse/FilesystemUtil.h @@ -1,8 +1,8 @@ #pragma once -#include +#include namespace cesium::omniverse::FilesystemUtil { -std::string getCesiumCacheDirectory(); -std::string getUserHomeDirectory(); +std::filesystem::path getCesiumCacheDirectory(); +std::filesystem::path getUserHomeDirectory(); } // namespace cesium::omniverse::FilesystemUtil diff --git a/src/core/src/Context.cpp b/src/core/src/Context.cpp index e8a92209b..71d40bbec 100644 --- a/src/core/src/Context.cpp +++ b/src/core/src/Context.cpp @@ -38,9 +38,8 @@ namespace cesium::omniverse { namespace { std::string getCacheDatabaseName() { - std::string cacheDir = FilesystemUtil::getCesiumCacheDirectory(); - if (!cacheDir.empty()) { - std::filesystem::path cacheDirPath(cacheDir); + auto cacheDirPath = FilesystemUtil::getCesiumCacheDirectory(); + if (!cacheDirPath.empty()) { auto cacheFilePath = cacheDirPath / "cesium-request-cache.sqlite"; return cacheFilePath.generic_string(); } @@ -54,7 +53,7 @@ std::shared_ptr makeCacheDatabase(const std::shared return {}; } else if (auto dbName = getCacheDatabaseName(); !dbName.empty()) { logger->oneTimeWarning(fmt::format("Cesium cache file: {}", dbName)); - return std::make_shared(logger, getCacheDatabaseName(), maxCacheItems); + return std::make_shared(logger, dbName, maxCacheItems); } logger->oneTimeWarning("could not get name for cache database"); return {}; diff --git a/src/core/src/FilesystemUtil.cpp b/src/core/src/FilesystemUtil.cpp index 73a31f477..59f4c4bc0 100644 --- a/src/core/src/FilesystemUtil.cpp +++ b/src/core/src/FilesystemUtil.cpp @@ -17,7 +17,7 @@ namespace cesium::omniverse::FilesystemUtil { -std::string getCesiumCacheDirectory() { +std::filesystem::path getCesiumCacheDirectory() { auto f = carb::getFramework(); auto* tokensInterface = f->tryAcquireInterface(); std::string cacheDir; @@ -27,7 +27,7 @@ std::string getCesiumCacheDirectory() { if (!cacheDir.empty()) { std::filesystem::path cacheDirPath(cacheDir); if (exists(cacheDirPath)) { - return cacheDirPath.generic_string(); + return cacheDirPath; } // Should we create the directory if it doesn't exist? It's hard to believe that Omniverse // won't have already created it. @@ -37,7 +37,7 @@ std::string getCesiumCacheDirectory() { std::filesystem::path homeDirPath(homeDir); auto cacheDirPath = homeDirPath / ".nvidia-omniverse"; if (exists(cacheDirPath)) { - return cacheDirPath.generic_string(); + return cacheDirPath; } } return {}; @@ -45,7 +45,7 @@ std::string getCesiumCacheDirectory() { // Quite a lot of ceremony to get the home directory. -std::string getUserHomeDirectory() { +std::filesystem::path getUserHomeDirectory() { std::string homeDir; #if defined(__linux__) if (char* cString = std::getenv("HOME")) { From 654e8a6e5599b5c6ed2050940f5d5b70156b63c3 Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Fri, 23 Feb 2024 17:00:04 +0100 Subject: [PATCH 08/10] Python formatting fixes --- exts/cesium.omniverse/cesium/omniverse/extension.py | 6 +++--- .../cesium.omniverse/cesium/omniverse/ui/settings_window.py | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/exts/cesium.omniverse/cesium/omniverse/extension.py b/exts/cesium.omniverse/cesium/omniverse/extension.py index cc0dc0d85..4f786a7b3 100644 --- a/exts/cesium.omniverse/cesium/omniverse/extension.py +++ b/exts/cesium.omniverse/cesium/omniverse/extension.py @@ -83,10 +83,10 @@ def on_startup(self): ui.Workspace.set_show_window_fn( CesiumOmniverseAssetWindow.WINDOW_NAME, partial(self.show_assets_window, None) ) + ui.Workspace.set_show_window_fn(CesiumOmniverseDebugWindow.WINDOW_NAME, partial(self.show_debug_window, None)) ui.Workspace.set_show_window_fn( - CesiumOmniverseDebugWindow.WINDOW_NAME, partial(self.show_debug_window, None)) - ui.Workspace.set_show_window_fn( - CesiumOmniverseSettingsWindow.WINDOW_NAME, partial(self.show_settings_window, None)) + CesiumOmniverseSettingsWindow.WINDOW_NAME, partial(self.show_settings_window, None) + ) settings = omni_settings.get_settings() show_on_startup = settings.get_as_bool("/exts/cesium.omniverse/showOnStartup") diff --git a/exts/cesium.omniverse/cesium/omniverse/ui/settings_window.py b/exts/cesium.omniverse/cesium/omniverse/ui/settings_window.py index 865110995..1ea6ebb77 100644 --- a/exts/cesium.omniverse/cesium/omniverse/ui/settings_window.py +++ b/exts/cesium.omniverse/cesium/omniverse/ui/settings_window.py @@ -5,6 +5,7 @@ from ..bindings import ICesiumOmniverseInterface from cesium.omniverse.utils.custom_fields import int_field_with_label + class CesiumOmniverseSettingsWindow(ui.Window): WINDOW_NAME = "Cesium Settings" MENU_PATH = f"Window/Cesium/{WINDOW_NAME}" @@ -49,4 +50,4 @@ def clear_cache(): self._cache_items_model = ui.SimpleIntModel(cache_items) int_field_with_label("Maximum cache items", model=self._cache_items_model) ui.Button("Set cache parameters (requires restart)", height=20, clicked_fn=set_cache_parameters) - ui.Button("Clear cache", height = 20, clicked_fn=clear_cache) + ui.Button("Clear cache", height=20, clicked_fn=clear_cache) From f9e2b2310f538560aa30e4079d6c4d409339286b Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Fri, 23 Feb 2024 17:12:16 +0100 Subject: [PATCH 09/10] Python flake8 "suggestions" --- exts/cesium.omniverse/cesium/omniverse/ui/settings_window.py | 1 - 1 file changed, 1 deletion(-) diff --git a/exts/cesium.omniverse/cesium/omniverse/ui/settings_window.py b/exts/cesium.omniverse/cesium/omniverse/ui/settings_window.py index 1ea6ebb77..babab557e 100644 --- a/exts/cesium.omniverse/cesium/omniverse/ui/settings_window.py +++ b/exts/cesium.omniverse/cesium/omniverse/ui/settings_window.py @@ -45,7 +45,6 @@ def clear_cache(): self._cesium_omniverse_interface.clear_accessor_cache() with ui.VStack(spacing=4): - label_style = {"Label": {"font_size": 16}} cache_items = carb.settings.get_settings().get(self._cache_items_setting) self._cache_items_model = ui.SimpleIntModel(cache_items) int_field_with_label("Maximum cache items", model=self._cache_items_model) From ddcb84be33be51fc38f0b25c93bd3971332d4ff1 Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Fri, 23 Feb 2024 17:36:47 +0100 Subject: [PATCH 10/10] Fix Windows std::filesystem::path conversion error --- src/core/src/FilesystemUtil.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/core/src/FilesystemUtil.cpp b/src/core/src/FilesystemUtil.cpp index 59f4c4bc0..0e3db7070 100644 --- a/src/core/src/FilesystemUtil.cpp +++ b/src/core/src/FilesystemUtil.cpp @@ -32,9 +32,8 @@ std::filesystem::path getCesiumCacheDirectory() { // Should we create the directory if it doesn't exist? It's hard to believe that Omniverse // won't have already created it. } - std::string homeDir = getUserHomeDirectory(); - if (!homeDir.empty()) { - std::filesystem::path homeDirPath(homeDir); + auto homeDirPath = getUserHomeDirectory(); + if (!homeDirPath.empty()) { auto cacheDirPath = homeDirPath / ".nvidia-omniverse"; if (exists(cacheDirPath)) { return cacheDirPath;