物理设备¶
更新记录
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("没有找到合适的物理设备");
}