diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index ad74adff8..dd4fbf76b 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -247,7 +247,7 @@ if(BUILD_OPENMW_VR) vrengine.cpp ) add_openmw_dir (mwvr - openxraction openxractionset openxrinput openxrmanager openxrmanagerimpl openxrswapchain openxrswapchainimpl + openxraction openxractionset openxrdebug openxrinput openxrmanager openxrmanagerimpl openxrswapchain openxrswapchainimpl realisticcombat vranimation vrenvironment vrgui vrinputmanager vrinput vrsession vrframebuffer vrshadow vrtypes vrview vrviewer ) diff --git a/apps/openmw/mwvr/openxraction.cpp b/apps/openmw/mwvr/openxraction.cpp index 430bf83b2..eb5196a3c 100644 --- a/apps/openmw/mwvr/openxraction.cpp +++ b/apps/openmw/mwvr/openxraction.cpp @@ -1,4 +1,5 @@ #include "openxraction.hpp" +#include "openxrdebug.hpp" #include "vrenvironment.hpp" #include "openxrmanagerimpl.hpp" @@ -15,6 +16,7 @@ namespace MWVR , mName(actionName) , mLocalName(localName) { + VrDebug::setName(action, "OpenMW XR Action " + actionName); }; OpenXRAction::~OpenXRAction() { diff --git a/apps/openmw/mwvr/openxractionset.cpp b/apps/openmw/mwvr/openxractionset.cpp index 7434b70c8..d2424e19a 100644 --- a/apps/openmw/mwvr/openxractionset.cpp +++ b/apps/openmw/mwvr/openxractionset.cpp @@ -1,4 +1,5 @@ #include "openxractionset.hpp" +#include "openxrdebug.hpp" #include "vrenvironment.hpp" #include "openxrmanager.hpp" @@ -128,6 +129,7 @@ namespace MWVR strcpy_s(createInfo.localizedActionSetName, localized_name.c_str()); createInfo.priority = 0; CHECK_XRCMD(xrCreateActionSet(xr->impl().xrInstance(), &createInfo, &actionSet)); + VrDebug::setName(actionSet, "OpenMW XR Action Set " + name); return actionSet; } diff --git a/apps/openmw/mwvr/openxrdebug.cpp b/apps/openmw/mwvr/openxrdebug.cpp new file mode 100644 index 000000000..ca9c5e099 --- /dev/null +++ b/apps/openmw/mwvr/openxrdebug.cpp @@ -0,0 +1,27 @@ +#include "openxrdebug.hpp" +#include "openxrmanagerimpl.hpp" +#include "vrenvironment.hpp" + +// The OpenXR SDK's platform headers assume we've included these windows headers +#include +#include + +#include +#include +#include + +void MWVR::VrDebug::setName(uint64_t handle, XrObjectType type, const std::string& name) +{ + auto& xrManager = Environment::get().getManager()->impl(); + if (xrManager.xrExtensionIsEnabled(XR_EXT_DEBUG_UTILS_EXTENSION_NAME)) + { + XrDebugUtilsObjectNameInfoEXT nameInfo{ XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, nullptr }; + nameInfo.objectHandle = handle; + nameInfo.objectType = type; + nameInfo.objectName = name.c_str(); + + static PFN_xrSetDebugUtilsObjectNameEXT setDebugUtilsObjectNameEXT + = reinterpret_cast(xrManager.xrGetFunction("xrSetDebugUtilsObjectNameEXT")); + CHECK_XRCMD(setDebugUtilsObjectNameEXT(xrManager.xrInstance(), &nameInfo)); + } +} diff --git a/apps/openmw/mwvr/openxrdebug.hpp b/apps/openmw/mwvr/openxrdebug.hpp new file mode 100644 index 000000000..c0dbba44a --- /dev/null +++ b/apps/openmw/mwvr/openxrdebug.hpp @@ -0,0 +1,73 @@ +#ifndef OPENXR_DEBUG_HPP +#define OPENXR_DEBUG_HPP + +#include + +#include + +namespace MWVR +{ + namespace VrDebug + { + //! Translates an OpenXR object to the associated XrObjectType enum value + template XrObjectType getObjectType(T t); + + //! Associates a name with an OpenXR symbol if XR_EXT_debug_utils is enabled + template void setName(T t, const std::string& name); + + //! Associates a name with an OpenXR symbol if XR_EXT_debug_utils is enabled + void setName(uint64_t handle, XrObjectType type, const std::string& name); + } +} + +template inline void MWVR::VrDebug::setName(T t, const std::string& name) +{ + setName(reinterpret_cast(t), getObjectType(t), name); +} + +template<> inline XrObjectType MWVR::VrDebug::getObjectType(XrInstance) +{ + return XR_OBJECT_TYPE_INSTANCE; +} + +template<> inline XrObjectType MWVR::VrDebug::getObjectType(XrSession) +{ + return XR_OBJECT_TYPE_SESSION; +} + +template<> inline XrObjectType MWVR::VrDebug::getObjectType(XrSpace) +{ + return XR_OBJECT_TYPE_SPACE; +} + +template<> inline XrObjectType MWVR::VrDebug::getObjectType(XrActionSet) +{ + return XR_OBJECT_TYPE_ACTION_SET; +} + +template<> inline XrObjectType MWVR::VrDebug::getObjectType(XrAction) +{ + return XR_OBJECT_TYPE_ACTION; +} + +template<> inline XrObjectType MWVR::VrDebug::getObjectType(XrDebugUtilsMessengerEXT) +{ + return XR_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT; +} + +template<> inline XrObjectType MWVR::VrDebug::getObjectType(XrSpatialAnchorMSFT) +{ + return XR_OBJECT_TYPE_SPATIAL_ANCHOR_MSFT; +} + +template<> inline XrObjectType MWVR::VrDebug::getObjectType(XrHandTrackerEXT) +{ + return XR_OBJECT_TYPE_HAND_TRACKER_EXT; +} + +template inline XrObjectType MWVR::VrDebug::getObjectType(T t) +{ + return XR_OBJECT_TYPE_UNKNOWN; +} + +#endif diff --git a/apps/openmw/mwvr/openxrmanager.cpp b/apps/openmw/mwvr/openxrmanager.cpp index cd7e8efc0..a216b8ac6 100644 --- a/apps/openmw/mwvr/openxrmanager.cpp +++ b/apps/openmw/mwvr/openxrmanager.cpp @@ -1,4 +1,5 @@ #include "openxrmanager.hpp" +#include "openxrdebug.hpp" #include "vrenvironment.hpp" #include "openxrmanagerimpl.hpp" #include "../mwinput/inputmanagerimp.hpp" diff --git a/apps/openmw/mwvr/openxrmanagerimpl.cpp b/apps/openmw/mwvr/openxrmanagerimpl.cpp index 468790d5d..0ddaede57 100644 --- a/apps/openmw/mwvr/openxrmanagerimpl.cpp +++ b/apps/openmw/mwvr/openxrmanagerimpl.cpp @@ -1,5 +1,5 @@ #include "openxrmanagerimpl.hpp" - +#include "openxrdebug.hpp" #include "openxrswapchain.hpp" #include "openxrswapchainimpl.hpp" @@ -30,7 +30,6 @@ #include #include - #define ENUM_CASE_STR(name, val) case name: return #name; #define MAKE_TO_STRING_FUNC(enumType) \ inline const char* to_string(enumType e) { \ @@ -52,13 +51,13 @@ namespace MWVR { OpenXRManagerImpl::OpenXRManagerImpl() { + logLayersAndExtensions(); setupExtensionsAndLayers(); std::vector extensions; for (auto& extension : mEnabledExtensions) extensions.push_back(extension.c_str()); - logLayersAndExtensions(); { // Create Instance XrInstanceCreateInfo createInfo{ XR_TYPE_INSTANCE_CREATE_INFO }; @@ -71,6 +70,8 @@ namespace MWVR assert(mInstance); } + setupDebugMessenger(); + { // Layer depth is enabled, cache the invariant values if (xrExtensionIsEnabled(XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME)) @@ -219,26 +220,33 @@ namespace MWVR } -#if !XR_KHR_composition_layer_depth \ - || !XR_KHR_opengl_enable \ - || !XR_EXT_hp_mixed_reality_controller - -#error "OpenXR extensions missing. Please upgrade your copy of the OpenXR SDK to 1.0.12 minimum" -#endif - - std::vector OpenXRManagerImpl::enumerateExtensions(const char* layerName) + static std::vector enumerateExtensions(const char* layerName, bool log = false, int logIndent = 2) { uint32_t extensionCount = 0; std::vector availableExtensions; - xrEnumerateInstanceExtensionProperties(nullptr, 0, &extensionCount, nullptr); + xrEnumerateInstanceExtensionProperties(layerName, 0, &extensionCount, nullptr); availableExtensions.resize(extensionCount, XrExtensionProperties{ XR_TYPE_EXTENSION_PROPERTIES }); - xrEnumerateInstanceExtensionProperties(nullptr, availableExtensions.size(), &extensionCount, availableExtensions.data()); + xrEnumerateInstanceExtensionProperties(layerName, availableExtensions.size(), &extensionCount, availableExtensions.data()); + std::vector extensionNames; + const std::string indentStr(logIndent, ' '); for (auto& extension : availableExtensions) + { extensionNames.push_back(extension.extensionName); + if (log) + Log(Debug::Verbose) << indentStr << "Name=" << extension.extensionName << " SpecVersion=" << extension.extensionVersion; + } return extensionNames; } +#if !XR_KHR_composition_layer_depth \ + || !XR_KHR_opengl_enable \ + || !XR_EXT_hp_mixed_reality_controller \ + || !XR_EXT_debug_utils + +#error "OpenXR extensions missing. Please upgrade your copy of the OpenXR SDK to 1.0.12 minimum" +#endif + void OpenXRManagerImpl::setupExtensionsAndLayers() { std::vector requiredExtensions = { @@ -250,7 +258,10 @@ namespace MWVR XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME }; - for (auto& extension : enumerateExtensions()) + if (Settings::Manager::getBool("enable XR_EXT_debug_utils", "VR")) + optionalExtensions.emplace_back(XR_EXT_DEBUG_UTILS_EXTENSION_NAME); + + for (auto& extension : enumerateExtensions(nullptr)) mAvailableExtensions.insert(extension); for (auto requiredExtension : requiredExtensions) @@ -278,55 +289,99 @@ namespace MWVR } } + static XrBool32 xrDebugCallback( + XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, + XrDebugUtilsMessageTypeFlagsEXT messageType, + const XrDebugUtilsMessengerCallbackDataEXT* callbackData, + void* userData) + { + OpenXRManagerImpl* manager = reinterpret_cast(userData); + std::string severityStr = ""; + std::string typeStr = ""; + + switch (messageSeverity) + { + case XR_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: + severityStr = "Verbose"; break; + case XR_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: + severityStr = "Info"; break; + case XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: + severityStr = "Warning"; break; + case XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: + severityStr = "Error"; break; + default: + severityStr = "Unknown"; break; + } + + switch (messageType) + { + case XR_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT: + typeStr = "General"; break; + case XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT: + typeStr = "Validation"; break; + case XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT: + typeStr = "Performance"; break; + case XR_DEBUG_UTILS_MESSAGE_TYPE_CONFORMANCE_BIT_EXT: + typeStr = "Conformance"; break; + default: + typeStr = "Unknown"; break; + } + + Log(Debug::Verbose) << "XrCallback: [" << severityStr << "][" << typeStr << "][ID=" << (callbackData->messageId ? callbackData->messageId : "null") << "]: " << callbackData->message; + + return XR_FALSE; + } + + void OpenXRManagerImpl::setupDebugMessenger(void) + { + if (xrExtensionIsEnabled(XR_EXT_DEBUG_UTILS_EXTENSION_NAME)) + { + XrDebugUtilsMessengerCreateInfoEXT createInfo{ XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, nullptr }; + + // Debug message severity levels + if (Settings::Manager::getBool("XR_EXT_debug_utils message level verbose", "VR")) + createInfo.messageSeverities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT; + if (Settings::Manager::getBool("XR_EXT_debug_utils message level info", "VR")) + createInfo.messageSeverities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; + if (Settings::Manager::getBool("XR_EXT_debug_utils message level warning", "VR")) + createInfo.messageSeverities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; + if (Settings::Manager::getBool("XR_EXT_debug_utils message level error", "VR")) + createInfo.messageSeverities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + + // Debug message types + if (Settings::Manager::getBool("XR_EXT_debug_utils message type general", "VR")) + createInfo.messageTypes |= XR_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT; + if (Settings::Manager::getBool("XR_EXT_debug_utils message type validation", "VR")) + createInfo.messageTypes |= XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; + if (Settings::Manager::getBool("XR_EXT_debug_utils message type performance", "VR")) + createInfo.messageTypes |= XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + if (Settings::Manager::getBool("XR_EXT_debug_utils message type conformance", "VR")) + createInfo.messageTypes |= XR_DEBUG_UTILS_MESSAGE_TYPE_CONFORMANCE_BIT_EXT; + + createInfo.userCallback = &xrDebugCallback; + createInfo.userData = this; + + PFN_xrCreateDebugUtilsMessengerEXT createDebugUtilsMessenger = reinterpret_cast(xrGetFunction("xrCreateDebugUtilsMessengerEXT")); + assert(createDebugUtilsMessenger); + CHECK_XRCMD(createDebugUtilsMessenger(mInstance, &createInfo, &mDebugMessenger)); + } + } + void OpenXRManagerImpl::logLayersAndExtensions() { - // Write out extension properties for a given layer. - const auto logExtensions = [](const char* layerName, int indent = 0) { - uint32_t instanceExtensionCount; - CHECK_XRCMD(xrEnumerateInstanceExtensionProperties(layerName, 0, &instanceExtensionCount, nullptr)); - - std::vector extensions(instanceExtensionCount); - for (XrExtensionProperties& extension : extensions) { - extension.type = XR_TYPE_EXTENSION_PROPERTIES; - } - - CHECK_XRCMD(xrEnumerateInstanceExtensionProperties(layerName, (uint32_t)extensions.size(), &instanceExtensionCount, - extensions.data())); - - const std::string indentStr(indent, ' '); - - std::stringstream ss; - ss << indentStr.c_str() << "Available Extensions: (" << instanceExtensionCount << ")" << std::endl; - - - for (const XrExtensionProperties& extension : extensions) { - ss << indentStr << " Name=" << std::string(extension.extensionName) << " SpecVersion=" << extension.extensionVersion << std::endl; - } - - Log(Debug::Verbose) << ss.str(); - }; - // Log layers and any of their extensions. - { - uint32_t layerCount; - CHECK_XRCMD(xrEnumerateApiLayerProperties(0, &layerCount, nullptr)); + uint32_t layerCount; + CHECK_XRCMD(xrEnumerateApiLayerProperties(0, &layerCount, nullptr)); + std::vector layers(layerCount, XrApiLayerProperties{ XR_TYPE_API_LAYER_PROPERTIES }); + CHECK_XRCMD(xrEnumerateApiLayerProperties((uint32_t)layers.size(), &layerCount, layers.data())); - std::vector layers(layerCount); - for (XrApiLayerProperties& layer : layers) { - layer.type = XR_TYPE_API_LAYER_PROPERTIES; - } + Log(Debug::Verbose) << "Available Extensions: "; + enumerateExtensions(nullptr, true, 2); + Log(Debug::Verbose) << "Available Layers: "; - CHECK_XRCMD(xrEnumerateApiLayerProperties((uint32_t)layers.size(), &layerCount, layers.data())); - - std::stringstream ss; - ss << "Available Layers: (" << layerCount << ")" << std::endl; - - for (const XrApiLayerProperties& layer : layers) { - ss << " Name=" << layer.layerName << " SpecVersion=" << layer.layerVersion << std::endl; - logExtensions(layer.layerName, 2); - } - - Log(Debug::Verbose) << ss.str(); + for (const XrApiLayerProperties& layer : layers) { + Log(Debug::Verbose) << " Name=" << layer.layerName << " SpecVersion=" << layer.layerVersion; + enumerateExtensions(layer.layerName, true, 4); } } @@ -722,6 +777,21 @@ namespace MWVR mAcquiredResources--; } + void OpenXRManagerImpl::xrUpdateNames() + { + VrDebug::setName(mInstance, "OpenMW XR Instance"); + VrDebug::setName(mSession, "OpenMW XR Session"); + VrDebug::setName(mReferenceSpaceStage, "OpenMW XR Reference Space Stage"); + VrDebug::setName(mReferenceSpaceView, "OpenMW XR Reference Space Stage"); + } + + PFN_xrVoidFunction OpenXRManagerImpl::xrGetFunction(const std::string& name) + { + PFN_xrVoidFunction function = nullptr; + xrGetInstanceProcAddr(mInstance, name.c_str(), &function); + return function; + } + bool OpenXRManagerImpl::xrSessionStopRequested() { return mSessionStopRequested; diff --git a/apps/openmw/mwvr/openxrmanagerimpl.hpp b/apps/openmw/mwvr/openxrmanagerimpl.hpp index 597dd50a0..deecd8bf8 100644 --- a/apps/openmw/mwvr/openxrmanagerimpl.hpp +++ b/apps/openmw/mwvr/openxrmanagerimpl.hpp @@ -69,11 +69,13 @@ namespace MWVR bool xrSessionCanRender(); void xrResourceAcquired(); void xrResourceReleased(); + void xrUpdateNames(); + PFN_xrVoidFunction xrGetFunction(const std::string& name); protected: - std::vector enumerateExtensions(const char* layerName = nullptr); void setupExtensionsAndLayers(); void enableExtension(const std::string& extension, bool optional); + void setupDebugMessenger(void); void logLayersAndExtensions(); void LogInstanceInfo(); void LogReferenceSpaces(); @@ -103,6 +105,7 @@ namespace MWVR XrSpace mReferenceSpaceStage = XR_NULL_HANDLE; XrFrameState mFrameState{}; XrSessionState mSessionState = XR_SESSION_STATE_UNKNOWN; + XrDebugUtilsMessengerEXT mDebugMessenger{ nullptr }; bool mSessionStopRequested = false; bool mSessionRunning = false; uint32_t mAcquiredResources = 0; diff --git a/apps/openmw/mwvr/openxrswapchainimpl.cpp b/apps/openmw/mwvr/openxrswapchainimpl.cpp index 1b2c3ce5e..6ba17078d 100644 --- a/apps/openmw/mwvr/openxrswapchainimpl.cpp +++ b/apps/openmw/mwvr/openxrswapchainimpl.cpp @@ -1,4 +1,5 @@ #include "openxrswapchainimpl.hpp" +#include "openxrdebug.hpp" #include "vrenvironment.hpp" #include "vrframebuffer.hpp" @@ -97,6 +98,7 @@ namespace MWVR { throw std::runtime_error(XrResultString(res)); continue; } + VrDebug::setName(mSwapchain, "OpenMW XR Color Swapchain " + config.name); } uint32_t imageCount = 0; @@ -118,6 +120,7 @@ namespace MWVR { auto res = xrCreateSwapchain(xr->impl().xrSession(), &swapchainCreateInfo, &mSwapchainDepth); if (!XR_SUCCEEDED(res)) throw std::runtime_error(XrResultString(res)); + VrDebug::setName(mSwapchainDepth, "OpenMW XR Depth Swapchain " + config.name); } CHECK_XRCMD(xrEnumerateSwapchainImages(mSwapchainDepth, 0, &imageCount, nullptr)); mSwapchainDepthBuffers.resize(imageCount, { XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR }); diff --git a/apps/openmw/mwvr/vrinput.cpp b/apps/openmw/mwvr/vrinput.cpp index 8fe3636fd..c2667ded6 100644 --- a/apps/openmw/mwvr/vrinput.cpp +++ b/apps/openmw/mwvr/vrinput.cpp @@ -1,4 +1,5 @@ #include "vrinput.hpp" +#include "openxrdebug.hpp" #include "vrenvironment.hpp" #include "openxrmanagerimpl.hpp" @@ -32,6 +33,7 @@ namespace MWVR createInfo.poseInActionSpace.orientation.w = 1.f; createInfo.subactionPath = XR_NULL_PATH; CHECK_XRCMD(xrCreateActionSpace(xr->impl().xrSession(), &createInfo, &mXRSpace)); + VrDebug::setName(mXRSpace, "OpenMW XR Action Space " + mXRAction->mName); } void PoseAction::update(long long time) diff --git a/apps/openmw/mwvr/vrtypes.hpp b/apps/openmw/mwvr/vrtypes.hpp index 701b7caee..c716d60c9 100644 --- a/apps/openmw/mwvr/vrtypes.hpp +++ b/apps/openmw/mwvr/vrtypes.hpp @@ -108,6 +108,7 @@ namespace MWVR int selectedWidth = -1; int selectedHeight = -1; int selectedSamples = -1; + std::string name = ""; }; struct FrameInfo diff --git a/apps/openmw/mwvr/vrviewer.cpp b/apps/openmw/mwvr/vrviewer.cpp index e42cf7527..8f204957b 100644 --- a/apps/openmw/mwvr/vrviewer.cpp +++ b/apps/openmw/mwvr/vrviewer.cpp @@ -146,6 +146,7 @@ namespace MWVR Log(Debug::Verbose) << name << " resolution: Max x=" << config[i].maxWidth << ", y=" << config[i].maxHeight; Log(Debug::Verbose) << name << " resolution: Selected x=" << config[i].selectedWidth << ", y=" << config[i].selectedHeight; + config[i].name = sViewNames[i]; auto view = new VRView(name, config[i], context->getState()); mViews[name] = view; diff --git a/files/settings-default.cfg b/files/settings-default.cfg index eb4352fb2..d2af5636d 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -944,4 +944,19 @@ log all openxr calls = false continue on errors = true # If true, movement direction is taken from the left hand tracker, instead of your head. -hand directed movement = false \ No newline at end of file +hand directed movement = false + +# If true, enable openxr debug functionality via the XR_EXT_debug_utils extension +enable XR_EXT_debug_utils = false + +# Enable/disable openxr debug message levels +XR_EXT_debug_utils message level verbose = false +XR_EXT_debug_utils message level info = true +XR_EXT_debug_utils message level warning = true +XR_EXT_debug_utils message level error = true +# Enable/disable openxr debug message types +XR_EXT_debug_utils message type general = false +XR_EXT_debug_utils message type validation = true +XR_EXT_debug_utils message type performance = true +XR_EXT_debug_utils message type conformance = true +