dolphin icon indicating copy to clipboard operation
dolphin copied to clipboard

Implement VK_KHR_present_wait to instrument actual present timings

Open phire opened this issue 2 years ago • 11 comments

Very few GPUs currently support the VK_KHR_present_wait extension.

But it has better support on desktop GPUs than VK_GOOGLE_display_timing, and we can abuse it to get presentation timings, which we can use for pretty graphs of when the user actually sees the a new frame.

Why present timings?

Because the frame timings don't actually represent what the user experiences. For example, here is a 30 FPS game running vsyned on my 100hz monitor. Because 30 doesn't divide into 100, the frame pacing is bad.

image

For another example, this sometimes happens to a 59.97 fps game when vsynced to my monitor at 60hz. It only happens if dolphin manages to run without a single stutter for several min. I'm guessing my monitor is actually slightly lower than 59.97hz and eventually dolphin runs ahead and is forced to wait for vsync.

image

Supported GPUs/Drivers

Currently only Nvidia on both Linux and Windows. But the next release of Mesa will add present_wait for AMD and Intel GPUs. But only if you use X11 and set a flag to force it on

Limitations:

Currently doesn't support wayland. And X11 will only show true present timings when running in full screen. Otherwise you get the timing that the compositor accepted the frame. Not the true present timing. This is could probably be considered to be a bug in Xorg.

phire avatar Jan 23 '23 07:01 phire

But only if you use X11 and set a flag to force it on

Slight correction: present_wait will be exposed by default on x11 by the next mesa release if the application doesn't enable any extension that can't support it. Which means in practice that it'll be available if VK_KHR_wayland_surface isn't enabled.

mbriar avatar Jan 23 '23 11:01 mbriar

Not the behaviour I experienced. When I built the current mesa trunk from source, the extension wasn't listed until I created the following /etc/drirc:

<driconf>
  <device>
    <application name="all">
      <option name="vk_khr_present_wait" value="true" />
    </application>
  </device>
</driconf>

phire avatar Jan 24 '23 02:01 phire

If you used the linux version of vulkaninfo then this is expected, because it enables VK_KHR_wayland_surface and thus won't list present_wait by default. If you e.g. run the vulkaninfo.exe from the windows vulkan sdk on a recent version of wine, it will, however, list it by default, because wine only supports x11 at the moment and doesn't enable VK_KHR_wayland_surface.
As a side note, you don't need to edit drirc to force it on, vk_khr_present_wait=true also works as an environment variable, like all drirc options.

mbriar avatar Jan 24 '23 08:01 mbriar

If you used the linux version of vulkaninfo then this is expected

Oh... Right... Good point.

phire avatar Jan 27 '23 01:01 phire

Metal has an API much closer to VK_GOOGLE_display_timing (where you can ask for the actual time of the present, instead of just getting a callback some time after it happened)

Would it make sense to try to make the VideoCommon API support that here (being given timestamps instead of calculating them as "the time you called this function") or should I leave that for when I add a Metal implementation for this?

TellowKrinkle avatar Jan 29 '23 22:01 TellowKrinkle

D3D12 also has something very similar to VK_KHR_present_wait as far as I know. So it would make sense to design something in VideoCommon.

K0bin avatar Jan 29 '23 22:01 K0bin

This adds to VideoCommon. Just a question of what API we want there. Metal and VK_GOOGLE_display_timing can provide their own timestamp for the best accuracy VK_KHR_present_wait can't, and needs to rely on a CPU timestamp

The current API is just a function you call that records the current CPU timestamp as the time of the present.

TellowKrinkle avatar Jan 29 '23 22:01 TellowKrinkle

This adds to VideoCommon

Well. It's dubious if performance metrics should be considered to be part of video common or not. I want to move everything ImGUI out of VideoCommon into a DolphinImGui subproject that sits along side DolphinQt and DolphinNogui. The drawing parts of PerformanceMetrics would obviously move, and maybe the collection parts too?

But we do want a VideoCommon API eventually (potentially not part of this PR).

The wait on present behaviour is somewhat useful for the async present PR I'm about to work on. As part of my almost finished refactor that Kills Renderer, I'm thinking about adding a "VideoEvents" class that contains various frame life-cycle events to replace the current messy code in RenderBase::Swap.

Most importantly, a clean FrameEnd event that various things can hook into. But it would also be useful to have BeforePresent and AfterPresent events. That AfterPresent event could be defined to happen after present wait (if the backend/driver have support for it, otherwise you might just get instant or post-vsync timings).

It would also be nice to have a VideoCommon API that exposes historical present timings. When the driver/backend doesn't support VK_GOOGLE_display_timing or VK_EXT_present_timing, it can fall back to CPU time of present wait (or worse).

phire avatar Jan 30 '23 02:01 phire

This adds to VideoCommon. Just a question of what API we want there.

@TellowKrinkle My intended API ended up in the massive KillRenderer PR here

Which probably means this should wait for #11522 (and also #11539) before merging.

phire avatar Feb 04 '23 03:02 phire

I'd recommend using #11532 to record timings with something like m_present_counter.Count(present_times, true);, which should give you a really good graph.

If you begin recording something like frame latency, it would be like m_frame_latency.Count(latency, false);

There is more information about what the boolean does in the PR, but it should give you a nice way to get some fast graphs. I spent a lot of time optimizing the PerformanceTracker class so there shouldn't be too much overhead to adding more counters.

Sam-Belliveau avatar Feb 10 '23 19:02 Sam-Belliveau

I'm going to mark this as draft until I finish my current work refactoring the whole vulkan backend.

phire avatar Feb 11 '23 06:02 phire