在 Vulkan 的设计哲学中,为了达到对硬件的绝对掌控,它把“显卡”这个概念极其显式地拆分成了两个层面:物理设备(Physical Device) 和 逻辑设备(Logical Device)。
简单来说:
物理设备 代表的是你电脑里那块看得见、摸得着的整块 GPU 显卡芯片(硬件实体)。
逻辑设备 代表的是你的应用程序与这块显卡之间建立的软件通信通道/会话(软件接口)。
1. 物理设备 (VkPhysicalDevice)#
物理设备 是对系统当前实际插在主板上的硬件 GPU 的抽象。
核心特点#
只读的硬件底牌: 你不能“创建”一个物理设备,你只能去“枚举(Enumerate)”和“查询(Query)”它。它就像是显卡厂商直接写死在硬件和驱动里的“说明书”。
区分不同的显卡: 如果你的电脑(比如游戏笔记本)同时有 Intel 核显和 NVIDIA 独显,Vulkan 就会枚举出两个不同的
VkPhysicalDevice句柄。
能够查询到什么?#
通过 Vulkan 提供的查询函数(如 vkGetPhysicalDeviceProperties 和 vkGetPhysicalDeviceFeatures),你可以把这块硬件的底细摸得一清二楚:
基础属性 (Properties): 显卡名称(例如 RTX 5070 Ti)、厂商 ID、驱动版本、以及它是独立显卡(Discrete)还是集成显卡(Integrated)。
硬件特性 (Features): 这块显卡支不支持硬件光线追踪?支不支持网格着色器(Mesh Shader)?支不支持几何着色器?
内存信息 (Memory Properties): 这张卡有多少显存(Device Local Memory)?有多少可以直接映射的系统内存?
队列族 (Queue Families): 之前聊过的,它有哪些车间?支持图形、计算还是传输?
2. 逻辑设备 (VkDevice)#
逻辑设备 是你在选中某块物理设备后,向它正式申请并创建出来的虚拟操作接口。
核心特点#
真正干活的句柄: 绝大多数 Vulkan 的核心操作(创建缓冲区、创建纹理、创建渲染管线、创建着色器模块等),其函数的第一个参数全都是
VkDevice。按需定制: 创建逻辑设备时,你是在对物理设备说:“我决定用你了,但我不需要你的全部功能,我只要开启你的光追特性,并且帮我从图形队列族里实例化出一个队列来。”
多实例并行: 针对同一个物理设备,你可以创建多个独立的逻辑设备。它们在同一个程序内互不干扰。
3. 两者的关系与生命周期#
物理设备和逻辑设备的关系,非常符合现代 C++ 的资源管理逻辑:
多对一的选择: 系统中可以有多个物理设备,但你的程序通过筛选算法,最终通常只会选择其中一个最合适的物理设备。
一对多的实例化: 选定物理设备后,基于它创建出一个或多个逻辑设备。
生命周期分离:
VkPhysicalDevice的生命周期跟随 Vulkan 实例(VkInstance),不需要也不能手动销毁。VkDevice必须遵循 RAII 原则。在程序退出或切换显卡时,你必须显式调用vkDestroyDevice(device, nullptr)来释放它以及挂在它底下的所有资源。
总结#
物理设备(Physical) 回答的是 “硬件能做到什么”(Capabilities)。
逻辑设备(Logical) 回答的是 “我的程序要用它做什么”(Activation)。
这种分离保证了 Vulkan 的纯净性:无论用户的电脑插了多少张卡,通过物理设备盘点清楚后,你的图形引擎主体只需要抱着创建好的逻辑设备(VkDevice)一路无脑画画就可以了。