在 Vulkan 中,Window Surface(窗口表面,通常对应句柄 VkSurfaceKHR) 是一个连接 Vulkan 图形管道 与 操作系统的窗口系统(OS Window System) 的跨平台抽象层桥梁。

简单来说:Vulkan 本身是一个极其纯粹的硬件渲染 API,它甚至不知道屏幕、窗口、或者“显示”是什么。它只负责在显存里往一片内存(Image)里涂颜色。

而 Window Surface 就是我们向操作系统申请的一块“画布”,有了它,Vulkan 才知道应该把显存里画好的图像投递到屏幕的哪个具体窗口上。

1. 为什么不能直接画在窗口上?(核心痛点)#

在老旧图形 API 比如 OpenGL 中,API 会隐式地处理与操作系统的对接。但 Vulkan 为了追求绝对的平台无关性,把底牌彻底掀开了:

  • Vulkan 的世界: 只有物理设备、逻辑设备、命令缓冲区、渲染管线、显存。
  • 操作系统的世界: Windows 认的是 HWND(窗口句柄)和 HDC;Linux 认的是 Window 变体(X11 或 Wayland);macOS 认的是 CAMetalLayer。

这两者由于设计哲学完全不同,根本无法直接对话。

VkSurfaceKHR 就是那个连接两者的中间人。 它把操作系统的原生窗口句柄(比如 Windows 的 HWND)包装起来,变成一个通用的、Vulkan 认识的对象。

2. 名字后面的 KHR 代表什么?#

如果仔细观察,会发现核心的 Vulkan 对象(如 VkDevice、VkImage)后面都没有后缀,而 VkSurfaceKHR 后面跟着 KHR。

其中,KHR 代表 Khronos 官方扩展(Window System Integration, WSI)。

  • 因为并不是所有的 Vulkan 程序都需要显示器。比如运行在高性能服务器上的 AI 训练、离线光线追踪渲染器,它们只需要把渲染结果保存为图片,不需要弹出一个窗口。
  • 因此,窗口显示功能被剥离出了核心规范,放进了扩展里。VkSurfaceKHR 就是由全局扩展 VK_KHR_surface 引入的。

3. Window Surface 是如何创建的?#

由于每个操作系统的窗口系统底层实现完全不同,Vulkan 官方针对不同平台提供了专属的“特化创建函数”。

如果纯手写跨平台代码,需要写一堆宏条件编译:

 1#if defined(VK_USE_PLATFORM_WIN32_KHR)
 2    // Windows 专用的创建表单
 3    VkWin32SurfaceCreateInfoKHR createInfo{};
 4    createInfo.hwnd = hwnd; // 传入 Win32 的窗口句柄
 5    vkCreateWin32SurfaceCreateInfoKHR(...);
 6    #elif defined(VK_USE_PLATFORM_XLIB_KHR)
 7    // Linux X11 专用
 8    VkXlibSurfaceCreateInfoKHR createInfo{};
 9    vkCreateXlibSurfaceKHR(...);
10#endif

C++ 现代工程实践(配合 GLFW)#

但是现在几乎没有人会去纯手写上面那些恶心的平台宏。我们通常会使用 GLFW。GLFW 会在内部自动判断当前的操作系统,只需要一行代码,它就能把 VkSurfaceKHR 完美创建出来:

1VkSurfaceKHR surface;
2// GLFW 内部会自动调用 vkCreateWin32SurfaceKHR 或 vkCreateXlibSurfaceKHR
3if (glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS) {
4    throw std::runtime_error("Failed to create window surface!");
5}

4. 拥有 Surface 之后,下一步做什么?#

创建好 Window Surface 只是第一步。在整个 Vulkan 初始化生命周期里,它是后续两个极为核心的步骤的强依赖参数:

① 筛选硬件队列族(Present Support Check)#

我们在聊“呈现队列”时提过,你需要拿着这个创建好的 surface 去质问物理显卡:“你的哪个队列族,能把画画好之后的图像安全地扔进这个 surface 里显示出来?”

1VkBool32 presentSupport = VK_FALSE;
2vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface, &presentSupport);

② 创建交换链(Swapchain)#

这是 Surface 最重要的归宿。有了 Surface,你才能向显卡申请交换链(Swapchain)。

交换链会在这个 Surface 背后开辟一个“前台缓冲区”和“后台缓冲区”(通常是 2~3 张图形图片,即双重缓冲或三重缓冲)。GPU 在后台缓冲区拼命画画,画完之后,通过交换链,把图片平铺到这个 Surface 上展示给玩家看。

总结#

  • Window Surface(VkSurfaceKHR) 不是一块真实的显存,也不是一个可以往里写数据的缓冲区。
  • 它是一个抽象的“显示表面占位符”。
  • 它的唯一任务,就是把操作系统的原生窗口死死地和 Vulkan 的世界锚定在一起。后续所有关于屏幕刷新率、垂直同步、交换链双缓冲、窗口缩放格式的配置,全部都要基于这个 Surface 来展开。

原文:Window Surface