Skip to content

Commit

Permalink
[dxvk] Use wineopenxr to apply required OpenXR extensions
Browse files Browse the repository at this point in the history
  • Loading branch information
aeikum authored and doitsujin committed Jan 7, 2021
1 parent a3065fc commit 2405e47
Show file tree
Hide file tree
Showing 6 changed files with 252 additions and 0 deletions.
4 changes: 4 additions & 0 deletions src/dxvk/dxvk_instance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "dxvk_instance.h"
#include "dxvk_openvr.h"
#include "dxvk_openxr.h"
#include "dxvk_platform_exts.h"

#include <algorithm>
Expand All @@ -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()));
Expand Down
168 changes: 168 additions & 0 deletions src/dxvk/dxvk_openxr.cpp
Original file line number Diff line number Diff line change
@@ -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<std::mutex> lock(m_mutex);
return m_insExtensions;
}


DxvkNameSet DxvkXrProvider::getDeviceExtensions(uint32_t adapterId) {
std::lock_guard<std::mutex> lock(m_mutex);
return m_devExtensions;
}


void DxvkXrProvider::initInstanceExtensions() {
std::lock_guard<std::mutex> 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<PFN___wineopenxr_GetVulkanInstanceExtensions>(this->getSym("__wineopenxr_GetVulkanInstanceExtensions"));
g_winexrFunctions.__wineopenxr_GetVulkanDeviceExtensions =
reinterpret_cast<PFN___wineopenxr_GetVulkanDeviceExtensions>(this->getSym("__wineopenxr_GetVulkanDeviceExtensions"));
return g_winexrFunctions.__wineopenxr_GetVulkanInstanceExtensions != nullptr
&& g_winexrFunctions.__wineopenxr_GetVulkanDeviceExtensions != nullptr;
}


void DxvkXrProvider::initDeviceExtensions(const DxvkInstance* instance) {
std::lock_guard<std::mutex> 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<char> 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<char> 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<void*>(
::GetProcAddress(m_wineOxr, sym));
}
}
75 changes: 75 additions & 0 deletions src/dxvk/dxvk_openxr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#pragma once

#include <mutex>
#include <vector>

#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);

};

}
1 change: 1 addition & 0 deletions src/dxvk/dxvk_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace dxvk {
DxvkOptions::DxvkOptions(const Config& config) {
enableStateCache = config.getOption<bool> ("dxvk.enableStateCache", true);
enableOpenVR = config.getOption<bool> ("dxvk.enableOpenVR", true);
enableOpenXR = config.getOption<bool> ("dxvk.enableOpenXR", true);
numCompilerThreads = config.getOption<int32_t> ("dxvk.numCompilerThreads", 0);
useRawSsbo = config.getOption<Tristate>("dxvk.useRawSsbo", Tristate::Auto);
useEarlyDiscard = config.getOption<Tristate>("dxvk.useEarlyDiscard", Tristate::Auto);
Expand Down
3 changes: 3 additions & 0 deletions src/dxvk/dxvk_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions src/dxvk/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down

0 comments on commit 2405e47

Please sign in to comment.