#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 #include #ifdef XR_USE_GRAPHICS_API_D3D11 #include #endif #elif __linux__ #include #include #undef None #else #error Unsupported platform #endif #include #include #include #include #include #include #include #include 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 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 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(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(wglGetProcAddress("wglDXOpenDeviceNV")); //P_wglDXOpenDeviceNV wglDXOpenDeviceNV = reinterpret_cast(wglGetProcAddress("wglDXOpenDeviceNV")); #define LOAD_WGL(a) a = reinterpret_cast(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(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 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 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(&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(&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(&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 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 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 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 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& 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()); } }