2020-01-09 23:10:09 +00:00
|
|
|
#include "openxrmanagerimpl.hpp"
|
2020-10-17 19:11:31 +00:00
|
|
|
#include "openxrdebug.hpp"
|
2020-06-24 20:22:09 +00:00
|
|
|
#include "openxrswapchain.hpp"
|
2020-06-24 19:26:11 +00:00
|
|
|
#include "openxrswapchainimpl.hpp"
|
2020-12-02 20:46:03 +00:00
|
|
|
#include "vrenvironment.hpp"
|
|
|
|
#include "vrinputmanager.hpp"
|
2020-01-09 23:10:09 +00:00
|
|
|
|
|
|
|
#include <components/debug/debuglog.hpp>
|
|
|
|
#include <components/sdlutil/sdlgraphicswindow.hpp>
|
2020-07-15 21:17:16 +00:00
|
|
|
#include <components/esm/loadrace.hpp>
|
|
|
|
|
2020-02-14 21:11:19 +00:00
|
|
|
#include "../mwmechanics/actorutil.hpp"
|
2020-07-15 21:17:16 +00:00
|
|
|
|
2020-02-14 21:11:19 +00:00
|
|
|
#include "../mwbase/world.hpp"
|
|
|
|
#include "../mwbase/environment.hpp"
|
2020-07-15 21:17:16 +00:00
|
|
|
|
2020-02-14 21:11:19 +00:00
|
|
|
#include "../mwworld/class.hpp"
|
|
|
|
#include "../mwworld/player.hpp"
|
|
|
|
#include "../mwworld/esmstore.hpp"
|
2020-01-09 23:10:09 +00:00
|
|
|
|
2020-10-30 23:29:24 +00:00
|
|
|
// The OpenXR SDK's platform headers assume we've included platform headers
|
|
|
|
#ifdef _WIN32
|
2020-01-09 23:10:09 +00:00
|
|
|
#include <Windows.h>
|
2020-10-17 10:33:46 +00:00
|
|
|
#include <objbase.h>
|
2020-01-09 23:10:09 +00:00
|
|
|
|
2020-10-30 23:29:24 +00:00
|
|
|
#elif __linux__
|
|
|
|
#include <X11/Xlib.h>
|
|
|
|
#include <GL/glx.h>
|
|
|
|
#undef None
|
|
|
|
|
|
|
|
#else
|
|
|
|
#error Unsupported platform
|
|
|
|
#endif
|
|
|
|
|
2020-01-09 23:10:09 +00:00
|
|
|
#include <openxr/openxr_platform.h>
|
|
|
|
#include <openxr/openxr_platform_defines.h>
|
|
|
|
#include <openxr/openxr_reflection.h>
|
|
|
|
|
|
|
|
#include <osg/Camera>
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
#include <array>
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
#define ENUM_CASE_STR(name, val) case name: return #name;
|
|
|
|
#define MAKE_TO_STRING_FUNC(enumType) \
|
|
|
|
inline const char* to_string(enumType e) { \
|
|
|
|
switch (e) { \
|
|
|
|
XR_LIST_ENUM_##enumType(ENUM_CASE_STR) \
|
|
|
|
default: return "Unknown " #enumType; \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
MAKE_TO_STRING_FUNC(XrReferenceSpaceType);
|
|
|
|
MAKE_TO_STRING_FUNC(XrViewConfigurationType);
|
|
|
|
MAKE_TO_STRING_FUNC(XrEnvironmentBlendMode);
|
|
|
|
MAKE_TO_STRING_FUNC(XrSessionState);
|
|
|
|
MAKE_TO_STRING_FUNC(XrResult);
|
|
|
|
MAKE_TO_STRING_FUNC(XrFormFactor);
|
|
|
|
MAKE_TO_STRING_FUNC(XrStructureType);
|
|
|
|
|
|
|
|
namespace MWVR
|
|
|
|
{
|
|
|
|
OpenXRManagerImpl::OpenXRManagerImpl()
|
|
|
|
{
|
2020-10-17 19:11:31 +00:00
|
|
|
logLayersAndExtensions();
|
2020-10-17 10:33:46 +00:00
|
|
|
setupExtensionsAndLayers();
|
|
|
|
|
|
|
|
std::vector<const char*> extensions;
|
|
|
|
for (auto& extension : mEnabledExtensions)
|
|
|
|
extensions.push_back(extension.c_str());
|
|
|
|
|
2020-01-09 23:10:09 +00:00
|
|
|
|
|
|
|
{ // Create Instance
|
|
|
|
XrInstanceCreateInfo createInfo{ XR_TYPE_INSTANCE_CREATE_INFO };
|
|
|
|
createInfo.next = nullptr;
|
|
|
|
createInfo.enabledExtensionCount = extensions.size();
|
|
|
|
createInfo.enabledExtensionNames = extensions.data();
|
2020-03-08 13:14:24 +00:00
|
|
|
strcpy(createInfo.applicationInfo.applicationName, "openmw_vr");
|
2020-01-09 23:10:09 +00:00
|
|
|
createInfo.applicationInfo.apiVersion = XR_CURRENT_API_VERSION;
|
2020-10-17 10:33:46 +00:00
|
|
|
CHECK_XRCMD(xrCreateInstance(&createInfo, &mInstance));
|
2020-01-09 23:10:09 +00:00
|
|
|
assert(mInstance);
|
|
|
|
}
|
|
|
|
|
2020-10-17 19:11:31 +00:00
|
|
|
setupDebugMessenger();
|
|
|
|
|
2020-07-15 21:17:16 +00:00
|
|
|
{
|
|
|
|
// Layer depth is enabled, cache the invariant values
|
|
|
|
if (xrExtensionIsEnabled(XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME))
|
|
|
|
{
|
|
|
|
GLfloat depthRange[2] = { 0.f, 1.f };
|
|
|
|
glGetFloatv(GL_DEPTH_RANGE, depthRange);
|
|
|
|
auto nearClip = Settings::Manager::getFloat("near clip", "Camera");
|
|
|
|
|
|
|
|
for (auto& layer : mLayerDepth)
|
|
|
|
{
|
|
|
|
layer.type = XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR;
|
|
|
|
layer.next = nullptr;
|
|
|
|
layer.minDepth = depthRange[0];
|
|
|
|
layer.maxDepth = depthRange[1];
|
|
|
|
layer.nearZ = nearClip;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-09 23:10:09 +00:00
|
|
|
{ // Get system ID
|
|
|
|
XrSystemGetInfo systemInfo{ XR_TYPE_SYSTEM_GET_INFO };
|
|
|
|
systemInfo.formFactor = mFormFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
|
|
|
|
CHECK_XRCMD(xrGetSystem(mInstance, &systemInfo, &mSystemId));
|
|
|
|
assert(mSystemId);
|
|
|
|
}
|
|
|
|
|
|
|
|
{ // Initialize OpenGL device
|
2020-06-21 21:40:07 +00:00
|
|
|
// Despite its name, xrGetOpenGLGraphicsRequirementsKHR is a required function call that sets up an opengl instance.
|
2020-01-09 23:10:09 +00:00
|
|
|
PFN_xrGetOpenGLGraphicsRequirementsKHR p_getRequirements = nullptr;
|
|
|
|
xrGetInstanceProcAddr(mInstance, "xrGetOpenGLGraphicsRequirementsKHR", reinterpret_cast<PFN_xrVoidFunction*>(&p_getRequirements));
|
|
|
|
XrGraphicsRequirementsOpenGLKHR requirements{ XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR };
|
|
|
|
CHECK_XRCMD(p_getRequirements(mInstance, mSystemId, &requirements));
|
|
|
|
|
|
|
|
const XrVersion desiredApiVersion = XR_MAKE_VERSION(4, 6, 0);
|
|
|
|
if (requirements.minApiVersionSupported > desiredApiVersion) {
|
|
|
|
std::cout << "Runtime does not support desired Graphics API and/or version" << std::endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-30 23:29:24 +00:00
|
|
|
#ifdef _WIN32
|
2020-01-09 23:10:09 +00:00
|
|
|
{ // Create Session
|
2020-06-02 19:46:22 +00:00
|
|
|
auto DC = wglGetCurrentDC();
|
|
|
|
auto GLRC = wglGetCurrentContext();
|
|
|
|
auto XRGLRC = wglCreateContext(DC);
|
|
|
|
wglShareLists(GLRC, XRGLRC);
|
2020-10-17 10:33:46 +00:00
|
|
|
|
|
|
|
XrGraphicsBindingOpenGLWin32KHR graphicsBindings;
|
|
|
|
graphicsBindings.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR;
|
|
|
|
graphicsBindings.next = nullptr;
|
|
|
|
graphicsBindings.hDC = DC;
|
|
|
|
graphicsBindings.hGLRC = XRGLRC;
|
|
|
|
|
|
|
|
if (!graphicsBindings.hDC)
|
2020-08-02 10:34:46 +00:00
|
|
|
Log(Debug::Warning) << "Missing DC";
|
2020-01-09 23:10:09 +00:00
|
|
|
|
|
|
|
XrSessionCreateInfo createInfo{ XR_TYPE_SESSION_CREATE_INFO };
|
2020-10-17 10:33:46 +00:00
|
|
|
createInfo.next = &graphicsBindings;
|
2020-01-09 23:10:09 +00:00
|
|
|
createInfo.systemId = mSystemId;
|
|
|
|
CHECK_XRCMD(xrCreateSession(mInstance, &createInfo, &mSession));
|
|
|
|
assert(mSession);
|
|
|
|
}
|
2020-10-30 23:29:24 +00:00
|
|
|
#elif __linux__
|
|
|
|
{ // Create Session
|
|
|
|
Display* xDisplay = XOpenDisplay(NULL);
|
|
|
|
GLXContext glxContext = glXGetCurrentContext();
|
|
|
|
GLXDrawable glxDrawable = glXGetCurrentDrawable();
|
|
|
|
|
|
|
|
// TODO: runtimes don't actually care (yet)
|
|
|
|
GLXFBConfig glxFBConfig = 0;
|
|
|
|
uint32_t visualid = 0;
|
|
|
|
|
|
|
|
XrGraphicsBindingOpenGLXlibKHR graphicsBindings;
|
|
|
|
graphicsBindings.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR;
|
|
|
|
graphicsBindings.next = nullptr;
|
|
|
|
graphicsBindings.xDisplay = xDisplay;
|
|
|
|
graphicsBindings.glxContext = glxContext;
|
|
|
|
graphicsBindings.glxDrawable = glxDrawable;
|
|
|
|
graphicsBindings.glxFBConfig = glxFBConfig;
|
|
|
|
graphicsBindings.visualid = visualid;
|
|
|
|
|
|
|
|
if (!graphicsBindings.glxContext)
|
|
|
|
Log(Debug::Warning) << "Missing glxContext";
|
|
|
|
|
|
|
|
if (!graphicsBindings.glxDrawable)
|
|
|
|
Log(Debug::Warning) << "Missing glxDrawable";
|
|
|
|
|
|
|
|
XrSessionCreateInfo createInfo{ XR_TYPE_SESSION_CREATE_INFO };
|
|
|
|
createInfo.next = &graphicsBindings;
|
|
|
|
createInfo.systemId = mSystemId;
|
|
|
|
CHECK_XRCMD(xrCreateSession(mInstance, &createInfo, &mSession));
|
|
|
|
assert(mSession);
|
|
|
|
}
|
|
|
|
#endif
|
2020-01-09 23:10:09 +00:00
|
|
|
|
|
|
|
LogInstanceInfo();
|
|
|
|
LogReferenceSpaces();
|
2020-08-02 10:34:46 +00:00
|
|
|
LogSwapchainFormats();
|
2020-01-09 23:10:09 +00:00
|
|
|
|
|
|
|
{ // Set up reference space
|
|
|
|
XrReferenceSpaceCreateInfo createInfo{ XR_TYPE_REFERENCE_SPACE_CREATE_INFO };
|
|
|
|
createInfo.poseInReferenceSpace.orientation.w = 1.f; // Identity pose
|
|
|
|
createInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_VIEW;
|
|
|
|
CHECK_XRCMD(xrCreateReferenceSpace(mSession, &createInfo, &mReferenceSpaceView));
|
|
|
|
createInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_STAGE;
|
|
|
|
CHECK_XRCMD(xrCreateReferenceSpace(mSession, &createInfo, &mReferenceSpaceStage));
|
|
|
|
}
|
|
|
|
|
|
|
|
{ // Read and log graphics properties for the swapchain
|
|
|
|
xrGetSystemProperties(mInstance, mSystemId, &mSystemProperties);
|
|
|
|
|
|
|
|
// Log system properties.
|
|
|
|
{
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << "System Properties: Name=" << mSystemProperties.systemName << " VendorId=" << mSystemProperties.vendorId << std::endl;
|
|
|
|
ss << "System Graphics Properties: MaxWidth=" << mSystemProperties.graphicsProperties.maxSwapchainImageWidth;
|
|
|
|
ss << " MaxHeight=" << mSystemProperties.graphicsProperties.maxSwapchainImageHeight;
|
|
|
|
ss << " MaxLayers=" << mSystemProperties.graphicsProperties.maxLayerCount << std::endl;
|
|
|
|
ss << "System Tracking Properties: OrientationTracking=" << mSystemProperties.trackingProperties.orientationTracking ? "True" : "False";
|
|
|
|
ss << " PositionTracking=" << mSystemProperties.trackingProperties.positionTracking ? "True" : "False";
|
|
|
|
Log(Debug::Verbose) << ss.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t viewCount = 0;
|
|
|
|
CHECK_XRCMD(xrEnumerateViewConfigurationViews(mInstance, mSystemId, mViewConfigType, 2, &viewCount, mConfigViews.data()));
|
2020-01-26 19:06:47 +00:00
|
|
|
|
2020-01-09 23:10:09 +00:00
|
|
|
if (viewCount != 2)
|
|
|
|
{
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << "xrEnumerateViewConfigurationViews returned " << viewCount << " views";
|
|
|
|
Log(Debug::Verbose) << ss.str();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-01 23:23:48 +00:00
|
|
|
XrResult CheckXrResult(XrResult res, const char* originator, const char* sourceLocation) {
|
2020-08-02 10:34:46 +00:00
|
|
|
static bool initialized = false;
|
|
|
|
static bool sLogAllXrCalls = false;
|
|
|
|
static bool sContinueOnErrors = false;
|
|
|
|
if (!initialized)
|
|
|
|
{
|
|
|
|
initialized = true;
|
2020-10-19 16:21:05 +00:00
|
|
|
sLogAllXrCalls = Settings::Manager::getBool("log all openxr calls", "VR Debug");
|
|
|
|
sContinueOnErrors = Settings::Manager::getBool("continue on errors", "VR Debug");
|
2020-08-02 10:34:46 +00:00
|
|
|
}
|
|
|
|
|
2020-01-09 23:10:09 +00:00
|
|
|
if (XR_FAILED(res)) {
|
2020-01-26 19:06:47 +00:00
|
|
|
std::stringstream ss;
|
2020-10-30 23:29:24 +00:00
|
|
|
#ifdef _WIN32
|
2020-07-21 10:28:39 +00:00
|
|
|
ss << sourceLocation << ": OpenXR[Error: " << to_string(res) << "][Thread: " << std::this_thread::get_id() << "][DC: " << wglGetCurrentDC() << "][GLRC: " << wglGetCurrentContext() << "]: " << originator;
|
2020-10-30 23:29:24 +00:00
|
|
|
#elif __linux__
|
|
|
|
ss << sourceLocation << ": OpenXR[Error: " << to_string(res) << "][Thread: " << std::this_thread::get_id() << "][glxContext: " << glXGetCurrentContext() << "][glxDrawable: " << glXGetCurrentDrawable() << "]: " << originator;
|
|
|
|
#endif
|
2020-01-26 19:06:47 +00:00
|
|
|
Log(Debug::Error) << ss.str();
|
2020-08-02 10:34:46 +00:00
|
|
|
if (res == XR_ERROR_TIME_INVALID)
|
|
|
|
Log(Debug::Error) << "Breakpoint";
|
|
|
|
if (!sContinueOnErrors)
|
|
|
|
throw std::runtime_error(ss.str().c_str());
|
2020-01-09 23:10:09 +00:00
|
|
|
}
|
2020-08-02 10:34:46 +00:00
|
|
|
else if (res != XR_SUCCESS || sLogAllXrCalls)
|
2020-01-09 23:10:09 +00:00
|
|
|
{
|
2020-10-30 23:29:24 +00:00
|
|
|
#ifdef _WIN32
|
2020-08-02 10:34:46 +00:00
|
|
|
Log(Debug::Verbose) << sourceLocation << ": OpenXR[" << to_string(res) << "][" << std::this_thread::get_id() << "][" << wglGetCurrentDC() << "][" << wglGetCurrentContext() << "]: " << originator;
|
2020-10-30 23:29:24 +00:00
|
|
|
#elif __linux__
|
|
|
|
Log(Debug::Verbose) << sourceLocation << ": OpenXR[" << to_string(res) << "][" << std::this_thread::get_id() << "][" << glXGetCurrentContext() << "][" << glXGetCurrentDrawable() << "]: " << originator;
|
|
|
|
#endif
|
2020-01-09 23:10:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2020-06-24 19:26:11 +00:00
|
|
|
std::string XrResultString(XrResult res)
|
|
|
|
{
|
|
|
|
return to_string(res);
|
|
|
|
}
|
|
|
|
|
2020-01-09 23:10:09 +00:00
|
|
|
OpenXRManagerImpl::~OpenXRManagerImpl()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-10-17 19:11:31 +00:00
|
|
|
static std::vector<std::string> enumerateExtensions(const char* layerName, bool log = false, int logIndent = 2)
|
2020-10-17 10:33:46 +00:00
|
|
|
{
|
|
|
|
uint32_t extensionCount = 0;
|
|
|
|
std::vector<XrExtensionProperties> availableExtensions;
|
2020-10-17 19:11:31 +00:00
|
|
|
xrEnumerateInstanceExtensionProperties(layerName, 0, &extensionCount, nullptr);
|
2020-10-17 10:33:46 +00:00
|
|
|
availableExtensions.resize(extensionCount, XrExtensionProperties{ XR_TYPE_EXTENSION_PROPERTIES });
|
2020-10-17 19:11:31 +00:00
|
|
|
xrEnumerateInstanceExtensionProperties(layerName, availableExtensions.size(), &extensionCount, availableExtensions.data());
|
|
|
|
|
2020-10-17 10:33:46 +00:00
|
|
|
std::vector<std::string> extensionNames;
|
2020-10-17 19:11:31 +00:00
|
|
|
const std::string indentStr(logIndent, ' ');
|
2020-10-17 10:33:46 +00:00
|
|
|
for (auto& extension : availableExtensions)
|
2020-10-17 19:11:31 +00:00
|
|
|
{
|
2020-10-17 10:33:46 +00:00
|
|
|
extensionNames.push_back(extension.extensionName);
|
2020-10-17 19:11:31 +00:00
|
|
|
if (log)
|
|
|
|
Log(Debug::Verbose) << indentStr << "Name=" << extension.extensionName << " SpecVersion=" << extension.extensionVersion;
|
|
|
|
}
|
2020-10-17 10:33:46 +00:00
|
|
|
return extensionNames;
|
|
|
|
}
|
|
|
|
|
2020-10-17 19:11:31 +00:00
|
|
|
#if !XR_KHR_composition_layer_depth \
|
|
|
|
|| !XR_KHR_opengl_enable \
|
|
|
|
|| !XR_EXT_hp_mixed_reality_controller \
|
2020-11-29 16:15:53 +00:00
|
|
|
|| !XR_EXT_debug_utils \
|
|
|
|
|| !XR_HTC_vive_cosmos_controller_interaction \
|
|
|
|
|| !XR_HUAWEI_controller_interaction
|
2020-10-17 19:11:31 +00:00
|
|
|
|
2020-11-29 16:15:53 +00:00
|
|
|
#error "OpenXR extensions missing. Please upgrade your copy of the OpenXR SDK to 1.0.13 minimum"
|
2020-10-17 19:11:31 +00:00
|
|
|
#endif
|
|
|
|
|
2020-10-17 10:33:46 +00:00
|
|
|
void OpenXRManagerImpl::setupExtensionsAndLayers()
|
|
|
|
{
|
|
|
|
std::vector<const char*> requiredExtensions = {
|
|
|
|
XR_KHR_OPENGL_ENABLE_EXTENSION_NAME,
|
|
|
|
};
|
|
|
|
|
|
|
|
std::vector<const char*> optionalExtensions = {
|
|
|
|
XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME,
|
2020-11-29 16:15:53 +00:00
|
|
|
XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME,
|
|
|
|
XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME,
|
|
|
|
XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME
|
2020-10-17 10:33:46 +00:00
|
|
|
};
|
|
|
|
|
2020-10-19 16:21:05 +00:00
|
|
|
if (Settings::Manager::getBool("enable XR_EXT_debug_utils", "VR Debug"))
|
2020-10-17 19:11:31 +00:00
|
|
|
optionalExtensions.emplace_back(XR_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
|
|
|
|
|
|
|
for (auto& extension : enumerateExtensions(nullptr))
|
2020-10-17 10:33:46 +00:00
|
|
|
mAvailableExtensions.insert(extension);
|
|
|
|
|
2020-11-01 16:49:46 +00:00
|
|
|
Log(Debug::Verbose) << "Using extensions:";
|
|
|
|
|
2020-10-17 10:33:46 +00:00
|
|
|
for (auto requiredExtension : requiredExtensions)
|
|
|
|
enableExtension(requiredExtension, false);
|
|
|
|
|
|
|
|
for (auto optionalExtension : optionalExtensions)
|
|
|
|
enableExtension(optionalExtension, true);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenXRManagerImpl::enableExtension(const std::string& extension, bool optional)
|
|
|
|
{
|
|
|
|
if (mAvailableExtensions.count(extension) > 0)
|
|
|
|
{
|
|
|
|
Log(Debug::Verbose) << " " << extension << ": enabled";
|
|
|
|
mEnabledExtensions.insert(extension);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Log(Debug::Verbose) << " " << extension << ": disabled (not supported)";
|
|
|
|
if (!optional)
|
|
|
|
{
|
|
|
|
throw std::runtime_error(std::string("Required OpenXR extension ") + extension + " not supported by the runtime");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-01-09 23:10:09 +00:00
|
|
|
|
2020-10-17 19:11:31 +00:00
|
|
|
static XrBool32 xrDebugCallback(
|
|
|
|
XrDebugUtilsMessageSeverityFlagsEXT messageSeverity,
|
|
|
|
XrDebugUtilsMessageTypeFlagsEXT messageType,
|
|
|
|
const XrDebugUtilsMessengerCallbackDataEXT* callbackData,
|
|
|
|
void* userData)
|
|
|
|
{
|
|
|
|
OpenXRManagerImpl* manager = reinterpret_cast<OpenXRManagerImpl*>(userData);
|
2020-11-29 18:02:06 +00:00
|
|
|
(void)manager;
|
2020-10-17 19:11:31 +00:00
|
|
|
std::string severityStr = "";
|
|
|
|
std::string typeStr = "";
|
2020-01-09 23:10:09 +00:00
|
|
|
|
2020-10-17 19:11:31 +00:00
|
|
|
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;
|
|
|
|
}
|
2020-01-09 23:10:09 +00:00
|
|
|
|
2020-10-17 19:11:31 +00:00
|
|
|
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;
|
|
|
|
}
|
2020-01-09 23:10:09 +00:00
|
|
|
|
2020-10-17 19:11:31 +00:00
|
|
|
Log(Debug::Verbose) << "XrCallback: [" << severityStr << "][" << typeStr << "][ID=" << (callbackData->messageId ? callbackData->messageId : "null") << "]: " << callbackData->message;
|
2020-01-09 23:10:09 +00:00
|
|
|
|
2020-10-17 19:11:31 +00:00
|
|
|
return XR_FALSE;
|
|
|
|
}
|
2020-01-09 23:10:09 +00:00
|
|
|
|
2020-10-17 19:11:31 +00:00
|
|
|
void OpenXRManagerImpl::setupDebugMessenger(void)
|
|
|
|
{
|
|
|
|
if (xrExtensionIsEnabled(XR_EXT_DEBUG_UTILS_EXTENSION_NAME))
|
|
|
|
{
|
|
|
|
XrDebugUtilsMessengerCreateInfoEXT createInfo{ XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, nullptr };
|
2020-01-09 23:10:09 +00:00
|
|
|
|
2020-10-17 19:11:31 +00:00
|
|
|
// Debug message severity levels
|
2020-10-19 16:21:05 +00:00
|
|
|
if (Settings::Manager::getBool("XR_EXT_debug_utils message level verbose", "VR Debug"))
|
2020-10-17 19:11:31 +00:00
|
|
|
createInfo.messageSeverities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
|
2020-10-19 16:21:05 +00:00
|
|
|
if (Settings::Manager::getBool("XR_EXT_debug_utils message level info", "VR Debug"))
|
2020-10-17 19:11:31 +00:00
|
|
|
createInfo.messageSeverities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
|
2020-10-19 16:21:05 +00:00
|
|
|
if (Settings::Manager::getBool("XR_EXT_debug_utils message level warning", "VR Debug"))
|
2020-10-17 19:11:31 +00:00
|
|
|
createInfo.messageSeverities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
|
2020-10-19 16:21:05 +00:00
|
|
|
if (Settings::Manager::getBool("XR_EXT_debug_utils message level error", "VR Debug"))
|
2020-10-17 19:11:31 +00:00
|
|
|
createInfo.messageSeverities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
|
2020-01-09 23:10:09 +00:00
|
|
|
|
2020-10-17 19:11:31 +00:00
|
|
|
// Debug message types
|
2020-10-19 16:21:05 +00:00
|
|
|
if (Settings::Manager::getBool("XR_EXT_debug_utils message type general", "VR Debug"))
|
2020-10-17 19:11:31 +00:00
|
|
|
createInfo.messageTypes |= XR_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
|
2020-10-19 16:21:05 +00:00
|
|
|
if (Settings::Manager::getBool("XR_EXT_debug_utils message type validation", "VR Debug"))
|
2020-10-17 19:11:31 +00:00
|
|
|
createInfo.messageTypes |= XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
|
2020-10-19 16:21:05 +00:00
|
|
|
if (Settings::Manager::getBool("XR_EXT_debug_utils message type performance", "VR Debug"))
|
2020-10-17 19:11:31 +00:00
|
|
|
createInfo.messageTypes |= XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
2020-10-19 16:21:05 +00:00
|
|
|
if (Settings::Manager::getBool("XR_EXT_debug_utils message type conformance", "VR Debug"))
|
2020-10-17 19:11:31 +00:00
|
|
|
createInfo.messageTypes |= XR_DEBUG_UTILS_MESSAGE_TYPE_CONFORMANCE_BIT_EXT;
|
2020-01-09 23:10:09 +00:00
|
|
|
|
2020-10-17 19:11:31 +00:00
|
|
|
createInfo.userCallback = &xrDebugCallback;
|
|
|
|
createInfo.userData = this;
|
2020-01-09 23:10:09 +00:00
|
|
|
|
2020-10-17 19:11:31 +00:00
|
|
|
PFN_xrCreateDebugUtilsMessengerEXT createDebugUtilsMessenger = reinterpret_cast<PFN_xrCreateDebugUtilsMessengerEXT>(xrGetFunction("xrCreateDebugUtilsMessengerEXT"));
|
|
|
|
assert(createDebugUtilsMessenger);
|
|
|
|
CHECK_XRCMD(createDebugUtilsMessenger(mInstance, &createInfo, &mDebugMessenger));
|
|
|
|
}
|
|
|
|
}
|
2020-01-09 23:10:09 +00:00
|
|
|
|
2020-10-17 19:11:31 +00:00
|
|
|
void
|
|
|
|
OpenXRManagerImpl::logLayersAndExtensions() {
|
|
|
|
// Log layers and any of their extensions.
|
|
|
|
uint32_t layerCount;
|
|
|
|
CHECK_XRCMD(xrEnumerateApiLayerProperties(0, &layerCount, nullptr));
|
|
|
|
std::vector<XrApiLayerProperties> layers(layerCount, XrApiLayerProperties{ XR_TYPE_API_LAYER_PROPERTIES });
|
|
|
|
CHECK_XRCMD(xrEnumerateApiLayerProperties((uint32_t)layers.size(), &layerCount, layers.data()));
|
2020-01-09 23:10:09 +00:00
|
|
|
|
2020-10-17 19:11:31 +00:00
|
|
|
Log(Debug::Verbose) << "Available Extensions: ";
|
|
|
|
enumerateExtensions(nullptr, true, 2);
|
|
|
|
Log(Debug::Verbose) << "Available Layers: ";
|
2020-01-09 23:10:09 +00:00
|
|
|
|
2020-11-01 16:49:46 +00:00
|
|
|
if (layers.size() == 0)
|
|
|
|
{
|
|
|
|
Log(Debug::Verbose) << " No layers available";
|
|
|
|
}
|
2020-10-17 19:11:31 +00:00
|
|
|
for (const XrApiLayerProperties& layer : layers) {
|
|
|
|
Log(Debug::Verbose) << " Name=" << layer.layerName << " SpecVersion=" << layer.layerVersion;
|
|
|
|
enumerateExtensions(layer.layerName, true, 4);
|
2020-01-09 23:10:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
OpenXRManagerImpl::LogInstanceInfo() {
|
|
|
|
|
|
|
|
XrInstanceProperties instanceProperties{ XR_TYPE_INSTANCE_PROPERTIES };
|
|
|
|
xrGetInstanceProperties(mInstance, &instanceProperties);
|
2020-06-21 21:40:07 +00:00
|
|
|
Log(Debug::Verbose) << "Instance RuntimeName=" << instanceProperties.runtimeName << " RuntimeVersion=" << instanceProperties.runtimeVersion;
|
2020-01-09 23:10:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
OpenXRManagerImpl::LogReferenceSpaces() {
|
|
|
|
|
|
|
|
uint32_t spaceCount;
|
|
|
|
xrEnumerateReferenceSpaces(mSession, 0, &spaceCount, nullptr);
|
|
|
|
std::vector<XrReferenceSpaceType> spaces(spaceCount);
|
|
|
|
xrEnumerateReferenceSpaces(mSession, spaceCount, &spaceCount, spaces.data());
|
|
|
|
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << "Available reference spaces=" << spaceCount << std::endl;
|
|
|
|
|
|
|
|
for (XrReferenceSpaceType space : spaces)
|
|
|
|
ss << " Name: " << to_string(space) << std::endl;
|
|
|
|
Log(Debug::Verbose) << ss.str();
|
|
|
|
}
|
|
|
|
|
2020-08-02 10:34:46 +00:00
|
|
|
void OpenXRManagerImpl::LogSwapchainFormats()
|
|
|
|
{
|
|
|
|
uint32_t swapchainFormatCount;
|
|
|
|
CHECK_XRCMD(xrEnumerateSwapchainFormats(xrSession(), 0, &swapchainFormatCount, nullptr));
|
|
|
|
std::vector<int64_t> swapchainFormats(swapchainFormatCount);
|
|
|
|
CHECK_XRCMD(xrEnumerateSwapchainFormats(xrSession(), (uint32_t)swapchainFormats.size(), &swapchainFormatCount, swapchainFormats.data()));
|
|
|
|
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << "Available Swapchain formats: (" << swapchainFormatCount << ")" << std::endl;
|
|
|
|
|
|
|
|
for (auto format : swapchainFormats)
|
|
|
|
{
|
2020-08-07 21:33:21 +00:00
|
|
|
ss << " Enum=" << std::dec << format << " (0x=" << std::hex << format << ")" << std::dec << std::endl;
|
2020-08-02 10:34:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Log(Debug::Verbose) << ss.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
FrameInfo
|
2020-01-09 23:10:09 +00:00
|
|
|
OpenXRManagerImpl::waitFrame()
|
|
|
|
{
|
2020-02-02 12:12:53 +00:00
|
|
|
XrFrameWaitInfo frameWaitInfo{ XR_TYPE_FRAME_WAIT_INFO };
|
|
|
|
XrFrameState frameState{ XR_TYPE_FRAME_STATE };
|
2020-01-23 23:14:23 +00:00
|
|
|
|
2020-02-02 12:12:53 +00:00
|
|
|
CHECK_XRCMD(xrWaitFrame(mSession, &frameWaitInfo, &frameState));
|
|
|
|
mFrameState = frameState;
|
2020-08-02 10:34:46 +00:00
|
|
|
|
|
|
|
FrameInfo frameInfo;
|
|
|
|
|
|
|
|
frameInfo.runtimePredictedDisplayTime = mFrameState.predictedDisplayTime;
|
|
|
|
frameInfo.runtimePredictedDisplayPeriod = mFrameState.predictedDisplayPeriod;
|
|
|
|
frameInfo.runtimeRequestsRender = !!mFrameState.shouldRender;
|
|
|
|
|
|
|
|
return frameInfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void clearGlErrors()
|
|
|
|
{
|
|
|
|
auto error = glGetError();
|
|
|
|
while (error != GL_NO_ERROR)
|
|
|
|
{
|
2020-08-07 21:33:21 +00:00
|
|
|
Log(Debug::Warning) << "glGetError: " << std::dec << error << " (0x" << std::hex << error << ")" << std::dec;
|
2020-08-02 10:34:46 +00:00
|
|
|
}
|
2020-01-23 23:14:23 +00:00
|
|
|
}
|
|
|
|
|
2020-01-26 19:06:47 +00:00
|
|
|
void
|
|
|
|
OpenXRManagerImpl::beginFrame()
|
2020-01-23 23:14:23 +00:00
|
|
|
{
|
2020-01-26 19:06:47 +00:00
|
|
|
XrFrameBeginInfo frameBeginInfo{ XR_TYPE_FRAME_BEGIN_INFO };
|
|
|
|
CHECK_XRCMD(xrBeginFrame(mSession, &frameBeginInfo));
|
2020-01-09 23:10:09 +00:00
|
|
|
}
|
|
|
|
|
2020-06-21 21:40:07 +00:00
|
|
|
XrCompositionLayerProjectionView toXR(MWVR::CompositionLayerProjectionView layer)
|
|
|
|
{
|
|
|
|
XrCompositionLayerProjectionView xrLayer;
|
|
|
|
xrLayer.type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW;
|
2020-06-24 19:26:11 +00:00
|
|
|
xrLayer.subImage = layer.swapchain->impl().xrSubImage();
|
2020-06-21 21:40:07 +00:00
|
|
|
xrLayer.pose = toXR(layer.pose);
|
|
|
|
xrLayer.fov = toXR(layer.fov);
|
|
|
|
xrLayer.next = nullptr;
|
2020-06-26 21:02:48 +00:00
|
|
|
|
2020-06-21 21:40:07 +00:00
|
|
|
return xrLayer;
|
|
|
|
}
|
|
|
|
|
2020-01-09 23:10:09 +00:00
|
|
|
void
|
2020-10-18 12:22:03 +00:00
|
|
|
OpenXRManagerImpl::endFrame(FrameInfo frameInfo, const std::array<CompositionLayerProjectionView, 2>* layerStack)
|
|
|
|
{
|
2020-07-15 21:17:16 +00:00
|
|
|
|
2020-01-09 23:10:09 +00:00
|
|
|
XrFrameEndInfo frameEndInfo{ XR_TYPE_FRAME_END_INFO };
|
2020-08-02 10:34:46 +00:00
|
|
|
frameEndInfo.displayTime = frameInfo.runtimePredictedDisplayTime;
|
2020-01-09 23:10:09 +00:00
|
|
|
frameEndInfo.environmentBlendMode = mEnvironmentBlendMode;
|
2020-10-18 12:22:03 +00:00
|
|
|
if (layerStack)
|
2020-08-02 10:34:46 +00:00
|
|
|
{
|
2020-10-18 12:22:03 +00:00
|
|
|
std::array<XrCompositionLayerProjectionView, 2> compositionLayerProjectionViews{};
|
|
|
|
compositionLayerProjectionViews[(int)Side::LEFT_SIDE] = toXR((*layerStack)[(int)Side::LEFT_SIDE]);
|
|
|
|
compositionLayerProjectionViews[(int)Side::RIGHT_SIDE] = toXR((*layerStack)[(int)Side::RIGHT_SIDE]);
|
|
|
|
XrCompositionLayerProjection layer{};
|
|
|
|
layer.type = XR_TYPE_COMPOSITION_LAYER_PROJECTION;
|
|
|
|
layer.space = getReferenceSpace(ReferenceSpace::STAGE);
|
|
|
|
layer.viewCount = 2;
|
|
|
|
layer.views = compositionLayerProjectionViews.data();
|
|
|
|
auto* xrLayerStack = reinterpret_cast<XrCompositionLayerBaseHeader*>(&layer);
|
|
|
|
|
|
|
|
std::array<XrCompositionLayerDepthInfoKHR, 2> compositionLayerDepth = mLayerDepth;
|
|
|
|
if (xrExtensionIsEnabled(XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME))
|
|
|
|
{
|
|
|
|
auto farClip = Settings::Manager::getFloat("viewing distance", "Camera");
|
|
|
|
// All values not set here are set previously as they are constant
|
|
|
|
compositionLayerDepth[(int)Side::LEFT_SIDE].farZ = farClip;
|
|
|
|
compositionLayerDepth[(int)Side::RIGHT_SIDE].farZ = farClip;
|
|
|
|
compositionLayerDepth[(int)Side::LEFT_SIDE].subImage = (*layerStack)[(int)Side::LEFT_SIDE].swapchain->impl().xrSubImageDepth();
|
|
|
|
compositionLayerDepth[(int)Side::RIGHT_SIDE].subImage = (*layerStack)[(int)Side::RIGHT_SIDE].swapchain->impl().xrSubImageDepth();
|
|
|
|
if (compositionLayerDepth[(int)Side::LEFT_SIDE].subImage.swapchain != XR_NULL_HANDLE
|
|
|
|
&& compositionLayerDepth[(int)Side::RIGHT_SIDE].subImage.swapchain != XR_NULL_HANDLE)
|
|
|
|
{
|
|
|
|
compositionLayerProjectionViews[(int)Side::LEFT_SIDE].next = &compositionLayerDepth[(int)Side::LEFT_SIDE];
|
|
|
|
compositionLayerProjectionViews[(int)Side::RIGHT_SIDE].next = &compositionLayerDepth[(int)Side::RIGHT_SIDE];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
frameEndInfo.layerCount = 1;
|
2020-08-02 10:34:46 +00:00
|
|
|
frameEndInfo.layers = &xrLayerStack;
|
|
|
|
}
|
2020-01-09 23:10:09 +00:00
|
|
|
CHECK_XRCMD(xrEndFrame(mSession, &frameEndInfo));
|
|
|
|
}
|
|
|
|
|
2020-06-26 21:02:48 +00:00
|
|
|
std::array<View, 2>
|
2020-01-26 19:06:47 +00:00
|
|
|
OpenXRManagerImpl::getPredictedViews(
|
2020-02-02 12:12:53 +00:00
|
|
|
int64_t predictedDisplayTime,
|
2020-06-24 19:26:11 +00:00
|
|
|
ReferenceSpace space)
|
2020-01-09 23:10:09 +00:00
|
|
|
{
|
2020-06-02 19:46:22 +00:00
|
|
|
if (!mPredictionsEnabled)
|
|
|
|
{
|
|
|
|
Log(Debug::Error) << "Prediction out of order";
|
|
|
|
throw std::logic_error("Prediction out of order");
|
|
|
|
}
|
2020-06-21 21:40:07 +00:00
|
|
|
std::array<XrView, 2> xrViews{ {{XR_TYPE_VIEW}, {XR_TYPE_VIEW}} };
|
2020-01-09 23:10:09 +00:00
|
|
|
XrViewState viewState{ XR_TYPE_VIEW_STATE };
|
|
|
|
uint32_t viewCount = 2;
|
|
|
|
|
|
|
|
XrViewLocateInfo viewLocateInfo{ XR_TYPE_VIEW_LOCATE_INFO };
|
|
|
|
viewLocateInfo.viewConfigurationType = mViewConfigType;
|
2020-02-02 12:12:53 +00:00
|
|
|
viewLocateInfo.displayTime = predictedDisplayTime;
|
2020-01-26 19:06:47 +00:00
|
|
|
switch (space)
|
|
|
|
{
|
2020-06-24 19:26:11 +00:00
|
|
|
case ReferenceSpace::STAGE:
|
2020-01-26 19:06:47 +00:00
|
|
|
viewLocateInfo.space = mReferenceSpaceStage;
|
|
|
|
break;
|
2020-06-24 19:26:11 +00:00
|
|
|
case ReferenceSpace::VIEW:
|
2020-01-26 19:06:47 +00:00
|
|
|
viewLocateInfo.space = mReferenceSpaceView;
|
|
|
|
break;
|
|
|
|
}
|
2020-06-21 21:40:07 +00:00
|
|
|
CHECK_XRCMD(xrLocateViews(mSession, &viewLocateInfo, &viewState, viewCount, &viewCount, xrViews.data()));
|
|
|
|
|
|
|
|
std::array<View, 2> vrViews{};
|
|
|
|
vrViews[(int)Side::LEFT_SIDE].pose = fromXR(xrViews[(int)Side::LEFT_SIDE].pose);
|
|
|
|
vrViews[(int)Side::RIGHT_SIDE].pose = fromXR(xrViews[(int)Side::RIGHT_SIDE].pose);
|
|
|
|
vrViews[(int)Side::LEFT_SIDE].fov = fromXR(xrViews[(int)Side::LEFT_SIDE].fov);
|
|
|
|
vrViews[(int)Side::RIGHT_SIDE].fov = fromXR(xrViews[(int)Side::RIGHT_SIDE].fov);
|
|
|
|
return vrViews;
|
2020-01-09 23:10:09 +00:00
|
|
|
}
|
|
|
|
|
2020-06-21 21:40:07 +00:00
|
|
|
MWVR::Pose OpenXRManagerImpl::getPredictedHeadPose(
|
|
|
|
int64_t predictedDisplayTime,
|
2020-06-24 19:26:11 +00:00
|
|
|
ReferenceSpace space)
|
2020-01-09 23:10:09 +00:00
|
|
|
{
|
2020-06-02 19:46:22 +00:00
|
|
|
if (!mPredictionsEnabled)
|
|
|
|
{
|
|
|
|
Log(Debug::Error) << "Prediction out of order";
|
|
|
|
throw std::logic_error("Prediction out of order");
|
|
|
|
}
|
2020-01-09 23:10:09 +00:00
|
|
|
XrSpaceLocation location{ XR_TYPE_SPACE_LOCATION };
|
2020-06-21 21:40:07 +00:00
|
|
|
XrSpace limbSpace = mReferenceSpaceView;
|
2020-01-23 23:14:23 +00:00
|
|
|
XrSpace referenceSpace = XR_NULL_HANDLE;
|
2020-06-21 21:40:07 +00:00
|
|
|
|
2020-01-23 23:14:23 +00:00
|
|
|
switch (space)
|
|
|
|
{
|
2020-06-24 19:26:11 +00:00
|
|
|
case ReferenceSpace::STAGE:
|
2020-01-23 23:14:23 +00:00
|
|
|
referenceSpace = mReferenceSpaceStage;
|
|
|
|
break;
|
2020-06-24 19:26:11 +00:00
|
|
|
case ReferenceSpace::VIEW:
|
2020-01-23 23:14:23 +00:00
|
|
|
referenceSpace = mReferenceSpaceView;
|
|
|
|
break;
|
|
|
|
}
|
2020-02-02 12:12:53 +00:00
|
|
|
CHECK_XRCMD(xrLocateSpace(limbSpace, referenceSpace, predictedDisplayTime, &location));
|
2020-06-21 21:40:07 +00:00
|
|
|
|
2020-05-01 19:37:01 +00:00
|
|
|
if (!location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT)
|
|
|
|
{
|
|
|
|
// Quat must have a magnitude of 1 but openxr sets it to 0 when tracking is unavailable.
|
|
|
|
// I want a no-track pose to still be valid
|
|
|
|
location.pose.orientation.w = 1;
|
|
|
|
}
|
2020-01-23 23:14:23 +00:00
|
|
|
return MWVR::Pose{
|
2020-06-24 19:26:11 +00:00
|
|
|
fromXR(location.pose.position),
|
|
|
|
fromXR(location.pose.orientation)
|
2020-01-23 23:14:23 +00:00
|
|
|
};
|
2020-01-09 23:10:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void OpenXRManagerImpl::handleEvents()
|
|
|
|
{
|
2020-10-22 18:39:53 +00:00
|
|
|
std::unique_lock<std::mutex> lock(mMutex);
|
2020-01-23 23:14:23 +00:00
|
|
|
|
2020-07-21 10:28:39 +00:00
|
|
|
xrQueueEvents();
|
|
|
|
|
2020-01-09 23:10:09 +00:00
|
|
|
while (auto* event = nextEvent())
|
|
|
|
{
|
2020-07-21 10:28:39 +00:00
|
|
|
if (!processEvent(event))
|
2020-01-09 23:10:09 +00:00
|
|
|
{
|
2020-07-21 10:28:39 +00:00
|
|
|
// Do not consider processing an event optional.
|
|
|
|
// Retry once per frame until every event has been successfully processed
|
|
|
|
return;
|
2020-01-09 23:10:09 +00:00
|
|
|
}
|
2020-07-21 10:28:39 +00:00
|
|
|
popEvent();
|
2020-01-09 23:10:09 +00:00
|
|
|
}
|
2020-10-18 12:22:03 +00:00
|
|
|
|
|
|
|
if (mXrSessionShouldStop)
|
|
|
|
{
|
|
|
|
if (checkStopCondition())
|
|
|
|
{
|
|
|
|
CHECK_XRCMD(xrEndSession(mSession));
|
|
|
|
mXrSessionShouldStop = false;
|
|
|
|
}
|
|
|
|
}
|
2020-01-09 23:10:09 +00:00
|
|
|
}
|
|
|
|
|
2020-07-21 10:28:39 +00:00
|
|
|
const XrEventDataBaseHeader* OpenXRManagerImpl::nextEvent()
|
|
|
|
{
|
|
|
|
if (mEventQueue.size() > 0)
|
|
|
|
return reinterpret_cast<XrEventDataBaseHeader*> (&mEventQueue.front());
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool OpenXRManagerImpl::processEvent(const XrEventDataBaseHeader* header)
|
|
|
|
{
|
|
|
|
Log(Debug::Verbose) << "OpenXR: Event received: " << to_string(header->type);
|
|
|
|
switch (header->type)
|
|
|
|
{
|
|
|
|
case XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED:
|
|
|
|
{
|
|
|
|
const auto* stateChangeEvent = reinterpret_cast<const XrEventDataSessionStateChanged*>(header);
|
|
|
|
return handleSessionStateChanged(*stateChangeEvent);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED:
|
2020-12-02 20:46:03 +00:00
|
|
|
MWVR::Environment::get().getInputManager()->notifyInteractionProfileChanged();
|
|
|
|
break;
|
|
|
|
case XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING:
|
2020-07-21 10:28:39 +00:00
|
|
|
case XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING:
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
Log(Debug::Verbose) << "OpenXR: Event ignored";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
OpenXRManagerImpl::handleSessionStateChanged(
|
2020-01-09 23:10:09 +00:00
|
|
|
const XrEventDataSessionStateChanged& stateChangedEvent)
|
|
|
|
{
|
2020-10-18 12:22:03 +00:00
|
|
|
Log(Debug::Verbose) << "XrEventDataSessionStateChanged: state " << to_string(mSessionState) << "->" << to_string(stateChangedEvent.state);
|
|
|
|
mSessionState = stateChangedEvent.state;
|
2020-01-09 23:10:09 +00:00
|
|
|
|
2020-10-18 12:22:03 +00:00
|
|
|
// Ref: https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#session-states
|
|
|
|
switch (mSessionState)
|
2020-01-09 23:10:09 +00:00
|
|
|
{
|
2020-10-18 12:22:03 +00:00
|
|
|
case XR_SESSION_STATE_IDLE:
|
|
|
|
{
|
|
|
|
mAppShouldSyncFrameLoop = false;
|
|
|
|
mAppShouldRender = false;
|
|
|
|
mAppShouldReadInput = false;
|
|
|
|
mXrSessionShouldStop = false;
|
|
|
|
break;
|
|
|
|
}
|
2020-01-09 23:10:09 +00:00
|
|
|
case XR_SESSION_STATE_READY:
|
|
|
|
{
|
2020-10-18 12:22:03 +00:00
|
|
|
mAppShouldSyncFrameLoop = true;
|
|
|
|
mAppShouldRender = false;
|
|
|
|
mAppShouldReadInput = false;
|
|
|
|
mXrSessionShouldStop = false;
|
|
|
|
|
2020-01-09 23:10:09 +00:00
|
|
|
XrSessionBeginInfo beginInfo{ XR_TYPE_SESSION_BEGIN_INFO };
|
|
|
|
beginInfo.primaryViewConfigurationType = mViewConfigType;
|
|
|
|
CHECK_XRCMD(xrBeginSession(mSession, &beginInfo));
|
2020-10-18 12:22:03 +00:00
|
|
|
|
2020-01-09 23:10:09 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case XR_SESSION_STATE_STOPPING:
|
|
|
|
{
|
2020-10-18 12:22:03 +00:00
|
|
|
mAppShouldSyncFrameLoop = false;
|
|
|
|
mAppShouldRender = false;
|
|
|
|
mAppShouldReadInput = false;
|
|
|
|
mXrSessionShouldStop = true;
|
2020-01-09 23:10:09 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-10-18 12:22:03 +00:00
|
|
|
case XR_SESSION_STATE_SYNCHRONIZED:
|
|
|
|
{
|
|
|
|
mAppShouldSyncFrameLoop = true;
|
|
|
|
mAppShouldRender = false;
|
|
|
|
mAppShouldReadInput = false;
|
|
|
|
mXrSessionShouldStop = false;
|
|
|
|
break;
|
2020-07-21 10:28:39 +00:00
|
|
|
}
|
2020-10-18 12:22:03 +00:00
|
|
|
case XR_SESSION_STATE_VISIBLE:
|
2020-07-21 10:28:39 +00:00
|
|
|
{
|
2020-10-18 12:22:03 +00:00
|
|
|
mAppShouldSyncFrameLoop = true;
|
|
|
|
mAppShouldRender = true;
|
|
|
|
mAppShouldReadInput = false;
|
|
|
|
mXrSessionShouldStop = false;
|
|
|
|
break;
|
2020-07-21 10:28:39 +00:00
|
|
|
}
|
2020-10-18 12:22:03 +00:00
|
|
|
case XR_SESSION_STATE_FOCUSED:
|
2020-07-21 10:28:39 +00:00
|
|
|
{
|
2020-10-18 12:22:03 +00:00
|
|
|
mAppShouldSyncFrameLoop = true;
|
|
|
|
mAppShouldRender = true;
|
|
|
|
mAppShouldReadInput = true;
|
|
|
|
mXrSessionShouldStop = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
Log(Debug::Warning) << "XrEventDataSessionStateChanged: Ignoring new state " << to_string(mSessionState);
|
2020-01-09 23:10:09 +00:00
|
|
|
}
|
2020-07-21 10:28:39 +00:00
|
|
|
|
2020-10-18 12:22:03 +00:00
|
|
|
return true;
|
2020-07-21 10:28:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool OpenXRManagerImpl::checkStopCondition()
|
|
|
|
{
|
|
|
|
return mAcquiredResources == 0;
|
2020-01-09 23:10:09 +00:00
|
|
|
}
|
|
|
|
|
2020-07-21 10:28:39 +00:00
|
|
|
bool OpenXRManagerImpl::xrNextEvent(XrEventDataBuffer& eventBuffer)
|
2020-01-09 23:10:09 +00:00
|
|
|
{
|
2020-07-21 10:28:39 +00:00
|
|
|
XrEventDataBaseHeader* baseHeader = reinterpret_cast<XrEventDataBaseHeader*>(&eventBuffer);
|
2020-01-09 23:10:09 +00:00
|
|
|
*baseHeader = { XR_TYPE_EVENT_DATA_BUFFER };
|
2020-07-21 10:28:39 +00:00
|
|
|
const XrResult result = xrPollEvent(mInstance, &eventBuffer);
|
2020-01-09 23:10:09 +00:00
|
|
|
if (result == XR_SUCCESS)
|
|
|
|
{
|
|
|
|
if (baseHeader->type == XR_TYPE_EVENT_DATA_EVENTS_LOST) {
|
|
|
|
const XrEventDataEventsLost* const eventsLost = reinterpret_cast<const XrEventDataEventsLost*>(baseHeader);
|
|
|
|
Log(Debug::Warning) << "OpenXRManagerImpl: Lost " << eventsLost->lostEventCount << " events";
|
|
|
|
}
|
|
|
|
|
|
|
|
return baseHeader;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result != XR_EVENT_UNAVAILABLE)
|
|
|
|
CHECK_XRRESULT(result, "xrPollEvent");
|
2020-10-30 23:29:24 +00:00
|
|
|
return false;
|
2020-01-09 23:10:09 +00:00
|
|
|
}
|
2020-01-23 23:14:23 +00:00
|
|
|
|
2020-07-21 10:28:39 +00:00
|
|
|
void OpenXRManagerImpl::popEvent()
|
|
|
|
{
|
|
|
|
if (mEventQueue.size() > 0)
|
|
|
|
mEventQueue.pop();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
OpenXRManagerImpl::xrQueueEvents()
|
|
|
|
{
|
|
|
|
XrEventDataBuffer eventBuffer;
|
|
|
|
while (xrNextEvent(eventBuffer))
|
|
|
|
{
|
|
|
|
mEventQueue.push(eventBuffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-23 23:14:23 +00:00
|
|
|
MWVR::Pose fromXR(XrPosef pose)
|
|
|
|
{
|
2020-06-24 19:26:11 +00:00
|
|
|
return MWVR::Pose{ fromXR(pose.position), fromXR(pose.orientation) };
|
2020-01-23 23:14:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
XrPosef toXR(MWVR::Pose pose)
|
|
|
|
{
|
2020-06-24 19:26:11 +00:00
|
|
|
return XrPosef{ toXR(pose.orientation), toXR(pose.position) };
|
2020-01-23 23:14:23 +00:00
|
|
|
}
|
2020-01-26 19:06:47 +00:00
|
|
|
|
2020-05-24 16:00:42 +00:00
|
|
|
MWVR::FieldOfView fromXR(XrFovf fov)
|
|
|
|
{
|
|
|
|
return MWVR::FieldOfView{ fov.angleLeft, fov.angleRight, fov.angleUp, fov.angleDown };
|
|
|
|
}
|
|
|
|
|
|
|
|
XrFovf toXR(MWVR::FieldOfView fov)
|
|
|
|
{
|
|
|
|
return XrFovf{ fov.angleLeft, fov.angleRight, fov.angleUp, fov.angleDown };
|
|
|
|
}
|
2020-01-26 19:06:47 +00:00
|
|
|
|
2020-06-24 19:26:11 +00:00
|
|
|
XrSpace OpenXRManagerImpl::getReferenceSpace(ReferenceSpace space)
|
2020-02-14 21:11:19 +00:00
|
|
|
{
|
2020-05-24 16:00:42 +00:00
|
|
|
XrSpace referenceSpace = XR_NULL_HANDLE;
|
2020-06-24 19:26:11 +00:00
|
|
|
if (space == ReferenceSpace::STAGE)
|
2020-05-24 16:00:42 +00:00
|
|
|
referenceSpace = mReferenceSpaceStage;
|
2020-06-24 19:26:11 +00:00
|
|
|
if (space == ReferenceSpace::VIEW)
|
2020-05-24 16:00:42 +00:00
|
|
|
referenceSpace = mReferenceSpaceView;
|
|
|
|
return referenceSpace;
|
2020-02-14 21:11:19 +00:00
|
|
|
}
|
2020-06-21 21:40:07 +00:00
|
|
|
|
2020-07-15 21:17:16 +00:00
|
|
|
bool OpenXRManagerImpl::xrExtensionIsEnabled(const char* extensionName) const
|
|
|
|
{
|
|
|
|
return mEnabledExtensions.count(extensionName) != 0;
|
|
|
|
}
|
|
|
|
|
2020-07-21 10:28:39 +00:00
|
|
|
void OpenXRManagerImpl::xrResourceAcquired()
|
|
|
|
{
|
2020-10-22 18:39:53 +00:00
|
|
|
std::unique_lock<std::mutex> lock(mMutex);
|
2020-07-21 10:28:39 +00:00
|
|
|
mAcquiredResources++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenXRManagerImpl::xrResourceReleased()
|
|
|
|
{
|
2020-10-22 18:39:53 +00:00
|
|
|
std::unique_lock<std::mutex> lock(mMutex);
|
2020-07-26 10:34:24 +00:00
|
|
|
if (mAcquiredResources == 0)
|
|
|
|
throw std::logic_error("Releasing a nonexistent resource");
|
2020-07-21 10:28:39 +00:00
|
|
|
mAcquiredResources--;
|
|
|
|
}
|
|
|
|
|
2020-10-17 19:11:31 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-06-02 19:46:22 +00:00
|
|
|
void OpenXRManagerImpl::enablePredictions()
|
|
|
|
{
|
|
|
|
mPredictionsEnabled = true;
|
|
|
|
}
|
2020-06-21 21:40:07 +00:00
|
|
|
|
2020-06-02 19:46:22 +00:00
|
|
|
void OpenXRManagerImpl::disablePredictions()
|
|
|
|
{
|
|
|
|
mPredictionsEnabled = false;
|
|
|
|
}
|
2020-06-21 21:40:07 +00:00
|
|
|
|
2020-06-24 19:26:11 +00:00
|
|
|
long long OpenXRManagerImpl::getLastPredictedDisplayTime()
|
|
|
|
{
|
|
|
|
return mFrameState.predictedDisplayTime;
|
|
|
|
}
|
|
|
|
|
2020-06-21 21:40:07 +00:00
|
|
|
long long OpenXRManagerImpl::getLastPredictedDisplayPeriod()
|
|
|
|
{
|
|
|
|
return mFrameState.predictedDisplayPeriod;
|
|
|
|
}
|
2020-06-24 19:26:11 +00:00
|
|
|
std::array<SwapchainConfig, 2> OpenXRManagerImpl::getRecommendedSwapchainConfig() const
|
|
|
|
{
|
|
|
|
std::array<SwapchainConfig, 2> config{};
|
|
|
|
for (uint32_t i = 0; i < 2; i++)
|
|
|
|
config[i] = SwapchainConfig{
|
2020-08-07 21:33:21 +00:00
|
|
|
(int)mConfigViews[i].recommendedImageRectWidth,
|
|
|
|
(int)mConfigViews[i].recommendedImageRectHeight,
|
|
|
|
(int)mConfigViews[i].recommendedSwapchainSampleCount,
|
|
|
|
(int)mConfigViews[i].maxImageRectWidth,
|
|
|
|
(int)mConfigViews[i].maxImageRectHeight,
|
|
|
|
(int)mConfigViews[i].maxSwapchainSampleCount,
|
2020-06-24 19:26:11 +00:00
|
|
|
};
|
|
|
|
return config;
|
|
|
|
}
|
2020-01-23 23:14:23 +00:00
|
|
|
|
2020-06-24 19:26:11 +00:00
|
|
|
osg::Vec3 fromXR(XrVector3f v)
|
2020-01-23 23:14:23 +00:00
|
|
|
{
|
2020-06-24 19:26:11 +00:00
|
|
|
return osg::Vec3{ v.x, -v.z, v.y };
|
2020-01-23 23:14:23 +00:00
|
|
|
}
|
|
|
|
|
2020-06-24 19:26:11 +00:00
|
|
|
osg::Quat fromXR(XrQuaternionf quat)
|
2020-01-23 23:14:23 +00:00
|
|
|
{
|
2020-06-24 19:26:11 +00:00
|
|
|
return osg::Quat{ quat.x, -quat.z, quat.y, quat.w };
|
2020-01-23 23:14:23 +00:00
|
|
|
}
|
|
|
|
|
2020-06-24 19:26:11 +00:00
|
|
|
XrVector3f toXR(osg::Vec3 v)
|
2020-01-23 23:14:23 +00:00
|
|
|
{
|
2020-02-23 10:02:38 +00:00
|
|
|
return XrVector3f{ v.x(), v.z(), -v.y() };
|
2020-01-23 23:14:23 +00:00
|
|
|
}
|
|
|
|
|
2020-06-24 19:26:11 +00:00
|
|
|
XrQuaternionf toXR(osg::Quat quat)
|
2020-01-23 23:14:23 +00:00
|
|
|
{
|
2020-10-30 23:29:24 +00:00
|
|
|
return XrQuaternionf{ static_cast<float>(quat.x()), static_cast<float>(quat.z()), static_cast<float>(-quat.y()), static_cast<float>(quat.w()) };
|
2020-01-23 23:14:23 +00:00
|
|
|
}
|
2020-01-09 23:10:09 +00:00
|
|
|
}
|
2020-06-24 19:26:11 +00:00
|
|
|
|