概述

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
);

使用建议

  1. 选择最小范围的同步原语
  2. 尽量避免使用全局内存屏障
  3. 优先使用 pipeline barriers 而不是 events
  4. 正确指定 pipeline stages 和 access masks
  5. 注意同步开销,避免过度同步

示例场景

// 渲染到交换链
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 应用程序正确处理资源访问和命令执行顺序。选择合适的同步机制对性能有重要影响。