概述
Vulkan 中的同步原语主要分为以下几类:
Semaphores (信号量)
VkSemaphore用于同步 GPU 队列之间的操作- 分两种:
// 二进制信号量 - 最常用
VK_SEMAPHORE_TYPE_BINARY
// 时间线信号量 - 可以有多个信号值
VK_SEMAPHORE_TYPE_TIMELINE主要用于:
- 交换链图像获取与渲染同步
- 多个队列间的工作同步
Fences (栅栏)
VkFence用于 CPU 和 GPU 之间的同步- 典型用途:
// 等待命令缓冲区执行完成
vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX);
// 重置fence以便重用
vkResetFences(device, 1, &fence);Events (事件)
VkEvent用于 GPU 命令之间的细粒度同步- 可以在 CPU 端设置和重置
vkCmdSetEvent(commandBuffer, event, VK_PIPELINE_STAGE_TRANSFER_BIT);
vkCmdWaitEvents(commandBuffer, ...);Pipeline Barriers (管线屏障)
- 用于同步管线内的操作
- 类型包括:
- Memory barriers (内存屏障)
- Buffer barriers (缓冲区屏障)
- Image barriers (图像屏障)
vkCmdPipelineBarrier(
commandBuffer,
srcStageMask,
dstStageMask,
0,
0, nullptr, // Memory barriers
0, nullptr, // Buffer barriers
1, &imageBarrier // Image barriers
);使用建议
- 选择最小范围的同步原语
- 尽量避免使用全局内存屏障
- 优先使用 pipeline barriers 而不是 events
- 正确指定 pipeline stages 和 access masks
- 注意同步开销,避免过度同步
示例场景
// 渲染到交换链
VkSemaphore imageAvailableSemaphore; // 图像可用信号量
VkSemaphore renderFinishedSemaphore; // 渲染完成信号量
VkFence inFlightFence; // CPU-GPU 同步栅栏
// 提交命令缓冲区
VkSubmitInfo submitInfo = {};
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = &imageAvailableSemaphore;
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = &renderFinishedSemaphore;
vkQueueSubmit(queue, 1, &submitInfo, inFlightFence);这些同步原语组合使用可以确保 Vulkan 应用程序正确处理资源访问和命令执行顺序。选择合适的同步机制对性能有重要影响。