FpsCounter.cs 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. using System;
  2. using System.Diagnostics;
  3. using System.Globalization;
  4. using Avalonia.Media;
  5. using Avalonia.Media.TextFormatting;
  6. using Avalonia.Platform;
  7. using Avalonia.Utilities;
  8. // Special license applies <see href="https://raw.githubusercontent.com/AvaloniaUI/Avalonia/master/src/Avalonia.Base/Rendering/Composition/License.md">License.md</see>
  9. namespace Avalonia.Rendering.Composition.Server;
  10. /// <summary>
  11. /// An FPS counter helper that can draw itself on the render thread
  12. /// </summary>
  13. internal class FpsCounter
  14. {
  15. private readonly Stopwatch _stopwatch = Stopwatch.StartNew();
  16. private int _framesThisSecond;
  17. private int _totalFrames;
  18. private int _fps;
  19. private TimeSpan _lastFpsUpdate;
  20. const int FirstChar = 32;
  21. const int LastChar = 126;
  22. // ASCII chars
  23. private GlyphRun[] _runs = new GlyphRun[LastChar - FirstChar + 1];
  24. public FpsCounter(IGlyphTypeface typeface)
  25. {
  26. for (var c = FirstChar; c <= LastChar; c++)
  27. {
  28. var s = new string((char)c, 1);
  29. var glyph = typeface.GetGlyph((uint)(s[0]));
  30. _runs[c - FirstChar] = new GlyphRun(typeface, 18, new ReadOnlySlice<char>(s.AsMemory()), new ushort[] { glyph });
  31. }
  32. }
  33. public void FpsTick() => _framesThisSecond++;
  34. public void RenderFps(IDrawingContextImpl context, string aux)
  35. {
  36. var now = _stopwatch.Elapsed;
  37. var elapsed = now - _lastFpsUpdate;
  38. ++_framesThisSecond;
  39. ++_totalFrames;
  40. if (elapsed.TotalSeconds > 1)
  41. {
  42. _fps = (int)(_framesThisSecond / elapsed.TotalSeconds);
  43. _framesThisSecond = 0;
  44. _lastFpsUpdate = now;
  45. }
  46. var fpsLine = FormattableString.Invariant($"Frame #{_totalFrames:00000000} FPS: {_fps:000} ") + aux;
  47. double width = 0;
  48. double height = 0;
  49. foreach (var ch in fpsLine)
  50. {
  51. var run = _runs[ch - FirstChar];
  52. width += run.Size.Width;
  53. height = Math.Max(height, run.Size.Height);
  54. }
  55. var rect = new Rect(0, 0, width + 3, height + 3);
  56. context.DrawRectangle(Brushes.Black, null, rect);
  57. double offset = 0;
  58. foreach (var ch in fpsLine)
  59. {
  60. var run = _runs[ch - FirstChar];
  61. context.Transform = Matrix.CreateTranslation(offset, 0);
  62. context.DrawGlyphRun(Brushes.White, run);
  63. offset += run.Size.Width;
  64. }
  65. }
  66. }