-
Notifications
You must be signed in to change notification settings - Fork 487
Implement low latency provider #6666
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
Open
smallketchup82
wants to merge
10
commits into
ppy:master
Choose a base branch
from
smallketchup82:reflex
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 2 commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
2cb5ca0
Add in rudimentary reflex implementation
smallketchup82 36325f8
get things working
smallketchup82 6163e21
Fix data-race issue
smallketchup82 225a4e5
Fix data-race in Swap()
smallketchup82 f250d43
Bind latency mode to FrameworkConfigManager value
smallketchup82 4809124
Attempt to overhaul exception handling
smallketchup82 f0ea66f
Add a bit of documentation
smallketchup82 5d1acaf
Set Draw thread FPS limit to refresh rate if Reflex is enabled
smallketchup82 5c02d43
Rename `LowLatencyProvider` to `Direct3D11LowLatencyProvider`
smallketchup82 489272e
Ensure Update thread runs at 1000hz
smallketchup82 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
osu.Framework/Graphics/Rendering/LowLatency/ILowLatencyProvider.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. | ||
| // See the LICENCE file in the repository root for full licence text. | ||
|
|
||
| using System; | ||
|
|
||
| namespace osu.Framework.Graphics.Rendering.LowLatency | ||
| { | ||
| public interface ILowLatencyProvider | ||
| { | ||
| bool IsAvailable { get; } | ||
|
|
||
| void Initialize(IntPtr nativeDeviceHandle); | ||
|
|
||
| void SetMode(LatencyMode mode); | ||
|
|
||
| void SetMarker(LatencyMarker marker, ulong frameId); | ||
|
|
||
| void FrameSleep(); | ||
| } | ||
| } |
17 changes: 17 additions & 0 deletions
17
osu.Framework/Graphics/Rendering/LowLatency/LatencyMarker.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. | ||
| // See the LICENCE file in the repository root for full licence text. | ||
|
|
||
| namespace osu.Framework.Graphics.Rendering.LowLatency | ||
| { | ||
| public enum LatencyMarker | ||
| { | ||
| SimulationStart, | ||
| SimulationEnd, | ||
| RenderSubmitStart, | ||
| RenderSubmitEnd, | ||
| PresentStart, | ||
| PresentEnd, | ||
| InputSample, | ||
| TriggerFlash | ||
| } | ||
| } |
12 changes: 12 additions & 0 deletions
12
osu.Framework/Graphics/Rendering/LowLatency/LatencyMode.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. | ||
| // See the LICENCE file in the repository root for full licence text. | ||
|
|
||
| namespace osu.Framework.Graphics.Rendering.LowLatency | ||
| { | ||
| public enum LatencyMode | ||
| { | ||
| Off = 0, | ||
| On = 1, | ||
| Boost = 2 | ||
| } | ||
| } |
22 changes: 22 additions & 0 deletions
22
osu.Framework/Graphics/Rendering/LowLatency/NoOpLowLatencyProvider.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. | ||
| // See the LICENCE file in the repository root for full licence text. | ||
|
|
||
| using System; | ||
|
|
||
| namespace osu.Framework.Graphics.Rendering.LowLatency | ||
| { | ||
| internal sealed class NoOpLowLatencyProvider : ILowLatencyProvider | ||
| { | ||
| public static readonly NoOpLowLatencyProvider INSTANCE = new NoOpLowLatencyProvider(); | ||
|
|
||
| public bool IsAvailable => false; | ||
|
|
||
| public void Initialize(IntPtr deviceHandle) { } | ||
|
|
||
| public void SetMode(LatencyMode mode) { } | ||
|
|
||
| public void SetMarker(LatencyMarker marker, ulong frameId) { } | ||
|
|
||
| public void FrameSleep() { } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,6 +30,7 @@ | |
| using osu.Framework.Graphics.OpenGL; | ||
| using osu.Framework.Graphics.Rendering; | ||
| using osu.Framework.Graphics.Rendering.Deferred; | ||
| using osu.Framework.Graphics.Rendering.LowLatency; | ||
| using osu.Framework.Input; | ||
| using osu.Framework.Input.Bindings; | ||
| using osu.Framework.Input.Handlers; | ||
|
|
@@ -466,6 +467,7 @@ protected virtual void OnExited() | |
|
|
||
| protected virtual void UpdateFrame() | ||
| { | ||
| FrameSleep(); | ||
| if (Root == null) return; | ||
|
|
||
| frameCount++; | ||
|
|
@@ -483,11 +485,15 @@ protected virtual void UpdateFrame() | |
|
|
||
| TypePerformanceMonitor.NewFrame(); | ||
|
|
||
| LatencyMark(LatencyMarker.SimulationStart, frameCount); | ||
|
|
||
| Root.UpdateSubTree(); | ||
| Root.UpdateSubTreeMasking(); | ||
|
|
||
| using (var buffer = drawRoots.GetForWrite()) | ||
| buffer.Object = Root.GenerateDrawNodeSubtree(frameCount, buffer.Index, false); | ||
|
|
||
| LatencyMark(LatencyMarker.SimulationEnd, frameCount); | ||
| } | ||
|
|
||
| private bool didRenderFrame; | ||
|
|
@@ -528,6 +534,8 @@ protected virtual void DrawFrame() | |
|
|
||
| try | ||
| { | ||
| LatencyMark(LatencyMarker.RenderSubmitStart, frameCount); | ||
|
|
||
| using (drawMonitor.BeginCollecting(PerformanceCollectionType.DrawReset)) | ||
| Renderer.BeginFrame(new Vector2(Window.ClientSize.Width, Window.ClientSize.Height)); | ||
|
|
||
|
|
@@ -560,6 +568,8 @@ protected virtual void DrawFrame() | |
|
|
||
| Renderer.FinishFrame(); | ||
|
|
||
| LatencyMark(LatencyMarker.RenderSubmitEnd, frameCount); | ||
|
|
||
| using (drawMonitor.BeginCollecting(PerformanceCollectionType.SwapBuffer)) | ||
| Swap(); | ||
|
|
||
|
|
@@ -577,12 +587,16 @@ protected virtual void DrawFrame() | |
| /// </summary> | ||
| protected virtual void Swap() | ||
| { | ||
| LatencyMark(LatencyMarker.PresentStart, frameCount); | ||
|
|
||
| Renderer.SwapBuffers(); | ||
|
|
||
| if (Window.GraphicsSurface.Type == GraphicsSurfaceType.OpenGL && Renderer.VerticalSync) | ||
| // without waiting (i.e. glFinish), vsync is basically unplayable due to the extra latency introduced. | ||
| // we will likely want to give the user control over this in the future as an advanced setting. | ||
| Renderer.WaitUntilIdle(); | ||
|
|
||
| LatencyMark(LatencyMarker.PresentEnd, frameCount); | ||
| } | ||
|
|
||
| /// <summary> | ||
|
|
@@ -1390,6 +1404,75 @@ private void setVSyncMode() | |
| DrawThread.Scheduler.Add(() => Renderer.VerticalSync = frameSyncMode.Value == FrameSync.VSync); | ||
| } | ||
|
|
||
| private ILowLatencyProvider lowLatency = NoOpLowLatencyProvider.INSTANCE; | ||
| private bool lowLatencyInitialized; | ||
|
|
||
| public void SetLowLatencyProvider(ILowLatencyProvider provider, IntPtr deviceHandle = 0) | ||
| { | ||
| lowLatency = provider ?? NoOpLowLatencyProvider.INSTANCE; | ||
| TryInitializeLowLatencyProvider(); | ||
| } | ||
|
|
||
| internal void TryInitializeLowLatencyProvider() | ||
| { | ||
| if (lowLatencyInitialized || lowLatency is NoOpLowLatencyProvider) return; | ||
|
|
||
| if (Renderer is not IVeldridRenderer veldridRenderer) return; | ||
|
|
||
| try | ||
| { | ||
| IntPtr deviceHandle = veldridRenderer.Device.GetD3D11Info().Device; | ||
|
|
||
| if (deviceHandle == IntPtr.Zero) return; | ||
|
|
||
| lowLatency.Initialize(deviceHandle); | ||
| var currentLatencyMode = Config.GetBindable<LatencyMode>(FrameworkSetting.LatencyMode); | ||
| SetLowLatencyMode(currentLatencyMode.Value); | ||
| lowLatencyInitialized = true; | ||
| } | ||
| catch (Exception) | ||
| { | ||
| // ignored | ||
| } | ||
| } | ||
|
|
||
| public void SetLowLatencyMode(LatencyMode mode) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't need to be public,
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in |
||
| { | ||
| try | ||
| { | ||
| Config.GetBindable<LatencyMode>(FrameworkSetting.LatencyMode).Value = mode; | ||
| lowLatency.SetMode(mode); | ||
| } | ||
| catch (Exception) | ||
| { | ||
| // ignored | ||
| } | ||
| } | ||
|
|
||
| internal void LatencyMark(LatencyMarker marker, ulong frameId) | ||
| { | ||
| try | ||
| { | ||
| lowLatency.SetMarker(marker, frameId); | ||
| } | ||
| catch (Exception) | ||
| { | ||
| // ignored | ||
| } | ||
| } | ||
|
|
||
| internal void FrameSleep() | ||
| { | ||
| try | ||
| { | ||
| lowLatency.FrameSleep(); | ||
| } | ||
| catch (Exception) | ||
| { | ||
| // ignored | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Construct all input handlers for this host. The order here decides the priority given to handlers, with the earliest occurring having higher priority. | ||
| /// </summary> | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
frameCountis set from the update thread and read here from the draw thread. This can cause a multitude of problems when running in multi-threaded:LatencyMark()in the same draw frame having different frame countsbuffer(as the update thread runs twice as fast)To make this correct, the
frameCountshould be stored in the buffer.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in
6163e21(#6666) and225a4e5(#6666). Let me know if you had a different solution in mind.I wonder if this might fix the frametime spikes I observed predominantly in the Reflex On and Boost modes.

(green is off, orange is on, blue is with boost)