mirror of
https://github.com/Ryujinx/Opentk.git
synced 2024-12-23 01:25:39 +00:00
Merge pull request #695 from tzachshabtay/develop
Game Window- allow configuring separate update thread
This commit is contained in:
commit
6ba91adfbe
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Threading;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using OpenTK.Platform;
|
using OpenTK.Platform;
|
||||||
|
|
||||||
|
@ -66,7 +67,11 @@ namespace OpenTK
|
||||||
{
|
{
|
||||||
private const double MaxFrequency = 500.0; // Frequency cap for Update/RenderFrame events
|
private const double MaxFrequency = 500.0; // Frequency cap for Update/RenderFrame events
|
||||||
|
|
||||||
private readonly Stopwatch watch = new Stopwatch();
|
private readonly Stopwatch watchRender = new Stopwatch();
|
||||||
|
private readonly Stopwatch watchUpdate = new Stopwatch();
|
||||||
|
private Thread updateThread;
|
||||||
|
|
||||||
|
private readonly bool isSingleThreaded;
|
||||||
|
|
||||||
private IGraphicsContext glContext;
|
private IGraphicsContext glContext;
|
||||||
|
|
||||||
|
@ -161,12 +166,30 @@ namespace OpenTK
|
||||||
/// <param name="sharedContext">An IGraphicsContext to share resources with.</param>
|
/// <param name="sharedContext">An IGraphicsContext to share resources with.</param>
|
||||||
public GameWindow(int width, int height, GraphicsMode mode, string title, GameWindowFlags options, DisplayDevice device,
|
public GameWindow(int width, int height, GraphicsMode mode, string title, GameWindowFlags options, DisplayDevice device,
|
||||||
int major, int minor, GraphicsContextFlags flags, IGraphicsContext sharedContext)
|
int major, int minor, GraphicsContextFlags flags, IGraphicsContext sharedContext)
|
||||||
|
: this(width, height, mode, title, options, device, major, minor, flags, sharedContext, true)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/// <summary>Constructs a new GameWindow with the specified attributes.</summary>
|
||||||
|
/// <param name="width">The width of the GameWindow in pixels.</param>
|
||||||
|
/// <param name="height">The height of the GameWindow in pixels.</param>
|
||||||
|
/// <param name="mode">The OpenTK.Graphics.GraphicsMode of the GameWindow.</param>
|
||||||
|
/// <param name="title">The title of the GameWindow.</param>
|
||||||
|
/// <param name="options">GameWindow options regarding window appearance and behavior.</param>
|
||||||
|
/// <param name="device">The OpenTK.Graphics.DisplayDevice to construct the GameWindow in.</param>
|
||||||
|
/// <param name="major">The major version for the OpenGL GraphicsContext.</param>
|
||||||
|
/// <param name="minor">The minor version for the OpenGL GraphicsContext.</param>
|
||||||
|
/// <param name="flags">The GraphicsContextFlags version for the OpenGL GraphicsContext.</param>
|
||||||
|
/// <param name="sharedContext">An IGraphicsContext to share resources with.</param>
|
||||||
|
/// <param name="isSingleThreaded">Should the update and render frames be fired on the same thread? If false, render and update events will be fired from separate threads.</param>
|
||||||
|
public GameWindow(int width, int height, GraphicsMode mode, string title, GameWindowFlags options, DisplayDevice device,
|
||||||
|
int major, int minor, GraphicsContextFlags flags, IGraphicsContext sharedContext, bool isSingleThreaded)
|
||||||
: base(width, height, title, options,
|
: base(width, height, title, options,
|
||||||
mode == null ? GraphicsMode.Default : mode,
|
mode == null ? GraphicsMode.Default : mode,
|
||||||
device == null ? DisplayDevice.Default : device)
|
device == null ? DisplayDevice.Default : device)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
this.isSingleThreaded = isSingleThreaded;
|
||||||
glContext = new GraphicsContext(mode == null ? GraphicsMode.Default : mode, WindowInfo, major, minor, flags);
|
glContext = new GraphicsContext(mode == null ? GraphicsMode.Default : mode, WindowInfo, major, minor, flags);
|
||||||
glContext.MakeCurrent(WindowInfo);
|
glContext.MakeCurrent(WindowInfo);
|
||||||
(glContext as IGraphicsContextInternal).LoadAll();
|
(glContext as IGraphicsContextInternal).LoadAll();
|
||||||
|
@ -334,13 +357,22 @@ namespace OpenTK
|
||||||
//Resize += DispatchUpdateAndRenderFrame;
|
//Resize += DispatchUpdateAndRenderFrame;
|
||||||
|
|
||||||
Debug.Print("Entering main loop.");
|
Debug.Print("Entering main loop.");
|
||||||
watch.Start();
|
if (!isSingleThreaded)
|
||||||
|
{
|
||||||
|
updateThread = new Thread(UpdateThread);
|
||||||
|
updateThread.Start();
|
||||||
|
}
|
||||||
|
watchRender.Start();
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
ProcessEvents();
|
ProcessEvents();
|
||||||
if (Exists && !IsExiting)
|
if (Exists && !IsExiting)
|
||||||
{
|
{
|
||||||
DispatchUpdateAndRenderFrame(this, EventArgs.Empty);
|
if (isSingleThreaded)
|
||||||
|
{
|
||||||
|
DispatchUpdateFrame(watchRender);
|
||||||
|
}
|
||||||
|
DispatchRenderFrame();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -350,9 +382,6 @@ namespace OpenTK
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
Move -= DispatchUpdateAndRenderFrame;
|
|
||||||
Resize -= DispatchUpdateAndRenderFrame;
|
|
||||||
|
|
||||||
if (Exists)
|
if (Exists)
|
||||||
{
|
{
|
||||||
// TODO: Should similar behaviour be retained, possibly on native window level?
|
// TODO: Should similar behaviour be retained, possibly on native window level?
|
||||||
|
@ -362,21 +391,30 @@ namespace OpenTK
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UpdateThread()
|
||||||
|
{
|
||||||
|
OnUpdateThreadStarted(this, new EventArgs());
|
||||||
|
watchUpdate.Start();
|
||||||
|
while (Exists && !IsExiting)
|
||||||
|
{
|
||||||
|
DispatchUpdateFrame(watchUpdate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private double ClampElapsed(double elapsed)
|
private double ClampElapsed(double elapsed)
|
||||||
{
|
{
|
||||||
return MathHelper.Clamp(elapsed, 0.0, 1.0);
|
return MathHelper.Clamp(elapsed, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DispatchUpdateAndRenderFrame(object sender, EventArgs e)
|
private void DispatchUpdateFrame(Stopwatch watch)
|
||||||
{
|
{
|
||||||
int is_running_slowly_retries = 4;
|
int is_running_slowly_retries = 4;
|
||||||
double timestamp = watch.Elapsed.TotalSeconds;
|
double timestamp = watch.Elapsed.TotalSeconds;
|
||||||
double elapsed = 0;
|
double elapsed = ClampElapsed(timestamp - update_timestamp);
|
||||||
|
|
||||||
elapsed = ClampElapsed(timestamp - update_timestamp);
|
|
||||||
while (elapsed > 0 && elapsed + update_epsilon >= TargetUpdatePeriod)
|
while (elapsed > 0 && elapsed + update_epsilon >= TargetUpdatePeriod)
|
||||||
{
|
{
|
||||||
RaiseUpdateFrame(elapsed, ref timestamp);
|
RaiseUpdateFrame(watch, elapsed, ref timestamp);
|
||||||
|
|
||||||
// Calculate difference (positive or negative) between
|
// Calculate difference (positive or negative) between
|
||||||
// actual elapsed time and target elapsed time. We must
|
// actual elapsed time and target elapsed time. We must
|
||||||
|
@ -403,15 +441,19 @@ namespace OpenTK
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
elapsed = ClampElapsed(timestamp - render_timestamp);
|
private void DispatchRenderFrame()
|
||||||
|
{
|
||||||
|
double timestamp = watchRender.Elapsed.TotalSeconds;
|
||||||
|
double elapsed = ClampElapsed(timestamp - render_timestamp);
|
||||||
if (elapsed > 0 && elapsed >= TargetRenderPeriod)
|
if (elapsed > 0 && elapsed >= TargetRenderPeriod)
|
||||||
{
|
{
|
||||||
RaiseRenderFrame(elapsed, ref timestamp);
|
RaiseRenderFrame(elapsed, ref timestamp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RaiseUpdateFrame(double elapsed, ref double timestamp)
|
private void RaiseUpdateFrame(Stopwatch watch, double elapsed, ref double timestamp)
|
||||||
{
|
{
|
||||||
// Raise UpdateFrame event
|
// Raise UpdateFrame event
|
||||||
update_args.Time = elapsed;
|
update_args.Time = elapsed;
|
||||||
|
@ -438,7 +480,7 @@ namespace OpenTK
|
||||||
|
|
||||||
// Update RenderTime property
|
// Update RenderTime property
|
||||||
render_timestamp = timestamp;
|
render_timestamp = timestamp;
|
||||||
timestamp = watch.Elapsed.TotalSeconds;
|
timestamp = watchRender.Elapsed.TotalSeconds;
|
||||||
render_time = timestamp - render_timestamp;
|
render_time = timestamp - render_timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -790,6 +832,12 @@ namespace OpenTK
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<FrameEventArgs> UpdateFrame = delegate { };
|
public event EventHandler<FrameEventArgs> UpdateFrame = delegate { };
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If game window is configured to run with a dedicated update thread (by passing isSingleThreaded = false in the constructor),
|
||||||
|
/// occurs when the update thread has started. This would be a good place to initialize thread specific stuff (like setting a synchronization context).
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler OnUpdateThreadStarted = delegate { };
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Override to add custom cleanup logic.
|
/// Override to add custom cleanup logic.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
Loading…
Reference in a new issue