Files
Ryujinx/src/Ryujinx/UI/Renderer/RendererHost.axaml.cs
Otozinclus 2bf48f57d2 Add more games to metal list (#447)
Mario Kart 8 Deluxe and Deltarune got tested by Isaac with help from
Peri previosly (His video: https://www.youtube.com/watch?v=GEVre_0ZVUg
)

Captain Toad, Cuphead and Animal Crossing I tested myself (side-by-side
Video comparison: https://youtu.be/auNS9MmZMPI )

Additional information:

Cuphead has flickering issues with certain UI elements on Vulkan via
MoltenVK. Metal fixes those and introduces no new issues, according to
my testing.

Animal Crossing is accurate, except for it having broken backgrounds in
interiors, causing them to appear as white instead of black. This is
caused by a hardware level sampler bug, that isaac never got to find a
workaround for.
However, this issue happens with Vulkan via MoltenVK as well, both Metal
and Vulkan have this issue, therefore Metal shouldn't have any downside
compared to using Vulkan in this game.
2024-12-25 14:19:53 -06:00

133 lines
4.5 KiB
C#

using Avalonia;
using Avalonia.Controls;
using Gommon;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.UI.Common.Configuration;
using System;
using System.Runtime.InteropServices;
namespace Ryujinx.Ava.UI.Renderer
{
public partial class RendererHost : UserControl, IDisposable
{
public readonly EmbeddedWindow EmbeddedWindow;
public event EventHandler<EventArgs> WindowCreated;
public event Action<object, Size> BoundsChanged;
public RendererHost()
{
InitializeComponent();
EmbeddedWindow = ConfigurationState.Instance.Graphics.GraphicsBackend.Value switch
{
GraphicsBackend.OpenGl => new EmbeddedWindowOpenGL(),
GraphicsBackend.Metal => new EmbeddedWindowMetal(),
GraphicsBackend.Vulkan or GraphicsBackend.Auto => new EmbeddedWindowVulkan(),
_ => throw new NotSupportedException()
};
Initialize();
}
public static readonly string[] KnownGreatMetalTitles =
[
"01006f8002326000", // Animal Crossings: New Horizons
"01009bf0072d4000", // Captain Toad: Treasure Tracker
"0100a5c00d162000", // Cuphead
"010023800d64a000", // Deltarune
"010028600EBDA000", // Mario 3D World
"0100152000022000", // Mario Kart 8 Deluxe
"01005CA01580E000", // Persona 5
"01008C0016544000", // Sea of Stars
"01006A800016E000", // Smash Ultimate
"0100000000010000", // Super Mario Odyessy
];
public GraphicsBackend Backend =>
EmbeddedWindow switch
{
EmbeddedWindowVulkan => GraphicsBackend.Vulkan,
EmbeddedWindowOpenGL => GraphicsBackend.OpenGl,
EmbeddedWindowMetal => GraphicsBackend.Metal,
_ => throw new NotImplementedException()
};
public RendererHost(string titleId)
{
InitializeComponent();
switch (ConfigurationState.Instance.Graphics.GraphicsBackend.Value)
{
case GraphicsBackend.Auto:
EmbeddedWindow =
OperatingSystem.IsMacOS() &&
RuntimeInformation.ProcessArchitecture == Architecture.Arm64 &&
KnownGreatMetalTitles.ContainsIgnoreCase(titleId)
? new EmbeddedWindowMetal()
: new EmbeddedWindowVulkan();
break;
case GraphicsBackend.OpenGl:
EmbeddedWindow = new EmbeddedWindowOpenGL();
break;
case GraphicsBackend.Metal:
EmbeddedWindow = new EmbeddedWindowMetal();
break;
case GraphicsBackend.Vulkan:
EmbeddedWindow = new EmbeddedWindowVulkan();
break;
}
string backendText = EmbeddedWindow switch
{
EmbeddedWindowVulkan => "Vulkan",
EmbeddedWindowOpenGL => "OpenGL",
EmbeddedWindowMetal => "Metal",
_ => throw new NotImplementedException()
};
Logger.Info?.PrintMsg(LogClass.Gpu, $"Backend ({ConfigurationState.Instance.Graphics.GraphicsBackend.Value}): {backendText}");
Initialize();
}
private void Initialize()
{
EmbeddedWindow.WindowCreated += CurrentWindow_WindowCreated;
EmbeddedWindow.BoundsChanged += CurrentWindow_BoundsChanged;
Content = EmbeddedWindow;
}
public void Dispose()
{
if (EmbeddedWindow != null)
{
EmbeddedWindow.WindowCreated -= CurrentWindow_WindowCreated;
EmbeddedWindow.BoundsChanged -= CurrentWindow_BoundsChanged;
}
GC.SuppressFinalize(this);
}
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnDetachedFromVisualTree(e);
Dispose();
}
private void CurrentWindow_BoundsChanged(object sender, Size e)
{
BoundsChanged?.Invoke(sender, e);
}
private void CurrentWindow_WindowCreated(object sender, nint e)
{
WindowCreated?.Invoke(this, EventArgs.Empty);
}
}
}