[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.
This commit is contained in:
Philip Rebohle 2018-01-16 13:24:36 +01:00
parent 8805958736
commit bc5dfc1cad
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
7 changed files with 238 additions and 36 deletions

View File

@ -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<DxvkDevice> DxvkAdapter::createDevice(const VkPhysicalDeviceFeatures& enabledFeatures) {
auto enabledExtensions = this->enableExtensions();
const Rc<DxvkDeviceExtensions> 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<const char*> extOptional = {
VK_KHR_MAINTENANCE2_EXTENSION_NAME,
};
std::vector<const char*> 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)));

View File

@ -155,8 +155,6 @@ namespace dxvk {
std::vector<VkQueueFamilyProperties> m_queueFamilies;
vk::NameList enableExtensions();
static void logNameList(const vk::NameList& names);
};

View File

@ -6,9 +6,11 @@ namespace dxvk {
DxvkDevice::DxvkDevice(
const Rc<DxvkAdapter>& adapter,
const Rc<vk::DeviceFn>& vkd,
const Rc<DxvkDeviceExtensions>& 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)),

View File

@ -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<DxvkAdapter>& adapter,
const Rc<vk::DeviceFn>& vkd,
const Rc<DxvkDeviceExtensions>& 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<DxvkAdapter> m_adapter;
Rc<vk::DeviceFn> m_vkd;
Rc<DxvkDeviceExtensions> m_extensions;
VkPhysicalDeviceFeatures m_features;
Rc<DxvkMemoryAllocator> m_memory;

View File

@ -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);
}
}

138
src/dxvk/dxvk_extensions.h Normal file
View File

@ -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<DxvkExtension*> 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 };
};
}

View File

@ -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',