我正在尝试使用Vulkan和C ++创建游戏。我必须使用带有线程的多个命令缓冲区 - 或者我认为如果我正确地执行它。
现在,我遇到了栅栏问题。控制台 - 我添加了一个验证层 - 说“Fence 0x21已经被另一个提交使用了。”
我从未在其他功能中使用过围栏。
下面的代码是绘图功能。我把这个函数称为循环。
update_ubo (); // this function just writes uniform data on the uniform buffer in the local device.
uint32_t image_index = 0;
VkResult result = vkAcquireNextImageKHR (device, swapchain, numeric_limits <uint64_t>::max (), semaphore_image_avail, fence, &image_index);
// I hope I'm using multithreading correctly.
// all command buffers recorded in record_commandbuffers function are secondary command buffers.
#pragma omp parallel for num_threads(thread::hardware_concurrency ())
for (int64_t i = 0 ; i < (int64_t) vkthreads.size () ; i ++)
record_commandbuffers (vkthreads [i], framebuffers [image_index]);
VkCommandBufferBeginInfo cmdbuf_info = {
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
nullptr,
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
nullptr
};
VkRenderPassBeginInfo renderpass_begin = {
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
nullptr,
renderpass,
framebuffers [image_index],
{
{ 0, 0 },
swapchain_extent
},
1,
&clear_value
};
vkBeginCommandBuffer (pcmdbuf, &cmdbuf_info);
vkCmdBeginRenderPass (pcmdbuf, &renderpass_begin, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
for (size_t i = 0 ; i < vkthreads.size () ; i ++)
vkCmdExecuteCommands (pcmdbuf, (uint32_t) vkthreads [i].cmdbufs.size (), vkthreads [i].cmdbufs.data ());
vkCmdEndRenderPass (pcmdbuf);
vkEndCommandBuffer (pcmdbuf);
if (result == VK_ERROR_OUT_OF_DATE_KHR)
window_changed ();
else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)
throw exception ("Could not acquire next images.");
VkPipelineStageFlags pipeline_flags [] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
VkSubmitInfo submit_info = {
VK_STRUCTURE_TYPE_SUBMIT_INFO,
nullptr,
1,
&semaphore_image_avail,
pipeline_flags,
1,
&pcmdbuf,
1,
&semaphore_render_finished
};
if (vkQueueSubmit (graphics_queue, 1, &submit_info, fence))
throw exception ("Could not submit information into the graphics queue.");
while (vkWaitForFences (device, 1, &fence, VK_TRUE, (uint64_t)100000000) == VK_TIMEOUT)
;
vkResetFences (device, 1, &fence);
VkSwapchainKHR swapchains [] = { swapchain };
VkPresentInfoKHR present_info = {
VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
nullptr,
1,
&semaphore_render_finished,
1,
swapchains,
&image_index,
nullptr
};
result = vkQueuePresentKHR (present_queue, &present_info);
if (result == VK_ERROR_OUT_OF_DATE_KHR)
window_changed ();
else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)
throw exception ("Could not presnet the queue.");
P.S。当我添加多线程(2000 fps到210 fps,在调试版本中)时,FPS显着下降,并且CPU使用率显着上升,这是预期的。我应该关心FPS吗?
答案 0 :(得分:2)
您将相同的围栏传递给AcquireNextImage和QueueSubmit,而无需等待。您只需将其传递给QueueSubmit,因为信号量将处理任何所需的同步。只需将VK_NULL_HANDLE传递给acquireNexImage。
由于线程开销而支付每帧5毫秒的巨大成本似乎有点陡峭我预计由于调度程序而需要一毫秒或两秒,尽管这取决于你实际上是多线程的。但是,只要每帧的总帧数保持在16毫秒以下,60帧/秒,这没什么大不了的。