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:
parent
f50f5bc9bc
commit
ef9d5048f3
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user