问题描述
我正在编写一个 Direct3D 11 桌面应用程序,我正在尝试实现 this 文档引入的可等待交换链以减少延迟(特别是用户移动鼠标和显示器显示之间的延迟)变化)
现在的问题是,我在 WaitForSingleObject
返回的句柄上调用了 GetFrameLatencyWaitableObject
,但它根本没有等待并立即返回,(这导致我的应用程序获得了大约 200 到 1000 fps,当我的显示器是 60Hz 时)所以我的问题是:
我是否正确理解了可等待交换链的作用?根据我的理解,这个东西和 VSync 非常相似(它是通过在交换链上调用
SyncInterval
时为Present
参数传递 1 来完成的),只是不是等待前一帧完成在渲染循环结束时呈现在屏幕上(即我们调用Present
时),我们可以在渲染循环开始时等待(通过在可等待对象上调用WaitForSingleObject
)-
如果我理解正确,那么我错过了什么?还是这东西只适用于 UWP 应用程序? (因为该文档及其示例项目在 UWP 中?)
这是我创建交换链的代码:
SwapChainDesc.Format = dxgi_FORMAT_R8G8B8A8_UnorM;
SwapChainDesc.Stereo = false;
SwapChainDesc.SampleDesc.Count = 1;
SwapChainDesc.SampleDesc.Quality = 0;
SwapChainDesc.BufferUsage = D3D11_BIND_RENDER_TARGET;
SwapChainDesc.BufferCount = 2;
SwapChainDesc.Scaling = dxgi_SCALING_STRETCH;
SwapChainDesc.SwapEffect = dxgi_SWAP_EFFECT_FLIP_disCARD;
SwapChainDesc.AlphaMode = dxgi_ALPHA_MODE_UNSPECIFIED;
SwapChainDesc.Flags = dxgi_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
result = Factory2->CreateSwapChainForHwnd(Device.Get(),hWnd,&SwapChainDesc,&FullscreenDesc,nullptr,&SwapChain1);
if (Failed(result)) return result;
result = SwapChain2->SetMaximumFrameLatency(1); // also tried setting it to "2"
if (Failed(result)) return result;
WaitableObject = SwapChain2->GetFrameLatencyWaitableObject(); // also,I never call ResizeBuffers
if (WaitableObject == NULL) return E_FAIL;
这是我的渲染循环代码:
while (Running) {
if (WaitForSingleObject(WaitableObject,1000) == WAIT_OBJECT_0) {
Render();
HRESULT result = SwapChain->Present(0,0);
if (Failed(result)) return result;
}
}
解决方法
所以我花了一些时间下载和测试官方示例,现在我想我已经准备好回答我自己的问题了:
-
不,可等待交换链不像我想的那样工作,它不会等到前一帧出现在监视器上。相反,我认为它所做的可能是等到
Present
之前的所有工作完成(GPU 完成渲染以渲染目标,但尚未在显示器上显示) 或 queued(CPU 已完成向 GPU 发送所有命令,但 GPU 尚未完成执行它们)我不确定哪个是真实情况,但理论上,任何一个都有助于减少输入延迟(根据我的测试,它确实如此,无论是在 VSync 开启还是关闭时),而且,现在我知道这件事与帧率控制几乎无关,我现在知道它不应该与垂直同步相提并论。 -
我不认为它仅限于 UWP
现在我想分享一些我自己总结的关于输入延迟和帧率控制的想法:
我现在认为减少输入延迟的概念和帧率控制的概念是相互排斥的,它们之间可能不存在完美的平衡点;
例如,如果我想将每个“vblank”的帧率限制为 1 帧,那么输入延迟(在理想情况下)将与监视器帧延迟一样高(对于 60hz 监视器约为 16 毫秒); 但是当我不限制帧率时,输入延迟将与 GPU 完成一帧所需的时间一样高(在理想情况下,大约 1 或 2 毫秒,这不仅在数量上显着更快,改进对用户的视角也是可见的),但会浪费大量帧(以及用于渲染它们的 CPU/GPU 资源)
作为一个FPS游戏玩家,我之所以要降低输入延迟是显而易见的,因为我讨厌输入延迟; 我想投资帧率控制的原因是:首先,我讨厌帧撕裂(比我讨厌输入延迟要多一点),其次,我想尽可能减少 CPU/GPU 的使用。
然而,最近我发现使用 flip model 完美地解决了帧撕裂(我在使用翻转模型时根本没有任何撕裂,不需要 VSync),所以我不必担心关于撕裂了。 所以我现在计划优先考虑减少延迟而不是帧率控制,直到有一天我转向 D3D12 以找出一种方法来减轻 CPU/GPU 的使用,同时保持低输入延迟。