mirror of
https://github.com/Ryujinx/Opentk.git
synced 2024-12-23 01:55:30 +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.Diagnostics;
|
||||
using System.Threading;
|
||||
using OpenTK.Graphics;
|
||||
using OpenTK.Platform;
|
||||
|
||||
|
@ -66,7 +67,11 @@ namespace OpenTK
|
|||
{
|
||||
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;
|
||||
|
||||
|
@ -161,12 +166,30 @@ namespace OpenTK
|
|||
/// <param name="sharedContext">An IGraphicsContext to share resources with.</param>
|
||||
public GameWindow(int width, int height, GraphicsMode mode, string title, GameWindowFlags options, DisplayDevice device,
|
||||
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,
|
||||
mode == null ? GraphicsMode.Default : mode,
|
||||
device == null ? DisplayDevice.Default : device)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.isSingleThreaded = isSingleThreaded;
|
||||
glContext = new GraphicsContext(mode == null ? GraphicsMode.Default : mode, WindowInfo, major, minor, flags);
|
||||
glContext.MakeCurrent(WindowInfo);
|
||||
(glContext as IGraphicsContextInternal).LoadAll();
|
||||
|
@ -334,13 +357,22 @@ namespace OpenTK
|
|||
//Resize += DispatchUpdateAndRenderFrame;
|
||||
|
||||
Debug.Print("Entering main loop.");
|
||||
watch.Start();
|
||||
if (!isSingleThreaded)
|
||||
{
|
||||
updateThread = new Thread(UpdateThread);
|
||||
updateThread.Start();
|
||||
}
|
||||
watchRender.Start();
|
||||
while (true)
|
||||
{
|
||||
ProcessEvents();
|
||||
if (Exists && !IsExiting)
|
||||
{
|
||||
DispatchUpdateAndRenderFrame(this, EventArgs.Empty);
|
||||
if (isSingleThreaded)
|
||||
{
|
||||
DispatchUpdateFrame(watchRender);
|
||||
}
|
||||
DispatchRenderFrame();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -350,9 +382,6 @@ namespace OpenTK
|
|||
}
|
||||
finally
|
||||
{
|
||||
Move -= DispatchUpdateAndRenderFrame;
|
||||
Resize -= DispatchUpdateAndRenderFrame;
|
||||
|
||||
if (Exists)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
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;
|
||||
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)
|
||||
{
|
||||
RaiseUpdateFrame(elapsed, ref timestamp);
|
||||
RaiseUpdateFrame(watch, elapsed, ref timestamp);
|
||||
|
||||
// Calculate difference (positive or negative) between
|
||||
// actual elapsed time and target elapsed time. We must
|
||||
|
@ -403,15 +441,19 @@ namespace OpenTK
|
|||
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)
|
||||
{
|
||||
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
|
||||
update_args.Time = elapsed;
|
||||
|
@ -438,7 +480,7 @@ namespace OpenTK
|
|||
|
||||
// Update RenderTime property
|
||||
render_timestamp = timestamp;
|
||||
timestamp = watch.Elapsed.TotalSeconds;
|
||||
timestamp = watchRender.Elapsed.TotalSeconds;
|
||||
render_time = timestamp - render_timestamp;
|
||||
}
|
||||
|
||||
|
@ -790,6 +832,12 @@ namespace OpenTK
|
|||
/// </summary>
|
||||
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>
|
||||
/// Override to add custom cleanup logic.
|
||||
/// </summary>
|
||||
|
|
Loading…
Reference in a new issue