You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

673 lines
25 KiB

#ifndef Magnum_Vk_DeviceProperties_h
#define Magnum_Vk_DeviceProperties_h
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020 Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
/** @file
* @brief Class @ref Magnum::Vk::DeviceProperties, enum @ref Magnum::Vk::DeviceType, @ref Magnum::Vk::QueueFlag, @ref Magnum::Vk::MemoryHeapFlag, enum set @ref Magnum::Vk::QueueFlags, @ref Magnum::Vk::MemoryHeapFlags, function @ref Magnum::Vk::enumerateDevices(), @ref Magnum::Vk::pickDevice(), @ref Magnum::Vk::tryPickDevice()
* @m_since_latest
*/
#include <Corrade/Containers/ArrayView.h>
#include <Corrade/Containers/Pointer.h>
#include <Corrade/Containers/Reference.h>
#include "Magnum/Magnum.h"
#include "Magnum/Tags.h"
#include "Magnum/Vk/Vulkan.h"
#include "Magnum/Vk/Vk.h"
#include "Magnum/Vk/visibility.h"
namespace Magnum { namespace Vk {
namespace Implementation {
struct InstanceState;
UnsignedInt enumerateDevicesInto(Instance& instance, Containers::ArrayView<DeviceProperties> out);
}
/**
@brief Physical device type
@m_since_latest
Wraps a @type_vk_keyword{PhysicalDeviceType}.
@see @ref DeviceProperties::type()
@m_enum_values_as_keywords
*/
enum class DeviceType: Int {
/** Anything that does not match any other available types */
Other = VK_PHYSICAL_DEVICE_TYPE_OTHER,
/**
* Typically a device embedded in or tightly coupled with the host
*/
IntegratedGpu = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU,
/**
* Typically a separate processor connected to the host via an
* interlink
*/
DiscreteGpu = VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU,
/** Typically a virtual node in a virtualization environment */
VirtualGpu = VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU,
/** Typically running on the same processors as the host */
Cpu = VK_PHYSICAL_DEVICE_TYPE_CPU
};
/**
@debugoperatorclassenum{DeviceProperties,DeviceType}
@m_since_latest
*/
MAGNUM_VK_EXPORT Debug& operator<<(Debug& debug, DeviceType value);
/**
@brief Physical device driver ID
@m_since_latest
Wraps a @type_vk_keyword{DriverId}.
@see @ref DeviceProperties::driver()
@requires_vk12 Extension @vk_extension{KHR,driver_properties}
@m_enum_values_as_keywords
*/
enum class DeviceDriver: Int {
/**
* Unknown. Returned from @ref DeviceProperties::driver() in case Vulkan
* 1.2 or the @vk_extension{KHR,driver_properties} extension isn't
* supported.
*/
Unknown = 0,
/* Unlike with VkDriverId, which gets allocated sequentially, the rest of
this list is sorted alphabetically for easier lookup. */
/** Open-source AMD */
AmdOpenSource = VK_DRIVER_ID_AMD_OPEN_SOURCE,
/** Proprietary AMD */
AmdProprietary = VK_DRIVER_ID_AMD_PROPRIETARY,
/** Proprietary ARM */
ArmProprietary = VK_DRIVER_ID_ARM_PROPRIETARY,
/** Proprietary Broadcom */
BroadcomProprietary = VK_DRIVER_ID_BROADCOM_PROPRIETARY,
/** Proprietary GGP */
GgpProprietary = VK_DRIVER_ID_GGP_PROPRIETARY,
/** Google SwiftShader */
GoogleSwiftShader = VK_DRIVER_ID_GOOGLE_SWIFTSHADER,
/** Proprietary Imagination */
ImaginationProprietary = VK_DRIVER_ID_IMAGINATION_PROPRIETARY,
/** Open-source Intel Mesa drivers */
IntelOpenSourceMesa = VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA,
/** Proprietary Intel driver on Windows */
IntelProprietaryWindows = VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS,
/** Mesa LLVMpipe */
MesaLlvmpipe = VK_DRIVER_ID_MESA_LLVMPIPE,
/** Mesa RADV */
MesaRadv = VK_DRIVER_ID_MESA_RADV,
/** MoltenVK */
MoltenVk = VK_DRIVER_ID_MOLTENVK,
/** Proprietary NVidia */
NVidiaProprietary = VK_DRIVER_ID_NVIDIA_PROPRIETARY,
/** Proprietary Qualcomm */
QualcommProprietary = VK_DRIVER_ID_QUALCOMM_PROPRIETARY,
};
/**
@debugoperatorclassenum{DeviceProperties,DeviceDriver}
@m_since_latest
*/
MAGNUM_VK_EXPORT Debug& operator<<(Debug& debug, DeviceDriver value);
/**
@brief Queue flag
@m_since_latest
Wraps a @type_vk_keyword{QueueFlagBits}.
@see @ref QueueFlags, @ref DeviceProperties::queueFamilyFlags()
@m_enum_values_as_keywords
*/
enum class QueueFlag: UnsignedInt {
/** Supports graphics operations */
Graphics = VK_QUEUE_GRAPHICS_BIT,
/** Supports compute operations */
Compute = VK_QUEUE_COMPUTE_BIT,
/** Supports transfer operations */
Transfer = VK_QUEUE_TRANSFER_BIT,
/** Supports sparse memory management operations */
SparseBinding = VK_QUEUE_SPARSE_BINDING_BIT,
/** Supports protected memory operations */
Protected = VK_QUEUE_PROTECTED_BIT
};
/**
@debugoperatorclassenum{DeviceProperties,QueueFlag}
@m_since_latest
*/
MAGNUM_VK_EXPORT Debug& operator<<(Debug& debug, QueueFlag value);
/**
@brief Queue flags
@m_since_latest
Type-safe wrapper for @type_vk_keyword{QueueFlags}.
@see @ref DeviceProperties::queueFamilyFlags()
*/
typedef Containers::EnumSet<QueueFlag> QueueFlags;
CORRADE_ENUMSET_OPERATORS(QueueFlags)
/**
@debugoperatorclassenum{DeviceProperties,QueueFlags}
@m_since_latest
*/
MAGNUM_VK_EXPORT Debug& operator<<(Debug& debug, QueueFlags value);
/**
@brief Memory heap flag
@m_since_latest
Wraps a @type_vk_keyword{MemoryHeapFlagBits}.
@see @ref QueueFlags, @ref DeviceProperties::queueFamilyFlags()
@m_enum_values_as_keywords
*/
enum class MemoryHeapFlag: UnsignedInt {
/** Corresponds to device-local memory */
DeviceLocal = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT,
/** @todo MultiInstance, Vk 1.1 */
};
/**
@debugoperatorclassenum{DeviceProperties,MemoryHeapFlag}
@m_since_latest
*/
MAGNUM_VK_EXPORT Debug& operator<<(Debug& debug, MemoryHeapFlag value);
/**
@brief Memory heap flags
@m_since_latest
Type-safe wrapper for @type_vk_keyword{MemoryHeapFlags}.
@see @ref DeviceProperties::memoryHeapFlags(), @ref MemoryFlags
*/
typedef Containers::EnumSet<MemoryHeapFlag> MemoryHeapFlags;
CORRADE_ENUMSET_OPERATORS(MemoryHeapFlags)
/**
@debugoperatorclassenum{DeviceProperties,MemoryHeapFlags}
@m_since_latest
*/
MAGNUM_VK_EXPORT Debug& operator<<(Debug& debug, MemoryHeapFlags value);
/* MemoryFlag/MemoryFlags are in Memory.h since those are used mainly in
contexts where DeviceProperties isn't present */
/**
@brief Physical device properties
@m_since_latest
Wraps a @type_vk_keyword{PhysicalDevice} along with its (lazy-populated)
properties such as @type_vk_keyword{PhysicalDeviceProperties2} and
@type_vk_keyword{GetPhysicalDeviceQueueFamilyProperties2}.
See the @ref Vk-Device-usage "Device class docs" for an example of using this
class for enumerating available devices and picking one of them.
@see @ref pickDevice(), @ref enumerateDevices()
*/
class MAGNUM_VK_EXPORT DeviceProperties {
public:
/**
* @brief Wrap existing Vulkan physical device
* @param instance Vulkan instance
* @param handle The @type_vk{PhysicalDevice} handle
*
* The @p handle is expected to be originating from @p instance. Unlike
* with other handle types, the @type_vk{PhysicalDevice} handles don't
* have to be destroyed at the end. so there's no equivalent of e.g.
* @ref Instance::release() or @ref Instance::handleFlags().
*/
static DeviceProperties wrap(Instance& instance, VkPhysicalDevice handle) {
return DeviceProperties{instance, handle};
}
/**
* @brief Construct without populating the contents
*
* The constructed instance is equivalent to moved-from state. Useful
* in cases where you will overwrite the instance later anyway. Move
* another object over it to make it useful.
*/
explicit DeviceProperties(NoCreateT) noexcept;
/** @brief Copying is not allowed */
DeviceProperties(const DeviceProperties&) = delete;
/** @brief Move constructor */
DeviceProperties(DeviceProperties&&) noexcept;
~DeviceProperties();
/** @brief Copying is not allowed */
DeviceProperties& operator=(const DeviceProperties&) = delete;
/** @brief Move assignment */
DeviceProperties& operator=(DeviceProperties&&) noexcept;
/**
* @brief Underlying @type_vk{PhysicalDevice} handle
*
* Unlike most handle getters, this one is marked as @cpp const @ce
* because the @ref DeviceProperties class is treated as a *view* on
* the physical device --- it doesn't change the device state in any
* way, only queries its properties.
*/
VkPhysicalDevice handle() const { return _handle; }
/** @overload */
operator VkPhysicalDevice() const { return _handle; }
/**
* @brief Raw device properties
*
* Populated lazily on first request. If Vulkan 1.1 is not supported
* and the @vk_extension{KHR,get_physical_device_properties2} extension
* is not enabled on the originating instance, only the Vulkan 1.0
* subset of device properties is queried, with the `pNext` member
* being @cpp nullptr @ce. Otherwise:
*
* - If Vulkan 1.2 is supported or the
* @vk_extension{KHR,driver_properties} extension is supported by
* the device, the `pNext` chain contains a
* @type_vk{PhysicalDeviceDriverProperties} structure and the
* @ref driver(), @ref driverName() and @ref driverInfo()
* properties are populated.
*
* @see @fn_vk_keyword{GetPhysicalDeviceProperties2},
* @fn_vk_keyword{GetPhysicalDeviceProperties}
*/
const VkPhysicalDeviceProperties2& properties();
/**
* @brief API version
*
* Convenience access to @ref properties() internals, populated lazily
* on first request.
*/
Version apiVersion() {
return Version(properties().properties.apiVersion);
}
/**
* @brief Device type
*
* Convenience access to @ref properties() internals, populated lazily
* on first request.
*/
DeviceType type() {
return DeviceType(properties().properties.deviceType);
}
/**
* @brief Device name
*
* Convenience access to @ref properties() internals, populated lazily
* on first request.
*/
Containers::StringView name();
/**
* @brief Driver ID
*
* Convenience access to @ref properties() internals, populated lazily
* on first request. Only present if Vulkan 1.2 is supported or the
* @vk_extension{KHR,driver_properties} extension is supported by the
* device, otherwise returns @ref DeviceDriver::Unknown. Note that
* there might be driver IDs not yet listed in the @ref DeviceDriver
* enum, moreover drivers are allowed to return unregistered IDs as
* well.
*/
DeviceDriver driver();
/**
* @brief Driver version
*
* Convenience access to @ref properties() internals, populated lazily
* on first request.
*/
Version driverVersion() {
return Version(properties().properties.driverVersion);
}
/**
* @brief Driver name
*
* Convenience access to @ref properties() internals, populated lazily
* on first request. Only present if Vulkan 1.2 is supported or the
* @vk_extension{KHR,driver_properties} extension is supported by the
* device, otherwise returns an empty string.
*/
Containers::StringView driverName();
/**
* @brief Driver info
*
* Convenience access to @ref properties() internals, populated lazily
* on first request. Only present if Vulkan 1.2 is supported or the
* @vk_extension{KHR,driver_properties} extension is supported by the
* device, otherwise returns an empty string.
*/
Containers::StringView driverInfo();
/**
* @brief Enumerate device extensions
* @param layers Additional layers to list extensions from
*
* Expects that all listed layers are supported --- however they don't
* need to be enabled on the instance.
* @see @ref LayerProperties::isSupported(),
* @fn_vk_keyword{EnumerateDeviceExtensionProperties}
*/
ExtensionProperties enumerateExtensionProperties(Containers::ArrayView<const Containers::StringView> layers = {});
/** @overload */
ExtensionProperties enumerateExtensionProperties(std::initializer_list<Containers::StringView> layers);
/**
* @brief Queue family properties
*
* Populated lazily on first request. If Vulkan 1.1 or the
* @vk_extension{KHR,get_physical_device_properties2} extension is not
* enabled on the originating instance, only the Vulkan 1.0 subset of
* device properties is queried.
* @see @fn_vk_keyword{GetPhysicalDeviceQueueFamilyProperties2},
* @fn_vk_keyword{GetPhysicalDeviceQueueFamilyProperties}
*/
Containers::ArrayView<const VkQueueFamilyProperties2> queueFamilyProperties();
/**
* @brief Queue family count
*
* Convenience access to @ref queueFamilyProperties() internals,
* populated lazily on first request.
*/
UnsignedInt queueFamilyCount();
/**
* @brief Queue count in given family
* @param queueFamily Queue family index, expected to be smaller than
* @ref queueFamilyCount()
*
* Convenience access to @ref queueFamilyProperties() internals,
* populated lazily on first request.
*/
UnsignedInt queueFamilySize(UnsignedInt queueFamily);
/**
* @brief Queue family flags
* @param queueFamily Queue family index, expected to be smaller than
* @ref queueFamilyCount()
*
* Convenience access to @ref queueFamilyProperties() internals,
* populated lazily on first request.
*/
QueueFlags queueFamilyFlags(UnsignedInt queueFamily);
/**
* @brief Pick a queue family satisfying given flags
* @return Queue family index for use in @ref queueFamilySize(),
* @ref queueFamilyFlags() and @ref DeviceCreateInfo::addQueues()
*
* Queries queue family properties using @ref queueFamilyProperties()
* and tries to find the first that contains all @p flags. If it is not
* found, exits. See @ref tryPickQueueFamily() for an alternative that
* doesn't exit on failure.
*/
UnsignedInt pickQueueFamily(QueueFlags flags);
/**
* @brief Try to pick a queue family satisfying given flags
*
* Compared to @ref pickQueueFamily() the function returns
* @ref Containers::NullOpt if a desired family isn't found instead of
* exiting.
*/
Containers::Optional<UnsignedInt> tryPickQueueFamily(QueueFlags flags);
/**
* @brief Device memory properties
*
* Populated lazily on first request. If Vulkan 1.1 or the
* @vk_extension{KHR,get_physical_device_properties2} extension is not
* enabled on the originating instance, only the Vulkan 1.0 subset of
* device properties is queried.
* @see @fn_vk_keyword{GetPhysicalDeviceMemoryProperties2},
* @fn_vk_keyword{GetPhysicalDeviceMemoryProperties}
*/
const VkPhysicalDeviceMemoryProperties2& memoryProperties();
/**
* @brief Memory heap count
*
* Convenience access to @ref memoryProperties() internals, populated
* lazily on first request.
*/
UnsignedInt memoryHeapCount();
/**
* @brief Memory heap size
* @param heap Memory heap index, expected to be smaller than
* @ref memoryHeapCount()
*
* Convenience access to @ref memoryProperties() internals, populated
* lazily on first request.
*/
UnsignedLong memoryHeapSize(UnsignedInt heap);
/**
* @brief Memory heap size
* @param heap Memory heap index, expected to be smaller than
* @ref memoryHeapCount()
*
* Convenience access to @ref memoryProperties() internals, populated
* lazily on first request.
*/
MemoryHeapFlags memoryHeapFlags(UnsignedInt heap);
/**
* @brief Memory type count
*
* Convenience access to @ref memoryProperties() internals, populated
* lazily on first request.
*/
UnsignedInt memoryCount();
/**
* @brief Memory type flags
* @param memory Memory type index, expected to be smaller than
* @ref memoryCount()
*
* Convenience access to @ref memoryProperties() internals, populated
* lazily on first request.
*/
MemoryFlags memoryFlags(UnsignedInt memory);
/**
* @brief Memory heap index
* @param memory Memory type index, expected to be smaller than
* @ref memoryCount()
* @return Memory heap index, always smaller than @ref memoryHeapCount()
*
* Convenience access to @ref memoryProperties() internals, populated
* lazily on first request.
*/
UnsignedInt memoryHeapIndex(UnsignedInt memory);
/**
* @brief Pick a memory type satisfying given flags
* @param requiredFlags Memory flags that should be present in
* picked memory type. Can be an empty set, but picking such
* memory is probably not very useful.
* @param preferredFlags If there's more than one memory type
* matching @p requiredFlags, prefer one that has most of these
* as well. Defaults to an empty set.
* @param memories Bits indicating which memory types should
* be considered (bit @cpp 0 @ce indicates memory type @cpp 0 @ce
* should be considered etc.). Expected to have at least one bit
* of the first @ref memoryCount() bits set, otherwise the
* function will always fail. Defaults to all bits set, meaning
* all memory types are considered. Corresponds to
* @ref MemoryRequirements::memories().
*
* Queries memory properties using @ref memoryProperties() and out of
* memory types set in @p memoryBits tries to find one that contains
* all @p requiredFlags and most of @p optionalFlags. If it is not
* found, exits. See @ref tryPickMemory() for an alternative that
* doesn't exit on failure.
*
* @m_class{m-note m-success}
*
* @par
* The @p preferredFlags can be used for example to ask for a
* @ref MemoryFlag::HostVisible bit on a
* @ref MemoryFlag::DeviceLocal memory --- on discrete GPUs this
* combination is usually not possible so you get just a
* device-only memory, but on integrated GPUs it can be used to
* avoid a need for a copy through a temporary staging buffer.
*/
UnsignedInt pickMemory(MemoryFlags requiredFlags, MemoryFlags preferredFlags = {}, UnsignedInt memories = ~UnsignedInt{});
/**
* @overload
*
* Equivalent to calling @ref pickMemory(MemoryFlags, MemoryFlags, UnsignedInt)
* with empty @p preferredFlags.
*/
UnsignedInt pickMemory(MemoryFlags requiredFlags, UnsignedInt memories);
/**
* @brief Try to pick a memory type satisfying given flags
*
* Compared to @ref pickMemory() the function returns
* @ref Containers::NullOpt if a desired memory type isn't found
* instead of exiting.
*/
Containers::Optional<UnsignedInt> tryPickMemory(MemoryFlags requiredFlags, MemoryFlags preferredFlags = {}, UnsignedInt memories = ~UnsignedInt{});
/**
* @overload
*
* Equivalent to calling @ref tryPickMemory(MemoryFlags, MemoryFlags, UnsignedInt)
* with empty @p preferredFlags.
*/
Containers::Optional<UnsignedInt> tryPickMemory(MemoryFlags requiredFlags, UnsignedInt memories);
private:
friend Implementation::InstanceState;
#ifndef DOXYGEN_GENERATING_OUTPUT
/* The DAMN THING lists this among friends, which is AN IMPLEMENTATION
DETAIL */
friend DeviceCreateInfo;
friend UnsignedInt Implementation::enumerateDevicesInto(Instance&, Containers::ArrayView<DeviceProperties>);
#endif
explicit DeviceProperties(Instance& instance, VkPhysicalDevice handle);
MAGNUM_VK_LOCAL static void getPropertiesImplementationDefault(DeviceProperties& self, VkPhysicalDeviceProperties2& properties);
MAGNUM_VK_LOCAL static void getPropertiesImplementationKHR(DeviceProperties& self, VkPhysicalDeviceProperties2& properties);
MAGNUM_VK_LOCAL static void getPropertiesImplementation11(DeviceProperties& self, VkPhysicalDeviceProperties2& properties);
MAGNUM_VK_LOCAL static void getQueueFamilyPropertiesImplementationDefault(DeviceProperties& self, UnsignedInt& count, VkQueueFamilyProperties2* properties);
MAGNUM_VK_LOCAL static void getQueueFamilyPropertiesImplementationKHR(DeviceProperties& self, UnsignedInt& count, VkQueueFamilyProperties2* properties);
MAGNUM_VK_LOCAL static void getQueueFamilyPropertiesImplementation11(DeviceProperties& self, UnsignedInt& count, VkQueueFamilyProperties2* properties);
MAGNUM_VK_LOCAL static void getMemoryPropertiesImplementationDefault(DeviceProperties& self, VkPhysicalDeviceMemoryProperties2& properties);
MAGNUM_VK_LOCAL static void getMemoryPropertiesImplementationKHR(DeviceProperties& self, VkPhysicalDeviceMemoryProperties2& properties);
MAGNUM_VK_LOCAL static void getMemoryPropertiesImplementation11(DeviceProperties& self, VkPhysicalDeviceMemoryProperties2& properties);
/* Can't be a reference because of the NoCreate constructor */
Instance* _instance;
VkPhysicalDevice _handle;
struct State;
Containers::Pointer<State> _state;
};
/**
@brief Enumerate physical devices
@m_since_latest
Returns a list of all devices present on the system. See @ref pickDevice() for
an alternative that pick just a single appropriate device. See @ref Device for
general usage information.
@see @fn_vk_keyword{EnumeratePhysicalDevices}
*/
MAGNUM_VK_EXPORT Containers::Array<DeviceProperties> enumerateDevices(Instance& instance);
/**
@brief Pick a physical device
@m_since_latest
Selects a device based on preferences specified through the `--magnum-device`
@ref Vk-Instance-command-line "command-line option". If a device is not found,
exits. See @ref tryPickDevice() for an alternative that doesn't exit on
failure. See @ref Device for general usage information.
If `--magnum-device` is not specified or `--magnum-device` specifies a device
index, this function enumerates just the first N devices to satisfy the
request. Otherwise calls @ref enumerateDevices() and picks the first device
matching the criteria in `--magnum-device`.
*/
MAGNUM_VK_EXPORT DeviceProperties pickDevice(Instance& instance);
/**
@brief Try to pick a physical device
@m_since_latest
Compared to @ref pickDevice() the function returns @ref Containers::NullOpt if
a device isn't found instead of exiting.
*/
MAGNUM_VK_EXPORT Containers::Optional<DeviceProperties> tryPickDevice(Instance& instance);
}}
#endif