From 9e0597f5dd877cabf78ff8727aa56e89572b69b3 Mon Sep 17 00:00:00 2001 From: AiAe Date: Tue, 30 Dec 2025 16:18:08 +0200 Subject: [PATCH 1/5] wip --- Wobble.Tests/WobbleTestsGame.cs | 32 +++++++------------ Wobble/Assets/WobbleAssets.cs | 8 +++-- Wobble/Audio/AudioManager.cs | 16 +++++++++- .../Sprites/Text/SpriteTextPlusLine.cs | 5 ++- Wobble/Graphics/UI/Debugging/FpsCounter.cs | 20 ++++++------ Wobble/Managers/TextureManager.cs | 21 +++++++++++- Wobble/Window/WindowManager.cs | 8 +++-- Wobble/WobbleGame.cs | 4 +++ 8 files changed, 76 insertions(+), 38 deletions(-) diff --git a/Wobble.Tests/WobbleTestsGame.cs b/Wobble.Tests/WobbleTestsGame.cs index 6a8a8fb2..3f728d0d 100644 --- a/Wobble.Tests/WobbleTestsGame.cs +++ b/Wobble.Tests/WobbleTestsGame.cs @@ -1,10 +1,8 @@ using System; using System.Collections.Generic; -using System.Drawing; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; using Wobble.Graphics; -using Wobble.Graphics.BitmapFonts; using Wobble.Graphics.Sprites; using Wobble.Graphics.Sprites.Text; using Wobble.Graphics.UI.Debugging; @@ -24,7 +22,7 @@ public class WobbleTestsGame : WobbleGame private FpsCounter FpsCounter { get; set; } - private SpriteText WaylandState { get; set; } + private SpriteTextPlus WaylandState { get; set; } public WobbleTestsGame() : base(true) { @@ -72,36 +70,30 @@ protected override void LoadContent() Resources.AddStore(new DllResourceStore("Wobble.Tests.Resources.dll")); - if (!BitmapFontFactory.CustomFonts.ContainsKey("exo2-bold")) - BitmapFontFactory.AddFont("exo2-bold", GameBase.Game.Resources.Get("Wobble.Tests.Resources/Fonts/exo2-bold.ttf")); - - if (!BitmapFontFactory.CustomFonts.ContainsKey("exo2-regular")) - BitmapFontFactory.AddFont("exo2-regular", GameBase.Game.Resources.Get("Wobble.Tests.Resources/Fonts/exo2-regular.ttf")); - - if (!BitmapFontFactory.CustomFonts.ContainsKey("exo2-semibold")) - BitmapFontFactory.AddFont("exo2-semibold", GameBase.Game.Resources.Get("Wobble.Tests.Resources/Fonts/exo2-semibold.ttf")); - - if (!BitmapFontFactory.CustomFonts.ContainsKey("exo2-medium")) - BitmapFontFactory.AddFont("exo2-medium", GameBase.Game.Resources.Get("Wobble.Tests.Resources/Fonts/exo2-medium.ttf")); + var fonts = new List { "exo2-bold", "exo2-regular", "exo2-semibold", "exo2-medium" }; + foreach (var fontName in fonts) + { + FontManager.CacheWobbleFont(fontName, new WobbleFontStore(20, GameBase.Game.Resources.Get($"Wobble.Tests.Resources/Fonts/{fontName}.ttf"))); + } - var font = new WobbleFontStore(20, GameBase.Game.Resources.Get("Wobble.Tests.Resources/Fonts/exo2-semibold.ttf"), new Dictionary() + var japaneseFont = new WobbleFontStore(20, GameBase.Game.Resources.Get("Wobble.Tests.Resources/Fonts/exo2-semibold.ttf"), new Dictionary() { {"Emoji", GameBase.Game.Resources.Get("Wobble.Tests.Resources/Fonts/symbola-emoji.ttf")}, {"Japanese", GameBase.Game.Resources.Get("Wobble.Tests.Resources/Fonts/droid-sans-japanese.ttf")} }); - FontManager.CacheWobbleFont("exo2-semibold", font); + FontManager.CacheWobbleFont("exo2-semibold-japanese", japaneseFont); IsReadyToUpdate = true; - FpsCounter = new FpsCounter(FontManager.LoadBitmapFont("Content/gotham"), 18) + FpsCounter = new FpsCounter(FontManager.GetWobbleFont("exo2-semibold"), 18) { Parent = GlobalUserInterface, Alignment = Alignment.BotRight, Size = new ScalableVector2(70, 30), }; - WaylandState = new SpriteText("exo2-semibold", $"Wayland: {WaylandVsync}", 18) + WaylandState = new SpriteTextPlus(FontManager.GetWobbleFont("exo2-semibold"), $"Wayland: {WaylandVsync}", 18) { Parent = GlobalUserInterface, Alignment = Alignment.BotRight, @@ -137,7 +129,7 @@ protected override void Update(GameTime gameTime) if (KeyboardManager.IsUniqueKeyPress(Keys.W) && OperatingSystem.IsLinux()) { WaylandVsync = !WaylandVsync; - WaylandState.ScheduleUpdate(() => WaylandState.Text = $"Wayland: {WaylandVsync}"); + WaylandState.Text = $"Wayland: {WaylandVsync}"; } } @@ -151,4 +143,4 @@ protected override void Draw(GameTime gameTime) GameBase.Game.TryEndBatch(); } } -} +} \ No newline at end of file diff --git a/Wobble/Assets/WobbleAssets.cs b/Wobble/Assets/WobbleAssets.cs index 3a3f0269..1f290a68 100644 --- a/Wobble/Assets/WobbleAssets.cs +++ b/Wobble/Assets/WobbleAssets.cs @@ -27,6 +27,10 @@ internal static void Load() /// /// Disposes of all the assets that Wobble has included /// - internal static void Dispose() => WhiteBox.Dispose(); + internal static void Dispose() + { + WhiteBox?.Dispose(); + Wallpaper?.Dispose(); + } } -} \ No newline at end of file +} diff --git a/Wobble/Audio/AudioManager.cs b/Wobble/Audio/AudioManager.cs index 14331a38..833ba2d8 100644 --- a/Wobble/Audio/AudioManager.cs +++ b/Wobble/Audio/AudioManager.cs @@ -64,7 +64,21 @@ public static void Initialize(int? devicePeriod, int? deviceBufferLength, int? d /// /// Disposes of any resources used by BASS. /// - internal static void Dispose() => Bass.Free(); + internal static void Dispose() + { + if (Tracks != null) + { + lock (Tracks) + { + for (var i = 0; i < Tracks.Count; i++) + Tracks[i]?.Dispose(); + + Tracks.Clear(); + } + } + + Bass.Free(); + } /// /// Updates the AudioManager and keeps things up-to-date. diff --git a/Wobble/Graphics/Sprites/Text/SpriteTextPlusLine.cs b/Wobble/Graphics/Sprites/Text/SpriteTextPlusLine.cs index 5b838e00..847a4d9c 100644 --- a/Wobble/Graphics/Sprites/Text/SpriteTextPlusLine.cs +++ b/Wobble/Graphics/Sprites/Text/SpriteTextPlusLine.cs @@ -112,7 +112,10 @@ public SpriteTextPlusLine(WobbleFontStore font, string text, float size = 0) private static float GetScale() { var scale = WindowManager.ScreenScale.X; - Debug.Assert(scale > 0, "You're setting up text too early (WindowManager.ScreenScale.X is 0)."); + + // Some stuff (namely DrawableLog and the FPS counter) wants to draw text before anything is initialized. + if (scale == 0) + scale = 1; if (GameBase.Game.Graphics.PreferredBackBufferWidth < 1600) return scale * 2; diff --git a/Wobble/Graphics/UI/Debugging/FpsCounter.cs b/Wobble/Graphics/UI/Debugging/FpsCounter.cs index a46dc876..36d51d67 100644 --- a/Wobble/Graphics/UI/Debugging/FpsCounter.cs +++ b/Wobble/Graphics/UI/Debugging/FpsCounter.cs @@ -1,9 +1,9 @@ using System; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; -using MonoGame.Extended.BitmapFonts; -using Wobble.Graphics.BitmapFonts; using Wobble.Graphics.Sprites; +using Wobble.Graphics.Sprites.Text; +using Wobble.Managers; namespace Wobble.Graphics.UI.Debugging { @@ -20,9 +20,9 @@ public class FpsCounter : Container private int FrameCounter { get; set; } /// - /// The SpriteText that displays the FPS value. + /// The SpriteTextPlus that displays the FPS value. /// - public SpriteTextBitmap TextFps { get; } + public SpriteTextPlus TextFps { get; } /// /// The current update rate. @@ -35,9 +35,9 @@ public class FpsCounter : Container private int UpdateCounter { get; set; } /// - /// The SpriteText that displays the UPS value. + /// The SpriteTextPlus that displays the UPS value. /// - public SpriteTextBitmap TextUps { get; } + public SpriteTextPlus TextUps { get; } /// /// The amount of time elapsed so we can begin counting each second. @@ -48,20 +48,18 @@ public class FpsCounter : Container /// /// Ctor /// - public FpsCounter(BitmapFont font, int size) + public FpsCounter(WobbleFontStore font, int size) { - TextFps = new SpriteTextBitmap(font, "0 FPS", false) + TextFps = new SpriteTextPlus(font, "0 FPS", size) { Parent = this, Alignment = Alignment.TopRight, - FontSize = size }; - TextUps = new SpriteTextBitmap(font, "0 UPS", false) + TextUps = new SpriteTextPlus(font, "0 UPS", size) { Parent = this, Alignment = Alignment.TopRight, - FontSize = size, Y = TextFps.Size.Y.Value }; } diff --git a/Wobble/Managers/TextureManager.cs b/Wobble/Managers/TextureManager.cs index 8f2b525a..7ffe281f 100644 --- a/Wobble/Managers/TextureManager.cs +++ b/Wobble/Managers/TextureManager.cs @@ -45,10 +45,29 @@ public static List LoadAtlas(string name, int rows, int columns) var tex = AssetLoader.LoadTexture2D(GameBase.Game.Resources.Get(name)); var textures = AssetLoader.LoadSpritesheetFromTexture(tex, rows, columns); + tex.Dispose(); TextureAtlases.Add(name, textures); return textures; } + + /// + /// Disposes all cached textures and clears the caches. + /// + internal static void Dispose() + { + foreach (var texture in Textures.Values) + texture?.Dispose(); + + foreach (var atlas in TextureAtlases.Values) + { + for (var i = 0; i < atlas.Count; i++) + atlas[i]?.Dispose(); + } + + Textures.Clear(); + TextureAtlases.Clear(); + } } -} \ No newline at end of file +} diff --git a/Wobble/Window/WindowManager.cs b/Wobble/Window/WindowManager.cs index 6e0c8a1b..4ab30c84 100644 --- a/Wobble/Window/WindowManager.cs +++ b/Wobble/Window/WindowManager.cs @@ -106,7 +106,11 @@ public static void Update() /// /// Unhooks all events from the WindowManager. /// - public static void UnHookEvents() => ResolutionChanged = null; + public static void UnHookEvents() + { + ResolutionChanged = null; + VirtualScreenSizeChanged = null; + } /// /// Changes the size of the virtual screen to be used. @@ -173,4 +177,4 @@ private static void UpdateBackBufferSize() GameBase.Game.Graphics.PreferredBackBufferHeight = GameBase.Game.Window.ClientBounds.Height; } } -} \ No newline at end of file +} diff --git a/Wobble/WobbleGame.cs b/Wobble/WobbleGame.cs index 8b2ab2c8..89958ffd 100644 --- a/Wobble/WobbleGame.cs +++ b/Wobble/WobbleGame.cs @@ -17,6 +17,7 @@ using Wobble.Input; using Wobble.IO; using Wobble.Logging; +using Wobble.Managers; using Wobble.Platform; using Wobble.Platform.Linux; using Wobble.Screens; @@ -216,6 +217,9 @@ protected override void LoadContent() protected override void UnloadContent() { WobbleAssets.Dispose(); + TextureManager.Dispose(); + Resources?.Dispose(); + Window.ClientSizeChanged -= WindowManager.OnClientSizeChanged; WindowManager.UnHookEvents(); AudioManager.Dispose(); DiscordManager.Dispose(); From 4e3200e8dc14d5a422570b53f34852f612aad851 Mon Sep 17 00:00:00 2001 From: AiAe Date: Tue, 30 Dec 2025 16:25:37 +0200 Subject: [PATCH 2/5] wip --- Wobble/Graphics/BitmapFonts/BitmapFontFactory.cs | 5 ++++- Wobble/Graphics/Sprites/Text/SpriteTextPlusLineRaw.cs | 7 +++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Wobble/Graphics/BitmapFonts/BitmapFontFactory.cs b/Wobble/Graphics/BitmapFonts/BitmapFontFactory.cs index 1dc5249f..1045321b 100644 --- a/Wobble/Graphics/BitmapFonts/BitmapFontFactory.cs +++ b/Wobble/Graphics/BitmapFonts/BitmapFontFactory.cs @@ -106,6 +106,9 @@ internal static Texture2D Create(string fontName, string text, float fontSize, C textSize.Width = Math.Max(1, textSize.Width); textSize.Height = Math.Max(1, textSize.Height); + // Add a pad based on font size to avoid descender clipping when rendering into the bitmap. + textSize.Height += Math.Max(2f, fontSize * 0.25f); + // Create the actual bitmap using the size of the text. using (var bmp = new Bitmap((int)(textSize.Width + 0.5), (int)(textSize.Height + 0.5), PixelFormat.Format32bppArgb)) using (var g = System.Drawing.Graphics.FromImage(bmp)) @@ -220,4 +223,4 @@ internal static void Dispose() font.Value.Family.Dispose(); } } -} \ No newline at end of file +} diff --git a/Wobble/Graphics/Sprites/Text/SpriteTextPlusLineRaw.cs b/Wobble/Graphics/Sprites/Text/SpriteTextPlusLineRaw.cs index acaad78f..445488e1 100644 --- a/Wobble/Graphics/Sprites/Text/SpriteTextPlusLineRaw.cs +++ b/Wobble/Graphics/Sprites/Text/SpriteTextPlusLineRaw.cs @@ -1,3 +1,4 @@ +using System; using Wobble.Window; namespace Wobble.Graphics.Sprites.Text @@ -67,7 +68,9 @@ private void RefreshSize() Font.FontSize = FontSize; var (x, y) = Font.Store.MeasureString(Text); - Size = new ScalableVector2(x, y); + var padding = Math.Max(2f, FontSize * 0.25f); + var height = Math.Max(y, Font.Store.LineHeight) + padding; + Size = new ScalableVector2(x, height); } } -} \ No newline at end of file +} From 85d147b8d23e5d6aad56f47ead23781348f7a4b2 Mon Sep 17 00:00:00 2001 From: AiAe Date: Tue, 30 Dec 2025 16:26:36 +0200 Subject: [PATCH 3/5] wip --- .../Screens/Tests/Background/TestBackgroundImageScreenView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Wobble.Tests/Screens/Tests/Background/TestBackgroundImageScreenView.cs b/Wobble.Tests/Screens/Tests/Background/TestBackgroundImageScreenView.cs index 482653c4..ed992cdb 100644 --- a/Wobble.Tests/Screens/Tests/Background/TestBackgroundImageScreenView.cs +++ b/Wobble.Tests/Screens/Tests/Background/TestBackgroundImageScreenView.cs @@ -17,7 +17,7 @@ public class TestBackgroundImageScreenView : ScreenView /// /// /// - public TestBackgroundImageScreenView(Screen screen) : base(screen) => Background = new BackgroundImage(WobbleAssets.WhiteBox, 60) + public TestBackgroundImageScreenView(Screen screen) : base(screen) => Background = new BackgroundImage(WobbleAssets.Wallpaper, 60) { Parent = Container }; From f721f16f34e063f61e79840761de9e76f6559761 Mon Sep 17 00:00:00 2001 From: AiAe Date: Tue, 30 Dec 2025 16:57:35 +0200 Subject: [PATCH 4/5] wip --- .../Screens/Tests/Audio/TestAudioScreen.cs | 1 + .../TestBlurContainerScreenView.cs | 12 ++++- .../TestBlurredBackgroundImageScreenView.cs | 4 +- .../TestScheduledUpdatesScreenView.cs | 27 +++++++--- Wobble.Tests/WobbleTestsGame.cs | 53 ++++++++++++++++++- Wobble/Graphics/ImGUI/ImGuiRenderer.cs | 12 ++++- Wobble/Graphics/Shaders/GaussianBlur.cs | 13 ++++- Wobble/Graphics/Sprites/BakeableSprite.cs | 11 ++++ Wobble/Graphics/Sprites/BlurContainer.cs | 27 +++++++++- .../Graphics/Sprites/RenderTargetContainer.cs | 11 ++++ .../Graphics/Sprites/SpriteAlphaMaskBlend.cs | 6 +++ Wobble/Logging/Logger.cs | 2 +- Wobble/Wobble.csproj | 2 +- 13 files changed, 163 insertions(+), 18 deletions(-) diff --git a/Wobble.Tests/Screens/Tests/Audio/TestAudioScreen.cs b/Wobble.Tests/Screens/Tests/Audio/TestAudioScreen.cs index c199483a..7a3678db 100644 --- a/Wobble.Tests/Screens/Tests/Audio/TestAudioScreen.cs +++ b/Wobble.Tests/Screens/Tests/Audio/TestAudioScreen.cs @@ -55,6 +55,7 @@ public override void Destroy() { Song?.Dispose(); Train?.Dispose(); + HitSound?.Dispose(); base.Destroy(); } diff --git a/Wobble.Tests/Screens/Tests/BlurContainer/TestBlurContainerScreenView.cs b/Wobble.Tests/Screens/Tests/BlurContainer/TestBlurContainerScreenView.cs index 7cba8a53..967a5682 100644 --- a/Wobble.Tests/Screens/Tests/BlurContainer/TestBlurContainerScreenView.cs +++ b/Wobble.Tests/Screens/Tests/BlurContainer/TestBlurContainerScreenView.cs @@ -23,6 +23,8 @@ public class TestBlurContainerScreenView : ScreenView /// public SpriteText BlurStrengthText { get; } + private int _lastStrength; + /// /// /// @@ -57,6 +59,8 @@ public TestBlurContainerScreenView(Screen screen) : base(screen) Alignment = Alignment.TopCenter, Y = 15, }; + + _lastStrength = (int)Blur.Strength; } /// @@ -85,7 +89,11 @@ public override void Update(GameTime gameTime) if (KeyboardManager.IsUniqueKeyPress(Keys.Right)) Blur.Strength += 1; - BlurStrengthText.Text = $"Blur Strength: {Blur.Strength}"; + if ((int)Blur.Strength != _lastStrength) + { + _lastStrength = (int)Blur.Strength; + BlurStrengthText.Text = $"Blur Strength: {Blur.Strength}"; + } Container?.Update(gameTime); } @@ -104,4 +112,4 @@ public override void Draw(GameTime gameTime) /// public override void Destroy() => Container?.Destroy(); } -} \ No newline at end of file +} diff --git a/Wobble.Tests/Screens/Tests/BlurredBgImage/TestBlurredBackgroundImageScreenView.cs b/Wobble.Tests/Screens/Tests/BlurredBgImage/TestBlurredBackgroundImageScreenView.cs index e68fb7c5..7f15db4d 100644 --- a/Wobble.Tests/Screens/Tests/BlurredBgImage/TestBlurredBackgroundImageScreenView.cs +++ b/Wobble.Tests/Screens/Tests/BlurredBgImage/TestBlurredBackgroundImageScreenView.cs @@ -11,7 +11,7 @@ public class TestBlurredBackgroundImageScreenView : ScreenView { public TestBlurredBackgroundImageScreenView(Screen screen) : base(screen) { - var blur = new GaussianBlur(1.1f); + using var blur = new GaussianBlur(1.1f); var image = blur.PerformGaussianBlur(WobbleAssets.Wallpaper); var background = new BackgroundImage(image) @@ -42,4 +42,4 @@ public override void Draw(GameTime gameTime) /// public override void Destroy() => Container?.Destroy(); } -} \ No newline at end of file +} diff --git a/Wobble.Tests/Screens/Tests/ScheduledUpdates/TestScheduledUpdatesScreenView.cs b/Wobble.Tests/Screens/Tests/ScheduledUpdates/TestScheduledUpdatesScreenView.cs index c06f0859..881fc875 100644 --- a/Wobble.Tests/Screens/Tests/ScheduledUpdates/TestScheduledUpdatesScreenView.cs +++ b/Wobble.Tests/Screens/Tests/ScheduledUpdates/TestScheduledUpdatesScreenView.cs @@ -17,6 +17,8 @@ namespace Wobble.Tests.Screens.Tests.ScheduledUpdates public class TestScheduledUpdatesScreenView: ScreenView { private SpriteTextPlus Scheduled { get; } + private CancellationTokenSource _updateTokenSource; + private Task _updateTask; /// /// @@ -27,20 +29,25 @@ public TestScheduledUpdatesScreenView(Screen screen) : base(screen) Scheduled = new SpriteTextPlus(FontManager.GetWobbleFont("exo2-semibold"), "", 36) { + Parent = Container, Alignment = Alignment.TopCenter, Y = 250 }; - Task.Run(() => + _updateTokenSource = new CancellationTokenSource(); + var token = _updateTokenSource.Token; + _updateTask = Task.Run(async () => { - while (!Scheduled.IsDisposed) + while (!token.IsCancellationRequested && !Scheduled.IsDisposed) { if (IsScheduled) Scheduled.ScheduleUpdate(() => Scheduled.Text = $"Scheduled - {DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}"); else Scheduled.Text = $"Unscheduled - {DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}"; + + await Task.Delay(16, token); } - }); + }, token); new SpriteText("exo2-semibold", "Press 1 to toggle between scheduled & unscheduled", 32) { @@ -62,10 +69,16 @@ public override void Draw(GameTime gameTime) { GameBase.Game.GraphicsDevice.Clear(Color.CornflowerBlue); Container?.Draw(gameTime); - - Scheduled.Draw(gameTime); } - public override void Destroy() => Container?.Destroy(); + public override void Destroy() + { + _updateTokenSource?.Cancel(); + _updateTokenSource?.Dispose(); + _updateTokenSource = null; + _updateTask = null; + + Container?.Destroy(); + } } -} \ No newline at end of file +} diff --git a/Wobble.Tests/WobbleTestsGame.cs b/Wobble.Tests/WobbleTestsGame.cs index 3f728d0d..dc7803e1 100644 --- a/Wobble.Tests/WobbleTestsGame.cs +++ b/Wobble.Tests/WobbleTestsGame.cs @@ -8,6 +8,7 @@ using Wobble.Graphics.UI.Debugging; using Wobble.Input; using Wobble.IO; +using Wobble.Logging; using Wobble.Managers; using Wobble.Screens; using Wobble.Tests.Screens.Selection; @@ -24,6 +25,10 @@ public class WobbleTestsGame : WobbleGame private SpriteTextPlus WaylandState { get; set; } + private bool _logGc; + private double _gcLogTimer; + private readonly int[] _lastGcCounts = new int[3]; + public WobbleTestsGame() : base(true) { } @@ -131,6 +136,32 @@ protected override void Update(GameTime gameTime) WaylandVsync = !WaylandVsync; WaylandState.Text = $"Wayland: {WaylandVsync}"; } + + if (KeyboardManager.IsUniqueKeyPress(Keys.F10)) + { + _logGc = !_logGc; + _gcLogTimer = 0; + Logger.Debug($"GC logging {(_logGc ? "enabled" : "disabled")}.", LogType.Runtime); + LogGc("GC toggle"); + } + + if (KeyboardManager.IsUniqueKeyPress(Keys.F9)) + { + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.Collect(); + LogGc("GC forced"); + } + + if (_logGc) + { + _gcLogTimer += gameTime.ElapsedGameTime.TotalMilliseconds; + if (_gcLogTimer >= 1000) + { + _gcLogTimer = 0; + LogGc("GC tick"); + } + } } protected override void Draw(GameTime gameTime) @@ -142,5 +173,25 @@ protected override void Draw(GameTime gameTime) GlobalUserInterface?.Draw(gameTime); GameBase.Game.TryEndBatch(); } + + private void LogGc(string tag) + { + var totalBytes = GC.GetTotalMemory(false); + var gen0 = GC.CollectionCount(0); + var gen1 = GC.CollectionCount(1); + var gen2 = GC.CollectionCount(2); + + var delta0 = gen0 - _lastGcCounts[0]; + var delta1 = gen1 - _lastGcCounts[1]; + var delta2 = gen2 - _lastGcCounts[2]; + + _lastGcCounts[0] = gen0; + _lastGcCounts[1] = gen1; + _lastGcCounts[2] = gen2; + + Logger.Debug( + $"{tag}: managed={totalBytes / (1024 * 1024)}MB gen0={gen0}(+{delta0}) gen1={gen1}(+{delta1}) gen2={gen2}(+{delta2})", + LogType.Runtime); + } } -} \ No newline at end of file +} diff --git a/Wobble/Graphics/ImGUI/ImGuiRenderer.cs b/Wobble/Graphics/ImGUI/ImGuiRenderer.cs index fb8959e9..f22b5e77 100644 --- a/Wobble/Graphics/ImGUI/ImGuiRenderer.cs +++ b/Wobble/Graphics/ImGUI/ImGuiRenderer.cs @@ -172,7 +172,13 @@ public IntPtr BindTexture(Texture2D texture) /// /// Removes a previously created texture pointer, releasing its reference and allowing it to be deallocated /// - public void UnbindTexture(IntPtr textureId) => LoadedTextures.Remove(textureId); + public void UnbindTexture(IntPtr textureId) + { + if (LoadedTextures.TryGetValue(textureId, out var texture)) + texture.Dispose(); + + LoadedTextures.Remove(textureId); + } /// /// Sets up ImGui for a new frame, should be called at frame start @@ -546,6 +552,10 @@ public void Dispose() if (DestroyContext) ImGui.DestroyContext(Context); + foreach (var texture in LoadedTextures.Values) + texture.Dispose(); + + LoadedTextures.Clear(); Effect?.Dispose(); RasterizerState?.Dispose(); VertexBuffer?.Dispose(); diff --git a/Wobble/Graphics/Shaders/GaussianBlur.cs b/Wobble/Graphics/Shaders/GaussianBlur.cs index a9ae29b0..d60cdb16 100644 --- a/Wobble/Graphics/Shaders/GaussianBlur.cs +++ b/Wobble/Graphics/Shaders/GaussianBlur.cs @@ -81,7 +81,7 @@ namespace Wobble.Graphics.Shaders /// offsetsHoriz and offsetsVert fields. /// /// - public class GaussianBlur + public class GaussianBlur : IDisposable { private Game game => GameBase.Game; private Effect effect; @@ -142,6 +142,15 @@ public GaussianBlur(float strength) ComputeKernel(7, strength); } + /// + /// + /// + public void Dispose() + { + effect?.Dispose(); + effect = null; + } + /// /// Calculates the Gaussian blur filter kernel. This implementation is /// ported from the original Java code appearing in chapter 16 of @@ -280,4 +289,4 @@ public Texture2D PerformGaussianBlur(Texture2D srcTexture) return outputTexture; } } -} \ No newline at end of file +} diff --git a/Wobble/Graphics/Sprites/BakeableSprite.cs b/Wobble/Graphics/Sprites/BakeableSprite.cs index bcb6039e..b09580c0 100644 --- a/Wobble/Graphics/Sprites/BakeableSprite.cs +++ b/Wobble/Graphics/Sprites/BakeableSprite.cs @@ -68,5 +68,16 @@ private void Bake(GameTime gameTime) HasBeenBaked = true; } + + /// + /// + /// + public override void Destroy() + { + if (BakedRenderTarget != null && !BakedRenderTarget.IsDisposed) + BakedRenderTarget.Dispose(); + + base.Destroy(); + } } } diff --git a/Wobble/Graphics/Sprites/BlurContainer.cs b/Wobble/Graphics/Sprites/BlurContainer.cs index 0d8338ce..a897b416 100644 --- a/Wobble/Graphics/Sprites/BlurContainer.cs +++ b/Wobble/Graphics/Sprites/BlurContainer.cs @@ -76,6 +76,31 @@ public override void Draw(GameTime gameTime) base.Draw(gameTime); } + + /// + /// + /// + public override void Destroy() + { + var activeEffect = SpriteBatchOptions?.Shader?.ShaderEffect; + + if (SpriteBatchOptions?.Shader != null) + { + SpriteBatchOptions.Shader.Dispose(); + SpriteBatchOptions.Shader = null; + } + + if (BlurEffects != null) + { + foreach (var effect in BlurEffects.Values) + { + if (!ReferenceEquals(effect, activeEffect)) + effect.Dispose(); + } + } + + base.Destroy(); + } } /// @@ -87,4 +112,4 @@ public enum BlurType Frosty, Fast } -} \ No newline at end of file +} diff --git a/Wobble/Graphics/Sprites/RenderTargetContainer.cs b/Wobble/Graphics/Sprites/RenderTargetContainer.cs index 4ad03a0b..094b6c60 100644 --- a/Wobble/Graphics/Sprites/RenderTargetContainer.cs +++ b/Wobble/Graphics/Sprites/RenderTargetContainer.cs @@ -69,5 +69,16 @@ public override void Draw(GameTime gameTime) // Attempt to end the spritebatch _ = GameBase.Game.TryEndBatch(); } + + /// + /// + /// + public override void Destroy() + { + if (RenderTarget != null && !RenderTarget.IsDisposed) + RenderTarget.Dispose(); + + base.Destroy(); + } } } diff --git a/Wobble/Graphics/Sprites/SpriteAlphaMaskBlend.cs b/Wobble/Graphics/Sprites/SpriteAlphaMaskBlend.cs index a3cfcb6a..4d19dd5d 100644 --- a/Wobble/Graphics/Sprites/SpriteAlphaMaskBlend.cs +++ b/Wobble/Graphics/Sprites/SpriteAlphaMaskBlend.cs @@ -17,6 +17,12 @@ public class SpriteAlphaMaskBlend : Sprite public Texture2D PerformBlend(Texture2D srcTexture, Texture2D srcMask) { + if (RenderTarget != null && !RenderTarget.IsDisposed) + { + RenderTarget.Dispose(); + RenderTarget = null; + } + RenderTarget = new RenderTarget2D(GameBase.Game.GraphicsDevice, srcTexture.Width, srcTexture.Height, false, GameBase.Game.GraphicsDevice.PresentationParameters.BackBufferFormat, DepthFormat.None); diff --git a/Wobble/Logging/Logger.cs b/Wobble/Logging/Logger.cs index 8234500b..6d17d091 100644 --- a/Wobble/Logging/Logger.cs +++ b/Wobble/Logging/Logger.cs @@ -152,7 +152,7 @@ public static void Log(string m, LogLevel level, LogType type, bool writeToFile catch (Exception e) { // If it fails, we can't really handle the error here. This shouldn't happen though. - Console.WriteLine(e); + // Console.WriteLine(e); } } diff --git a/Wobble/Wobble.csproj b/Wobble/Wobble.csproj index dd2e6473..b1d5c56b 100644 --- a/Wobble/Wobble.csproj +++ b/Wobble/Wobble.csproj @@ -2,7 +2,7 @@ net6.0 true - 7.1 + 7.2 false From 8eed9d851281782905c49dabdd88e4197198139a Mon Sep 17 00:00:00 2001 From: AiAe Date: Tue, 30 Dec 2025 17:04:24 +0200 Subject: [PATCH 5/5] wip --- Wobble/Graphics/Drawable.cs | 6 ++++++ Wobble/Graphics/Sprites/Sprite.cs | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Wobble/Graphics/Drawable.cs b/Wobble/Graphics/Drawable.cs index 18a8812f..b4990733 100644 --- a/Wobble/Graphics/Drawable.cs +++ b/Wobble/Graphics/Drawable.cs @@ -539,6 +539,12 @@ public virtual void Draw(GameTime gameTime) for (var i = 0; i < Children.Count; i++) { var drawable = Children[i]; + if (drawable == null) + { + Children.RemoveAt(i); + i--; + continue; + } drawable.Draw(gameTime); TotalDrawn++; diff --git a/Wobble/Graphics/Sprites/Sprite.cs b/Wobble/Graphics/Sprites/Sprite.cs index 42052fa0..867e2027 100644 --- a/Wobble/Graphics/Sprites/Sprite.cs +++ b/Wobble/Graphics/Sprites/Sprite.cs @@ -135,7 +135,7 @@ public bool IndependentRotation public override void Draw(GameTime gameTime) { // If there is no image set, create a dummy 1px one. - if (Image == null) + if (Image == null || Image.IsDisposed) Image = WobbleAssets.WhiteBox; if (SpriteBatchOptions != null)