Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] D3D12: Use waitable swap chain to reduce input latency #94960

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

alvinhochun
Copy link
Contributor

Using a waitable swap chain allows Godot to delay input processing until the swap chain is ready to accept a new frame. This moves the blocking wait that usually happens when trying to present a new frame while the swap chain queue is full, to before starting the process for a new frame, thus reducing input latency

(This is basically a straight port of what I have in #94503 to the D3D12 driver.)

Here is a trace with Intel Graphics Trace Analyzer:

trace

Zoomed in:

trace

GPUView:

GPUView

@alvinhochun alvinhochun marked this pull request as ready for review July 30, 2024 19:53
@alvinhochun alvinhochun requested review from a team as code owners July 30, 2024 19:53
@alvinhochun alvinhochun changed the title D3D12: Use waitable swap chain to reduce input latency [RFC] D3D12: Use waitable swap chain to reduce input latency Jul 30, 2024
@KeyboardDanni
Copy link
Contributor

I dig the idea behind waitable swapchains because it solves an issue that's plagued graphics APIs on PC for quite some time: will the call to Present() block or not? With a waitable swapchain we basically give control back to the application, and we know precisely when the next frame is ready. Also the ability to wait before we start on a new frame will certainly help with latency in double/triple-buffered frame queue scenarios (I don't think this is needed for single-buffered).

Oddly enough, Special K seems to recommend against waitable swapchains, citing stutter issues when DirectFlip deactivates. I'm not sure if they're referring to an intermittent stutter during the transition, or an ever-present stutter while DirectFlip is inactive. I don't think this is good reason to avoid waitable swapchains, but it might need investigation.

I'm a bit concerned that Linux and Mac will be left out when it comes to these improvements. Is anyone familiar with the current landscape over on those other platforms? Do we have access to waitable swapchains there too?

@alvinhochun
Copy link
Contributor Author

I made an attempt at implementing an equivalent for Vulkan, but I have no idea if it works: #94973

@RandomShaper
Copy link
Member

Can you elaborate on how this is different from the mailbox V-sync mode, the way it's currently implemented?

Aside, the rendering driver interacting with higher level components (Main) shouldn't happen.

@KeyboardDanni
Copy link
Contributor

Can you elaborate on how this is different from the mailbox V-sync mode, the way it's currently implemented?

Mailbox affects how the swapchain works. Waitable swapchain affects how the CPU waits on the swapchain.

In mailbox mode, the swapchain holds the latest rendered frame, and the application continually goes through the available images, continually replacing the latest rendered frame. This video gives an overview: https://www.youtube.com/watch?v=nSzQcyQTtRY&t=1116s

Waitable swapchain, on the other hand, means we move the CPU wait from before frame submission to before starting the next frame. Without waitable swapchain, we're doing this:

[poll input] -> [render frame] -> [wait for available swapchain image] -> [submit swapchain image]

With waitable swapchain, instead this happens:

[wait for available swapchain image] -> [poll input] -> [render frame] -> [submit swapchain image]

Theoretically, you should be able to use these two techniques together. However, the way mailbox is described seems to imply that the application can just keep rendering frames before the next frame in the swapchain is sent to the display, since whenever a new frame enters the mailbox, the existing frame leaves and becomes available for use again. This could mean that the swapchain always has an image available, so we never end up waiting on the swapchain, thus the waitable swapchain does nothing if we try to use it with mailbox.

However, waitable swapchain is nice because it lets us lower latency without relying on the driver supporting mailbox. It should also be much better for battery life since it, well, waits. I suppose mailbox could be made more energy-efficient by applying an FPS cap on the CPU side, but I digress.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants