ppy / osu-framework

A game framework written with osu! in mind.
MIT License
1.66k stars 419 forks source link

Adding a WaveformGraph to a screen leads to huge fps drop #5677

Closed Azn9 closed 1 year ago

Azn9 commented 1 year ago

Hello, I don't know if it is an issue or if I'm doing something wrong, but I want to use a WaveformGraph on one of my screens, and as soon as it is added, my FPS drops from ~1000 to ~30/40.

Here is the full source code :

using System.IO;
using MDE.Game.UI;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Audio;
using osu.Framework.IO.Stores;
using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Game.Screens.Edit;
using osuTK;
using osuTK.Graphics;

namespace MDE.Game.Screens;

public partial class TestScreen : Screen
{
    private EditorClock editorClock;
    private DependencyContainer dependencies;
    protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
        => dependencies = new DependencyContainer(base.CreateChildDependencies(parent));

    private Track track;
    private Stream stream;

    [BackgroundDependencyLoader]
    private void load(AudioManager audioManager, GameHost gameHost)
    {
        editorClock = new EditorClock();
        dependencies.CacheAs(editorClock);
        AddInternal(editorClock);

        const string folder_path = @"D:\test";
        var trackStore = audioManager.GetTrackStore(
                new StorageBackedResourceStore(
                    new DesktopStorage(folder_path, gameHost as DesktopGameHost)
                    )
                );
        track = trackStore.Get("music.ogg");
        stream = trackStore.GetStream("music.ogg");

        Schedule(loadTrack);
    }

    private void loadTrack()
    {
        if (!track.IsLoaded)
        {
            Schedule(loadTrack);
            return;
        }

        editorClock.ChangeSource(track);

        var length = track.Length;
        var sizeX = (float)(length / 10f);

        var waveformComponent = new WaveformComponent() // this is just a ZoomableScrollContainer
        {
            Origin = Anchor.Centre,
            Anchor = Anchor.Centre,
            Size = new Vector2(sizeX, 200),
        };
        waveformComponent.Add(new WaveformGraph()
        {
            Origin = Anchor.Centre,
            Anchor = Anchor.Centre,
            Size = new Vector2(1, 1),
            RelativeSizeAxes = Axes.Both,
            Position = new Vector2(sizeX / 2, 0),
            Waveform = new Waveform(stream),
            HighColour = Color4.Green,
            LowColour = Color4.Red,
            MidColour = Color4.Aqua,
            BaseColour = Color4.Aquamarine
        });
        waveformComponent.SetupZoom(5, 1, 10);

        AddInternal(waveformComponent);
    }

}

Has anyone encountered this kind of issue or can explain what I am doing wrong? Thanks, Azn9

peppy commented 1 year ago

Decrease the waveform resolution, it's probably rendering too many segments.

Azn9 commented 1 year ago

Oh, thanks for your reply! I hadn't seen the "Resolution" parameter. But, to keep a decent amount of FPS, I need to set it very low, like 0.1, which gives me a really "smoothed" waveform. Is there a way to mask the parts of the waveform that aren't visible to keep both performance and precision?

Azn9 commented 1 year ago

Oh, thanks for your reply! I hadn't seen the "Resolution" parameter. But, to keep a decent amount of FPS, I need to set it very low, like 0.1, which gives me a really "smoothed" waveform. Is there a way to mask the parts of the waveform that aren't visible to keep both performance and precision?

I managed to do it by duplicating the Waveform file and changing its inner constant "resolution". It may be useful to add a setter for this. Anyway, thanks for the help!

peppy commented 1 year ago

That still seems very weird. Is it due to the nature of the test file you were using? Is it a very long audio file or something like that?

If you are able to provide a test where the low FPS can be reproduced (especially if you can do so on the included visual tests in the framework project) I'd still want to look into it.

Azn9 commented 1 year ago

That still seems very weird. Is it due to the nature of the test file you were using? Is it a very long audio file or something like that?

If you are able to provide a test where the low FPS can be reproduced (especially if you can do so on the included visual tests in the framework project) I'd still want to look into it.

It is just a ~4min long ogg file. I've tested with a random other mp3 file and had the same "issue". You can find on https://github.com/Azn9/bugdemo a complete project showing the issue. Its weird because importing the same audio file into osu!lazer editor "only" drops the fps from ~600 to ~250 in max zoom.

peppy commented 1 year ago

This change to your BaseWaveformGraph test fixes the issue (I think you were misusing the zoomable scroll container a bit which meant that the non-visible portion could not be optimised away).

diff --git a/bugdemo/bugdemo.Game.Tests/TestScreen.cs b/bugdemo/bugdemo.Game.Tests/TestScreen.cs
index 6e0a87e..93ac275 100644
--- a/bugdemo/bugdemo.Game.Tests/TestScreen.cs
+++ b/bugdemo/bugdemo.Game.Tests/TestScreen.cs
@@ -22,16 +22,13 @@ public void ShowWaveform(Track track, Stream stream)
         {
             Origin = Anchor.Centre,
             Anchor = Anchor.Centre,
-            Size = new Vector2(sizeX, 200),
+            RelativeSizeAxes = Axes.X,
+            Height = 200,
         };
         waveformComponent.Add(new WaveformGraph()
         {
-            Origin = Anchor.Centre,
-            Anchor = Anchor.Centre,
-            Size = new Vector2(1, 1),
-            RelativeSizeAxes = Axes.Both,
-            Position = new Vector2(sizeX / 2, 0),
             Waveform = new Waveform(stream),
+            RelativeSizeAxes = Axes.Both,
             HighColour = Color4.Green,
             LowColour = Color4.Red,
             MidColour = Color4.Aqua,

You can check this kinda thing by using the draw visualiser and looking for containers with sizes much larger than they actually require. In this case, it's a scroll container with a horizontal size of 60,000, defeating its purpose of existing.

Please let me know if this resolves your issue.

Azn9 commented 1 year ago

Awesome that's working perfectly! I'm not really used to working with the framework for now 😅 . Thanks for helping me tackle the issue! ❤️