Compare commits

..

1 Commits

Author SHA1 Message Date
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
5 changed files with 10 additions and 332 deletions

View File

@@ -11,7 +11,6 @@ namespace Ryujinx.Input.SDL2
private readonly Dictionary<int, string> _gamepadsInstanceIdsMapping;
private readonly List<string> _gamepadsIds;
private readonly Lock _lock = new();
private readonly SDL2JoyConPair joyConPair;
public ReadOnlySpan<string> GamepadsIds
{
@@ -37,7 +36,7 @@ namespace Ryujinx.Input.SDL2
SDL2Driver.Instance.Initialize();
SDL2Driver.Instance.OnJoyStickConnected += HandleJoyStickConnected;
SDL2Driver.Instance.OnJoystickDisconnected += HandleJoyStickDisconnected;
joyConPair = new SDL2JoyConPair();
// Add already connected gamepads
int numJoysticks = SDL_NumJoysticks();
@@ -90,10 +89,6 @@ namespace Ryujinx.Input.SDL2
lock (_lock)
{
_gamepadsIds.Remove(id);
if (joyConPair.GetGamepad(_gamepadsIds) == null)
{
_gamepadsIds.Remove(joyConPair.Id);
}
}
OnGamepadDisconnected?.Invoke(id);
@@ -125,11 +120,6 @@ namespace Ryujinx.Input.SDL2
_gamepadsIds.Insert(joystickDeviceId, id);
else
_gamepadsIds.Add(id);
if (joyConPair.GetGamepad(_gamepadsIds) != null)
{
_gamepadsIds.Remove(joyConPair.Id);
_gamepadsIds.Add(joyConPair.Id);
}
}
OnGamepadConnected?.Invoke(id);
@@ -167,14 +157,6 @@ namespace Ryujinx.Input.SDL2
public IGamepad GetGamepad(string id)
{
if (id == joyConPair.Id)
{
lock (_lock)
{
return joyConPair.GetGamepad(_gamepadsIds);
}
}
int joystickIndex = GetJoystickIndexByGamepadId(id);
if (joystickIndex == -1)
@@ -189,7 +171,6 @@ namespace Ryujinx.Input.SDL2
return null;
}
Console.WriteLine("Game controller opened" + SDL_GameControllerName(gamepadHandle));
return new SDL2Gamepad(gamepadHandle, id);
}
}

View File

@@ -1,281 +0,0 @@
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Controller;
using Ryujinx.Common.Logging;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Threading;
using static SDL2.SDL;
using Timer = System.Timers.Timer;
namespace Ryujinx.Input.SDL2
{
internal class SDL2JoyConPair : IGamepad
{
private IGamepad _left;
private IGamepad _right;
private Timer timer;
private StandardControllerInputConfig _configuration;
private readonly StickInputId[] _stickUserMapping =
[
StickInputId.Unbound,
StickInputId.Left,
StickInputId.Right
];
private readonly record struct ButtonMappingEntry(GamepadButtonInputId To, GamepadButtonInputId From)
{
public bool IsValid => To is not GamepadButtonInputId.Unbound && From is not GamepadButtonInputId.Unbound;
}
private readonly List<ButtonMappingEntry> _buttonsUserMapping = new(20);
private readonly Lock _userMappingLock = new();
public GamepadFeaturesFlag Features => (_left?.Features ?? GamepadFeaturesFlag.None) |
(_right?.Features ?? GamepadFeaturesFlag.None);
public string Id => "JoyConPair";
public string Name => "Nintendo Switch Joy-Con (L/R)";
private const string LeftName = "Nintendo Switch Joy-Con (L)";
private const string RightName = "Nintendo Switch Joy-Con (R)";
public bool IsConnected => _left is { IsConnected: true } && _right is { IsConnected: true };
public void Dispose()
{
_left?.Dispose();
_right?.Dispose();
}
public GamepadStateSnapshot GetMappedStateSnapshot()
{
GamepadStateSnapshot rawState = GetStateSnapshot();
GamepadStateSnapshot result = default;
lock (_userMappingLock)
{
if (_buttonsUserMapping.Count == 0)
return rawState;
// ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator
foreach (ButtonMappingEntry entry in _buttonsUserMapping)
{
if (!entry.IsValid)
continue;
// Do not touch state of button already pressed
if (!result.IsPressed(entry.To))
{
result.SetPressed(entry.To, rawState.IsPressed(entry.From));
}
}
(float leftStickX, float leftStickY) = rawState.GetStick(_stickUserMapping[(int)StickInputId.Left]);
(float rightStickX, float rightStickY) = rawState.GetStick(_stickUserMapping[(int)StickInputId.Right]);
result.SetStick(StickInputId.Left, leftStickX, leftStickY);
result.SetStick(StickInputId.Right, rightStickX, rightStickY);
}
return result;
}
public Vector3 GetMotionData(MotionInputId inputId)
{
return inputId switch
{
MotionInputId.SecondAccelerometer => _right.GetMotionData(MotionInputId.Accelerometer),
MotionInputId.SecondGyroscope => _right.GetMotionData(MotionInputId.Gyroscope),
_ => _left.GetMotionData(inputId)
};
}
public GamepadStateSnapshot GetStateSnapshot()
{
return IGamepad.GetStateSnapshot(this);
}
public (float, float) GetStick(StickInputId inputId)
{
switch (inputId)
{
case StickInputId.Left:
{
(float x, float y) = _left.GetStick(StickInputId.Left);
return (y, -x);
}
case StickInputId.Right:
{
(float x, float y) = _right.GetStick(StickInputId.Left);
return (-y, x);
}
case StickInputId.Unbound:
case StickInputId.Count:
default:
return (0, 0);
}
}
public bool IsPressed(GamepadButtonInputId inputId)
{
return inputId switch
{
GamepadButtonInputId.LeftStick => _left.IsPressed(GamepadButtonInputId.LeftStick),
GamepadButtonInputId.DpadUp => _left.IsPressed(GamepadButtonInputId.Y),
GamepadButtonInputId.DpadDown => _left.IsPressed(GamepadButtonInputId.A),
GamepadButtonInputId.DpadLeft => _left.IsPressed(GamepadButtonInputId.B),
GamepadButtonInputId.DpadRight => _left.IsPressed(GamepadButtonInputId.X),
GamepadButtonInputId.Minus => _left.IsPressed(GamepadButtonInputId.Start),
GamepadButtonInputId.LeftShoulder => _left.IsPressed(GamepadButtonInputId.Paddle2),
GamepadButtonInputId.LeftTrigger => _left.IsPressed(GamepadButtonInputId.Paddle4),
GamepadButtonInputId.SingleRightTrigger0 => _left.IsPressed(GamepadButtonInputId.LeftShoulder),
GamepadButtonInputId.SingleLeftTrigger0 => _left.IsPressed(GamepadButtonInputId.RightShoulder),
GamepadButtonInputId.RightStick => _right.IsPressed(GamepadButtonInputId.LeftStick),
GamepadButtonInputId.A => _right.IsPressed(GamepadButtonInputId.B),
GamepadButtonInputId.B => _right.IsPressed(GamepadButtonInputId.Y),
GamepadButtonInputId.X => _right.IsPressed(GamepadButtonInputId.A),
GamepadButtonInputId.Y => _right.IsPressed(GamepadButtonInputId.X),
GamepadButtonInputId.Plus => _right.IsPressed(GamepadButtonInputId.Start),
GamepadButtonInputId.RightShoulder => _right.IsPressed(GamepadButtonInputId.Paddle1),
GamepadButtonInputId.RightTrigger => _right.IsPressed(GamepadButtonInputId.Paddle3),
GamepadButtonInputId.SingleRightTrigger1 => _right.IsPressed(GamepadButtonInputId.LeftShoulder),
GamepadButtonInputId.SingleLeftTrigger1 => _right.IsPressed(GamepadButtonInputId.RightShoulder),
_ => false
};
}
public void Rumble(float lowFrequency, float highFrequency, uint durationMs)
{
if (lowFrequency != 0)
{
_right.Rumble(lowFrequency, lowFrequency, durationMs);
}
if (highFrequency != 0)
{
_left.Rumble(highFrequency, highFrequency, durationMs);
}
if (lowFrequency == 0 && highFrequency == 0)
{
_left.Rumble(0, 0, durationMs);
_right.Rumble(0, 0, durationMs);
}
}
public void SetConfiguration(InputConfig configuration)
{
lock (_userMappingLock)
{
_configuration = (StandardControllerInputConfig)configuration;
_left.SetConfiguration(configuration);
_right.SetConfiguration(configuration);
_buttonsUserMapping.Clear();
// First update sticks
_stickUserMapping[(int)StickInputId.Left] = (StickInputId)_configuration.LeftJoyconStick.Joystick;
_stickUserMapping[(int)StickInputId.Right] = (StickInputId)_configuration.RightJoyconStick.Joystick;
// Then left joycon
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftStick,
(GamepadButtonInputId)_configuration.LeftJoyconStick.StickButton));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadUp,
(GamepadButtonInputId)_configuration.LeftJoycon.DpadUp));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadDown,
(GamepadButtonInputId)_configuration.LeftJoycon.DpadDown));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadLeft,
(GamepadButtonInputId)_configuration.LeftJoycon.DpadLeft));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadRight,
(GamepadButtonInputId)_configuration.LeftJoycon.DpadRight));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Minus,
(GamepadButtonInputId)_configuration.LeftJoycon.ButtonMinus));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftShoulder,
(GamepadButtonInputId)_configuration.LeftJoycon.ButtonL));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftTrigger,
(GamepadButtonInputId)_configuration.LeftJoycon.ButtonZl));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger0,
(GamepadButtonInputId)_configuration.LeftJoycon.ButtonSr));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger0,
(GamepadButtonInputId)_configuration.LeftJoycon.ButtonSl));
// Finally right joycon
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightStick,
(GamepadButtonInputId)_configuration.RightJoyconStick.StickButton));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.A,
(GamepadButtonInputId)_configuration.RightJoycon.ButtonA));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.B,
(GamepadButtonInputId)_configuration.RightJoycon.ButtonB));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.X,
(GamepadButtonInputId)_configuration.RightJoycon.ButtonX));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Y,
(GamepadButtonInputId)_configuration.RightJoycon.ButtonY));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Plus,
(GamepadButtonInputId)_configuration.RightJoycon.ButtonPlus));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightShoulder,
(GamepadButtonInputId)_configuration.RightJoycon.ButtonR));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightTrigger,
(GamepadButtonInputId)_configuration.RightJoycon.ButtonZr));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger1,
(GamepadButtonInputId)_configuration.RightJoycon.ButtonSr));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger1,
(GamepadButtonInputId)_configuration.RightJoycon.ButtonSl));
SetTriggerThreshold(_configuration.TriggerThreshold);
}
}
public void SetTriggerThreshold(float triggerThreshold)
{
_left.SetTriggerThreshold(triggerThreshold);
_right.SetTriggerThreshold(triggerThreshold);
}
public IGamepad GetGamepad(List<string> gamepadsIds)
{
this.Dispose();
var gamepadNames = gamepadsIds.Where(gamepadId => gamepadId != Id)
.Select((_, index) => SDL_GameControllerNameForIndex(index)).ToList();
int leftIndex = gamepadNames.IndexOf(LeftName);
int rightIndex = gamepadNames.IndexOf(RightName);
if (leftIndex == -1 || rightIndex == -1)
{
return null;
}
nint leftGamepadHandle = SDL_GameControllerOpen(leftIndex);
nint rightGamepadHandle = SDL_GameControllerOpen(rightIndex);
if (leftGamepadHandle == nint.Zero || rightGamepadHandle == nint.Zero)
{
return null;
}
_left = new SDL2Gamepad(leftGamepadHandle, gamepadsIds[leftIndex]);
_right = new SDL2Gamepad(rightGamepadHandle, gamepadsIds[rightIndex]);
ShowPowerLevel(leftGamepadHandle, rightGamepadHandle);
return this;
}
private void ShowPowerLevel(nint leftGamepadHandle, nint rightGamepadHandle)
{
timer?.Stop();
timer = new Timer(2000);
timer.Elapsed += (_, _) =>
{
timer.Stop();
var leftLevel = SDL_JoystickCurrentPowerLevel(SDL_GameControllerGetJoystick(leftGamepadHandle));
var rightLevel = SDL_JoystickCurrentPowerLevel(SDL_GameControllerGetJoystick(rightGamepadHandle));
Logger.Info?.Print(LogClass.Hid, $"Left power level: {leftLevel}, Right power level: {rightLevel}");
};
timer.AutoReset = false;
timer.Start();
}
}
}

View File

@@ -266,7 +266,6 @@ namespace Ryujinx.Input.HLE
if (motionConfig.MotionBackend != MotionInputBackendType.CemuHook)
{
_leftMotionInput = new MotionInput();
_rightMotionInput = new MotionInput();
}
else
{
@@ -299,20 +298,7 @@ namespace Ryujinx.Input.HLE
if (controllerConfig.ControllerType == ConfigControllerType.JoyconPair)
{
if (gamepad.Id== "JoyConPair")
{
Vector3 rightAccelerometer = gamepad.GetMotionData(MotionInputId.SecondAccelerometer);
Vector3 rightGyroscope = gamepad.GetMotionData(MotionInputId.SecondGyroscope);
rightAccelerometer = new Vector3(rightAccelerometer.X, -rightAccelerometer.Z, rightAccelerometer.Y);
rightGyroscope = new Vector3(rightGyroscope.X, -rightGyroscope.Z, rightGyroscope.Y);
_rightMotionInput.Update(rightAccelerometer, rightGyroscope, (ulong)PerformanceCounter.ElapsedNanoseconds / 1000, controllerConfig.Motion.Sensitivity, (float)controllerConfig.Motion.GyroDeadzone);
}
else
{
_rightMotionInput = _leftMotionInput;
}
_rightMotionInput = _leftMotionInput;
}
}
}
@@ -347,7 +333,6 @@ namespace Ryujinx.Input.HLE
// Reset states
State = default;
_leftMotionInput = null;
_rightMotionInput = null;
}
}

View File

@@ -21,17 +21,5 @@ namespace Ryujinx.Input
/// </summary>
/// <remarks>Values are in degrees</remarks>
Gyroscope,
/// <summary>
/// Second accelerometer.
/// </summary>
/// <remarks>Values are in m/s^2</remarks>
SecondAccelerometer,
/// <summary>
/// Second gyroscope.
/// </summary>
/// <remarks>Values are in degrees</remarks>
SecondGyroscope
}
}

View File

@@ -33,11 +33,16 @@ namespace Ryujinx.Ava.UI.Renderer
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
"01008C0016544000", // Sea of Stars
"01005CA01580E000", // Persona 5
"010028600EBDA000", // Mario 3D World
];
public GraphicsBackend Backend =>