1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-04 16:24:29 +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(
devExtensionList.size(),
devExtensionList.data(),
extensionsEnabled))
&extensionsEnabled))
throw DxvkError("DxvkAdapter: Failed to create device");
// Enable additional extensions if necessary

View File

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

View File

@ -117,6 +117,12 @@ namespace dxvk {
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
* \param [in] pName The name
@ -169,6 +175,11 @@ namespace dxvk {
public:
DxvkNameSet();
DxvkNameSet(
uint32_t count,
const char* const* names);
~DxvkNameSet();
/**
@ -188,6 +199,13 @@ namespace dxvk {
void merge(
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
*
@ -212,7 +230,7 @@ namespace dxvk {
bool enableExtensions(
uint32_t numExtensions,
DxvkExt** ppExtensions,
DxvkNameSet& nameSet) const;
DxvkNameSet* nameSet) const;
/**
* \brief Disables given extension

View File

@ -10,7 +10,13 @@
namespace dxvk {
DxvkInstance::DxvkInstance() {
DxvkInstance::DxvkInstance()
: DxvkInstance(DxvkInstanceImportInfo()) {
}
DxvkInstance::DxvkInstance(const DxvkInstanceImportInfo& args) {
Logger::info(str::format("Game: ", env::getExeName()));
Logger::info(str::format("DXVK: ", DXVK_VERSION));
@ -20,6 +26,13 @@ namespace dxvk {
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);
#ifdef _WIN32
m_extProviders.push_back(&VrInstance::s_instance);
@ -33,24 +46,7 @@ namespace dxvk {
for (const auto& provider : m_extProviders)
provider->initInstanceExtensions();
m_vkl = new vk::LibraryFn();
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.");
}
createInstanceLoader(args);
m_adapters = this->queryAdapters();
for (const auto& provider : m_extProviders)
@ -103,85 +99,137 @@ namespace dxvk {
}
VkInstance DxvkInstance::createInstance() {
DxvkInstanceExtensions insExtensions;
void DxvkInstance::createLibraryLoader(const DxvkInstanceImportInfo& args) {
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
// adds additional overhead to winevulkan
std::string debugEnv = env::getEnvVar("DXVK_DEBUG");
DxvkNameList layerNameList;
void DxvkInstance::createInstanceLoader(const DxvkInstanceImportInfo& args) {
DxvkNameList layerList;
DxvkNameList extensionList;
DxvkNameSet extensionSet;
m_enablePerfEvents = debugEnv == "markers";
m_enableValidation = debugEnv == "validation";
bool enablePerfEvents = false;
bool enableValidation = false;
if (m_enablePerfEvents || m_enableValidation || m_options.enableDebugUtils) {
insExtensionList.push_back(&insExtensions.extDebugUtils);
Logger::warn("Debug Utils are enabled. May affect performance.");
if (args.instance) {
extensionList = DxvkNameList(args.extensionCount, args.extensionNames);
extensionSet = getExtensionSet(extensionList);
if (m_enableValidation) {
const char* layerName = "VK_LAYER_KHRONOS_validation";
DxvkNameSet layers = DxvkNameSet::enumInstanceLayers(m_vkl);
auto extensionInfos = getExtensionList(m_extensions, true);
if (layers.supports(layerName)) {
layerNameList.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));
if (!extensionSet.enableExtensions(extensionInfos.size(), extensionInfos.data(), nullptr))
throw DxvkError("DxvkInstance: Required instance extensions not enabled");
} else {
// Hide VK_EXT_debug_utils behind an environment variable.
// This extension adds additional overhead to winevulkan.
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:");
this->logNameList(extensionNameList);
this->logNameList(extensionList);
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 = 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 necessary, create a new Vulkan instance
VkInstance instance = args.instance;
if (status != VK_SUCCESS)
throw DxvkError("DxvkInstance::createInstance: Failed to create Vulkan 1.1 instance");
if (!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;
}
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() {
uint32_t numAdapters = 0;
if (m_vki->vkEnumeratePhysicalDevices(m_vki->instance(), &numAdapters, nullptr) != VK_SUCCESS)

View File

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