mirror of
https://github.com/Ryujinx/Opentk.git
synced 2025-07-01 05:28:30 +00:00
Refactored and simplified the Run() loop.
This commit is contained in:
parent
a6984a7a48
commit
c0528707c3
|
@ -371,7 +371,7 @@ namespace OpenTK
|
||||||
TargetRenderFrequency = frames_per_second;
|
TargetRenderFrequency = frames_per_second;
|
||||||
|
|
||||||
Stopwatch update_watch = new Stopwatch(), render_watch = new Stopwatch();
|
Stopwatch update_watch = new Stopwatch(), render_watch = new Stopwatch();
|
||||||
double time, next_render = 0.0, next_update = 0.0, update_time_counter = 0.0;
|
double next_render = 0.0, next_update = 0.0;
|
||||||
int num_updates = 0;
|
int num_updates = 0;
|
||||||
FrameEventArgs update_args = new FrameEventArgs();
|
FrameEventArgs update_args = new FrameEventArgs();
|
||||||
FrameEventArgs render_args = new FrameEventArgs();
|
FrameEventArgs render_args = new FrameEventArgs();
|
||||||
|
@ -387,77 +387,8 @@ namespace OpenTK
|
||||||
{
|
{
|
||||||
ProcessEvents();
|
ProcessEvents();
|
||||||
|
|
||||||
// Raise UpdateFrame events
|
RaiseUpdateFrame(update_watch, ref next_update, update_args);
|
||||||
time = update_watch.Elapsed.TotalSeconds;
|
RaiseRenderFrame(render_watch, ref next_render, render_args);
|
||||||
if (time > 1.0)
|
|
||||||
time = 1.0;
|
|
||||||
while (next_update - time <= 0.0)
|
|
||||||
{
|
|
||||||
next_update = next_update - time + TargetUpdatePeriod;
|
|
||||||
if (next_update < -1.0) // Cap the maximum time drift, to avoid lengthy catch-up games.
|
|
||||||
next_update = -1.0;
|
|
||||||
|
|
||||||
update_time_counter += time;
|
|
||||||
++num_updates;
|
|
||||||
|
|
||||||
update_watch.Reset();
|
|
||||||
update_watch.Start();
|
|
||||||
|
|
||||||
if (time > 0)
|
|
||||||
{
|
|
||||||
update_args.Time = time;
|
|
||||||
OnUpdateFrameInternal(update_args);
|
|
||||||
update_time = update_watch.Elapsed.TotalSeconds;
|
|
||||||
}
|
|
||||||
if (TargetUpdateFrequency == 0.0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
time = update_watch.Elapsed.TotalSeconds;
|
|
||||||
next_update -= time;
|
|
||||||
update_time_counter += time;
|
|
||||||
|
|
||||||
// Allow up to 10 frames to be dropped. Prevents the application from hanging
|
|
||||||
// with very high update frequencies.
|
|
||||||
if (num_updates >= 10)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (num_updates > 0)
|
|
||||||
{
|
|
||||||
update_period = update_time_counter / (double)num_updates;
|
|
||||||
num_updates = 0;
|
|
||||||
update_time_counter = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Raise RenderFrame event
|
|
||||||
time = render_watch.Elapsed.TotalSeconds;
|
|
||||||
if (time > 1.0)
|
|
||||||
time = 1.0;
|
|
||||||
double time_left = next_render - time;
|
|
||||||
if (VSync == VSyncMode.Adaptive)
|
|
||||||
{
|
|
||||||
// Check if we have enough time for a vsync
|
|
||||||
if (TargetRenderPeriod != 0 && RenderTime > 2.0 * TargetRenderPeriod)
|
|
||||||
Context.VSync = false;
|
|
||||||
else
|
|
||||||
Context.VSync = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (time_left <= 0.0)
|
|
||||||
{
|
|
||||||
next_render = time_left + TargetRenderPeriod;
|
|
||||||
if (next_render < -1.0) // Cap the maximum time drift, to avoid lengthy catch-up games.
|
|
||||||
next_render = -1.0;
|
|
||||||
|
|
||||||
render_watch.Reset();
|
|
||||||
render_watch.Start();
|
|
||||||
|
|
||||||
if (time > 0)
|
|
||||||
{
|
|
||||||
render_period = render_args.Time = time;
|
|
||||||
OnRenderFrameInternal(render_args);
|
|
||||||
render_time = render_watch.Elapsed.TotalSeconds;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
@ -475,6 +406,98 @@ namespace OpenTK
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RaiseUpdateFrame(Stopwatch update_watch, ref double next_update, FrameEventArgs update_args)
|
||||||
|
{
|
||||||
|
int num_updates = 0;
|
||||||
|
|
||||||
|
// Cap the maximum time drift to 1 second (e.g. when the process is suspended).
|
||||||
|
double time = update_watch.Elapsed.TotalSeconds;
|
||||||
|
if (time > 1.0)
|
||||||
|
time = 1.0;
|
||||||
|
|
||||||
|
// Raise UpdateFrame events until we catch up with our target update rate.
|
||||||
|
while (next_update - time <= 0.0)
|
||||||
|
{
|
||||||
|
// Don't schedule a new update more than 1 second in the future.
|
||||||
|
// Sometimes the hardware cannot keep up with updates
|
||||||
|
// (e.g. when the update rate is too high, or the UpdateFrame processing
|
||||||
|
// is too costly). This cap ensures we can catch up in a reasonable time
|
||||||
|
// once the load becomes lighter.
|
||||||
|
next_update = next_update - time + TargetUpdatePeriod;
|
||||||
|
if (next_update < -1.0)
|
||||||
|
next_update = -1.0;
|
||||||
|
|
||||||
|
// Allow up to 10 consecutive UpdateFrame events.
|
||||||
|
// This prevents the application from "hanging" when the hardware cannot
|
||||||
|
// keep up with the requested update rate.
|
||||||
|
if (++num_updates >= 10)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (time > 0)
|
||||||
|
{
|
||||||
|
update_args.Time = time;
|
||||||
|
OnUpdateFrameInternal(update_args);
|
||||||
|
update_time = update_watch.Elapsed.TotalSeconds;
|
||||||
|
}
|
||||||
|
if (TargetUpdateFrequency == 0.0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
time = update_watch.Elapsed.TotalSeconds;
|
||||||
|
next_update -= time;
|
||||||
|
|
||||||
|
// Stopwatches are not accurate over long time periods.
|
||||||
|
// We accumlate the total elapsed time into the time variable
|
||||||
|
// while reseting the Stopwatch frequently.
|
||||||
|
update_watch.Reset();
|
||||||
|
update_watch.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate statistics
|
||||||
|
if (num_updates > 0)
|
||||||
|
{
|
||||||
|
update_period = time / (double)num_updates;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RaiseRenderFrame(Stopwatch render_watch, ref double next_render, FrameEventArgs render_args)
|
||||||
|
{
|
||||||
|
// Cap the maximum time drift to 1 second (e.g. when the process is suspended).
|
||||||
|
double time = render_watch.Elapsed.TotalSeconds;
|
||||||
|
if (time > 1.0)
|
||||||
|
time = 1.0;
|
||||||
|
|
||||||
|
double time_left = next_render - time;
|
||||||
|
|
||||||
|
// Todo: remove this?
|
||||||
|
if (VSync == VSyncMode.Adaptive)
|
||||||
|
{
|
||||||
|
// Check if we have enough time for a vsync
|
||||||
|
if (TargetRenderPeriod != 0 && RenderTime > 2.0 * TargetRenderPeriod)
|
||||||
|
Context.VSync = false;
|
||||||
|
else
|
||||||
|
Context.VSync = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (time_left <= 0.0)
|
||||||
|
{
|
||||||
|
// Schedule next render event. The 1 second cap ensures
|
||||||
|
// the process does not appear to hang.
|
||||||
|
next_render = time_left + TargetRenderPeriod;
|
||||||
|
if (next_render < -1.0)
|
||||||
|
next_render = -1.0;
|
||||||
|
|
||||||
|
render_watch.Reset();
|
||||||
|
render_watch.Start();
|
||||||
|
|
||||||
|
if (time > 0)
|
||||||
|
{
|
||||||
|
render_period = render_args.Time = time;
|
||||||
|
OnRenderFrameInternal(render_args);
|
||||||
|
render_time = render_watch.Elapsed.TotalSeconds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region SwapBuffers
|
#region SwapBuffers
|
||||||
|
|
Loading…
Reference in a new issue