本节摘要:选型没有全局冠军,只有场景最优。本节以一个"反例团队"的踩坑故事开场,把 DirectX、Vulkan、OpenGL、Metal 放上同一张对比桌,给出按平台、团队、渲染目标逐项校验的决策方法。
某独立团队做出一款画面精致的 PC 演示,用 D3D 12 写渲染层,决定移植全平台。负责人想当然:"D3D 12 都这么底层了,抽象一层换后端还不容易?"半年后他们在痛苦中发现:Vulkan 后端不是"换个函数名",RenderPass、管线缓存、内存分配器的语义全要对齐;macOS 版更是撞墙——苹果压根不提供 Metal 之外的官方图形 API,整个移植方案推倒重来。反例的教训先行:图形 API 不是可以随意互换的引擎零件,而是各带世界观的操作系统方言。选型失误的代价按年计,这节值得你花时间细读。
先把四位选手的底细摆开。它们都回答同一个问题——"程序如何指挥 GPU"——但答案的气质迥异。
DirectX 是 Windows 的原住民。它不是单一 API 而是一个家族:Direct3D 管三维渲染,Direct2D/DirectWrite 管二维与文字,DXGI 管适配器与交换链,XAudio2、XInput 管声音与手柄,DirectML 管机器学习推理。家族式整合是它的最大护城河:Windows 上要的每一块能力,微软都给配齐了,且相互咬合。代价是平台绑定——出了 Windows 门,它一步都不跟你走。
Vulkan 是 Khronos 集团拿出的跨平台答案,血统上可视为"OpenGL 的 D3D 12 化重写"。它学的是显式控制那套哲学:命令缓冲、管线状态、内存与同步全部显式。一次编写,Windows、Linux、Android 乃至主机定制层都可落地。代价有两个:样板代码量与 D3D 12 相当甚至更多;各平台驱动的成熟度参差,"跨平台"不等于"跨平台都好调"。
OpenGL 是老前辈。状态机模型、全局上下文、驱动幕后代劳——自动挡的舒适与天花板它都有。它的黄昏是结构性的:移动端被 ES 分支分走精力,驱动质量靠厂商自觉,Khronos 自己也把资源转向 Vulkan。但存量巨大,维护旧项目、教学演示、快速原型场景里它依然称职。
Metal 是苹果生态的唯一正解。Objective-C/Swift 风格的接口,显式程度接近 D3D 12/Vulkan,但与苹果硬件和系统服务咬合得更紧。苹果生态内几乎没有第二选项;生态外则毫无存在感。

对比表看懂只是第一步,实际决策建议按顺序问三个问题。
一问:平台在哪? 这是硬约束,优先级高于一切。目标含 Apple 移动端或 macOS 桌面 → Metal 是必选项(跨平台方案里它通常由引擎或转译层代劳);锁定 Windows 与 Xbox → DirectX 12 生态红利吃满;需要覆盖 Android 与 Linux → Vulkan 进入候选。平台问题没定论之前,谈性能与团队都是空转。
二问:团队多大、多久? 显式 API 的样板与心智成本对团队规模极其敏感。三五个人的项目,直接用 D3D 12 裸写渲染层,大概率把一半工期耗在基础设施上;这时 D3D 11 或现成渲染库往往更划算。反之,渲染密集型的长期项目,D3D 12 的性能上限与可预测性会持续分红。Vulkan 的团队成本与 D3D 12 相仿,还要额外背跨设备驱动适配——这份成本要提前计入,别像开头的反例团队那样 mid-project 才发现。
三问:渲染目标多高? 只是 UI 与轻量 3D,OpenGL/D3D 11 的托管舒适完全够用;追求大规模场景、主机级帧预算、GPU 驱动管线(第一章 1.2 节讲的手动挡红利),显式 API 才有意义。还有一个常被忽视的中间答案:转译层与兼容层——把高层 API 调用翻译成底层 API 的运行时方案,让 D3D 11 代码跑在 Vulkan 上、让老 OpenGL 代码继续服役,维护期项目的常用缓兵之计。
三问之外,再给一个更直观的手感对比。每个图形 API 的第一步都是"创建设备"——向系统要一个可用的 GPU 句柄。同样的动作,三种方言的啰嗦程度不一样(伪代码,仅示意结构差异):
// D3D 12:一个函数入口,特性级别用协商 ID3D12Device* dev = nullptr; D3D12CreateDevice(adapter, FEATURE_LEVEL_11_0, IID_PPV_ARGS(&dev)); // Vulkan:实例、物理设备、逻辑设备三层递进,逐项声明队列 vkCreateInstance(&instInfo, nullptr, &instance); vkEnumeratePhysicalDevices(instance, &count, physDevs); vkCreateDevice(physDevs[0], &devInfo, nullptr, &device); // Metal:一行拿到默认设备,其余交给系统 id<MTLDevice> device = MTLCreateSystemDefaultDevice();
三段代码读出三种世界观。D3D 12 把复杂度收拢在一个入口函数与特性级别协商里,家族内部的其他组件(交换链、调试层)随后逐一挂接;Vulkan 要求你先把"实例—物理设备—逻辑设备"的层次亲手搭出来,换来的是对多 GPU、多队列拓扑的完全可见;Metal 则大包大揽地替你挑好设备,简洁的代价是选择权也交了出去。这段对比不是为了分高下,而是提醒你:样板代码的重量就是日常开发的重量,三问里"团队多大"那一问,称的就是这个东西。
主机是另一个值得单独一提的分支。家用主机的图形接口历来是厂商自研的私有方言:主机硬件固定,厂商把驱动薄薄一层直接暴露给开发者,省掉 PC 上"适配万千显卡"的兼容税。所以主机开发者手里的 API 名字你大概率没听过——它们不对外,但对内的哲学与这一节讲的一样,经历了从托管到显式的同一条演化线。理解了 PC 上四大 API 的分野,再去接触任何主机的文档,你会发现概念表几乎可以逐项对译:命令缓冲对命令列表,管线状态对 PSO,描述符对描述符。方言在变,语法在收敛——这正是近十年图形 API 演化最确定的方向。
把三问压缩成可直接执行的清单:
1. 目标平台含 Apple 系? 是 → 方案必须含 Metal(通常由引擎解决) 2. 只发 Windows / Xbox? 是 → D3D 12(追求上限)或 D3D 11(追求工期),OpenGL 仅限遗留 3. 需要跨非 Apple 多平台 + 自研引擎 + 长期项目? 是 → Vulkan(或 Vulkan + D3D 12 双后端) 4. 教学、原型、工具小软件? → 任一托管型 API 均可,别为 hello triangle 上手动挡
回到开头那个反例团队,他们的正确路径其实是:要么一开始就用商用引擎,要么在立项时就按三问把双后端的工作量写进排期。选型的智慧不在于选出"最好的 API",而在于让 API 的世界观与项目的平台、团队、目标互咬合。
下一章开始,我们钻进这辆车的底盘:COM 是焊点,适配器是电源,设备是发动机——初始化的每一步,第二章见。