物理设备¶
更新记录
2024/1/2 增加该文档。
2024/2/2 更新该文档。
2024/2/2 增加
vkEnumeratePhysicalDevices
章节。2024/2/2 增加
获取物理设备信息
章节。2024/2/2 增加
vkGetPhysicalDeviceProperties
章节。2024/2/2 增加
VkPhysicalDeviceType
章节。2024/2/2 增加
VkPhysicalDeviceLimits
章节。2024/2/2 增加
VkPhysicalDeviceSparseProperties
章节。2024/2/2 增加
示例
章节。
一台主机上可能插着多个支持 Vulkan
的物理设备,为此 Vulkan
提供列举出系统中支持 Vulkan
的所有物理设备功能,开发者可通过 vkEnumeratePhysicalDevices(...)
函数进行物理设备列举。其定义如下:
vkEnumeratePhysicalDevices¶
// 由 VK_VERSION_1_0 提供
VkResult vkEnumeratePhysicalDevices(
VkInstance instance,
uint32_t* pPhysicalDeviceCount,
VkPhysicalDevice* pPhysicalDevices);
instance 是之前使用
vkCreateInstance
创建的VkInstance
句柄。pPhysicalDeviceCount 是用于指定或获取的物理设备数量。
pPhysicalDevices 要么是
NULL
要么是数量不小于pPhysicalDeviceCount
的VkPhysicalDevice
数组。
当 pPhysicalDevices
为 nullptr
时,该函数会将系统中支持 Vulkan
的设备数量写入 pPhysicalDeviceCount
中。
如果 pPhysicalDevices
为一个有效指针,则其指向一个 VkPhysicalDevice
数组,并且该数组长度 不能 小于 pPhysicalDeviceCount
。
如果 pPhysicalDeviceCount
中指定的数量小于系统中的物理设备数量,则 pPhysicalDevices
中写入的物理设备不是所有,则 vkEnumeratePhysicalDevices(...)
函数将会写入 pPhysicalDeviceCount
个物理设备到 pPhysicalDevices
数组中,并返回 VkResult::VK_INCOMPLETE
。
如果所有物理设备成功写入,则会返回 VkResult::VK_SUCCESS
。
因此,枚举所有物理设备需要调用 vkEnumeratePhysicalDevices(...)
两次:
将
pPhysicalDevices
设置为nullptr
,并通过pPhysicalDeviceCount
获取支持系统中支持Vulkan
的物理设备数量。创建
pPhysicalDevices
数量的VkPhysicalDevice
数组,并传入pPhysicalDevices
中以获取系统中支持的VkPhysicalDevice
物理设备。
VkInstance instance = 支持创建的 VkInstance;
uint32_t physical_device_count = 0;
vkEnumeratePhysicalDevices(instance, &physical_device_count, nullptr);
std::vector<VkPhysicalDevice> physical_devices(physical_device_count);
vkEnumeratePhysicalDevices(instance, &physical_device_count, physical_devices.data());
这样就可以枚举出系统中支持 Vulkan
的所有物理设备。
备注
枚举的 VkPhysicalDevice
句柄是在调用 vkCreateInstance(...)
创建 VkInstance
时驱动内部创建的。换句话说就是:
VkPhysicalDevice
句柄的生命周期与 VkInstance
相同, VkInstance
创建 VkPhysicalDevice
句柄们也会创建, VkInstance
销毁 VkPhysicalDevice
句柄们也会销毁。
获取物理设备信息¶
在通过 vkEnumeratePhysicalDevices(...)
获取系统中支持的物理设备句柄后,我们需要筛选出我们需要的物理设备,比如,相比于使用集成显卡,我们往往倾向于使用性能更强悍的独立显卡。
我们可以通过 vkGetPhysicalDeviceProperties(...)
函数获取物理设备信息:
vkGetPhysicalDeviceProperties¶
// 由 VK_VERSION_1_0 提供
void vkGetPhysicalDeviceProperties(
VkPhysicalDevice physicalDevice,
VkPhysicalDeviceProperties* pProperties);
physicalDevice 对应要获取属性的物理设备的句柄。
pProperties 对应返回的物理设备属性。
其中 VkPhysicalDeviceProperties
定义如下:
VkPhysicalDeviceProperties¶
// 由 VK_VERSION_1_0 提供
typedef struct VkPhysicalDeviceProperties {
uint32_t apiVersion;
uint32_t driverVersion;
uint32_t vendorID;
uint32_t deviceID;
VkPhysicalDeviceType deviceType;
char deviceName[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE];
uint8_t pipelineCacheUUID[VK_UUID_SIZE];
VkPhysicalDeviceLimits limits;
VkPhysicalDeviceSparseProperties sparseProperties;
} VkPhysicalDeviceProperties;
apiVersion 该设备驱动支持的
Vulkan
版本。driverVersion 该设备驱动版本。
vendorID 设备供应商的
ID
。deviceID 设备的
ID
。deviceType 设备类型。
deviceName 设备名称。
pipelineCacheUUID 设备的通用唯一识别码(
universally unique identifier
)。limits 设备的限制信息。
sparseProperties 稀疏数据属性。
其中 apiVersion
是最为 重要 的参数,该参数表明该设备支持的 Vulkan
最高版本。该版本与 VkApplicationInfo::apiVersion
中的版本类似,您只能获取到 VkPhysicalDeviceProperties::apiVersion
版本及之前版本 Vulkan
对应的 Device 域函数
。
所以能够获取到的 Vulkan
函数逻辑如下:
flowchart TD VulkanAPI["Vulkan 某一个函数"] IsLessEqualInstanceVulkanVersion{"小于等于 VkApplicationInfo::apiVersion 版本"} IsInstanceAPI{"为 Instance/PhysicalDevice 域函数"} IsDeviceAPI{"为 Device 域函数"} IsLessEqualDeviceVulkanVersion{"小于等于 VkPhysicalDeviceProperties::apiVersion 版本"} ReturnValidAPI["返回有效API"] ReturnNullAPI["返回无效API\n(nullptr)"] VulkanAPI-->IsLessEqualInstanceVulkanVersion IsLessEqualInstanceVulkanVersion--是-->IsInstanceAPI IsLessEqualInstanceVulkanVersion--否-->ReturnNullAPI IsInstanceAPI--是-->ReturnValidAPI IsInstanceAPI--否-->IsDeviceAPI IsDeviceAPI--是-->IsLessEqualDeviceVulkanVersion IsDeviceAPI--否-->Undefine["未定义\n一个函数不可能 既不是 Instance/PhysicalDevice 域函数也不是 Device 域函数"] IsLessEqualDeviceVulkanVersion--是-->ReturnValidAPI IsLessEqualDeviceVulkanVersion--否-->ReturnNullAPI
其中 VkPhysicalDeviceType
定义如下:
VkPhysicalDeviceType¶
// 由 VK_VERSION_1_0 提供
typedef enum VkPhysicalDeviceType {
VK_PHYSICAL_DEVICE_TYPE_OTHER = 0,
VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU = 1,
VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU = 2,
VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU = 3,
VK_PHYSICAL_DEVICE_TYPE_CPU = 4,
} VkPhysicalDeviceType;
VK_PHYSICAL_DEVICE_TYPE_OTHER 该设备类型不与任何其他类型匹配,
Vulkan
中未定义的设备类型。VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU 集成显卡。
VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU 独立显卡。
VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU 虚拟环境中的虚拟显卡。
VK_PHYSICAL_DEVICE_TYPE_CPU 中央处理器(
CPU
)。
一般首选使用 VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
独立显卡,之后再考虑使用 VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU
集成显卡。
其中 VkPhysicalDeviceLimits
用于表述该设备的一些限制,比如最大支持的图片像素大小。
VkPhysicalDeviceLimits¶
备注
由于该结构体中有很多还没有涉及到的知识,并且成员过多,所以这里只给出定义。用户只需要知道该结构体中存有物理设备的上限信息即可。
// 由 VK_VERSION_1_0 提供
typedef struct VkPhysicalDeviceLimits {
uint32_t maxImageDimension1D;
uint32_t maxImageDimension2D;
uint32_t maxImageDimension3D;
uint32_t maxImageDimensionCube;
uint32_t maxImageArrayLayers;
uint32_t maxTexelBufferElements;
uint32_t maxUniformBufferRange;
uint32_t maxStorageBufferRange;
uint32_t maxPushConstantsSize;
uint32_t maxMemoryAllocationCount;
uint32_t maxSamplerAllocationCount;
VkDeviceSize bufferImageGranularity;
VkDeviceSize sparseAddressSpaceSize;
uint32_t maxBoundDescriptorSets;
uint32_t maxPerStageDescriptorSamplers;
uint32_t maxPerStageDescriptorUniformBuffers;
uint32_t maxPerStageDescriptorStorageBuffers;
uint32_t maxPerStageDescriptorSampledImages;
uint32_t maxPerStageDescriptorStorageImages;
uint32_t maxPerStageDescriptorInputAttachments;
uint32_t maxPerStageResources;
uint32_t maxDescriptorSetSamplers;
uint32_t maxDescriptorSetUniformBuffers;
uint32_t maxDescriptorSetUniformBuffersDynamic;
uint32_t maxDescriptorSetStorageBuffers;
uint32_t maxDescriptorSetStorageBuffersDynamic;
uint32_t maxDescriptorSetSampledImages;
uint32_t maxDescriptorSetStorageImages;
uint32_t maxDescriptorSetInputAttachments;
uint32_t maxVertexInputAttributes;
uint32_t maxVertexInputBindings;
uint32_t maxVertexInputAttributeOffset;
uint32_t maxVertexInputBindingStride;
uint32_t maxVertexOutputComponents;
uint32_t maxTessellationGenerationLevel;
uint32_t maxTessellationPatchSize;
uint32_t maxTessellationControlPerVertexInputComponents;
uint32_t maxTessellationControlPerVertexOutputComponents;
uint32_t maxTessellationControlPerPatchOutputComponents;
uint32_t maxTessellationControlTotalOutputComponents;
uint32_t maxTessellationEvaluationInputComponents;
uint32_t maxTessellationEvaluationOutputComponents;
uint32_t maxGeometryShaderInvocations;
uint32_t maxGeometryInputComponents;
uint32_t maxGeometryOutputComponents;
uint32_t maxGeometryOutputVertices;
uint32_t maxGeometryTotalOutputComponents;
uint32_t maxFragmentInputComponents;
uint32_t maxFragmentOutputAttachments;
uint32_t maxFragmentDualSrcAttachments;
uint32_t maxFragmentCombinedOutputResources;
uint32_t maxComputeSharedMemorySize;
uint32_t maxComputeWorkGroupCount[3];
uint32_t maxComputeWorkGroupInvocations;
uint32_t maxComputeWorkGroupSize[3];
uint32_t subPixelPrecisionBits;
uint32_t subTexelPrecisionBits;
uint32_t mipmapPrecisionBits;
uint32_t maxDrawIndexedIndexValue;
uint32_t maxDrawIndirectCount;
float maxSamplerLodBias;
float maxSamplerAnisotropy;
uint32_t maxViewports;
uint32_t maxViewportDimensions[2];
float viewportBoundsRange[2];
uint32_t viewportSubPixelBits;
size_t minMemoryMapAlignment;
VkDeviceSize minTexelBufferOffsetAlignment;
VkDeviceSize minUniformBufferOffsetAlignment;
VkDeviceSize minStorageBufferOffsetAlignment;
int32_t minTexelOffset;
uint32_t maxTexelOffset;
int32_t minTexelGatherOffset;
uint32_t maxTexelGatherOffset;
float minInterpolationOffset;
float maxInterpolationOffset;
uint32_t subPixelInterpolationOffsetBits;
uint32_t maxFramebufferWidth;
uint32_t maxFramebufferHeight;
uint32_t maxFramebufferLayers;
VkSampleCountFlags framebufferColorSampleCounts;
VkSampleCountFlags framebufferDepthSampleCounts;
VkSampleCountFlags framebufferStencilSampleCounts;
VkSampleCountFlags framebufferNoAttachmentsSampleCounts;
uint32_t maxColorAttachments;
VkSampleCountFlags sampledImageColorSampleCounts;
VkSampleCountFlags sampledImageIntegerSampleCounts;
VkSampleCountFlags sampledImageDepthSampleCounts;
VkSampleCountFlags sampledImageStencilSampleCounts;
VkSampleCountFlags storageImageSampleCounts;
uint32_t maxSampleMaskWords;
VkBool32 timestampComputeAndGraphics;
float timestampPeriod;
uint32_t maxClipDistances;
uint32_t maxCullDistances;
uint32_t maxCombinedClipAndCullDistances;
uint32_t discreteQueuePriorities;
float pointSizeRange[2];
float lineWidthRange[2];
float pointSizeGranularity;
float lineWidthGranularity;
VkBool32 strictLines;
VkBool32 standardSampleLocations;
VkDeviceSize optimalBufferCopyOffsetAlignment;
VkDeviceSize optimalBufferCopyRowPitchAlignment;
VkDeviceSize nonCoherentAtomSize;
} VkPhysicalDeviceLimits;
VkPhysicalDeviceSparseProperties¶
VkPhysicalDeviceSparseProperties
将会在 稀疏
资源章节中进行讲解。
示例¶
VkInstance instance = 支持创建的 VkInstance;
uint32_t physical_device_count = 0;
vkEnumeratePhysicalDevices(instance, &physical_device_count, nullptr);
std::vector<VkPhysicalDevice> physical_devices(physical_device_count);
vkEnumeratePhysicalDevices(instance, &physical_device_count, physical_devices.data());
VkPhysicalDevice target_physical_device = VK_NULL_HANDLE;
for(VkPhysicalDevice& physical_device : physical_devices)
{
VkPhysicalDeviceProperties physical_device_properties = {};
vkGetPhysicalDeviceProperties(physical_device, &physical_device_properties);
if(physical_device_properties.deviceType == VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
{
target_physical_device = physical_device;
break;
}
else if(physical_device_properties.deviceType == VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU)
{
target_physical_device = physical_device;
}
}
if(target_physical_device == VK_NULL_HANDLE)
{
throw std::runtime_error("没有找到合适的物理设备");
}