DXGI Waitable SwapChain 不等待 (D3D11)

问题描述

网站上还有一个同名问题,但那个问题没有解决我的问题

我正在编写一个 Direct3D 11 桌面应用程序,我正在尝试实现 this 文档引入的可等待交换链以减少延迟(特别是用户移动鼠标和显示显示间的延迟)变化)

现在的问题是,我在 WaitForSingleObject 返回的句柄上调用GetFrameLatencyWaitableObject,但它根本没有等待并立即返回,(这导致我的应用程序获得了大约 200 到 1000 fps,当我的显示器是 60Hz 时)所以我的问题是:

  1. 我是否正确理解了可等待交换链的作用?根据我的理解,这个东西和 VSync 非常相似(它是通过在交换链上调用 SyncInterval 时为 Present 参数传递 1 来完成的),只是不是等待前一帧完成在渲染循环结束时呈现在屏幕上(即我们调用 Present 时),我们可以在渲染循环开始时等待(通过在可等待对象上调用 WaitForSingleObject

  2. 如果我理解正确,那么我错过了什么?还是这东西只适用于 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;
        }
    }

解决方法

所以我花了一些时间下载和测试官方示例,现在我想我已经准备好回答我自己的问题了:

  1. 不,可等待交换链不像我想的那样工作,它不会等到前一帧出现在监视器上。相反,我认为它所做的可能是等到 Present 之前的所有工作完成GPU 完成渲染以渲染目标,但尚未在显示器上显示) 或 queuedCPU 已完成向 GPU 发送所有命令,但 GPU 尚未完成执行它们)我不确定哪个是真实情况,但理论上,任何一个都有助于减少输入延迟(根据我的测试,它确实如此,无论是在 VSync 开启还是关闭时),而且,现在我知道这件事与帧率控制几乎无关,我现在知道它不应该与垂直同步相提并论。

  2. 我不认为它仅限于 UWP

现在我想分享一些我自己总结的关于输入延迟和帧率控制的想法:

我现在认为减少输入延迟的概念和帧率控制的概念是相互排斥的,它们之间可能不存在完美的平衡点;

例如,如果我想将每个“vblank”的帧率限制为 1 帧,那么输入延迟(在理想情况下)将与监视器帧延迟一样高(对于 60hz 监视器约为 16 毫秒); 但是当我不限制帧率时,输入延迟将与 GPU 完成一帧所需的时间一样高(在理想情况下,大约 1 或 2 毫秒,这不仅在数量上显着更快,改进对用户的视角也是可见的),但会浪费大量帧(以及用于渲染它们的 CPU/GPU 资源)

作为一个FPS游戏玩家,我之所以要降低输入延迟是显而易见的,因为我讨厌输入延迟; 我想投资帧率控制的原因是:首先,我讨厌帧撕裂(比我讨厌输入延迟要多一点),其次,我想尽可能减少 CPU/GPU 的使用。

然而,最近我发现使用 flip model 完美地解决了帧撕裂(我在使用翻转模型时根本没有任何撕裂,不需要 VSync),所以我不必担心关于撕裂了。 所以我现在计划优先考虑减少延迟而不是帧率控制,直到有一天我转向 D3D12 以找出一种方法来减轻 CPU/GPU 的使用,同时保持低输入延迟。