semaphore用于 同步不同的queue之间,或者同一个queue不同的submission之间的执行顺序。
一般来说semaphore解决的是队列中的渲染和呈现两个任务的同步的,渲染和呈现都是以命令的形式提交到队列中的,由于vulkan的多线程特性,这两者不一定谁先执行,但是我们的逻辑又得要求先要渲染完才能去呈现,所以引入了信号量来解决这个问题。
类似于fence,semaphore也有signaled和unsignaled的状态之分,但是semaphore,我们没有办法显式的设置,重置和等待它。
在GPU的draw任务中,主要做下面的三件事:
• 从交换链获取一张图像
• 对帧缓冲附着执行指令缓冲中的渲染指令
• 返回渲染后的图像到交换链进行呈现操作
所以我们需要两个semaphore,一个信号量发出图像已经被获取,可以开始渲染的信号;一个信号量发出渲染已经结束,可以开始呈现的信号。
首先创建两个信号量1
2
3
4
5VkSemaphore imageAvailableSemaphore;
VkSemaphore renderFinishedSemaphore;
vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphore);
vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphore);
然后在获取图像时,当图像能够获取到后, 会设置imageAvailableSemaphore1
VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
然后我们在vkQueueSubmit的时候,会设置需要等待的semaphore,以及vkQueueSubmit完成后需要设置的semaphore1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
VkSemaphore waitSemaphores[] = { imageAvailableSemaphore };
VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = waitSemaphores; // 需要等待的semaphore
submitInfo.pWaitDstStageMask = waitStages;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffers[imageIndex];
VkSemaphore signalSemaphores[] = { renderFinishedSemaphore};
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signalSemaphores; // 需要设置的semaphore
vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[currentFrame]);
同样在prensent的时候,也有需要等待的semaphore,就是上面渲染命令完成后设置的信号量renderFinishedSemaphore1
2
3
4
5
6
7
8
9
10
11
12
13VkPresentInfoKHR presentInfo{};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presentInfo.waitSemaphoreCount = 1;
presentInfo.pWaitSemaphores = signalSemaphores;
VkSwapchainKHR swapChains[] = { swapChain };
presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = swapChains;
presentInfo.pImageIndices = &imageIndex;
result = vkQueuePresentKHR(presentQueue, &presentInfo);