dxvk icon indicating copy to clipboard operation
dxvk copied to clipboard

[d3d9] Added functionality to empty WaitForVBlank function.

Open kdobrowo opened this issue 3 years ago • 7 comments

kdobrowo avatar Sep 15 '22 08:09 kdobrowo

This code change fixes WaitForVbl WHQL test (d3d9).

kdobrowo avatar Sep 15 '22 08:09 kdobrowo

I imagine it is due to the test being broken that it fixes the test?

It is not possible for us to implement this properly without present timing maybe (or doing something hacky with present wait).

misyltoad avatar Sep 15 '22 08:09 misyltoad

The test:

  1. calls present
  2. calls WaitForVBlank which should "Suspend execution of the calling thread until the next vertical blank signal." (https://docs.microsoft.com/en-us/windows/win32/api/d3d9/nf-d3d9-idirect3ddevice9ex-waitforvblank)
  3. measures time between presents

This is why SyncFrameLatency was added there.

Isn't it good enough solution?

kdobrowo avatar Sep 15 '22 09:09 kdobrowo

No for two reasons:

  • Our frame latency implementation does not use present wait right now. (It is triggered on the present thread when we call queuepresent, not on vblank or TTL)
  • The call you are using waits for up to the Max frame latency, not 1.

misyltoad avatar Sep 15 '22 09:09 misyltoad

If the docs are anything to go by, this function doesn't really interact with presents anyway, so even present_wait wouldn't really help. We can't really implement this correctly.

The main problem with this particular implementation is that we'll return immediately if

  • the app is CPU-bound
  • there is any sort of GPU->CPU sync point between frames (e.g. occlusion queries)
  • no presents are queued between calls

I think there's a way to come somewhat close to expected behaviour if we store a CPU-side timer somewhere and do something like this (pseudocode):

auto now = dxvk::high_resolution_clock::now();
auto refreshPeriod = getDisplayRefreshPeriod();
auto vblankCount = (now - m_startTime) / refreshPeriod;
auto target = m_startTime + (vblankCount + 1) * refreshPeriod;
sleep_until(target);

This is going to need some preliminary work though, and may behave weirdly in VRR scenarios.

doitsujin avatar Sep 15 '22 10:09 doitsujin

I made a proof-of-concept implementation in this branch, this can be ported to d3d9 fairly easily.

doitsujin avatar Sep 15 '22 13:09 doitsujin

@kdobrowo Friendly ping. What is the status of this?

Blisto91 avatar Mar 09 '23 09:03 Blisto91