diff --git a/src/dxvk/dxvk_openvr.cpp b/src/dxvk/dxvk_openvr.cpp index 5d15463a2..7b77923c0 100644 --- a/src/dxvk/dxvk_openvr.cpp +++ b/src/dxvk/dxvk_openvr.cpp @@ -7,9 +7,20 @@ #include +using VR_InitInternalProc = vr::IVRSystem* (VR_CALLTYPE *)(vr::EVRInitError*, vr::EVRApplicationType); +using VR_ShutdownInternalProc = void (VR_CALLTYPE *)(); +using VR_GetGenericInterfaceProc = void* (VR_CALLTYPE *)(const char*, vr::EVRInitError*); + namespace dxvk { - VrInstance g_vrInstance; + struct VrFunctions { + VR_InitInternalProc initInternal = nullptr; + VR_ShutdownInternalProc shutdownInternal = nullptr; + VR_GetGenericInterfaceProc getGenericInterface = nullptr; + }; + + VrFunctions g_vrFunctions; + VrInstance g_vrInstance; VrInstance:: VrInstance() { } VrInstance::~VrInstance() { } @@ -34,15 +45,13 @@ namespace dxvk { void VrInstance::initInstanceExtensions() { std::lock_guard lock(m_mutex); - if (m_initializedInsExt) - return; - - vr::IVRCompositor* compositor = this->getCompositor(); + if (m_compositor == nullptr) + m_compositor = this->getCompositor(); - if (compositor == nullptr) + if (m_compositor == nullptr || m_initializedInsExt) return; - m_insExtensions = this->queryInstanceExtensions(compositor); + m_insExtensions = this->queryInstanceExtensions(); m_initializedInsExt = true; } @@ -50,40 +59,38 @@ namespace dxvk { void VrInstance::initDeviceExtensions(const DxvkInstance* instance) { std::lock_guard lock(m_mutex); - if (m_initializedDevExt) - return; - - vr::IVRCompositor* compositor = this->getCompositor(); - - if (compositor == nullptr) + if (m_compositor == nullptr || m_initializedDevExt) return; for (uint32_t i = 0; instance->enumAdapters(i) != nullptr; i++) { m_devExtensions.push_back(this->queryDeviceExtensions( - compositor, instance->enumAdapters(i)->handle())); + instance->enumAdapters(i)->handle())); } + if (m_initializedOpenVr) + g_vrFunctions.shutdownInternal(); + m_initializedDevExt = true; } - vk::NameSet VrInstance::queryInstanceExtensions(vr::IVRCompositor* compositor) const { - uint32_t len = compositor->GetVulkanInstanceExtensionsRequired(nullptr, 0); + vk::NameSet VrInstance::queryInstanceExtensions() const { + uint32_t len = m_compositor->GetVulkanInstanceExtensionsRequired(nullptr, 0); std::vector extensionList(len); - len = compositor->GetVulkanInstanceExtensionsRequired(extensionList.data(), len); + len = m_compositor->GetVulkanInstanceExtensionsRequired(extensionList.data(), len); return parseExtensionList(std::string(extensionList.data(), len)); } - vk::NameSet VrInstance::queryDeviceExtensions(vr::IVRCompositor* compositor, VkPhysicalDevice adapter) const { - uint32_t len = compositor->GetVulkanDeviceExtensionsRequired(adapter, nullptr, 0); + vk::NameSet VrInstance::queryDeviceExtensions(VkPhysicalDevice adapter) const { + uint32_t len = m_compositor->GetVulkanDeviceExtensionsRequired(adapter, nullptr, 0); std::vector extensionList(len); - len = compositor->GetVulkanDeviceExtensionsRequired(adapter, extensionList.data(), len); + len = m_compositor->GetVulkanDeviceExtensionsRequired(adapter, extensionList.data(), len); return parseExtensionList(std::string(extensionList.data(), len)); } - vk::NameSet VrInstance::parseExtensionList(const std::string& str) { + vk::NameSet VrInstance::parseExtensionList(const std::string& str) const { vk::NameSet result; std::stringstream strstream(str); @@ -97,9 +104,6 @@ namespace dxvk { vr::IVRCompositor* VrInstance::getCompositor() { - using GetGenericInterfaceProc = - void* (VR_CALLTYPE *)(const char*, vr::EVRInitError*); - // Locate the OpenVR DLL if loaded by the process HMODULE ovrApi = ::GetModuleHandle("openvr_api.dll"); @@ -109,10 +113,11 @@ namespace dxvk { } // Load method used to retrieve the IVRCompositor interface - auto vrGetGenericInterface = reinterpret_cast( - ::GetProcAddress(ovrApi, "VR_GetGenericInterface")); + g_vrFunctions.initInternal = reinterpret_cast (::GetProcAddress(ovrApi, "VR_InitInternal")); + g_vrFunctions.shutdownInternal = reinterpret_cast (::GetProcAddress(ovrApi, "VR_ShutdownInternal")); + g_vrFunctions.getGenericInterface = reinterpret_cast(::GetProcAddress(ovrApi, "VR_GetGenericInterface")); - if (vrGetGenericInterface == nullptr) { + if (g_vrFunctions.getGenericInterface == nullptr) { Logger::warn("OpenVR: VR_GetGenericInterface not found"); return nullptr; } @@ -120,15 +125,38 @@ namespace dxvk { // Retrieve the compositor interface vr::EVRInitError error = vr::VRInitError_None; - auto compositor = reinterpret_cast( - vrGetGenericInterface(vr::IVRCompositor_Version, &error)); + vr::IVRCompositor* compositor = reinterpret_cast( + g_vrFunctions.getGenericInterface(vr::IVRCompositor_Version, &error)); - if (error != vr::VRInitError_None) { - Logger::warn(str::format("OpenVR: Failed to retrieve ", vr::IVRCompositor_Version)); - return nullptr; + if (error != vr::VRInitError_None || compositor == nullptr) { + if (g_vrFunctions.initInternal == nullptr + || g_vrFunctions.shutdownInternal == nullptr) { + Logger::warn("OpenVR: VR_InitInternal or VR_ShutdownInternal not found"); + return nullptr; + } + + // If the app has not initialized OpenVR yet, we need + // to do it now in order to grab a compositor instance + g_vrFunctions.initInternal(&error, vr::VRApplication_Background); + m_initializedOpenVr = error == vr::VRInitError_None; + + if (error != vr::VRInitError_None) { + Logger::warn("OpenVR: Failed to initialize OpenVR"); + return nullptr; + } + + compositor = reinterpret_cast( + g_vrFunctions.getGenericInterface(vr::IVRCompositor_Version, &error)); + + if (error != vr::VRInitError_None || compositor == nullptr) { + Logger::warn("OpenVR: Failed to query compositor interface"); + g_vrFunctions.shutdownInternal(); + m_initializedOpenVr = false; + return nullptr; + } } - Logger::warn("OpenVR: Compositor interface found"); + Logger::info("OpenVR: Compositor interface found"); return compositor; } diff --git a/src/dxvk/dxvk_openvr.h b/src/dxvk/dxvk_openvr.h index 16dfbb1f1..2d33aa3fe 100644 --- a/src/dxvk/dxvk_openvr.h +++ b/src/dxvk/dxvk_openvr.h @@ -7,12 +7,13 @@ namespace vr { class IVRCompositor; + class IVRSystem; } namespace dxvk { class DxvkInstance; - + /** * \brief OpenVR instance * @@ -63,24 +64,25 @@ namespace dxvk { private: - std::mutex m_mutex; + std::mutex m_mutex; + vr::IVRCompositor* m_compositor = nullptr; + bool m_initializedOpenVr = false; bool m_initializedInsExt = false; bool m_initializedDevExt = false; vk::NameSet m_insExtensions; std::vector m_devExtensions; - vk::NameSet queryInstanceExtensions( - vr::IVRCompositor* compositor) const; + vk::NameSet queryInstanceExtensions() const; vk::NameSet queryDeviceExtensions( - vr::IVRCompositor* compositor, VkPhysicalDevice adapter) const; - static vk::NameSet parseExtensionList(const std::string& str); + vk::NameSet parseExtensionList( + const std::string& str) const; - static vr::IVRCompositor* getCompositor(); + vr::IVRCompositor* getCompositor(); };