From 0c3d43026d956be5b9e6ba8ed0534eaf99a0f378 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 20 Jul 2022 02:53:29 +0900 Subject: [PATCH] Add initial structure for fps counter --- .../UserInterface/TestSceneFPSCounter.cs | 51 ++++++ osu.Game/Graphics/UserInterface/FPSCounter.cs | 149 ++++++++++++++++++ .../UserInterface/FPSCounterTooltip.cs | 96 +++++++++++ 3 files changed, 296 insertions(+) create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneFPSCounter.cs create mode 100644 osu.Game/Graphics/UserInterface/FPSCounter.cs create mode 100644 osu.Game/Graphics/UserInterface/FPSCounterTooltip.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFPSCounter.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFPSCounter.cs new file mode 100644 index 0000000000..d78707045b --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFPSCounter.cs @@ -0,0 +1,51 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Testing; +using osu.Game.Graphics.UserInterface; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public class TestSceneFPSCounter : OsuTestScene + { + [SetUpSteps] + public void SetUpSteps() + { + AddStep("create display", () => + { + Children = new Drawable[] + { + new Box + { + Colour = Color4.White, + RelativeSizeAxes = Axes.Both, + }, + new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new FPSCounter(), + new FPSCounter { Scale = new Vector2(2) }, + new FPSCounter { Scale = new Vector2(4) }, + } + }, + }; + }); + } + + [Test] + public void TestBasic() + { + } + } +} diff --git a/osu.Game/Graphics/UserInterface/FPSCounter.cs b/osu.Game/Graphics/UserInterface/FPSCounter.cs new file mode 100644 index 0000000000..222c30c1dc --- /dev/null +++ b/osu.Game/Graphics/UserInterface/FPSCounter.cs @@ -0,0 +1,149 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Localisation; +using osu.Framework.Platform; +using osu.Framework.Threading; +using osu.Game.Graphics.Sprites; +using osuTK; + +namespace osu.Game.Graphics.UserInterface +{ + public class FPSCounter : CompositeDrawable, IHasCustomTooltip + { + private RollingCounter msCounter = null!; + private RollingCounter fpsCounter = null!; + + private Container mainContent = null!; + + public FPSCounter() + { + AutoSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + InternalChildren = new Drawable[] + { + mainContent = new Container + { + Alpha = 0, + Size = new Vector2(30), + Children = new Drawable[] + { + msCounter = new FrameTimeCounter + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Colour = colours.Orange2, + }, + fpsCounter = new FramesPerSecondCounter + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Y = 11, + Scale = new Vector2(0.8f), + Colour = colours.Lime3, + } + } + }, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + displayTemporarily(); + } + + private bool isDisplayed; + + private ScheduledDelegate? fadeOutDelegate; + + private void displayTemporarily() + { + if (!isDisplayed) + mainContent.FadeTo(1, 300, Easing.OutQuint); + + fadeOutDelegate?.Cancel(); + fadeOutDelegate = Scheduler.AddDelayed(() => + { + mainContent.FadeTo(0, 1000, Easing.In); + isDisplayed = false; + }, 2000); + } + + [Resolved] + private GameHost gameHost { get; set; } = null!; + + protected override void Update() + { + base.Update(); + + // TODO: this is wrong (elapsed clock time, not actual run time). + double newFrameTime = gameHost.UpdateThread.Clock.ElapsedFrameTime; + double newFps = gameHost.DrawThread.Clock.FramesPerSecond; + + bool hasSignificantChanges = + Math.Abs(msCounter.Current.Value - newFrameTime) > 5 || + Math.Abs(fpsCounter.Current.Value - newFps) > 10; + + if (hasSignificantChanges) + displayTemporarily(); + + msCounter.Current.Value = newFrameTime; + fpsCounter.Current.Value = newFps; + } + + public ITooltip GetCustomTooltip() => new FPSCounterTooltip(); + + public object TooltipContent => this; + + public class FramesPerSecondCounter : RollingCounter + { + protected override double RollingDuration => 400; + + protected override OsuSpriteText CreateSpriteText() + { + return new OsuSpriteText + { + Font = OsuFont.Default.With(fixedWidth: true, size: 16, weight: FontWeight.SemiBold), + Spacing = new Vector2(-2), + }; + } + + protected override LocalisableString FormatCount(double count) + { + return $"{count:#,0}fps"; + } + } + + public class FrameTimeCounter : RollingCounter + { + protected override double RollingDuration => 1000; + + protected override OsuSpriteText CreateSpriteText() + { + return new OsuSpriteText + { + Font = OsuFont.Default.With(fixedWidth: true, size: 16, weight: FontWeight.SemiBold), + Spacing = new Vector2(-1), + }; + } + + protected override LocalisableString FormatCount(double count) + { + if (count < 1) + return $"{count:N1}ms"; + + return $"{count:N0}ms"; + } + } + } +} diff --git a/osu.Game/Graphics/UserInterface/FPSCounterTooltip.cs b/osu.Game/Graphics/UserInterface/FPSCounterTooltip.cs new file mode 100644 index 0000000000..af95fbe556 --- /dev/null +++ b/osu.Game/Graphics/UserInterface/FPSCounterTooltip.cs @@ -0,0 +1,96 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Platform; +using osu.Game.Graphics.Containers; +using osuTK; + +namespace osu.Game.Graphics.UserInterface +{ + public class FPSCounterTooltip : CompositeDrawable, ITooltip + { + private OsuTextFlowContainer textFlow = null!; + + [Resolved] + private GameHost gameHost { get; set; } = null!; + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + AutoSizeAxes = Axes.Both; + + CornerRadius = 15; + Masking = true; + + InternalChildren = new Drawable[] + { + new Box + { + Colour = colours.Gray1, + Alpha = 1, + RelativeSizeAxes = Axes.Both, + }, + new OsuTextFlowContainer(cp => + { + cp.Font = OsuFont.Default.With(weight: FontWeight.SemiBold); + cp.Spacing = new Vector2(-1); + }) + { + AutoSizeAxes = Axes.Both, + TextAnchor = Anchor.TopRight, + Margin = new MarginPadding { Left = 5, Vertical = 10 }, + Text = string.Join('\n', gameHost.Threads.Select(t => t.Name)) + }, + textFlow = new OsuTextFlowContainer(cp => + { + cp.Font = OsuFont.Default.With(fixedWidth: true, weight: FontWeight.Regular); + cp.Spacing = new Vector2(-1); + }) + { + Width = 190, + Margin = new MarginPadding { Left = 35, Right = 10, Vertical = 10 }, + AutoSizeAxes = Axes.Y, + TextAnchor = Anchor.TopRight, + }, + }; + } + + private int lastUpdate; + + protected override void Update() + { + int currentSecond = (int)(Clock.CurrentTime / 100); + + if (currentSecond != lastUpdate) + { + lastUpdate = currentSecond; + + textFlow.Clear(); + + foreach (var thread in gameHost.Threads) + { + var clock = thread.Clock; + + string maximum = $"{(clock.MaximumUpdateHz > 0 && clock.MaximumUpdateHz < 10000 ? clock.MaximumUpdateHz.ToString("0") : "∞"),4}"; + + textFlow.AddParagraph($"{clock.FramesPerSecond:0}/{maximum}fps ({clock.ElapsedFrameTime:0.00}ms)"); + } + } + } + + public void SetContent(object content) + { + } + + public void Move(Vector2 pos) + { + Position = pos; + } + } +}