From bc5dfc1cada5d68451aa4abb622664ed1a4e6e54 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Tue, 16 Jan 2018 13:24:36 +0100 Subject: [PATCH] [dxvk] Refactored device extension handling Support for extensions can now be queried from the device object in an efficient way. This will allow the backend to use optional extensions for the purpose of optimization. --- src/dxvk/dxvk_adapter.cpp | 45 +++--------- src/dxvk/dxvk_adapter.h | 2 - src/dxvk/dxvk_device.cpp | 2 + src/dxvk/dxvk_device.h | 11 +++ src/dxvk/dxvk_extensions.cpp | 75 +++++++++++++++++++ src/dxvk/dxvk_extensions.h | 138 +++++++++++++++++++++++++++++++++++ src/dxvk/meson.build | 1 + 7 files changed, 238 insertions(+), 36 deletions(-) create mode 100644 src/dxvk/dxvk_extensions.cpp create mode 100644 src/dxvk/dxvk_extensions.h diff --git a/src/dxvk/dxvk_adapter.cpp b/src/dxvk/dxvk_adapter.cpp index a735ad34f..f1a93db81 100644 --- a/src/dxvk/dxvk_adapter.cpp +++ b/src/dxvk/dxvk_adapter.cpp @@ -74,7 +74,7 @@ namespace dxvk { return i; } - throw DxvkError("DxvkAdapter::graphicsQueueFamily: No graphics queue found"); + throw DxvkError("DxvkAdapter: No graphics queue found"); } @@ -147,7 +147,14 @@ namespace dxvk { Rc DxvkAdapter::createDevice(const VkPhysicalDeviceFeatures& enabledFeatures) { - auto enabledExtensions = this->enableExtensions(); + const Rc extensions = new DxvkDeviceExtensions(); + extensions->enableExtensions(vk::NameSet::enumerateDeviceExtensions(*m_vki, m_handle)); + + if (!extensions->checkSupportStatus()) + throw DxvkError("DxvkAdapter: Failed to create device"); + + const vk::NameList enabledExtensions = + extensions->getEnabledExtensionNames(); Logger::info("Enabled device extensions:"); this->logNameList(enabledExtensions); @@ -188,8 +195,8 @@ namespace dxvk { VkDevice device = VK_NULL_HANDLE; if (m_vki->vkCreateDevice(m_handle, &info, nullptr, &device) != VK_SUCCESS) - throw DxvkError("DxvkDevice::createDevice: Failed to create device"); - return new DxvkDevice(this, new vk::DeviceFn(m_vki->instance(), device), enabledFeatures); + throw DxvkError("DxvkAdapter: Failed to create device"); + return new DxvkDevice(this, new vk::DeviceFn(m_vki->instance(), device), extensions, enabledFeatures); } @@ -198,36 +205,6 @@ namespace dxvk { } - vk::NameList DxvkAdapter::enableExtensions() { - std::vector extOptional = { - VK_KHR_MAINTENANCE2_EXTENSION_NAME, - }; - - std::vector extRequired = { - VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, - VK_KHR_SWAPCHAIN_EXTENSION_NAME, - VK_KHR_MAINTENANCE1_EXTENSION_NAME, - }; - - const vk::NameSet extensionsAvailable - = vk::NameSet::enumerateDeviceExtensions(*m_vki, m_handle); - vk::NameList extensionsEnabled; - - for (auto e : extOptional) { - if (extensionsAvailable.supports(e)) - extensionsEnabled.add(e); - } - - for (auto e : extRequired) { - if (!extensionsAvailable.supports(e)) - throw DxvkError(str::format("DxvkDevice::getExtensions: Extension ", e, " not supported")); - extensionsEnabled.add(e); - } - - return extensionsEnabled; - } - - void DxvkAdapter::logNameList(const vk::NameList& names) { for (uint32_t i = 0; i < names.count(); i++) Logger::info(str::format(" ", names.name(i))); diff --git a/src/dxvk/dxvk_adapter.h b/src/dxvk/dxvk_adapter.h index 6907e295a..badbfbb64 100644 --- a/src/dxvk/dxvk_adapter.h +++ b/src/dxvk/dxvk_adapter.h @@ -155,8 +155,6 @@ namespace dxvk { std::vector m_queueFamilies; - vk::NameList enableExtensions(); - static void logNameList(const vk::NameList& names); }; diff --git a/src/dxvk/dxvk_device.cpp b/src/dxvk/dxvk_device.cpp index dede436dd..abfd64a87 100644 --- a/src/dxvk/dxvk_device.cpp +++ b/src/dxvk/dxvk_device.cpp @@ -6,9 +6,11 @@ namespace dxvk { DxvkDevice::DxvkDevice( const Rc& adapter, const Rc& vkd, + const Rc& extensions, const VkPhysicalDeviceFeatures& features) : m_adapter (adapter), m_vkd (vkd), + m_extensions (extensions), m_features (features), m_memory (new DxvkMemoryAllocator(adapter, vkd)), m_renderPassPool (new DxvkRenderPassPool (vkd)), diff --git a/src/dxvk/dxvk_device.h b/src/dxvk/dxvk_device.h index 13e6870c2..77d7948e6 100644 --- a/src/dxvk/dxvk_device.h +++ b/src/dxvk/dxvk_device.h @@ -5,6 +5,7 @@ #include "dxvk_compute.h" #include "dxvk_constant_state.h" #include "dxvk_context.h" +#include "dxvk_extensions.h" #include "dxvk_framebuffer.h" #include "dxvk_image.h" #include "dxvk_memory.h" @@ -40,6 +41,7 @@ namespace dxvk { DxvkDevice( const Rc& adapter, const Rc& vkd, + const Rc& extensions, const VkPhysicalDeviceFeatures& features); ~DxvkDevice(); @@ -71,6 +73,14 @@ namespace dxvk { return m_adapter; } + /** + * \brief Enabled device extensions + * \returns Enabled device extensions + */ + const DxvkDeviceExtensions& extensions() const { + return *m_extensions; + } + /** * \brief Enabled device features * \returns Enabled features @@ -300,6 +310,7 @@ namespace dxvk { Rc m_adapter; Rc m_vkd; + Rc m_extensions; VkPhysicalDeviceFeatures m_features; Rc m_memory; diff --git a/src/dxvk/dxvk_extensions.cpp b/src/dxvk/dxvk_extensions.cpp new file mode 100644 index 000000000..e1fd22e13 --- /dev/null +++ b/src/dxvk/dxvk_extensions.cpp @@ -0,0 +1,75 @@ +#include "dxvk_extensions.h" + +namespace dxvk { + + DxvkExtensionList:: DxvkExtensionList() { } + DxvkExtensionList::~DxvkExtensionList() { } + + + void DxvkExtensionList::enableExtensions(const vk::NameSet& extensions) { + for (auto ext : m_extensions) { + if (extensions.supports(ext->name())) + ext->setEnabled(true); + } + } + + + bool DxvkExtensionList::checkSupportStatus() { + bool requiredExtensionsEnabled = true; + + for (auto ext : m_extensions) { + if (!ext->enabled()) { + switch (ext->type()) { + case DxvkExtensionType::Optional: + // An optional extension should not have any impact on + // the functionality of an application, so inform the + // user only if verbose debug messages are enabled + Logger::debug(str::format("Optional Vulkan extension ", ext->name(), " not supported")); + break; + + case DxvkExtensionType::Desired: + // If a desired extension is not supported, applications + // should keep working but may exhibit unexpected behaviour, + // so we'll inform the user anyway + Logger::warn(str::format("Vulkan extension ", ext->name(), " not supported")); + break; + + case DxvkExtensionType::Required: + // Do not exit early so we can catch all unsupported extensions. + requiredExtensionsEnabled = false; + Logger::err(str::format("Required Vulkan extension ", ext->name(), " not supported")); + break; + } + } + } + + return requiredExtensionsEnabled; + } + + + vk::NameList DxvkExtensionList::getEnabledExtensionNames() const { + vk::NameList names; + + for (auto ext : m_extensions) { + if (ext->enabled()) + names.add(ext->name()); + } + + return names; + } + + + void DxvkExtensionList::registerExtension(DxvkExtension* extension) { + m_extensions.push_back(extension); + } + + + DxvkExtension::DxvkExtension( + DxvkExtensionList* parent, + const char* name, + DxvkExtensionType type) + : m_name(name), m_type(type), m_enabled(false) { + parent->registerExtension(this); + } + +} \ No newline at end of file diff --git a/src/dxvk/dxvk_extensions.h b/src/dxvk/dxvk_extensions.h new file mode 100644 index 000000000..e86d42715 --- /dev/null +++ b/src/dxvk/dxvk_extensions.h @@ -0,0 +1,138 @@ +#pragma once + +#include "dxvk_include.h" + +namespace dxvk { + + // Forward declarations + class DxvkExtension; + class DxvkExtensionList; + + /** + * \brief Extension type + */ + enum class DxvkExtensionType { + Optional, ///< Nothing will happen if not supported + Desired, ///< A warning will be issued if not supported + Required, ///< Device creation will fail if not supported + }; + + /** + * \brief Vulkan extension list + * + * Convenience class to manage a set of extensions + * which can be either required or optional. + */ + class DxvkExtensionList : public RcObject { + friend class DxvkExtension; + public: + + DxvkExtensionList(); + ~DxvkExtensionList(); + + DxvkExtensionList (const DxvkExtensionList&) = delete; + DxvkExtensionList& operator = (const DxvkExtensionList&) = delete; + + /** + * \brief Enables Vulkan extensions + * + * Marks all extension in the list as enabled. + * \param [in] extensions Supported extensions + */ + void enableExtensions( + const vk::NameSet& extensions); + + /** + * \brief Checks extension support status + * + * Checks whether all required extensions are present + * and logs the name of any unsupported extension. + * \returns \c true if required extensions are present + */ + bool checkSupportStatus(); + + /** + * \brief Creates a list of enabled extensions + * + * The resulting list can be fed into the Vulkan + * structs for device and instance creation. + * \returns Names of enabled Vulkan extensions + */ + vk::NameList getEnabledExtensionNames() const; + + private: + + std::vector m_extensions; + + void registerExtension(DxvkExtension* extension); + + }; + + /** + * \brief Extension class + * + * Stores the name, type and support + * status of a single Vulkan extension. + */ + class DxvkExtension { + friend class DxvkExtensionList; + public: + + DxvkExtension( + DxvkExtensionList* parent, + const char* name, + DxvkExtensionType type); + + DxvkExtension (const DxvkExtension&) = delete; + DxvkExtension& operator = (const DxvkExtension&) = delete; + + /** + * \brief Extension name + * \returns Extension name + */ + const char* name() const { + return m_name; + } + + /** + * \brief Extension type + * \returns Extension type + */ + DxvkExtensionType type() const { + return m_type; + } + + /** + * \brief Extension support status + * \returns \c true if supported + */ + bool enabled() const { + return m_enabled; + } + + private: + + const char* m_name; + DxvkExtensionType m_type; + bool m_enabled; + + void setEnabled(bool enabled) { + m_enabled = enabled; + } + + }; + + /** + * \brief Device extensions + * + * Lists all Vulkan extensions that are potentially + * used by DXVK if supported by the implementation. + */ + struct DxvkDeviceExtensions : public DxvkExtensionList { + DxvkExtension khrMaintenance1 = { this, VK_KHR_MAINTENANCE1_EXTENSION_NAME, DxvkExtensionType::Required }; + DxvkExtension khrMaintenance2 = { this, VK_KHR_MAINTENANCE2_EXTENSION_NAME, DxvkExtensionType::Desired }; + DxvkExtension khrShaderDrawParameters = { this, VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, DxvkExtensionType::Required }; + DxvkExtension khrSwapchain = { this, VK_KHR_SWAPCHAIN_EXTENSION_NAME, DxvkExtensionType::Required }; + }; + +} \ No newline at end of file diff --git a/src/dxvk/meson.build b/src/dxvk/meson.build index 2694bf88f..687b7eb20 100644 --- a/src/dxvk/meson.build +++ b/src/dxvk/meson.build @@ -14,6 +14,7 @@ dxvk_src = files([ 'dxvk_data.cpp', 'dxvk_descriptor.cpp', 'dxvk_device.cpp', + 'dxvk_extensions.cpp', 'dxvk_format.cpp', 'dxvk_framebuffer.cpp', 'dxvk_graphics.cpp',