diff --git a/Directory.Packages.props b/Directory.Packages.props
index 07b9bcdff..dee75986c 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -38,7 +38,7 @@
-
+
diff --git a/Ryujinx.slnx b/Ryujinx.slnx
new file mode 100644
index 000000000..a8fc8f3ab
--- /dev/null
+++ b/Ryujinx.slnx
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Ryujinx.sln.DotSettings b/Ryujinx.slnx.DotSettings
similarity index 100%
rename from Ryujinx.sln.DotSettings
rename to Ryujinx.slnx.DotSettings
diff --git a/docs/README.md b/docs/README.md
index 82ebb8d2c..b866d76cf 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -8,7 +8,7 @@ Intro to Kenji-NX
Kenji-NX is an open-source Nintendo Switch emulator written in C#. It is based on Ryujinx, which was originally created by gdkchan.
* The CPU emulator, ARMeilleure, emulates an ARMv8 CPU and currently has support for most 64-bit ARMv8 and some of the ARMv7 (and older) instructions.
* The GPU emulator emulates the Switch's Maxwell GPU using either the OpenGL (version 4.5 minimum), Vulkan, or Metal (via MoltenVK) APIs through a custom build of OpenTK or Silk.NET respectively.
-* Audio output is entirely supported via C# wrappers for SDL2, with OpenAL & libsoundio as fallbacks.
+* Audio output is entirely supported via C# wrappers for SDL3, with OpenAL & libsoundio as fallbacks.
Getting Started
===============
diff --git a/src/LibKenjinx/LibKenjinx.Input.cs b/src/LibKenjinx/LibKenjinx.Input.cs
index 267e14aa7..ba77de4b2 100644
--- a/src/LibKenjinx/LibKenjinx.Input.cs
+++ b/src/LibKenjinx/LibKenjinx.Input.cs
@@ -113,7 +113,7 @@ namespace LibKenjinx
return new StandardControllerInputConfig
{
Version = InputConfig.CurrentVersion,
- Backend = InputBackendType.GamepadSDL2,
+ Backend = InputBackendType.GamepadSDL3,
Id = null,
ControllerType = ControllerType.ProController,
DeadzoneLeft = 0.1f,
diff --git a/src/LibKenjinx/LibKenjinx.cs b/src/LibKenjinx/LibKenjinx.cs
index 1f08154e8..590d654ab 100644
--- a/src/LibKenjinx/LibKenjinx.cs
+++ b/src/LibKenjinx/LibKenjinx.cs
@@ -12,7 +12,7 @@ using LibHac.Tools.FsSystem.NcaUtils;
using LibKenjinx.Android;
using OpenTK.Audio.OpenAL;
using Ryujinx.Audio.Backends.Dummy;
-using Ryujinx.Audio.Backends.SDL2;
+using Ryujinx.Audio.Backends.SDL3;
using Ryujinx.Audio.Integration;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
@@ -96,7 +96,7 @@ namespace LibKenjinx
public static void InitializeAudio()
{
- AudioDriver = new SDL2HardwareDeviceDriver();
+ AudioDriver = new SDL3HardwareDeviceDriver();
}
public static GameStats GetGameStats()
diff --git a/src/LibKenjinx/LibKenjinx.csproj b/src/LibKenjinx/LibKenjinx.csproj
index 006625cb4..42149e4c0 100644
--- a/src/LibKenjinx/LibKenjinx.csproj
+++ b/src/LibKenjinx/LibKenjinx.csproj
@@ -27,7 +27,7 @@
-
+
diff --git a/src/Ryujinx.Audio.Backends.SDL2/Ryujinx.Audio.Backends.SDL2.csproj b/src/Ryujinx.Audio.Backends.SDL3/Ryujinx.Audio.Backends.SDL3.csproj
similarity index 78%
rename from src/Ryujinx.Audio.Backends.SDL2/Ryujinx.Audio.Backends.SDL2.csproj
rename to src/Ryujinx.Audio.Backends.SDL3/Ryujinx.Audio.Backends.SDL3.csproj
index d0d45122e..094a81594 100644
--- a/src/Ryujinx.Audio.Backends.SDL2/Ryujinx.Audio.Backends.SDL2.csproj
+++ b/src/Ryujinx.Audio.Backends.SDL3/Ryujinx.Audio.Backends.SDL3.csproj
@@ -7,7 +7,7 @@
-
+
diff --git a/src/Ryujinx.Audio.Backends.SDL2/SDL2AudioBuffer.cs b/src/Ryujinx.Audio.Backends.SDL3/SDL3AudioBuffer.cs
similarity index 69%
rename from src/Ryujinx.Audio.Backends.SDL2/SDL2AudioBuffer.cs
rename to src/Ryujinx.Audio.Backends.SDL3/SDL3AudioBuffer.cs
index a390c5467..55a4a60e1 100644
--- a/src/Ryujinx.Audio.Backends.SDL2/SDL2AudioBuffer.cs
+++ b/src/Ryujinx.Audio.Backends.SDL3/SDL3AudioBuffer.cs
@@ -1,12 +1,12 @@
-namespace Ryujinx.Audio.Backends.SDL2
+namespace Ryujinx.Audio.Backends.SDL3
{
- class SDL2AudioBuffer
+ class SDL3AudioBuffer
{
public readonly ulong DriverIdentifier;
public readonly ulong SampleCount;
public ulong SamplePlayed;
- public SDL2AudioBuffer(ulong driverIdentifier, ulong sampleCount)
+ public SDL3AudioBuffer(ulong driverIdentifier, ulong sampleCount)
{
DriverIdentifier = driverIdentifier;
SampleCount = sampleCount;
diff --git a/src/Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceDriver.cs b/src/Ryujinx.Audio.Backends.SDL3/SDL3HardwareDeviceDriver.cs
similarity index 58%
rename from src/Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceDriver.cs
rename to src/Ryujinx.Audio.Backends.SDL3/SDL3HardwareDeviceDriver.cs
index 35ff79f16..598de8835 100644
--- a/src/Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceDriver.cs
+++ b/src/Ryujinx.Audio.Backends.SDL3/SDL3HardwareDeviceDriver.cs
@@ -2,44 +2,41 @@ using Ryujinx.Audio.Common;
using Ryujinx.Audio.Integration;
using Ryujinx.Common.Logging;
using Ryujinx.Memory;
-using Ryujinx.SDL2.Common;
+using Ryujinx.SDL3.Common;
using System;
using System.Collections.Concurrent;
-using System.Runtime.InteropServices;
using System.Threading;
using static Ryujinx.Audio.Integration.IHardwareDeviceDriver;
-using static SDL2.SDL;
+using SDL;
+using static SDL.SDL3;
+using System.Runtime.InteropServices;
-namespace Ryujinx.Audio.Backends.SDL2
+
+namespace Ryujinx.Audio.Backends.SDL3
{
- public sealed class SDL2HardwareDeviceDriver : IHardwareDeviceDriver
+
+ using unsafe SDL_AudioStreamCallbackPointer = delegate* unmanaged[Cdecl];
+
+ public sealed class SDL3HardwareDeviceDriver : IHardwareDeviceDriver
{
private readonly ManualResetEvent _updateRequiredEvent;
private readonly ManualResetEvent _pauseEvent;
- private readonly ConcurrentDictionary _sessions;
+ private readonly ConcurrentDictionary _sessions;
private readonly bool _supportSurroundConfiguration;
public float Volume { get; set; }
- // TODO: Add this to SDL2-CS
- // NOTE: We use a DllImport here because of marshaling issue for spec.
-#pragma warning disable SYSLIB1054
- [DllImport("SDL2")]
- private static extern int SDL_GetDefaultAudioInfo(nint name, out SDL_AudioSpec spec, int isCapture);
-#pragma warning restore SYSLIB1054
-
- public SDL2HardwareDeviceDriver()
+ public unsafe SDL3HardwareDeviceDriver()
{
_updateRequiredEvent = new ManualResetEvent(false);
_pauseEvent = new ManualResetEvent(true);
- _sessions = new ConcurrentDictionary();
+ _sessions = new ConcurrentDictionary();
- SDL2Driver.Instance.Initialize();
+ SDL3Driver.Instance.Initialize();
- int res = SDL_GetDefaultAudioInfo(nint.Zero, out var spec, 0);
-
- if (res != 0)
+ SDL_AudioSpec spec;
+ if (!SDL_GetAudioDeviceFormat(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, null))
{
Logger.Error?.Print(LogClass.Application,
$"SDL_GetDefaultAudioInfo failed with error \"{SDL_GetError()}\"");
@@ -56,16 +53,16 @@ namespace Ryujinx.Audio.Backends.SDL2
public static bool IsSupported => IsSupportedInternal();
- private static bool IsSupportedInternal()
+ private unsafe static bool IsSupportedInternal()
{
- uint device = OpenStream(SampleFormat.PcmInt16, Constants.TargetSampleRate, Constants.ChannelCountMax, Constants.TargetSampleCount, null);
+ SDL_AudioStream* device = OpenStream(SampleFormat.PcmInt16, Constants.TargetSampleRate, Constants.ChannelCountMax, Constants.TargetSampleCount, null);
- if (device != 0)
+ if (device != null)
{
- SDL_CloseAudioDevice(device);
+ SDL_DestroyAudioStream(device);
}
- return device != 0;
+ return device != null;
}
public ManualResetEvent GetUpdateRequiredEvent()
@@ -92,67 +89,68 @@ namespace Ryujinx.Audio.Backends.SDL2
if (direction != Direction.Output)
{
- throw new NotImplementedException("Input direction is currently not implemented on SDL2 backend!");
+ throw new NotImplementedException("Input direction is currently not implemented on SDL3 backend!");
}
- SDL2HardwareDeviceSession session = new(this, memoryManager, sampleFormat, sampleRate, channelCount);
+ SDL3HardwareDeviceSession session = new(this, memoryManager, sampleFormat, sampleRate, channelCount);
_sessions.TryAdd(session, 0);
return session;
}
- internal bool Unregister(SDL2HardwareDeviceSession session)
+ internal bool Unregister(SDL3HardwareDeviceSession session)
{
return _sessions.TryRemove(session, out _);
}
- private static SDL_AudioSpec GetSDL2Spec(SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, uint sampleCount)
+ private static SDL_AudioSpec GetSDL3Spec(SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount)
{
return new SDL_AudioSpec
{
channels = (byte)requestedChannelCount,
- format = GetSDL2Format(requestedSampleFormat),
+ format = GetSDL3Format(requestedSampleFormat),
freq = (int)requestedSampleRate,
- samples = (ushort)sampleCount,
};
}
- internal static ushort GetSDL2Format(SampleFormat format)
+ internal static SDL_AudioFormat GetSDL3Format(SampleFormat format)
{
return format switch
{
- SampleFormat.PcmInt8 => AUDIO_S8,
- SampleFormat.PcmInt16 => AUDIO_S16,
- SampleFormat.PcmInt32 => AUDIO_S32,
- SampleFormat.PcmFloat => AUDIO_F32,
+ SampleFormat.PcmInt8 => SDL_AudioFormat.SDL_AUDIO_S8,
+ SampleFormat.PcmInt16 => SDL_AudioFormat.SDL_AUDIO_S16LE,
+ SampleFormat.PcmInt32 => SDL_AudioFormat.SDL_AUDIO_S32LE,
+ SampleFormat.PcmFloat => SDL_AudioFormat.SDL_AUDIO_F32LE,
_ => throw new ArgumentException($"Unsupported sample format {format}"),
};
}
- internal static uint OpenStream(SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, uint sampleCount, SDL_AudioCallback callback)
+ internal unsafe static SDL_AudioStream* OpenStream(SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, uint sampleCount, SDL3HardwareDeviceSession.SDL_AudioStreamCallback callback)
{
- SDL_AudioSpec desired = GetSDL2Spec(requestedSampleFormat, requestedSampleRate, requestedChannelCount, sampleCount);
+ SDL_AudioSpec desired = GetSDL3Spec(requestedSampleFormat, requestedSampleRate, requestedChannelCount);
+ SDL_AudioSpec got = desired;
+ var pCallback = callback != null ? (SDL_AudioStreamCallbackPointer)Marshal.GetFunctionPointerForDelegate(callback) : null;
- desired.callback = callback;
+ // From SDL 3 and on, SDL requires us to set this as a hint
+ SDL_SetHint(SDL_HINT_AUDIO_DEVICE_SAMPLE_FRAMES, $"{sampleCount}");
+ SDL_AudioStream* device = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &got, pCallback, 0);
- uint device = SDL_OpenAudioDevice(nint.Zero, 0, ref desired, out SDL_AudioSpec got, 0);
-
- if (device == 0)
+ if (device == null)
{
- Logger.Error?.Print(LogClass.Application, $"SDL2 open audio device initialization failed with error \"{SDL_GetError()}\"");
+ Logger.Error?.Print(LogClass.Application, $"SDL3 open audio device initialization failed with error \"{SDL_GetError()}\"");
- return 0;
+ return null;
}
bool isValid = got.format == desired.format && got.freq == desired.freq && got.channels == desired.channels;
if (!isValid)
{
- Logger.Error?.Print(LogClass.Application, "SDL2 open audio device is not valid");
- SDL_CloseAudioDevice(device);
+ Logger.Error?.Print(LogClass.Application, "SDL3 open audio device is not valid");
+ SDL_DestroyAudioStream(device);
- return 0;
+ return null;
}
return device;
@@ -168,12 +166,12 @@ namespace Ryujinx.Audio.Backends.SDL2
{
if (disposing)
{
- foreach (SDL2HardwareDeviceSession session in _sessions.Keys)
+ foreach (SDL3HardwareDeviceSession session in _sessions.Keys)
{
session.Dispose();
}
- SDL2Driver.Instance.Dispose();
+ SDL3Driver.Instance.Dispose();
_pauseEvent.Dispose();
}
diff --git a/src/Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceSession.cs b/src/Ryujinx.Audio.Backends.SDL3/SDL3HardwareDeviceSession.cs
similarity index 64%
rename from src/Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceSession.cs
rename to src/Ryujinx.Audio.Backends.SDL3/SDL3HardwareDeviceSession.cs
index 5f7f4b411..e6c791133 100644
--- a/src/Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceSession.cs
+++ b/src/Ryujinx.Audio.Backends.SDL3/SDL3HardwareDeviceSession.cs
@@ -6,36 +6,40 @@ using Ryujinx.Memory;
using System;
using System.Collections.Concurrent;
using System.Threading;
+using SDL;
+using static SDL.SDL3;
+using System.Runtime.InteropServices;
-using static SDL2.SDL;
-
-namespace Ryujinx.Audio.Backends.SDL2
+namespace Ryujinx.Audio.Backends.SDL3
{
- sealed class SDL2HardwareDeviceSession : HardwareDeviceSessionOutputBase
+ unsafe sealed class SDL3HardwareDeviceSession : HardwareDeviceSessionOutputBase
{
- private readonly SDL2HardwareDeviceDriver _driver;
- private readonly ConcurrentQueue _queuedBuffers;
+ private readonly SDL3HardwareDeviceDriver _driver;
+ private readonly ConcurrentQueue _queuedBuffers;
private readonly DynamicRingBuffer _ringBuffer;
private ulong _playedSampleCount;
private readonly ManualResetEvent _updateRequiredEvent;
- private uint _outputStream;
+ private SDL_AudioStream* _outputStream;
private bool _hasSetupError;
- private readonly SDL_AudioCallback _callbackDelegate;
+ private readonly SDL_AudioStreamCallback _callbackDelegate;
private readonly int _bytesPerFrame;
private uint _sampleCount;
private bool _started;
private float _volume;
- private readonly ushort _nativeSampleFormat;
+ private readonly SDL_AudioFormat _nativeSampleFormat;
- public SDL2HardwareDeviceSession(SDL2HardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount)
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ internal delegate void SDL_AudioStreamCallback(nint session, SDL_AudioStream* stream, int stream_count, int device_count);
+
+ public SDL3HardwareDeviceSession(SDL3HardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount)
{
_driver = driver;
_updateRequiredEvent = _driver.GetUpdateRequiredEvent();
- _queuedBuffers = new ConcurrentQueue();
+ _queuedBuffers = new ConcurrentQueue();
_ringBuffer = new DynamicRingBuffer();
_callbackDelegate = Update;
_bytesPerFrame = BackendHelper.GetSampleSize(RequestedSampleFormat) * (int)RequestedChannelCount;
- _nativeSampleFormat = SDL2HardwareDeviceDriver.GetSDL2Format(RequestedSampleFormat);
+ _nativeSampleFormat = SDL3HardwareDeviceDriver.GetSDL3Format(RequestedSampleFormat);
_sampleCount = uint.MaxValue;
_started = false;
_volume = 1f;
@@ -44,45 +48,51 @@ namespace Ryujinx.Audio.Backends.SDL2
private void EnsureAudioStreamSetup(AudioBuffer buffer)
{
uint bufferSampleCount = (uint)GetSampleCount(buffer);
- bool needAudioSetup = (_outputStream == 0 && !_hasSetupError) ||
+ bool needAudioSetup = (_outputStream == null && !_hasSetupError) ||
(bufferSampleCount >= Constants.TargetSampleCount && bufferSampleCount < _sampleCount);
if (needAudioSetup)
{
_sampleCount = Math.Max(Constants.TargetSampleCount, bufferSampleCount);
- uint newOutputStream = SDL2HardwareDeviceDriver.OpenStream(RequestedSampleFormat, RequestedSampleRate, RequestedChannelCount, _sampleCount, _callbackDelegate);
+ SDL_AudioStream* newOutputStream = SDL3HardwareDeviceDriver.OpenStream(RequestedSampleFormat, RequestedSampleRate, RequestedChannelCount, _sampleCount, _callbackDelegate);
- _hasSetupError = newOutputStream == 0;
+ _hasSetupError = newOutputStream == null;
if (!_hasSetupError)
{
- if (_outputStream != 0)
+ if (_outputStream != null)
{
- SDL_CloseAudioDevice(_outputStream);
+ SDL_DestroyAudioStream(_outputStream);
}
_outputStream = newOutputStream;
- SDL_PauseAudioDevice(_outputStream, _started ? 0 : 1);
+ if (_started) {
+ SDL_ResumeAudioStreamDevice(_outputStream);
+ } else {
+ SDL_PauseAudioStreamDevice(_outputStream);
+ }
Logger.Info?.Print(LogClass.Audio, $"New audio stream setup with a target sample count of {_sampleCount}");
}
}
}
- private unsafe void Update(nint userdata, nint stream, int streamLength)
+ private void Update(nint userdata, SDL_AudioStream* streamDevice, int additionalAmount, int totalAmmount)
{
- Span streamSpan = new((void*)stream, streamLength);
+ using SpanOwner stream = SpanOwner.Rent(additionalAmount);
+ Span streamSpan = stream.Span;
- int maxFrameCount = (int)GetSampleCount(streamLength);
+
+ int maxFrameCount = (int)GetSampleCount(additionalAmount);
int bufferedFrames = _ringBuffer.Length / _bytesPerFrame;
int frameCount = Math.Min(bufferedFrames, maxFrameCount);
if (frameCount == 0)
{
- // SDL2 left the responsibility to the user to clear the buffer.
+ // SDL3 left the responsibility to the user to clear the buffer.
streamSpan.Clear();
return;
@@ -94,15 +104,17 @@ namespace Ryujinx.Audio.Backends.SDL2
_ringBuffer.Read(samples, 0, samples.Length);
- fixed (byte* p = samples)
- {
- nint pStreamSrc = (nint)p;
+ // Zero the dest buffer
+ streamSpan.Clear();
- // Zero the dest buffer
- streamSpan.Clear();
+ fixed (byte* pStreamDst = streamSpan) {
+ fixed (byte* pStreamSrc = samples)
+ {
- // Apply volume to written data
- SDL_MixAudioFormat(stream, pStreamSrc, _nativeSampleFormat, (uint)samples.Length, (int)(_driver.Volume * _volume * SDL_MIX_MAXVOLUME));
+ // Apply volume to written data
+ SDL_MixAudio(pStreamDst, pStreamSrc, _nativeSampleFormat, (uint)samples.Length, _driver.Volume * _volume);
+ SDL_PutAudioStreamData(streamDevice, (nint)pStreamDst, additionalAmount);
+ }
}
ulong sampleCount = GetSampleCount(samples.Length);
@@ -111,7 +123,7 @@ namespace Ryujinx.Audio.Backends.SDL2
bool needUpdate = false;
- while (availaibleSampleCount > 0 && _queuedBuffers.TryPeek(out SDL2AudioBuffer driverBuffer))
+ while (availaibleSampleCount > 0 && _queuedBuffers.TryPeek(out SDL3AudioBuffer driverBuffer))
{
ulong sampleStillNeeded = driverBuffer.SampleCount - Interlocked.Read(ref driverBuffer.SamplePlayed);
ulong playedAudioBufferSampleCount = Math.Min(sampleStillNeeded, availaibleSampleCount);
@@ -152,9 +164,9 @@ namespace Ryujinx.Audio.Backends.SDL2
{
EnsureAudioStreamSetup(buffer);
- if (_outputStream != 0)
+ if (_outputStream != null)
{
- SDL2AudioBuffer driverBuffer = new(buffer.DataPointer, GetSampleCount(buffer));
+ SDL3AudioBuffer driverBuffer = new(buffer.DataPointer, GetSampleCount(buffer));
_ringBuffer.Write(buffer.Data, 0, buffer.Data.Length);
@@ -177,9 +189,9 @@ namespace Ryujinx.Audio.Backends.SDL2
{
if (!_started)
{
- if (_outputStream != 0)
+ if (_outputStream != null)
{
- SDL_PauseAudioDevice(_outputStream, 0);
+ SDL_ResumeAudioStreamDevice(_outputStream);
}
_started = true;
@@ -190,9 +202,9 @@ namespace Ryujinx.Audio.Backends.SDL2
{
if (_started)
{
- if (_outputStream != 0)
+ if (_outputStream != null)
{
- SDL_PauseAudioDevice(_outputStream, 1);
+ SDL_PauseAudioStreamDevice(_outputStream);
}
_started = false;
@@ -203,7 +215,7 @@ namespace Ryujinx.Audio.Backends.SDL2
public override bool WasBufferFullyConsumed(AudioBuffer buffer)
{
- if (!_queuedBuffers.TryPeek(out SDL2AudioBuffer driverBuffer))
+ if (!_queuedBuffers.TryPeek(out SDL3AudioBuffer driverBuffer))
{
return true;
}
@@ -218,9 +230,9 @@ namespace Ryujinx.Audio.Backends.SDL2
PrepareToClose();
Stop();
- if (_outputStream != 0)
+ if (_outputStream != null)
{
- SDL_CloseAudioDevice(_outputStream);
+ SDL_DestroyAudioStream(_outputStream);
}
}
}
diff --git a/src/Ryujinx.Common/Configuration/Hid/InputBackendType.cs b/src/Ryujinx.Common/Configuration/Hid/InputBackendType.cs
index 81b80cdc7..c3336dc64 100644
--- a/src/Ryujinx.Common/Configuration/Hid/InputBackendType.cs
+++ b/src/Ryujinx.Common/Configuration/Hid/InputBackendType.cs
@@ -7,6 +7,7 @@ namespace Ryujinx.Common.Configuration.Hid
{
Invalid,
WindowKeyboard,
- GamepadSDL2,
+ GamepadSDL2, //backcompat
+ GamepadSDL3,
}
}
diff --git a/src/Ryujinx.Common/Configuration/Hid/JsonInputConfigConverter.cs b/src/Ryujinx.Common/Configuration/Hid/JsonInputConfigConverter.cs
index 39c2260ea..9d99f4210 100644
--- a/src/Ryujinx.Common/Configuration/Hid/JsonInputConfigConverter.cs
+++ b/src/Ryujinx.Common/Configuration/Hid/JsonInputConfigConverter.cs
@@ -58,7 +58,7 @@ namespace Ryujinx.Common.Configuration.Hid
return backendType switch
{
InputBackendType.WindowKeyboard => JsonSerializer.Deserialize(ref reader, _serializerContext.StandardKeyboardInputConfig),
- InputBackendType.GamepadSDL2 => JsonSerializer.Deserialize(ref reader, _serializerContext.StandardControllerInputConfig),
+ InputBackendType.GamepadSDL2 or InputBackendType.GamepadSDL3 => JsonSerializer.Deserialize(ref reader, _serializerContext.StandardControllerInputConfig),
_ => throw new InvalidOperationException($"Unknown backend type {backendType}"),
};
}
@@ -70,7 +70,7 @@ namespace Ryujinx.Common.Configuration.Hid
case InputBackendType.WindowKeyboard:
JsonSerializer.Serialize(writer, value as StandardKeyboardInputConfig, _serializerContext.StandardKeyboardInputConfig);
break;
- case InputBackendType.GamepadSDL2:
+ case InputBackendType.GamepadSDL2 or InputBackendType.GamepadSDL3:
JsonSerializer.Serialize(writer, value as StandardControllerInputConfig, _serializerContext.StandardControllerInputConfig);
break;
default:
diff --git a/src/Ryujinx.Input.SDL2/SDL2GamepadDriver.cs b/src/Ryujinx.Input.SDL2/SDL2GamepadDriver.cs
deleted file mode 100644
index 72e14dd39..000000000
--- a/src/Ryujinx.Input.SDL2/SDL2GamepadDriver.cs
+++ /dev/null
@@ -1,228 +0,0 @@
-using Ryujinx.Common.Logging;
-using Ryujinx.SDL2.Common;
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using static SDL2.SDL;
-
-namespace Ryujinx.Input.SDL2
-{
- public class SDL2GamepadDriver : IGamepadDriver
- {
- private readonly Dictionary _gamepadsInstanceIdsMapping;
- private readonly List _gamepadsIds;
- private readonly Lock _lock = new();
-
- public ReadOnlySpan GamepadsIds
- {
- get
- {
- lock (_lock)
- {
- return _gamepadsIds.ToArray();
- }
- }
- }
-
- public string DriverName => "SDL2";
-
- public event Action OnGamepadConnected;
- public event Action OnGamepadDisconnected;
-
- public SDL2GamepadDriver()
- {
- _gamepadsInstanceIdsMapping = new Dictionary();
- _gamepadsIds = [];
-
- SDL2Driver.Instance.Initialize();
- SDL2Driver.Instance.OnJoyStickConnected += HandleJoyStickConnected;
- SDL2Driver.Instance.OnJoystickDisconnected += HandleJoyStickDisconnected;
- SDL2Driver.Instance.OnJoyBatteryUpdated += HandleJoyBatteryUpdated;
-
- // Add already connected gamepads
- int numJoysticks = SDL_NumJoysticks();
-
- for (int joystickIndex = 0; joystickIndex < numJoysticks; joystickIndex++)
- {
- HandleJoyStickConnected(joystickIndex, SDL_JoystickGetDeviceInstanceID(joystickIndex));
- }
- }
-
- private string GenerateGamepadId(int joystickIndex)
- {
- Guid guid = SDL_JoystickGetDeviceGUID(joystickIndex);
-
- // Add a unique identifier to the start of the GUID in case of duplicates.
-
- if (guid == Guid.Empty)
- {
- return null;
- }
-
- // Remove the first 4 char of the guid (CRC part) to make it stable
- string guidString = "0000" + guid.ToString().Substring(4);
-
- string id;
-
- lock (_lock)
- {
- int guidIndex = 0;
- id = guidIndex + "-" + guidString;
-
- while (_gamepadsIds.Contains(id))
- {
- id = (++guidIndex) + "-" + guidString;
- }
- }
-
- return id;
- }
-
- private int GetJoystickIndexByGamepadId(string id)
- {
- lock (_lock)
- {
- return _gamepadsIds.IndexOf(id);
- }
- }
-
- private void HandleJoyStickDisconnected(int joystickInstanceId)
- {
- bool joyConPairDisconnected = false;
-
- if (_gamepadsInstanceIdsMapping.TryGetValue(joystickInstanceId, out string id))
- {
- _gamepadsInstanceIdsMapping.Remove(joystickInstanceId);
-
- lock (_lock)
- {
- _gamepadsIds.Remove(id);
- if (!SDL2JoyConPair.IsCombinable(_gamepadsIds))
- {
- _gamepadsIds.Remove(SDL2JoyConPair.Id);
- joyConPairDisconnected = true;
- }
- }
- }
-
- OnGamepadDisconnected?.Invoke(id);
- if (joyConPairDisconnected)
- {
- OnGamepadDisconnected?.Invoke(SDL2JoyConPair.Id);
- }
- }
-
- private void HandleJoyStickConnected(int joystickDeviceId, int joystickInstanceId)
- {
- bool joyConPairConnected = false;
-
- if (SDL_IsGameController(joystickDeviceId) == SDL_bool.SDL_TRUE)
- {
- if (_gamepadsInstanceIdsMapping.ContainsKey(joystickInstanceId))
- {
- // Sometimes a JoyStick connected event fires after the app starts even though it was connected before
- // so it is rejected to avoid doubling the entries.
- return;
- }
-
- string id = GenerateGamepadId(joystickDeviceId);
-
- if (id == null)
- {
- return;
- }
-
- if (_gamepadsInstanceIdsMapping.TryAdd(joystickInstanceId, id))
- {
- lock (_lock)
- {
- if (joystickDeviceId <= _gamepadsIds.FindLastIndex(_ => true))
- _gamepadsIds.Insert(joystickDeviceId, id);
- else
- _gamepadsIds.Add(id);
-
- if (SDL2JoyConPair.IsCombinable(_gamepadsIds))
- {
- _gamepadsIds.Remove(SDL2JoyConPair.Id);
- _gamepadsIds.Add(SDL2JoyConPair.Id);
- joyConPairConnected = true;
- }
- }
-
- OnGamepadConnected?.Invoke(id);
- if (joyConPairConnected)
- {
- OnGamepadConnected?.Invoke(SDL2JoyConPair.Id);
- }
- }
- }
- }
-
- private void HandleJoyBatteryUpdated(int joystickDeviceId, SDL_JoystickPowerLevel powerLevel)
- {
- Logger.Info?.Print(LogClass.Hid,
- $"{SDL_GameControllerNameForIndex(joystickDeviceId)} power level: {powerLevel}");
- }
-
-
- protected virtual void Dispose(bool disposing)
- {
- if (disposing)
- {
- SDL2Driver.Instance.OnJoyStickConnected -= HandleJoyStickConnected;
- SDL2Driver.Instance.OnJoystickDisconnected -= HandleJoyStickDisconnected;
-
- // Simulate a full disconnect when disposing
- foreach (string id in _gamepadsIds)
- {
- OnGamepadDisconnected?.Invoke(id);
- }
-
- lock (_lock)
- {
- _gamepadsIds.Clear();
- }
-
- SDL2Driver.Instance.Dispose();
- }
- }
-
- public void Dispose()
- {
- GC.SuppressFinalize(this);
- Dispose(true);
- }
-
- public IGamepad GetGamepad(string id)
- {
- if (id == SDL2JoyConPair.Id)
- {
- lock (_lock)
- {
- return SDL2JoyConPair.GetGamepad(_gamepadsIds);
- }
- }
-
- int joystickIndex = GetJoystickIndexByGamepadId(id);
-
- if (joystickIndex == -1)
- {
- return null;
- }
-
- nint gamepadHandle = SDL_GameControllerOpen(joystickIndex);
-
- if (gamepadHandle == nint.Zero)
- {
- return null;
- }
-
- if (SDL_GameControllerName(gamepadHandle).StartsWith(SDL2JoyCon.Prefix))
- {
- return new SDL2JoyCon(gamepadHandle, id);
- }
-
- return new SDL2Gamepad(gamepadHandle, id);
- }
- }
-}
diff --git a/src/Ryujinx.Input.SDL2/Ryujinx.Input.SDL2.csproj b/src/Ryujinx.Input.SDL3/Ryujinx.Input.SDL3.csproj
similarity index 73%
rename from src/Ryujinx.Input.SDL2/Ryujinx.Input.SDL2.csproj
rename to src/Ryujinx.Input.SDL3/Ryujinx.Input.SDL3.csproj
index 1215fc987..d8450f9c8 100644
--- a/src/Ryujinx.Input.SDL2/Ryujinx.Input.SDL2.csproj
+++ b/src/Ryujinx.Input.SDL3/Ryujinx.Input.SDL3.csproj
@@ -6,7 +6,7 @@
-
+
diff --git a/src/Ryujinx.Input.SDL2/SDL2Gamepad.cs b/src/Ryujinx.Input.SDL3/SDL3Gamepad.cs
similarity index 58%
rename from src/Ryujinx.Input.SDL2/SDL2Gamepad.cs
rename to src/Ryujinx.Input.SDL3/SDL3Gamepad.cs
index 0534b1646..84afd0661 100644
--- a/src/Ryujinx.Input.SDL2/SDL2Gamepad.cs
+++ b/src/Ryujinx.Input.SDL3/SDL3Gamepad.cs
@@ -1,59 +1,63 @@
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Controller;
using Ryujinx.Common.Logging;
+using SDL;
using System;
using System.Collections.Generic;
using System.Numerics;
using System.Threading;
-using static SDL2.SDL;
+using static SDL.SDL3;
-namespace Ryujinx.Input.SDL2
+namespace Ryujinx.Input.SDL3
{
- class SDL2Gamepad : IGamepad
+ public unsafe class SDL3Gamepad : IGamepad
{
private bool HasConfiguration => _configuration != null;
- private record struct ButtonMappingEntry(GamepadButtonInputId To, GamepadButtonInputId From);
+ private readonly record struct ButtonMappingEntry(GamepadButtonInputId To, GamepadButtonInputId From)
+ {
+ public bool IsValid => To is not GamepadButtonInputId.Unbound && From is not GamepadButtonInputId.Unbound;
+ }
private StandardControllerInputConfig _configuration;
- private static readonly SDL_GameControllerButton[] _buttonsDriverMapping =
+ private readonly SDL_GamepadButton[] _buttonsDriverMapping =
[
// Unbound, ignored.
- SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_INVALID,
+ SDL_GamepadButton.SDL_GAMEPAD_BUTTON_INVALID,
- SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_A,
- SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_B,
- SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_X,
- SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_Y,
- SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSTICK,
- SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_RIGHTSTICK,
- SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
- SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
+ SDL_GamepadButton.SDL_GAMEPAD_BUTTON_EAST,
+ SDL_GamepadButton.SDL_GAMEPAD_BUTTON_SOUTH,
+ SDL_GamepadButton.SDL_GAMEPAD_BUTTON_NORTH,
+ SDL_GamepadButton.SDL_GAMEPAD_BUTTON_WEST,
+ SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_STICK,
+ SDL_GamepadButton.SDL_GAMEPAD_BUTTON_RIGHT_STICK,
+ SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_SHOULDER,
+ SDL_GamepadButton.SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER,
// NOTE: The left and right trigger are axis, we handle those differently
- SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_INVALID,
- SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_INVALID,
+ SDL_GamepadButton.SDL_GAMEPAD_BUTTON_INVALID,
+ SDL_GamepadButton.SDL_GAMEPAD_BUTTON_INVALID,
- SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_UP,
- SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_DOWN,
- SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_LEFT,
- SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
- SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_BACK,
- SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_START,
- SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_GUIDE,
- SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_MISC1,
- SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_PADDLE1,
- SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_PADDLE2,
- SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_PADDLE3,
- SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_PADDLE4,
- SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_TOUCHPAD,
+ SDL_GamepadButton.SDL_GAMEPAD_BUTTON_DPAD_UP,
+ SDL_GamepadButton.SDL_GAMEPAD_BUTTON_DPAD_DOWN,
+ SDL_GamepadButton.SDL_GAMEPAD_BUTTON_DPAD_LEFT,
+ SDL_GamepadButton.SDL_GAMEPAD_BUTTON_DPAD_RIGHT,
+ SDL_GamepadButton.SDL_GAMEPAD_BUTTON_BACK,
+ SDL_GamepadButton.SDL_GAMEPAD_BUTTON_START,
+ SDL_GamepadButton.SDL_GAMEPAD_BUTTON_GUIDE,
+ SDL_GamepadButton.SDL_GAMEPAD_BUTTON_MISC1,
+ SDL_GamepadButton.SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1,
+ SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_PADDLE1,
+ SDL_GamepadButton.SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2,
+ SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_PADDLE2,
+ SDL_GamepadButton.SDL_GAMEPAD_BUTTON_TOUCHPAD,
// Virtual buttons are invalid, ignored.
- SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_INVALID,
- SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_INVALID,
- SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_INVALID,
- SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_INVALID
+ SDL_GamepadButton.SDL_GAMEPAD_BUTTON_INVALID,
+ SDL_GamepadButton.SDL_GAMEPAD_BUTTON_INVALID,
+ SDL_GamepadButton.SDL_GAMEPAD_BUTTON_INVALID,
+ SDL_GamepadButton.SDL_GAMEPAD_BUTTON_INVALID,
];
private readonly Lock _userMappingLock = new();
@@ -69,29 +73,43 @@ namespace Ryujinx.Input.SDL2
public GamepadFeaturesFlag Features { get; }
- private nint _gamepadHandle;
+ private SDL_Gamepad* _gamepadHandle;
private float _triggerThreshold;
- public SDL2Gamepad(nint gamepadHandle, string driverId)
+ public SDL3Gamepad(SDL_Gamepad* gamepadHandle, string driverId)
{
_gamepadHandle = gamepadHandle;
_buttonsUserMapping = new List(20);
- Name = SDL_GameControllerName(_gamepadHandle);
+ Name = SDL_GetGamepadName(_gamepadHandle);
Id = driverId;
Features = GetFeaturesFlag();
_triggerThreshold = 0.0f;
+ // Face button mapping
+ SDL_GamepadButton[] faceButtons = _buttonsDriverMapping[1..5];
+ foreach (SDL_GamepadButton btn in faceButtons) {
+ int mapId = SDL_GetGamepadButtonLabel(_gamepadHandle, btn) switch {
+ SDL_GamepadButtonLabel.SDL_GAMEPAD_BUTTON_LABEL_A or SDL_GamepadButtonLabel.SDL_GAMEPAD_BUTTON_LABEL_CROSS => 1,
+ SDL_GamepadButtonLabel.SDL_GAMEPAD_BUTTON_LABEL_B or SDL_GamepadButtonLabel.SDL_GAMEPAD_BUTTON_LABEL_CIRCLE => 2,
+ SDL_GamepadButtonLabel.SDL_GAMEPAD_BUTTON_LABEL_X or SDL_GamepadButtonLabel.SDL_GAMEPAD_BUTTON_LABEL_SQUARE => 3,
+ SDL_GamepadButtonLabel.SDL_GAMEPAD_BUTTON_LABEL_Y or SDL_GamepadButtonLabel.SDL_GAMEPAD_BUTTON_LABEL_TRIANGLE => 4,
+ _ => -1
+ };
+ if (mapId == -1) { continue; }
+ _buttonsDriverMapping[mapId] = btn;
+ }
+
// Enable motion tracking
if ((Features & GamepadFeaturesFlag.Motion) != 0)
{
- if (SDL_GameControllerSetSensorEnabled(_gamepadHandle, SDL_SensorType.SDL_SENSOR_ACCEL, SDL_bool.SDL_TRUE) != 0)
+ if (!SDL_SetGamepadSensorEnabled(_gamepadHandle, SDL_SensorType.SDL_SENSOR_ACCEL, true))
{
Logger.Error?.Print(LogClass.Hid, $"Could not enable data reporting for SensorType {SDL_SensorType.SDL_SENSOR_ACCEL}.");
}
- if (SDL_GameControllerSetSensorEnabled(_gamepadHandle, SDL_SensorType.SDL_SENSOR_GYRO, SDL_bool.SDL_TRUE) != 0)
+ if (!SDL_SetGamepadSensorEnabled(_gamepadHandle, SDL_SensorType.SDL_SENSOR_GYRO, true))
{
Logger.Error?.Print(LogClass.Hid, $"Could not enable data reporting for SensorType {SDL_SensorType.SDL_SENSOR_GYRO}.");
}
@@ -102,40 +120,43 @@ namespace Ryujinx.Input.SDL2
{
GamepadFeaturesFlag result = GamepadFeaturesFlag.None;
- if (SDL_GameControllerHasSensor(_gamepadHandle, SDL_SensorType.SDL_SENSOR_ACCEL) == SDL_bool.SDL_TRUE &&
- SDL_GameControllerHasSensor(_gamepadHandle, SDL_SensorType.SDL_SENSOR_GYRO) == SDL_bool.SDL_TRUE)
+ if (SDL_GamepadHasSensor(_gamepadHandle, SDL_SensorType.SDL_SENSOR_ACCEL) &&
+ SDL_GamepadHasSensor(_gamepadHandle, SDL_SensorType.SDL_SENSOR_GYRO))
{
result |= GamepadFeaturesFlag.Motion;
}
-
- int error = SDL_GameControllerRumble(_gamepadHandle, 0, 0, 100);
-
- if (error == 0)
+ SDL_PropertiesID propID = SDL_GetGamepadProperties(_gamepadHandle);
+ SDL_LockProperties(propID);
+ if (SDL_GetBooleanProperty(propID, SDL_PROP_GAMEPAD_CAP_RUMBLE_BOOLEAN, false))
{
result |= GamepadFeaturesFlag.Rumble;
}
+ SDL_UnlockProperties(propID);
+ SDL_DestroyProperties(propID);
+
return result;
}
public string Id { get; }
public string Name { get; }
- public bool IsConnected => SDL_GameControllerGetAttached(_gamepadHandle) == SDL_bool.SDL_TRUE;
+ public bool IsConnected => SDL_GamepadConnected(_gamepadHandle);
protected virtual void Dispose(bool disposing)
{
- if (disposing && _gamepadHandle != nint.Zero)
+ if (disposing && _gamepadHandle != null)
{
- SDL_GameControllerClose(_gamepadHandle);
+ SDL_CloseGamepad(_gamepadHandle);
- _gamepadHandle = nint.Zero;
+ _gamepadHandle = null;
}
}
public void Dispose()
{
Dispose(true);
+ GC.SuppressFinalize(this);
}
public void SetTriggerThreshold(float triggerThreshold)
@@ -146,85 +167,62 @@ namespace Ryujinx.Input.SDL2
public void Rumble(float lowFrequency, float highFrequency, uint durationMs)
{
if ((Features & GamepadFeaturesFlag.Rumble) == 0)
- {
- ushort lowFrequencyRaw = (ushort)(lowFrequency * ushort.MaxValue);
- ushort highFrequencyRaw = (ushort)(highFrequency * ushort.MaxValue);
+ return;
- if (durationMs == uint.MaxValue)
- {
- if (SDL_GameControllerRumble(_gamepadHandle, lowFrequencyRaw, highFrequencyRaw, SDL_HAPTIC_INFINITY) != 0)
- {
- Logger.Error?.Print(LogClass.Hid, "Rumble is not supported on this game controller.");
- }
- }
- else if (durationMs > SDL_HAPTIC_INFINITY)
- {
- Logger.Error?.Print(LogClass.Hid, $"Unsupported rumble duration {durationMs}");
- }
- else
- {
- if (SDL_GameControllerRumble(_gamepadHandle, lowFrequencyRaw, highFrequencyRaw, durationMs) != 0)
- {
- Logger.Error?.Print(LogClass.Hid, "Rumble is not supported on this game controller.");
- }
- }
+ ushort lowFrequencyRaw = (ushort)(lowFrequency * ushort.MaxValue);
+ ushort highFrequencyRaw = (ushort)(highFrequency * ushort.MaxValue);
+
+ if (durationMs == uint.MaxValue)
+ {
+ if (!SDL_RumbleGamepad(_gamepadHandle, lowFrequencyRaw, highFrequencyRaw, SDL_HAPTIC_INFINITY))
+ Logger.Error?.Print(LogClass.Hid, "Rumble is not supported on this game controller.");
+ }
+ else if (durationMs > SDL_HAPTIC_INFINITY)
+ {
+ Logger.Error?.Print(LogClass.Hid, $"Unsupported rumble duration {durationMs}");
+ }
+ else
+ {
+ if (!SDL_RumbleGamepad(_gamepadHandle, lowFrequencyRaw, highFrequencyRaw, durationMs))
+ Logger.Error?.Print(LogClass.Hid, "Rumble is not supported on this game controller.");
}
}
public Vector3 GetMotionData(MotionInputId inputId)
{
- SDL_SensorType sensorType = SDL_SensorType.SDL_SENSOR_INVALID;
-
- if (inputId == MotionInputId.Accelerometer)
+ SDL_SensorType sensorType = inputId switch
{
- sensorType = SDL_SensorType.SDL_SENSOR_ACCEL;
- }
- else if (inputId == MotionInputId.Gyroscope)
- {
- sensorType = SDL_SensorType.SDL_SENSOR_GYRO;
- }
+ MotionInputId.Accelerometer => SDL_SensorType.SDL_SENSOR_ACCEL,
+ MotionInputId.Gyroscope => SDL_SensorType.SDL_SENSOR_GYRO,
+ _ => SDL_SensorType.SDL_SENSOR_INVALID
+ };
- if ((Features & GamepadFeaturesFlag.Motion) == 0 || sensorType is SDL_SensorType.SDL_SENSOR_INVALID)
+ if (!Features.HasFlag(GamepadFeaturesFlag.Motion) || sensorType is SDL_SensorType.SDL_SENSOR_INVALID)
return Vector3.Zero;
const int ElementCount = 3;
- unsafe
- {
- float* values = stackalloc float[ElementCount];
+ float[] values = new float[3];
- int result = SDL_GameControllerGetSensorData(_gamepadHandle, sensorType, (nint)values, ElementCount);
+ fixed (float* pValues = &values[0]) {
- if (result == 0)
+ if (!SDL_GetGamepadSensorData(_gamepadHandle, sensorType, pValues, ElementCount))
+ return Vector3.Zero;
+
+ Vector3 value = new(values[0], values[1], values[2]);
+
+ return inputId switch
{
- Vector3 value = new(values[0], values[1], values[2]);
-
- if (inputId == MotionInputId.Gyroscope)
- {
- return RadToDegree(value);
- }
-
- if (inputId == MotionInputId.Accelerometer)
- {
- return GsToMs2(value);
- }
-
- return value;
- }
+ MotionInputId.Gyroscope => RadToDegree(value),
+ MotionInputId.Accelerometer => GsToMs2(value),
+ _ => value
+ };
}
-
- return Vector3.Zero;
}
- private static Vector3 RadToDegree(Vector3 rad)
- {
- return rad * (180 / MathF.PI);
- }
+ private static Vector3 RadToDegree(Vector3 rad) => rad * (180 / MathF.PI);
- private static Vector3 GsToMs2(Vector3 gs)
- {
- return gs / SDL_STANDARD_GRAVITY;
- }
+ private static Vector3 GsToMs2(Vector3 gs) => gs / SDL_STANDARD_GRAVITY;
public void SetConfiguration(InputConfig configuration)
{
@@ -279,16 +277,13 @@ namespace Ryujinx.Input.SDL2
lock (_userMappingLock)
{
if (_buttonsUserMapping.Count == 0)
- {
return rawState;
- }
+ // ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator
foreach (ButtonMappingEntry entry in _buttonsUserMapping)
{
- if (entry.From == GamepadButtonInputId.Unbound || entry.To == GamepadButtonInputId.Unbound)
- {
+ if (!entry.IsValid)
continue;
- }
// Do not touch state of button already pressed
if (!result.IsPressed(entry.To))
@@ -329,15 +324,14 @@ namespace Ryujinx.Input.SDL2
else
return _configuration.RightJoyconStick;
}
+
return null;
}
public (float, float) GetStick(StickInputId inputId)
{
if (inputId == StickInputId.Unbound)
- {
return (0.0f, 0.0f);
- }
(short stickX, short stickY) = GetStickXY(inputId);
@@ -346,7 +340,7 @@ namespace Ryujinx.Input.SDL2
if (HasConfiguration)
{
- var joyconStickConfig = GetLogicalJoyStickConfig(inputId);
+ JoyconConfigControllerStick joyconStickConfig = GetLogicalJoyStickConfig(inputId);
if (joyconStickConfig != null)
{
@@ -368,36 +362,35 @@ namespace Ryujinx.Input.SDL2
return (resultX, resultY);
}
+ // ReSharper disable once InconsistentNaming
private (short, short) GetStickXY(StickInputId inputId) =>
inputId switch
{
StickInputId.Left => (
- SDL_GameControllerGetAxis(_gamepadHandle, SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_LEFTX),
- SDL_GameControllerGetAxis(_gamepadHandle, SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_LEFTY)),
+ SDL_GetGamepadAxis(_gamepadHandle, SDL_GamepadAxis.SDL_GAMEPAD_AXIS_LEFTX),
+ SDL_GetGamepadAxis(_gamepadHandle, SDL_GamepadAxis.SDL_GAMEPAD_AXIS_LEFTY)),
StickInputId.Right => (
- SDL_GameControllerGetAxis(_gamepadHandle, SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_RIGHTX),
- SDL_GameControllerGetAxis(_gamepadHandle, SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_RIGHTY)),
+ SDL_GetGamepadAxis(_gamepadHandle, SDL_GamepadAxis.SDL_GAMEPAD_AXIS_RIGHTX),
+ SDL_GetGamepadAxis(_gamepadHandle, SDL_GamepadAxis.SDL_GAMEPAD_AXIS_RIGHTY)),
_ => throw new NotSupportedException($"Unsupported stick {inputId}")
};
public bool IsPressed(GamepadButtonInputId inputId)
{
- if (inputId == GamepadButtonInputId.LeftTrigger)
+ switch (inputId)
{
- return ConvertRawStickValue(SDL_GameControllerGetAxis(_gamepadHandle, SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERLEFT)) > _triggerThreshold;
+ case GamepadButtonInputId.LeftTrigger:
+ return ConvertRawStickValue(SDL_GetGamepadAxis(_gamepadHandle, SDL_GamepadAxis.SDL_GAMEPAD_AXIS_LEFT_TRIGGER)) > _triggerThreshold;
+ case GamepadButtonInputId.RightTrigger:
+ return ConvertRawStickValue(SDL_GetGamepadAxis(_gamepadHandle, SDL_GamepadAxis.SDL_GAMEPAD_AXIS_RIGHT_TRIGGER)) > _triggerThreshold;
}
- if (inputId == GamepadButtonInputId.RightTrigger)
- {
- return ConvertRawStickValue(SDL_GameControllerGetAxis(_gamepadHandle, SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERRIGHT)) > _triggerThreshold;
- }
-
- if (_buttonsDriverMapping[(int)inputId] == SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_INVALID)
+ if (_buttonsDriverMapping[(int)inputId] == SDL_GamepadButton.SDL_GAMEPAD_BUTTON_INVALID)
{
return false;
}
- return SDL_GameControllerGetButton(_gamepadHandle, _buttonsDriverMapping[(int)inputId]) == 1;
+ return SDL_GetGamepadButton(_gamepadHandle, _buttonsDriverMapping[(int)inputId]);
}
}
}
diff --git a/src/Ryujinx.Input.SDL3/SDL3GamepadDriver.cs b/src/Ryujinx.Input.SDL3/SDL3GamepadDriver.cs
new file mode 100644
index 000000000..1d524d95c
--- /dev/null
+++ b/src/Ryujinx.Input.SDL3/SDL3GamepadDriver.cs
@@ -0,0 +1,254 @@
+using Ryujinx.Common.Logging;
+using Ryujinx.SDL3.Common;
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using SDL;
+using System.Linq;
+using static SDL.SDL3;
+
+namespace Ryujinx.Input.SDL3
+{
+ public unsafe class SDL3GamepadDriver : IGamepadDriver
+ {
+ private readonly Dictionary _gamepadsInstanceIdsMapping;
+ private readonly Dictionary _gamepadsIds;
+ private readonly Lock _lock = new();
+
+ public ReadOnlySpan GamepadsIds
+ {
+ get
+ {
+ lock (_lock)
+ {
+ return _gamepadsIds.Values.ToArray();
+ }
+ }
+ }
+
+ public string DriverName => "SDL3";
+
+ public event Action OnGamepadConnected;
+ public event Action OnGamepadDisconnected;
+
+ public SDL3GamepadDriver()
+ {
+ _gamepadsInstanceIdsMapping = new Dictionary();
+ _gamepadsIds = [];
+
+ SDL3Driver.Instance.Initialize();
+ SDL3Driver.Instance.OnJoyStickConnected += HandleJoyStickConnected;
+ SDL3Driver.Instance.OnJoystickDisconnected += HandleJoyStickDisconnected;
+ SDL3Driver.Instance.OnJoyBatteryUpdated += HandleJoyBatteryUpdated;
+
+ // Add already connected gamepads
+ int joystickCount = 0;
+
+ SDL_JoystickID* pJoystickInstanceIds = SDL_GetJoysticks(&joystickCount);
+
+ for (int i = 0; i < joystickCount; i++)
+ {
+ HandleJoyStickConnected(pJoystickInstanceIds[i]);
+ }
+ }
+
+ private static string SDLGuidToString(SDL_GUID guid)
+ {
+ string map = "0123456789abcdef";
+ char[] guidBytes = new char[33];
+
+ for (int i = 0; i < 16; i++) {
+ byte c = guid.data[i];
+ guidBytes[i * 2] = map[c >> 4];
+ guidBytes[(i * 2) + 1] = map[c & 0x0f];
+ }
+
+ string strGuid = new(guidBytes);
+
+ return $"{strGuid[4..6]}{strGuid[6..8]}{strGuid[2..4]}{strGuid[0..2]}-{strGuid[10..12]}{strGuid[8..10]}-{strGuid[12..16]}-{strGuid[16..20]}-{strGuid[20..32]}";
+
+ }
+
+ private string GenerateGamepadId(SDL_JoystickID joystickInstanceId)
+ {
+ SDL_GUID sdlGuid = SDL_GetJoystickGUIDForID(joystickInstanceId);
+ string guidBytes = SDLGuidToString(sdlGuid);
+ Guid guid = Guid.Parse(guidBytes);
+
+ // Add a unique identifier to the start of the GUID in case of duplicates.
+
+ if (guid == Guid.Empty)
+ {
+ return null;
+ }
+
+ // Remove the first 4 char of the guid (CRC part) to make it stable
+ string guidString = $"0000{guid.ToString()[4..]}";
+
+ string id;
+
+ lock (_lock)
+ {
+ int guidIndex = 0;
+ id = guidIndex + "-" + guidString;
+
+ while (_gamepadsIds.ContainsValue(id))
+ {
+ id = (++guidIndex) + "-" + guidString;
+ }
+ }
+
+ return id;
+ }
+
+ private void HandleJoyStickDisconnected(SDL_JoystickID joystickInstanceId)
+ {
+ bool joyConPairDisconnected = false;
+
+ if (!_gamepadsInstanceIdsMapping.Remove(joystickInstanceId, out string id))
+ return;
+
+ lock (_lock)
+ {
+ _gamepadsIds.Remove(joystickInstanceId);
+ if (!SDL3JoyConPair.IsCombinable(_gamepadsIds))
+ {
+ _gamepadsIds.Remove(GetInstanceIdFromId(SDL3JoyConPair.Id));
+ joyConPairDisconnected = true;
+ }
+ }
+
+ OnGamepadDisconnected?.Invoke(id);
+ if (joyConPairDisconnected)
+ {
+ OnGamepadDisconnected?.Invoke(SDL3JoyConPair.Id);
+ }
+ }
+
+ private void HandleJoyStickConnected(SDL_JoystickID joystickInstanceId)
+ {
+ bool joyConPairConnected = false;
+
+ if (SDL_IsGamepad(joystickInstanceId))
+ {
+ if (_gamepadsInstanceIdsMapping.ContainsKey(joystickInstanceId))
+ {
+ // Sometimes a JoyStick connected event fires after the app starts even though it was connected before
+ // so it is rejected to avoid doubling the entries.
+ return;
+ }
+
+ string id = GenerateGamepadId(joystickInstanceId);
+
+ if (id == null)
+ {
+ return;
+ }
+
+ if (_gamepadsInstanceIdsMapping.TryAdd(joystickInstanceId, id))
+ {
+ lock (_lock)
+ {
+
+ _gamepadsIds.Add(joystickInstanceId, id);
+
+ if (SDL3JoyConPair.IsCombinable(_gamepadsIds))
+ {
+ // TODO - It appears that you can only have one joy con pair connected at a time?
+ // This was also the behavior before SDL3
+ _gamepadsIds.Remove(GetInstanceIdFromId(SDL3JoyConPair.Id));
+ uint fakeInstanceID = uint.MaxValue;
+ while (!_gamepadsIds.TryAdd((SDL_JoystickID)fakeInstanceID, SDL3JoyConPair.Id))
+ {
+ fakeInstanceID--;
+ }
+ joyConPairConnected = true;
+ }
+ }
+
+ OnGamepadConnected?.Invoke(id);
+ if (joyConPairConnected)
+ {
+ OnGamepadConnected?.Invoke(SDL3JoyConPair.Id);
+ }
+ }
+ }
+ }
+
+ private void HandleJoyBatteryUpdated(SDL_JoystickID joystickInstanceId, SDL_PowerState powerLevel)
+ {
+ Logger.Info?.Print(LogClass.Hid,
+ $"{SDL_GetGamepadNameForID(joystickInstanceId)} power level: {powerLevel}");
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ SDL3Driver.Instance.OnJoyStickConnected -= HandleJoyStickConnected;
+ SDL3Driver.Instance.OnJoystickDisconnected -= HandleJoyStickDisconnected;
+
+ // Simulate a full disconnect when disposing
+ foreach (var gamepad in _gamepadsIds)
+ {
+ OnGamepadDisconnected?.Invoke(gamepad.Value);
+ }
+
+ lock (_lock)
+ {
+ _gamepadsIds.Clear();
+ }
+
+ SDL3Driver.Instance.Dispose();
+ }
+ }
+
+ public void Dispose()
+ {
+ GC.SuppressFinalize(this);
+ Dispose(true);
+ }
+
+ public SDL_JoystickID GetInstanceIdFromId(string id) {
+ return _gamepadsInstanceIdsMapping.Where(e => e.Value == id).FirstOrDefault().Key;
+ }
+
+ public IGamepad GetGamepad(string id)
+ {
+ if (id == SDL3JoyConPair.Id)
+ {
+ lock (_lock)
+ {
+ return SDL3JoyConPair.GetGamepad(_gamepadsIds);
+ }
+ }
+
+ SDL_JoystickID instanceId = GetInstanceIdFromId(id);
+
+ SDL_Gamepad* gamepadHandle = SDL_OpenGamepad(instanceId);
+
+ if (gamepadHandle == null)
+ {
+ return null;
+ }
+
+ if (SDL_GetGamepadName(gamepadHandle).StartsWith(SDL3JoyCon.Prefix))
+ {
+ return new SDL3JoyCon(gamepadHandle, id);
+ }
+
+ return new SDL3Gamepad(gamepadHandle, id);
+ }
+
+ public IEnumerable GetGamepads()
+ {
+ lock (_gamepadsIds)
+ {
+ foreach (var gamepad in _gamepadsIds)
+ {
+ yield return GetGamepad(gamepad.Value);
+ }
+ }
+ }
+ }
+}
diff --git a/src/Ryujinx.Input.SDL2/SDL2JoyCon.cs b/src/Ryujinx.Input.SDL3/SDL3JoyCon.cs
similarity index 77%
rename from src/Ryujinx.Input.SDL2/SDL2JoyCon.cs
rename to src/Ryujinx.Input.SDL3/SDL3JoyCon.cs
index 60b7b0857..677b8a781 100644
--- a/src/Ryujinx.Input.SDL2/SDL2JoyCon.cs
+++ b/src/Ryujinx.Input.SDL3/SDL3JoyCon.cs
@@ -1,15 +1,16 @@
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Controller;
using Ryujinx.Common.Logging;
+using SDL;
using System;
using System.Collections.Generic;
using System.Numerics;
using System.Threading;
-using static SDL2.SDL;
+using static SDL.SDL3;
-namespace Ryujinx.Input.SDL2
+namespace Ryujinx.Input.SDL3
{
- internal class SDL2JoyCon : IGamepad
+ internal unsafe class SDL3JoyCon : IGamepad
{
private bool HasConfiguration => _configuration != null;
@@ -20,34 +21,34 @@ namespace Ryujinx.Input.SDL2
private StandardControllerInputConfig _configuration;
- private readonly Dictionary _leftButtonsDriverMapping = new()
+ private readonly Dictionary _leftButtonsDriverMapping = new()
{
- { GamepadButtonInputId.LeftStick , SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSTICK },
- {GamepadButtonInputId.DpadUp ,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_Y},
- {GamepadButtonInputId.DpadDown ,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_A},
- {GamepadButtonInputId.DpadLeft ,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_B},
- {GamepadButtonInputId.DpadRight ,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_X},
- {GamepadButtonInputId.Minus ,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_START},
- {GamepadButtonInputId.LeftShoulder,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_PADDLE2},
- {GamepadButtonInputId.LeftTrigger,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_PADDLE4},
- {GamepadButtonInputId.SingleRightTrigger0,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
- {GamepadButtonInputId.SingleLeftTrigger0,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
+ { GamepadButtonInputId.LeftStick , SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_STICK },
+ {GamepadButtonInputId.DpadUp ,SDL_GamepadButton.SDL_GAMEPAD_BUTTON_NORTH},
+ {GamepadButtonInputId.DpadDown ,SDL_GamepadButton.SDL_GAMEPAD_BUTTON_SOUTH},
+ {GamepadButtonInputId.DpadLeft ,SDL_GamepadButton.SDL_GAMEPAD_BUTTON_EAST},
+ {GamepadButtonInputId.DpadRight ,SDL_GamepadButton.SDL_GAMEPAD_BUTTON_WEST},
+ {GamepadButtonInputId.Minus ,SDL_GamepadButton.SDL_GAMEPAD_BUTTON_START},
+ {GamepadButtonInputId.LeftShoulder,SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_PADDLE1},
+ {GamepadButtonInputId.LeftTrigger,SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_PADDLE2},
+ {GamepadButtonInputId.SingleRightTrigger0,SDL_GamepadButton.SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER},
+ {GamepadButtonInputId.SingleLeftTrigger0,SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_SHOULDER},
};
- private readonly Dictionary _rightButtonsDriverMapping = new()
+ private readonly Dictionary _rightButtonsDriverMapping = new()
{
- {GamepadButtonInputId.RightStick,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSTICK},
- {GamepadButtonInputId.A,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_B},
- {GamepadButtonInputId.B,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_Y},
- {GamepadButtonInputId.X,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_A},
- {GamepadButtonInputId.Y,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_X},
- {GamepadButtonInputId.Plus,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_START},
- {GamepadButtonInputId.RightShoulder,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_PADDLE1},
- {GamepadButtonInputId.RightTrigger,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_PADDLE3},
- {GamepadButtonInputId.SingleRightTrigger1,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
- {GamepadButtonInputId.SingleLeftTrigger1,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSHOULDER}
+ {GamepadButtonInputId.RightStick,SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_STICK},
+ {GamepadButtonInputId.A,SDL_GamepadButton.SDL_GAMEPAD_BUTTON_EAST},
+ {GamepadButtonInputId.B,SDL_GamepadButton.SDL_GAMEPAD_BUTTON_NORTH},
+ {GamepadButtonInputId.X,SDL_GamepadButton.SDL_GAMEPAD_BUTTON_SOUTH},
+ {GamepadButtonInputId.Y,SDL_GamepadButton.SDL_GAMEPAD_BUTTON_WEST},
+ {GamepadButtonInputId.Plus,SDL_GamepadButton.SDL_GAMEPAD_BUTTON_START},
+ {GamepadButtonInputId.RightShoulder,SDL_GamepadButton.SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1},
+ {GamepadButtonInputId.RightTrigger,SDL_GamepadButton.SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2},
+ {GamepadButtonInputId.SingleRightTrigger1,SDL_GamepadButton.SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER},
+ {GamepadButtonInputId.SingleLeftTrigger1,SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_SHOULDER}
};
- private readonly Dictionary _buttonsDriverMapping;
+ private readonly Dictionary _buttonsDriverMapping;
private readonly Lock _userMappingLock = new();
private readonly List _buttonsUserMapping;
@@ -59,7 +60,7 @@ namespace Ryujinx.Input.SDL2
public GamepadFeaturesFlag Features { get; }
- private nint _gamepadHandle;
+ private SDL_Gamepad* _gamepadHandle;
private enum JoyConType
{
@@ -72,27 +73,25 @@ namespace Ryujinx.Input.SDL2
private readonly JoyConType _joyConType;
- public SDL2JoyCon(nint gamepadHandle, string driverId)
+ public SDL3JoyCon(SDL_Gamepad* gamepadHandle, string driverId)
{
_gamepadHandle = gamepadHandle;
_buttonsUserMapping = new List(10);
- Name = SDL_GameControllerName(_gamepadHandle);
+ Name = SDL_GetGamepadName(_gamepadHandle);
Id = driverId;
Features = GetFeaturesFlag();
// Enable motion tracking
if ((Features & GamepadFeaturesFlag.Motion) != 0)
{
- if (SDL_GameControllerSetSensorEnabled(_gamepadHandle, SDL_SensorType.SDL_SENSOR_ACCEL,
- SDL_bool.SDL_TRUE) != 0)
+ if (!SDL_SetGamepadSensorEnabled(_gamepadHandle, SDL_SensorType.SDL_SENSOR_ACCEL, true))
{
Logger.Error?.Print(LogClass.Hid,
$"Could not enable data reporting for SensorType {SDL_SensorType.SDL_SENSOR_ACCEL}.");
}
- if (SDL_GameControllerSetSensorEnabled(_gamepadHandle, SDL_SensorType.SDL_SENSOR_GYRO,
- SDL_bool.SDL_TRUE) != 0)
+ if (!SDL_SetGamepadSensorEnabled(_gamepadHandle, SDL_SensorType.SDL_SENSOR_GYRO, true))
{
Logger.Error?.Print(LogClass.Hid,
$"Could not enable data reporting for SensorType {SDL_SensorType.SDL_SENSOR_GYRO}.");
@@ -120,15 +119,13 @@ namespace Ryujinx.Input.SDL2
{
GamepadFeaturesFlag result = GamepadFeaturesFlag.None;
- if (SDL_GameControllerHasSensor(_gamepadHandle, SDL_SensorType.SDL_SENSOR_ACCEL) == SDL_bool.SDL_TRUE &&
- SDL_GameControllerHasSensor(_gamepadHandle, SDL_SensorType.SDL_SENSOR_GYRO) == SDL_bool.SDL_TRUE)
+ if (SDL_GamepadHasSensor(_gamepadHandle, SDL_SensorType.SDL_SENSOR_ACCEL) &&
+ SDL_GamepadHasSensor(_gamepadHandle, SDL_SensorType.SDL_SENSOR_GYRO))
{
result |= GamepadFeaturesFlag.Motion;
}
- int error = SDL_GameControllerRumble(_gamepadHandle, 0, 0, 100);
-
- if (error == 0)
+ if (SDL_RumbleGamepad(_gamepadHandle, 0, 0, 100))
{
result |= GamepadFeaturesFlag.Rumble;
}
@@ -138,15 +135,15 @@ namespace Ryujinx.Input.SDL2
public string Id { get; }
public string Name { get; }
- public bool IsConnected => SDL_GameControllerGetAttached(_gamepadHandle) == SDL_bool.SDL_TRUE;
+ public bool IsConnected => SDL_GamepadConnected(_gamepadHandle);
protected virtual void Dispose(bool disposing)
{
- if (disposing && _gamepadHandle != nint.Zero)
+ if (disposing && _gamepadHandle != null)
{
- SDL_GameControllerClose(_gamepadHandle);
+ SDL_CloseGamepad(_gamepadHandle);
- _gamepadHandle = nint.Zero;
+ _gamepadHandle = null;
}
}
@@ -171,8 +168,7 @@ namespace Ryujinx.Input.SDL2
if (durationMs == uint.MaxValue)
{
- if (SDL_GameControllerRumble(_gamepadHandle, lowFrequencyRaw, highFrequencyRaw, SDL_HAPTIC_INFINITY) !=
- 0)
+ if (!SDL_RumbleGamepad(_gamepadHandle, lowFrequencyRaw, highFrequencyRaw, SDL_HAPTIC_INFINITY))
Logger.Error?.Print(LogClass.Hid, "Rumble is not supported on this game controller.");
}
else if (durationMs > SDL_HAPTIC_INFINITY)
@@ -181,7 +177,7 @@ namespace Ryujinx.Input.SDL2
}
else
{
- if (SDL_GameControllerRumble(_gamepadHandle, lowFrequencyRaw, highFrequencyRaw, durationMs) != 0)
+ if (!SDL_RumbleGamepad(_gamepadHandle, lowFrequencyRaw, highFrequencyRaw, durationMs))
Logger.Error?.Print(LogClass.Hid, "Rumble is not supported on this game controller.");
}
}
@@ -200,13 +196,10 @@ namespace Ryujinx.Input.SDL2
const int ElementCount = 3;
- unsafe
- {
- float* values = stackalloc float[ElementCount];
+ float[] values = new float[3];
- int result = SDL_GameControllerGetSensorData(_gamepadHandle, sensorType, (nint)values, ElementCount);
-
- if (result != 0)
+ fixed (float* pValues = &values[0]) {
+ if (!SDL_GetGamepadSensorData(_gamepadHandle, sensorType, pValues, ElementCount))
return Vector3.Zero;
Vector3 value = _joyConType switch
@@ -276,10 +269,6 @@ namespace Ryujinx.Input.SDL2
}
}
- public void SetLed(uint packedRgb)
- {
- }
-
public GamepadStateSnapshot GetStateSnapshot()
{
return IGamepad.GetStateSnapshot(this);
@@ -394,18 +383,18 @@ namespace Ryujinx.Input.SDL2
private (short, short) GetStickXY()
{
return (
- SDL_GameControllerGetAxis(_gamepadHandle, SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_LEFTX),
- SDL_GameControllerGetAxis(_gamepadHandle, SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_LEFTY));
+ SDL_GetGamepadAxis(_gamepadHandle, SDL_GamepadAxis.SDL_GAMEPAD_AXIS_LEFTX),
+ SDL_GetGamepadAxis(_gamepadHandle, SDL_GamepadAxis.SDL_GAMEPAD_AXIS_LEFTY));
}
public bool IsPressed(GamepadButtonInputId inputId)
{
- if (!_buttonsDriverMapping.TryGetValue(inputId, out var button))
+ if (!_buttonsDriverMapping.TryGetValue(inputId, out SDL_GamepadButton button))
{
return false;
}
- return SDL_GameControllerGetButton(_gamepadHandle, button) == 1;
+ return SDL_GetGamepadButton(_gamepadHandle, button);
}
}
}
diff --git a/src/Ryujinx.Input.SDL2/SDL2JoyConPair.cs b/src/Ryujinx.Input.SDL3/SDL3JoyConPair.cs
similarity index 69%
rename from src/Ryujinx.Input.SDL2/SDL2JoyConPair.cs
rename to src/Ryujinx.Input.SDL3/SDL3JoyConPair.cs
index b00665408..757cca240 100644
--- a/src/Ryujinx.Input.SDL2/SDL2JoyConPair.cs
+++ b/src/Ryujinx.Input.SDL3/SDL3JoyConPair.cs
@@ -2,11 +2,12 @@
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
-using static SDL2.SDL;
+using SDL;
+using static SDL.SDL3;
-namespace Ryujinx.Input.SDL2
+namespace Ryujinx.Input.SDL3
{
- internal class SDL2JoyConPair(IGamepad left, IGamepad right) : IGamepad
+ internal class SDL3JoyConPair(IGamepad left, IGamepad right) : IGamepad
{
public GamepadFeaturesFlag Features => (left?.Features ?? GamepadFeaturesFlag.None) |
(right?.Features ?? GamepadFeaturesFlag.None);
@@ -85,51 +86,50 @@ namespace Ryujinx.Input.SDL2
right.SetConfiguration(configuration);
}
- public void SetLed(uint packedRgb)
- {
- }
-
public void SetTriggerThreshold(float triggerThreshold)
{
left.SetTriggerThreshold(triggerThreshold);
right.SetTriggerThreshold(triggerThreshold);
}
- public static bool IsCombinable(List gamepadsIds)
+ public static bool IsCombinable(Dictionary gamepadsIds)
{
(int leftIndex, int rightIndex) = DetectJoyConPair(gamepadsIds);
return leftIndex >= 0 && rightIndex >= 0;
}
- private static (int leftIndex, int rightIndex) DetectJoyConPair(List gamepadsIds)
+ private static (int leftIndex, int rightIndex) DetectJoyConPair(Dictionary gamepadsIds)
{
- var gamepadNames = gamepadsIds.Where(gamepadId => gamepadId != Id)
- .Select((_, index) => SDL_GameControllerNameForIndex(index)).ToList();
- int leftIndex = gamepadNames.IndexOf(SDL2JoyCon.LeftName);
- int rightIndex = gamepadNames.IndexOf(SDL2JoyCon.RightName);
+ Dictionary gamepadNames = gamepadsIds
+ .Where(gamepadId => gamepadId.Value != Id && SDL_GetGamepadNameForID(gamepadId.Key) is SDL3JoyCon.LeftName or SDL3JoyCon.RightName)
+ .Select(gamepad => (SDL_GetGamepadNameForID(gamepad.Key), gamepad.Key))
+ .ToDictionary();
+ SDL_JoystickID idx;
+ int leftIndex = gamepadNames.TryGetValue(SDL3JoyCon.LeftName, out idx) ? (int)idx : -1;
+ int rightIndex = gamepadNames.TryGetValue(SDL3JoyCon.RightName, out idx) ? (int)idx : -1;
return (leftIndex, rightIndex);
}
- public static IGamepad GetGamepad(List gamepadsIds)
+ public unsafe static IGamepad GetGamepad(Dictionary gamepadsIds)
{
(int leftIndex, int rightIndex) = DetectJoyConPair(gamepadsIds);
- if (leftIndex == -1 || rightIndex == -1)
+
+ if (leftIndex <= 0 || rightIndex <= 0)
{
return null;
}
- nint leftGamepadHandle = SDL_GameControllerOpen(leftIndex);
- nint rightGamepadHandle = SDL_GameControllerOpen(rightIndex);
+ SDL_Gamepad* leftGamepadHandle = SDL_OpenGamepad((SDL_JoystickID)leftIndex);
+ SDL_Gamepad* rightGamepadHandle = SDL_OpenGamepad((SDL_JoystickID)rightIndex);
- if (leftGamepadHandle == nint.Zero || rightGamepadHandle == nint.Zero)
+ if (leftGamepadHandle == null || rightGamepadHandle == null)
{
return null;
}
-
- return new SDL2JoyConPair(new SDL2JoyCon(leftGamepadHandle, gamepadsIds[leftIndex]),
- new SDL2JoyCon(rightGamepadHandle, gamepadsIds[rightIndex]));
+ return new SDL3JoyConPair(new SDL3JoyCon(leftGamepadHandle, gamepadsIds[(SDL_JoystickID)leftIndex]),
+ new SDL3JoyCon(rightGamepadHandle, gamepadsIds[(SDL_JoystickID)rightIndex]));
}
}
}
diff --git a/src/Ryujinx.Input.SDL2/SDL2Keyboard.cs b/src/Ryujinx.Input.SDL3/SDL3Keyboard.cs
similarity index 85%
rename from src/Ryujinx.Input.SDL2/SDL2Keyboard.cs
rename to src/Ryujinx.Input.SDL3/SDL3Keyboard.cs
index 6681248a5..3c4d1c0b2 100644
--- a/src/Ryujinx.Input.SDL2/SDL2Keyboard.cs
+++ b/src/Ryujinx.Input.SDL3/SDL3Keyboard.cs
@@ -1,17 +1,18 @@
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Keyboard;
+using SDL;
using System;
using System.Collections.Generic;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Threading;
-using static SDL2.SDL;
+using static SDL.SDL3;
using ConfigKey = Ryujinx.Common.Configuration.Hid.Key;
-namespace Ryujinx.Input.SDL2
+namespace Ryujinx.Input.SDL3
{
- class SDL2Keyboard : IKeyboard
+ class SDL3Keyboard : IKeyboard
{
private readonly record struct ButtonMappingEntry(GamepadButtonInputId To, Key From)
{
@@ -21,7 +22,7 @@ namespace Ryujinx.Input.SDL2
private readonly Lock _userMappingLock = new();
#pragma warning disable IDE0052 // Remove unread private member
- private readonly SDL2KeyboardDriver _driver;
+ private readonly SDL3KeyboardDriver _driver;
#pragma warning restore IDE0052
private StandardKeyboardInputConfig _configuration;
private readonly List _buttonsUserMapping;
@@ -115,32 +116,32 @@ namespace Ryujinx.Input.SDL2
SDL_Keycode.SDLK_KP_PLUS,
SDL_Keycode.SDLK_KP_DECIMAL,
SDL_Keycode.SDLK_KP_ENTER,
- SDL_Keycode.SDLK_a,
- SDL_Keycode.SDLK_b,
- SDL_Keycode.SDLK_c,
- SDL_Keycode.SDLK_d,
- SDL_Keycode.SDLK_e,
- SDL_Keycode.SDLK_f,
- SDL_Keycode.SDLK_g,
- SDL_Keycode.SDLK_h,
- SDL_Keycode.SDLK_i,
- SDL_Keycode.SDLK_j,
- SDL_Keycode.SDLK_k,
- SDL_Keycode.SDLK_l,
- SDL_Keycode.SDLK_m,
- SDL_Keycode.SDLK_n,
- SDL_Keycode.SDLK_o,
- SDL_Keycode.SDLK_p,
- SDL_Keycode.SDLK_q,
- SDL_Keycode.SDLK_r,
- SDL_Keycode.SDLK_s,
- SDL_Keycode.SDLK_t,
- SDL_Keycode.SDLK_u,
- SDL_Keycode.SDLK_v,
- SDL_Keycode.SDLK_w,
- SDL_Keycode.SDLK_x,
- SDL_Keycode.SDLK_y,
- SDL_Keycode.SDLK_z,
+ SDL_Keycode.SDLK_A,
+ SDL_Keycode.SDLK_B,
+ SDL_Keycode.SDLK_C,
+ SDL_Keycode.SDLK_D,
+ SDL_Keycode.SDLK_E,
+ SDL_Keycode.SDLK_F,
+ SDL_Keycode.SDLK_G,
+ SDL_Keycode.SDLK_H,
+ SDL_Keycode.SDLK_I,
+ SDL_Keycode.SDLK_J,
+ SDL_Keycode.SDLK_K,
+ SDL_Keycode.SDLK_L,
+ SDL_Keycode.SDLK_M,
+ SDL_Keycode.SDLK_N,
+ SDL_Keycode.SDLK_O,
+ SDL_Keycode.SDLK_P,
+ SDL_Keycode.SDLK_Q,
+ SDL_Keycode.SDLK_R,
+ SDL_Keycode.SDLK_S,
+ SDL_Keycode.SDLK_T,
+ SDL_Keycode.SDLK_U,
+ SDL_Keycode.SDLK_V,
+ SDL_Keycode.SDLK_W,
+ SDL_Keycode.SDLK_X,
+ SDL_Keycode.SDLK_Y,
+ SDL_Keycode.SDLK_Z,
SDL_Keycode.SDLK_0,
SDL_Keycode.SDLK_1,
SDL_Keycode.SDLK_2,
@@ -151,14 +152,14 @@ namespace Ryujinx.Input.SDL2
SDL_Keycode.SDLK_7,
SDL_Keycode.SDLK_8,
SDL_Keycode.SDLK_9,
- SDL_Keycode.SDLK_BACKQUOTE,
- SDL_Keycode.SDLK_BACKQUOTE,
+ SDL_Keycode.SDLK_GRAVE,
+ SDL_Keycode.SDLK_GRAVE,
SDL_Keycode.SDLK_MINUS,
SDL_Keycode.SDLK_PLUS,
SDL_Keycode.SDLK_LEFTBRACKET,
SDL_Keycode.SDLK_RIGHTBRACKET,
SDL_Keycode.SDLK_SEMICOLON,
- SDL_Keycode.SDLK_QUOTE,
+ SDL_Keycode.SDLK_APOSTROPHE,
SDL_Keycode.SDLK_COMMA,
SDL_Keycode.SDLK_PERIOD,
SDL_Keycode.SDLK_SLASH,
@@ -168,7 +169,7 @@ namespace Ryujinx.Input.SDL2
SDL_Keycode.SDLK_0
];
- public SDL2Keyboard(SDL2KeyboardDriver driver, string id, string name)
+ public SDL3Keyboard(SDL3KeyboardDriver driver, string id, string name)
{
_driver = driver;
Id = id;
@@ -192,55 +193,49 @@ namespace Ryujinx.Input.SDL2
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static int ToSDL2Scancode(Key key)
+ private unsafe static int ToSDL3Scancode(Key key)
{
if (key >= Key.Unknown && key <= Key.Menu)
{
return -1;
}
- return (int)SDL_GetScancodeFromKey(_keysDriverMapping[(int)key]);
+ return (int)SDL_GetScancodeFromKey(_keysDriverMapping[(int)key], null);
}
private static SDL_Keymod GetKeyboardModifierMask(Key key)
{
return key switch
{
- Key.ShiftLeft => SDL_Keymod.KMOD_LSHIFT,
- Key.ShiftRight => SDL_Keymod.KMOD_RSHIFT,
- Key.ControlLeft => SDL_Keymod.KMOD_LCTRL,
- Key.ControlRight => SDL_Keymod.KMOD_RCTRL,
- Key.AltLeft => SDL_Keymod.KMOD_LALT,
- Key.AltRight => SDL_Keymod.KMOD_RALT,
- Key.WinLeft => SDL_Keymod.KMOD_LGUI,
- Key.WinRight => SDL_Keymod.KMOD_RGUI,
- // NOTE: Menu key isn't supported by SDL2.
- _ => SDL_Keymod.KMOD_NONE,
+ Key.ShiftLeft => SDL_Keymod.SDL_KMOD_LSHIFT,
+ Key.ShiftRight => SDL_Keymod.SDL_KMOD_RSHIFT,
+ Key.ControlLeft => SDL_Keymod.SDL_KMOD_LCTRL,
+ Key.ControlRight => SDL_Keymod.SDL_KMOD_RCTRL,
+ Key.AltLeft => SDL_Keymod.SDL_KMOD_LALT,
+ Key.AltRight => SDL_Keymod.SDL_KMOD_RALT,
+ Key.WinLeft => SDL_Keymod.SDL_KMOD_LGUI,
+ Key.WinRight => SDL_Keymod.SDL_KMOD_RGUI,
+ // NOTE: Menu key isn't supported by SDL3.
+ _ => SDL_Keymod.SDL_KMOD_NONE,
};
}
- public KeyboardStateSnapshot GetKeyboardStateSnapshot()
+ public unsafe KeyboardStateSnapshot GetKeyboardStateSnapshot()
{
- ReadOnlySpan rawKeyboardState;
SDL_Keymod rawKeyboardModifierState = SDL_GetModState();
- unsafe
- {
- nint statePtr = SDL_GetKeyboardState(out int numKeys);
-
- rawKeyboardState = new ReadOnlySpan((byte*)statePtr, numKeys);
- }
+ SDLBool* rawKeyboardState = SDL_GetKeyboardState(null);
bool[] keysState = new bool[(int)Key.Count];
for (Key key = 0; key < Key.Count; key++)
{
- int index = ToSDL2Scancode(key);
+ int index = ToSDL3Scancode(key);
if (index == -1)
{
SDL_Keymod modifierMask = GetKeyboardModifierMask(key);
- if (modifierMask == SDL_Keymod.KMOD_NONE)
+ if (modifierMask == SDL_Keymod.SDL_KMOD_NONE)
{
continue;
}
@@ -249,7 +244,7 @@ namespace Ryujinx.Input.SDL2
}
else
{
- keysState[(int)key] = rawKeyboardState[index] == 1;
+ keysState[(int)key] = rawKeyboardState[index];
}
}
diff --git a/src/Ryujinx.Input.SDL2/SDL2Mouse.cs b/src/Ryujinx.Input.SDL3/SDL3Mouse.cs
similarity index 90%
rename from src/Ryujinx.Input.SDL2/SDL2Mouse.cs
rename to src/Ryujinx.Input.SDL3/SDL3Mouse.cs
index 8beb0ec31..95933bc9a 100644
--- a/src/Ryujinx.Input.SDL2/SDL2Mouse.cs
+++ b/src/Ryujinx.Input.SDL3/SDL3Mouse.cs
@@ -3,17 +3,17 @@ using System;
using System.Drawing;
using System.Numerics;
-namespace Ryujinx.Input.SDL2
+namespace Ryujinx.Input.SDL3
{
- class SDL2Mouse : IMouse
+ class SDL3Mouse : IMouse
{
- private SDL2MouseDriver _driver;
+ private SDL3MouseDriver _driver;
public GamepadFeaturesFlag Features => throw new NotImplementedException();
public string Id => "0";
- public string Name => "SDL2Mouse";
+ public string Name => "SDL3Mouse";
public bool IsConnected => true;
@@ -21,7 +21,7 @@ namespace Ryujinx.Input.SDL2
Size IMouse.ClientSize => _driver.GetClientSize();
- public SDL2Mouse(SDL2MouseDriver driver)
+ public SDL3Mouse(SDL3MouseDriver driver)
{
_driver = driver;
}
diff --git a/src/Ryujinx.Input.SDL2/SDL2MouseDriver.cs b/src/Ryujinx.Input.SDL3/SDL3MouseDriver.cs
similarity index 76%
rename from src/Ryujinx.Input.SDL2/SDL2MouseDriver.cs
rename to src/Ryujinx.Input.SDL3/SDL3MouseDriver.cs
index 36a7f2175..5b51ba691 100644
--- a/src/Ryujinx.Input.SDL2/SDL2MouseDriver.cs
+++ b/src/Ryujinx.Input.SDL3/SDL3MouseDriver.cs
@@ -1,15 +1,17 @@
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
+using SDL;
using System;
+using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Numerics;
using System.Runtime.CompilerServices;
-using static SDL2.SDL;
+using static SDL.SDL3;
-namespace Ryujinx.Input.SDL2
+namespace Ryujinx.Input.SDL3
{
- public class SDL2MouseDriver : IGamepadDriver
+ public class SDL3MouseDriver : IGamepadDriver
{
private const int CursorHideIdleTime = 5; // seconds
@@ -24,14 +26,14 @@ namespace Ryujinx.Input.SDL2
public Vector2 Scroll { get; private set; }
public Size ClientSize;
- public SDL2MouseDriver(HideCursorMode hideCursorMode)
+ public SDL3MouseDriver(HideCursorMode hideCursorMode)
{
PressedButtons = new bool[(int)MouseButton.Count];
_hideCursorMode = hideCursorMode;
if (_hideCursorMode == HideCursorMode.Always)
{
- if (SDL_ShowCursor(SDL_DISABLE) != SDL_DISABLE)
+ if (!SDL_HideCursor())
{
Logger.Error?.PrintMsg(LogClass.Application, "Failed to disable the cursor.");
}
@@ -43,14 +45,16 @@ namespace Ryujinx.Input.SDL2
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static MouseButton DriverButtonToMouseButton(uint rawButton)
{
- Debug.Assert(rawButton > 0 && rawButton <= (int)MouseButton.Count);
+ Debug.Assert(rawButton is > 0 and <= (int)MouseButton.Count);
return (MouseButton)(rawButton - 1);
}
- public void UpdatePosition()
+ public unsafe void UpdatePosition()
{
- _ = SDL_GetMouseState(out int posX, out int posY);
+ float posX = 0;
+ float posY = 0;
+ _ = SDL_GetMouseState(&posX, &posY);
Vector2 position = new(posX, posY);
if (CurrentPosition != position)
@@ -75,7 +79,7 @@ namespace Ryujinx.Input.SDL2
{
if (!_isHidden)
{
- if (SDL_ShowCursor(SDL_DISABLE) != SDL_DISABLE)
+ if (!SDL_HideCursor())
{
Logger.Error?.PrintMsg(LogClass.Application, "Failed to disable the cursor.");
}
@@ -87,7 +91,7 @@ namespace Ryujinx.Input.SDL2
{
if (_isHidden)
{
- if (SDL_ShowCursor(SDL_ENABLE) != SDL_ENABLE)
+ if (!SDL_ShowCursor())
{
Logger.Error?.PrintMsg(LogClass.Application, "Failed to enable the cursor.");
}
@@ -99,15 +103,15 @@ namespace Ryujinx.Input.SDL2
public void Update(SDL_Event evnt)
{
- switch (evnt.type)
+ switch (evnt.Type)
{
- case SDL_EventType.SDL_MOUSEBUTTONDOWN:
- case SDL_EventType.SDL_MOUSEBUTTONUP:
- uint rawButton = evnt.button.button;
+ case SDL_EventType.SDL_EVENT_MOUSE_BUTTON_DOWN:
+ case SDL_EventType.SDL_EVENT_MOUSE_BUTTON_UP:
+ uint rawButton = (uint)evnt.button.Button;
- if (rawButton > 0 && rawButton <= (int)MouseButton.Count)
+ if (rawButton is > 0 and <= ((int)MouseButton.Count))
{
- PressedButtons[(int)DriverButtonToMouseButton(rawButton)] = evnt.type == SDL_EventType.SDL_MOUSEBUTTONDOWN;
+ PressedButtons[(int)DriverButtonToMouseButton(rawButton)] = evnt.Type == SDL_EventType.SDL_EVENT_MOUSE_BUTTON_DOWN;
CurrentPosition = new Vector2(evnt.button.x, evnt.button.y);
}
@@ -115,13 +119,13 @@ namespace Ryujinx.Input.SDL2
break;
// NOTE: On Linux using Wayland mouse motion events won't be received at all.
- case SDL_EventType.SDL_MOUSEMOTION:
+ case SDL_EventType.SDL_EVENT_MOUSE_MOTION:
CurrentPosition = new Vector2(evnt.motion.x, evnt.motion.y);
_lastCursorMoveTime = Stopwatch.GetTimestamp();
break;
- case SDL_EventType.SDL_MOUSEWHEEL:
+ case SDL_EventType.SDL_EVENT_MOUSE_WHEEL:
Scroll = new Vector2(evnt.wheel.x, evnt.wheel.y);
break;
@@ -143,7 +147,7 @@ namespace Ryujinx.Input.SDL2
return ClientSize;
}
- public string DriverName => "SDL2";
+ public string DriverName => "SDL3";
public event Action OnGamepadConnected
{
@@ -161,9 +165,11 @@ namespace Ryujinx.Input.SDL2
public IGamepad GetGamepad(string id)
{
- return new SDL2Mouse(this);
+ return new SDL3Mouse(this);
}
+ public IEnumerable GetGamepads() => [GetGamepad("0")];
+
public void Dispose()
{
if (_isDisposed)
@@ -171,6 +177,7 @@ namespace Ryujinx.Input.SDL2
return;
}
+ GC.SuppressFinalize(this);
_isDisposed = true;
}
}
diff --git a/src/Ryujinx.Input.SDL2/SDLKeyboardDriver.cs b/src/Ryujinx.Input.SDL3/SDLKeyboardDriver.cs
similarity index 71%
rename from src/Ryujinx.Input.SDL2/SDLKeyboardDriver.cs
rename to src/Ryujinx.Input.SDL3/SDLKeyboardDriver.cs
index 0894c6966..9ff142833 100644
--- a/src/Ryujinx.Input.SDL2/SDLKeyboardDriver.cs
+++ b/src/Ryujinx.Input.SDL3/SDLKeyboardDriver.cs
@@ -1,16 +1,16 @@
-using Ryujinx.SDL2.Common;
+using Ryujinx.SDL3.Common;
using System;
-namespace Ryujinx.Input.SDL2
+namespace Ryujinx.Input.SDL3
{
- public class SDL2KeyboardDriver : IGamepadDriver
+ public class SDL3KeyboardDriver : IGamepadDriver
{
- public SDL2KeyboardDriver()
+ public SDL3KeyboardDriver()
{
- SDL2Driver.Instance.Initialize();
+ SDL3Driver.Instance.Initialize();
}
- public string DriverName => "SDL2";
+ public string DriverName => "SDL3";
private static readonly string[] _keyboardIdentifers = ["0"];
@@ -32,7 +32,7 @@ namespace Ryujinx.Input.SDL2
{
if (disposing)
{
- SDL2Driver.Instance.Dispose();
+ SDL3Driver.Instance.Dispose();
}
}
@@ -49,7 +49,7 @@ namespace Ryujinx.Input.SDL2
return null;
}
- return new SDL2Keyboard(this, _keyboardIdentifers[0], "All keyboards");
+ return new SDL3Keyboard(this, _keyboardIdentifers[0], "All keyboards");
}
}
}
diff --git a/src/Ryujinx.SDL2.Common/Ryujinx.SDL2.Common.csproj b/src/Ryujinx.SDL3.Common/Ryujinx.SDL3.Common.csproj
similarity index 75%
rename from src/Ryujinx.SDL2.Common/Ryujinx.SDL2.Common.csproj
rename to src/Ryujinx.SDL3.Common/Ryujinx.SDL3.Common.csproj
index cfd3eb772..22baf1448 100644
--- a/src/Ryujinx.SDL2.Common/Ryujinx.SDL2.Common.csproj
+++ b/src/Ryujinx.SDL3.Common/Ryujinx.SDL3.Common.csproj
@@ -2,10 +2,11 @@
$(DefaultItemExcludes);._*
+ true
-
+
diff --git a/src/Ryujinx.SDL2.Common/SDL2Driver.cs b/src/Ryujinx.SDL3.Common/SDL3Driver.cs
similarity index 59%
rename from src/Ryujinx.SDL2.Common/SDL2Driver.cs
rename to src/Ryujinx.SDL3.Common/SDL3Driver.cs
index 741092088..fdbeeddf4 100644
--- a/src/Ryujinx.SDL2.Common/SDL2Driver.cs
+++ b/src/Ryujinx.SDL3.Common/SDL3Driver.cs
@@ -1,23 +1,24 @@
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
+using SDL;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Threading;
-using static SDL2.SDL;
+using static SDL.SDL3;
-namespace Ryujinx.SDL2.Common
+namespace Ryujinx.SDL3.Common
{
- public class SDL2Driver : IDisposable
+ public class SDL3Driver : IDisposable
{
- private static SDL2Driver _instance;
+ private static SDL3Driver _instance;
- public static SDL2Driver Instance
+ public static SDL3Driver Instance
{
get
{
- _instance ??= new SDL2Driver();
+ _instance ??= new SDL3Driver();
return _instance;
}
@@ -25,26 +26,22 @@ namespace Ryujinx.SDL2.Common
public static Action MainThreadDispatcher { get; set; }
- private const uint SdlInitFlags = SDL_INIT_EVENTS | SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK | SDL_INIT_AUDIO | SDL_INIT_VIDEO;
+ private const SDL_InitFlags SdlInitFlags = SDL_InitFlags.SDL_INIT_EVENTS | SDL_InitFlags.SDL_INIT_GAMEPAD | SDL_InitFlags.SDL_INIT_JOYSTICK | SDL_InitFlags.SDL_INIT_AUDIO | SDL_InitFlags.SDL_INIT_VIDEO;
private bool _isRunning;
private uint _refereceCount;
private Thread _worker;
- private const uint SDL_JOYBATTERYUPDATED = 1543;
-
- public event Action OnJoyStickConnected;
- public event Action OnJoystickDisconnected;
+ public event Action OnJoyStickConnected;
+ public event Action OnJoystickDisconnected;
- public event Action OnJoyBatteryUpdated;
+ public event Action OnJoyBatteryUpdated;
- private ConcurrentDictionary> _registeredWindowHandlers;
+ private ConcurrentDictionary> _registeredWindowHandlers;
private readonly Lock _lock = new();
- private SDL2Driver() { }
-
- private const string SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS = "SDL_JOYSTICK_HIDAPI_COMBINE_JOY_CONS";
+ private SDL3Driver() { }
public void Initialize()
{
@@ -58,8 +55,7 @@ namespace Ryujinx.SDL2.Common
}
SDL_SetHint(SDL_HINT_APP_NAME, "Ryujinx");
- SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1");
- SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1");
+ SDL_SetHint(SDL_HINT_JOYSTICK_ENHANCED_REPORTS , "1");
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED, "0");
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1");
@@ -70,9 +66,9 @@ namespace Ryujinx.SDL2.Common
// We disable this behavior for now.
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS, "0");
- if (SDL_Init(SdlInitFlags) != 0)
+ if (!SDL_Init(SdlInitFlags))
{
- string errorMessage = $"SDL2 initialization failed with error \"{SDL_GetError()}\"";
+ string errorMessage = $"SDL3 initialization failed with error \"{SDL_GetError()}\"";
Logger.Error?.Print(LogClass.Application, errorMessage);
@@ -80,80 +76,77 @@ namespace Ryujinx.SDL2.Common
}
// First ensure that we only enable joystick events (for connected/disconnected).
- if (SDL_GameControllerEventState(SDL_IGNORE) != SDL_IGNORE)
+ SDL_SetGamepadEventsEnabled(false);
+ SDL_SetJoystickEventsEnabled(true);
+ if (SDL_GamepadEventsEnabled())
{
Logger.Error?.PrintMsg(LogClass.Application, "Couldn't change the state of game controller events.");
}
- if (SDL_JoystickEventState(SDL_ENABLE) < 0)
+ if (!SDL_JoystickEventsEnabled())
{
Logger.Error?.PrintMsg(LogClass.Application, $"Failed to enable joystick event polling: {SDL_GetError()}");
}
// Disable all joysticks information, we don't need them no need to flood the event queue for that.
- SDL_EventState(SDL_EventType.SDL_JOYAXISMOTION, SDL_DISABLE);
- SDL_EventState(SDL_EventType.SDL_JOYBALLMOTION, SDL_DISABLE);
- SDL_EventState(SDL_EventType.SDL_JOYHATMOTION, SDL_DISABLE);
- SDL_EventState(SDL_EventType.SDL_JOYBUTTONDOWN, SDL_DISABLE);
- SDL_EventState(SDL_EventType.SDL_JOYBUTTONUP, SDL_DISABLE);
+ SDL_SetEventEnabled((uint)SDL_EventType.SDL_EVENT_JOYSTICK_AXIS_MOTION, false);
+ SDL_SetEventEnabled((uint)SDL_EventType.SDL_EVENT_JOYSTICK_BALL_MOTION, false);
+ SDL_SetEventEnabled((uint)SDL_EventType.SDL_EVENT_JOYSTICK_HAT_MOTION, false);
+ SDL_SetEventEnabled((uint)SDL_EventType.SDL_EVENT_JOYSTICK_BUTTON_DOWN, false);
+ SDL_SetEventEnabled((uint)SDL_EventType.SDL_EVENT_JOYSTICK_BUTTON_UP, false);
- SDL_EventState(SDL_EventType.SDL_CONTROLLERSENSORUPDATE, SDL_DISABLE);
+ SDL_SetEventEnabled((uint)SDL_EventType.SDL_EVENT_GAMEPAD_SENSOR_UPDATE, false);
string gamepadDbPath = Path.Combine(AppDataManager.BaseDirPath, "SDL_GameControllerDB.txt");
if (File.Exists(gamepadDbPath))
{
- SDL_GameControllerAddMappingsFromFile(gamepadDbPath);
+ SDL_AddGamepadMappingsFromFile(gamepadDbPath);
}
- _registeredWindowHandlers = new ConcurrentDictionary>();
+ _registeredWindowHandlers = new ConcurrentDictionary>();
_worker = new Thread(EventWorker);
_isRunning = true;
_worker.Start();
}
}
- public bool RegisterWindow(uint windowId, Action windowEventHandler)
+ public bool RegisterWindow(SDL_WindowID windowId, Action windowEventHandler)
{
return _registeredWindowHandlers.TryAdd(windowId, windowEventHandler);
}
- public void UnregisterWindow(uint windowId)
+ public void UnregisterWindow(SDL_WindowID windowId)
{
_registeredWindowHandlers.Remove(windowId, out _);
}
private void HandleSDLEvent(ref SDL_Event evnt)
{
- if (evnt.type == SDL_EventType.SDL_JOYDEVICEADDED)
+ SDL_EventType type = evnt.Type;
+ if (type == SDL_EventType.SDL_EVENT_JOYSTICK_ADDED)
{
- int deviceId = evnt.cbutton.which;
-
- // SDL2 loves to be inconsistent here by providing the device id instead of the instance id (like on removed event), as such we just grab it and send it inside our system.
- int instanceId = SDL_JoystickGetDeviceInstanceID(deviceId);
-
- if (instanceId == -1)
- {
- return;
- }
+ SDL_JoystickID instanceId = evnt.jbutton.which;
+ // SDL3 loves to be inconsistent here by providing the device id instead of the instance id (like on removed event), as such we just grab it and send it inside our system.
Logger.Debug?.Print(LogClass.Application, $"Added joystick instance id {instanceId}");
- OnJoyStickConnected?.Invoke(deviceId, instanceId);
+ OnJoyStickConnected?.Invoke(instanceId);
}
- else if (evnt.type == SDL_EventType.SDL_JOYDEVICEREMOVED)
+ else if (type == SDL_EventType.SDL_EVENT_JOYSTICK_REMOVED)
{
- Logger.Debug?.Print(LogClass.Application, $"Removed joystick instance id {evnt.cbutton.which}");
+ Logger.Debug?.Print(LogClass.Application, $"Removed joystick instance id {evnt.jbutton.which}");
- OnJoystickDisconnected?.Invoke(evnt.cbutton.which);
+ OnJoystickDisconnected?.Invoke(evnt.jbutton.which);
}
- else if ((uint)evnt.type == SDL_JOYBATTERYUPDATED)
+ else if (type == SDL_EventType.SDL_EVENT_JOYSTICK_BATTERY_UPDATED)
{
- OnJoyBatteryUpdated?.Invoke(evnt.cbutton.which, (SDL_JoystickPowerLevel)evnt.user.code);
+ OnJoyBatteryUpdated?.Invoke(evnt.jbutton.which, evnt.jbattery.state);
}
- else if (evnt.type is SDL_EventType.SDL_WINDOWEVENT
- or SDL_EventType.SDL_MOUSEBUTTONDOWN
- or SDL_EventType.SDL_MOUSEBUTTONUP)
+ else if (
+ ((uint)type >= (uint)SDL_EventType.SDL_EVENT_WINDOW_FIRST && (uint)type <= (uint)SDL_EventType.SDL_EVENT_WINDOW_LAST) ||
+ type is SDL_EventType.SDL_EVENT_MOUSE_BUTTON_DOWN or SDL_EventType.SDL_EVENT_MOUSE_BUTTON_UP
+ )
{
if (_registeredWindowHandlers.TryGetValue(evnt.window.windowID, out Action handler))
{
@@ -162,7 +155,7 @@ namespace Ryujinx.SDL2.Common
}
}
- private void EventWorker()
+ private unsafe void EventWorker()
{
const int WaitTimeMs = 10;
@@ -172,7 +165,8 @@ namespace Ryujinx.SDL2.Common
{
MainThreadDispatcher?.Invoke(() =>
{
- while (SDL_PollEvent(out SDL_Event evnt) != 0)
+ SDL_Event evnt = new();
+ while (SDL_PollEvent(&evnt))
{
HandleSDLEvent(ref evnt);
}
diff --git a/src/Ryujinx.UI.Common/Configuration/AudioBackend.cs b/src/Ryujinx.UI.Common/Configuration/AudioBackend.cs
index 220e1e50c..aadbe33a6 100644
--- a/src/Ryujinx.UI.Common/Configuration/AudioBackend.cs
+++ b/src/Ryujinx.UI.Common/Configuration/AudioBackend.cs
@@ -8,6 +8,6 @@ namespace Ryujinx.UI.Common.Configuration
Dummy,
OpenAl,
SoundIo,
- SDL2,
+ SDL3,
}
}
diff --git a/src/Ryujinx.UI.Common/Configuration/ConfigurationState.cs b/src/Ryujinx.UI.Common/Configuration/ConfigurationState.cs
index 81b0bb232..44ba90ace 100644
--- a/src/Ryujinx.UI.Common/Configuration/ConfigurationState.cs
+++ b/src/Ryujinx.UI.Common/Configuration/ConfigurationState.cs
@@ -909,7 +909,7 @@ namespace Ryujinx.UI.Common.Configuration
System.EnableInternetAccess.Value = false;
System.EnableFsIntegrityChecks.Value = true;
System.FsGlobalAccessLogMode.Value = 0;
- System.AudioBackend.Value = AudioBackend.SDL2;
+ System.AudioBackend.Value = AudioBackend.SDL3;
System.AudioVolume.Value = 1;
System.MemoryManagerMode.Value = MemoryManagerMode.HostMappedUnsafe;
System.DramSize.Value = MemoryConfiguration.MemoryConfiguration4GiB;
diff --git a/src/Ryujinx/AppHost.cs b/src/Ryujinx/AppHost.cs
index f14f0efdc..b98435f55 100644
--- a/src/Ryujinx/AppHost.cs
+++ b/src/Ryujinx/AppHost.cs
@@ -6,7 +6,7 @@ using Avalonia.Threading;
using LibHac.Tools.FsSystem;
using Ryujinx.Audio.Backends.Dummy;
using Ryujinx.Audio.Backends.OpenAL;
-using Ryujinx.Audio.Backends.SDL2;
+using Ryujinx.Audio.Backends.SDL3;
using Ryujinx.Audio.Backends.SoundIo;
using Ryujinx.Audio.Integration;
using Ryujinx.Ava.Common;
@@ -945,7 +945,7 @@ namespace Ryujinx.Ava
{
var availableBackends = new List
{
- AudioBackend.SDL2,
+ AudioBackend.SDL3,
AudioBackend.SoundIo,
AudioBackend.OpenAl,
AudioBackend.Dummy,
@@ -984,7 +984,7 @@ namespace Ryujinx.Ava
deviceDriver = currentBackend switch
{
- AudioBackend.SDL2 => InitializeAudioBackend(AudioBackend.SDL2, nextBackend),
+ AudioBackend.SDL3 => InitializeAudioBackend(AudioBackend.SDL3, nextBackend),
AudioBackend.SoundIo => InitializeAudioBackend(AudioBackend.SoundIo, nextBackend),
AudioBackend.OpenAl => InitializeAudioBackend(AudioBackend.OpenAl, nextBackend),
_ => new DummyHardwareDeviceDriver(),
diff --git a/src/Ryujinx/Assets/Locales/ar_SA.json b/src/Ryujinx/Assets/Locales/ar_SA.json
index 57c0c4347..80703f323 100644
--- a/src/Ryujinx/Assets/Locales/ar_SA.json
+++ b/src/Ryujinx/Assets/Locales/ar_SA.json
@@ -153,7 +153,7 @@
"SettingsTabSystemAudioBackendDummy": "زائف",
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
- "SettingsTabSystemAudioBackendSDL2": "SDL2",
+ "SettingsTabSystemAudioBackendSDL3": "SDL3",
"SettingsTabSystemHacks": "هاكات",
"SettingsTabSystemHacksNote": "قد يتسبب في عدم الاستقرار",
"SettingsTabSystemDramSize": "استخدام تخطيط الذاكرة البديل (المطورين)",
@@ -594,7 +594,7 @@
"LowPowerPptcToggleTooltip": "قم بتحميل PPTC باستخدام ثلث كمية النوى",
"JitCacheEvictionToggleTooltip": "م بتمكين إخلاء JIT Cache لإدارة الذاكرة بكفاءة",
"FsIntegrityToggleTooltip": "يتحقق من وجود ملفات تالفة عند تشغيل لعبة ما، وإذا تم اكتشاف ملفات تالفة، فسيتم عرض خطأ تجزئة في السجل.\n\nليس له أي تأثير على الأداء ويهدف إلى المساعدة في استكشاف الأخطاء وإصلاحها.\n\nاتركه مفعلا إذا كنت غير متأكد.",
- "AudioBackendTooltip": "يغير الواجهة الخلفية المستخدمة لتقديم الصوت.\n\nSDL2 هو الخيار المفضل، بينما يتم استخدام OpenAL وSoundIO كبديلين. زائف لن يكون لها صوت.\n\nاضبط على SDL2 إذا لم تكن متأكدا.",
+ "AudioBackendTooltip": "يغير الواجهة الخلفية المستخدمة لتقديم الصوت.\n\nSDL3 هو الخيار المفضل، بينما يتم استخدام OpenAL وSoundIO كبديلين. زائف لن يكون لها صوت.\n\nاضبط على SDL3 إذا لم تكن متأكدا.",
"MemoryManagerTooltip": "تغيير كيفية تعيين ذاكرة الضيف والوصول إليها. يؤثر بشكل كبير على أداء وحدة المعالجة المركزية التي تمت محاكاتها.\n\nاضبط على المضيف غير محدد إذا لم تكن متأكدا.",
"MemoryManagerSoftwareTooltip": "استخدام جدول الصفحات البرمجي لترجمة العناوين. أعلى دقة ولكن أبطأ أداء.",
"MemoryManagerHostTooltip": "تعيين الذاكرة مباشرة في مساحة عنوان المضيف. تجميع وتنفيذ JIT أسرع بكثير.",
diff --git a/src/Ryujinx/Assets/Locales/de_DE.json b/src/Ryujinx/Assets/Locales/de_DE.json
index 8960387ab..57e0b0e81 100644
--- a/src/Ryujinx/Assets/Locales/de_DE.json
+++ b/src/Ryujinx/Assets/Locales/de_DE.json
@@ -154,7 +154,7 @@
"SettingsTabSystemAudioBackendDummy": "Ohne Funktion",
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
- "SettingsTabSystemAudioBackendSDL2": "SDL2",
+ "SettingsTabSystemAudioBackendSDL3": "SDL3",
"SettingsTabSystemHacks": "Hacks",
"SettingsTabSystemHacksNote": " (Kann Fehler verursachen)",
"SettingsTabSystemDramSize": "DRAM Größe:",
@@ -595,7 +595,7 @@
"LowPowerPptcToggleTooltip": "Lädt den PPTC mit einem Drittel der verfügbaren Prozessorkernen",
"JitCacheEvictionToggleTooltip": "Aktivieren Sie die JIT-Cache-Eviction, um den Speicher effizient zu verwalten",
"FsIntegrityToggleTooltip": "Prüft beim Startvorgang auf beschädigte Dateien und zeigt bei beschädigten Dateien einen Hash-Fehler (Hash Error) im Log an.\n\nDiese Einstellung hat keinen Einfluss auf die Leistung und hilft bei der Fehlersuche.\n\nIm Zweifelsfall AN lassen.",
- "AudioBackendTooltip": "Ändert das Backend, das zum Rendern von Audio verwendet wird.\n\nSDL2 ist das bevorzugte Audio-Backend, OpenAL und SoundIO sind als Alternativen vorhanden. Dummy wird keinen Audio-Output haben.\n\nIm Zweifelsfall SDL2 auswählen.",
+ "AudioBackendTooltip": "Ändert das Backend, das zum Rendern von Audio verwendet wird.\n\nSDL3 ist das bevorzugte Audio-Backend, OpenAL und SoundIO sind als Alternativen vorhanden. Dummy wird keinen Audio-Output haben.\n\nIm Zweifelsfall SDL3 auswählen.",
"MemoryManagerTooltip": "Ändert wie der Gastspeicher abgebildet wird und wie auf ihn zugegriffen wird. Beinflusst die Leistung der emulierten CPU erheblich.\n\nIm Zweifelsfall Host ungeprüft auswählen.",
"MemoryManagerSoftwareTooltip": "Verwendung einer Software-Seitentabelle für die Adressumsetzung. Höchste Genauigkeit, aber langsamste Leistung.",
"MemoryManagerHostTooltip": "Direkte Zuordnung von Speicher im Host-Adressraum. Viel schnellere JIT-Kompilierung und Ausführung.",
diff --git a/src/Ryujinx/Assets/Locales/el_GR.json b/src/Ryujinx/Assets/Locales/el_GR.json
index 8d943352f..d8db1e931 100644
--- a/src/Ryujinx/Assets/Locales/el_GR.json
+++ b/src/Ryujinx/Assets/Locales/el_GR.json
@@ -153,7 +153,7 @@
"SettingsTabSystemAudioBackendDummy": "Απενεργοποιημένο",
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
- "SettingsTabSystemAudioBackendSDL2": "SDL2",
+ "SettingsTabSystemAudioBackendSDL3": "SDL3",
"SettingsTabSystemHacks": "Μικροδιορθώσεις",
"SettingsTabSystemHacksNote": " (Μπορεί να προκαλέσουν αστάθεια)",
"SettingsTabSystemDramSize": "Μέγεθος DRAM:",
diff --git a/src/Ryujinx/Assets/Locales/en_US.json b/src/Ryujinx/Assets/Locales/en_US.json
index 1f4e5ada6..56ad0c840 100644
--- a/src/Ryujinx/Assets/Locales/en_US.json
+++ b/src/Ryujinx/Assets/Locales/en_US.json
@@ -174,7 +174,7 @@
"SettingsTabSystemAudioBackendDummy": "Dummy",
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
- "SettingsTabSystemAudioBackendSDL2": "SDL2",
+ "SettingsTabSystemAudioBackendSDL3": "SDL3",
"SettingsTabSystemCustomVSyncInterval": "Interval",
"SettingsTabSystemHacks": "Hacks",
"SettingsTabSystemHacksNote": "May cause instability",
@@ -626,7 +626,7 @@
"LowPowerPptcToggleTooltip": "Load the PPTC using a third of the amount of cores",
"JitCacheEvictionToggleTooltip": "Enable JIT Cache eviction to manage memory efficiently",
"FsIntegrityToggleTooltip": "Checks for corrupt files when booting a game, and if corrupt files are detected, displays a hash error in the log.\n\nHas no impact on performance and is meant to help troubleshooting.\n\nLeave ON if unsure.",
- "AudioBackendTooltip": "Changes the backend used to render audio.\n\nSDL2 is the preferred one, while OpenAL and SoundIO are used as fallbacks. Dummy will have no sound.\n\nSet to SDL2 if unsure.",
+ "AudioBackendTooltip": "Changes the backend used to render audio.\n\nSDL3 is the preferred one, while OpenAL and SoundIO are used as fallbacks. Dummy will have no sound.\n\nSet to SDL3 if unsure.",
"MemoryManagerTooltip": "Change how guest memory is mapped and accessed. Greatly affects emulated CPU performance.\n\nSet to HOST UNCHECKED if unsure.",
"MemoryManagerSoftwareTooltip": "Use a software page table for address translation. Highest accuracy but slowest performance.",
"MemoryManagerHostTooltip": "Directly map memory in the host address space. Much faster JIT compilation and execution.",
diff --git a/src/Ryujinx/Assets/Locales/es_ES.json b/src/Ryujinx/Assets/Locales/es_ES.json
index ee5052302..e2a87015d 100644
--- a/src/Ryujinx/Assets/Locales/es_ES.json
+++ b/src/Ryujinx/Assets/Locales/es_ES.json
@@ -153,7 +153,7 @@
"SettingsTabSystemAudioBackendDummy": "Vacio",
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
- "SettingsTabSystemAudioBackendSDL2": "SDL2",
+ "SettingsTabSystemAudioBackendSDL3": "SDL3",
"SettingsTabSystemHacks": "Hacks",
"SettingsTabSystemHacksNote": " (Pueden causar inestabilidad)",
"SettingsTabSystemDramSize": "Tamaño DRAM:",
@@ -594,7 +594,7 @@
"LowPowerPptcToggleTooltip": "Cargue el PPTC usando un tercio de la cantidad de núcleos",
"JitCacheEvictionToggleTooltip": "Habilite el desalojo de JIT Cache para administrar la memoria de manera eficiente",
"FsIntegrityToggleTooltip": "Comprueba si hay archivos corruptos en los juegos que ejecutes al abrirlos, y si detecta archivos corruptos, muestra un error de Hash en los registros.\n\nEsto no tiene impacto alguno en el rendimiento y está pensado para ayudar a resolver problemas.\n\nActívalo si no sabes qué hacer.",
- "AudioBackendTooltip": "Cambia el motor usado para renderizar audio.\n\nSDL2 es el preferido, mientras que OpenAL y SoundIO se usan si hay problemas con este. Dummy no produce audio.\n\nSelecciona SDL2 si no sabes qué hacer.",
+ "AudioBackendTooltip": "Cambia el motor usado para renderizar audio.\n\nSDL3 es el preferido, mientras que OpenAL y SoundIO se usan si hay problemas con este. Dummy no produce audio.\n\nSelecciona SDL3 si no sabes qué hacer.",
"MemoryManagerTooltip": "Cambia la forma de mapear y acceder a la memoria del guest. Afecta en gran medida al rendimiento de la CPU emulada.\n\nSelecciona \"Host sin verificación\" si no sabes qué hacer.",
"MemoryManagerSoftwareTooltip": "Usa una tabla de paginación de software para traducir direcciones. Ofrece la precisión más exacta pero el rendimiento más lento.",
"MemoryManagerHostTooltip": "Mapea la memoria directamente en la dirección de espacio del host. Compilación y ejecución JIT mucho más rápida.",
diff --git a/src/Ryujinx/Assets/Locales/fr_FR.json b/src/Ryujinx/Assets/Locales/fr_FR.json
index 535f1d904..364a03fa1 100644
--- a/src/Ryujinx/Assets/Locales/fr_FR.json
+++ b/src/Ryujinx/Assets/Locales/fr_FR.json
@@ -155,7 +155,7 @@
"SettingsTabSystemAudioBackendDummy": "Factice",
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
- "SettingsTabSystemAudioBackendSDL2": "SDL2",
+ "SettingsTabSystemAudioBackendSDL3": "SDL3",
"SettingsTabSystemHacks": "Hacks",
"SettingsTabSystemHacksNote": "Cela peut causer des instabilités",
"SettingsTabSystemDramSize": "Utiliser disposition alternative de la mémoire (développeur)",
@@ -597,7 +597,7 @@
"LowPowerPptcToggleTooltip": "Chargez le PPTC en utilisant un tiers de la quantité de cœurs",
"JitCacheEvictionToggleTooltip": "Activer l'expulsion du cache JIT pour gérer efficacement la mémoire",
"FsIntegrityToggleTooltip": "Vérifie si des fichiers sont corrompus lors du lancement d'un jeu, et si des fichiers corrompus sont détectés, affiche une erreur de hachage dans la console.\n\nN'a aucun impact sur les performances et est destiné à aider le dépannage.\n\nLaissez activer en cas d'incertitude.",
- "AudioBackendTooltip": "Modifie le backend utilisé pour donnée un rendu audio.\n\nSDL2 est préféré, tandis que OpenAL et SoundIO sont utilisés comme backend secondaire. Le backend Dummy (Factice) ne rends aucun son.\n\nLaissez sur SDL2 si vous n'êtes pas sûr.",
+ "AudioBackendTooltip": "Modifie le backend utilisé pour donnée un rendu audio.\n\nSDL3 est préféré, tandis que OpenAL et SoundIO sont utilisés comme backend secondaire. Le backend Dummy (Factice) ne rends aucun son.\n\nLaissez sur SDL3 si vous n'êtes pas sûr.",
"MemoryManagerTooltip": "Change la façon dont la mémoire émulée est mappée et utiliser. Cela affecte grandement les performances du processeur.\n\nRéglez sur Host Uncheked en cas d'incertitude.",
"MemoryManagerSoftwareTooltip": "Utilisez une table logicielle pour la traduction d'adresses. La plus grande précision est fournie, mais les performances en seront impacter.",
"MemoryManagerHostTooltip": "Mappez directement la mémoire dans l'espace d'adresses de l'hôte. Compilation et exécution JIT beaucoup plus rapides.",
diff --git a/src/Ryujinx/Assets/Locales/he_IL.json b/src/Ryujinx/Assets/Locales/he_IL.json
index f50acba27..c36304d04 100644
--- a/src/Ryujinx/Assets/Locales/he_IL.json
+++ b/src/Ryujinx/Assets/Locales/he_IL.json
@@ -153,7 +153,7 @@
"SettingsTabSystemAudioBackendDummy": "גולם",
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
- "SettingsTabSystemAudioBackendSDL2": "SDL2",
+ "SettingsTabSystemAudioBackendSDL3": "SDL3",
"SettingsTabSystemHacks": "האצות",
"SettingsTabSystemHacksNote": "עלול לגרום לאי יציבות",
"SettingsTabSystemDramSize": "השתמש בפריסת זיכרון חלופית (נועד למפתחים)",
@@ -594,7 +594,7 @@
"LowPowerPptcToggleTooltip": "טען את ה-PPTC באמצעות שליש מכמות הליבות",
"JitCacheEvictionToggleTooltip": "אפשר פינוי JIT Cache לניהול זיכרון ביעילות",
"FsIntegrityToggleTooltip": "בודק לקבצים שגויים כאשר משחק עולה, ואם מתגלים כאלו, מציג את מזהה השגיאה שלהם לקובץ הלוג.\n\nאין לכך השפעה על הביצועים ונועד לעזור לבדיקה וניפוי שגיאות של האמולטור.\n\nמוטב להשאיר דלוק אם לא בטוחים.",
- "AudioBackendTooltip": "משנה את אחראי השמע.\n\nSDL2 הוא הנבחר, למראת שOpenAL וגם SoundIO משומשים כאפשרויות חלופיות. אפשרות הDummy לא תשמיע קול כלל.\n\nמוטב להשאיר על SDL2 אם לא בטוחים.",
+ "AudioBackendTooltip": "משנה את אחראי השמע.\n\nSDL3 הוא הנבחר, למראת שOpenAL וגם SoundIO משומשים כאפשרויות חלופיות. אפשרות הDummy לא תשמיע קול כלל.\n\nמוטב להשאיר על SDL3 אם לא בטוחים.",
"MemoryManagerTooltip": "שנה איך שזיכרון מארח מיוחד ומונגד. משפיע מאוד על ביצועי המעבד המדומה.\n\nמוטב להשאיר על מארח לא מבוקר אם לא בטוחים.",
"MemoryManagerSoftwareTooltip": "השתמש בתוכנת ה-page table בכדי להתייחס לתרגומים. דיוק מרבי לקונסולה אך המימוש הכי איטי.",
"MemoryManagerHostTooltip": "ממפה זיכרון ישירות לכתובת המארח. מהיר בהרבה ביכולות קימפול ה-JIT והריצה.",
diff --git a/src/Ryujinx/Assets/Locales/it_IT.json b/src/Ryujinx/Assets/Locales/it_IT.json
index 44ed32081..d90c6f8c3 100644
--- a/src/Ryujinx/Assets/Locales/it_IT.json
+++ b/src/Ryujinx/Assets/Locales/it_IT.json
@@ -153,7 +153,7 @@
"SettingsTabSystemAudioBackendDummy": "Dummy",
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
- "SettingsTabSystemAudioBackendSDL2": "SDL2",
+ "SettingsTabSystemAudioBackendSDL3": "SDL3",
"SettingsTabSystemHacks": "Espedienti",
"SettingsTabSystemHacksNote": "Possono causare instabilità",
"SettingsTabSystemDramSize": "Usa layout di memoria alternativo (per sviluppatori)",
@@ -595,7 +595,7 @@
"LowPowerPptcToggleTooltip": "Carica il PPTC utilizzando un terzo della quantità di core",
"JitCacheEvictionToggleTooltip": "Abilita l'eliminazione della cache JIT per gestire la memoria in modo efficiente",
"FsIntegrityToggleTooltip": "Controlla la presenza di file corrotti quando si avvia un gioco. Se vengono rilevati dei file corrotti, verrà mostrato un errore di hash nel log.\n\nQuesta opzione non influisce sulle prestazioni ed è pensata per facilitare la risoluzione dei problemi.\n\nNel dubbio, lascia l'opzione attiva.",
- "AudioBackendTooltip": "Cambia il backend usato per riprodurre l'audio.\n\nSDL2 è quello preferito, mentre OpenAL e SoundIO sono usati come ripiego. Dummy non riprodurrà alcun suono.\n\nNel dubbio, imposta l'opzione su SDL2.",
+ "AudioBackendTooltip": "Cambia il backend usato per riprodurre l'audio.\n\nSDL3 è quello preferito, mentre OpenAL e SoundIO sono usati come ripiego. Dummy non riprodurrà alcun suono.\n\nNel dubbio, imposta l'opzione su SDL3.",
"MemoryManagerTooltip": "Cambia il modo in cui la memoria guest è mappata e vi si accede. Influisce notevolmente sulle prestazioni della CPU emulata.\n\nNel dubbio, imposta l'opzione su Host Unchecked.",
"MemoryManagerSoftwareTooltip": "Usa una software page table per la traduzione degli indirizzi. Massima precisione ma prestazioni più lente.",
"MemoryManagerHostTooltip": "Mappa direttamente la memoria nello spazio degli indirizzi dell'host. Compilazione ed esecuzione JIT molto più veloce.",
diff --git a/src/Ryujinx/Assets/Locales/ja_JP.json b/src/Ryujinx/Assets/Locales/ja_JP.json
index bc68a8aa1..dee8f66e6 100644
--- a/src/Ryujinx/Assets/Locales/ja_JP.json
+++ b/src/Ryujinx/Assets/Locales/ja_JP.json
@@ -153,7 +153,7 @@
"SettingsTabSystemAudioBackendDummy": "ダミー",
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
- "SettingsTabSystemAudioBackendSDL2": "SDL2",
+ "SettingsTabSystemAudioBackendSDL3": "SDL3",
"SettingsTabSystemHacks": "ハック",
"SettingsTabSystemHacksNote": " (挙動が不安定になる可能性があります)",
"SettingsTabSystemDramSize": "DRAMサイズ:",
@@ -594,7 +594,7 @@
"LowPowerPptcToggleTooltip": "コア数の 3 分の 1 を使用して PPTC をロードします。",
"JitCacheEvictionToggleTooltip": "JIT キャッシュのエビクションを有効にしてメモリを効率的に管理する",
"FsIntegrityToggleTooltip": "ゲーム起動時にファイル破損をチェックし,破損が検出されたらログにハッシュエラーを表示します..\n\nパフォーマンスには影響なく, トラブルシューティングに役立ちます.\n\nよくわからない場合はオンのままにしてください.",
- "AudioBackendTooltip": "音声レンダリングに使用するバックエンドを変更します.\n\nSDL2 が優先され, OpenAL と SoundIO はフォールバックとして使用されます. ダミーは音声出力しません.\n\nよくわからない場合は SDL2 を設定してください.",
+ "AudioBackendTooltip": "音声レンダリングに使用するバックエンドを変更します.\n\nSDL3 が優先され, OpenAL と SoundIO はフォールバックとして使用されます. ダミーは音声出力しません.\n\nよくわからない場合は SDL3 を設定してください.",
"MemoryManagerTooltip": "ゲストメモリのマップ/アクセス方式を変更します. エミュレートされるCPUのパフォーマンスに大きな影響を与えます.\n\nよくわからない場合は「ホスト,チェックなし」を設定してください.",
"MemoryManagerSoftwareTooltip": "アドレス変換にソフトウェアページテーブルを使用します. 非常に正確ですがパフォーマンスが大きく低下します.",
"MemoryManagerHostTooltip": "ホストのアドレス空間にメモリを直接マップします.JITのコンパイルと実行速度が大きく向上します.",
diff --git a/src/Ryujinx/Assets/Locales/ko_KR.json b/src/Ryujinx/Assets/Locales/ko_KR.json
index 63e85afc6..926eb545f 100644
--- a/src/Ryujinx/Assets/Locales/ko_KR.json
+++ b/src/Ryujinx/Assets/Locales/ko_KR.json
@@ -156,7 +156,7 @@
"SettingsTabSystemAudioBackendDummy": "더미",
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
"SettingsTabSystemAudioBackendSoundIO": "사운드IO",
- "SettingsTabSystemAudioBackendSDL2": "SDL2",
+ "SettingsTabSystemAudioBackendSDL3": "SDL3",
"SettingsTabSystemHacks": "해킹",
"SettingsTabSystemHacksNote": "불안정성을 유발할 수 있음",
"SettingsTabSystemDramSize": "대체 메모리 레이아웃 사용(개발자)",
@@ -598,7 +598,7 @@
"LowPowerPptcToggleTooltip": "코어 양의 1/3을 사용하여 PPTC를 로드합니다.",
"JitCacheEvictionToggleTooltip": "메모리를 효율적으로 관리하기 위해 JIT 캐시 제거를 활성화합니다.",
"FsIntegrityToggleTooltip": "게임을 부팅할 때 손상된 파일을 확인하고 손상된 파일이 감지되면 로그에 해시 오류를 표시합니다.\n\n성능에 영향을 미치지 않으며 문제 해결에 도움이 됩니다.\n\n확실하지 않으면 켜 두세요.",
- "AudioBackendTooltip": "오디오를 렌더링하는 데 사용되는 백엔드를 변경합니다.\n\nSDL2가 선호되는 반면 OpenAL 및 사운드IO는 폴백으로 사용됩니다. 더미는 소리가 나지 않습니다.\n\n확실하지 않으면 SDL2로 설정하세요.",
+ "AudioBackendTooltip": "오디오를 렌더링하는 데 사용되는 백엔드를 변경합니다.\n\nSDL3가 선호되는 반면 OpenAL 및 사운드IO는 폴백으로 사용됩니다. 더미는 소리가 나지 않습니다.\n\n확실하지 않으면 SDL3로 설정하세요.",
"MemoryManagerTooltip": "게스트 메모리가 매핑되고 접속되는 방식을 변경합니다. 에뮬레이트된 CPU 성능에 크게 영향을 미칩니다.\n\n확실하지 않은 경우 호스트 확인 안함으로 설정하세요.",
"MemoryManagerSoftwareTooltip": "주소 변환을 위해 소프트웨어 페이지 테이블을 사용하세요. 정확도는 가장 높지만 성능은 가장 느립니다.",
"MemoryManagerHostTooltip": "호스트 주소 공간의 메모리를 직접 매핑합니다. 훨씬 빠른 JIT 컴파일 및 실행합니다.",
diff --git a/src/Ryujinx/Assets/Locales/pl_PL.json b/src/Ryujinx/Assets/Locales/pl_PL.json
index c716c00e5..2be362eb8 100644
--- a/src/Ryujinx/Assets/Locales/pl_PL.json
+++ b/src/Ryujinx/Assets/Locales/pl_PL.json
@@ -153,7 +153,7 @@
"SettingsTabSystemAudioBackendDummy": "Atrapa",
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
- "SettingsTabSystemAudioBackendSDL2": "SDL2",
+ "SettingsTabSystemAudioBackendSDL3": "SDL3",
"SettingsTabSystemHacks": "Hacki",
"SettingsTabSystemHacksNote": " (mogą powodować niestabilność)",
"SettingsTabSystemDramSize": "Użyj alternatywnego układu pamięci (Deweloperzy)",
@@ -594,7 +594,7 @@
"LowPowerPptcToggleTooltip": "Załaduj PPTC, używając jednej trzeciej liczby rdzeni",
"JitCacheEvictionToggleTooltip": "Włącz eksmisję pamięci podręcznej JIT, aby efektywnie zarządzać pamięcią",
"FsIntegrityToggleTooltip": "Sprawdza pliki podczas uruchamiania gry i jeśli zostaną wykryte uszkodzone pliki, wyświetla w dzienniku błąd hash.\n\nNie ma wpływu na wydajność i ma pomóc w rozwiązywaniu problemów.\n\nPozostaw WŁĄCZONE, jeśli nie masz pewności.",
- "AudioBackendTooltip": "Zmienia backend używany do renderowania dźwięku.\n\nSDL2 jest preferowany, podczas gdy OpenAL i SoundIO są używane jako rezerwy. Dummy nie będzie odtwarzać dźwięku.\n\nW razie wątpliwości ustaw SDL2.",
+ "AudioBackendTooltip": "Zmienia backend używany do renderowania dźwięku.\n\nSDL3 jest preferowany, podczas gdy OpenAL i SoundIO są używane jako rezerwy. Dummy nie będzie odtwarzać dźwięku.\n\nW razie wątpliwości ustaw SDL3.",
"MemoryManagerTooltip": "Zmień sposób mapowania i uzyskiwania dostępu do pamięci gości. Znacznie wpływa na wydajność emulowanego procesora.\n\nUstaw na HOST UNCHECKED, jeśli nie masz pewności.",
"MemoryManagerSoftwareTooltip": "Użyj tabeli stron oprogramowania do translacji adresów. Najwyższa celność, ale najwolniejsza wydajność.",
"MemoryManagerHostTooltip": "Bezpośrednio mapuj pamięć w przestrzeni adresowej hosta. Znacznie szybsza kompilacja i wykonanie JIT.",
diff --git a/src/Ryujinx/Assets/Locales/pt_BR.json b/src/Ryujinx/Assets/Locales/pt_BR.json
index 10f0a2bac..a9f457beb 100644
--- a/src/Ryujinx/Assets/Locales/pt_BR.json
+++ b/src/Ryujinx/Assets/Locales/pt_BR.json
@@ -156,7 +156,7 @@
"SettingsTabSystemAudioBackendDummy": "Nenhuma",
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
- "SettingsTabSystemAudioBackendSDL2": "SDL2",
+ "SettingsTabSystemAudioBackendSDL3": "SDL3",
"SettingsTabSystemHacks": "Hacks",
"SettingsTabSystemHacksNote": " (Pode causar instabilidade)",
"SettingsTabSystemDramSize": "Tamanho da DRAM:",
diff --git a/src/Ryujinx/Assets/Locales/ru_RU.json b/src/Ryujinx/Assets/Locales/ru_RU.json
index 51b48ca93..ee72d4555 100644
--- a/src/Ryujinx/Assets/Locales/ru_RU.json
+++ b/src/Ryujinx/Assets/Locales/ru_RU.json
@@ -174,7 +174,7 @@
"SettingsTabSystemAudioBackendDummy": "Без звука",
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
- "SettingsTabSystemAudioBackendSDL2": "SDL2",
+ "SettingsTabSystemAudioBackendSDL3": "SDL3",
"SettingsTabSystemCustomVSyncInterval": "Интервал",
"SettingsTabSystemHacks": "Хаки",
"SettingsTabSystemHacksNote": "Возможна нестабильная работа",
@@ -625,7 +625,7 @@
"LowPowerPptcToggleTooltip": "Загружает PPTC, используя треть от количества ядер.",
"JitCacheEvictionToggleTooltip": "Включите вытеснение JIT-кэша для эффективного управления памятью.",
"FsIntegrityToggleTooltip": "Проверяет файлы при загрузке игры и если обнаружены поврежденные файлы, выводит сообщение о поврежденном хэше в журнале.\n\nНе влияет на производительность и необходим для помощи в устранении неполадок.\n\nРекомендуется оставить включенным.",
- "AudioBackendTooltip": "Изменяет используемый аудио бэкенд для рендера звука.\n\nSDL2 является предпочтительным вариантом, в то время как OpenAL и SoundIO используются в качестве резервных.\n\nРекомендуется использование SDL2.",
+ "AudioBackendTooltip": "Изменяет используемый аудио бэкенд для рендера звука.\n\nSDL3 является предпочтительным вариантом, в то время как OpenAL и SoundIO используются в качестве резервных.\n\nРекомендуется использование SDL3.",
"MemoryManagerTooltip": "Меняет разметку и доступ к гостевой памяти. Значительно влияет на производительность процессора.\n\nРекомендуется оставить \"Хост не установлен\"",
"MemoryManagerSoftwareTooltip": "Использует таблицу страниц для преобразования адресов. \nСамая высокая точность, но самая низкая производительность.",
"MemoryManagerHostTooltip": "Прямая разметка памяти в адресном пространстве хоста. \nЗначительно более быстрые запуск и компиляция JIT.",
diff --git a/src/Ryujinx/Assets/Locales/th_TH.json b/src/Ryujinx/Assets/Locales/th_TH.json
index 64b4b556c..4701b917c 100644
--- a/src/Ryujinx/Assets/Locales/th_TH.json
+++ b/src/Ryujinx/Assets/Locales/th_TH.json
@@ -153,7 +153,7 @@
"SettingsTabSystemAudioBackendDummy": "Dummy",
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
- "SettingsTabSystemAudioBackendSDL2": "SDL2",
+ "SettingsTabSystemAudioBackendSDL3": "SDL3",
"SettingsTabSystemHacks": "แฮ็ก",
"SettingsTabSystemHacksNote": "อาจทำให้เกิดข้อผิดพลาดได้",
"SettingsTabSystemDramSize": "ใช้รูปแบบหน่วยความจำสำรอง (โหมดนักพัฒนา)",
@@ -594,7 +594,7 @@
"LowPowerPptcToggleTooltip": "โหลด PPTC โดยใช้หนึ่งในสามของจำนวนคอร์",
"JitCacheEvictionToggleTooltip": "เปิดใช้งานการขับไล่ JIT Cache เพื่อจัดการหน่วยความจำอย่างมีประสิทธิภาพ",
"FsIntegrityToggleTooltip": "ตรวจสอบไฟล์ที่เสียหายเมื่อบูตเกม และหากตรวจพบไฟล์ที่เสียหาย จะแสดงข้อผิดพลาดของแฮชในบันทึก\n\nไม่มีผลกระทบต่อประสิทธิภาพการทำงานและมีไว้เพื่อช่วยในการแก้ไขปัญหา\n\nปล่อยไว้หากคุณไม่แน่ใจ",
- "AudioBackendTooltip": "เปลี่ยนแบ็กเอนด์ที่ใช้ในการเรนเดอร์เสียง\n\nSDL2 เป็นที่ต้องการ ในขณะที่ OpenAL และ SoundIO ถูกใช้เป็นทางเลือกสำรอง ดัมมี่จะไม่มีเสียง\n\nปล่อยไว้หากคุณไม่แน่ใจ",
+ "AudioBackendTooltip": "เปลี่ยนแบ็กเอนด์ที่ใช้ในการเรนเดอร์เสียง\n\nSDL3 เป็นที่ต้องการ ในขณะที่ OpenAL และ SoundIO ถูกใช้เป็นทางเลือกสำรอง ดัมมี่จะไม่มีเสียง\n\nปล่อยไว้หากคุณไม่แน่ใจ",
"MemoryManagerTooltip": "เปลี่ยนวิธีการแมปและเข้าถึงหน่วยความจำของผู้เยี่ยมชม ส่งผลอย่างมากต่อประสิทธิภาพการทำงานของ CPU ที่จำลอง\n\nตั้งค่าเป็น ไม่ทำการตรวจสอบ โฮสต์ หากคุณไม่แน่ใจ",
"MemoryManagerSoftwareTooltip": "ใช้ตารางหน้าซอฟต์แวร์สำหรับการแปลที่อยู่ ความแม่นยำสูงสุดแต่ประสิทธิภาพช้าที่สุด",
"MemoryManagerHostTooltip": "แมปหน่วยความจำในพื้นที่ที่อยู่โฮสต์โดยตรง การคอมไพล์และดำเนินการ JIT เร็วขึ้นมาก",
diff --git a/src/Ryujinx/Assets/Locales/tr_TR.json b/src/Ryujinx/Assets/Locales/tr_TR.json
index 5d7554f49..690effb09 100644
--- a/src/Ryujinx/Assets/Locales/tr_TR.json
+++ b/src/Ryujinx/Assets/Locales/tr_TR.json
@@ -153,7 +153,7 @@
"SettingsTabSystemAudioBackendDummy": "Yapay",
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
- "SettingsTabSystemAudioBackendSDL2": "SDL2",
+ "SettingsTabSystemAudioBackendSDL3": "SDL3",
"SettingsTabSystemHacks": "Hack'ler",
"SettingsTabSystemHacksNote": " (dengesizlik oluşturabilir)",
"SettingsTabSystemDramSize": "Alternatif bellek düzeni kullan (Geliştirici)",
@@ -594,7 +594,7 @@
"LowPowerPptcToggleTooltip": "Çekirdek miktarının üçte birini kullanarak PPTC'yi yükleyin",
"JitCacheEvictionToggleTooltip": "Belleği verimli bir şekilde yönetmek için JIT Önbellek tahliyesini etkinleştirin",
"FsIntegrityToggleTooltip": "Oyun açarken hatalı dosyaların olup olmadığını kontrol eder, ve hatalı dosya bulursa log dosyasında hash hatası görüntüler.\n\nPerformansa herhangi bir etkisi yoktur ve sorun gidermeye yardımcı olur.\n\nEmin değilseniz aktif halde bırakın.",
- "AudioBackendTooltip": "Ses çıkış motorunu değiştirir.\n\nSDL2 tercih edilen seçenektir, OpenAL ve SoundIO ise alternatif olarak kullanılabilir. Dummy seçeneğinde ses çıkışı olmayacaktır.\n\nEmin değilseniz SDL2 seçeneğine ayarlayın.",
+ "AudioBackendTooltip": "Ses çıkış motorunu değiştirir.\n\nSDL3 tercih edilen seçenektir, OpenAL ve SoundIO ise alternatif olarak kullanılabilir. Dummy seçeneğinde ses çıkışı olmayacaktır.\n\nEmin değilseniz SDL3 seçeneğine ayarlayın.",
"MemoryManagerTooltip": "Guest hafızasının nasıl tahsis edilip erişildiğini değiştirir. Emüle edilen CPU performansını ciddi biçimde etkiler.\n\nEmin değilseniz HOST UNCHECKED seçeneğine ayarlayın.",
"MemoryManagerSoftwareTooltip": "Adres çevirisi için bir işlemci sayfası kullanır. En yüksek doğruluğu ve en yavaş performansı sunar.",
"MemoryManagerHostTooltip": "Hafızayı doğrudan host adres aralığında tahsis eder. Çok daha hızlı JIT derleme ve işletimi sunar.",
diff --git a/src/Ryujinx/Assets/Locales/uk_UA.json b/src/Ryujinx/Assets/Locales/uk_UA.json
index 5a5dec26a..58fbd3126 100644
--- a/src/Ryujinx/Assets/Locales/uk_UA.json
+++ b/src/Ryujinx/Assets/Locales/uk_UA.json
@@ -156,7 +156,7 @@
"SettingsTabSystemAudioBackendDummy": "Dummy",
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
- "SettingsTabSystemAudioBackendSDL2": "SDL2",
+ "SettingsTabSystemAudioBackendSDL3": "SDL3",
"SettingsTabSystemHacks": "Хитрощі",
"SettingsTabSystemHacksNote": " (може викликати нестабільність)",
"SettingsTabSystemDramSize": "Використовувати альтернативне розташування пам'яті (розробники)",
@@ -598,7 +598,7 @@
"LowPowerPptcToggleTooltip": "Завантажте PPTC, використовуючи третину кількості ядер",
"JitCacheEvictionToggleTooltip": "Увімкніть видалення кешу JIT для ефективного керування пам’яттю",
"FsIntegrityToggleTooltip": "Перевіряє наявність пошкоджених файлів під час завантаження гри, і якщо виявлено пошкоджені файли, показує помилку хешу в журналі.\n\nНе впливає на продуктивність і призначений для усунення несправностей.\n\nЗалиште увімкненим, якщо не впевнені.",
- "AudioBackendTooltip": "Змінює серверну частину, яка використовується для відтворення аудіо.\n\nSDL2 є кращим, тоді як OpenAL і SoundIO використовуються як резервні варіанти. Dummy не матиме звуку.\n\nВстановіть SDL2, якщо не впевнені.",
+ "AudioBackendTooltip": "Змінює серверну частину, яка використовується для відтворення аудіо.\n\nSDL3 є кращим, тоді як OpenAL і SoundIO використовуються як резервні варіанти. Dummy не матиме звуку.\n\nВстановіть SDL3, якщо не впевнені.",
"MemoryManagerTooltip": "Змінює спосіб відображення та доступу до гостьової пам’яті. Значно впливає на продуктивність емульованого ЦП.\n\nВстановіть «Неперевірений хост», якщо не впевнені.",
"MemoryManagerSoftwareTooltip": "Використовує програмну таблицю сторінок для перекладу адрес. Найвища точність, але найповільніша продуктивність.",
"MemoryManagerHostTooltip": "Пряме відображення пам'яті в адресному просторі хосту. Набагато швидша компіляція та виконання JIT.",
diff --git a/src/Ryujinx/Assets/Locales/zh_CN.json b/src/Ryujinx/Assets/Locales/zh_CN.json
index de41fbbca..09ece3c8c 100644
--- a/src/Ryujinx/Assets/Locales/zh_CN.json
+++ b/src/Ryujinx/Assets/Locales/zh_CN.json
@@ -156,7 +156,7 @@
"SettingsTabSystemAudioBackendDummy": "无",
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
- "SettingsTabSystemAudioBackendSDL2": "SDL2",
+ "SettingsTabSystemAudioBackendSDL3": "SDL3",
"SettingsTabSystemHacks": "修改",
"SettingsTabSystemHacksNote": "会导致模拟器不稳定",
"SettingsTabSystemDramSize": "使用开发机的内存布局(开发人员使用)",
@@ -598,7 +598,7 @@
"LowPowerPptcToggleTooltip": "使用三分之一的核心数量加载 PPTC",
"JitCacheEvictionToggleTooltip": "启用 JIT 缓存驱逐以有效管理内存",
"FsIntegrityToggleTooltip": "启动游戏时检查游戏文件的完整性,并在日志中记录损坏的文件。\n\n对性能没有影响,用于排查故障。\n\n如果不确定,请保持开启状态。",
- "AudioBackendTooltip": "更改音频处理引擎。\n\n推荐选择“SDL2”,另外“OpenAL”和“SoundIO”可以作为备选,选择“无”将没有声音。\n\n如果不确定,请设置为“SDL2”。",
+ "AudioBackendTooltip": "更改音频处理引擎。\n\n推荐选择“SDL3”,另外“OpenAL”和“SoundIO”可以作为备选,选择“无”将没有声音。\n\n如果不确定,请设置为“SDL3”。",
"MemoryManagerTooltip": "更改模拟器内存映射和访问的方式,对模拟器 CPU 的性能影响很大。\n\n如果不确定,请设置为“跳过检查的本机映射”。",
"MemoryManagerSoftwareTooltip": "使用软件内存页进行内存地址映射,最准确但是速度最慢。",
"MemoryManagerHostTooltip": "直接映射内存页到电脑内存,使得即时编译和执行的效率更高。",
diff --git a/src/Ryujinx/Assets/Locales/zh_TW.json b/src/Ryujinx/Assets/Locales/zh_TW.json
index bcbdac5ef..cb738920b 100644
--- a/src/Ryujinx/Assets/Locales/zh_TW.json
+++ b/src/Ryujinx/Assets/Locales/zh_TW.json
@@ -156,7 +156,7 @@
"SettingsTabSystemAudioBackendDummy": "虛設 (Dummy)",
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
- "SettingsTabSystemAudioBackendSDL2": "SDL2",
+ "SettingsTabSystemAudioBackendSDL3": "SDL3",
"SettingsTabSystemHacks": "補釘修正",
"SettingsTabSystemHacksNote": "可能導致模擬器不穩定",
"SettingsTabSystemDramSize": "使用替代的記憶體配置 (開發者專用)",
@@ -598,7 +598,7 @@
"LowPowerPptcToggleTooltip": "使用三分之一的核心數量加載 PPTC",
"JitCacheEvictionToggleTooltip": "啟用 JIT 快取驅逐以有效管理內存",
"FsIntegrityToggleTooltip": "在啟動遊戲時檢查損壞的檔案,如果檢測到損壞的檔案,則在日誌中顯示雜湊值錯誤。\n\n對效能沒有影響,旨在幫助排除故障。\n\n如果不確定,請保持開啟狀態。",
- "AudioBackendTooltip": "變更用於繪製音訊的後端。\n\nSDL2 是首選,而 OpenAL 和 SoundIO 則作為備用。虛設 (Dummy) 將沒有聲音。\n\n如果不確定,請設定為 SDL2。",
+ "AudioBackendTooltip": "變更用於繪製音訊的後端。\n\nSDL3 是首選,而 OpenAL 和 SoundIO 則作為備用。虛設 (Dummy) 將沒有聲音。\n\n如果不確定,請設定為 SDL3。",
"MemoryManagerTooltip": "變更客體記憶體的映射和存取方式。這會極大地影響模擬 CPU 效能。\n\n如果不確定,請設定為主體略過檢查模式。",
"MemoryManagerSoftwareTooltip": "使用軟體分頁表進行位址轉換。精度最高,但效能最差。",
"MemoryManagerHostTooltip": "直接映射主體位址空間中的記憶體。更快的 JIT 編譯和執行速度。",
diff --git a/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs b/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs
index 9ed2250db..30e9cea72 100644
--- a/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs
+++ b/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs
@@ -1,6 +1,6 @@
using DiscordRPC;
using LibHac.Tools.FsSystem;
-using Ryujinx.Audio.Backends.SDL2;
+using Ryujinx.Audio.Backends.SDL3;
using Ryujinx.Ava;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid;
@@ -158,7 +158,7 @@ namespace Ryujinx.Headless
config = new StandardControllerInputConfig
{
Version = InputConfig.CurrentVersion,
- Backend = InputBackendType.GamepadSDL2,
+ Backend = InputBackendType.GamepadSDL3,
Id = null,
ControllerType = ControllerType.JoyconPair,
DeadzoneLeft = 0.1f,
@@ -307,7 +307,7 @@ namespace Ryujinx.Headless
return new VulkanRenderer(
api,
(instance, _) => new SurfaceKHR((ulong)(vulkanWindow.CreateWindowSurface(instance.Handle))),
- vulkanWindow.GetRequiredInstanceExtensions,
+ VulkanWindow.GetRequiredInstanceExtensions,
preferredGpuId);
}
@@ -331,7 +331,7 @@ namespace Ryujinx.Headless
_accountManager,
_userChannelPersistence,
renderer,
- new SDL2HardwareDeviceDriver(),
+ new SDL3HardwareDeviceDriver(),
options.DramSize,
window,
options.SystemLanguage,
diff --git a/src/Ryujinx/Headless/HeadlessRyujinx.cs b/src/Ryujinx/Headless/HeadlessRyujinx.cs
index 7a3eb9873..0262b0c01 100644
--- a/src/Ryujinx/Headless/HeadlessRyujinx.cs
+++ b/src/Ryujinx/Headless/HeadlessRyujinx.cs
@@ -19,9 +19,10 @@ using Ryujinx.HLE.HOS;
using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.Input;
using Ryujinx.Input.HLE;
-using Ryujinx.Input.SDL2;
-using Ryujinx.SDL2.Common;
+using Ryujinx.Input.SDL3;
+using Ryujinx.SDL3.Common;
using Ryujinx.UI.Common.Configuration;
+using SDL;
using System;
using System.Collections.Generic;
using System.IO;
@@ -58,7 +59,7 @@ namespace Ryujinx.Headless
AutoResetEvent invoked = new(false);
// MacOS must perform SDL polls from the main thread.
- SDL2Driver.MainThreadDispatcher = action =>
+ SDL3Driver.MainThreadDispatcher = action =>
{
invoked.Reset();
@@ -169,7 +170,7 @@ namespace Ryujinx.Headless
_accountManager = new AccountManager(_libHacHorizonManager.RyujinxClient, option.UserProfile);
_userChannelPersistence = new UserChannelPersistence();
- _inputManager = new InputManager(new SDL2KeyboardDriver(), new SDL2GamepadDriver());
+ _inputManager = new InputManager(new SDL3KeyboardDriver(), new SDL3GamepadDriver());
GraphicsConfig.EnableShaderCache = !option.DisableShaderCache;
@@ -367,7 +368,7 @@ namespace Ryujinx.Headless
_window = window;
_window.IsFullscreen = options.IsFullscreen;
- _window.DisplayId = options.DisplayId;
+ _window.DisplayId = (SDL_DisplayID)options.DisplayId;
_window.IsExclusiveFullscreen = options.IsExclusiveFullscreen;
_window.ExclusiveFullscreenWidth = options.ExclusiveFullscreenWidth;
_window.ExclusiveFullscreenHeight = options.ExclusiveFullscreenHeight;
diff --git a/src/Ryujinx/Headless/OpenGL/OpenGLWindow.cs b/src/Ryujinx/Headless/OpenGL/OpenGLWindow.cs
index c00a0648f..7ea1f399f 100644
--- a/src/Ryujinx/Headless/OpenGL/OpenGLWindow.cs
+++ b/src/Ryujinx/Headless/OpenGL/OpenGLWindow.cs
@@ -4,16 +4,17 @@ using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.OpenGL;
using Ryujinx.Input.HLE;
+using SDL;
using System;
-using static SDL2.SDL;
+using static SDL.SDL3;
namespace Ryujinx.Headless
{
- class OpenGLWindow : WindowBase
+ unsafe class OpenGLWindow : WindowBase
{
- private static void CheckResult(int result)
+ private static void CheckResult(bool result)
{
- if (result < 0)
+ if (!result)
{
throw new InvalidOperationException($"SDL_GL function returned an error: {SDL_GetError()}");
}
@@ -21,21 +22,21 @@ namespace Ryujinx.Headless
private static void SetupOpenGLAttributes(bool sharedContext, GraphicsDebugLevel debugLevel)
{
- CheckResult(SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_CONTEXT_MAJOR_VERSION, 3));
- CheckResult(SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_CONTEXT_MINOR_VERSION, 3));
- CheckResult(SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_CONTEXT_PROFILE_MASK, SDL_GLprofile.SDL_GL_CONTEXT_PROFILE_COMPATIBILITY));
- CheckResult(SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_CONTEXT_FLAGS, debugLevel != GraphicsDebugLevel.None ? (int)SDL_GLcontext.SDL_GL_CONTEXT_DEBUG_FLAG : 0));
- CheckResult(SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_SHARE_WITH_CURRENT_CONTEXT, sharedContext ? 1 : 0));
+ CheckResult(SDL_GL_SetAttribute(SDL_GLAttr.SDL_GL_CONTEXT_MAJOR_VERSION, 4));
+ CheckResult(SDL_GL_SetAttribute(SDL_GLAttr.SDL_GL_CONTEXT_MINOR_VERSION, 3));
+ CheckResult(SDL_GL_SetAttribute(SDL_GLAttr.SDL_GL_CONTEXT_PROFILE_MASK, (int)SDL_GLProfile.SDL_GL_CONTEXT_PROFILE_COMPATIBILITY));
+ CheckResult(SDL_GL_SetAttribute(SDL_GLAttr.SDL_GL_CONTEXT_FLAGS, debugLevel != GraphicsDebugLevel.None ? (int)SDL_GLContextFlag.SDL_GL_CONTEXT_DEBUG_FLAG : 0));
+ CheckResult(SDL_GL_SetAttribute(SDL_GLAttr.SDL_GL_SHARE_WITH_CURRENT_CONTEXT, sharedContext ? 1 : 0));
- CheckResult(SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_ACCELERATED_VISUAL, 1));
- CheckResult(SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_RED_SIZE, 8));
- CheckResult(SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_GREEN_SIZE, 8));
- CheckResult(SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_BLUE_SIZE, 8));
- CheckResult(SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_ALPHA_SIZE, 8));
- CheckResult(SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_DEPTH_SIZE, 16));
- CheckResult(SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_STENCIL_SIZE, 0));
- CheckResult(SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_DOUBLEBUFFER, 1));
- CheckResult(SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_STEREO, 0));
+ CheckResult(SDL_GL_SetAttribute(SDL_GLAttr.SDL_GL_ACCELERATED_VISUAL, 1));
+ CheckResult(SDL_GL_SetAttribute(SDL_GLAttr.SDL_GL_RED_SIZE, 8));
+ CheckResult(SDL_GL_SetAttribute(SDL_GLAttr.SDL_GL_GREEN_SIZE, 8));
+ CheckResult(SDL_GL_SetAttribute(SDL_GLAttr.SDL_GL_BLUE_SIZE, 8));
+ CheckResult(SDL_GL_SetAttribute(SDL_GLAttr.SDL_GL_ALPHA_SIZE, 8));
+ CheckResult(SDL_GL_SetAttribute(SDL_GLAttr.SDL_GL_DEPTH_SIZE, 16));
+ CheckResult(SDL_GL_SetAttribute(SDL_GLAttr.SDL_GL_STENCIL_SIZE, 0));
+ CheckResult(SDL_GL_SetAttribute(SDL_GLAttr.SDL_GL_DOUBLEBUFFER, 1));
+ CheckResult(SDL_GL_SetAttribute(SDL_GLAttr.SDL_GL_STEREO, 0));
}
private class OpenToolkitBindingsContext : IBindingsContext
@@ -46,35 +47,35 @@ namespace Ryujinx.Headless
}
}
- private class SDL2OpenGLContext : IOpenGLContext
+ private class SDL3OpenGLContext : IOpenGLContext
{
- private readonly nint _context;
- private readonly nint _window;
+ private readonly SDL_GLContextState* _context;
+ private readonly SDL_Window* _window;
private readonly bool _shouldDisposeWindow;
- public SDL2OpenGLContext(nint context, nint window, bool shouldDisposeWindow = true)
+ public SDL3OpenGLContext(SDL_GLContextState* context, SDL_Window* window, bool shouldDisposeWindow = true)
{
_context = context;
_window = window;
_shouldDisposeWindow = shouldDisposeWindow;
}
- public static SDL2OpenGLContext CreateBackgroundContext(SDL2OpenGLContext sharedContext)
+ public static SDL3OpenGLContext CreateBackgroundContext(SDL3OpenGLContext sharedContext)
{
sharedContext.MakeCurrent();
// Ensure we share our contexts.
SetupOpenGLAttributes(true, GraphicsDebugLevel.None);
- nint windowHandle = SDL_CreateWindow("Ryujinx background context window", 0, 0, 1, 1, SDL_WindowFlags.SDL_WINDOW_OPENGL | SDL_WindowFlags.SDL_WINDOW_HIDDEN);
- nint context = SDL_GL_CreateContext(windowHandle);
+ SDL_Window* windowHandle = SDL_CreateWindow("Ryujinx background context window", 1, 1, SDL_WindowFlags.SDL_WINDOW_OPENGL | SDL_WindowFlags.SDL_WINDOW_HIDDEN);
+ SDL_GLContextState* context = SDL_GL_CreateContext(windowHandle);
GL.LoadBindings(new OpenToolkitBindingsContext());
- CheckResult(SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 0));
+ CheckResult(SDL_GL_SetAttribute(SDL_GLAttr.SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 0));
- CheckResult(SDL_GL_MakeCurrent(windowHandle, nint.Zero));
+ CheckResult(SDL_GL_MakeCurrent(windowHandle, null));
- return new SDL2OpenGLContext(context, windowHandle);
+ return new SDL3OpenGLContext(context, windowHandle);
}
public void MakeCurrent()
@@ -84,9 +85,9 @@ namespace Ryujinx.Headless
return;
}
- int res = SDL_GL_MakeCurrent(_window, _context);
+ bool res = SDL_GL_MakeCurrent(_window, _context);
- if (res != 0)
+ if (!res)
{
string errorMessage = $"SDL_GL_CreateContext failed with error \"{SDL_GetError()}\"";
@@ -96,11 +97,11 @@ namespace Ryujinx.Headless
}
}
- public bool HasContext() => SDL_GL_GetCurrentContext() != nint.Zero;
+ public bool HasContext() => SDL_GL_GetCurrentContext() != null;
public void Dispose()
{
- SDL_GL_DeleteContext(_context);
+ SDL_GL_DestroyContext (_context);
if (_shouldDisposeWindow)
{
@@ -110,7 +111,7 @@ namespace Ryujinx.Headless
}
private readonly GraphicsDebugLevel _glLogLevel;
- private SDL2OpenGLContext _openGLContext;
+ private SDL3OpenGLContext _openGLContext;
public OpenGLWindow(
InputManager inputManager,
@@ -124,16 +125,16 @@ namespace Ryujinx.Headless
_glLogLevel = glLogLevel;
}
- public override SDL_WindowFlags GetWindowFlags() => SDL_WindowFlags.SDL_WINDOW_OPENGL;
+ public override SDL_WindowFlags WindowFlags => SDL_WindowFlags.SDL_WINDOW_OPENGL;
protected override void InitializeWindowRenderer()
{
// Ensure to not share this context with other contexts before this point.
SetupOpenGLAttributes(false, _glLogLevel);
- nint context = SDL_GL_CreateContext(WindowHandle);
+ SDL_GLContextState* context = SDL_GL_CreateContext(WindowHandle);
CheckResult(SDL_GL_SetSwapInterval(1));
- if (context == nint.Zero)
+ if (context == null)
{
string errorMessage = $"SDL_GL_CreateContext failed with error \"{SDL_GetError()}\"";
@@ -143,10 +144,10 @@ namespace Ryujinx.Headless
}
// NOTE: The window handle needs to be disposed by the thread that created it and is handled separately.
- _openGLContext = new SDL2OpenGLContext(context, WindowHandle, false);
+ _openGLContext = new SDL3OpenGLContext(context, WindowHandle, false);
// First take exclusivity on the OpenGL context.
- ((OpenGLRenderer)Renderer).InitializeBackgroundContext(SDL2OpenGLContext.CreateBackgroundContext(_openGLContext));
+ ((OpenGLRenderer)Renderer).InitializeBackgroundContext(SDL3OpenGLContext.CreateBackgroundContext(_openGLContext));
_openGLContext.MakeCurrent();
@@ -162,7 +163,8 @@ namespace Ryujinx.Headless
else if (IsFullscreen)
{
// NOTE: grabbing the main display's dimensions directly as OpenGL doesn't scale along like the VulkanWindow.
- if (SDL_GetDisplayBounds(DisplayId, out SDL_Rect displayBounds) < 0)
+ SDL_Rect displayBounds = new();
+ if (!SDL_GetDisplayBounds(DisplayId, &displayBounds))
{
Logger.Warning?.Print(LogClass.Application, $"Could not retrieve display bounds: {SDL_GetError()}");
@@ -191,7 +193,7 @@ namespace Ryujinx.Headless
Device.DisposeGpu();
// Unbind context and destroy everything
- CheckResult(SDL_GL_MakeCurrent(WindowHandle, nint.Zero));
+ CheckResult(SDL_GL_MakeCurrent(WindowHandle, null));
_openGLContext.Dispose();
}
diff --git a/src/Ryujinx/Headless/Vulkan/VulkanWindow.cs b/src/Ryujinx/Headless/Vulkan/VulkanWindow.cs
index 92caad34e..f9a6ff527 100644
--- a/src/Ryujinx/Headless/Vulkan/VulkanWindow.cs
+++ b/src/Ryujinx/Headless/Vulkan/VulkanWindow.cs
@@ -1,17 +1,16 @@
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Input.HLE;
-using Ryujinx.SDL2.Common;
+using Ryujinx.SDL3.Common;
+using SDL;
using System;
using System.Runtime.InteropServices;
-using static SDL2.SDL;
+using static SDL.SDL3;
namespace Ryujinx.Headless
{
class VulkanWindow : WindowBase
{
- private readonly GraphicsDebugLevel _glLogLevel;
-
public VulkanWindow(
InputManager inputManager,
GraphicsDebugLevel glLogLevel,
@@ -21,10 +20,9 @@ namespace Ryujinx.Headless
bool ignoreControllerApplet)
: base(inputManager, glLogLevel, aspectRatio, enableMouse, hideCursorMode, ignoreControllerApplet)
{
- _glLogLevel = glLogLevel;
}
- public override SDL_WindowFlags GetWindowFlags() => SDL_WindowFlags.SDL_WINDOW_VULKAN;
+ public override SDL_WindowFlags WindowFlags => SDL_WindowFlags.SDL_WINDOW_VULKAN;
protected override void InitializeWindowRenderer() { }
@@ -42,18 +40,15 @@ namespace Ryujinx.Headless
}
}
- private static void BasicInvoke(Action action)
+ public unsafe nint CreateWindowSurface(nint instance)
{
- action();
- }
-
- public nint CreateWindowSurface(nint instance)
- {
- ulong surfaceHandle = 0;
+ VkSurfaceKHR_T surface = new();
+ VkSurfaceKHR_T* surfaceHandle = &surface;
+ VkSurfaceKHR_T** surfaceHandleHandle = &surfaceHandle;
void CreateSurface()
{
- if (SDL_Vulkan_CreateSurface(WindowHandle, instance, out surfaceHandle) == SDL_bool.SDL_FALSE)
+ if (!SDL_Vulkan_CreateSurface(WindowHandle, (VkInstance_T*)instance, null, surfaceHandleHandle))
{
string errorMessage = $"SDL_Vulkan_CreateSurface failed with error \"{SDL_GetError()}\"";
@@ -63,9 +58,9 @@ namespace Ryujinx.Headless
}
}
- if (SDL2Driver.MainThreadDispatcher != null)
+ if (SDL3Driver.MainThreadDispatcher != null)
{
- SDL2Driver.MainThreadDispatcher(CreateSurface);
+ SDL3Driver.MainThreadDispatcher(CreateSurface);
}
else
{
@@ -75,32 +70,22 @@ namespace Ryujinx.Headless
return (nint)surfaceHandle;
}
- public unsafe string[] GetRequiredInstanceExtensions()
+ public unsafe static string[] GetRequiredInstanceExtensions()
{
- if (SDL_Vulkan_GetInstanceExtensions(WindowHandle, out uint extensionsCount, nint.Zero) == SDL_bool.SDL_TRUE)
- {
- nint[] rawExtensions = new nint[(int)extensionsCount];
- string[] extensions = new string[(int)extensionsCount];
+ uint extensionCount = 0;
+ byte** extensions = SDL_Vulkan_GetInstanceExtensions(&extensionCount);
+ if (extensionCount == 0) {
+ string errorMessage = $"SDL_Vulkan_GetInstanceExtensions failed with error \"{SDL_GetError()}\"";
- fixed (nint* rawExtensionsPtr = rawExtensions)
- {
- if (SDL_Vulkan_GetInstanceExtensions(WindowHandle, out extensionsCount, (nint)rawExtensionsPtr) == SDL_bool.SDL_TRUE)
- {
- for (int i = 0; i < extensions.Length; i++)
- {
- extensions[i] = Marshal.PtrToStringUTF8(rawExtensions[i]);
- }
+ Logger.Error?.Print(LogClass.Application, errorMessage);
- return extensions;
- }
- }
+ throw new Exception(errorMessage);
}
-
- string errorMessage = $"SDL_Vulkan_GetInstanceExtensions failed with error \"{SDL_GetError()}\"";
-
- Logger.Error?.Print(LogClass.Application, errorMessage);
-
- throw new Exception(errorMessage);
+ string[] extensionArr = new string[extensionCount];
+ for (int i = 0; i < extensionCount; i++) {
+ extensionArr[i] = Marshal.PtrToStringUTF8((nint)extensions[i]);
+ }
+ return extensionArr;
}
protected override void FinalizeWindowRenderer()
diff --git a/src/Ryujinx/Headless/WindowBase.cs b/src/Ryujinx/Headless/WindowBase.cs
index 641a0aea6..6d56594e3 100644
--- a/src/Ryujinx/Headless/WindowBase.cs
+++ b/src/Ryujinx/Headless/WindowBase.cs
@@ -1,3 +1,4 @@
+using LibHac.Util;
using Ryujinx.Ava;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
@@ -12,36 +13,32 @@ using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationPr
using Ryujinx.HLE.UI;
using Ryujinx.Input;
using Ryujinx.Input.HLE;
-using Ryujinx.Input.SDL2;
-using Ryujinx.SDL2.Common;
+using Ryujinx.Input.SDL3;
+using Ryujinx.SDL3.Common;
+using SDL;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
-using System.Runtime.InteropServices;
using System.Threading;
-using static SDL2.SDL;
+using static SDL.SDL3;
using AntiAliasing = Ryujinx.Common.Configuration.AntiAliasing;
using ScalingFilter = Ryujinx.Common.Configuration.ScalingFilter;
using Switch = Ryujinx.HLE.Switch;
namespace Ryujinx.Headless
{
- abstract partial class WindowBase : IHostUIHandler, IDisposable
+ abstract unsafe class WindowBase : IHostUIHandler, IDisposable
{
protected const int DefaultWidth = 1280;
protected const int DefaultHeight = 720;
private const int TargetFps = 60;
- private SDL_WindowFlags DefaultFlags = SDL_WindowFlags.SDL_WINDOW_ALLOW_HIGHDPI | SDL_WindowFlags.SDL_WINDOW_RESIZABLE | SDL_WindowFlags.SDL_WINDOW_INPUT_FOCUS | SDL_WindowFlags.SDL_WINDOW_SHOWN;
+ private SDL_WindowFlags DefaultFlags = SDL_WindowFlags.SDL_WINDOW_HIGH_PIXEL_DENSITY | SDL_WindowFlags.SDL_WINDOW_RESIZABLE | SDL_WindowFlags.SDL_WINDOW_INPUT_FOCUS;
private SDL_WindowFlags FullscreenFlag = 0;
private static readonly ConcurrentQueue _mainThreadActions = new();
- [LibraryImport("SDL2")]
- // TODO: Remove this as soon as SDL2-CS was updated to expose this method publicly
- private static partial nint SDL_LoadBMP_RW(nint src, int freesrc);
-
public static void QueueMainThreadAction(Action action)
{
_mainThreadActions.Enqueue(action);
@@ -54,12 +51,12 @@ namespace Ryujinx.Headless
public event EventHandler StatusUpdatedEvent;
- protected nint WindowHandle { get; set; }
+ protected SDL_Window* WindowHandle { get; set; }
public IHostUITheme HostUITheme { get; }
public int Width { get; private set; }
public int Height { get; private set; }
- public int DisplayId { get; set; }
+ public SDL_DisplayID DisplayId { get; set; }
public bool IsFullscreen { get; set; }
public bool IsExclusiveFullscreen { get; set; }
public int ExclusiveFullscreenWidth { get; set; }
@@ -68,7 +65,7 @@ namespace Ryujinx.Headless
public ScalingFilter ScalingFilter { get; set; }
public int ScalingFilterLevel { get; set; }
- protected SDL2MouseDriver MouseDriver;
+ protected SDL3MouseDriver MouseDriver;
private readonly InputManager _inputManager;
private readonly IKeyboard _keyboardInterface;
private readonly GraphicsDebugLevel _glLogLevel;
@@ -81,7 +78,7 @@ namespace Ryujinx.Headless
private long _ticks;
private bool _isActive;
private bool _isStopped;
- private uint _windowId;
+ private SDL_WindowID _windowId;
private string _gpuDriverName;
@@ -97,7 +94,7 @@ namespace Ryujinx.Headless
HideCursorMode hideCursorMode,
bool ignoreControllerApplet)
{
- MouseDriver = new SDL2MouseDriver(hideCursorMode);
+ MouseDriver = new SDL3MouseDriver(hideCursorMode);
_inputManager = inputManager;
_inputManager.SetMouseDriver(MouseDriver);
NpadManager = _inputManager.CreateNpadManager();
@@ -114,7 +111,7 @@ namespace Ryujinx.Headless
_ignoreControllerApplet = ignoreControllerApplet;
HostUITheme = new HeadlessHostUiTheme();
- SDL2Driver.Instance.Initialize();
+ SDL3Driver.Instance.Initialize();
}
public void Initialize(Switch device, List inputConfigs, bool enableKeyboard, bool enableMouse)
@@ -149,16 +146,13 @@ namespace Ryujinx.Headless
iconStream.Close();
- unsafe
+ fixed (byte* iconPtr = iconBytes)
{
- fixed (byte* iconPtr = iconBytes)
- {
- nint rwOpsStruct = SDL_RWFromConstMem((nint)iconPtr, iconBytes.Length);
- nint iconHandle = SDL_LoadBMP_RW(rwOpsStruct, 1);
+ SDL_IOStream* rwOpsStruct = SDL_IOFromConstMem((nint)iconPtr, (UIntPtr)iconBytes.Length);
+ SDL_Surface* iconHandle = SDL_LoadBMP_IO(rwOpsStruct, true);
- SDL_SetWindowIcon(WindowHandle, iconHandle);
- SDL_FreeSurface(iconHandle);
- }
+ SDL_SetWindowIcon(WindowHandle, iconHandle);
+ SDL_DestroySurface(iconHandle);
}
}
@@ -181,18 +175,27 @@ namespace Ryujinx.Headless
Width = ExclusiveFullscreenWidth;
Height = ExclusiveFullscreenHeight;
- DefaultFlags = SDL_WindowFlags.SDL_WINDOW_ALLOW_HIGHDPI;
+ DefaultFlags = SDL_WindowFlags.SDL_WINDOW_HIGH_PIXEL_DENSITY;
FullscreenFlag = SDL_WindowFlags.SDL_WINDOW_FULLSCREEN;
}
else if (IsFullscreen)
{
- DefaultFlags = SDL_WindowFlags.SDL_WINDOW_ALLOW_HIGHDPI;
- FullscreenFlag = SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP;
+ DefaultFlags = SDL_WindowFlags.SDL_WINDOW_HIGH_PIXEL_DENSITY;
+ FullscreenFlag = SDL_WindowFlags.SDL_WINDOW_BORDERLESS;
}
- WindowHandle = SDL_CreateWindow($"Ryujinx {Program.Version}{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}", SDL_WINDOWPOS_CENTERED_DISPLAY(DisplayId), SDL_WINDOWPOS_CENTERED_DISPLAY(DisplayId), Width, Height, DefaultFlags | FullscreenFlag | GetWindowFlags());
+ SDL_PropertiesID props = SDL_CreateProperties();
+ SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, $"Ryujinx {Program.Version}{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}");
+ SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, SDL_WINDOWPOS_CENTERED_DISPLAY(DisplayId));
+ SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, SDL_WINDOWPOS_CENTERED_DISPLAY(DisplayId));
+ SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, Width);
+ SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, Height);
+ SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_FLAGS_NUMBER, (long)(DefaultFlags | FullscreenFlag | WindowFlags));
- if (WindowHandle == nint.Zero)
+ WindowHandle = SDL_CreateWindowWithProperties(props);
+ SDL_DestroyProperties(props);
+
+ if (WindowHandle == null)
{
string errorMessage = $"SDL_CreateWindow failed with error \"{SDL_GetError()}\"";
@@ -204,16 +207,16 @@ namespace Ryujinx.Headless
SetWindowIcon();
_windowId = SDL_GetWindowID(WindowHandle);
- SDL2Driver.Instance.RegisterWindow(_windowId, HandleWindowEvent);
+ SDL3Driver.Instance.RegisterWindow(_windowId, HandleWindowEvent);
}
private void HandleWindowEvent(SDL_Event evnt)
{
- if (evnt.type == SDL_EventType.SDL_WINDOWEVENT)
+ if ((uint)evnt.Type >= (uint)SDL_EventType.SDL_EVENT_WINDOW_FIRST && (uint)evnt.Type <= (uint)SDL_EventType.SDL_EVENT_WINDOW_LAST)
{
- switch (evnt.window.windowEvent)
+ switch (evnt.Type)
{
- case SDL_WindowEventID.SDL_WINDOWEVENT_SIZE_CHANGED:
+ case SDL_EventType.SDL_EVENT_WINDOW_RESIZED:
// Unlike on Windows, this event fires on macOS when triggering fullscreen mode.
// And promptly crashes the process because `Renderer?.window.SetSize` is undefined.
// As we don't need this to fire in either case we can test for fullscreen.
@@ -226,7 +229,7 @@ namespace Ryujinx.Headless
}
break;
- case SDL_WindowEventID.SDL_WINDOWEVENT_CLOSE:
+ case SDL_EventType.SDL_EVENT_WINDOW_CLOSE_REQUESTED:
Exit();
break;
}
@@ -245,7 +248,7 @@ namespace Ryujinx.Headless
protected abstract void SwapBuffers();
- public abstract SDL_WindowFlags GetWindowFlags();
+ public abstract SDL_WindowFlags WindowFlags { get; }
private string GetGpuDriverName()
{
@@ -421,7 +424,7 @@ namespace Ryujinx.Headless
// Get screen touch position
if (!_enableMouse)
{
- hasTouch = TouchScreenManager.Update(true, ((SDL2MouseDriver)_inputManager.MouseDriver).IsButtonPressed(MouseButton.Button1), _aspectRatio.ToFloat());
+ hasTouch = TouchScreenManager.Update(true, ((SDL3MouseDriver)_inputManager.MouseDriver).IsButtonPressed(MouseButton.Button1), _aspectRatio.ToFloat());
}
if (!hasTouch)
@@ -473,7 +476,7 @@ namespace Ryujinx.Headless
public bool DisplayInputDialog(SoftwareKeyboardUIArgs args, out string userText)
{
- // SDL2 doesn't support input dialogs
+ // SDL3 doesn't support input dialogs
userText = "Ryujinx";
return true;
@@ -488,7 +491,7 @@ namespace Ryujinx.Headless
public bool DisplayCabinetDialog(out string userText)
{
- // SDL2 doesn't support input dialogs
+ // SDL3 doesn't support input dialogs
userText = "Ryujinx";
return true;
@@ -528,25 +531,34 @@ namespace Ryujinx.Headless
public bool DisplayErrorAppletDialog(string title, string message, string[] buttonsText)
{
- SDL_MessageBoxData data = new()
- {
- title = title,
- message = message,
- buttons = new SDL_MessageBoxButtonData[buttonsText.Length],
- numbuttons = buttonsText.Length,
- window = WindowHandle,
- };
+ SDL_MessageBoxButtonData[] buttons = new SDL_MessageBoxButtonData[buttonsText.Length];
for (int i = 0; i < buttonsText.Length; i++)
{
- data.buttons[i] = new SDL_MessageBoxButtonData
- {
- buttonid = i,
- text = buttonsText[i],
- };
+ string buttonText = buttonsText[i];
+ fixed (byte* pButtonText = &buttonText.ToBytes()[0])
+ buttons[i] = new SDL_MessageBoxButtonData
+ {
+ buttonID = i,
+ text = pButtonText,
+ };
}
- SDL_ShowMessageBox(ref data, out int _);
+ fixed (byte* pTitle = &title.ToBytes()[0])
+ fixed (byte* pMessage = &message.ToBytes()[0])
+ fixed (SDL_MessageBoxButtonData* p = &buttons[0]) {
+ SDL_MessageBoxData data = new()
+ {
+ title = pTitle,
+ message = pMessage,
+ buttons = p,
+ numbuttons = buttonsText.Length,
+ window = WindowHandle
+ };
+
+
+ SDL_ShowMessageBox(&data, null);
+ }
return true;
}
@@ -564,11 +576,11 @@ namespace Ryujinx.Headless
TouchScreenManager?.Dispose();
NpadManager.Dispose();
- SDL2Driver.Instance.UnregisterWindow(_windowId);
+ SDL3Driver.Instance.UnregisterWindow(_windowId);
SDL_DestroyWindow(WindowHandle);
- SDL2Driver.Instance.Dispose();
+ SDL3Driver.Instance.Dispose();
}
}
diff --git a/src/Ryujinx/Program.cs b/src/Ryujinx/Program.cs
index d9a85e3b0..41180b90e 100644
--- a/src/Ryujinx/Program.cs
+++ b/src/Ryujinx/Program.cs
@@ -10,7 +10,7 @@ using Ryujinx.Common.SystemInterop;
using Ryujinx.Graphics.Vulkan.MoltenVK;
using Ryujinx.Headless;
using Ryujinx.Modules;
-using Ryujinx.SDL2.Common;
+using Ryujinx.SDL3.Common;
using Ryujinx.UI.Common;
using Ryujinx.UI.Common.Configuration;
using Ryujinx.UI.Common.Helper;
@@ -118,8 +118,8 @@ namespace Ryujinx.Ava
// Initialize Discord integration.
DiscordIntegrationModule.Initialize();
- // Initialize SDL2 driver
- SDL2Driver.MainThreadDispatcher = action => Dispatcher.UIThread.InvokeAsync(action, DispatcherPriority.Input);
+ // Initialize SDL3 driver
+ SDL3Driver.MainThreadDispatcher = action => Dispatcher.UIThread.InvokeAsync(action, DispatcherPriority.Input);
ReloadConfig();
diff --git a/src/Ryujinx/Ryujinx.csproj b/src/Ryujinx/Ryujinx.csproj
index 04fe97bfb..322512523 100644
--- a/src/Ryujinx/Ryujinx.csproj
+++ b/src/Ryujinx/Ryujinx.csproj
@@ -57,11 +57,11 @@
-
+
-
+
diff --git a/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs b/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs
index 833670bdc..c03f58a22 100644
--- a/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs
+++ b/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs
@@ -491,7 +491,7 @@ namespace Ryujinx.Ava.UI.Models.Input
var config = new StandardControllerInputConfig
{
Id = Id,
- Backend = InputBackendType.GamepadSDL2,
+ Backend = InputBackendType.GamepadSDL3,
PlayerIndex = PlayerIndex,
ControllerType = ControllerType,
LeftJoycon = new LeftJoyconCommonConfig
diff --git a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs
index a46a8065c..2b5cd44f3 100644
--- a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs
@@ -617,7 +617,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
config = new StandardControllerInputConfig
{
Version = InputConfig.CurrentVersion,
- Backend = InputBackendType.GamepadSDL2,
+ Backend = InputBackendType.GamepadSDL3,
Id = id,
ControllerType = ControllerType.ProController,
DeadzoneLeft = 0.1f,
diff --git a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs
index 7a9cce0bb..4a6fc06f0 100644
--- a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs
@@ -3,7 +3,7 @@ using Avalonia.Controls;
using Avalonia.Threading;
using LibHac.Tools.FsSystem;
using Ryujinx.Audio.Backends.OpenAL;
-using Ryujinx.Audio.Backends.SDL2;
+using Ryujinx.Audio.Backends.SDL3;
using Ryujinx.Audio.Backends.SoundIo;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Helpers;
@@ -248,7 +248,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool EnableDebug { get; set; }
public bool IsOpenAlEnabled { get; set; }
public bool IsSoundIoEnabled { get; set; }
- public bool IsSDL2Enabled { get; set; }
+ public bool IsSDL3Enabled { get; set; }
public bool IsCustomResolutionScaleActive => _resolutionScale == 4;
public bool IsScalingFilterActive => _scalingFilter == (int)Ryujinx.Common.Configuration.ScalingFilter.Fsr;
@@ -427,13 +427,13 @@ namespace Ryujinx.Ava.UI.ViewModels
{
IsOpenAlEnabled = OpenALHardwareDeviceDriver.IsSupported;
IsSoundIoEnabled = SoundIoHardwareDeviceDriver.IsSupported;
- IsSDL2Enabled = SDL2HardwareDeviceDriver.IsSupported;
+ IsSDL3Enabled = SDL3HardwareDeviceDriver.IsSupported;
await Dispatcher.UIThread.InvokeAsync(() =>
{
OnPropertyChanged(nameof(IsOpenAlEnabled));
OnPropertyChanged(nameof(IsSoundIoEnabled));
- OnPropertyChanged(nameof(IsSDL2Enabled));
+ OnPropertyChanged(nameof(IsSDL3Enabled));
});
}
diff --git a/src/Ryujinx/UI/Views/Settings/SettingsAudioView.axaml b/src/Ryujinx/UI/Views/Settings/SettingsAudioView.axaml
index 9195edaf4..0996184c0 100644
--- a/src/Ryujinx/UI/Views/Settings/SettingsAudioView.axaml
+++ b/src/Ryujinx/UI/Views/Settings/SettingsAudioView.axaml
@@ -43,8 +43,8 @@
IsEnabled="{Binding IsSoundIoEnabled}"
Content="{locale:Locale SettingsTabSystemAudioBackendSoundIO}" />
+ IsEnabled="{Binding IsSDL3Enabled}"
+ Content="{locale:Locale SettingsTabSystemAudioBackendSDL3}" />
diff --git a/src/Ryujinx/UI/Windows/MainWindow.axaml.cs b/src/Ryujinx/UI/Windows/MainWindow.axaml.cs
index 35e88f690..93e3ed43b 100644
--- a/src/Ryujinx/UI/Windows/MainWindow.axaml.cs
+++ b/src/Ryujinx/UI/Windows/MainWindow.axaml.cs
@@ -19,7 +19,7 @@ using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS;
using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.Input.HLE;
-using Ryujinx.Input.SDL2;
+using Ryujinx.Input.SDL3;
using Ryujinx.Modules;
using Ryujinx.UI.App.Common;
using Ryujinx.UI.Common;
@@ -107,7 +107,7 @@ namespace Ryujinx.Ava.UI.Windows
if (Program.PreviewerDetached)
{
- InputManager = new InputManager(new AvaloniaKeyboardDriver(this), new SDL2GamepadDriver());
+ InputManager = new InputManager(new AvaloniaKeyboardDriver(this), new SDL3GamepadDriver());
this.GetObservable(IsActiveProperty).Subscribe(IsActiveChanged);
this.ScalingChanged += OnScalingChanged;