为什么即使在三重缓冲时,我的 GPU 时间线中也会出现时间气泡?
Why are there time bubbles in my GPU timeline even when triple buffering?
我无法理解为什么在使用 PIX 时序捕获检查我的应用程序时我的 GPU 时间轴上有时间气泡。这是我正在谈论的其中一个时间泡泡的图片,以橙色突出显示:
时间线和我想象的完全不一样。由于我是三重缓冲,我希望 GPU 能够持续工作,帧之间没有任何时间间隔,因为 CPU 很容易在 GPU 处理完命令之前将命令提供给 GPU。相反,CPU 似乎并不领先 3 帧。似乎 CPU 在开始处理新帧之前一直在等待 GPU 完成。所以这让我想知道我的三重缓冲代码是否可能被破坏了?这是我移动到下一帧的代码:
void gpu_interface::next_frame()
{
UINT64 current_frame_fence_value = get_frame_resource()->fence_value;
UINT64 next_frame_fence_value = current_frame_fence_value + 1;
check_hr(swapchain->Present(0, 0));
check_hr(graphics_cmd_queue->Signal(fence.Get(), current_frame_fence_value));
{
// CPU and GPU frame-to-frame event.
PIXEndEvent(graphics_cmd_queue.Get());
PIXBeginEvent(graphics_cmd_queue.Get(), 0, "fence value: %d", next_frame_fence_value);
}
// Check if the next frame is ready to be rendered.
// The GPU must have reached at least up to the fence value of the frame we're about to render.
if (fence->GetCompletedValue() < current_frame_fence_value)
{
PIXBeginEvent(0, "CPU Waiting for GPU to reach fence value: %d", current_frame_fence_value);
// Wait for the next frame resource to be ready
fence->SetEventOnCompletion(current_frame_fence_value, fence_event);
WaitForSingleObject(fence_event, INFINITE);
PIXEndEvent();
}
// Next frame is ready to be rendered
// Update the frame_index. GetCurrentBackBufferIndex() gets incremented after swapchain->Present() calls.
frame_index = swapchain->GetCurrentBackBufferIndex();
frames[frame_index].fence_value = next_frame_fence_value;
}
这是整个时序捕获:https://1drv.ms/u/s!AiGFMy6hVmtNgaky52n7QDrQ6o7V1A?e=MFc4xW
编辑:固定答案
void gpu_interface::next_frame()
{
check_hr(swapchain->Present(0, 0));
UINT64 current_frame_fence_value = get_frame_resource()->fence_value;
UINT64 next_frame_fence_value = current_frame_fence_value + 1;
check_hr(graphics_cmd_queue->Signal(fence.Get(), current_frame_fence_value));
//// Update the frame_index. GetCurrentBackBufferIndex() gets incremented after swapchain->Present() calls.
frame_index = swapchain->GetCurrentBackBufferIndex();
// The GPU must have reached at least up to the fence value of the frame we're about to render.
size_t minimum_fence = get_frame_resource()->fence_value;
size_t completed = fence->GetCompletedValue();
if (completed < minimum_fence)
{
PIXBeginEvent(0, "CPU Waiting for GPU to reach fence value: %d", minimum_fence);
// Wait for the next frame resource to be ready
fence->SetEventOnCompletion(minimum_fence, fence_event);
WaitForSingleObject(fence_event, INFINITE);
PIXEndEvent();
}
frames[frame_index].fence_value = next_frame_fence_value;
{
// CPU and GPU frame-to-frame event.
PIXEndEvent(graphics_cmd_queue.Get());
PIXBeginEvent(graphics_cmd_queue.Get(), 0, "fence value: %d", next_frame_fence_value);
}
}
定时抓取正确代码:https://1drv.ms/u/s!AiGFMy6hVmtNgakzGizTiA_s-FwPqA?e=qIHHTw
您用 current_frame_fence_value
向队列发出信号,并在检查后立即
if (fence->GetCompletedValue() < current_frame_fence_value)
如果围栏完成了那个值。您需要检查下一帧的栅栏值以查看是否可以继续,即更新 frame_index
的 fence_values[frame_index]
。它会是这样的:
void gpu_interface::next_frame()
{
check_hr(swapchain->Present(0, 0));
UINT64 current_frame_fence_value = get_frame_resource()->fence_value;
check_hr(graphics_cmd_queue->Signal(fence.Get(), current_frame_fence_value));
UINT64 next_frame_fence_value = current_frame_fence_value + 1;
frame_index = swapchain->GetCurrentBackBufferIndex();
// The GPU must have reached at least up to the fence value of the frame we're about to render.
//current_frame_fence_value is not the fence value of the frame you are about the render, it is fence_values[frame_index]
//note that frame_index is updated before this call
if (fence->GetCompletedValue() < fence_values[frame_index])
{
// Wait for the next frame resource to be ready
fence->SetEventOnCompletion(fence_values[frame_index], fence_event);
WaitForSingleObject(fence_event, INFINITE);
}
frames[frame_index].fence_value = next_frame_fence_value;
}
尝试记下前几帧的围栏值,看看效果如何。
我无法理解为什么在使用 PIX 时序捕获检查我的应用程序时我的 GPU 时间轴上有时间气泡。这是我正在谈论的其中一个时间泡泡的图片,以橙色突出显示:
时间线和我想象的完全不一样。由于我是三重缓冲,我希望 GPU 能够持续工作,帧之间没有任何时间间隔,因为 CPU 很容易在 GPU 处理完命令之前将命令提供给 GPU。相反,CPU 似乎并不领先 3 帧。似乎 CPU 在开始处理新帧之前一直在等待 GPU 完成。所以这让我想知道我的三重缓冲代码是否可能被破坏了?这是我移动到下一帧的代码:
void gpu_interface::next_frame()
{
UINT64 current_frame_fence_value = get_frame_resource()->fence_value;
UINT64 next_frame_fence_value = current_frame_fence_value + 1;
check_hr(swapchain->Present(0, 0));
check_hr(graphics_cmd_queue->Signal(fence.Get(), current_frame_fence_value));
{
// CPU and GPU frame-to-frame event.
PIXEndEvent(graphics_cmd_queue.Get());
PIXBeginEvent(graphics_cmd_queue.Get(), 0, "fence value: %d", next_frame_fence_value);
}
// Check if the next frame is ready to be rendered.
// The GPU must have reached at least up to the fence value of the frame we're about to render.
if (fence->GetCompletedValue() < current_frame_fence_value)
{
PIXBeginEvent(0, "CPU Waiting for GPU to reach fence value: %d", current_frame_fence_value);
// Wait for the next frame resource to be ready
fence->SetEventOnCompletion(current_frame_fence_value, fence_event);
WaitForSingleObject(fence_event, INFINITE);
PIXEndEvent();
}
// Next frame is ready to be rendered
// Update the frame_index. GetCurrentBackBufferIndex() gets incremented after swapchain->Present() calls.
frame_index = swapchain->GetCurrentBackBufferIndex();
frames[frame_index].fence_value = next_frame_fence_value;
}
这是整个时序捕获:https://1drv.ms/u/s!AiGFMy6hVmtNgaky52n7QDrQ6o7V1A?e=MFc4xW
编辑:固定答案
void gpu_interface::next_frame()
{
check_hr(swapchain->Present(0, 0));
UINT64 current_frame_fence_value = get_frame_resource()->fence_value;
UINT64 next_frame_fence_value = current_frame_fence_value + 1;
check_hr(graphics_cmd_queue->Signal(fence.Get(), current_frame_fence_value));
//// Update the frame_index. GetCurrentBackBufferIndex() gets incremented after swapchain->Present() calls.
frame_index = swapchain->GetCurrentBackBufferIndex();
// The GPU must have reached at least up to the fence value of the frame we're about to render.
size_t minimum_fence = get_frame_resource()->fence_value;
size_t completed = fence->GetCompletedValue();
if (completed < minimum_fence)
{
PIXBeginEvent(0, "CPU Waiting for GPU to reach fence value: %d", minimum_fence);
// Wait for the next frame resource to be ready
fence->SetEventOnCompletion(minimum_fence, fence_event);
WaitForSingleObject(fence_event, INFINITE);
PIXEndEvent();
}
frames[frame_index].fence_value = next_frame_fence_value;
{
// CPU and GPU frame-to-frame event.
PIXEndEvent(graphics_cmd_queue.Get());
PIXBeginEvent(graphics_cmd_queue.Get(), 0, "fence value: %d", next_frame_fence_value);
}
}
定时抓取正确代码:https://1drv.ms/u/s!AiGFMy6hVmtNgakzGizTiA_s-FwPqA?e=qIHHTw
您用 current_frame_fence_value
向队列发出信号,并在检查后立即
if (fence->GetCompletedValue() < current_frame_fence_value)
如果围栏完成了那个值。您需要检查下一帧的栅栏值以查看是否可以继续,即更新 frame_index
的 fence_values[frame_index]
。它会是这样的:
void gpu_interface::next_frame()
{
check_hr(swapchain->Present(0, 0));
UINT64 current_frame_fence_value = get_frame_resource()->fence_value;
check_hr(graphics_cmd_queue->Signal(fence.Get(), current_frame_fence_value));
UINT64 next_frame_fence_value = current_frame_fence_value + 1;
frame_index = swapchain->GetCurrentBackBufferIndex();
// The GPU must have reached at least up to the fence value of the frame we're about to render.
//current_frame_fence_value is not the fence value of the frame you are about the render, it is fence_values[frame_index]
//note that frame_index is updated before this call
if (fence->GetCompletedValue() < fence_values[frame_index])
{
// Wait for the next frame resource to be ready
fence->SetEventOnCompletion(fence_values[frame_index], fence_event);
WaitForSingleObject(fence_event, INFINITE);
}
frames[frame_index].fence_value = next_frame_fence_value;
}
尝试记下前几帧的围栏值,看看效果如何。