Vulkan 渲染流程
简单说明一下Vulkan的渲染流程,不涉及太具体的使用。
初始化
全局和设备
VkInstance,创建一个实例,包含应用的名字、版本、使用的VulkanAPI版本等;同时指定要启用的Instance 扩展和验证层。之后所有的Vulkan对象都是依赖它的
VkPhjysicsDevice,物理设备(GPU),先通过 vkEnumeratePhysicalDevices 查询主机上的 GPU。然后可以根据评分策略来选择合适的物理设备
VkDevice,在选定的 VkPhysicalDevice 上创建。需要指定要启用的 Device 拓展以及要创建哪些 queue family 的 queue,和每个 queue 的数量和优先级
VkQueue 队列按功能可以分为:
- Graphics queue:提交绘制命令。
- Compute queue:提交计算任务。
- Transfer queue:提交数据传输任务。
- Present queue:提交呈现任务(把 image 显示到屏幕)。
窗口和呈现
VkSurfaceKHR,窗口表面,由窗口系统(GLFW/Win32/X11 以及其他)创建。作用是沟通了Vulkan和OS的窗口,(如果离屏渲染就不需要这个)。
同时,它和物理设备共同决定这个 GPU 是否支持在该 surface 上呈现,以及支持哪些 surface format、present mode 等
VkSwapchainKHR,交换链,基于 VkDevice + VkSurfaceKHR 创建。本质上是一组可以被 present 出来的 VkImage 管理器。一些关键参数 ——
minImageCount:交换链中 image 的数量(通常 2 或 3)。imageFormat/colorSpace:颜色格式。imageExtent:分辨率(通常等于窗口大小)。presentMode:呈现模式(FIFO / MAILBOX / IMMEDIATE 等)。
它的运行逻辑是在每一帧的时候用 vkAcquireNextImageKHR 从 swapchain 拿一张 image,接着渲染到这张 image 上,最后用 vkQueuePresentKHR 把它呈现到屏幕。
渲染配置
VkPipeline,用来描述GPU侧的渲染流程,大致为——
- Shader 阶段(vertex / fragment / optional others)。
- 顶点输入布局(vertex buffer 的格式)。
- 图元装配(点/线/三角形)。
- 光栅化设置(填充/线框、背面剔除、正面朝向)。
- 多重采样(MSAA)。
- 颜色混合(blending)。
- 深度/模板测试(如果有)。
值得注意,pipeline 一旦创建后不可修改,只能重新创建新的 pipeline。
更值得注意,因为它只是单纯的描述GPU侧的行为,所以Pipeline 必须与某个 RenderPass 的某个 Subpass 匹配,否则 pipeline 无法使用
VkRenderPass,用于描述渲染过程,pipeline 只是告诉 GPU 要怎么流水线式的工作,还需要一层用于描述完整渲染流程的工作 ——
- 使用哪些 attachment(color / depth / stencil)。
- 每个 attachment 的 load/store 行为(清空、保留、丢弃)。
- attachment 的初始布局和最终布局。
- subpass 之间的依赖关系。
可以简单理解为「这次渲染要怎么用这些图像资源」的高层脚本。
VkFramebuffer 具体的渲染目标实例
- 和
VkRenderPass配合使用。 - 把一组具体的
VkImageView绑定到 render pass 的 attachment 上。 - 对于 swapchain:
- 通常是「每个 swapchain image 对应一个 framebuffer」。
即告诉本次渲染具体需要渲染到哪几张图上。
命令和同步
VkCommandBuffer,用来录制具体的 GPU 命令 ——
- 开始 render pass
- 绑定 pipeline
- 绑定 vertex buffer
- 发出 draw call 等。
录制完成后,通过 vkQueueSubmit 提交到某个 VkQueue 执行。
CommandBuffer 本身不执行任何操作,它只是一个“命令列表”。只有提交到 Queue 后才会被 GPU 执行
VkCommandPool,和某一个 Queue Family 绑定,用于分配 VkCommandBuffer,提升效率
异步的提交一定涉及到同步数据的问题 ——
VkSemaphore信号量- 用于 GPU-GPU 或 GPU-present 之间的同步。
- 常见用法:
imageAvailableSemaphore:image 可用 → 才能开始渲染。renderFinishedSemaphore:渲染完成 → 才能呈现。
VkFence栅栏- 用于 GPU-CPU 同步。
- 常见用法:
- CPU 等待某一帧的 GPU 提交完成,再重用对应的资源(command buffer、同步对象等)。
资源对象
VkBuffer,所有线性数据都存放在里面—— 顶点、索引、uniform、storage 等 VkImage:二维/三维图像数据(颜色贴图、深度贴图、G-buffer 等)。
但是需要注意,在VkBuffer和VkImage创建的时候并不会自动绑定内存,后面需要手动显式的分配/绑定
VkDescriptorSet (以及其他描述表)
VkDescriptorSetLayout:描述 shader 可见的资源布局:- 第几个 binding 是 uniform buffer?
- 第几个 binding 是 sampled image?
VkDescriptorPool:用来分配 descriptor set 的池。VkDescriptorSet:具体的一组绑定:- 把某个 uniform buffer / image view / sampler 绑定到某个 binding 上。
- 作用:
- 在 draw call 前,通过
vkCmdBindDescriptorSets把这些资源绑定给 pipeline 使用。 可以理解为:「告诉 shader:你要的数据在哪」的描述表,单独设计这一层的原因是 Vulkan 不允许 shader 直接访问资源,必须通过 DescriptorSet 显式绑定资源,使得资源访问完全可追踪、可验证、可同步。
- 在 draw call 前,通过
组装到一起
先初始化Instance和各个设备、模块;
然后是渲染过程——
- CPU等待上一帧的
VkFence vkAcquireNextImageKHR从 swapchain 获取一张 image,signalimageAvailableSemaphore- 重置并录制
VkCommandBuffer:vkCmdBeginRenderPass(指定 render pass + framebuffer + clear color)。vkCmdBindPipeline。- 绑定 vertex buffer / descriptor set(如果有)。
vkCmdDraw。vkCmdEndRenderPass。
- 提交命令
- 等待
imageAvailableSemaphore。 - 执行 command buffer。
- signal
renderFinishedSemaphore+inFlightFence。
- 等待
- 展示图片
- 等待
renderFinishedSemaphore。 - 把对应的 swapchain image 呈现到屏幕。
- 等待
不过一定要注意,这里 CPU/GPU、GPU/GPU、GPU/Present 之间的所有依赖是需要我们手动指定的,否则会产生数据竞争或未定义行为。
最后清理
![[Assets/Pasted image 20260312134308.png]]