前言
上章深入分析了帧循环中呈现阶段的具体实现。本章将分析多线程下的记录与提交,进一步剖析vsg帧循环过程中的同步机制,并揭露信号量(VkSemaphore)和围栏(VkFence)以及vsg::FrameBlock与vsg::Barrier在其中的作用。
目录
- 1 信号量(VkSemaphore)、栅栏(VkFence)、vsg::FrameBlock与vsg::Barrier
- 2 多线程记录与提交
1 信号量(VkSemaphore)、围栏(VkFence)与vsg::FrameBlock、vsg::Barrier
vsg::Semaphore封装了VkSaphore,用于将vulkan命令的完成与其他vulkan命令提交的开始同步,为GPU内部的同步;vsg::Fence封装了vkFence,用于同步Vulkan命令提交到队列的完成情况,用于应用程序(CPU端)与Vulkan命令提交到队列的完成情况(GPU端)的同步;vsg::FrameBlock提供了一种机制,用于同步等待新帧开始的线程;vsg::Barrier提供了一种同步多个线程的方法,一旦指定数量的线程加入Barrier,这些线程就会一起释放。
1.1 vsg::Semaphore
Semaphore::Semaphore(Device* device, VkPipelineStageFlags pipelineStageFlags, void* pNextCreateInfo) :
_pipelineStageFlags(pipelineStageFlags),
_device(device)
{
VkSemaphoreCreateInfo semaphoreInfo = {};
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
semaphoreInfo.pNext = pNextCreateInfo;
VkResult result = vkCreateSemaphore(*device, &semaphoreInfo, _device->getAllocationCallbacks(), &_semaphore);
if (result != VK_SUCCESS)
{
throw Exception{"Error: Failed to create semaphore.", result};
}
}
vsg::Semaphore构造函数使用vkCreateSemaphore创建信号量VkSemaphore,信号量的创建与某一逻辑设备绑定,即信号量可用于GPU内部同一队列或同一逻辑设备的不同队列间的同步。
Semaphore::~Semaphore()
{
if (_semaphore)
{
vkDestroySemaphore(*_device, _semaphore, _device->getAllocationCallbacks());
}
}
vsg::Semaphore析构函数使用vkDestroySemaphore释放信号量VkSemaphore。
1.2 vsg::Fence
vsg::Fence构造函数使用vkCreateFence创建VkFence,围栏的创建与某一逻辑设备绑定。
Fence::Fence(Device* device, VkFenceCreateFlags flags) :
_device(device)
{
VkFenceCreateInfo createFenceInfo = {};
createFenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
createFenceInfo.flags = flags;
createFenceInfo.pNext = nullptr;
if (VkResult result = vkCreateFence(*device, &createFenceInfo, _device->getAllocationCallbacks(), &_vkFence); result != VK_SUCCESS)
{
throw Exception{"Error: Failed to create Fence.", result};
}
}
vsg::Fence析构函数使用vkDestroyFence释放围栏。
Fence::~Fence()
{
if (_vkFence)
{
vkDestroyFence(*_device, _vkFence, _device->getAllocationCallbacks());
}
}
vsg::Fence在应用层(CPU端)的使用通过调用wait函数,其通过封装vkWaitForFences实现。
VkResult Fence::wait(uint64_t timeout) const
{
return vkWaitForFences(*_device, 1, &_vkFence, VK_TRUE, timeout);
}
vsg::Fence在GPU端使用时,需重置为无信号状态,否则可能会导致应用层调用vkWaitForFences卡死。
VkResult Fence::reset() const
{
return vkResetFences(*_device, 1, &_vkFence);
}
1.3 vsg::FrameBlock
vsg::FrameBlock提供了一种机制,用于同步等待新帧开始的线程。
std::mutex _mutex;
std::condition_variable _cv;
ref_ptr<FrameStamp> _value;
ref_ptr<ActivityStatus> _status;
上述代码为vsg::FrameBlock的成员变量,其通过对std::mutex和std::condition_variable的封装实现了一种针对vsg::FrameStamp是否变化的阻塞能力,即同步所有等待新帧开始的线程,而变量_status(vsg::ActivityStatus类型)用于标记vsg::FrameBlock的阻塞能力是否有效。
bool wait_for_change(ref_ptr<FrameStamp>& value)
{
std::unique_lock lock(_mutex);
while (_value == value && _status->active())
{
_cv.wait(lock);
}
value = _value;
return _status->active();
}
通过调用wait_for_change接口,当传入的vsg::FrameStamp对象与已有的一致时,阻塞应用程序所在线程。

最低0.47元/天 解锁文章
1126

被折叠的 条评论
为什么被折叠?



