diff --git a/Directory.Packages.props b/Directory.Packages.props
index b2a838496..fd61602a8 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -16,6 +16,7 @@
+
@@ -41,7 +42,6 @@
-
diff --git a/README.md b/README.md
index 3dcf939b1..7a785055f 100644
--- a/README.md
+++ b/README.md
@@ -66,7 +66,7 @@ If you are planning to contribute or just want to learn more about this project
- **Audio**
Audio output is entirely supported, audio input (microphone) isn't supported.
- We use C# wrappers for [OpenAL](https://openal-soft.org/), and [SDL2](https://www.libsdl.org/) & [libsoundio](http://libsound.io/) as fallbacks.
+ We use C# wrappers for [OpenAL](https://openal-soft.org/), and [SDL3](https://www.libsdl.org/) & [libsoundio](http://libsound.io/) as fallbacks.
- **CPU**
diff --git a/Ryujinx.sln b/Ryujinx.sln
index 4babf3fb9..8c48ecead 100644
--- a/Ryujinx.sln
+++ b/Ryujinx.sln
@@ -51,12 +51,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.Soun
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Input", "src\Ryujinx.Input\Ryujinx.Input.csproj", "{C16F112F-38C3-40BC-9F5F-4791112063D6}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Input.SDL2", "src\Ryujinx.Input.SDL2\Ryujinx.Input.SDL2.csproj", "{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.SDL2.Common", "src\Ryujinx.SDL2.Common\Ryujinx.SDL2.Common.csproj", "{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.SDL2", "src\Ryujinx.Audio.Backends.SDL2\Ryujinx.Audio.Backends.SDL2.csproj", "{D99A395A-8569-4DB0-B336-900647890052}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.FFmpeg", "src\Ryujinx.Graphics.Nvdec.FFmpeg\Ryujinx.Graphics.Nvdec.FFmpeg.csproj", "{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx", "src\Ryujinx\Ryujinx.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}"
@@ -89,171 +83,488 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
nuget.config = nuget.config
EndProjectSection
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.SDL3.Common", "src\Ryujinx.SDL3.Common\Ryujinx.SDL3.Common.csproj", "{F6F9826A-BC58-4D78-A700-F358A66B2B06}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Input.SDL3", "src\Ryujinx.Input.SDL3\Ryujinx.Input.SDL3.csproj", "{D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Audio.Backends.SDL3", "src\Ryujinx.Audio.Backends.SDL3\Ryujinx.Audio.Backends.SDL3.csproj", "{988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|x64.Build.0 = Debug|Any CPU
+ {EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|x86.Build.0 = Debug|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|x64.ActiveCfg = Release|Any CPU
+ {EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|x64.Build.0 = Release|Any CPU
+ {EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|x86.ActiveCfg = Release|Any CPU
+ {EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|x86.Build.0 = Release|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|x64.Build.0 = Debug|Any CPU
+ {D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|x86.Build.0 = Debug|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|x64.ActiveCfg = Release|Any CPU
+ {D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|x64.Build.0 = Release|Any CPU
+ {D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|x86.ActiveCfg = Release|Any CPU
+ {D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|x86.Build.0 = Release|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|x64.Build.0 = Debug|Any CPU
+ {CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|x86.Build.0 = Debug|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|x64.ActiveCfg = Release|Any CPU
+ {CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|x64.Build.0 = Release|Any CPU
+ {CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|x86.ActiveCfg = Release|Any CPU
+ {CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|x86.Build.0 = Release|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|x64.Build.0 = Debug|Any CPU
+ {3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|x86.Build.0 = Debug|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|x64.ActiveCfg = Release|Any CPU
+ {3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|x64.Build.0 = Release|Any CPU
+ {3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|x86.ActiveCfg = Release|Any CPU
+ {3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|x86.Build.0 = Release|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Debug|x64.Build.0 = Debug|Any CPU
+ {5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Debug|x86.Build.0 = Debug|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Release|x64.ActiveCfg = Release|Any CPU
+ {5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Release|x64.Build.0 = Release|Any CPU
+ {5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Release|x86.ActiveCfg = Release|Any CPU
+ {5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Release|x86.Build.0 = Release|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|x64.Build.0 = Debug|Any CPU
+ {ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|x86.Build.0 = Debug|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|x64.ActiveCfg = Release|Any CPU
+ {ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|x64.Build.0 = Release|Any CPU
+ {ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|x86.ActiveCfg = Release|Any CPU
+ {ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|x86.Build.0 = Release|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {ADA7EA87-0D63-4D97-9433-922A2124401F}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {ADA7EA87-0D63-4D97-9433-922A2124401F}.Debug|x64.Build.0 = Debug|Any CPU
+ {ADA7EA87-0D63-4D97-9433-922A2124401F}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {ADA7EA87-0D63-4D97-9433-922A2124401F}.Debug|x86.Build.0 = Debug|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {ADA7EA87-0D63-4D97-9433-922A2124401F}.Release|x64.ActiveCfg = Release|Any CPU
+ {ADA7EA87-0D63-4D97-9433-922A2124401F}.Release|x64.Build.0 = Release|Any CPU
+ {ADA7EA87-0D63-4D97-9433-922A2124401F}.Release|x86.ActiveCfg = Release|Any CPU
+ {ADA7EA87-0D63-4D97-9433-922A2124401F}.Release|x86.Build.0 = Release|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Debug|x64.Build.0 = Debug|Any CPU
+ {A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Debug|x86.Build.0 = Debug|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Release|x64.ActiveCfg = Release|Any CPU
+ {A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Release|x64.Build.0 = Release|Any CPU
+ {A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Release|x86.ActiveCfg = Release|Any CPU
+ {A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Release|x86.Build.0 = Release|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9558FB96-075D-4219-8FFF-401979DC0B69}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {9558FB96-075D-4219-8FFF-401979DC0B69}.Debug|x64.Build.0 = Debug|Any CPU
+ {9558FB96-075D-4219-8FFF-401979DC0B69}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {9558FB96-075D-4219-8FFF-401979DC0B69}.Debug|x86.Build.0 = Debug|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9558FB96-075D-4219-8FFF-401979DC0B69}.Release|x64.ActiveCfg = Release|Any CPU
+ {9558FB96-075D-4219-8FFF-401979DC0B69}.Release|x64.Build.0 = Release|Any CPU
+ {9558FB96-075D-4219-8FFF-401979DC0B69}.Release|x86.ActiveCfg = Release|Any CPU
+ {9558FB96-075D-4219-8FFF-401979DC0B69}.Release|x86.Build.0 = Release|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E1B1AD28-289D-47B7-A106-326972240207}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {E1B1AD28-289D-47B7-A106-326972240207}.Debug|x64.Build.0 = Debug|Any CPU
+ {E1B1AD28-289D-47B7-A106-326972240207}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {E1B1AD28-289D-47B7-A106-326972240207}.Debug|x86.Build.0 = Debug|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E1B1AD28-289D-47B7-A106-326972240207}.Release|x64.ActiveCfg = Release|Any CPU
+ {E1B1AD28-289D-47B7-A106-326972240207}.Release|x64.Build.0 = Release|Any CPU
+ {E1B1AD28-289D-47B7-A106-326972240207}.Release|x86.ActiveCfg = Release|Any CPU
+ {E1B1AD28-289D-47B7-A106-326972240207}.Release|x86.Build.0 = Release|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Debug|x64.Build.0 = Debug|Any CPU
+ {03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Debug|x86.Build.0 = Debug|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Release|x64.ActiveCfg = Release|Any CPU
+ {03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Release|x64.Build.0 = Release|Any CPU
+ {03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Release|x86.ActiveCfg = Release|Any CPU
+ {03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Release|x86.Build.0 = Release|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Debug|x64.Build.0 = Debug|Any CPU
+ {85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Debug|x86.Build.0 = Debug|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Release|x64.ActiveCfg = Release|Any CPU
+ {85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Release|x64.Build.0 = Release|Any CPU
+ {85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Release|x86.ActiveCfg = Release|Any CPU
+ {85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Release|x86.Build.0 = Release|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Debug|x64.Build.0 = Debug|Any CPU
+ {806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Debug|x86.Build.0 = Debug|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Release|Any CPU.ActiveCfg = Release|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Release|Any CPU.Build.0 = Release|Any CPU
+ {806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Release|x64.ActiveCfg = Release|Any CPU
+ {806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Release|x64.Build.0 = Release|Any CPU
+ {806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Release|x86.ActiveCfg = Release|Any CPU
+ {806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Release|x86.Build.0 = Release|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A5E6C691-9E22-4263-8F40-42F002CE66BE}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {A5E6C691-9E22-4263-8F40-42F002CE66BE}.Debug|x64.Build.0 = Debug|Any CPU
+ {A5E6C691-9E22-4263-8F40-42F002CE66BE}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {A5E6C691-9E22-4263-8F40-42F002CE66BE}.Debug|x86.Build.0 = Debug|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A5E6C691-9E22-4263-8F40-42F002CE66BE}.Release|x64.ActiveCfg = Release|Any CPU
+ {A5E6C691-9E22-4263-8F40-42F002CE66BE}.Release|x64.Build.0 = Release|Any CPU
+ {A5E6C691-9E22-4263-8F40-42F002CE66BE}.Release|x86.ActiveCfg = Release|Any CPU
+ {A5E6C691-9E22-4263-8F40-42F002CE66BE}.Release|x86.Build.0 = Release|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D1CC5322-7325-4F6B-9625-194B30BE1296}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {D1CC5322-7325-4F6B-9625-194B30BE1296}.Debug|x64.Build.0 = Debug|Any CPU
+ {D1CC5322-7325-4F6B-9625-194B30BE1296}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D1CC5322-7325-4F6B-9625-194B30BE1296}.Debug|x86.Build.0 = Debug|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D1CC5322-7325-4F6B-9625-194B30BE1296}.Release|x64.ActiveCfg = Release|Any CPU
+ {D1CC5322-7325-4F6B-9625-194B30BE1296}.Release|x64.Build.0 = Release|Any CPU
+ {D1CC5322-7325-4F6B-9625-194B30BE1296}.Release|x86.ActiveCfg = Release|Any CPU
+ {D1CC5322-7325-4F6B-9625-194B30BE1296}.Release|x86.Build.0 = Release|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3DF35E3D-D844-4399-A9A1-A9E923264C17}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {3DF35E3D-D844-4399-A9A1-A9E923264C17}.Debug|x64.Build.0 = Debug|Any CPU
+ {3DF35E3D-D844-4399-A9A1-A9E923264C17}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {3DF35E3D-D844-4399-A9A1-A9E923264C17}.Debug|x86.Build.0 = Debug|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3DF35E3D-D844-4399-A9A1-A9E923264C17}.Release|x64.ActiveCfg = Release|Any CPU
+ {3DF35E3D-D844-4399-A9A1-A9E923264C17}.Release|x64.Build.0 = Release|Any CPU
+ {3DF35E3D-D844-4399-A9A1-A9E923264C17}.Release|x86.ActiveCfg = Release|Any CPU
+ {3DF35E3D-D844-4399-A9A1-A9E923264C17}.Release|x86.Build.0 = Release|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Debug|x64.Build.0 = Debug|Any CPU
+ {C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Debug|x86.Build.0 = Debug|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Release|x64.ActiveCfg = Release|Any CPU
+ {C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Release|x64.Build.0 = Release|Any CPU
+ {C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Release|x86.ActiveCfg = Release|Any CPU
+ {C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Release|x86.Build.0 = Release|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Debug|x64.Build.0 = Debug|Any CPU
+ {C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Debug|x86.Build.0 = Debug|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Release|x64.ActiveCfg = Release|Any CPU
+ {C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Release|x64.Build.0 = Release|Any CPU
+ {C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Release|x86.ActiveCfg = Release|Any CPU
+ {C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Release|x86.Build.0 = Release|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B9AECA11-E248-4886-A10B-81B631CAAF29}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {B9AECA11-E248-4886-A10B-81B631CAAF29}.Debug|x64.Build.0 = Debug|Any CPU
+ {B9AECA11-E248-4886-A10B-81B631CAAF29}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {B9AECA11-E248-4886-A10B-81B631CAAF29}.Debug|x86.Build.0 = Debug|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B9AECA11-E248-4886-A10B-81B631CAAF29}.Release|x64.ActiveCfg = Release|Any CPU
+ {B9AECA11-E248-4886-A10B-81B631CAAF29}.Release|x64.Build.0 = Release|Any CPU
+ {B9AECA11-E248-4886-A10B-81B631CAAF29}.Release|x86.ActiveCfg = Release|Any CPU
+ {B9AECA11-E248-4886-A10B-81B631CAAF29}.Release|x86.Build.0 = Release|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|x64.Build.0 = Debug|Any CPU
+ {81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|x86.Build.0 = Debug|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Release|Any CPU.ActiveCfg = Release|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Release|Any CPU.Build.0 = Release|Any CPU
+ {81BB2C11-9408-4EA3-822E-42987AF54429}.Release|x64.ActiveCfg = Release|Any CPU
+ {81BB2C11-9408-4EA3-822E-42987AF54429}.Release|x64.Build.0 = Release|Any CPU
+ {81BB2C11-9408-4EA3-822E-42987AF54429}.Release|x86.ActiveCfg = Release|Any CPU
+ {81BB2C11-9408-4EA3-822E-42987AF54429}.Release|x86.Build.0 = Release|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|x64.Build.0 = Debug|Any CPU
+ {FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|x86.Build.0 = Debug|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|x64.ActiveCfg = Release|Any CPU
+ {FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|x64.Build.0 = Release|Any CPU
+ {FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|x86.ActiveCfg = Release|Any CPU
+ {FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|x86.Build.0 = Release|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Debug|x64.Build.0 = Debug|Any CPU
+ {0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Debug|x86.Build.0 = Debug|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Release|x64.ActiveCfg = Release|Any CPU
+ {0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Release|x64.Build.0 = Release|Any CPU
+ {0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Release|x86.ActiveCfg = Release|Any CPU
+ {0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Release|x86.Build.0 = Release|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {716364DE-B988-41A6-BAB4-327964266ECC}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {716364DE-B988-41A6-BAB4-327964266ECC}.Debug|x64.Build.0 = Debug|Any CPU
+ {716364DE-B988-41A6-BAB4-327964266ECC}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {716364DE-B988-41A6-BAB4-327964266ECC}.Debug|x86.Build.0 = Debug|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {716364DE-B988-41A6-BAB4-327964266ECC}.Release|x64.ActiveCfg = Release|Any CPU
+ {716364DE-B988-41A6-BAB4-327964266ECC}.Release|x64.Build.0 = Release|Any CPU
+ {716364DE-B988-41A6-BAB4-327964266ECC}.Release|x86.ActiveCfg = Release|Any CPU
+ {716364DE-B988-41A6-BAB4-327964266ECC}.Release|x86.Build.0 = Release|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C16F112F-38C3-40BC-9F5F-4791112063D6}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {C16F112F-38C3-40BC-9F5F-4791112063D6}.Debug|x64.Build.0 = Debug|Any CPU
+ {C16F112F-38C3-40BC-9F5F-4791112063D6}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {C16F112F-38C3-40BC-9F5F-4791112063D6}.Debug|x86.Build.0 = Debug|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Release|Any CPU.Build.0 = Release|Any CPU
- {DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Release|Any CPU.Build.0 = Release|Any CPU
- {2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Release|Any CPU.Build.0 = Release|Any CPU
- {D99A395A-8569-4DB0-B336-900647890052}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {D99A395A-8569-4DB0-B336-900647890052}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C16F112F-38C3-40BC-9F5F-4791112063D6}.Release|x64.ActiveCfg = Release|Any CPU
+ {C16F112F-38C3-40BC-9F5F-4791112063D6}.Release|x64.Build.0 = Release|Any CPU
+ {C16F112F-38C3-40BC-9F5F-4791112063D6}.Release|x86.ActiveCfg = Release|Any CPU
+ {C16F112F-38C3-40BC-9F5F-4791112063D6}.Release|x86.Build.0 = Release|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|x64.Build.0 = Debug|Any CPU
+ {BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|x86.Build.0 = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|x64.ActiveCfg = Release|Any CPU
+ {BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|x64.Build.0 = Release|Any CPU
+ {BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|x86.ActiveCfg = Release|Any CPU
+ {BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|x86.Build.0 = Release|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|x64.Build.0 = Debug|Any CPU
+ {7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|x86.Build.0 = Debug|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|Any CPU.Build.0 = Release|Any CPU
- {BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|x64.ActiveCfg = Release|Any CPU
+ {7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|x64.Build.0 = Release|Any CPU
+ {7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|x86.ActiveCfg = Release|Any CPU
+ {7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|x86.Build.0 = Release|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|x64.Build.0 = Debug|Any CPU
+ {6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|x86.Build.0 = Debug|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|x64.ActiveCfg = Release|Any CPU
+ {6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|x64.Build.0 = Release|Any CPU
+ {6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|x86.ActiveCfg = Release|Any CPU
+ {6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|x86.Build.0 = Release|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D4D09B08-D580-4D69-B886-C35D2853F6C8}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {D4D09B08-D580-4D69-B886-C35D2853F6C8}.Debug|x64.Build.0 = Debug|Any CPU
+ {D4D09B08-D580-4D69-B886-C35D2853F6C8}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D4D09B08-D580-4D69-B886-C35D2853F6C8}.Debug|x86.Build.0 = Debug|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D4D09B08-D580-4D69-B886-C35D2853F6C8}.Release|x64.ActiveCfg = Release|Any CPU
+ {D4D09B08-D580-4D69-B886-C35D2853F6C8}.Release|x64.Build.0 = Release|Any CPU
+ {D4D09B08-D580-4D69-B886-C35D2853F6C8}.Release|x86.ActiveCfg = Release|Any CPU
+ {D4D09B08-D580-4D69-B886-C35D2853F6C8}.Release|x86.Build.0 = Release|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|x64.Build.0 = Debug|Any CPU
+ {2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|x86.Build.0 = Debug|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|x64.ActiveCfg = Release|Any CPU
+ {2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|x64.Build.0 = Release|Any CPU
+ {2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|x86.ActiveCfg = Release|Any CPU
+ {2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|x86.Build.0 = Release|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|x64.Build.0 = Debug|Any CPU
+ {77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|x86.Build.0 = Debug|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|x64.ActiveCfg = Release|Any CPU
+ {77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|x64.Build.0 = Release|Any CPU
+ {77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|x86.ActiveCfg = Release|Any CPU
+ {77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|x86.Build.0 = Release|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {77F96ECE-4952-42DB-A528-DED25572A573}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {77F96ECE-4952-42DB-A528-DED25572A573}.Debug|x64.Build.0 = Debug|Any CPU
+ {77F96ECE-4952-42DB-A528-DED25572A573}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {77F96ECE-4952-42DB-A528-DED25572A573}.Debug|x86.Build.0 = Debug|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Release|Any CPU.ActiveCfg = Release|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Release|Any CPU.Build.0 = Release|Any CPU
+ {77F96ECE-4952-42DB-A528-DED25572A573}.Release|x64.ActiveCfg = Release|Any CPU
+ {77F96ECE-4952-42DB-A528-DED25572A573}.Release|x64.Build.0 = Release|Any CPU
+ {77F96ECE-4952-42DB-A528-DED25572A573}.Release|x86.ActiveCfg = Release|Any CPU
+ {77F96ECE-4952-42DB-A528-DED25572A573}.Release|x86.Build.0 = Release|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|x64.Build.0 = Debug|Any CPU
+ {AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|x86.Build.0 = Debug|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|x64.ActiveCfg = Release|Any CPU
+ {AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|x64.Build.0 = Release|Any CPU
+ {AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|x86.ActiveCfg = Release|Any CPU
+ {AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|x86.Build.0 = Release|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|x64.Build.0 = Debug|Any CPU
+ {7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|x86.Build.0 = Debug|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|x64.ActiveCfg = Release|Any CPU
+ {7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|x64.Build.0 = Release|Any CPU
+ {7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|x86.ActiveCfg = Release|Any CPU
+ {7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|x86.Build.0 = Release|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|x64.Build.0 = Debug|Any CPU
+ {B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|x86.Build.0 = Debug|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|x64.ActiveCfg = Release|Any CPU
+ {B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|x64.Build.0 = Release|Any CPU
+ {B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|x86.ActiveCfg = Release|Any CPU
+ {B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|x86.Build.0 = Release|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|x64.Build.0 = Debug|Any CPU
+ {4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|x86.Build.0 = Debug|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Release|x64.ActiveCfg = Release|Any CPU
+ {4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Release|x64.Build.0 = Release|Any CPU
+ {4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Release|x86.ActiveCfg = Release|Any CPU
+ {4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Release|x86.Build.0 = Release|Any CPU
+ {F6F9826A-BC58-4D78-A700-F358A66B2B06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F6F9826A-BC58-4D78-A700-F358A66B2B06}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F6F9826A-BC58-4D78-A700-F358A66B2B06}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {F6F9826A-BC58-4D78-A700-F358A66B2B06}.Debug|x64.Build.0 = Debug|Any CPU
+ {F6F9826A-BC58-4D78-A700-F358A66B2B06}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {F6F9826A-BC58-4D78-A700-F358A66B2B06}.Debug|x86.Build.0 = Debug|Any CPU
+ {F6F9826A-BC58-4D78-A700-F358A66B2B06}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F6F9826A-BC58-4D78-A700-F358A66B2B06}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F6F9826A-BC58-4D78-A700-F358A66B2B06}.Release|x64.ActiveCfg = Release|Any CPU
+ {F6F9826A-BC58-4D78-A700-F358A66B2B06}.Release|x64.Build.0 = Release|Any CPU
+ {F6F9826A-BC58-4D78-A700-F358A66B2B06}.Release|x86.ActiveCfg = Release|Any CPU
+ {F6F9826A-BC58-4D78-A700-F358A66B2B06}.Release|x86.Build.0 = Release|Any CPU
+ {D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Debug|x64.Build.0 = Debug|Any CPU
+ {D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Debug|x86.Build.0 = Debug|Any CPU
+ {D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Release|x64.ActiveCfg = Release|Any CPU
+ {D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Release|x64.Build.0 = Release|Any CPU
+ {D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Release|x86.ActiveCfg = Release|Any CPU
+ {D728444C-3D1F-4A0E-B4C9-5C9375D47EA3}.Release|x86.Build.0 = Release|Any CPU
+ {988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Debug|x64.Build.0 = Debug|Any CPU
+ {988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Debug|x86.Build.0 = Debug|Any CPU
+ {988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Release|Any CPU.Build.0 = Release|Any CPU
+ {988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Release|x64.ActiveCfg = Release|Any CPU
+ {988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Release|x64.Build.0 = Release|Any CPU
+ {988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Release|x86.ActiveCfg = Release|Any CPU
+ {988E6191-82E1-4E13-9DDB-CB9FA2FDAF29}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {F6F9826A-BC58-4D78-A700-F358A66B2B06} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
+ {D728444C-3D1F-4A0E-B4C9-5C9375D47EA3} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
+ {988E6191-82E1-4E13-9DDB-CB9FA2FDAF29} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
+ EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {110169B3-3328-4730-8AB0-BA05BEF75C1A}
EndGlobalSection
diff --git a/assets/locales.json b/assets/locales.json
index 02f7d033c..242d66108 100644
--- a/assets/locales.json
+++ b/assets/locales.json
@@ -4893,12 +4893,12 @@
}
},
{
- "ID": "SettingsTabSystemAudioBackendSDL2",
+ "ID": "SettingsTabSystemAudioBackendSDL3",
"Translations": {
"ar_SA": null,
"de_DE": null,
"el_GR": null,
- "en_US": "SDL2",
+ "en_US": "SDL3",
"es_ES": null,
"fr_FR": null,
"he_IL": null,
@@ -16370,26 +16370,26 @@
{
"ID": "AudioBackendTooltip",
"Translations": {
- "ar_SA": "يغير الواجهة الخلفية المستخدمة لتقديم الصوت.\n\nSDL2 هو الخيار المفضل، بينما يتم استخدام OpenAL وSoundIO كبديلين. زائف لن يكون لها صوت.\n\nاضبط على SDL2 إذا لم تكن متأكدا.",
- "de_DE": "Ä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.",
+ "ar_SA": "يغير الواجهة الخلفية المستخدمة لتقديم الصوت.\n\nSDL3 هو الخيار المفضل، بينما يتم استخدام OpenAL وSoundIO كبديلين. زائف لن يكون لها صوت.\n\nاضبط على SDL3 إذا لم تكن متأكدا.",
+ "de_DE": "Ä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.",
"el_GR": "Αλλαγή ήχου υποστήριξης",
- "en_US": "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.",
- "es_ES": "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.",
- "fr_FR": "Modifie la backend utilisé pour donner un rendu audio.\n\nSDL2 est recommandé, tandis que OpenAL et SoundIO sont utilisés en secours. Dummy ne produit aucun son.\n\nLaissez sur SDL2 si vous n'êtes pas sûr.",
- "he_IL": "משנה את אחראי השמע.\n\nSDL2 הוא הנבחר, למראת שOpenAL וגם SoundIO משומשים כאפשרויות חלופיות. אפשרות הDummy לא תשמיע קול כלל.\n\nמוטב להשאיר על SDL2 אם לא בטוחים.",
- "it_IT": "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.",
- "ja_JP": "音声レンダリングに使用するバックエンドを変更します.\n\nSDL2 が優先され, OpenAL と SoundIO はフォールバックとして使用されます. ダミーは音声出力しません.\n\nよくわからない場合は SDL2 を設定してください.",
- "ko_KR": "오디오 렌더링에 사용되는 백엔드를 변경합니다.\n\nSDL2가 선호되는 반면 OpenAL 및 SoundIO는 대체 수단으로 사용됩니다. 더미에는 소리가 나지 않습니다.\n\n모르면 SDL2로 설정하세요.",
- "no_NO": "Endrer backend brukt til å gjengi lyd.\n\nSDL2 er foretrukket, mens OpenAL og SoundIO brukes som reserveløsning. Dummy kommer ikke til å ha lyd.\n\nSett til SDL2 hvis usikker.",
- "pl_PL": "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.",
- "pt_BR": "Altera o módulo usado para renderizar áudio.\n\nSDL2 é o preferido, enquanto OpenAL e SoundIO são usados como fallbacks. Dummy não terá som.\n\nDefina como SDL2 se não tiver certeza.",
- "ru_RU": "Меняет бэкенд используемый для воспроизведения аудио.\n\nSDL2 — предпочтительный вариант, в то время как OpenAL и SoundIO используются как резервные. Dummy не будет воспроизводить звук.\n\nРекомендуется использовать SDL2.",
- "sv_SE": "Ändrar bakänden som används för att rendera ljud.\n\nSDL2 är den föredragna, men OpenAL och SoundIO används för att falla tillbaka på. Dummy har inget ljud.\n\nStäll in till SDL2 om du är osäker.",
- "th_TH": "เปลี่ยนแบ็กเอนด์ที่ใช้ในการเรนเดอร์เสียง\n\nแนะนำเป็น SDL2 ในขณะที่ OpenAL และ SoundIO ถูกใช้เป็นทางเลือกสำรอง ดัมมี่จะไม่มีเสียง\n\nตั้งค่าเป็น SDL2 หากคุณไม่แน่ใจ",
- "tr_TR": "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.",
- "uk_UA": "Змінює серверну частину, яка використовується для відтворення аудіо.\n\nSDL2 є кращим, тоді як OpenAL і SoundIO використовуються як резервні варіанти. Dummy не матиме звуку.\n\nВстановіть SDL2, якщо не впевнені.",
- "zh_CN": "更改音频处理引擎。\n\n推荐选择“SDL2”,另外“OpenAL”和“SoundIO”可以作为备选,选择“无”将没有声音。\n\n如果不确定,请设置为“SDL2”。",
- "zh_TW": "變更用於繪製音訊的後端。\n\nSDL2 是首選,而 OpenAL 和 SoundIO 則作為備用。虛設 (Dummy) 將沒有聲音。\n\n如果不確定,請設定為 SDL2。"
+ "en_US": "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.",
+ "es_ES": "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.",
+ "fr_FR": "Modifie la backend utilisé pour donner un rendu audio.\n\nSDL3 est recommandé, tandis que OpenAL et SoundIO sont utilisés en secours. Dummy ne produit aucun son.\n\nLaissez sur SDL3 si vous n'êtes pas sûr.",
+ "he_IL": "משנה את אחראי השמע.\n\nSDL3 הוא הנבחר, למראת שOpenAL וגם SoundIO משומשים כאפשרויות חלופיות. אפשרות הDummy לא תשמיע קול כלל.\n\nמוטב להשאיר על SDL3 אם לא בטוחים.",
+ "it_IT": "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.",
+ "ja_JP": "音声レンダリングに使用するバックエンドを変更します.\n\nSDL3 が優先され, OpenAL と SoundIO はフォールバックとして使用されます. ダミーは音声出力しません.\n\nよくわからない場合は SDL3 を設定してください.",
+ "ko_KR": "오디오 렌더링에 사용되는 백엔드를 변경합니다.\n\nSDL3가 선호되는 반면 OpenAL 및 SoundIO는 대체 수단으로 사용됩니다. 더미에는 소리가 나지 않습니다.\n\n모르면 SDL3로 설정하세요.",
+ "no_NO": "Endrer backend brukt til å gjengi lyd.\n\nSDL3 er foretrukket, mens OpenAL og SoundIO brukes som reserveløsning. Dummy kommer ikke til å ha lyd.\n\nSett til SDL3 hvis usikker.",
+ "pl_PL": "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.",
+ "pt_BR": "Altera o módulo usado para renderizar áudio.\n\nSDL3 é o preferido, enquanto OpenAL e SoundIO são usados como fallbacks. Dummy não terá som.\n\nDefina como SDL3 se não tiver certeza.",
+ "ru_RU": "Меняет бэкенд используемый для воспроизведения аудио.\n\nSDL3 — предпочтительный вариант, в то время как OpenAL и SoundIO используются как резервные. Dummy не будет воспроизводить звук.\n\nРекомендуется использовать SDL3.",
+ "sv_SE": "Ändrar bakänden som används för att rendera ljud.\n\nSDL3 är den föredragna, men OpenAL och SoundIO används för att falla tillbaka på. Dummy har inget ljud.\n\nStäll in till SDL3 om du är osäker.",
+ "th_TH": "เปลี่ยนแบ็กเอนด์ที่ใช้ในการเรนเดอร์เสียง\n\nแนะนำเป็น SDL3 ในขณะที่ OpenAL และ SoundIO ถูกใช้เป็นทางเลือกสำรอง ดัมมี่จะไม่มีเสียง\n\nตั้งค่าเป็น SDL3 หากคุณไม่แน่ใจ",
+ "tr_TR": "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.",
+ "uk_UA": "Змінює серверну частину, яка використовується для відтворення аудіо.\n\nSDL3 є кращим, тоді як OpenAL і SoundIO використовуються як резервні варіанти. Dummy не матиме звуку.\n\nВстановіть SDL3, якщо не впевнені.",
+ "zh_CN": "更改音频处理引擎。\n\n推荐选择“SDL3”,另外“OpenAL”和“SoundIO”可以作为备选,选择“无”将没有声音。\n\n如果不确定,请设置为“SDL3”。",
+ "zh_TW": "變更用於繪製音訊的後端。\n\nSDL3 是首選,而 OpenAL 和 SoundIO 則作為備用。虛設 (Dummy) 將沒有聲音。\n\n如果不確定,請設定為 SDL3。"
}
},
{
diff --git a/distribution/linux/Ryujinx.sh b/distribution/linux/Ryujinx.sh
index daeea9bfd..5793f8359 100755
--- a/distribution/linux/Ryujinx.sh
+++ b/distribution/linux/Ryujinx.sh
@@ -2,8 +2,8 @@
SCRIPT_DIR=$(dirname "$(realpath "$0")")
-if [ -f "$SCRIPT_DIR/Ryujinx.Headless.SDL2" ]; then
- RYUJINX_BIN="Ryujinx.Headless.SDL2"
+if [ -f "$SCRIPT_DIR/Ryujinx.Headless.SDL3" ]; then
+ RYUJINX_BIN="Ryujinx.Headless.SDL3"
fi
if [ -f "$SCRIPT_DIR/Ryujinx" ]; then
diff --git a/distribution/macos/create_macos_build_headless.sh b/distribution/macos/create_macos_build_headless.sh
index 6052b202c..e7843f438 100755
--- a/distribution/macos/create_macos_build_headless.sh
+++ b/distribution/macos/create_macos_build_headless.sh
@@ -43,7 +43,7 @@ fi
ARM64_OUTPUT="$TEMP_DIRECTORY/publish_arm64"
X64_OUTPUT="$TEMP_DIRECTORY/publish_x64"
UNIVERSAL_OUTPUT="$OUTPUT_DIRECTORY/publish"
-EXECUTABLE_SUB_PATH=Ryujinx.Headless.SDL2
+EXECUTABLE_SUB_PATH=Ryujinx.Headless.SDL3
rm -rf "$TEMP_DIRECTORY"
mkdir -p "$TEMP_DIRECTORY"
@@ -51,9 +51,9 @@ mkdir -p "$TEMP_DIRECTORY"
DOTNET_COMMON_ARGS=(-p:DebugType=embedded -p:Version="$VERSION" -p:SourceRevisionId="$SOURCE_REVISION_ID" --self-contained true $EXTRA_ARGS)
dotnet restore
-dotnet build -c "$CONFIGURATION" src/Ryujinx.Headless.SDL2
-dotnet publish -c "$CONFIGURATION" -r osx-arm64 -o "$TEMP_DIRECTORY/publish_arm64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Headless.SDL2
-dotnet publish -c "$CONFIGURATION" -r osx-x64 -o "$TEMP_DIRECTORY/publish_x64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Headless.SDL2
+dotnet build -c "$CONFIGURATION" src/Ryujinx.Headless.SDL3
+dotnet publish -c "$CONFIGURATION" -r osx-arm64 -o "$TEMP_DIRECTORY/publish_arm64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Headless.SDL3
+dotnet publish -c "$CONFIGURATION" -r osx-x64 -o "$TEMP_DIRECTORY/publish_x64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Headless.SDL3
# Get rid of the support library for ARMeilleure for x64 (that's only for arm64)
rm -rf "$TEMP_DIRECTORY/publish_x64/libarmeilleure-jitsupport.dylib"
@@ -115,8 +115,8 @@ fi
echo "Creating archive"
pushd "$OUTPUT_DIRECTORY"
-tar --exclude "publish/Ryujinx.Headless.SDL2" -cvf "$RELEASE_TAR_FILE_NAME" publish 1> /dev/null
-python3 "$BASE_DIR/distribution/misc/add_tar_exec.py" "$RELEASE_TAR_FILE_NAME" "publish/Ryujinx.Headless.SDL2" "publish/Ryujinx.Headless.SDL2"
+tar --exclude "publish/Ryujinx.Headless.SDL3" -cvf "$RELEASE_TAR_FILE_NAME" publish 1> /dev/null
+python3 "$BASE_DIR/distribution/misc/add_tar_exec.py" "$RELEASE_TAR_FILE_NAME" "publish/Ryujinx.Headless.SDL3" "publish/Ryujinx.Headless.SDL3"
gzip -9 < "$RELEASE_TAR_FILE_NAME" > "$RELEASE_TAR_FILE_NAME.gz"
rm "$RELEASE_TAR_FILE_NAME"
popd
diff --git a/docs/README.md b/docs/README.md
index a22da3c7c..80a1cf0be 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -8,7 +8,7 @@ Intro to Ryujinx
Ryujinx is an open-source Nintendo Switch emulator, created by gdkchan, written in C#.
* 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/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 d5381209e..646d67e73 100644
--- a/src/Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceDriver.cs
+++ b/src/Ryujinx.Audio.Backends.SDL3/SDL3HardwareDeviceDriver.cs
@@ -2,42 +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 class SDL2HardwareDeviceDriver : IHardwareDeviceDriver
+
+ using unsafe SDL_AudioStreamCallbackPointer = delegate* unmanaged[Cdecl];
+
+ public 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.
- [DllImport("SDL2")]
- private static extern int SDL_GetDefaultAudioInfo(nint name, out SDL_AudioSpec spec, int isCapture);
-
- 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 SDL_AudioSpec 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()}\"");
@@ -54,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()
@@ -90,67 +89,69 @@ 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);
+ Console.WriteLine(got.freq);
- 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;
@@ -166,12 +167,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 9170b73c7..377d86d2b 100644
--- a/src/Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceSession.cs
+++ b/src/Ryujinx.Audio.Backends.SDL3/SDL3HardwareDeviceSession.cs
@@ -6,36 +6,43 @@ 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
{
- class SDL2HardwareDeviceSession : HardwareDeviceSessionOutputBase
+
+
+
+ unsafe 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 +51,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 unsafe 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 +107,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 +126,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 +167,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 +192,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 +205,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 +218,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 +233,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 c3e4402b2..bf6a1e772 100644
--- a/src/Ryujinx.Common/Configuration/Hid/InputBackendType.cs
+++ b/src/Ryujinx.Common/Configuration/Hid/InputBackendType.cs
@@ -8,6 +8,6 @@ namespace Ryujinx.Common.Configuration.Hid
{
Invalid,
WindowKeyboard,
- GamepadSDL2,
+ GamepadSDL3,
}
}
diff --git a/src/Ryujinx.Common/Configuration/Hid/JsonInputConfigConverter.cs b/src/Ryujinx.Common/Configuration/Hid/JsonInputConfigConverter.cs
index 6c2a69b88..ec2fa14da 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.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.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 5b3756fb6..000000000
--- a/src/Ryujinx.Input.SDL2/SDL2GamepadDriver.cs
+++ /dev/null
@@ -1,236 +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()[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.Remove(joystickInstanceId, out string id))
- return;
-
- 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);
- }
-
- public IEnumerable GetGamepads()
- {
- lock (_gamepadsIds)
- {
- foreach (string gamepadId in _gamepadsIds)
- {
- yield return GetGamepad(gamepadId);
- }
- }
- }
- }
-}
diff --git a/src/Ryujinx.Input.SDL2/Ryujinx.Input.SDL2.csproj b/src/Ryujinx.Input.SDL3/Ryujinx.Input.SDL3.csproj
similarity index 69%
rename from src/Ryujinx.Input.SDL2/Ryujinx.Input.SDL2.csproj
rename to src/Ryujinx.Input.SDL3/Ryujinx.Input.SDL3.csproj
index 89f5adda1..06f25ace7 100644
--- a/src/Ryujinx.Input.SDL2/Ryujinx.Input.SDL2.csproj
+++ b/src/Ryujinx.Input.SDL3/Ryujinx.Input.SDL3.csproj
@@ -1,4 +1,4 @@
-
+
true
@@ -7,7 +7,7 @@
-
+
diff --git a/src/Ryujinx.Input.SDL2/SDL2Gamepad.cs b/src/Ryujinx.Input.SDL3/SDL3Gamepad.cs
similarity index 74%
rename from src/Ryujinx.Input.SDL2/SDL2Gamepad.cs
rename to src/Ryujinx.Input.SDL3/SDL3Gamepad.cs
index 39401b4be..707fdb909 100644
--- a/src/Ryujinx.Input.SDL2/SDL2Gamepad.cs
+++ b/src/Ryujinx.Input.SDL3/SDL3Gamepad.cs
@@ -6,11 +6,12 @@ using System;
using System.Collections.Generic;
using System.Numerics;
using System.Threading;
-using static SDL2.SDL;
+using SDL;
+using static SDL.SDL3;
-namespace Ryujinx.Input.SDL2
+namespace Ryujinx.Input.SDL3
{
- public class SDL2Gamepad : IGamepad
+ public unsafe class SDL3Gamepad : IGamepad
{
private bool HasConfiguration => _configuration != null;
@@ -21,43 +22,43 @@ namespace Ryujinx.Input.SDL2
private StandardControllerInputConfig _configuration;
- private static readonly SDL_GameControllerButton[] _buttonsDriverMapping =
+ private static 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();
@@ -73,16 +74,16 @@ 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;
@@ -90,12 +91,12 @@ namespace Ryujinx.Input.SDL2
// 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}.");
}
@@ -111,7 +112,7 @@ namespace Ryujinx.Input.SDL2
byte green = packedRgb > 0 ? (byte)(packedRgb >> 8) : (byte)0;
byte blue = packedRgb > 0 ? (byte)(packedRgb % 256) : (byte)0;
- if (SDL_GameControllerSetLED(_gamepadHandle, red, green, blue) != 0)
+ if (!SDL_SetGamepadLED(_gamepadHandle, red, green, blue))
Logger.Debug?.Print(LogClass.Hid, "LED setting failed; probably in the middle of disconnecting.");
}
@@ -119,21 +120,24 @@ 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;
}
-
- if (SDL_GameControllerHasRumble(_gamepadHandle) == SDL_bool.SDL_TRUE)
+ SDL_PropertiesID propID = SDL_GetGamepadProperties(_gamepadHandle);
+ SDL_LockProperties(propID);
+ if (SDL_GetBooleanProperty(propID, SDL_PROP_GAMEPAD_CAP_RUMBLE_BOOLEAN, false))
{
result |= GamepadFeaturesFlag.Rumble;
}
- if (SDL_GameControllerHasLED(_gamepadHandle) == SDL_bool.SDL_TRUE)
+ if (SDL_GetBooleanProperty(propID, SDL_PROP_GAMEPAD_CAP_MONO_LED_BOOLEAN, false))
{
result |= GamepadFeaturesFlag.Led;
}
+ SDL_UnlockProperties(propID);
+ SDL_DestroyProperties(propID);
return result;
}
@@ -141,15 +145,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;
}
}
@@ -174,7 +178,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)
@@ -183,7 +187,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.");
}
}
@@ -197,18 +201,16 @@ namespace Ryujinx.Input.SDL2
_ => 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]);
@@ -380,11 +382,11 @@ namespace Ryujinx.Input.SDL2
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}")
};
@@ -393,17 +395,17 @@ namespace Ryujinx.Input.SDL2
switch (inputId)
{
case GamepadButtonInputId.LeftTrigger:
- return ConvertRawStickValue(SDL_GameControllerGetAxis(_gamepadHandle, SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERLEFT)) > _triggerThreshold;
+ return ConvertRawStickValue(SDL_GetGamepadAxis(_gamepadHandle, SDL_GamepadAxis.SDL_GAMEPAD_AXIS_LEFT_TRIGGER)) > _triggerThreshold;
case GamepadButtonInputId.RightTrigger:
- return ConvertRawStickValue(SDL_GameControllerGetAxis(_gamepadHandle, SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERRIGHT)) > _triggerThreshold;
+ return ConvertRawStickValue(SDL_GetGamepadAxis(_gamepadHandle, SDL_GamepadAxis.SDL_GAMEPAD_AXIS_RIGHT_TRIGGER)) > _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..ac0e7f22e
--- /dev/null
+++ b/src/Ryujinx.Input.SDL3/SDL3GamepadDriver.cs
@@ -0,0 +1,248 @@
+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 unsafe 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[0..8]}-{strGuid[8..12]}-{strGuid[12..16]}-{strGuid[16..20]}-{strGuid[20..32]}";
+
+ }
+
+ private unsafe 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))
+ {
+ _gamepadsIds.Remove(GetInstanceIdFromId(SDL3JoyConPair.Id));
+ _gamepadsIds.Add(joystickInstanceId, SDL3JoyConPair.Id);
+ 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 1762f19d3..d71b06dda 100644
--- a/src/Ryujinx.Input.SDL2/SDL2JoyCon.cs
+++ b/src/Ryujinx.Input.SDL3/SDL3JoyCon.cs
@@ -5,11 +5,12 @@ using System;
using System.Collections.Generic;
using System.Numerics;
using System.Threading;
-using static SDL2.SDL;
+using 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;
}
}
@@ -170,8 +167,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)
@@ -180,7 +176,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.");
}
}
@@ -199,13 +195,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
@@ -392,18 +385,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 SDL_GameControllerButton 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 70%
rename from src/Ryujinx.Input.SDL2/SDL2JoyConPair.cs
rename to src/Ryujinx.Input.SDL3/SDL3JoyConPair.cs
index dce767523..08f6f7d37 100644
--- a/src/Ryujinx.Input.SDL2/SDL2JoyConPair.cs
+++ b/src/Ryujinx.Input.SDL3/SDL3JoyConPair.cs
@@ -2,11 +2,12 @@ using Ryujinx.Common.Configuration.Hid;
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);
@@ -95,40 +96,44 @@ namespace Ryujinx.Input.SDL2
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)
{
- List 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.LeftName, 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 1cbf4d35c..f5da11a19 100644
--- a/src/Ryujinx.Input.SDL2/SDL2Keyboard.cs
+++ b/src/Ryujinx.Input.SDL3/SDL3Keyboard.cs
@@ -6,13 +6,14 @@ using System.Collections.Generic;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Threading;
-using static SDL2.SDL;
+using 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)
{
@@ -22,11 +23,12 @@ 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;
+
private static readonly SDL_Keycode[] _keysDriverMapping =
[
// INVALID
@@ -116,32 +118,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,
@@ -152,14 +154,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,
@@ -169,7 +171,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;
@@ -193,55 +195,53 @@ namespace Ryujinx.Input.SDL2
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static int ToSDL2Scancode(Key key)
+ private unsafe static int ToSDL3Scancode(Key key)
{
if (key is >= Key.Unknown and <= 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;
+ SDLBool* rawKeyboardState;
SDL_Keymod rawKeyboardModifierState = SDL_GetModState();
unsafe
{
- nint statePtr = SDL_GetKeyboardState(out int numKeys);
-
- rawKeyboardState = new ReadOnlySpan((byte*)statePtr, numKeys);
+ 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;
}
@@ -250,7 +250,7 @@ namespace Ryujinx.Input.SDL2
}
else
{
- keysState[(int)key] = rawKeyboardState[index] == 1;
+ keysState[(int)key] = rawKeyboardState[index];
}
}
@@ -388,7 +388,7 @@ namespace Ryujinx.Input.SDL2
public void SetLed(uint packedRgb)
{
- Logger.Info?.Print(LogClass.UI, "SetLed called on an SDL2Keyboard");
+ Logger.Info?.Print(LogClass.UI, "SetLed called on an SDL3Keyboard");
}
public void SetTriggerThreshold(float triggerThreshold)
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 eb86fa799..9fdeb36ab 100644
--- a/src/Ryujinx.Input.SDL2/SDL2Mouse.cs
+++ b/src/Ryujinx.Input.SDL3/SDL3Mouse.cs
@@ -4,17 +4,17 @@ using System;
using System.Drawing;
using System.Numerics;
-namespace Ryujinx.Input.SDL2
+namespace Ryujinx.Input.SDL3
{
- public class SDL2Mouse : IMouse
+ public 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;
@@ -22,7 +22,7 @@ namespace Ryujinx.Input.SDL2
Size IMouse.ClientSize => _driver.GetClientSize();
- public SDL2Mouse(SDL2MouseDriver driver)
+ public SDL3Mouse(SDL3MouseDriver driver)
{
_driver = driver;
}
@@ -79,7 +79,7 @@ namespace Ryujinx.Input.SDL2
public void SetLed(uint packedRgb)
{
- Logger.Info?.Print(LogClass.UI, "SetLed called on an SDL2Mouse");
+ Logger.Info?.Print(LogClass.UI, "SetLed called on an SDL3Mouse");
}
public void SetTriggerThreshold(float triggerThreshold)
diff --git a/src/Ryujinx.Input.SDL2/SDL2MouseDriver.cs b/src/Ryujinx.Input.SDL3/SDL3MouseDriver.cs
similarity index 81%
rename from src/Ryujinx.Input.SDL2/SDL2MouseDriver.cs
rename to src/Ryujinx.Input.SDL3/SDL3MouseDriver.cs
index a1f6c1d7b..e24f20b1c 100644
--- a/src/Ryujinx.Input.SDL2/SDL2MouseDriver.cs
+++ b/src/Ryujinx.Input.SDL3/SDL3MouseDriver.cs
@@ -6,11 +6,12 @@ using System.Diagnostics;
using System.Drawing;
using System.Numerics;
using System.Runtime.CompilerServices;
-using static SDL2.SDL;
+using 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
@@ -25,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.");
}
@@ -49,9 +50,11 @@ namespace Ryujinx.Input.SDL2
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)
@@ -76,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.");
}
@@ -88,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.");
}
@@ -100,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 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);
}
@@ -116,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;
@@ -144,7 +147,7 @@ namespace Ryujinx.Input.SDL2
return ClientSize;
}
- public string DriverName => "SDL2";
+ public string DriverName => "SDL3";
public event Action OnGamepadConnected
{
@@ -162,7 +165,7 @@ namespace Ryujinx.Input.SDL2
public IGamepad GetGamepad(string id)
{
- return new SDL2Mouse(this);
+ return new SDL3Mouse(this);
}
public IEnumerable GetGamepads() => [GetGamepad("0")];
diff --git a/src/Ryujinx.Input.SDL2/SDLKeyboardDriver.cs b/src/Ryujinx.Input.SDL3/SDLKeyboardDriver.cs
similarity index 76%
rename from src/Ryujinx.Input.SDL2/SDLKeyboardDriver.cs
rename to src/Ryujinx.Input.SDL3/SDLKeyboardDriver.cs
index 25c6f4fe6..cd2a067be 100644
--- a/src/Ryujinx.Input.SDL2/SDLKeyboardDriver.cs
+++ b/src/Ryujinx.Input.SDL3/SDLKeyboardDriver.cs
@@ -1,17 +1,17 @@
-using Ryujinx.SDL2.Common;
+using Ryujinx.SDL3.Common;
using System;
using System.Collections.Generic;
-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"];
@@ -33,7 +33,7 @@ namespace Ryujinx.Input.SDL2
{
if (disposing)
{
- SDL2Driver.Instance.Dispose();
+ SDL3Driver.Instance.Dispose();
}
}
@@ -50,7 +50,7 @@ namespace Ryujinx.Input.SDL2
return null;
}
- return new SDL2Keyboard(this, _keyboardIdentifers[0], "All keyboards");
+ return new SDL3Keyboard(this, _keyboardIdentifers[0], "All keyboards");
}
public IEnumerable GetGamepads()
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 895d1a9ce..53e856956 100644
--- a/src/Ryujinx.SDL2.Common/Ryujinx.SDL2.Common.csproj
+++ b/src/Ryujinx.SDL3.Common/Ryujinx.SDL3.Common.csproj
@@ -1,15 +1,16 @@
+ true
$(DefaultItemExcludes);._*
-
-
-
-
+
+
+
+
diff --git a/src/Ryujinx.SDL2.Common/SDL2Driver.cs b/src/Ryujinx.SDL3.Common/SDL3Driver.cs
similarity index 58%
rename from src/Ryujinx.SDL2.Common/SDL2Driver.cs
rename to src/Ryujinx.SDL3.Common/SDL3Driver.cs
index df11966bc..529a846e0 100644
--- a/src/Ryujinx.SDL2.Common/SDL2Driver.cs
+++ b/src/Ryujinx.SDL3.Common/SDL3Driver.cs
@@ -5,19 +5,20 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Threading;
-using static SDL2.SDL;
+using 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,20 +55,19 @@ 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");
SDL_SetHint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER, "1");
- // NOTE: As of SDL2 2.24.0, joycons are combined by default but the motion source only come from one of them.
+ // NOTE: As of SDL3 2.24.0, joycons are combined by default but the motion source only come from one of them.
// 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);
@@ -79,78 +75,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))
{
@@ -159,7 +154,7 @@ namespace Ryujinx.SDL2.Common
}
}
- private void EventWorker()
+ private unsafe void EventWorker()
{
const int WaitTimeMs = 10;
@@ -169,7 +164,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/Headless/HeadlessRyujinx.Init.cs b/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs
index e2fa68397..af61b7b63 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.Ava.Systems;
using Ryujinx.Ava.Systems.Configuration;
@@ -157,7 +157,7 @@ namespace Ryujinx.Headless
config = new StandardControllerInputConfig
{
Version = InputConfig.CurrentVersion,
- Backend = InputBackendType.GamepadSDL2,
+ Backend = InputBackendType.GamepadSDL3,
Id = null,
ControllerType = ControllerType.JoyconPair,
DeadzoneLeft = 0.1f,
@@ -305,8 +305,8 @@ namespace Ryujinx.Headless
return new VulkanRenderer(
api,
- (instance, vk) => new SurfaceKHR((ulong)(vulkanWindow.CreateWindowSurface(instance.Handle))),
- vulkanWindow.GetRequiredInstanceExtensions,
+ (instance, vk) => new SurfaceKHR((ulong)vulkanWindow.CreateWindowSurface(instance.Handle)),
+ VulkanWindow.GetRequiredInstanceExtensions,
preferredGpuId);
}
@@ -350,7 +350,7 @@ namespace Ryujinx.Headless
_accountManager,
_userChannelPersistence,
renderer.TryMakeThreaded(options.BackendThreading),
- new SDL2HardwareDeviceDriver(),
+ new SDL3HardwareDeviceDriver(),
window
)
);
diff --git a/src/Ryujinx/Headless/HeadlessRyujinx.cs b/src/Ryujinx/Headless/HeadlessRyujinx.cs
index 9a06482f9..bba505dbb 100644
--- a/src/Ryujinx/Headless/HeadlessRyujinx.cs
+++ b/src/Ryujinx/Headless/HeadlessRyujinx.cs
@@ -22,13 +22,14 @@ 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 System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
+using SDL;
namespace Ryujinx.Headless
{
@@ -61,7 +62,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();
@@ -180,7 +181,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;
@@ -396,7 +397,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/Windows/OpenGLWindow.cs b/src/Ryujinx/Headless/Windows/OpenGLWindow.cs
index 02f24f218..0951f68f5 100644
--- a/src/Ryujinx/Headless/Windows/OpenGLWindow.cs
+++ b/src/Ryujinx/Headless/Windows/OpenGLWindow.cs
@@ -5,15 +5,17 @@ using Ryujinx.Common.Logging;
using Ryujinx.Graphics.OpenGL;
using Ryujinx.Input.HLE;
using System;
-using static SDL2.SDL;
+using SDL;
+using static SDL.SDL3;
+using System.Runtime.InteropServices;
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 +23,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 +48,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 unsafe 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 +86,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 +98,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)
{
@@ -109,7 +111,7 @@ namespace Ryujinx.Headless
}
}
- private SDL2OpenGLContext _openGLContext;
+ private SDL3OpenGLContext _openGLContext;
public OpenGLWindow(
InputManager inputManager,
@@ -128,10 +130,10 @@ namespace Ryujinx.Headless
{
// 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()}\"";
@@ -141,10 +143,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();
@@ -160,7 +162,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()}");
@@ -189,7 +192,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/Windows/VulkanWindow.cs b/src/Ryujinx/Headless/Windows/VulkanWindow.cs
index 2abbbd1e9..b71dbd728 100644
--- a/src/Ryujinx/Headless/Windows/VulkanWindow.cs
+++ b/src/Ryujinx/Headless/Windows/VulkanWindow.cs
@@ -1,10 +1,11 @@
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Input.HLE;
-using Ryujinx.SDL2.Common;
+using Ryujinx.SDL3.Common;
using System;
+using SDL;
+using static SDL.SDL3;
using System.Runtime.InteropServices;
-using static SDL2.SDL;
namespace Ryujinx.Headless
{
@@ -39,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()}\"";
@@ -60,9 +58,9 @@ namespace Ryujinx.Headless
}
}
- if (SDL2Driver.MainThreadDispatcher != null)
+ if (SDL3Driver.MainThreadDispatcher != null)
{
- SDL2Driver.MainThreadDispatcher(CreateSurface);
+ SDL3Driver.MainThreadDispatcher(CreateSurface);
}
else
{
@@ -72,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/Windows/WindowBase.cs b/src/Ryujinx/Headless/Windows/WindowBase.cs
index 14b090264..8e06a3f20 100644
--- a/src/Ryujinx/Headless/Windows/WindowBase.cs
+++ b/src/Ryujinx/Headless/Windows/WindowBase.cs
@@ -15,37 +15,34 @@ using Ryujinx.HLE.Loaders.Processes;
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 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 SDL;
+using static SDL.SDL3;
using AntiAliasing = Ryujinx.Common.Configuration.AntiAliasing;
using ScalingFilter = Ryujinx.Common.Configuration.ScalingFilter;
using Switch = Ryujinx.HLE.Switch;
using UserProfile = Ryujinx.HLE.HOS.Services.Account.Acc.UserProfile;
+using LibHac.Util;
namespace Ryujinx.Headless
{
- abstract partial class WindowBase : IHostUIHandler, IDisposable
+ abstract unsafe partial 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);
@@ -56,12 +53,12 @@ namespace Ryujinx.Headless
public Switch Device { get; private set; }
public IRenderer Renderer { get; private set; }
- 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; }
@@ -70,7 +67,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;
protected readonly GraphicsDebugLevel GlLogLevel;
@@ -83,7 +80,7 @@ namespace Ryujinx.Headless
private long _ticks;
private bool _isActive;
private bool _isStopped;
- private uint _windowId;
+ private SDL_WindowID _windowId;
private string _gpuDriverName;
@@ -99,7 +96,7 @@ namespace Ryujinx.Headless
HideCursorMode hideCursorMode,
bool ignoreControllerApplet)
{
- MouseDriver = new SDL2MouseDriver(hideCursorMode);
+ MouseDriver = new SDL3MouseDriver(hideCursorMode);
_inputManager = inputManager;
_inputManager.SetMouseDriver(MouseDriver);
NpadManager = _inputManager.CreateNpadManager();
@@ -116,7 +113,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)
@@ -155,11 +152,11 @@ namespace Ryujinx.Headless
{
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, (nuint)iconBytes.Length);
+ SDL_Surface* iconHandle = SDL_LoadBMP_IO(rwOpsStruct, true);
SDL_SetWindowIcon(WindowHandle, iconHandle);
- SDL_FreeSurface(iconHandle);
+ SDL_DestroySurface(iconHandle);
}
}
}
@@ -183,18 +180,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 | WindowFlags);
+ 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()}\"";
@@ -206,16 +212,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.
@@ -229,7 +235,7 @@ namespace Ryujinx.Headless
break;
- case SDL_WindowEventID.SDL_WINDOWEVENT_CLOSE:
+ case SDL_EventType.SDL_EVENT_WINDOW_CLOSE_REQUESTED:
Exit();
break;
}
@@ -409,7 +415,7 @@ namespace Ryujinx.Headless
// Get screen touch position
if (!_enableMouse)
{
- hasTouch = TouchScreenManager.Update(true, (_inputManager.MouseDriver as SDL2MouseDriver).IsButtonPressed(MouseButton.Button1), _aspectRatio.ToFloat());
+ hasTouch = TouchScreenManager.Update(true, (_inputManager.MouseDriver as SDL3MouseDriver).IsButtonPressed(MouseButton.Button1), _aspectRatio.ToFloat());
}
if (!hasTouch)
@@ -461,7 +467,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;
@@ -476,7 +482,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;
@@ -515,27 +521,36 @@ namespace Ryujinx.Headless
Exit();
}
- public bool DisplayErrorAppletDialog(string title, string message, string[] buttonsText, (uint Module, uint Description)? errorCode = null)
+ public unsafe bool DisplayErrorAppletDialog(string title, string message, string[] buttonsText, (uint Module, uint Description)? errorCode = null)
{
- 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
+ string buttonText = buttonsText[i];
+ fixed (byte* pButtonText = &buttonText.ToBytes()[0])
+ buttons[i] = new SDL_MessageBoxButtonData
{
- buttonid = i,
- text = buttonsText[i],
+ 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;
}
@@ -553,11 +568,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 b5b5447db..407c3a556 100644
--- a/src/Ryujinx/Program.cs
+++ b/src/Ryujinx/Program.cs
@@ -19,7 +19,7 @@ using Ryujinx.Common.Logging;
using Ryujinx.Common.SystemInterop;
using Ryujinx.Graphics.Vulkan.MoltenVK;
using Ryujinx.Headless;
-using Ryujinx.SDL2.Common;
+using Ryujinx.SDL3.Common;
using System;
using System.Collections.Generic;
using System.IO;
@@ -149,8 +149,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 3d40ae64e..31dc20aac 100644
--- a/src/Ryujinx/Ryujinx.csproj
+++ b/src/Ryujinx/Ryujinx.csproj
@@ -77,10 +77,10 @@
-
+
-
+
diff --git a/src/Ryujinx/Systems/AppHost.cs b/src/Ryujinx/Systems/AppHost.cs
index 0aca8d3a4..1f397cdd5 100644
--- a/src/Ryujinx/Systems/AppHost.cs
+++ b/src/Ryujinx/Systems/AppHost.cs
@@ -8,7 +8,7 @@ using LibHac.Common;
using LibHac.Ns;
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;
@@ -949,7 +949,7 @@ namespace Ryujinx.Ava.Systems
{
List availableBackends =
[
- AudioBackend.SDL2,
+ AudioBackend.SDL3,
AudioBackend.SoundIo,
AudioBackend.OpenAl,
AudioBackend.Dummy
@@ -988,7 +988,7 @@ namespace Ryujinx.Ava.Systems
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/Systems/Configuration/AudioBackend.cs b/src/Ryujinx/Systems/Configuration/AudioBackend.cs
index a0aa30f38..af8b7f0b5 100644
--- a/src/Ryujinx/Systems/Configuration/AudioBackend.cs
+++ b/src/Ryujinx/Systems/Configuration/AudioBackend.cs
@@ -9,6 +9,6 @@ namespace Ryujinx.Ava.Systems.Configuration
Dummy,
OpenAl,
SoundIo,
- SDL2,
+ SDL3,
}
}
diff --git a/src/Ryujinx/Systems/Configuration/ConfigurationState.cs b/src/Ryujinx/Systems/Configuration/ConfigurationState.cs
index 185aedf64..0e2f6aaec 100644
--- a/src/Ryujinx/Systems/Configuration/ConfigurationState.cs
+++ b/src/Ryujinx/Systems/Configuration/ConfigurationState.cs
@@ -207,7 +207,7 @@ namespace Ryujinx.Ava.Systems.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/UI/Models/Input/GamepadInputConfig.cs b/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs
index 526e63afe..fa08156af 100644
--- a/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs
+++ b/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs
@@ -205,7 +205,7 @@ namespace Ryujinx.Ava.UI.Models.Input
{
Id = Id,
Name = Name,
- 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 7b3857760..c89846dc4 100644
--- a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs
@@ -714,7 +714,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
config = new StandardControllerInputConfig
{
Version = InputConfig.CurrentVersion,
- Backend = InputBackendType.GamepadSDL2,
+ Backend = InputBackendType.GamepadSDL3,
Id = id,
Name = name,
ControllerType = ControllerType.ProController,
diff --git a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs
index acf7517d8..6757abfb2 100644
--- a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs
@@ -6,7 +6,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
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.Systems.Configuration;
@@ -269,7 +269,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;
@@ -512,13 +512,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 b09c6ef6c..22dfc57ac 100644
--- a/src/Ryujinx/UI/Views/Settings/SettingsAudioView.axaml
+++ b/src/Ryujinx/UI/Views/Settings/SettingsAudioView.axaml
@@ -44,8 +44,8 @@
IsEnabled="{Binding IsSoundIoEnabled}"
Content="{ext:Locale SettingsTabSystemAudioBackendSoundIO}" />
+ IsEnabled="{Binding IsSDL3Enabled}"
+ Content="{ext:Locale SettingsTabSystemAudioBackendSDL3}" />
diff --git a/src/Ryujinx/UI/Windows/MainWindow.axaml.cs b/src/Ryujinx/UI/Windows/MainWindow.axaml.cs
index e363ee2cd..ea4e2978f 100644
--- a/src/Ryujinx/UI/Windows/MainWindow.axaml.cs
+++ b/src/Ryujinx/UI/Windows/MainWindow.axaml.cs
@@ -29,7 +29,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 System;
using System.Collections.Generic;
using System.Linq;
@@ -105,7 +105,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(it => ViewModel.IsActive = it);
this.ScalingChanged += OnScalingChanged;