diff --git a/src/Ryujinx.Graphics.Gpu/GpuContext.cs b/src/Ryujinx.Graphics.Gpu/GpuContext.cs
index d0b8277da..4e71e8582 100644
--- a/src/Ryujinx.Graphics.Gpu/GpuContext.cs
+++ b/src/Ryujinx.Graphics.Gpu/GpuContext.cs
@@ -40,6 +40,7 @@ namespace Ryujinx.Graphics.Gpu
/// GPU synchronization manager.
///
public SynchronizationManager Synchronization { get; }
+ public IOverlayManager OverlayManager { get; }
///
/// Presentation window.
@@ -121,14 +122,18 @@ namespace Ryujinx.Graphics.Gpu
/// Creates a new instance of the GPU emulation context.
///
/// Host renderer
- public GpuContext(IRenderer renderer, DirtyHacks hacks)
+ /// Enabled dirty hacks
+ /// Overlay manager for rendering overlays
+ public GpuContext(IRenderer renderer, DirtyHacks hacks, IOverlayManager overlayManager)
{
Renderer = renderer;
GPFifo = new GPFifoDevice(this);
Synchronization = new SynchronizationManager();
-
+
+ OverlayManager = overlayManager;
+
Window = new Window(this);
HostInitalized = new ManualResetEvent(false);
@@ -462,6 +467,8 @@ namespace Ryujinx.Graphics.Gpu
RunDeferredActions();
Renderer.Dispose();
+
+ OverlayManager.Dispose();
}
}
}
diff --git a/src/Ryujinx.Graphics.Gpu/IOverlay.cs b/src/Ryujinx.Graphics.Gpu/IOverlay.cs
new file mode 100644
index 000000000..700b6330a
--- /dev/null
+++ b/src/Ryujinx.Graphics.Gpu/IOverlay.cs
@@ -0,0 +1,54 @@
+using SkiaSharp;
+using System;
+
+namespace Ryujinx.Graphics.Gpu
+{
+ ///
+ /// Interface for overlay functionality
+ ///
+ public interface IOverlay : IDisposable
+ {
+ ///
+ /// Name of the overlay
+ ///
+ string Name { get; set; }
+
+ ///
+ /// Whether the overlay is visible
+ ///
+ bool IsVisible { get; set; }
+
+ ///
+ /// Opacity of the overlay (0.0 to 1.0)
+ ///
+ float Opacity { get; set; }
+
+ ///
+ /// X position of the overlay
+ ///
+ float X { get; set; }
+
+ ///
+ /// Y position of the overlay
+ ///
+ float Y { get; set; }
+
+ ///
+ /// Z-index for overlay ordering
+ ///
+ int ZIndex { get; set; }
+
+ ///
+ /// Update overlay (for animations)
+ ///
+ /// Time elapsed since last update
+ /// Current screen size
+ void Update(float deltaTime, SKSize screenSize = default);
+
+ ///
+ /// Render this overlay
+ ///
+ /// The canvas to render to
+ void Render(SKCanvas canvas);
+ }
+}
diff --git a/src/Ryujinx.Graphics.Gpu/IOverlayManager.cs b/src/Ryujinx.Graphics.Gpu/IOverlayManager.cs
new file mode 100644
index 000000000..d3aeba260
--- /dev/null
+++ b/src/Ryujinx.Graphics.Gpu/IOverlayManager.cs
@@ -0,0 +1,30 @@
+using SkiaSharp;
+using System;
+
+namespace Ryujinx.Graphics.Gpu
+{
+ ///
+ /// Interface for overlay management functionality
+ ///
+ public interface IOverlayManager : IDisposable
+ {
+ ///
+ /// Add an overlay to the manager
+ ///
+ /// The overlay to add
+ void AddOverlay(IOverlay overlay);
+
+ ///
+ /// Update all overlays (for animations)
+ ///
+ /// Time elapsed since last update
+ /// Current screen size
+ void Update(float deltaTime, SKSize screenSize = default);
+
+ ///
+ /// Render all visible overlays
+ ///
+ /// The canvas to render to
+ void Render(SKCanvas canvas);
+ }
+}
diff --git a/src/Ryujinx.Graphics.Gpu/Window.cs b/src/Ryujinx.Graphics.Gpu/Window.cs
index 7c023d5a8..6bcedd2b7 100644
--- a/src/Ryujinx.Graphics.Gpu/Window.cs
+++ b/src/Ryujinx.Graphics.Gpu/Window.cs
@@ -3,7 +3,6 @@ using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Image;
using Ryujinx.Graphics.Gpu.Memory;
-using Ryujinx.Graphics.Gpu.Overlay;
using Ryujinx.Graphics.Texture;
using Ryujinx.Memory.Range;
using SkiaSharp;
@@ -20,7 +19,6 @@ namespace Ryujinx.Graphics.Gpu
public class Window
{
private readonly GpuContext _context;
- private readonly OverlayManager _overlayManager;
private DateTime? _lastUpdateTime = null;
///
@@ -105,7 +103,6 @@ namespace Ryujinx.Graphics.Gpu
public Window(GpuContext context)
{
_context = context;
- _overlayManager = new OverlayManager();
_frameQueue = new ConcurrentQueue();
}
@@ -258,9 +255,9 @@ namespace Ryujinx.Graphics.Gpu
///
/// Add overlay to the overlay manager
///
- public void AddOverlay(Overlay.Overlay overlay)
+ public void AddOverlay(IOverlay overlay)
{
- _overlayManager.AddOverlay(overlay);
+ _context.OverlayManager.AddOverlay(overlay);
}
///
@@ -276,7 +273,7 @@ namespace Ryujinx.Graphics.Gpu
{
// Calculate delta time for lifespan updates
float deltaTime = (float)(currentTime - _lastUpdateTime.Value).TotalSeconds;
- _overlayManager.Update(deltaTime, new SKSize(texture.Info.Width, texture.Info.Height));
+ _context.OverlayManager.Update(deltaTime, new SKSize(texture.Info.Width, texture.Info.Height));
}
// Update overlay animations
@@ -326,7 +323,7 @@ namespace Ryujinx.Graphics.Gpu
}
// Render all overlays
- _overlayManager.Render(canvas);
+ _context.OverlayManager.Render(canvas);
// Copy modified bitmap data back to texture data array
var pixels = bitmap.Bytes;
@@ -370,13 +367,5 @@ namespace Ryujinx.Graphics.Gpu
return false;
}
-
- ///
- /// Dispose resources
- ///
- public void Dispose()
- {
- _overlayManager?.Dispose();
- }
}
}
diff --git a/src/Ryujinx.HLE/HleConfiguration.cs b/src/Ryujinx.HLE/HleConfiguration.cs
index 10c2a1f30..85d0e3502 100644
--- a/src/Ryujinx.HLE/HleConfiguration.cs
+++ b/src/Ryujinx.HLE/HleConfiguration.cs
@@ -3,6 +3,7 @@ using Ryujinx.Audio.Integration;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Multiplayer;
using Ryujinx.Graphics.GAL;
+using Ryujinx.Graphics.Gpu;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS;
using Ryujinx.HLE.HOS.Services.Account.Acc;
@@ -65,6 +66,12 @@ namespace Ryujinx.HLE
/// This cannot be changed after instantiation.
internal IHostUIHandler HostUIHandler { get; private set; }
+ ///
+ /// The overlay manager to use for all overlay operations.
+ ///
+ /// This cannot be changed after instantiation.
+ internal IOverlayManager OverlayManager { get; private set; }
+
///
/// Control the memory configuration used by the emulation context.
///
@@ -262,7 +269,8 @@ namespace Ryujinx.HLE
UserChannelPersistence userChannelPersistence,
IRenderer gpuRenderer,
IHardwareDeviceDriver audioDeviceDriver,
- IHostUIHandler hostUIHandler
+ IHostUIHandler hostUIHandler,
+ IOverlayManager overlayManager
)
{
VirtualFileSystem = virtualFileSystem;
@@ -273,6 +281,7 @@ namespace Ryujinx.HLE
GpuRenderer = gpuRenderer;
AudioDeviceDriver = audioDeviceDriver;
HostUIHandler = hostUIHandler;
+ OverlayManager = overlayManager;
return this;
}
}
diff --git a/src/Ryujinx.HLE/Switch.cs b/src/Ryujinx.HLE/Switch.cs
index bdcbe82c7..071d4125d 100644
--- a/src/Ryujinx.HLE/Switch.cs
+++ b/src/Ryujinx.HLE/Switch.cs
@@ -71,7 +71,7 @@ namespace Ryujinx.HLE
DirtyHacks = new DirtyHacks(Configuration.Hacks);
AudioDeviceDriver = new CompatLayerHardwareDeviceDriver(Configuration.AudioDeviceDriver);
Memory = new MemoryBlock(Configuration.MemoryConfiguration.ToDramSize(), memoryAllocationFlags);
- Gpu = new GpuContext(Configuration.GpuRenderer, DirtyHacks);
+ Gpu = new GpuContext(Configuration.GpuRenderer, DirtyHacks, Configuration.OverlayManager);
System = new HOS.Horizon(this);
Statistics = new PerformanceStatistics(this);
Hid = new Hid(this, System.HidStorage);
diff --git a/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs b/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs
index f15d24e8a..ce1597fb4 100644
--- a/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs
+++ b/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs
@@ -17,6 +17,7 @@ using Ryujinx.Graphics.OpenGL;
using Ryujinx.Graphics.Vulkan;
using Ryujinx.HLE;
using Ryujinx.Input;
+using Ryujinx.UI.Overlay;
using Silk.NET.Vulkan;
using System;
using System.IO;
@@ -348,7 +349,8 @@ namespace Ryujinx.Headless
_userChannelPersistence,
renderer.TryMakeThreaded(options.BackendThreading),
new SDL2HardwareDeviceDriver(),
- window
+ window,
+ new OverlayManager()
)
);
}
diff --git a/src/Ryujinx/Systems/AppHost.cs b/src/Ryujinx/Systems/AppHost.cs
index 756771de5..3c9c6f6b3 100644
--- a/src/Ryujinx/Systems/AppHost.cs
+++ b/src/Ryujinx/Systems/AppHost.cs
@@ -33,7 +33,7 @@ using Ryujinx.Common.Utilities;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.GAL.Multithreading;
using Ryujinx.Graphics.Gpu;
-using Ryujinx.Graphics.Gpu.Overlay;
+using Ryujinx.UI.Overlay;
using Ryujinx.Graphics.OpenGL;
using Ryujinx.Graphics.Vulkan;
using Ryujinx.HLE.FileSystem;
@@ -931,20 +931,12 @@ namespace Ryujinx.Ava.Systems
_userChannelPersistence,
renderer.TryMakeThreaded(ConfigurationState.Instance.Graphics.BackendThreading),
InitializeAudio(),
- _viewModel.UiHandler
+ _viewModel.UiHandler,
+ new OverlayManager()
)
);
- // Initialize controller overlay with localization
- var localization = new ControllerOverlayLocalization
- {
- TitleText = LocaleManager.Instance[LocaleKeys.ControllerOverlayTitle],
- NoControllerText = LocaleManager.Instance[LocaleKeys.ControllerOverlayNoController],
- KeyboardText = LocaleManager.Instance[LocaleKeys.ControllerOverlayKeyboard],
- ControllerText = LocaleManager.Instance[LocaleKeys.ControllerOverlayController],
- UnknownText = LocaleManager.Instance[LocaleKeys.ControllerOverlayUnknown]
- };
- _controllerOverlay = new ControllerOverlay(localization);
+ _controllerOverlay = new ControllerOverlay();
Device.Gpu.Window.AddOverlay(_controllerOverlay);
}
diff --git a/src/Ryujinx.Graphics.Gpu/Overlay/ControllerOverlay.cs b/src/Ryujinx/UI/Overlay/ControllerOverlay.cs
similarity index 88%
rename from src/Ryujinx.Graphics.Gpu/Overlay/ControllerOverlay.cs
rename to src/Ryujinx/UI/Overlay/ControllerOverlay.cs
index 9cfbb869b..e8ea8a547 100644
--- a/src/Ryujinx.Graphics.Gpu/Overlay/ControllerOverlay.cs
+++ b/src/Ryujinx/UI/Overlay/ControllerOverlay.cs
@@ -5,21 +5,10 @@ using System.Linq;
using OriginalInputConfig = Ryujinx.Common.Configuration.Hid.InputConfig;
using OriginalPlayerIndex = Ryujinx.Common.Configuration.Hid.PlayerIndex;
using OriginalInputBackendType = Ryujinx.Common.Configuration.Hid.InputBackendType;
+using Ryujinx.Ava.Common.Locale;
-namespace Ryujinx.Graphics.Gpu.Overlay
+namespace Ryujinx.UI.Overlay
{
- ///
- /// Localization strings for the controller overlay
- ///
- public class ControllerOverlayLocalization
- {
- public string TitleText { get; set; } = "Controller Bindings";
- public string NoControllerText { get; set; } = "No controller assigned";
- public string KeyboardText { get; set; } = "Keyboard";
- public string ControllerText { get; set; } = "Controller";
- public string UnknownText { get; set; } = "Unknown";
- }
-
///
/// Controller overlay that shows controller bindings matching the original AXAML design
///
@@ -35,11 +24,9 @@ namespace Ryujinx.Graphics.Gpu.Overlay
private const float PlayerTextSize = 22;
private float _lifespan = 0f;
- private ControllerOverlayLocalization _localization;
- public ControllerOverlay(ControllerOverlayLocalization localization) : base("ControllerOverlay")
+ public ControllerOverlay() : base("ControllerOverlay")
{
- _localization = localization;
CreateBaseElements();
}
@@ -57,7 +44,7 @@ namespace Ryujinx.Graphics.Gpu.Overlay
AddElement(background);
// Title text (will be updated with localized text)
- var titleText = new TextElement(Padding + 30, Padding, _localization.TitleText, TitleTextSize, SKColors.White)
+ var titleText = new TextElement(Padding + 30, Padding, LocaleManager.Instance[LocaleKeys.ControllerOverlayTitle], TitleTextSize, SKColors.White)
{
Name = "TitleText",
FontStyle = SKFontStyle.Bold
@@ -74,7 +61,7 @@ namespace Ryujinx.Graphics.Gpu.Overlay
var titleElement = FindElement("TitleText");
if (titleElement != null)
{
- titleElement.Text = _localization.TitleText;
+ titleElement.Text = LocaleManager.Instance[LocaleKeys.ControllerOverlayTitle];
}
// Reset lifespan and opacity
@@ -144,7 +131,7 @@ namespace Ryujinx.Graphics.Gpu.Overlay
}
else
{
- var noControllerTextElement = new TextElement(Padding + 56, rowY + 2, _localization.NoControllerText, PlayerTextSize, new SKColor(128, 128, 128)) // Gray
+ var noControllerTextElement = new TextElement(Padding + 56, rowY + 2, LocaleManager.Instance[LocaleKeys.ControllerOverlayNoController], PlayerTextSize, new SKColor(128, 128, 128)) // Gray
{
Name = $"NoControllerText_{i}",
FontStyle = SKFontStyle.Italic
@@ -188,9 +175,9 @@ namespace Ryujinx.Graphics.Gpu.Overlay
{
return config.Backend switch
{
- OriginalInputBackendType.WindowKeyboard => _localization.KeyboardText,
- OriginalInputBackendType.GamepadSDL2 => _localization.ControllerText,
- _ => _localization.UnknownText
+ OriginalInputBackendType.WindowKeyboard => LocaleManager.Instance[LocaleKeys.ControllerOverlayKeyboard],
+ OriginalInputBackendType.GamepadSDL2 => LocaleManager.Instance[LocaleKeys.ControllerOverlayController],
+ _ => LocaleManager.Instance[LocaleKeys.ControllerOverlayUnknown]
};
}
diff --git a/src/Ryujinx.Graphics.Gpu/Overlay/ImageElement.cs b/src/Ryujinx/UI/Overlay/ImageElement.cs
similarity index 99%
rename from src/Ryujinx.Graphics.Gpu/Overlay/ImageElement.cs
rename to src/Ryujinx/UI/Overlay/ImageElement.cs
index 2f2fb0811..7745d5333 100644
--- a/src/Ryujinx.Graphics.Gpu/Overlay/ImageElement.cs
+++ b/src/Ryujinx/UI/Overlay/ImageElement.cs
@@ -2,7 +2,7 @@ using Ryujinx.Common.Logging;
using SkiaSharp;
using System;
-namespace Ryujinx.Graphics.Gpu.Overlay
+namespace Ryujinx.UI.Overlay
{
///
/// Image overlay element
diff --git a/src/Ryujinx.Graphics.Gpu/Overlay/Overlay.cs b/src/Ryujinx/UI/Overlay/Overlay.cs
similarity index 96%
rename from src/Ryujinx.Graphics.Gpu/Overlay/Overlay.cs
rename to src/Ryujinx/UI/Overlay/Overlay.cs
index a414888e1..34616f1bc 100644
--- a/src/Ryujinx.Graphics.Gpu/Overlay/Overlay.cs
+++ b/src/Ryujinx/UI/Overlay/Overlay.cs
@@ -2,13 +2,14 @@ using SkiaSharp;
using System;
using System.Collections.Generic;
using System.Linq;
+using Ryujinx.Graphics.Gpu;
-namespace Ryujinx.Graphics.Gpu.Overlay
+namespace Ryujinx.UI.Overlay
{
///
/// Base overlay class containing multiple elements
///
- public abstract class Overlay : IDisposable
+ public abstract class Overlay : IOverlay
{
private readonly List _elements = new();
diff --git a/src/Ryujinx.Graphics.Gpu/Overlay/OverlayElement.cs b/src/Ryujinx/UI/Overlay/OverlayElement.cs
similarity index 97%
rename from src/Ryujinx.Graphics.Gpu/Overlay/OverlayElement.cs
rename to src/Ryujinx/UI/Overlay/OverlayElement.cs
index c4c528d65..2c5bf66fa 100644
--- a/src/Ryujinx.Graphics.Gpu/Overlay/OverlayElement.cs
+++ b/src/Ryujinx/UI/Overlay/OverlayElement.cs
@@ -1,7 +1,7 @@
using SkiaSharp;
using System;
-namespace Ryujinx.Graphics.Gpu.Overlay
+namespace Ryujinx.UI.Overlay
{
///
/// Base class for all overlay elements
diff --git a/src/Ryujinx.Graphics.Gpu/Overlay/OverlayManager.cs b/src/Ryujinx/UI/Overlay/OverlayManager.cs
similarity index 92%
rename from src/Ryujinx.Graphics.Gpu/Overlay/OverlayManager.cs
rename to src/Ryujinx/UI/Overlay/OverlayManager.cs
index fb0a4906f..d54098ef4 100644
--- a/src/Ryujinx.Graphics.Gpu/Overlay/OverlayManager.cs
+++ b/src/Ryujinx/UI/Overlay/OverlayManager.cs
@@ -3,21 +3,22 @@ using System;
using System.Collections.Generic;
using System.Linq;
using Ryujinx.Graphics.Gpu.Image;
+using Ryujinx.Graphics.Gpu;
-namespace Ryujinx.Graphics.Gpu.Overlay
+namespace Ryujinx.UI.Overlay
{
///
/// Manages multiple overlays and handles rendering
///
- public class OverlayManager : IDisposable
+ public class OverlayManager : IOverlayManager
{
- private readonly List _overlays = new();
+ private readonly List _overlays = new();
private readonly object _lock = new();
///
/// Add an overlay to the manager
///
- public void AddOverlay(Overlay overlay)
+ public void AddOverlay(IOverlay overlay)
{
lock (_lock)
{
@@ -56,7 +57,7 @@ namespace Ryujinx.Graphics.Gpu.Overlay
///
/// Find overlay by name
///
- public Overlay FindOverlay(string name)
+ public IOverlay FindOverlay(string name)
{
lock (_lock)
{
@@ -67,7 +68,7 @@ namespace Ryujinx.Graphics.Gpu.Overlay
///
/// Get all overlays
///
- public IReadOnlyList GetOverlays()
+ public IReadOnlyList GetOverlays()
{
lock (_lock)
{
diff --git a/src/Ryujinx.Graphics.Gpu/Overlay/RectangleElement.cs b/src/Ryujinx/UI/Overlay/RectangleElement.cs
similarity index 98%
rename from src/Ryujinx.Graphics.Gpu/Overlay/RectangleElement.cs
rename to src/Ryujinx/UI/Overlay/RectangleElement.cs
index b310ef2fc..a0ce52845 100644
--- a/src/Ryujinx.Graphics.Gpu/Overlay/RectangleElement.cs
+++ b/src/Ryujinx/UI/Overlay/RectangleElement.cs
@@ -1,6 +1,6 @@
using SkiaSharp;
-namespace Ryujinx.Graphics.Gpu.Overlay
+namespace Ryujinx.UI.Overlay
{
///
/// Rectangle overlay element
diff --git a/src/Ryujinx.Graphics.Gpu/Overlay/TextElement.cs b/src/Ryujinx/UI/Overlay/TextElement.cs
similarity index 99%
rename from src/Ryujinx.Graphics.Gpu/Overlay/TextElement.cs
rename to src/Ryujinx/UI/Overlay/TextElement.cs
index a1788fde6..b4c412fda 100644
--- a/src/Ryujinx.Graphics.Gpu/Overlay/TextElement.cs
+++ b/src/Ryujinx/UI/Overlay/TextElement.cs
@@ -1,6 +1,6 @@
using SkiaSharp;
-namespace Ryujinx.Graphics.Gpu.Overlay
+namespace Ryujinx.UI.Overlay
{
///
/// Text overlay element