-
-
Notifications
You must be signed in to change notification settings - Fork 729
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
platform/windows: add DwmFlush() call to improve Windows capture #164
Conversation
5b460b6
to
0e7696a
Compare
I notice the webui entry is not working correctly. Clicking on I won't be have the opportunity to check this until later tonight, so I'll set this as a draft. |
Perhaps I'm missing something, but it seems that the webui is not behaving correctly independently of this commit? I downloaded the latest Windows binary release and launched a fresh session. After only setting up the username/pass and logging in, simply clicking randomly between |
Can you share a screenshot of what you're experiencing? I will see if I can replicate it. |
I've tested this and don't see any regressions, so I guess that the fix works. @psyke83 if the problem happens outside of your changes it's problably better to file an issue and merge this anyway |
@TheElixZammuto @ReenigneArcher The problem that was happening for me: when you randomly switched tabs on the webui - particularly when moving from I've updated the PR with two small fixes for the webui that are split out from the DwmFlush commit. I'd like a little more time to test the DwmFlush change itself, as I noticed a strange performance regression in a game (Dying Light) when this is enabled, but in the meantime, if you would like me to split out the unrelated webui/video_t struct commits into a new PR, let me know and I'll do that. |
@psyke83 if there are game dependent performance issues, would it be possible (or even make sense) to enable this depending on the application that is launched? |
I've tested about a dozen games using different graphics APIs with this patch. For all games that were affected by stuttering issues, DwmFlush seems to work as intended, and none exhibit any negative performance issues similar to what I see with Dying Light. Keeping in mind that Dying Light was never a game in which I ever noticed the type of stutter DwmFlush is aimed at fixing, some notes:
I checked Dying Light's Steam forums, and there's a recent thread of users complaining of major FPS drops. Although Steam's FPS counter showed a locked 60fps for me, I decided to try the workaround in the thread of manually selecting the beta branch that holds the previous released version, and Sunshine now works perfectly fine with or without DwmFlush enabled. So, I'm chalking this up to some kind of issue with the latest Dying Light that happens to negatively impact Sunshine. I'll remove the draft status and let this go for review now. If any other regressions in other applications or games are noticed when DwmFlush is enabled, please let me know. Thanks. |
I've made additional changes that would enable DwmFlush to be enabled by default: psyke83/SunshineStream@DwmFlush...psyke83:DwmFlush_auto Should I include that commit into this PR? I also found a very useful resource to help exhibit stuttering issue: https://www.vsynctester.com/ - specifically, the |
@TheElixZammuto I'll leave it up to your judgement if you think this option should be applied as the default. |
Given that @psyke83 has given a very toughtful comparison of both situations, and also made an option for disabling it using the Web UI, IMHO we should make it enabled-by-default. |
I don't want to be that guy, but AFAICT dwmflush is always just kind of a hack to workaround issues elsewhere. In this case, you aren't really "rendering" stuff yourself (and the entire thing has to inherently depend and wait on another process anyway), but it still feels like having thrown something at the wall and appreciating that it sticked. |
Keeping in mind that I'm quite unfamiliar with programming with DirectX/DXGI or Windows in general, I did investigate some alternative solutions before
Another alternative I tried was flushing the command queue and blocking until complete using an event query, as per the official documentation: psyke83/SunshineStream@DwmFlush...psyke83:DwmFlush_alternative - this didn't help. I also tried replacing the frame wait logic with I'm not familiar with all of the projects you mentioned, but OBS invokes Would appreciate any suggestions, but I can say that I haven't noticed increased capture latency when DwmFlush is used. |
I really have no technical insight on the matter (my skill is spitballing), but it's just that it looks particularly odd here for a random vista function to be necessary for good performance despite not being mentioned anywhere. https://stackoverflow.com/questions/48278207/dxgi-desktop-duplication-screen-capture-speed/#48279602 obsproject/obs-studio#2604 (comment) |
The problem doesn't seem to be that we're not receiving frames fast enough. When the stutter issue occurs,
That's Looking-Glass, which was listed in the Credits section of this project by the original author. If you check their upstream, they use DwmFlush to resolve the same issue via a commit that post-dates their blog entry you linked: gnif/LookingGlass@92f27cc
duplication_t::next_frame does release and acquisition, and display_ram_t::capture is what waits between frames. The current implementation means that
No. I tested this against The Witcher 3 (it has the stutter issue when scrolling the in-game map); there is an in-game option to enable the hardware cursor, and it made no difference. |
Sigh... thank you for putting up with my own set of "throwing at the wall". psieg/Lightpack#199 https://old.reddit.com/r/VFIO/comments/f22k6u/windows_capture_performance_dxgi_bug/ Instead what I believe LS uses DwmFlush for (and not even by default then) is actually.. just letting the system breath more. |
Happy to have more eyes on the problem.
No. I'm testing on a 60Hz non-Freesync laptop LCD via Linux, usually at 1366x768. Shouldn't be too taxing.
This is describing our problem exactly, yes. Unfortunately I can't see the MS link, but I suspect that DwmFlush was the solution that gnif settled on?
I'm aware of this problem. The symptoms was that (only) in high GPU load scenarios, Sunshine's encoder would throttle to below the displayed render rate while the intensive application/game was in the foreground, but would shoot up to full speed if the application was backgrounded (even if mostly still on-screen). I solved that in Sunshine some time ago: 0a883ab As a troubleshooting measure, I tried disabling this, as well as disabling other measures to reduce latency. None made a difference with this specific mouse-induced stutter issue.
I'm not convinced about that. DwmFlush is invoked within Edit: also, keep in mind that DwmFlush is not enabled by default in LookingGlass due to the potential to throttle the client to the host's framerate. One of my commits in this PR works around the issue by comparing the host framerate to the client requested rate, and automatically disables if the client rate exceeds the host. So, theoretically, there should be no issue, as long as the function always reports the correct rate and doesn't screw up with multi-monitor configs, etc. I can't really test that as my host only has one connected monitor. |
Don't you need to run as a service/SYSTEM for that to apply?
I'm not making a technical argument there, lol. I'm just comparing "times", if I can explain.
Uhm, speaking of which, now that I think to it.. what happens to the entire house of cards is you are running in exclusive fullscreen mode? |
Yes, but it can work as administrator account due to the invocation of We don't touch MCSS scheduling in the code, but I did do some tests turning it on/off, and it made no difference. As for process priority: the Windows service defaults to "above normal", but I've tried everything from lowest to realtime. None of that impacts this issue. I've even gone as far as fiddling with process affinities, but it makes absolutely no difference. My CPU is getting old (Ryzen 2700 @ 3.9Ghz), but when configured to use software encoding with all 16 threads, it uses very little CPU. The AMD AMF encoder also has the exact same mouse stuttering irrespective of all the above.
Unfortunately I can't test LookingGlass, as I've only got a single-GPU system.
I don't see any issues with exclusive fullscreen mode, but that may be because Windows 10/11 uses fake exclusive fullscreen unless you manually change the compatibility property for an executable. To re-iterate, an alternative solution to this is to reorder the |
@psyke83 mind including these in this PR? |
It's already present in the current PR set via commit: 37d86401712adaddf5d24ce9c4654b2c6607e44 |
Can you resolve the conflict? I believe the only conflict is that the |
These were causing unusual behaviour (select dialogs displaying a blank label when a value should be selected, and values randomly setting themselves to undefined when switching tabs).
…ture Invoke DwmFlush() before acquiring the next frame to alleviate visual stutter during mouse movement at the cost of constraining the capture rate to the host's monitor refresh. Disabled by default; enable via "dwmflush" boolean configuration parameter.
On each re/init, query the active monitor refresh rate via DwmGetCompositionTimingInfo. If the client requested framerate exceeds the host monitor refresh, automatically disable DwmFlush. This avoids the problem by which DwmFlush would constrain the client FPS if the host monitor runs at a lower refresh rate, thus allowing the feature to be enabled by default. If there are other issues caused by DwmFlush for certain systems, it can still be disabled via configuration.
Description
Adds DwmFlush() call before acquiring a new frame to resolve framerate stuttering observed when moving the mouse. For more context, see (obsolete) PR and issue from upstream that describes the problem in detail:
loki-47-6F-64/sunshine#227
loki-47-6F-64/sunshine#286
Please note that I had to include a very minor but unrelated fix for VideoToolbox variables missing from the video_t struct, as this needed to be fixed in order to accommodate the new
dwmflush
entry correctly.Issues Fixed or Closed
Type of Change
Potential breakage only in specific circumstances when enabled: DwmFlush() constrains the framerate to the host computer's monitor refresh rate, so it may cause issues if the client is streaming at an FPS higher than supported by the host's connected monitor. I would personally prefer for this fix to be enabled by default, as this scenario seems like a rare edge case compared to the stutter that's experienced on all Windows clients. Feedback on whether I should change the default would be appreciated.Breakage should no longer occur, as DwmFlush() is now called only if enabled and the host monitor refresh rate meets or exceeds the client requested rate.
Checklist