Added a framerate graph

This commit is contained in:
Lee Fogg 2020-04-18 17:34:16 +01:00
parent 5c0fdf4b24
commit e4db538745
2 changed files with 115 additions and 36 deletions

View File

@ -48,7 +48,10 @@ namespace Emux.GameBoy
public double FramesPerSecond;
public bool EnableFrameLimit;
public TimeSpan _frameStartTime;
public TimeSpan FrameDelta;
private DateTime lastFrame;
private TimeSpan _frameStartTime;
public GameBoy(ICartridge cartridge, IClock clock, bool preferGbcMode)
@ -81,7 +84,15 @@ namespace Emux.GameBoy
IsBackground = true
}.Start();
Gpu.VBlankStarted += (_, __) => framesCount++;
lastFrame = DateTime.Now;
Gpu.VBlankStarted += (_, __) =>
{
framesCount++;
FrameDelta = DateTime.Now - lastFrame;
lastFrame = DateTime.Now;
};
}
private ICollection<IGameBoyComponent> Components
@ -172,9 +183,9 @@ namespace Emux.GameBoy
var delta = time - _frameStartTime;
if (delta.TotalSeconds > 1)
{
FramesPerSecond = framesCount / delta.TotalSeconds;
FramesPerSecond = framesCount / FrameDelta.TotalSeconds;
framesCount = 0;
Cpu.SecondElapsed(delta);
Cpu.SecondElapsed(FrameDelta);
_frameStartTime = time;
}

View File

@ -17,7 +17,7 @@ namespace Emux.MonoGame
{
public new event EventHandler Tick;
public const int FrameScaler = 3;
public const int FrameScaler = 2;
private const bool FitVideo = false;
private readonly Settings _settings;
private readonly GraphicsDeviceManager _graphics;
@ -25,12 +25,11 @@ namespace Emux.MonoGame
private Texture2D _video;
private bool _clockEnabled = false;
private SpriteFont _font;
private TimeSpan _last;
private readonly IList<double> _fps = new List<double>();
private double _averageFps, _minFps, _maxFps;
private readonly IList<double> _gbfps = new List<double>();
private double _averageGbFps, _minGbFps, _maxGbFps;
private int _fpsIndex;
private const float _averageTimeSeconds = 5;
private int _numDeltaSamples;
private double[] _deltas;
private double _speedFactor;
@ -42,7 +41,7 @@ namespace Emux.MonoGame
_graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IsMouseVisible = true;
}
}
public GameBoy.GameBoy GameBoy
{
@ -55,11 +54,15 @@ namespace Emux.MonoGame
base.Initialize();
}
Texture2D white1x1;
protected override void LoadContent()
{
_spriteBatch = new SpriteBatch(GraphicsDevice);
_video = new Texture2D(GraphicsDevice, GameBoyGpu.FrameWidth, GameBoyGpu.FrameHeight);
white1x1 = new Texture2D(GraphicsDevice, 1, 1, false, SurfaceFormat.Color);
var dataColors = new Color[1] { Color.White };
white1x1.SetData(dataColors);
_font = Content.Load<SpriteFont>("Calibri");
_graphics.PreferredBackBufferWidth = GameBoyGpu.FrameWidth * FrameScaler;
@ -69,6 +72,9 @@ namespace Emux.MonoGame
_graphics.ApplyChanges();
IsFixedTimeStep = GameBoy.EnableFrameLimit;
_numDeltaSamples = (int)((_averageTimeSeconds * 1000f) / (1000f / Emux.GameBoy.GameBoy.OfficialFrameRate));
_deltas = Enumerable.Repeat(1000d / Emux.GameBoy.GameBoy.OfficialFrameRate, _numDeltaSamples).ToArray();
GameBoy.Run();
}
@ -163,38 +169,100 @@ namespace Emux.MonoGame
private void DrawDebugInformation(GameTime time)
{
_fps.Add(1 / time.ElapsedGameTime.TotalSeconds);
_gbfps.Add(GameBoy.FramesPerSecond);
var deltaMs = GameBoy.FrameDelta.TotalMilliseconds;
if (deltaMs == 0)
return;
_fpsIndex = (_fpsIndex + 1) % _deltas.Length;
_deltas[_fpsIndex] = deltaMs;
var rawAverage = _deltas.Average();
var average = 1000f / rawAverage;
var min = 1000f / _deltas.Min();
var max = 1000f / _deltas.Max();
var difference = time.TotalGameTime - _last;
if (difference.TotalSeconds > 1)
{
_minGbFps = _gbfps.Min();
_averageGbFps = _gbfps.Average();
_maxGbFps = _gbfps.Max();
_minFps = _fps.Min();
_averageFps = _fps.Average();
_maxFps = _fps.Max();
_speedFactor = average / Emux.GameBoy.GameBoy.OfficialFrameRate;
_speedFactor = _averageGbFps / Emux.GameBoy.GameBoy.OfficialFrameRate;
_last = time.TotalGameTime;
_gbfps.Clear();
_fps.Clear();
}
string info = $"GameBoy FPS: {_averageGbFps:0.00} (Min: {_minGbFps:0.00}, Max: {_maxGbFps:0.00})\n" +
$"Clock FPS: {_averageFps:0.00} (Min: {_minFps:0.00}, Max: {_maxFps:0.00})\n" +
string info = $"GameBoy FPS: {average:0.00} (Min: {min:0.00}, Max: {max:0.00})\n" +
$"Speed Factor: {_speedFactor:0.00}\n" +
$"GBC Mode: {(GameBoy.Cpu.DoubleSpeed ? "Double speed" : "Normal speed")}\n" +
$"LY: {GameBoy.Gpu.LY}\n" +
$"LYC: {GameBoy.Gpu.LYC}\n";
_spriteBatch.DrawString(_font, info, Vector2.Zero, Color.Cyan);
}
public void Start()
drawGraph(rawAverage);
}
private void drawGraph(double average)
{
// Chart
const double max = 100; // ms
float chartTop = _graphics.PreferredBackBufferHeight - (_graphics.PreferredBackBufferHeight * 0.1f);
float chartBottom = _graphics.PreferredBackBufferHeight ;
float sampleWidth = (float)_graphics.PreferredBackBufferWidth / _numDeltaSamples;
var y = (float)map(_deltas[0], 0, max, chartBottom, chartTop);
Vector2 endPoint = new Vector2(0, y);
for (var i = 1; i < _deltas.Length; i++)
{
var delta = _deltas[i];
y = (float)map(delta, 0, max, chartBottom, chartTop);
var startPoint = new Vector2(i * sampleWidth, y);
DrawLine(
startPoint,
endPoint,
Color.White
);
endPoint = startPoint;
}
// Current Frame indicator
DrawLine(
new Vector2(_fpsIndex * sampleWidth, chartTop),
new Vector2(_fpsIndex * sampleWidth, chartBottom),
Color.Red
);
// Average
DrawLine(
new Vector2(0, (float)map(average, 0, max, chartBottom, chartTop)),
new Vector2(_graphics.PreferredBackBufferWidth, (float)map(average, 0, max, chartBottom, chartTop)),
Color.Green
);
}
double map(double x, double in_min, double in_max, double out_min, double out_max)
=> ((x - in_min) * (out_max - out_min) / (in_max - in_min)) + out_min;
void DrawLine(Vector2 start, Vector2 end, Color color)
{
Vector2 edge = end - start;
// calculate angle to rotate line
float angle =
(float)Math.Atan2(edge.Y, edge.X);
_spriteBatch.Draw(white1x1,
new Rectangle(
(int)start.X,
(int)start.Y,
(int)edge.Length(),
1
),
null,
color,
angle,
Vector2.Zero,
SpriteEffects.None,
0
);
}
public void Start()
{
_clockEnabled = true;
}