1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-05 01:24:14 +01:00

[dxvk] Rework instance creation

Allows importing foreign Vulkan instances.
This commit is contained in:
Philip Rebohle 2023-03-14 15:34:12 +01:00
parent f50f5bc9bc
commit ef9d5048f3
5 changed files with 217 additions and 99 deletions

View File

@ -393,7 +393,7 @@ namespace dxvk {
if (!m_deviceExtensions.enableExtensions( if (!m_deviceExtensions.enableExtensions(
devExtensionList.size(), devExtensionList.size(),
devExtensionList.data(), devExtensionList.data(),
extensionsEnabled)) &extensionsEnabled))
throw DxvkError("DxvkAdapter: Failed to create device"); throw DxvkError("DxvkAdapter: Failed to create device");
// Enable additional extensions if necessary // Enable additional extensions if necessary

View File

@ -2,8 +2,22 @@
namespace dxvk { namespace dxvk {
DxvkNameSet::DxvkNameSet() { } DxvkNameSet::DxvkNameSet() {
DxvkNameSet::~DxvkNameSet() { }
}
DxvkNameSet::DxvkNameSet(
uint32_t count,
const char* const* names) {
for (uint32_t i = 0; i < count; i++)
add(names[i]);
}
DxvkNameSet::~DxvkNameSet() {
}
void DxvkNameSet::add(const char* pName) { void DxvkNameSet::add(const char* pName) {
@ -17,6 +31,13 @@ namespace dxvk {
} }
void DxvkNameSet::mergeRevisions(
const DxvkNameSet& names) {
for (auto& pair : m_names)
pair.second = names.supports(pair.first.c_str());
}
uint32_t DxvkNameSet::supports(const char* pName) const { uint32_t DxvkNameSet::supports(const char* pName) const {
auto entry = m_names.find(pName); auto entry = m_names.find(pName);
@ -32,7 +53,7 @@ namespace dxvk {
bool DxvkNameSet::enableExtensions( bool DxvkNameSet::enableExtensions(
uint32_t numExtensions, uint32_t numExtensions,
DxvkExt** ppExtensions, DxvkExt** ppExtensions,
DxvkNameSet& nameSet) const { DxvkNameSet* nameSet) const {
bool allRequiredEnabled = true; bool allRequiredEnabled = true;
for (uint32_t i = 0; i < numExtensions; i++) { for (uint32_t i = 0; i < numExtensions; i++) {
@ -44,8 +65,8 @@ namespace dxvk {
uint32_t revision = supports(ext->name()); uint32_t revision = supports(ext->name());
if (revision) { if (revision) {
if (ext->mode() != DxvkExtMode::Passive) if (nameSet && ext->mode() != DxvkExtMode::Passive)
nameSet.add(ext->name()); nameSet->add(ext->name());
ext->enable(revision); ext->enable(revision);
} else if (ext->mode() == DxvkExtMode::Required) { } else if (ext->mode() == DxvkExtMode::Required) {
@ -68,8 +89,10 @@ namespace dxvk {
DxvkNameList DxvkNameSet::toNameList() const { DxvkNameList DxvkNameSet::toNameList() const {
DxvkNameList nameList; DxvkNameList nameList;
for (const auto& pair : m_names) for (const auto& pair : m_names) {
nameList.add(pair.first.c_str()); if (pair.second)
nameList.add(pair.first.c_str());
}
return nameList; return nameList;
} }

View File

@ -117,6 +117,12 @@ namespace dxvk {
public: public:
DxvkNameList() { }
DxvkNameList(uint32_t count, const char* const* names) {
for (uint32_t i = 0; i < count; i++)
add(names[i]);
}
/** /**
* \brief Adds a name * \brief Adds a name
* \param [in] pName The name * \param [in] pName The name
@ -169,6 +175,11 @@ namespace dxvk {
public: public:
DxvkNameSet(); DxvkNameSet();
DxvkNameSet(
uint32_t count,
const char* const* names);
~DxvkNameSet(); ~DxvkNameSet();
/** /**
@ -188,6 +199,13 @@ namespace dxvk {
void merge( void merge(
const DxvkNameSet& names); const DxvkNameSet& names);
/**
* \brief Pulls in revisions from another name set
* \param [in] names Name set to pull revisions from
*/
void mergeRevisions(
const DxvkNameSet& names);
/** /**
* \brief Checks whether an extension is supported * \brief Checks whether an extension is supported
* *
@ -212,7 +230,7 @@ namespace dxvk {
bool enableExtensions( bool enableExtensions(
uint32_t numExtensions, uint32_t numExtensions,
DxvkExt** ppExtensions, DxvkExt** ppExtensions,
DxvkNameSet& nameSet) const; DxvkNameSet* nameSet) const;
/** /**
* \brief Disables given extension * \brief Disables given extension

View File

@ -10,7 +10,13 @@
namespace dxvk { namespace dxvk {
DxvkInstance::DxvkInstance() { DxvkInstance::DxvkInstance()
: DxvkInstance(DxvkInstanceImportInfo()) {
}
DxvkInstance::DxvkInstance(const DxvkInstanceImportInfo& args) {
Logger::info(str::format("Game: ", env::getExeName())); Logger::info(str::format("Game: ", env::getExeName()));
Logger::info(str::format("DXVK: ", DXVK_VERSION)); Logger::info(str::format("DXVK: ", DXVK_VERSION));
@ -20,6 +26,13 @@ namespace dxvk {
m_options = DxvkOptions(m_config); m_options = DxvkOptions(m_config);
// Load Vulkan library
createLibraryLoader(args);
if (!m_vkl->valid())
throw DxvkError("Failed to load vulkan-1 library.");
// Initialize extension providers
m_extProviders.push_back(&DxvkPlatformExts::s_instance); m_extProviders.push_back(&DxvkPlatformExts::s_instance);
#ifdef _WIN32 #ifdef _WIN32
m_extProviders.push_back(&VrInstance::s_instance); m_extProviders.push_back(&VrInstance::s_instance);
@ -33,24 +46,7 @@ namespace dxvk {
for (const auto& provider : m_extProviders) for (const auto& provider : m_extProviders)
provider->initInstanceExtensions(); provider->initInstanceExtensions();
m_vkl = new vk::LibraryFn(); createInstanceLoader(args);
if (!m_vkl->valid())
throw DxvkError("Failed to load vulkan-1 library.");
m_vki = new vk::InstanceFn(m_vkl, true, this->createInstance());
if (m_enableValidation) {
VkDebugUtilsMessengerCreateInfoEXT messengerInfo = { VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT };
messengerInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT
| VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
| VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
messengerInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT
| VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
messengerInfo.pfnUserCallback = &debugCallback;
if (m_vki->vkCreateDebugUtilsMessengerEXT(m_vki->instance(), &messengerInfo, nullptr, &m_messenger))
Logger::err("DxvkInstance::createInstance: Failed to create debug messenger, proceeding without.");
}
m_adapters = this->queryAdapters(); m_adapters = this->queryAdapters();
for (const auto& provider : m_extProviders) for (const auto& provider : m_extProviders)
@ -103,85 +99,137 @@ namespace dxvk {
} }
VkInstance DxvkInstance::createInstance() { void DxvkInstance::createLibraryLoader(const DxvkInstanceImportInfo& args) {
DxvkInstanceExtensions insExtensions; m_vkl = args.loaderProc
? new vk::LibraryFn(args.loaderProc)
: new vk::LibraryFn();
}
std::vector<DxvkExt*> insExtensionList = {{
&insExtensions.khrGetSurfaceCapabilities2,
&insExtensions.khrSurface,
}};
// Hide VK_EXT_debug_utils behind an environment variable. This extension void DxvkInstance::createInstanceLoader(const DxvkInstanceImportInfo& args) {
// adds additional overhead to winevulkan DxvkNameList layerList;
std::string debugEnv = env::getEnvVar("DXVK_DEBUG"); DxvkNameList extensionList;
DxvkNameList layerNameList; DxvkNameSet extensionSet;
m_enablePerfEvents = debugEnv == "markers"; bool enablePerfEvents = false;
m_enableValidation = debugEnv == "validation"; bool enableValidation = false;
if (m_enablePerfEvents || m_enableValidation || m_options.enableDebugUtils) { if (args.instance) {
insExtensionList.push_back(&insExtensions.extDebugUtils); extensionList = DxvkNameList(args.extensionCount, args.extensionNames);
Logger::warn("Debug Utils are enabled. May affect performance."); extensionSet = getExtensionSet(extensionList);
if (m_enableValidation) { auto extensionInfos = getExtensionList(m_extensions, true);
const char* layerName = "VK_LAYER_KHRONOS_validation";
DxvkNameSet layers = DxvkNameSet::enumInstanceLayers(m_vkl);
if (layers.supports(layerName)) { if (!extensionSet.enableExtensions(extensionInfos.size(), extensionInfos.data(), nullptr))
layerNameList.add(layerName); throw DxvkError("DxvkInstance: Required instance extensions not enabled");
Logger::warn(str::format("Enabled instance layer ", layerName)); } else {
} else { // Hide VK_EXT_debug_utils behind an environment variable.
// This can happen on winevulkan since it does not support layers // This extension adds additional overhead to winevulkan.
Logger::warn(str::format("Validation layers not found, set VK_INSTANCE_LAYERS=", layerName)); std::string debugEnv = env::getEnvVar("DXVK_DEBUG");
enablePerfEvents = debugEnv == "markers";
enableValidation = debugEnv == "validation";
bool enableDebug = enablePerfEvents || enableValidation || m_options.enableDebugUtils;
if (enableDebug) {
Logger::warn("Debug Utils are enabled. May affect performance.");
if (enableValidation) {
const char* layerName = "VK_LAYER_KHRONOS_validation";
DxvkNameSet layers = DxvkNameSet::enumInstanceLayers(m_vkl);
if (layers.supports(layerName)) {
layerList.add(layerName);
Logger::warn(str::format("Enabled instance layer ", layerName));
} else {
// This can happen on winevulkan since it does not support layers
Logger::warn(str::format("Validation layers not found, set VK_INSTANCE_LAYERS=", layerName));
}
} }
} }
// Get set of extensions to enable based on available
// extensions and extension providers.
auto extensionInfos = getExtensionList(m_extensions, enableDebug);
DxvkNameSet extensionsAvailable = DxvkNameSet::enumInstanceExtensions(m_vkl);
if (!extensionsAvailable.enableExtensions(extensionInfos.size(), extensionInfos.data(), &extensionSet))
throw DxvkError("DxvkInstance: Required instance extensions not supported");
for (const auto& provider : m_extProviders)
extensionSet.merge(provider->getInstanceExtensions());
// Generate list of extensions to enable
extensionList = extensionSet.toNameList();
} }
DxvkNameSet extensionsEnabled;
DxvkNameSet extensionsAvailable = DxvkNameSet::enumInstanceExtensions(m_vkl);
if (!extensionsAvailable.enableExtensions(
insExtensionList.size(),
insExtensionList.data(),
extensionsEnabled))
throw DxvkError("DxvkInstance: Failed to create instance");
m_extensions = insExtensions;
// Enable additional extensions if necessary
for (const auto& provider : m_extProviders)
extensionsEnabled.merge(provider->getInstanceExtensions());
DxvkNameList extensionNameList = extensionsEnabled.toNameList();
Logger::info("Enabled instance extensions:"); Logger::info("Enabled instance extensions:");
this->logNameList(extensionNameList); this->logNameList(extensionList);
std::string appName = env::getExeName(); // If necessary, create a new Vulkan instance
VkInstance instance = args.instance;
VkApplicationInfo appInfo = { VK_STRUCTURE_TYPE_APPLICATION_INFO };
appInfo.pApplicationName = appName.c_str();
appInfo.pEngineName = "DXVK";
appInfo.engineVersion = VK_MAKE_VERSION(2, 1, 0);
appInfo.apiVersion = VK_MAKE_VERSION(1, 3, 0);
VkInstanceCreateInfo info = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
info.pApplicationInfo = &appInfo;
info.enabledLayerCount = layerNameList.count();
info.ppEnabledLayerNames = layerNameList.names();
info.enabledExtensionCount = extensionNameList.count();
info.ppEnabledExtensionNames = extensionNameList.names();
VkInstance result = VK_NULL_HANDLE;
VkResult status = m_vkl->vkCreateInstance(&info, nullptr, &result);
if (status != VK_SUCCESS) if (!instance) {
throw DxvkError("DxvkInstance::createInstance: Failed to create Vulkan 1.1 instance"); std::string appName = env::getExeName();
VkApplicationInfo appInfo = { VK_STRUCTURE_TYPE_APPLICATION_INFO };
appInfo.pApplicationName = appName.c_str();
appInfo.pEngineName = "DXVK";
appInfo.engineVersion = VK_MAKE_VERSION(2, 1, 0);
appInfo.apiVersion = VK_MAKE_VERSION(1, 3, 0);
VkInstanceCreateInfo info = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
info.pApplicationInfo = &appInfo;
info.enabledLayerCount = layerList.count();
info.ppEnabledLayerNames = layerList.names();
info.enabledExtensionCount = extensionList.count();
info.ppEnabledExtensionNames = extensionList.names();
VkResult status = m_vkl->vkCreateInstance(&info, nullptr, &instance);
if (status != VK_SUCCESS)
throw DxvkError("DxvkInstance::createInstance: Failed to create Vulkan 1.1 instance");
}
// Create the Vulkan instance loader
m_vki = new vk::InstanceFn(m_vkl, !args.instance, instance);
if (enableValidation) {
VkDebugUtilsMessengerCreateInfoEXT messengerInfo = { VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT };
messengerInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT
| VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
| VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
messengerInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT
| VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
messengerInfo.pfnUserCallback = &debugCallback;
if (m_vki->vkCreateDebugUtilsMessengerEXT(m_vki->instance(), &messengerInfo, nullptr, &m_messenger))
Logger::err("DxvkInstance::createInstance: Failed to create debug messenger, proceeding without.");
}
}
std::vector<DxvkExt*> DxvkInstance::getExtensionList(DxvkInstanceExtensions& ext, bool withDebug) {
std::vector<DxvkExt*> result = {{
&ext.khrGetSurfaceCapabilities2,
&ext.khrSurface,
}};
if (withDebug)
result.push_back(&ext.extDebugUtils);
return result; return result;
} }
DxvkNameSet DxvkInstance::getExtensionSet(const DxvkNameList& extensions) {
DxvkNameSet enabledSet(extensions.count(), extensions.names());
enabledSet.mergeRevisions(DxvkNameSet::enumInstanceLayers(m_vkl));
return enabledSet;
}
std::vector<Rc<DxvkAdapter>> DxvkInstance::queryAdapters() { std::vector<Rc<DxvkAdapter>> DxvkInstance::queryAdapters() {
uint32_t numAdapters = 0; uint32_t numAdapters = 0;
if (m_vki->vkEnumeratePhysicalDevices(m_vki->instance(), &numAdapters, nullptr) != VK_SUCCESS) if (m_vki->vkEnumeratePhysicalDevices(m_vki->instance(), &numAdapters, nullptr) != VK_SUCCESS)

View File

@ -8,7 +8,18 @@
#include "dxvk_options.h" #include "dxvk_options.h"
namespace dxvk { namespace dxvk {
/**
* \brief Vulkan instance creation parameters
*/
struct DxvkInstanceImportInfo {
PFN_vkGetInstanceProcAddr loaderProc;
VkInstance instance;
uint32_t extensionCount;
const char** extensionNames;
};
/** /**
* \brief DXVK instance * \brief DXVK instance
* *
@ -19,8 +30,18 @@ namespace dxvk {
class DxvkInstance : public RcObject { class DxvkInstance : public RcObject {
public: public:
/**
* \brief Creates new Vulkan instance
*/
DxvkInstance(); DxvkInstance();
/**
* \brief Imports existing Vulkan instance
*/
explicit DxvkInstance(
const DxvkInstanceImportInfo& args);
~DxvkInstance(); ~DxvkInstance();
/** /**
@ -108,22 +129,30 @@ namespace dxvk {
private: private:
Config m_config; Config m_config;
DxvkOptions m_options; DxvkOptions m_options;
Rc<vk::LibraryFn> m_vkl; Rc<vk::LibraryFn> m_vkl;
Rc<vk::InstanceFn> m_vki; Rc<vk::InstanceFn> m_vki;
DxvkInstanceExtensions m_extensions; DxvkInstanceExtensions m_extensions;
bool m_enablePerfEvents = false;
bool m_enableValidation = false;
VkDebugUtilsMessengerEXT m_messenger = VK_NULL_HANDLE; VkDebugUtilsMessengerEXT m_messenger = VK_NULL_HANDLE;
std::vector<DxvkExtensionProvider*> m_extProviders; std::vector<DxvkExtensionProvider*> m_extProviders;
std::vector<Rc<DxvkAdapter>> m_adapters; std::vector<Rc<DxvkAdapter>> m_adapters;
VkInstance createInstance(); void createLibraryLoader(
const DxvkInstanceImportInfo& args);
void createInstanceLoader(
const DxvkInstanceImportInfo& args);
std::vector<DxvkExt*> getExtensionList(
DxvkInstanceExtensions& ext,
bool withDebug);
DxvkNameSet getExtensionSet(
const DxvkNameList& extensions);
std::vector<Rc<DxvkAdapter>> queryAdapters(); std::vector<Rc<DxvkAdapter>> queryAdapters();