开发日志
为什么 Vulkan 比 OpenGL 复杂:显式控制的代价与收益
写过 OpenGL 的人第一次看 Vulkan 的”Hello Triangle”示例,通常反应是:“画一个三角形要 写这么多代码?“——这个反应是对的,Vulkan 确实把 OpenGL 隐藏的一切都摊开给你看了。
OpenGL 的隐式状态机 vs Vulkan 的显式一切
OpenGL 是一个巨大的隐式状态机:glBindTexture、glBindBuffer 改的是全局上下文
状态,驱动在背后帮你做同步、内存管理、shader 编译缓存。好处是好上手,坏处是这些
“背后的魔法”经常是性能瓶颈的黑盒——你不知道一次 draw call 究竟触发了驱动做了多少
隐藏的工作。
Vulkan 反过来:内存分配、同步、pipeline 状态、命令录制全部显式化。驱动只做驱动该 做的事(把命令翻译成 GPU 能执行的形式),其余的都由应用自己管理。多线程录制命令 缓冲区、精确控制 GPU-CPU 同步时机,这些在 OpenGL 里几乎不可能做到,在 Vulkan 里是 基本操作。
核心对象模型
VkInstance └─ VkPhysicalDevice(枚举到的物理 GPU) └─ VkDevice(逻辑设备,实际交互的句柄) ├─ VkQueue(提交命令的队列,分 graphics / compute / transfer 等 family) ├─ VkCommandPool → VkCommandBuffer(命令录制) ├─ VkPipeline(着色器 + 光栅化/混合等状态的不可变快照) └─ VkDeviceMemory(显式分配的显存)关键设计:Pipeline 是不可变对象。OpenGL 里你可以随时改混合模式、深度测试开关;
Vulkan 里这些状态在创建 VkPipeline 时就固定下来了,运行时切换意味着切换整个
pipeline 对象(当然也有 dynamic state 可以豁免部分状态,但核心思路是”提前编译好,
运行时别改”)。
命令录制:先写”剧本”,再一次性提交
vkBeginCommandBuffer(cmdBuf, &beginInfo);
vkCmdBeginRenderPass(cmdBuf, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);vkCmdBindVertexBuffers(cmdBuf, 0, 1, &vertexBuffer, offsets);vkCmdDraw(cmdBuf, vertexCount, 1, 0, 0);vkCmdEndRenderPass(cmdBuf);
vkEndCommandBuffer(cmdBuf);命令缓冲区录制完之后可以反复提交、可以在多个线程里并行录制多个命令缓冲区——这是 Vulkan 相对 OpenGL 最大的实际收益之一:OpenGL 的命令提交本质上是单线程的(多线程 共享 context 代价极高),Vulkan 从设计上就允许”渲染线程只管录制,提交线程统一 提交”。
同步:最难,也是最容易出 bug 的部分
Vulkan 不会帮你插入任何隐式的同步屏障。GPU 上一堆队列、一堆命令缓冲区并行执行, 你需要显式声明”这个操作要等那个操作完成”:
- Fence:GPU → CPU 同步(“这批命令执行完了吗,CPU 可以查询/等待”)
- Semaphore:GPU 内部队列间同步(比如”渲染完成后交换链才能呈现”)
- Pipeline Barrier / Image Layout Transition:同一个队列内部的读写依赖 (比如一张纹理先被写入,再被采样,中间必须插 barrier,否则读到脏数据)
忘记插 barrier 是 Vulkan 新手最常见的 bug 来源之一,而且很多情况下”忘记同步”在 某些 GPU/驱动上恰好不出问题(因为硬件实现凑巧覆盖了这个 race),换一张显卡就炸—— 这也是为什么 Vulkan 强烈建议开着 validation layer 开发。
2026 年的进展:Descriptor Heap
Vulkan 生态在 2026 年的一个重要更新是 Roadmap 2026 里程碑,核心是全新的
VK_EXT_descriptor_heap 扩展——对现有 descriptor set 系统的一次重构,允许直接
访问 descriptor 内存,同时保持跟传统 descriptor set 和其他图形 API 的兼容
Khronos 博客。
当前最新的 Vulkan 规范版本是 1.4.356
Vulkan 规范。
什么时候该用 Vulkan,什么时候别用
- 引擎/中间件(Unreal、自研引擎)、需要极致榨干多核 CPU 提交能力的场景 → Vulkan
- 小工具、原型、不需要压榨性能的场景 → OpenGL(甚至 WebGPU,语义上更接近现代 API 但心智负担小得多)依然是更划算的选择
Vulkan 的复杂度不是”过度设计”,而是把 GPU 真实的并行/异步本质暴露出来的必然结果—— 代价是你要自己管好这份复杂度。
Sources: