You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
747 lines
30 KiB
C++
747 lines
30 KiB
C++
#include "openxrswapchainimage.hpp"
|
|
#include "openxrmanagerimpl.hpp"
|
|
#include "openxrplatform.hpp"
|
|
#include "vrenvironment.hpp"
|
|
|
|
// The OpenXR SDK's platform headers assume we've included platform headers
|
|
#ifdef _WIN32
|
|
#include <Windows.h>
|
|
#include <objbase.h>
|
|
|
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
|
#include <d3d11_1.h>
|
|
#endif
|
|
|
|
#elif __linux__
|
|
#include <X11/Xlib.h>
|
|
#include <GL/glx.h>
|
|
#undef None
|
|
|
|
#else
|
|
#error Unsupported platform
|
|
#endif
|
|
|
|
#include <openxr/openxr.h>
|
|
#include <openxr/openxr_platform.h>
|
|
#include <openxr/openxr_platform_defines.h>
|
|
#include <openxr/openxr_reflection.h>
|
|
|
|
#include <stdexcept>
|
|
#include <deque>
|
|
#include <cassert>
|
|
#include <optional>
|
|
|
|
namespace MWVR
|
|
{
|
|
|
|
XrResult CheckXrResult(XrResult res, const char* originator, const char* sourceLocation) {
|
|
static bool initialized = false;
|
|
static bool sLogAllXrCalls = false;
|
|
static bool sContinueOnErrors = false;
|
|
if (!initialized)
|
|
{
|
|
initialized = true;
|
|
sLogAllXrCalls = Settings::Manager::getBool("log all openxr calls", "VR Debug");
|
|
sContinueOnErrors = Settings::Manager::getBool("continue on errors", "VR Debug");
|
|
}
|
|
|
|
auto resultString = XrResultString(res);
|
|
|
|
if (XR_FAILED(res)) {
|
|
std::stringstream ss;
|
|
#ifdef _WIN32
|
|
ss << sourceLocation << ": OpenXR[Error: " << resultString << "][Thread: " << std::this_thread::get_id() << "]: " << originator;
|
|
#elif __linux__
|
|
ss << sourceLocation << ": OpenXR[Error: " << resultString << "][Thread: " << std::this_thread::get_id() << "]: " << originator;
|
|
#endif
|
|
Log(Debug::Error) << ss.str();
|
|
if (!sContinueOnErrors)
|
|
throw std::runtime_error(ss.str().c_str());
|
|
}
|
|
else if (res != XR_SUCCESS || sLogAllXrCalls)
|
|
{
|
|
#ifdef _WIN32
|
|
Log(Debug::Verbose) << sourceLocation << ": OpenXR[" << resultString << "][" << std::this_thread::get_id() << "]: " << originator;
|
|
#elif __linux__
|
|
Log(Debug::Verbose) << sourceLocation << ": OpenXR[" << resultString << "][" << std::this_thread::get_id() << "]: " << originator;
|
|
#endif
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
void OpenXRPlatform::enumerateExtensions(const char* layerName, int logIndent)
|
|
{
|
|
uint32_t extensionCount = 0;
|
|
std::vector<XrExtensionProperties> availableExtensions;
|
|
CHECK_XRCMD(xrEnumerateInstanceExtensionProperties(layerName, 0, &extensionCount, nullptr));
|
|
availableExtensions.resize(extensionCount, XrExtensionProperties{ XR_TYPE_EXTENSION_PROPERTIES });
|
|
CHECK_XRCMD(xrEnumerateInstanceExtensionProperties(layerName, availableExtensions.size(), &extensionCount, availableExtensions.data()));
|
|
|
|
std::vector<std::string> extensionNames;
|
|
const std::string indentStr(logIndent, ' ');
|
|
for (auto& extension : availableExtensions)
|
|
{
|
|
if (layerName)
|
|
mAvailableLayerExtensions[layerName][extension.extensionName] = extension;
|
|
else
|
|
mAvailableExtensions[extension.extensionName] = extension;
|
|
|
|
Log(Debug::Verbose) << indentStr << "Name=" << extension.extensionName << " SpecVersion=" << extension.extensionVersion;
|
|
}
|
|
}
|
|
|
|
struct OpenXRPlatformPrivate
|
|
{
|
|
OpenXRPlatformPrivate(osg::GraphicsContext* gc);
|
|
~OpenXRPlatformPrivate();
|
|
|
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
|
typedef BOOL(WINAPI* P_wglDXSetResourceShareHandleNV)(void* dxObject, HANDLE shareHandle);
|
|
typedef HANDLE(WINAPI* P_wglDXOpenDeviceNV)(void* dxDevice);
|
|
typedef BOOL(WINAPI* P_wglDXCloseDeviceNV)(HANDLE hDevice);
|
|
typedef HANDLE(WINAPI* P_wglDXRegisterObjectNV)(HANDLE hDevice, void* dxObject,
|
|
GLuint name, GLenum type, GLenum access);
|
|
typedef BOOL(WINAPI* P_wglDXUnregisterObjectNV)(HANDLE hDevice, HANDLE hObject);
|
|
typedef BOOL(WINAPI* P_wglDXObjectAccessNV)(HANDLE hObject, GLenum access);
|
|
typedef BOOL(WINAPI* P_wglDXLockObjectsNV)(HANDLE hDevice, GLint count, HANDLE* hObjects);
|
|
typedef BOOL(WINAPI* P_wglDXUnlockObjectsNV)(HANDLE hDevice, GLint count, HANDLE* hObjects);
|
|
|
|
void initializeD3D11(XrGraphicsRequirementsD3D11KHR requirements)
|
|
{
|
|
mD3D11Dll = LoadLibrary("D3D11.dll");
|
|
|
|
if (!mD3D11Dll)
|
|
throw std::runtime_error("Current OpenXR runtime requires DirectX >= 11.0 but D3D11.dll was not found.");
|
|
|
|
pD3D11CreateDevice = reinterpret_cast<PFN_D3D11_CREATE_DEVICE>(GetProcAddress(mD3D11Dll, "D3D11CreateDevice"));
|
|
|
|
if (!pD3D11CreateDevice)
|
|
throw std::runtime_error("Symbol 'D3D11CreateDevice' not found in D3D11.dll");
|
|
|
|
// Create the device and device context objects
|
|
pD3D11CreateDevice(
|
|
nullptr,
|
|
D3D_DRIVER_TYPE_HARDWARE,
|
|
nullptr,
|
|
0,
|
|
nullptr,
|
|
0,
|
|
D3D11_SDK_VERSION,
|
|
&mD3D11Device,
|
|
nullptr,
|
|
&mD3D11ImmediateContext);
|
|
|
|
mD3D11bindings.device = mD3D11Device;
|
|
|
|
//typedef HANDLE (WINAPI* P_wglDXOpenDeviceNV)(void* dxDevice);
|
|
//P_wglDXOpenDeviceNV wglDXOpenDeviceNV = reinterpret_cast<P_wglDXOpenDeviceNV>(wglGetProcAddress("wglDXOpenDeviceNV"));
|
|
//P_wglDXOpenDeviceNV wglDXOpenDeviceNV = reinterpret_cast<P_wglDXOpenDeviceNV>(wglGetProcAddress("wglDXOpenDeviceNV"));
|
|
|
|
#define LOAD_WGL(a) a = reinterpret_cast<decltype(a)>(wglGetProcAddress(#a)); if(!a) throw std::runtime_error("Extension WGL_NV_DX_interop2 required to run OpenMW VR via DirectX missing expected symbol '" #a "'.")
|
|
LOAD_WGL(wglDXSetResourceShareHandleNV);
|
|
LOAD_WGL(wglDXOpenDeviceNV);
|
|
LOAD_WGL(wglDXCloseDeviceNV);
|
|
LOAD_WGL(wglDXRegisterObjectNV);
|
|
LOAD_WGL(wglDXUnregisterObjectNV);
|
|
LOAD_WGL(wglDXObjectAccessNV);
|
|
LOAD_WGL(wglDXLockObjectsNV);
|
|
LOAD_WGL(wglDXUnlockObjectsNV);
|
|
#undef LOAD_WGL
|
|
|
|
wglDXDevice = wglDXOpenDeviceNV(mD3D11Device);
|
|
}
|
|
|
|
bool mWGL_NV_DX_interop2 = false;
|
|
XrGraphicsBindingD3D11KHR mD3D11bindings{ XR_TYPE_GRAPHICS_BINDING_D3D11_KHR };
|
|
ID3D11Device* mD3D11Device = nullptr;
|
|
ID3D11DeviceContext* mD3D11ImmediateContext = nullptr;
|
|
HMODULE mD3D11Dll = nullptr;
|
|
PFN_D3D11_CREATE_DEVICE pD3D11CreateDevice = nullptr;
|
|
|
|
P_wglDXSetResourceShareHandleNV wglDXSetResourceShareHandleNV = nullptr;
|
|
P_wglDXOpenDeviceNV wglDXOpenDeviceNV = nullptr;
|
|
P_wglDXCloseDeviceNV wglDXCloseDeviceNV = nullptr;
|
|
P_wglDXRegisterObjectNV wglDXRegisterObjectNV = nullptr;
|
|
P_wglDXUnregisterObjectNV wglDXUnregisterObjectNV = nullptr;
|
|
P_wglDXObjectAccessNV wglDXObjectAccessNV = nullptr;
|
|
P_wglDXLockObjectsNV wglDXLockObjectsNV = nullptr;
|
|
P_wglDXUnlockObjectsNV wglDXUnlockObjectsNV = nullptr;
|
|
|
|
HANDLE wglDXDevice = nullptr;
|
|
#endif
|
|
};
|
|
|
|
OpenXRPlatformPrivate::OpenXRPlatformPrivate(osg::GraphicsContext* gc)
|
|
{
|
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
|
typedef const char* (WINAPI* PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc);
|
|
PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = 0;
|
|
wglGetExtensionsStringARB = reinterpret_cast<PFNWGLGETEXTENSIONSSTRINGARBPROC>(wglGetProcAddress("wglGetExtensionsStringARB"));
|
|
if (wglGetExtensionsStringARB)
|
|
{
|
|
std::string wglExtensions = wglGetExtensionsStringARB(wglGetCurrentDC());
|
|
Log(Debug::Verbose) << "WGL Extensions: " << wglExtensions;
|
|
mWGL_NV_DX_interop2 = wglExtensions.find("WGL_NV_DX_interop2") != std::string::npos;
|
|
}
|
|
else
|
|
Log(Debug::Verbose) << "Unable to query WGL extensions";
|
|
#endif
|
|
}
|
|
|
|
OpenXRPlatformPrivate::~OpenXRPlatformPrivate()
|
|
{
|
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
|
if (wglDXDevice)
|
|
wglDXCloseDeviceNV(wglDXDevice);
|
|
if (mD3D11ImmediateContext)
|
|
mD3D11ImmediateContext->Release();
|
|
if (mD3D11Device)
|
|
mD3D11Device->Release();
|
|
if (mD3D11Dll)
|
|
FreeLibrary(mD3D11Dll);
|
|
#endif
|
|
}
|
|
|
|
OpenXRPlatform::OpenXRPlatform(osg::GraphicsContext* gc)
|
|
: mPrivate(new OpenXRPlatformPrivate(gc))
|
|
{
|
|
// Enumerate layers and 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()));
|
|
|
|
Log(Debug::Verbose) << "Available Extensions: ";
|
|
enumerateExtensions(nullptr, 2);
|
|
Log(Debug::Verbose) << "Available Layers: ";
|
|
|
|
if (layers.size() == 0)
|
|
{
|
|
Log(Debug::Verbose) << " No layers available";
|
|
}
|
|
for (const XrApiLayerProperties& layer : layers) {
|
|
Log(Debug::Verbose) << " Name=" << layer.layerName << " SpecVersion=" << layer.layerVersion;
|
|
mAvailableLayers[layer.layerName] = layer;
|
|
enumerateExtensions(layer.layerName, 4);
|
|
}
|
|
|
|
setupExtensions();
|
|
}
|
|
|
|
OpenXRPlatform::~OpenXRPlatform()
|
|
{
|
|
}
|
|
|
|
#if !XR_KHR_composition_layer_depth \
|
|
|| !XR_EXT_hp_mixed_reality_controller \
|
|
|| !XR_EXT_debug_utils \
|
|
|| !XR_HTC_vive_cosmos_controller_interaction \
|
|
|| !XR_HUAWEI_controller_interaction
|
|
|
|
#error "OpenXR extensions missing. Please upgrade your copy of the OpenXR SDK to 1.0.13 minimum"
|
|
#endif
|
|
void OpenXRPlatform::setupExtensions()
|
|
{
|
|
std::vector<const char*> optionalExtensions = {
|
|
XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME,
|
|
XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME,
|
|
XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME
|
|
};
|
|
|
|
if (Settings::Manager::getBool("enable XR_KHR_composition_layer_depth", "VR Debug"))
|
|
optionalExtensions.emplace_back(XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME);
|
|
|
|
if (Settings::Manager::getBool("enable XR_EXT_debug_utils", "VR Debug"))
|
|
optionalExtensions.emplace_back(XR_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
|
|
|
selectGraphicsAPIExtension();
|
|
|
|
Log(Debug::Verbose) << "Using extensions:";
|
|
|
|
auto* graphicsAPIExtension = graphicsAPIExtensionName();
|
|
if (!graphicsAPIExtension || !enableExtension(graphicsAPIExtension, true))
|
|
{
|
|
throw std::runtime_error("No graphics APIs supported by openmw are supported by the OpenXR runtime.");
|
|
}
|
|
|
|
for (auto optionalExtension : optionalExtensions)
|
|
enableExtension(optionalExtension, true);
|
|
}
|
|
|
|
bool OpenXRPlatform::selectDirectX()
|
|
{
|
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
|
if (mPrivate->mWGL_NV_DX_interop2)
|
|
{
|
|
if (mAvailableExtensions.count(XR_KHR_D3D11_ENABLE_EXTENSION_NAME))
|
|
{
|
|
mGraphicsAPIExtension = XR_KHR_D3D11_ENABLE_EXTENSION_NAME;
|
|
return true;
|
|
}
|
|
else
|
|
Log(Debug::Warning) << "Warning: Failed to select DirectX swapchains: OpenXR runtime does not support essential extension '" << XR_KHR_D3D11_ENABLE_EXTENSION_NAME << "'";
|
|
}
|
|
else
|
|
Log(Debug::Warning) << "Warning: Failed to select DirectX swapchains: Essential WGL extension 'WGL_NV_DX_interop2' not supported by the graphics driver.";
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
bool OpenXRPlatform::selectOpenGL()
|
|
{
|
|
#ifdef XR_USE_GRAPHICS_API_OPENGL
|
|
if (mAvailableExtensions.count(XR_KHR_OPENGL_ENABLE_EXTENSION_NAME))
|
|
{
|
|
mGraphicsAPIExtension = XR_KHR_OPENGL_ENABLE_EXTENSION_NAME;
|
|
return true;
|
|
}
|
|
else
|
|
Log(Debug::Warning) << "Warning: Failed to select OpenGL swapchains: OpenXR runtime does not support essential extension '" << XR_KHR_OPENGL_ENABLE_EXTENSION_NAME << "'";
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
#ifdef XR_USE_GRAPHICS_API_OPENGL
|
|
#if !XR_KHR_opengl_enable
|
|
#error "OpenXR extensions missing. Please upgrade your copy of the OpenXR SDK to 1.0.13 minimum"
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
|
#if !XR_KHR_D3D11_enable
|
|
#error "OpenXR extensions missing. Please upgrade your copy of the OpenXR SDK to 1.0.13 minimum"
|
|
#endif
|
|
#endif
|
|
|
|
const char* OpenXRPlatform::graphicsAPIExtensionName()
|
|
{
|
|
return mGraphicsAPIExtension;
|
|
}
|
|
|
|
void OpenXRPlatform::selectGraphicsAPIExtension()
|
|
{
|
|
bool preferDirectX = Settings::Manager::getBool("Prefer DirectX swapchains", "VR");
|
|
|
|
if (preferDirectX)
|
|
if (selectDirectX() || selectOpenGL())
|
|
return;
|
|
if (selectOpenGL() || selectDirectX())
|
|
return;
|
|
|
|
Log(Debug::Verbose) << "Error: No graphics API supported by OpenMW VR is supported by the OpenXR runtime.";
|
|
throw std::runtime_error("Error: No graphics API supported by OpenMW VR is supported by the OpenXR runtime.");
|
|
}
|
|
|
|
bool OpenXRPlatform::supportsExtension(const std::string& extensionName) const
|
|
{
|
|
return mAvailableExtensions.count(extensionName) > 0;
|
|
}
|
|
|
|
bool OpenXRPlatform::supportsExtension(const std::string& extensionName, uint32_t minimumVersion) const
|
|
{
|
|
auto it = mAvailableExtensions.find(extensionName);
|
|
return it != mAvailableExtensions.end() && it->second.extensionVersion > minimumVersion;
|
|
}
|
|
|
|
bool OpenXRPlatform::supportsLayer(const std::string& layerName) const
|
|
{
|
|
return mAvailableLayers.count(layerName) > 0;
|
|
}
|
|
|
|
bool OpenXRPlatform::supportsLayer(const std::string& layerName, uint32_t minimumVersion) const
|
|
{
|
|
auto it = mAvailableLayers.find(layerName);
|
|
return it != mAvailableLayers.end() && it->second.layerVersion > minimumVersion;
|
|
}
|
|
|
|
bool OpenXRPlatform::enableExtension(const std::string& extensionName, bool optional)
|
|
{
|
|
auto it = mAvailableExtensions.find(extensionName);
|
|
if (it != mAvailableExtensions.end())
|
|
{
|
|
Log(Debug::Verbose) << " " << extensionName << ": enabled";
|
|
mEnabledExtensions.push_back(it->second.extensionName);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
Log(Debug::Verbose) << " " << extensionName << ": disabled (not supported)";
|
|
if (!optional)
|
|
{
|
|
throw std::runtime_error(std::string("Required OpenXR extension ") + extensionName + " not supported by the runtime");
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool OpenXRPlatform::enableExtension(const std::string& extensionName, bool optional, uint32_t minimumVersion)
|
|
{
|
|
auto it = mAvailableExtensions.find(extensionName);
|
|
if (it != mAvailableExtensions.end() && it->second.extensionVersion > minimumVersion)
|
|
{
|
|
Log(Debug::Verbose) << " " << extensionName << ": enabled";
|
|
mEnabledExtensions.push_back(it->second.extensionName);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
Log(Debug::Verbose) << " " << extensionName << ": disabled (not supported)";
|
|
if (!optional)
|
|
{
|
|
throw std::runtime_error(std::string("Required OpenXR extension ") + extensionName + " not supported by the runtime");
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
bool OpenXRPlatform::extensionEnabled(const std::string& extensionName) const
|
|
{
|
|
for (auto* extension : mEnabledExtensions)
|
|
if (extension == extensionName)
|
|
return true;
|
|
return false;
|
|
}
|
|
XrInstance OpenXRPlatform::createXrInstance(const std::string& name)
|
|
{
|
|
XrInstance instance = XR_NULL_HANDLE;
|
|
XrInstanceCreateInfo createInfo{ XR_TYPE_INSTANCE_CREATE_INFO };
|
|
createInfo.next = nullptr;
|
|
createInfo.enabledExtensionCount = mEnabledExtensions.size();
|
|
createInfo.enabledExtensionNames = mEnabledExtensions.data();
|
|
strcpy(createInfo.applicationInfo.applicationName, "openmw_vr");
|
|
createInfo.applicationInfo.apiVersion = XR_CURRENT_API_VERSION;
|
|
|
|
auto res = CHECK_XRCMD(xrCreateInstance(&createInfo, &instance));
|
|
if (!XR_SUCCEEDED(res))
|
|
initFailure(res, instance);
|
|
return instance;
|
|
}
|
|
|
|
XrSession OpenXRPlatform::createXrSession(XrInstance instance, XrSystemId systemId)
|
|
{
|
|
XrSession session = XR_NULL_HANDLE;
|
|
XrResult res = XR_SUCCESS;
|
|
#ifdef _WIN32
|
|
std::string graphicsAPIExtension = graphicsAPIExtensionName();
|
|
if(graphicsAPIExtension == XR_KHR_OPENGL_ENABLE_EXTENSION_NAME)
|
|
{
|
|
// Get system requirements
|
|
PFN_xrGetOpenGLGraphicsRequirementsKHR p_getRequirements = nullptr;
|
|
CHECK_XRCMD(xrGetInstanceProcAddr(instance, "xrGetOpenGLGraphicsRequirementsKHR", reinterpret_cast<PFN_xrVoidFunction*>(&p_getRequirements)));
|
|
XrGraphicsRequirementsOpenGLKHR requirements{ XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR };
|
|
CHECK_XRCMD(p_getRequirements(instance, systemId, &requirements));
|
|
|
|
// TODO: Actually get system version
|
|
const XrVersion systemApiVersion = XR_MAKE_VERSION(4, 6, 0);
|
|
if (requirements.minApiVersionSupported > systemApiVersion) {
|
|
std::cout << "Runtime does not support desired Graphics API and/or version" << std::endl;
|
|
}
|
|
|
|
// Create Session
|
|
auto DC = wglGetCurrentDC();
|
|
auto GLRC = wglGetCurrentContext();
|
|
|
|
XrGraphicsBindingOpenGLWin32KHR graphicsBindings;
|
|
graphicsBindings.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR;
|
|
graphicsBindings.next = nullptr;
|
|
graphicsBindings.hDC = DC;
|
|
graphicsBindings.hGLRC = GLRC;
|
|
|
|
if (!graphicsBindings.hDC)
|
|
Log(Debug::Warning) << "Missing DC";
|
|
|
|
XrSessionCreateInfo createInfo{ XR_TYPE_SESSION_CREATE_INFO };
|
|
createInfo.next = &graphicsBindings;
|
|
createInfo.systemId = systemId;
|
|
res = CHECK_XRCMD(xrCreateSession(instance, &createInfo, &session));
|
|
}
|
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
|
else if(graphicsAPIExtension == XR_KHR_D3D11_ENABLE_EXTENSION_NAME)
|
|
{
|
|
PFN_xrGetD3D11GraphicsRequirementsKHR p_getRequirements = nullptr;
|
|
CHECK_XRCMD(xrGetInstanceProcAddr(instance, "xrGetD3D11GraphicsRequirementsKHR", reinterpret_cast<PFN_xrVoidFunction*>(&p_getRequirements)));
|
|
XrGraphicsRequirementsD3D11KHR requirements{ XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR };
|
|
CHECK_XRCMD(p_getRequirements(instance, systemId, &requirements));
|
|
mPrivate->initializeD3D11(requirements);
|
|
|
|
XrSessionCreateInfo createInfo{ XR_TYPE_SESSION_CREATE_INFO };
|
|
createInfo.next = &mPrivate->mD3D11bindings;
|
|
createInfo.systemId = systemId;
|
|
res = CHECK_XRCMD(xrCreateSession(instance, &createInfo, &session));
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
throw std::logic_error("Enum value not implemented");
|
|
}
|
|
#elif __linux__
|
|
{
|
|
// Get system requirements
|
|
PFN_xrGetOpenGLGraphicsRequirementsKHR p_getRequirements = nullptr;
|
|
xrGetInstanceProcAddr(instance, "xrGetOpenGLGraphicsRequirementsKHR", reinterpret_cast<PFN_xrVoidFunction*>(&p_getRequirements));
|
|
XrGraphicsRequirementsOpenGLKHR requirements{ XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR };
|
|
CHECK_XRCMD(p_getRequirements(instance, systemId, &requirements));
|
|
|
|
// TODO: Actually get system version
|
|
const XrVersion systemApiVersion = XR_MAKE_VERSION(4, 6, 0);
|
|
if (requirements.minApiVersionSupported > systemApiVersion) {
|
|
std::cout << "Runtime does not support desired Graphics API and/or version" << std::endl;
|
|
}
|
|
|
|
// 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 = systemId;
|
|
res = CHECK_XRCMD(xrCreateSession(instance, &createInfo, &session));
|
|
}
|
|
#endif
|
|
if (!XR_SUCCEEDED(res))
|
|
initFailure(res, instance);
|
|
|
|
uint32_t swapchainFormatCount;
|
|
CHECK_XRCMD(xrEnumerateSwapchainFormats(session, 0, &swapchainFormatCount, nullptr));
|
|
mSwapchainFormats.resize(swapchainFormatCount);
|
|
CHECK_XRCMD(xrEnumerateSwapchainFormats(session, (uint32_t)mSwapchainFormats.size(), &swapchainFormatCount, mSwapchainFormats.data()));
|
|
|
|
std::stringstream ss;
|
|
ss << "Available Swapchain formats: (" << swapchainFormatCount << ")" << std::endl;
|
|
|
|
for (auto format : mSwapchainFormats)
|
|
{
|
|
ss << " Enum=" << std::dec << format << " (0x=" << std::hex << format << ")" << std::dec << std::endl;
|
|
}
|
|
|
|
Log(Debug::Verbose) << ss.str();
|
|
|
|
return session;
|
|
}
|
|
|
|
/*
|
|
* For reference: These are the DXGI formats offered by WMR when using D3D11:
|
|
Enum=29 //(0x=1d) DXGI_FORMAT_R8G8B8A8_UNORM_SRGB
|
|
Enum=91 //(0x=5b) DXGI_FORMAT_B8G8R8A8_UNORM_SRGB
|
|
Enum=28 //(0x=1c) DXGI_FORMAT_R8G8B8A8_UNORM
|
|
Enum=87 //(0x=57) DXGI_FORMAT_B8G8R8A8_UNORM
|
|
Enum=40 //(0x=28) DXGI_FORMAT_D32_FLOAT
|
|
Enum=20 //(0x=14) DXGI_FORMAT_D32_FLOAT_S8X24_UINT
|
|
Enum=45 //(0x=2d) DXGI_FORMAT_D24_UNORM_S8_UINT
|
|
Enum=55 //(0x=37) DXGI_FORMAT_D16_UNORM
|
|
* And these extra formats are offered by SteamVR:
|
|
0xa , // DXGI_FORMAT_R16G16B16A16_FLOAT
|
|
0x18 , // DXGI_FORMAT_R10G10B10A2_UNORM
|
|
*/
|
|
|
|
int64_t OpenXRPlatform::selectColorFormat()
|
|
{
|
|
std::string graphicsAPIExtension = graphicsAPIExtensionName();
|
|
if (graphicsAPIExtension == XR_KHR_OPENGL_ENABLE_EXTENSION_NAME)
|
|
{
|
|
std::vector<int64_t> requestedColorSwapchainFormats;
|
|
|
|
if (Settings::Manager::getBool("Prefer sRGB swapchains", "VR"))
|
|
{
|
|
requestedColorSwapchainFormats.push_back(0x8C43); // GL_SRGB8_ALPHA8
|
|
requestedColorSwapchainFormats.push_back(0x8C41); // GL_SRGB8
|
|
}
|
|
|
|
requestedColorSwapchainFormats.push_back(0x8058); // GL_RGBA8
|
|
requestedColorSwapchainFormats.push_back(0x8F97); // GL_RGBA8_SNORM
|
|
requestedColorSwapchainFormats.push_back(0x881A); // GL_RGBA16F
|
|
requestedColorSwapchainFormats.push_back(0x881B); // GL_RGB16F
|
|
requestedColorSwapchainFormats.push_back(0x8C3A); // GL_R11F_G11F_B10F
|
|
|
|
return selectFormat(requestedColorSwapchainFormats);
|
|
}
|
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
|
else if (graphicsAPIExtension == XR_KHR_D3D11_ENABLE_EXTENSION_NAME)
|
|
{
|
|
std::vector<int64_t> requestedColorSwapchainFormats;
|
|
|
|
if (Settings::Manager::getBool("Prefer sRGB swapchains", "VR"))
|
|
{
|
|
requestedColorSwapchainFormats.push_back(0x1d); // DXGI_FORMAT_R8G8B8A8_UNORM_SRGB
|
|
requestedColorSwapchainFormats.push_back(0x5b); // DXGI_FORMAT_B8G8R8A8_UNORM_SRGB
|
|
}
|
|
|
|
requestedColorSwapchainFormats.push_back(0x1c); // DXGI_FORMAT_R8G8B8A8_UNORM
|
|
requestedColorSwapchainFormats.push_back(0x57); // DXGI_FORMAT_B8G8R8A8_UNORM
|
|
requestedColorSwapchainFormats.push_back(0xa); // DXGI_FORMAT_R16G16B16A16_FLOAT
|
|
requestedColorSwapchainFormats.push_back(0x18); // DXGI_FORMAT_R10G10B10A2_UNORM
|
|
|
|
return selectFormat(requestedColorSwapchainFormats);
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
throw std::logic_error("Enum value not implemented");
|
|
}
|
|
|
|
}
|
|
|
|
int64_t OpenXRPlatform::selectDepthFormat()
|
|
{
|
|
std::string graphicsAPIExtension = graphicsAPIExtensionName();
|
|
if (graphicsAPIExtension == XR_KHR_OPENGL_ENABLE_EXTENSION_NAME)
|
|
{
|
|
// Find supported depth swapchain format.
|
|
std::vector<int64_t> requestedDepthSwapchainFormats = {
|
|
0x88F0, // GL_DEPTH24_STENCIL8
|
|
0x8CAC, // GL_DEPTH_COMPONENT32F
|
|
0x81A7, // GL_DEPTH_COMPONENT32
|
|
0x8DAB, // GL_DEPTH_COMPONENT32F_NV
|
|
0x8CAD, // GL_DEPTH32_STENCIL8
|
|
0x81A6, // GL_DEPTH_COMPONENT24
|
|
// Need 32bit minimum: // 0x81A5, // GL_DEPTH_COMPONENT16
|
|
};
|
|
|
|
return selectFormat(requestedDepthSwapchainFormats);
|
|
}
|
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
|
else if (graphicsAPIExtension == XR_KHR_D3D11_ENABLE_EXTENSION_NAME)
|
|
{
|
|
// Find supported color swapchain format.
|
|
std::vector<int64_t> requestedDepthSwapchainFormats = {
|
|
0x2d, // DXGI_FORMAT_D24_UNORM_S8_UINT
|
|
0x14, // DXGI_FORMAT_D32_FLOAT_S8X24_UINT
|
|
0x28, // DXGI_FORMAT_D32_FLOAT
|
|
// Need 32bit minimum: 0x37, // DXGI_FORMAT_D16_UNORM
|
|
};
|
|
return selectFormat(requestedDepthSwapchainFormats);
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
throw std::logic_error("Enum value not implemented");
|
|
}
|
|
}
|
|
|
|
void OpenXRPlatform::eraseFormat(int64_t format)
|
|
{
|
|
for (auto it = mSwapchainFormats.begin(); it != mSwapchainFormats.end(); it++)
|
|
{
|
|
if (*it == format)
|
|
{
|
|
mSwapchainFormats.erase(it);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
int64_t OpenXRPlatform::selectFormat(const std::vector<int64_t>& requestedFormats)
|
|
{
|
|
auto it =
|
|
std::find_first_of(std::begin(requestedFormats), std::end(requestedFormats),
|
|
mSwapchainFormats.begin(), mSwapchainFormats.end());
|
|
if (it == std::end(requestedFormats))
|
|
{
|
|
return 0;
|
|
}
|
|
return *it;
|
|
}
|
|
void* OpenXRPlatform::DXRegisterObject(void* dxResource, uint32_t glName, uint32_t glType, bool discard, void* ntShareHandle)
|
|
{
|
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
|
if (ntShareHandle)
|
|
{
|
|
mPrivate->wglDXSetResourceShareHandleNV(dxResource, ntShareHandle);
|
|
}
|
|
return mPrivate->wglDXRegisterObjectNV(mPrivate->wglDXDevice, dxResource, glName, glType, 1);
|
|
#else
|
|
return nullptr;
|
|
#endif
|
|
}
|
|
void OpenXRPlatform::DXUnregisterObject(void* dxResourceShareHandle)
|
|
{
|
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
|
mPrivate->wglDXUnregisterObjectNV(mPrivate->wglDXDevice, dxResourceShareHandle);
|
|
#endif
|
|
}
|
|
void OpenXRPlatform::DXLockObject(void* dxResourceShareHandle)
|
|
{
|
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
|
mPrivate->wglDXLockObjectsNV(mPrivate->wglDXDevice, 1, &dxResourceShareHandle);
|
|
#endif
|
|
}
|
|
void OpenXRPlatform::DXUnlockObject(void* dxResourceShareHandle)
|
|
{
|
|
#ifdef XR_USE_GRAPHICS_API_D3D11
|
|
mPrivate->wglDXUnlockObjectsNV(mPrivate->wglDXDevice, 1, &dxResourceShareHandle);
|
|
#endif
|
|
}
|
|
|
|
static XrInstanceProperties
|
|
getInstanceProperties(XrInstance instance)
|
|
{
|
|
XrInstanceProperties properties{ XR_TYPE_INSTANCE_PROPERTIES };
|
|
if (instance)
|
|
xrGetInstanceProperties(instance, &properties);
|
|
return properties;
|
|
}
|
|
|
|
std::string OpenXRPlatform::getInstanceName(XrInstance instance)
|
|
{
|
|
if (instance)
|
|
return getInstanceProperties(instance).runtimeName;
|
|
return "unknown";
|
|
}
|
|
|
|
XrVersion OpenXRPlatform::getInstanceVersion(XrInstance instance)
|
|
{
|
|
if (instance)
|
|
return getInstanceProperties(instance).runtimeVersion;
|
|
return 0;
|
|
}
|
|
void OpenXRPlatform::initFailure(XrResult res, XrInstance instance)
|
|
{
|
|
std::stringstream ss;
|
|
std::string runtimeName = getInstanceName(instance);
|
|
XrVersion runtimeVersion = getInstanceVersion(instance);
|
|
ss << "Error caught while initializing VR device: " << XrResultString(res) << std::endl;
|
|
ss << "Device: " << runtimeName << std::endl;
|
|
ss << "Version: " << runtimeVersion << std::endl;
|
|
if (res == XR_ERROR_FORM_FACTOR_UNAVAILABLE)
|
|
{
|
|
ss << "Cause: Unable to open VR device. Make sure your device is plugged in and the VR driver is running." << std::endl;
|
|
ss << std::endl;
|
|
if (runtimeName == "Oculus" || runtimeName == "Quest")
|
|
{
|
|
ss << "Your device has been identified as an Oculus device." << std::endl;
|
|
ss << "The most common cause for this error when using an oculus device, is quest users attempting to run the game via Virtual Desktop." << std::endl;
|
|
ss << "Unfortunately this is currently broken, and quest users will need to play via a link cable." << std::endl;
|
|
}
|
|
}
|
|
else if (res == XR_ERROR_LIMIT_REACHED)
|
|
{
|
|
ss << "Cause: Device resources exhausted. Close other VR applications if you have any open. If you have none, you may need to reboot to reset the driver." << std::endl;
|
|
}
|
|
else
|
|
{
|
|
ss << "Cause: Unknown. Make sure your device is plugged in and ready." << std::endl;
|
|
}
|
|
throw std::runtime_error(ss.str());
|
|
}
|
|
}
|