2

there is another question with the same title on the site, but that one didn't solve my problem

I'm writing a Direct3D 11 desktop application, and I'm trying to implement waitable swap chain introduced by this document to reduce latency (specifically, the latency between when user moved the mouse and when the monitor displayed the change)

Now the problem is, I called WaitForSingleObject on the handle returned by GetFrameLatencyWaitableObject, but it did not wait at all and returned immediately, (which result in my application getting about 200 to 1000 fps, when my monitor is 60Hz) so my questions are:

  1. Did even I understand correctly what a waitable swap chain does? According to my understanding, this thing is very similar to VSync (which is done by passing 1 for the SyncInterval param when calling Present on the swap chain), except instead of waiting for a previous frame to finish presenting on the screen at the end of a render loop (which is when we're calling Present), we can wait at the start of a render loop (by calling WaitForSingleObject on the waitable object)

  2. If I understood correctly, then what am I missing? or is this thing only works for UWP applications? (because that document and its sample project are in UWP?)

here's my code to create swap chain:

    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;

here's my code to get waitable object:

    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;

and here's my code for render loop:

    while (Running) {
        if (WaitForSingleObject(WaitableObject, 1000) == WAIT_OBJECT_0) {
            Render();
            HRESULT result = SwapChain->Present(0, 0);
            if (FAILED(result)) return result;
        }
    }
wd357dui
  • 135
  • 1
  • 8
  • 1
    Heve you tried and compared with the official sample here: https://github.com/microsoftarchive/msdn-code-gallery-microsoft/tree/master/Official%20Windows%20Platform%20Sample/DirectX%20latency%20sample (even if it's UWP) – Simon Mourier Mar 17 '21 at 16:50
  • 1
    You present without vsync, so it is only natural that FPS are not limited. Note that use of waitable swap chain does not interfere with vsync, it only allows application to start rendering new frame precisely when GPU is ready for it and to do something useful instead of being blocked while waiting for `Present`. – user7860670 Mar 29 '21 at 09:13

1 Answers1

1

So I took some time to download and test the official sample, now I think I'm ready to answer my own questions:

  1. No, waitable swap chain does not work like how I think, it does not wait until a previous frame is presented on the monitor. Instead, I think what it does is probably to wait until all the work before Present are finished (GPU finished rendering to render target, but not yet displayed it on the monitor) or queued (CPU finished sending GPU all the commands, but GPU haven't finished executing them yet) I'm not sure which one is the real case, but either one, in theory, would help reduce input latency (and according to my tests, it did, both when VSync is on and off), also, now that I know that this thing has almost nothing to do with framerate control, I know now that it shouldn't be compared with VSync.

  2. I don't think it's limited to UWP

And now I'd like to share some ideas that I have concluded for myself about input latency and framerate control:

I now believe that the concept of reducing input latency and the concept of framerate control are mutually exclusive and that a perfect balance point between them probably doesn't exist;

for example, if I want to limit framerate to 1 frame per "vblank", then the input latency (in an ideal scenario) would be as high as the monitor frame latency (which is about 16ms for a 60hz monitor); but when I don't limit framerate, the input latency would be as high as how long a GPU would take to finish a frame (which in an ideal scenario, about 1 or 2ms, which is significantly faster not only in numbers, the improvement is visible to user's perspective as well), but a lot of frames (and CPU/GPU resources used to render them) would be wasted

As an FPS game player myself, the reason why I want to reduce input latency is obvious, is because I hate input lag; and the reasons why I want to invest in framerate control are: firstly, I hate frame tearing (a little more than how much I hate input lag), secondly, I want to ease CPU/GPU usage when possible.

However, recently I discovered that frame tearing is perfectly defeated by using flip model (I just don't get any tearing at all when using flip model, no VSync needed), so I don't need to worry about tearing anymore. So I now plan to prioritize latency reduction rather than framerate control until when and if one day I move on to D3D12 to figure out a way to ease CPU/GPU usage while preserving low input latency.

wd357dui
  • 135
  • 1
  • 8