Vulkan整体流程图

OpenTK 2026-07-08 11:19:22

整体流程图

┌─────────────────────────────────────────────────────────────────────────────┐
│                        Vulkan 初始化 13 步                                  │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                   阶段一:基础设施 (1-5)                            │   │
│  ├─────────────────────────────────────────────────────────────────────┤   │
│  │                                                                     │   │
│  │  ① createInstance()       —— 建立与Vulkan驱动的连接                │   │
│  │          ↓                                                          │   │
│  │  ② setupDebugMessenger()  —— 安装错误检测系统 (仅调试)             │   │
│  │          ↓                                                          │   │
│  │  ③ createSurface()        —— 创建渲染目标窗口                      │   │
│  │          ↓                                                          │   │
│  │  ④ pickPhysicalDevice()   —— 选择GPU硬件                           │   │
│  │          ↓                                                          │   │
│  │  ⑤ createLogicalDevice()  —— 打开与GPU的软件通信通道               │   │
│  │                                                                     │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                    ↓                                        │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                   阶段二:渲染目标 (6-7)                            │   │
│  ├─────────────────────────────────────────────────────────────────────┤   │
│  │                                                                     │   │
│  │  ⑥ createSwapChain()       —— 创建显示图像缓冲区                   │   │
│  │          ↓                                                          │   │
│  │  ⑦ createImageViews()      —— 让GPU可以写入图像                    │   │
│  │                                                                     │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                    ↓                                        │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                   阶段三:渲染配置 (8-10)                           │   │
│  ├─────────────────────────────────────────────────────────────────────┤   │
│  │                                                                     │   │
│  │  ⑧ createRenderPass()      —— 定义"怎么画"的步骤                   │   │
│  │          ↓                                                          │   │
│  │  ⑨ createGraphicsPipeline()—— 配置完整的渲染流水线                 │   │
│  │          ↓                                                          │   │
│  │  ⑩ createFramebuffers()    —— 将"怎么画"绑定到"画在哪里"           │   │
│  │                                                                     │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                    ↓                                        │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                   阶段四:命令准备 (11-13)                          │   │
│  ├─────────────────────────────────────────────────────────────────────┤   │
│  │                                                                     │   │
│  │  ⑪ createCommandPool()     —— 创建命令内存分配器                   │   │
│  │          ↓                                                          │   │
│  │  ⑫ createCommandBuffers()  —— 预分配命令存储空间                   │   │
│  │          ↓                                                          │   │
│  │  ⑬ createSyncObjects()     —— 创建CPU-GPU同步机制                  │   │
│  │                                                                     │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

类比理解:开一家"渲染餐厅"

┌─────────────────────────────────────────────────────────────────────────────┐
│                        类比:渲染餐厅 13 步                                 │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ① createInstance()          = 办理营业执照                                │
│     建立与Vulkan驱动的连接                                                  │
│                                                                             │
│  ② setupDebugMessenger()     = 安装监控摄像头                              │
│     安装错误检测系统                                                        │
│                                                                             │
│  ③ createSurface()           = 租用店面                                    │
│     创建窗口表面                                                            │
│                                                                             │
│  ④ pickPhysicalDevice()      = 选择厨房设备品牌                            │
│     选择合适的GPU                                                           │
│                                                                             │
│  ⑤ createLogicalDevice()     = 签订厨房使用合同                            │
│     创建逻辑设备                                                            │
│                                                                             │
│  ⑥ createSwapChain()         = 购买餐具(盘子)                            │
│     创建交换链图像                                                          │
│                                                                             │
│  ⑦ createImageViews()        = 将餐具摆上餐台                              │
│     为图像创建视图                                                          │
│                                                                             │
│  ⑧ createRenderPass()        = 制定出菜流程                                │
│     定义渲染操作结构                                                        │
│                                                                             │
│  ⑨ createGraphicsPipeline()  = 培训厨师团队                                │
│     配置完整的渲染流水线                                                    │
│                                                                             │
│  ⑩ createFramebuffers()      = 给每个盘子分配对应的菜                      │
│     绑定渲染目标和帧缓冲                                                    │
│                                                                             │
│  ⑪ createCommandPool()       = 采购记事本                                  │
│     创建命令内存分配器                                                      │
│                                                                             │
│  ⑫ createCommandBuffers()    = 在记事本上写菜谱                            │
│     分配命令缓冲区                                                          │
│                                                                             │
│  ⑬ createSyncObjects()       = 制定上菜顺序和时间                          │
│     创建CPU-GPU同步机制                                                     │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

为什么不能简化?依赖性分析

┌─────────────────────────────────────────────────────────────────────────────┐
│                        步骤依赖关系图                                        │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ① Instance ──────────┬─────► ② DebugMessenger                            │
│        │               │                                                    │
│        ├─────► ③ Surface ──┬──► ④ PhysicalDevice ──► ⑤ Device            │
│        │                   │                     │                         │
│        └───────────────────┘                     │                         │
│                                                   │                         │
│                                                   ▼                         │
│                                           ⑥ SwapChain                      │
│                                                   │                         │
│                                                   ▼                         │
│                                           ⑦ ImageViews                     │
│                                                   │                         │
│                                                   ▼                         │
│                                           ⑧ RenderPass ──┬──► ⑨ Pipeline  │
│                                                   │      │                 │
│                                                   ▼      ▼                 │
│                                           ⑩ Framebuffers                   │
│                                                   │                         │
│                                                   ▼                         │
│                                           ⑪ CommandPool                    │
│                                                   │                         │
│                                                   ▼                         │
│                                           ⑫ CommandBuffers                 │
│                                                   │                         │
│                                                   ▼                         │
│                                           ⑬ SyncObjects                    │
│                                                                             │
│  依赖规则:箭头指向的步骤必须在其之前创建                                    │
│  例如:⑥ SwapChain 需要 ⑤ Device 已经存在                                  │
│        ⑩ Framebuffers 需要 ⑦ ImageViews 和 ⑧ RenderPass 都存在            │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

每个步骤的核心问题

步骤核心问题如果不做会怎样?
① Instance"我要用Vulkan,谁在管理?"没有Vulkan驱动连接,无法进行任何操作
② Debug"出错了谁能告诉我?"验证层消息无法接收,调试困难
③ Surface"图像要画到哪里?"没有显示目标,无法呈现
④ PhysicalDevice"用哪块GPU?"不知道该用哪个显卡
⑤ Device"如何与GPU通信?"没有操作接口,无法提交命令
⑥ SwapChain"用多少个缓冲区?"没有帧缓冲区管理,画面闪烁
⑦ ImageViews"如何让GPU写入图像?"GPU无法直接操作交换链图像
⑧ RenderPass"渲染流程是什么?"不知道帧缓冲的加载/存储方式
⑨ Pipeline"用什么着色器?如何光栅化?"没有渲染状态,无法绘制三角形
⑩ Framebuffers"具体画到哪个图像上?"渲染不知道输出目标
⑪ CommandPool"命令分配在哪?"无法管理命令缓冲区内存
⑫ CommandBuffers"命令序列存哪?"每一帧都要重新分配,效率低
⑬ SyncObjects"CPU怎么知道GPU完成了?"CPU和GPU不同步,出现数据竞争

实际运行时的数据流

┌─────────────────────────────────────────────────────────────────────────────┐
│                          帧循环数据流                                       │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  初始化阶段创建的资源:                                                      │
│                                                                             │
│  ⑬ SyncObjects ──► ⑫ CommandBuffer ──► ⑤ Device ──► ④ PhysicalDevice    │
│       │                    │                    │              │             │
│       ▼                    ▼                    ▼              ▼             │
│  等待上一帧完成    vkCmdDraw(...)       vkQueueSubmit    GPU执行           │
│                        │                                                   │
│                        ▼                                                   │
│                   ⑨ Pipeline                                               │
│                        │                                                   │
│                        ▼                                                   │
│                   ⑩ Framebuffer ──► ⑦ ImageView ──► ⑥ SwapChain          │
│                        │                                                   │
│                        ▼                                                   │
│                   ⑧ RenderPass                                             │
│                        │                                                   │
│                        ▼                                                   │
│                   呈现到屏幕                                                │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

总结:为什么Vulkan要这么"麻烦"

// OpenGL风格 (隐含大量状态)
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 3);
// 驱动做了大量幕后工作,你不知道发生了什么

// Vulkan风格 (显式控制每一步)
// 1. 我需要先建立连接 (Instance)
// 2. 选择硬件 (PhysicalDevice)
// 3. 建立通信 (Device)
// 4. 配置目标 (SwapChain + Framebuffers)
// 5. 配置渲染方式 (RenderPass + Pipeline)
// 6. 准备命令 (CommandBuffer)
// 7. 同步执行 (SyncObjects)
// 每一步你都清楚发生了什么,并且可以优化

Vulkan的设计哲学就是: 让你精确控制每一步,消除驱动的"魔法",代价就是需要更多的初始化代码。这13步是Vulkan程序能够高效运行的基础架构!

 

 

 

完整渲染管线流程

┌─────────────────────────────────────────────────────────────────────────────────┐
│                         Vulkan 完整渲染过程                                      │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│  阶段1: CPU准备 (每帧开始)                                                      │
│  ════════════════════════════════════════════════════════════════════════════  │
│                                                                                 │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │ ① vkWaitForFences()                                                    │   │
│  │    ├─► CPU等待当前帧的栅栏被触发                                        │   │
│  │    ├─► 栅栏触发 = 上一帧的GPU工作已完成                               │   │
│  │    └─► CPU确认GPU可用,开始新帧                                        │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                      │                                           │
│                                      ▼                                           │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │ ② vkAcquireNextImageKHR()                                              │   │
│  │    ├─► CPU向GPU请求下一个可用的交换链图像                               │   │
│  │    ├─► GPU检查显示控制器状态                                            │   │
│  │    ├─► GPU返回可用的图像索引                                            │   │
│  │    └─► 图像获取完成后触发 imageAvailableSemaphore                       │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                      │                                           │
│                                      ▼                                           │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │ ③ vkResetFences()                                                      │   │
│  │    ├─► CPU重置当前帧的栅栏为未触发状态                                  │   │
│  │    └─► 准备用于本次提交                                                │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                      │                                           │
│                                      ▼                                           │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │ ④ vkResetCommandBuffer() + recordCommandBuffer()                       │   │
│  │    ├─► CPU重置命令缓冲区                                                │   │
│  │    ├─► CPU开始录制命令 (实际是写入内存)                                │   │
│  │    │                                                                     │   │
│  │    │ 录制的命令序列:                                                    │   │
│  │    │ ├─► vkCmdBeginRenderPass()                                        │   │
│  │    │ │   ├─► 设置渲染区域                                              │   │
│  │    │ │   ├─► 绑定帧缓冲                                                │   │
│  │    │ │   └─► 设置清除颜色 (清空为黑色)                                │   │
│  │    │ ├─► vkCmdBindPipeline()                                           │   │
│  │    │ │   └─► 绑定图形管线 (着色器+固定功能状态)                       │   │
│  │    │ ├─► vkCmdSetViewport()                                            │   │
│  │    │ │   └─► 设置视口大小                                              │   │
│  │    │ ├─► vkCmdSetScissor()                                             │   │
│  │    │ │   └─► 设置裁剪矩形                                              │   │
│  │    │ ├─► vkCmdDraw()                                                   │   │
│  │    │ │   ├─► 告诉GPU画3个顶点                                          │   │
│  │    │ │   ├─► 1个实例                                                   │   │
│  │    │ │   └─► 从顶点0开始                                              │   │
│  │    │ └─► vkCmdEndRenderPass()                                          │   │
│  │    │     └─► 结束渲染                                                  │   │
│  │    └─► vkEndCommandBuffer() 结束录制                                   │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                      │                                           │
│                                      ▼                                           │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │ ⑤ vkQueueSubmit()                                                      │   │
│  │    ├─► CPU构建提交信息                                                 │   │
│  │    ├─► 设置等待: imageAvailableSemaphore                               │   │
│  │    ├─► 设置命令: commandBuffers[currentFrame]                          │   │
│  │    ├─► 设置触发: renderFinishedSemaphore                               │   │
│  │    ├─► 设置栅栏: inFlightFences[currentFrame]                          │   │
│  │    ├─► CPU→GPU: 将命令缓冲区传输到GPU可访问内存                        │   │
│  │    └─► GPU调度器接收命令                                               │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                      │                                           │
│                                      ▼                                           │
│  阶段2: GPU执行 (异步进行)                                                      │
│  ════════════════════════════════════════════════════════════════════════════  │
│                                                                                 │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │ ⑥ GPU调度器处理                                                         │   │
│  │    ├─► 等待 imageAvailableSemaphore 被触发                              │   │
│  │    ├─► 检查命令缓冲区的依赖                                             │   │
│  │    └─► 开始执行命令序列                                                 │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                      │                                           │
│                                      ▼                                           │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │ ⑦ vkCmdBeginRenderPass() - GPU执行                                     │   │
│  │    ├─► GPU准备帧缓冲 (目标图像)                                        │   │
│  │    ├─► GPU执行清除操作 (填充为黑色)                                    │   │
│  │    └─► GPU进入渲染状态                                                 │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                      │                                           │
│                                      ▼                                           │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │ ⑧ 图形管线执行 (每个顶点/像素)                                         │   │
│  │                                                                         │   │
│  │    ┌─────────────────────────────────────────────────────────────┐     │   │
│  │    │ 输入汇编器 (Input Assembler)                                 │     │   │
│  │    │ ├─► 读取顶点数据 (从顶点缓冲区)                              │     │   │
│  │    │ ├─► 组装图元 (3个顶点组成三角形)                            │     │   │
│  │    │ └─► 输出顶点流                                              │     │   │
│  │    └─────────────────────────────────────────────────────────────┘     │   │
│  │                                      │                                   │   │
│  │                                      ▼                                   │   │
│  │    ┌─────────────────────────────────────────────────────────────┐     │   │
│  │    │ 顶点着色器 (Vertex Shader) - GPU核心执行                    │     │   │
│  │    │ ├─► 输入: 顶点位置 (x, y, z)                                │     │   │
│  │    │ ├─► 处理: 模型变换、视图变换、投影变换                      │     │   │
│  │    │ ├─► 输出: 裁剪空间位置 (x, y, z, w)                        │     │   │
│  │    │ └─► 输出: 其他数据 (法线、纹理坐标、颜色)                   │     │   │
│  │    │                                                              │     │   │
│  │    │ 例子: 3个顶点                                               │     │   │
│  │    │   v0: (-0.5, -0.5, 0.0) → ( -0.5, -0.5, 0.0, 1.0 )        │     │   │
│  │    │   v1: ( 0.5, -0.5, 0.0) → (  0.5, -0.5, 0.0, 1.0 )        │     │   │
│  │    │   v2: ( 0.0,  0.5, 0.0) → (  0.0,  0.5, 0.0, 1.0 )        │     │   │
│  │    └─────────────────────────────────────────────────────────────┘     │   │
│  │                                      │                                   │   │
│  │                                      ▼                                   │   │
│  │    ┌─────────────────────────────────────────────────────────────┐     │   │
│  │    │ 细分/几何着色器 (可选) - 本例跳过                           │     │   │
│  │    └─────────────────────────────────────────────────────────────┘     │   │
│  │                                      │                                   │   │
│  │                                      ▼                                   │   │
│  │    ┌─────────────────────────────────────────────────────────────┐     │   │
│  │    │ 光栅化 (Rasterization) - GPU硬件单元                       │     │   │
│  │    │ ├─► 将三角形转换为片元 (像素)                              │     │   │
│  │    │ ├─► 计算片元覆盖范围                                        │     │   │
│  │    │ ├─► 插值顶点属性 (颜色、纹理坐标等)                        │     │   │
│  │    │ └─► 生成片元流                                              │     │   │
│  │    │                                                              │     │   │
│  │    │ 例子: 三角形覆盖了约5000个像素                              │     │   │
│  │    │   每个片元包含: 位置、插值的颜色、深度值                    │     │   │
│  │    └─────────────────────────────────────────────────────────────┘     │   │
│  │                                      │                                   │   │
│  │                                      ▼                                   │   │
│  │    ┌─────────────────────────────────────────────────────────────┐     │   │
│  │    │ 片段着色器 (Fragment Shader) - GPU核心执行                 │     │   │
│  │    │ ├─► 输入: 插值的顶点数据                                    │     │   │
│  │    │ ├─► 处理: 计算每个像素的颜色                                │     │   │
│  │    │ ├─► 可以: 纹理采样、光照计算、阴影计算                      │     │   │
│  │    │ └─► 输出: 颜色值 (R, G, B, A)                              │     │   │
│  │    │                                                              │     │   │
│  │    │ 例子: 三角形颜色从红到蓝渐变                                │     │   │
│  │    │   每个像素执行:                                              │     │   │
│  │    │     color = mix(red, blue, interpolatedValue)               │     │   │
│  │    │     return color                                            │     │   │
│  │    └─────────────────────────────────────────────────────────────┘     │   │
│  │                                      │                                   │   │
│  │                                      ▼                                   │   │
│  │    ┌─────────────────────────────────────────────────────────────┐     │   │
│  │    │ 深度/模板测试 (Depth/Stencil Test)                          │     │   │
│  │    │ ├─► 比较片元深度值与深度缓冲                                │     │   │
│  │    │ ├─► 如果通过: 写入颜色和深度                                │     │   │
│  │    │ └─► 如果失败: 丢弃片元                                      │     │   │
│  │    └─────────────────────────────────────────────────────────────┘     │   │
│  │                                      │                                   │   │
│  │                                      ▼                                   │   │
│  │    ┌─────────────────────────────────────────────────────────────┐     │   │
│  │    │ 颜色混合 (Color Blending)                                   │     │   │
│  │    │ ├─► 将片元颜色与帧缓冲中现有颜色混合                        │     │   │
│  │    │ ├─► 支持: 加法、乘法、Alpha混合等                          │     │   │
│  │    │ └─► 输出: 最终颜色到帧缓冲                                  │     │   │
│  │    └─────────────────────────────────────────────────────────────┘     │   │
│  │                                                                         │   │
│  │    注意: 每个像素都是并行处理的!                                      │   │
│  │    现代GPU有数千个核心,同时处理不同像素                              │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                      │                                           │
│                                      ▼                                           │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │ ⑨ vkCmdEndRenderPass() - GPU执行                                      │   │
│  │    ├─► 完成所有渲染操作                                               │   │
│  │    ├─► 执行布局转换 (COLOR_ATTACHMENT_OPTIMAL → PRESENT_SRC_KHR)      │   │
│  │    └─► 准备图像用于呈现                                               │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                      │                                           │
│                                      ▼                                           │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │ ⑩ 触发同步对象                                                         │   │
│  │    ├─► GPU触发 renderFinishedSemaphore (渲染完成信号量)                │   │
│  │    ├─► GPU触发 inFlightFences (栅栏)                                   │   │
│  │    └─► 通知CPU渲染已完成                                              │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                                                                 │
│  阶段3: 呈现 (Present)                                                          │
│  ════════════════════════════════════════════════════════════════════════════  │
│                                                                                 │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │ ⑪ vkQueuePresentKHR() - CPU提交呈现请求                               │   │
│  │    ├─► CPU构建呈现信息                                                 │   │
│  │    ├─► 设置等待: renderFinishedSemaphore (渲染必须完成)                │   │
│  │    ├─► 指定交换链和图像索引                                            │   │
│  │    └─► CPU→GPU: 提交呈现请求到呈现队列                                 │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                      │                                           │
│                                      ▼                                           │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │ ⑫ GPU呈现引擎执行                                                      │   │
│  │    ├─► GPU等待 renderFinishedSemaphore 触发                            │   │
│  │    ├─► GPU将图像交给显示控制器                                         │   │
│  │    └─► GPU更新交换链状态 (标记图像为"正在显示")                         │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                      │                                           │
│                                      ▼                                           │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │ ⑬ 显示控制器 (Display Controller) - 独立硬件                           │   │
│  │    ├─► 在下一个VBlank垂直同步信号时读取图像                             │   │
│  │    ├─► 将像素数据转换为显示信号                                        │   │
│  │    └─► 通过HDMI/DP发送到显示器                                         │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                      │                                           │
│                                      ▼                                           │
│  ┌─────────────────────────────────────────────────────────────────────────┐   │
│  │ ⑭ 显示器显示                                                           │   │
│  │    ├─► 接收显示信号                                                   │   │
│  │    ├─► 驱动LCD/OLED面板                                                │   │
│  │    └─► 用户看到三角形                                                 │   │
│  └─────────────────────────────────────────────────────────────────────────┘   │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘

详细的GPU流水线执行

┌─────────────────────────────────────────────────────────────────────────────────┐
│                        GPU内部流水线 (每个阶段并行)                            │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│  命令缓冲区 (Command Buffer)                                                    │
│  ┌─────────────────────────────────────────────────────────────────────┐       │
│  │ [BeginRenderPass] [BindPipeline] [SetViewport] [Draw] [EndRenderPass]│       │
│  └─────────────────────────────────────────────────────────────────────┘       │
│                                    │                                             │
│                                    ▼                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐       │
│  │ 前端 (Frontend)                                                     │       │
│  │ ├─► 命令解析器: 解析命令缓冲区中的命令                              │       │
│  │ ├─► 状态跟踪: 跟踪当前管线状态                                      │       │
│  │ └─► 任务分发: 将工作分发到各个流水线阶段                          │       │
│  └─────────────────────────────────────────────────────────────────────┘       │
│                                    │                                             │
│                                    ▼                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐       │
│  │ 顶点处理阶段 (Vertex Processing)                                    │       │
│  │ ┌─────────────────────────────────────────────────────────────┐     │       │
│  │ │ 顶点获取 (Vertex Fetch)                                      │     │       │
│  │ │ ├─► 从顶点缓冲区读取顶点数据                                │     │       │
│  │ │ └─► 每个顶点: 位置、颜色、法线、纹理坐标等                  │     │       │
│  │ └─────────────────────────────────────────────────────────────┘     │       │
│  │                              │                                        │       │
│  │                              ▼                                        │       │
│  │ ┌─────────────────────────────────────────────────────────────┐     │       │
│  │ │ 顶点着色器 (Vertex Shader) - 并行处理所有顶点               │     │       │
│  │ │ ├─► 顶点0: 位置变换、计算颜色                              │     │       │
│  │ │ ├─► 顶点1: 位置变换、计算颜色                              │     │       │
│  │ │ ├─► 顶点2: 位置变换、计算颜色                              │     │       │
│  │ │ └─► ... (如果有更多顶点)                                   │     │       │
│  │ │                                                              │     │       │
│  │ │ 每个顶点独立处理! 可以并行                                  │     │       │
│  │ └─────────────────────────────────────────────────────────────┘     │       │
│  │                              │                                        │       │
│  │                              ▼                                        │       │
│  │ ┌─────────────────────────────────────────────────────────────┐     │       │
│  │ │ 细分/几何处理 (可选)                                        │     │       │
│  │ │ ├─► 细分着色器: 增加三角形数量                             │     │       │
│  │ │ └─► 几何着色器: 生成/修改图元                             │     │       │
│  │ └─────────────────────────────────────────────────────────────┘     │       │
│  └─────────────────────────────────────────────────────────────────────┘       │
│                                    │                                             │
│                                    ▼                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐       │
│  │ 光栅化阶段 (Rasterization) - 固定功能硬件                          │       │
│  │ ┌─────────────────────────────────────────────────────────────┐     │       │
│  │ │ 图元装配 (Primitive Assembly)                               │     │       │
│  │ │ ├─► 组装顶点为三角形                                        │     │       │
│  │ │ └─► 三角形: (v0, v1, v2)                                   │     │       │
│  │ └─────────────────────────────────────────────────────────────┘     │       │
│  │                              │                                        │       │
│  │                              ▼                                        │       │
│  │ ┌─────────────────────────────────────────────────────────────┐     │       │
│  │ │ 扫描转换 (Scan Conversion)                                 │     │       │
│  │ │ ├─► 确定三角形覆盖了哪些像素                               │     │       │
│  │ │ ├─► 对每个像素计算重心坐标                                 │     │       │
│  │ │ └─► 生成片元 (Fragment)                                    │     │       │
│  │ │                                                              │     │       │
│  │ │ 例子: 1920x1080分辨率                                     │     │       │
│  │ │ 三角形覆盖了约5000个像素                                   │     │       │
│  │ │ 生成5000个片元                                             │     │       │
│  │ └─────────────────────────────────────────────────────────────┘     │       │
│  │                              │                                        │       │
│  │                              ▼                                        │       │
│  │ ┌─────────────────────────────────────────────────────────────┐     │       │
│  │ │ 属性插值 (Attribute Interpolation)                         │     │       │
│  │ │ ├─► 对每个片元插值顶点属性                                 │     │       │
│  │ │ ├─► 颜色: 从红到蓝渐变                                     │     │       │
│  │ │ └─► 其他属性: 纹理坐标、法线等                            │     │       │
│  │ └─────────────────────────────────────────────────────────────┘     │       │
│  └─────────────────────────────────────────────────────────────────────┘       │
│                                    │                                             │
│                                    ▼                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐       │
│  │ 片段处理阶段 (Fragment Processing)                                 │       │
│  │ ┌─────────────────────────────────────────────────────────────┐     │       │
│  │ │ 片段着色器 (Fragment Shader) - 并行处理所有片元            │     │       │
│  │ │ ├─► 片元0: 计算颜色                                        │     │       │
│  │ │ ├─► 片元1: 计算颜色                                        │     │       │
│  │ │ ├─► 片元2: 计算颜色                                        │     │       │
│  │ │ ├─► ... (5000个片元并行执行)                              │     │       │
│  │ │ └─► 输出: 每个片元的颜色值                                 │     │       │
│  │ │                                                              │     │       │
│  │ │ 注意: 现代GPU有数千个核心!                                 │     │       │
│  │ │ 所有片元同时执行                                            │     │       │
│  │ └─────────────────────────────────────────────────────────────┘     │       │
│  │                              │                                        │       │
│  │                              ▼                                        │       │
│  │ ┌─────────────────────────────────────────────────────────────┐     │       │
│  │ │ 深度/模板测试 (Per-Fragment Tests)                         │     │       │
│  │ │ ├─► 深度测试: 检查片元是否被遮挡                          │     │       │
│  │ │ ├─► 模板测试: 检查模板值                                   │     │       │
│  │ │ └─► 通过: 继续; 失败: 丢弃片元                            │     │       │
│  │ └─────────────────────────────────────────────────────────────┘     │       │
│  │                              │                                        │       │
│  │                              ▼                                        │       │
│  │ ┌─────────────────────────────────────────────────────────────┐     │       │
│  │ │ 颜色混合 (Color Blending)                                  │     │       │
│  │ │ ├─► 读取帧缓冲中的现有颜色                                │     │       │
│  │ │ ├─► 混合: newColor = src * srcFactor + dst * dstFactor     │     │       │
│  │ │ └─► 写入帧缓冲                                             │     │       │
│  │ └─────────────────────────────────────────────────────────────┘     │       │
│  └─────────────────────────────────────────────────────────────────────┘       │
│                                    │                                             │
│                                    ▼                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐       │
│  │ 写回 (Write Back)                                                  │       │
│  │ ├─► 将渲染结果写入交换链图像                                       │       │
│  │ ├─► 更新深度/模板缓冲                                             │       │
│  │ └─► 完成一个帧的渲染                                               │       │
│  └─────────────────────────────────────────────────────────────────────┘       │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘

同步与等待机制

┌─────────────────────────────────────────────────────────────────────────────────┐
│                        CPU-GPU 同步机制                                          │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│  时间线 (多帧重叠执行):                                                          │
│                                                                                 │
│  帧 N-1           帧 N             帧 N+1                                       │
│  ├────────────────┼────────────────┼────────────────┤                           │
│                                                                                 │
│  CPU:                                                                           │
│  ├──────────────────────────────────────────────────────────────────────────┤   │
│  │ Frame N-1:       Frame N:          Frame N+1:                           │   │
│  │ 录制命令        等待栅栏           录制命令                             │   │
│  │ 提交命令        获取图像           提交命令                             │   │
│  │ 呈现            录制命令           呈现                                 │   │
│  │                 提交命令                                                │   │
│  │                 呈现                                                    │   │
│  └──────────────────────────────────────────────────────────────────────────┘   │
│                                                                                 │
│  GPU:                                                                            │
│  ├──────────────────────────────────────────────────────────────────────────┤   │
│  │ Frame N-1:       Frame N:          Frame N+1:                           │   │
│  │ 执行命令        等待图像可用       执行命令                             │   │
│  │ 呈现            执行命令           呈现                                 │   │
│  │                 呈现                                                    │   │
│  └──────────────────────────────────────────────────────────────────────────┘   │
│                                                                                 │
│  同步点:                                                                        │
│  ● = 栅栏 (Fence) - CPU等待GPU                                                │
│  ▲ = 信号量 (Semaphore) - GPU等待GPU                                          │
│  ─ = 数据依赖                                                                  │
│                                                                                 │
│  帧 N 的详细同步:                                                               │
│  ┌─────────────────────────────────────────────────────────────────┐          │
│  │                                                                 │          │
│  │  CPU                           GPU                              │          │
│  │  │                             │                                │          │
│  │  │ ① vkWaitForFences()        │                                │          │
│  │  │    ● 等待上一帧完成         │                                │          │
│  │  │                             │                                │          │
│  │  │ ② vkAcquireImage()         │                                │          │
│  │  │    ├──────────────────────►│                                │          │
│  │  │    │  请求图像              │                                │          │
│  │  │    │                        │   等待显示控制器               │          │
│  │  │    │                        │   选择可用图像                 │          │
│  │  │    │◄──────────────────────┤                                │          │
│  │  │    │  返回图像索引          │                                │          │
│  │  │    │                        │ ▲ 触发imageAvailableSemaphore │          │
│  │  │                             │                                │          │
│  │  │ ③ vkResetFences()          │                                │          │
│  │  │    ● 重置栅栏               │                                │          │
│  │  │                             │                                │          │
│  │  │ ④ recordCommandBuffer()    │                                │          │
│  │  │    录制命令                 │                                │          │
│  │  │                             │                                │          │
│  │  │ ⑤ vkQueueSubmit()          │                                │          │
│  │  │    ├──────────────────────►│                                │          │
│  │  │    │  提交命令              │   等待imageAvailable          │          │
│  │  │    │                        │   执行渲染                     │          │
│  │  │    │                        │ ▲ 触发renderFinished          │          │
│  │  │    │                        │ ● 触发Fence                   │          │
│  │  │                             │                                │          │
│  │  │ ⑥ vkQueuePresent()         │                                │          │
│  │  │    ├──────────────────────►│                                │          │
│  │  │    │  请求呈现              │   等待renderFinished          │          │
│  │  │    │                        │   交给显示控制器               │          │
│  │  │    │◄──────────────────────┤                                │          │
│  │  │    │  呈现完成              │                                │          │
│  │  │                             │                                │          │
│  │  │ ⑦ currentFrame++           │                                │          │
│  │  │                             │                                │          │
│  └─────────────────────────────────────────────────────────────────┘          │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘

性能优化关键点

┌─────────────────────────────────────────────────────────────────────────────────┐
│                        性能优化关键点                                            │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│  1. 减少CPU-GPU同步等待                                                         │
│     ├─► 使用双重/三重缓冲 (MAX_FRAMES_IN_FLIGHT = 2 或 3)                    │
│     ├─► CPU和GPU同时工作,互不阻塞                                             │
│     └─► 避免 vkDeviceWaitIdle() (除非必要)                                    │
│                                                                                 │
│  2. 减少状态切换                                                                 │
│     ├─► 在命令缓冲区中批量录制命令                                              │
│     ├─► 对相似的绘制调用排序,减少管线切换                                      │
│     └─► 使用 push constants 代替 descriptor sets (更快的更新)                  │
│                                                                                 │
│  3. 减少数据传输                                                                 │
│     ├─► 尽可能在GPU显存中保持数据 (不频繁更新)                                 │
│     ├─► 使用 staging buffer 异步传输顶点/纹理数据                              │
│     └─► 避免每帧更新 large uniform buffers                                     │
│                                                                                 │
│  4. 利用GPU并行性                                                               │
│     ├─► 尽量使用 compute shader 做通用计算                                     │
│     ├─► 利用多线程录制命令缓冲区 (vkBeginCommandBuffer 支持)                   │
│     └─► 使用 indirect draws 减少CPU开销                                        │
│                                                                                 │
│  5. 呈现模式选择                                                                 │
│     ├─► MAILBOX: 低延迟,无撕裂 (推荐游戏)                                     │
│     ├─► FIFO: 垂直同步,稳定 (推荐视频播放)                                    │
│     └─► IMMEDIATE: 最低延迟,可能撕裂 (推荐VR)                                 │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘

 

...全文
263 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

4

社区成员

发帖
与我相关
我的任务
社区描述
openTK、OpenGL、WebGL技术学习交流
图形渲染c#程序人生 技术论坛(原bbs) 广东省·深圳市
社区管理员
  • 亿只小灿灿
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧