From 2405e474e5a102327d2e33e7c18ae160c720c23e Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Mon, 4 Jan 2021 14:33:11 -0600 Subject: [PATCH] [dxvk] Use wineopenxr to apply required OpenXR extensions --- src/dxvk/dxvk_instance.cpp | 4 + src/dxvk/dxvk_openxr.cpp | 168 +++++++++++++++++++++++++++++++++++++ src/dxvk/dxvk_openxr.h | 75 +++++++++++++++++ src/dxvk/dxvk_options.cpp | 1 + src/dxvk/dxvk_options.h | 3 + src/dxvk/meson.build | 1 + 6 files changed, 252 insertions(+) create mode 100644 src/dxvk/dxvk_openxr.cpp create mode 100644 src/dxvk/dxvk_openxr.h diff --git a/src/dxvk/dxvk_instance.cpp b/src/dxvk/dxvk_instance.cpp index a6f5b921..8fe3d52c 100644 --- a/src/dxvk/dxvk_instance.cpp +++ b/src/dxvk/dxvk_instance.cpp @@ -2,6 +2,7 @@ #include "dxvk_instance.h" #include "dxvk_openvr.h" +#include "dxvk_openxr.h" #include "dxvk_platform_exts.h" #include @@ -23,6 +24,9 @@ namespace dxvk { if (m_options.enableOpenVR) m_extProviders.push_back(&VrInstance::s_instance); + if (m_options.enableOpenXR) + m_extProviders.push_back(&DxvkXrProvider::s_instance); + Logger::info("Built-in extension providers:"); for (const auto& provider : m_extProviders) Logger::info(str::format(" ", provider->getName())); diff --git a/src/dxvk/dxvk_openxr.cpp b/src/dxvk/dxvk_openxr.cpp new file mode 100644 index 00000000..d632b989 --- /dev/null +++ b/src/dxvk/dxvk_openxr.cpp @@ -0,0 +1,168 @@ +#include "dxvk_instance.h" +#include "dxvk_openxr.h" + +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +#endif + +using PFN___wineopenxr_GetVulkanInstanceExtensions = int (WINAPI *)(uint32_t, uint32_t *, char *); +using PFN___wineopenxr_GetVulkanDeviceExtensions = int (WINAPI *)(uint32_t, uint32_t *, char *); + +namespace dxvk { + + struct WineXrFunctions { + PFN___wineopenxr_GetVulkanInstanceExtensions __wineopenxr_GetVulkanInstanceExtensions = nullptr; + PFN___wineopenxr_GetVulkanDeviceExtensions __wineopenxr_GetVulkanDeviceExtensions = nullptr; + }; + + WineXrFunctions g_winexrFunctions; + DxvkXrProvider DxvkXrProvider::s_instance; + + DxvkXrProvider:: DxvkXrProvider() { } + + DxvkXrProvider::~DxvkXrProvider() { } + + + std::string_view DxvkXrProvider::getName() { + return "OpenXR"; + } + + + DxvkNameSet DxvkXrProvider::getInstanceExtensions() { + std::lock_guard lock(m_mutex); + return m_insExtensions; + } + + + DxvkNameSet DxvkXrProvider::getDeviceExtensions(uint32_t adapterId) { + std::lock_guard lock(m_mutex); + return m_devExtensions; + } + + + void DxvkXrProvider::initInstanceExtensions() { + std::lock_guard lock(m_mutex); + + if (!m_wineOxr) + m_wineOxr = this->loadLibrary(); + + if (!m_wineOxr || m_initializedInsExt) + return; + + if (!this->loadFunctions()) { + this->shutdown(); + return; + } + + m_insExtensions = this->queryInstanceExtensions(); + m_initializedInsExt = true; + } + + + bool DxvkXrProvider::loadFunctions() { + g_winexrFunctions.__wineopenxr_GetVulkanInstanceExtensions = + reinterpret_cast(this->getSym("__wineopenxr_GetVulkanInstanceExtensions")); + g_winexrFunctions.__wineopenxr_GetVulkanDeviceExtensions = + reinterpret_cast(this->getSym("__wineopenxr_GetVulkanDeviceExtensions")); + return g_winexrFunctions.__wineopenxr_GetVulkanInstanceExtensions != nullptr + && g_winexrFunctions.__wineopenxr_GetVulkanDeviceExtensions != nullptr; + } + + + void DxvkXrProvider::initDeviceExtensions(const DxvkInstance* instance) { + std::lock_guard lock(m_mutex); + + if (!m_wineOxr || m_initializedDevExt) + return; + + m_devExtensions = this->queryDeviceExtensions(); + m_initializedDevExt = true; + + this->shutdown(); + } + + + DxvkNameSet DxvkXrProvider::queryInstanceExtensions() const { + int res; + uint32_t len; + + res = g_winexrFunctions.__wineopenxr_GetVulkanInstanceExtensions(0, &len, nullptr); + if (res != 0) { + Logger::warn("OpenXR: Unable to get required Vulkan instance extensions size"); + return DxvkNameSet(); + } + + std::vector extensionList(len); + res = g_winexrFunctions.__wineopenxr_GetVulkanInstanceExtensions(len, &len, &extensionList[0]); + if (res != 0) { + Logger::warn("OpenXR: Unable to get required Vulkan instance extensions"); + return DxvkNameSet(); + } + + return parseExtensionList(std::string(extensionList.data(), len)); + } + + + DxvkNameSet DxvkXrProvider::queryDeviceExtensions() const { + int res; + + uint32_t len; + res = g_winexrFunctions.__wineopenxr_GetVulkanDeviceExtensions(0, &len, nullptr); + if (res != 0) { + Logger::warn("OpenXR: Unable to get required Vulkan Device extensions size"); + return DxvkNameSet(); + } + + std::vector extensionList(len); + res = g_winexrFunctions.__wineopenxr_GetVulkanDeviceExtensions(len, &len, &extensionList[0]); + if (res != 0) { + Logger::warn("OpenXR: Unable to get required Vulkan Device extensions"); + return DxvkNameSet(); + } + + return parseExtensionList(std::string(extensionList.data(), len)); + } + + + DxvkNameSet DxvkXrProvider::parseExtensionList(const std::string& str) const { + DxvkNameSet result; + + std::stringstream strstream(str); + std::string section; + + while (std::getline(strstream, section, ' ')) + result.add(section.c_str()); + + return result; + } + + + void DxvkXrProvider::shutdown() { + if (m_loadedOxrApi) + this->freeLibrary(); + + m_loadedOxrApi = false; + m_wineOxr = nullptr; + } + + + SoHandle DxvkXrProvider::loadLibrary() { + SoHandle handle = nullptr; + if (!(handle = ::GetModuleHandle("wineopenxr.dll"))) { + handle = ::LoadLibrary("wineopenxr.dll"); + m_loadedOxrApi = handle != nullptr; + } + return handle; + } + + + void DxvkXrProvider::freeLibrary() { + ::FreeLibrary(m_wineOxr); + } + + + void* DxvkXrProvider::getSym(const char* sym) { + return reinterpret_cast( + ::GetProcAddress(m_wineOxr, sym)); + } +} diff --git a/src/dxvk/dxvk_openxr.h b/src/dxvk/dxvk_openxr.h new file mode 100644 index 00000000..785abcea --- /dev/null +++ b/src/dxvk/dxvk_openxr.h @@ -0,0 +1,75 @@ +#pragma once + +#include +#include + +#include "dxvk_extension_provider.h" + +#ifdef __WINE__ +using SoHandle = void*; +#else +using SoHandle = HMODULE; +#endif + +namespace dxvk { + + class DxvkInstance; + + /** + * \brief OpenXR instance + * + * Loads OpenXR to provide access to Vulkan extension queries. + */ + class DxvkXrProvider : public DxvkExtensionProvider { + + public: + + DxvkXrProvider(); + ~DxvkXrProvider(); + + std::string_view getName(); + + DxvkNameSet getInstanceExtensions(); + + DxvkNameSet getDeviceExtensions( + uint32_t adapterId); + + void initInstanceExtensions(); + + void initDeviceExtensions( + const DxvkInstance* instance); + + static DxvkXrProvider s_instance; + + private: + + std::mutex m_mutex; + SoHandle m_wineOxr = nullptr; + + bool m_loadedOxrApi = false; + bool m_initializedInsExt = false; + bool m_initializedDevExt = false; + + DxvkNameSet m_insExtensions; + DxvkNameSet m_devExtensions; + + DxvkNameSet queryInstanceExtensions() const; + + DxvkNameSet queryDeviceExtensions() const; + + DxvkNameSet parseExtensionList( + const std::string& str) const; + + bool loadFunctions(); + + void shutdown(); + + SoHandle loadLibrary(); + + void freeLibrary(); + + void* getSym(const char* sym); + + }; + +} \ No newline at end of file diff --git a/src/dxvk/dxvk_options.cpp b/src/dxvk/dxvk_options.cpp index 904082f6..73dd69d1 100644 --- a/src/dxvk/dxvk_options.cpp +++ b/src/dxvk/dxvk_options.cpp @@ -5,6 +5,7 @@ namespace dxvk { DxvkOptions::DxvkOptions(const Config& config) { enableStateCache = config.getOption ("dxvk.enableStateCache", true); enableOpenVR = config.getOption ("dxvk.enableOpenVR", true); + enableOpenXR = config.getOption ("dxvk.enableOpenXR", true); numCompilerThreads = config.getOption ("dxvk.numCompilerThreads", 0); useRawSsbo = config.getOption("dxvk.useRawSsbo", Tristate::Auto); useEarlyDiscard = config.getOption("dxvk.useEarlyDiscard", Tristate::Auto); diff --git a/src/dxvk/dxvk_options.h b/src/dxvk/dxvk_options.h index 6843c16f..3c5dde91 100644 --- a/src/dxvk/dxvk_options.h +++ b/src/dxvk/dxvk_options.h @@ -14,6 +14,9 @@ namespace dxvk { /// Enables OpenVR loading bool enableOpenVR; + /// Enables OpenXR loading + bool enableOpenXR; + /// Number of compiler threads /// when using the state cache int32_t numCompilerThreads; diff --git a/src/dxvk/meson.build b/src/dxvk/meson.build index 1dc113c3..d1785d75 100644 --- a/src/dxvk/meson.build +++ b/src/dxvk/meson.build @@ -81,6 +81,7 @@ dxvk_src = files([ 'dxvk_meta_pack.cpp', 'dxvk_meta_resolve.cpp', 'dxvk_openvr.cpp', + 'dxvk_openxr.cpp', 'dxvk_options.cpp', 'dxvk_pipecache.cpp', 'dxvk_pipelayout.cpp',