Profiler config broken in thes commit. Next will fix
Merge branch 'original_master' into profiling # Conflicts: # Ryujinx.Common/Ryujinx.Common.csproj # Ryujinx.sln # Ryujinx/Config.cs # Ryujinx/Ryujinx.conf # Ryujinx/Ui/GLScreen.cs
This commit is contained in:
commit
7c011cfca7
64 changed files with 2904 additions and 980 deletions
210
CONFIG.md
210
CONFIG.md
|
@ -1,123 +1,124 @@
|
|||
## Config File
|
||||
|
||||
`Ryujinx.conf` should be present in executable folder (It's an *.ini file) following this format:
|
||||
`Config.jsonc` should be present in executable folder. The available settings follow:
|
||||
|
||||
- `Logging_Enable_Info` *(bool)*
|
||||
- `graphics_shaders_dump_path` *(string)*
|
||||
|
||||
Dump shaders in local directory (e.g. `C:\ShaderDumps`)
|
||||
|
||||
- `logging_enable_debug` *(bool)*
|
||||
|
||||
Enable the Debug Logging.
|
||||
|
||||
- `logging_enable_stub` *(bool)*
|
||||
|
||||
Enable the Trace Logging.
|
||||
|
||||
- `logging_enable_info` *(bool)*
|
||||
|
||||
Enable the Informations Logging.
|
||||
|
||||
- `Logging_Enable_Trace` *(bool)*
|
||||
- `logging_enable_warn` *(bool)*
|
||||
|
||||
Enable the Trace Logging (Enabled in Debug recommended).
|
||||
|
||||
- `Logging_Enable_Debug` *(bool)*
|
||||
Enable the Warning Logging.
|
||||
|
||||
Enable the Debug Logging (Enabled in Debug recommended).
|
||||
- `logging_enable_error` *(bool)*
|
||||
|
||||
- `Logging_Enable_Warn` *(bool)*
|
||||
Enable the Error Logging.
|
||||
|
||||
Enable the Warning Logging (Enabled in Debug recommended).
|
||||
|
||||
- `Logging_Enable_Error` *(bool)*
|
||||
|
||||
Enable the Error Logging (Enabled in Debug recommended).
|
||||
|
||||
- `Logging_Enable_Fatal` *(bool)*
|
||||
|
||||
Enable the Fatal Logging (Enabled in Debug recommended).
|
||||
|
||||
- `Logging_Enable_Ipc` *(bool)*
|
||||
|
||||
Enable the Ipc Message Logging.
|
||||
|
||||
- `Logging_Enable_LogFile` *(bool)*
|
||||
- `enable_file_log` *(bool)*
|
||||
|
||||
Enable writing the logging inside a Ryujinx.log file.
|
||||
|
||||
- `GamePad_Index` *(int)*
|
||||
|
||||
The index of the Controller Device.
|
||||
|
||||
- `GamePad_Deadzone` *(float)*
|
||||
- `system_language` *(string)*
|
||||
|
||||
The deadzone of both analog sticks on the Controller.
|
||||
Change System Language, [System Language list](https://gist.github.com/HorrorTroll/b6e4a88d774c3c9b3bdf54d79a7ca43b)
|
||||
|
||||
- `GamePad_Enable` *(bool)*
|
||||
|
||||
Whether or not to enable Controller Support.
|
||||
|
||||
- `Controls_Left_JoyConKeyboard_XX` *(int)*
|
||||
```
|
||||
Controls_Left_JoyConKeyboard_Stick_Up (int)
|
||||
Controls_Left_JoyConKeyboard_Stick_Down (int)
|
||||
Controls_Left_JoyConKeyboard_Stick_Left (int)
|
||||
Controls_Left_JoyConKeyboard_Stick_Right (int)
|
||||
Controls_Left_JoyConKeyboard_Stick_Button (int)
|
||||
Controls_Left_JoyConKeyboard_DPad_Up (int)
|
||||
Controls_Left_JoyConKeyboard_DPad_Down (int)
|
||||
Controls_Left_JoyConKeyboard_DPad_Left (int)
|
||||
Controls_Left_JoyConKeyboard_DPad_Right (int)
|
||||
Controls_Left_JoyConKeyboard_Button_Minus (int)
|
||||
Controls_Left_JoyConKeyboard_Button_L (int)
|
||||
Controls_Left_JoyConKeyboard_Button_ZL (int)
|
||||
```
|
||||
|
||||
Keys of the Left Emulated Joycon, the values depend of the [OpenTK Enum Keys](https://github.com/opentk/opentk/blob/develop/src/OpenTK/Input/Key.cs).
|
||||
|
||||
OpenTK use a QWERTY layout, so pay attention if you use another Keyboard Layout.
|
||||
|
||||
Ex: `Controls_Left_JoyConKeyboard_Button_Minus = 52` > Tab key (All Layout).
|
||||
- `docked_mode` *(bool)*
|
||||
|
||||
- `Controls_Right_JoyConKeyboard_XX` *(int)*
|
||||
```
|
||||
Controls_Right_JoyConKeyboard_Stick_Up (int)
|
||||
Controls_Right_JoyConKeyboard_Stick_Down (int)
|
||||
Controls_Right_JoyConKeyboard_Stick_Left (int)
|
||||
Controls_Right_JoyConKeyboard_Stick_Right (int)
|
||||
Controls_Right_JoyConKeyboard_Stick_Button (int)
|
||||
Controls_Right_JoyConKeyboard_Button_A (int)
|
||||
Controls_Right_JoyConKeyboard_Button_B (int)
|
||||
Controls_Right_JoyConKeyboard_Button_X (int)
|
||||
Controls_Right_JoyConKeyboard_Button_Y (int)
|
||||
Controls_Right_JoyConKeyboard_Button_Plus (int)
|
||||
Controls_Right_JoyConKeyboard_Button_R (int)
|
||||
Controls_Right_JoyConKeyboard_Button_ZR (int)
|
||||
```
|
||||
Enable or Disable Docked Mode
|
||||
|
||||
Keys of the right Emulated Joycon, the values depend of the [OpenTK Enum Keys](https://github.com/opentk/opentk/blob/develop/src/OpenTK/Input/Key.cs).
|
||||
|
||||
OpenTK use a QWERTY layout, so pay attention if you use another Keyboard Layout.
|
||||
|
||||
Ex: `Controls_Right_JoyConKeyboard_Button_A = 83` > A key (QWERTY Layout) / Q key (AZERTY Layout).
|
||||
|
||||
- `Controls_Left_JoyConController_XX` *(String)*
|
||||
```
|
||||
Controls_Left_JoyConController_Stick (String)
|
||||
Controls_Left_JoyConController_Stick_Button (String)
|
||||
Controls_Left_JoyConController_DPad_Up (String)
|
||||
Controls_Left_JoyConController_DPad_Down (String)
|
||||
Controls_Left_JoyConController_DPad_Left (String)
|
||||
Controls_Left_JoyConController_DPad_Right (String)
|
||||
Controls_Left_JoyConController_Button_Minus (String)
|
||||
Controls_Left_JoyConController_Button_L (String)
|
||||
Controls_Left_JoyConController_Button_ZL (String)
|
||||
```
|
||||
|
||||
- `Controls_Right_JoyConController_XX` *(String)*
|
||||
```
|
||||
Controls_Right_JoyConController_Stick (String)
|
||||
Controls_Right_JoyConController_Stick_Button (String)
|
||||
Controls_Right_JoyConController_Button_A (String)
|
||||
Controls_Right_JoyConController_Button_B (String)
|
||||
Controls_Right_JoyConController_Button_X (String)
|
||||
Controls_Right_JoyConController_Button_Y (String)
|
||||
Controls_Right_JoyConController_Button_Plus (String)
|
||||
Controls_Right_JoyConController_Button_R (String)
|
||||
Controls_Right_JoyConController_Button_ZR (String)
|
||||
```
|
||||
- `enable_vsync` *(bool)*
|
||||
|
||||
- Default Mapping
|
||||
- Controller
|
||||
Enable or Disable Game Vsync
|
||||
|
||||
- `enable_multicore_scheduling` *(bool)*
|
||||
|
||||
Enable or Disable Multi-core scheduling of threads
|
||||
|
||||
- `enable_fs_integrity_checks` *(bool)*
|
||||
|
||||
Enable integrity checks on Switch content files
|
||||
|
||||
- `controller_type` *(string)*
|
||||
|
||||
The primary controller's type.
|
||||
Supported Values: `Handheld`, `ProController`, `NpadPair`, `NpadLeft`, `NpadRight`
|
||||
|
||||
- `keyboard_controls` *(object)* :
|
||||
- `left_joycon` *(object)* :
|
||||
Left JoyCon Keyboard Bindings
|
||||
- `stick_up` *(string)*
|
||||
- `stick_down` *(string)*
|
||||
- `stick_left` *(string)*
|
||||
- `stick_right` *(string)*
|
||||
- `stick_button` *(string)*
|
||||
- `dpad_up` *(string)*
|
||||
- `dpad_down` *(string)*
|
||||
- `dpad_left` *(string)*
|
||||
- `dpad_right` *(string)*
|
||||
- `button_minus` *(string)*
|
||||
- `button_l` *(string)*
|
||||
- `button_zl` *(string)*
|
||||
- `right_joycon` *(object)* :
|
||||
Right JoyCon Keyboard Bindings
|
||||
- `stick_up` *(string)*
|
||||
- `stick_down` *(string)*
|
||||
- `stick_left` *(string)*
|
||||
- `stick_right` *(string)*
|
||||
- `stick_button` *(string)*
|
||||
- `button_a` *(string)*
|
||||
- `button_b` *(string)*
|
||||
- `button_x` *(string)*
|
||||
- `button_y` *(string)*
|
||||
- `button_plus` *(string)*
|
||||
- `button_r` *(string)*
|
||||
- `button_zr` *(string)*
|
||||
|
||||
- `gamepad_controls` *(object)* :
|
||||
- `enabled` *(bool)*
|
||||
Whether or not to enable Controller Support.
|
||||
- `index` *(int)*
|
||||
The index of the Controller Device.
|
||||
- `deadzone` *(number)*
|
||||
The deadzone of both analog sticks on the Controller.
|
||||
- `trigger_threshold` *(number)*
|
||||
The value of how pressed down each trigger has to be in order to register a button press
|
||||
- `left_joycon` *(object)* :
|
||||
Left JoyCon Controller Bindings
|
||||
- `stick` *(string)*
|
||||
- `stick_button` *(string)*
|
||||
- `dpad_up` *(string)*
|
||||
- `dpad_down` *(string)*
|
||||
- `dpad_left` *(string)*
|
||||
- `dpad_right` *(string)*
|
||||
- `button_minus` *(string)*
|
||||
- `button_l` *(string)*
|
||||
- `button_zl` *(string)*
|
||||
- `right_joycon` *(object)* :
|
||||
Right JoyCon Controller Bindings
|
||||
- `stick` *(string)*
|
||||
- `stick_button` *(string)*
|
||||
- `button_a` *(string)*
|
||||
- `button_b` *(string)*
|
||||
- `button_x` *(string)*
|
||||
- `button_y` *(string)*
|
||||
- `button_plus` *(string)*
|
||||
- `button_r` *(string)*
|
||||
- `button_zr` *(string)*
|
||||
|
||||
### Default Mapping
|
||||
#### Controller
|
||||
- Left Joycon:
|
||||
- Analog Stick = Left Analog Stick
|
||||
- DPad Up = DPad Up
|
||||
|
@ -137,7 +138,8 @@
|
|||
- Plus = Start / Options
|
||||
- R = Right Shoulder Button
|
||||
- ZR = Right Trigger
|
||||
- Keyboard
|
||||
|
||||
#### Keyboard
|
||||
- Left Joycon:
|
||||
- Stick Up = W
|
||||
- Stick Down = S
|
||||
|
@ -166,7 +168,7 @@
|
|||
- R = U
|
||||
- ZR = O
|
||||
|
||||
- Valid Button Mappings
|
||||
### Valid Button Mappings
|
||||
- A = The A / Cross Button
|
||||
- B = The B / Circle Button
|
||||
- X = The X / Square Button
|
||||
|
|
|
@ -18,7 +18,7 @@ or just drag'n'drop the homebrew *.NRO / *.NSO or the game *.NSP / *.XCI on the
|
|||
|
||||
- Controller Input is supported, see [CONFIG.md](CONFIG.md)
|
||||
|
||||
- Config File: `Ryujinx.conf` should be present in executable folder.
|
||||
- Config File: `Config.jsonc` should be present in executable folder.
|
||||
For more information [you can go here](CONFIG.md).
|
||||
|
||||
**Help**
|
||||
|
|
|
@ -3,21 +3,36 @@ using System.Runtime.InteropServices;
|
|||
|
||||
namespace SoundIOSharp
|
||||
{
|
||||
public static class MarshalEx
|
||||
{
|
||||
public static double ReadDouble (IntPtr handle, int offset = 0)
|
||||
{
|
||||
return BitConverter.Int64BitsToDouble (Marshal.ReadInt64 (handle, offset));
|
||||
}
|
||||
public static class MarshalEx
|
||||
{
|
||||
public static double ReadDouble(IntPtr handle, int offset = 0)
|
||||
{
|
||||
return BitConverter.Int64BitsToDouble(Marshal.ReadInt64(handle, offset));
|
||||
}
|
||||
|
||||
public static void WriteDouble (IntPtr handle, double value)
|
||||
{
|
||||
WriteDouble (handle, 0, value);
|
||||
}
|
||||
public static void WriteDouble(IntPtr handle, double value)
|
||||
{
|
||||
WriteDouble(handle, 0, value);
|
||||
}
|
||||
|
||||
public static void WriteDouble (IntPtr handle, int offset, double value)
|
||||
{
|
||||
Marshal.WriteInt64 (handle, offset, BitConverter.DoubleToInt64Bits (value));
|
||||
}
|
||||
}
|
||||
public static void WriteDouble(IntPtr handle, int offset, double value)
|
||||
{
|
||||
Marshal.WriteInt64(handle, offset, BitConverter.DoubleToInt64Bits(value));
|
||||
}
|
||||
|
||||
public static float ReadFloat(IntPtr handle, int offset = 0)
|
||||
{
|
||||
return BitConverter.Int32BitsToSingle(Marshal.ReadInt32(handle, offset));
|
||||
}
|
||||
|
||||
public static void WriteFloat(IntPtr handle, float value)
|
||||
{
|
||||
WriteFloat(handle, 0, value);
|
||||
}
|
||||
|
||||
public static void WriteFloat(IntPtr handle, int offset, float value)
|
||||
{
|
||||
Marshal.WriteInt32(handle, offset, BitConverter.SingleToInt32Bits(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,6 +77,12 @@ namespace SoundIOSharp
|
|||
}
|
||||
static readonly int software_latency_offset = (int)Marshal.OffsetOf<SoundIoOutStream> ("software_latency");
|
||||
|
||||
public float Volume {
|
||||
get { return MarshalEx.ReadFloat (handle, volume_offset); }
|
||||
set { MarshalEx.WriteFloat (handle, volume_offset, value); }
|
||||
}
|
||||
static readonly int volume_offset = (int)Marshal.OffsetOf<SoundIoOutStream> ("volume");
|
||||
|
||||
// error_callback
|
||||
public Action ErrorCallback {
|
||||
get { return error_callback; }
|
||||
|
@ -237,5 +243,12 @@ namespace SoundIOSharp
|
|||
return *dptr;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetVolume (double volume)
|
||||
{
|
||||
var ret = (SoundIoError) Natives.soundio_outstream_set_volume (handle, volume);
|
||||
if (ret != SoundIoError.SoundIoErrorNone)
|
||||
throw new SoundIOException (ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -178,7 +178,7 @@ namespace SoundIOSharp
|
|||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct SoundIoChannelLayout // soundio.h (302, 8)
|
||||
struct SoundIoChannelLayout // soundio.h (306, 8)
|
||||
{
|
||||
[CTypeDetails("Pointer<byte>")] public System.IntPtr @name;
|
||||
public int @channel_count;
|
||||
|
@ -187,21 +187,21 @@ namespace SoundIOSharp
|
|||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct SoundIoSampleRateRange // soundio.h (309, 8)
|
||||
struct SoundIoSampleRateRange // soundio.h (313, 8)
|
||||
{
|
||||
public int @min;
|
||||
public int @max;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct SoundIoChannelArea // soundio.h (315, 8)
|
||||
struct SoundIoChannelArea // soundio.h (319, 8)
|
||||
{
|
||||
[CTypeDetails("Pointer<byte>")] public System.IntPtr @ptr;
|
||||
public int @step;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct SoundIo // soundio.h (324, 8)
|
||||
struct SoundIo // soundio.h (328, 8)
|
||||
{
|
||||
[CTypeDetails("Pointer<void>")] public System.IntPtr @userdata;
|
||||
[CTypeDetails("Pointer<void (SoundIo *)>")] public delegate0 @on_devices_change;
|
||||
|
@ -215,7 +215,7 @@ namespace SoundIOSharp
|
|||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct SoundIoDevice // soundio.h (383, 8)
|
||||
struct SoundIoDevice // soundio.h (387, 8)
|
||||
{
|
||||
[CTypeDetails("Pointer<SoundIo>")] public System.IntPtr @soundio;
|
||||
[CTypeDetails("Pointer<byte>")] public System.IntPtr @id;
|
||||
|
@ -239,13 +239,14 @@ namespace SoundIOSharp
|
|||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct SoundIoOutStream // soundio.h (493, 8)
|
||||
struct SoundIoOutStream // soundio.h (497, 8)
|
||||
{
|
||||
[CTypeDetails("Pointer<SoundIoDevice>")] public System.IntPtr @device;
|
||||
public SoundIoFormat @format;
|
||||
public int @sample_rate;
|
||||
public SoundIoChannelLayout @layout;
|
||||
public double @software_latency;
|
||||
public float @volume;
|
||||
[CTypeDetails("Pointer<void>")] public System.IntPtr @userdata;
|
||||
[CTypeDetails("Pointer<void (SoundIoOutStream *, int, int)>")] public delegate4 @write_callback;
|
||||
[CTypeDetails("Pointer<void (SoundIoOutStream *)>")] public delegate5 @underflow_callback;
|
||||
|
@ -258,7 +259,7 @@ namespace SoundIOSharp
|
|||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct SoundIoInStream // soundio.h (595, 8)
|
||||
struct SoundIoInStream // soundio.h (600, 8)
|
||||
{
|
||||
[CTypeDetails("Pointer<SoundIoDevice>")] public System.IntPtr @device;
|
||||
public SoundIoFormat @format;
|
||||
|
@ -277,302 +278,306 @@ namespace SoundIOSharp
|
|||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct SoundIoRingBuffer // soundio.h (1167, 8)
|
||||
struct SoundIoRingBuffer // soundio.h (1170, 8)
|
||||
{
|
||||
}
|
||||
|
||||
partial class Natives
|
||||
{
|
||||
const string LibraryName = "libsoundio";
|
||||
// function soundio_version_string - soundio.h (677, 28)
|
||||
// function soundio_version_string - soundio.h (682, 28)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_version_string();
|
||||
|
||||
// function soundio_version_major - soundio.h (679, 20)
|
||||
// function soundio_version_major - soundio.h (684, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_version_major();
|
||||
|
||||
// function soundio_version_minor - soundio.h (681, 20)
|
||||
// function soundio_version_minor - soundio.h (686, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_version_minor();
|
||||
|
||||
// function soundio_version_patch - soundio.h (683, 20)
|
||||
// function soundio_version_patch - soundio.h (688, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_version_patch();
|
||||
|
||||
// function soundio_create - soundio.h (689, 32)
|
||||
// function soundio_create - soundio.h (694, 32)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_create();
|
||||
|
||||
// function soundio_destroy - soundio.h (690, 21)
|
||||
// function soundio_destroy - soundio.h (695, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_destroy([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
||||
|
||||
// function soundio_connect - soundio.h (700, 20)
|
||||
// function soundio_connect - soundio.h (705, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_connect([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
||||
|
||||
// function soundio_connect_backend - soundio.h (712, 20)
|
||||
// function soundio_connect_backend - soundio.h (717, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_connect_backend([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio, SoundIoBackend @backend);
|
||||
|
||||
// function soundio_disconnect - soundio.h (713, 21)
|
||||
// function soundio_disconnect - soundio.h (718, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_disconnect([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
||||
|
||||
// function soundio_strerror - soundio.h (716, 28)
|
||||
// function soundio_strerror - soundio.h (721, 28)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_strerror(int @error);
|
||||
|
||||
// function soundio_backend_name - soundio.h (718, 28)
|
||||
// function soundio_backend_name - soundio.h (723, 28)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_backend_name(SoundIoBackend @backend);
|
||||
|
||||
// function soundio_backend_count - soundio.h (721, 20)
|
||||
// function soundio_backend_count - soundio.h (726, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_backend_count([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
||||
|
||||
// function soundio_get_backend - soundio.h (724, 36)
|
||||
// function soundio_get_backend - soundio.h (729, 36)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern SoundIoBackend soundio_get_backend([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio, int @index);
|
||||
|
||||
// function soundio_have_backend - soundio.h (727, 21)
|
||||
// function soundio_have_backend - soundio.h (732, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern bool soundio_have_backend(SoundIoBackend @backend);
|
||||
|
||||
// function soundio_flush_events - soundio.h (751, 21)
|
||||
// function soundio_flush_events - soundio.h (756, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_flush_events([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
||||
|
||||
// function soundio_wait_events - soundio.h (755, 21)
|
||||
// function soundio_wait_events - soundio.h (760, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_wait_events([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
||||
|
||||
// function soundio_wakeup - soundio.h (758, 21)
|
||||
// function soundio_wakeup - soundio.h (763, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_wakeup([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
||||
|
||||
// function soundio_force_device_scan - soundio.h (775, 21)
|
||||
// function soundio_force_device_scan - soundio.h (780, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_force_device_scan([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
||||
|
||||
// function soundio_channel_layout_equal - soundio.h (782, 21)
|
||||
// function soundio_channel_layout_equal - soundio.h (787, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern bool soundio_channel_layout_equal([CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @a, [CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @b);
|
||||
|
||||
// function soundio_get_channel_name - soundio.h (786, 28)
|
||||
// function soundio_get_channel_name - soundio.h (791, 28)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_get_channel_name(SoundIoChannelId @id);
|
||||
|
||||
// function soundio_parse_channel_id - soundio.h (790, 38)
|
||||
// function soundio_parse_channel_id - soundio.h (795, 38)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern SoundIoChannelId soundio_parse_channel_id([CTypeDetails("Pointer<byte>")]System.IntPtr @str, int @str_len);
|
||||
|
||||
// function soundio_channel_layout_builtin_count - soundio.h (793, 20)
|
||||
// function soundio_channel_layout_builtin_count - soundio.h (798, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_channel_layout_builtin_count();
|
||||
|
||||
// function soundio_channel_layout_get_builtin - soundio.h (798, 51)
|
||||
// function soundio_channel_layout_get_builtin - soundio.h (803, 51)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_channel_layout_get_builtin(int @index);
|
||||
|
||||
// function soundio_channel_layout_get_default - soundio.h (801, 51)
|
||||
// function soundio_channel_layout_get_default - soundio.h (806, 51)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_channel_layout_get_default(int @channel_count);
|
||||
|
||||
// function soundio_channel_layout_find_channel - soundio.h (804, 20)
|
||||
// function soundio_channel_layout_find_channel - soundio.h (809, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_channel_layout_find_channel([CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @layout, SoundIoChannelId @channel);
|
||||
|
||||
// function soundio_channel_layout_detect_builtin - soundio.h (809, 21)
|
||||
// function soundio_channel_layout_detect_builtin - soundio.h (814, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern bool soundio_channel_layout_detect_builtin([CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @layout);
|
||||
|
||||
// function soundio_best_matching_channel_layout - soundio.h (814, 51)
|
||||
// function soundio_best_matching_channel_layout - soundio.h (819, 51)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_best_matching_channel_layout([CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @preferred_layouts, int @preferred_layout_count, [CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @available_layouts, int @available_layout_count);
|
||||
|
||||
// function soundio_sort_channel_layouts - soundio.h (819, 21)
|
||||
// function soundio_sort_channel_layouts - soundio.h (824, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_sort_channel_layouts([CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @layouts, int @layout_count);
|
||||
|
||||
// function soundio_get_bytes_per_sample - soundio.h (825, 20)
|
||||
// function soundio_get_bytes_per_sample - soundio.h (830, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_get_bytes_per_sample(SoundIoFormat @format);
|
||||
|
||||
// function soundio_get_bytes_per_frame - soundio.h (828, 19)
|
||||
// function soundio_get_bytes_per_frame - soundio.h (833, 19)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_get_bytes_per_frame(SoundIoFormat @format, int @channel_count);
|
||||
|
||||
// function soundio_get_bytes_per_second - soundio.h (833, 19)
|
||||
// function soundio_get_bytes_per_second - soundio.h (838, 19)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_get_bytes_per_second(SoundIoFormat @format, int @channel_count, int @sample_rate);
|
||||
|
||||
// function soundio_format_string - soundio.h (840, 29)
|
||||
// function soundio_format_string - soundio.h (845, 29)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_format_string(SoundIoFormat @format);
|
||||
|
||||
// function soundio_input_device_count - soundio.h (856, 20)
|
||||
// function soundio_input_device_count - soundio.h (861, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_input_device_count([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
||||
|
||||
// function soundio_output_device_count - soundio.h (859, 20)
|
||||
// function soundio_output_device_count - soundio.h (864, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_output_device_count([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
||||
|
||||
// function soundio_get_input_device - soundio.h (865, 38)
|
||||
// function soundio_get_input_device - soundio.h (870, 38)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_get_input_device([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio, int @index);
|
||||
|
||||
// function soundio_get_output_device - soundio.h (870, 38)
|
||||
// function soundio_get_output_device - soundio.h (875, 38)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_get_output_device([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio, int @index);
|
||||
|
||||
// function soundio_default_input_device_index - soundio.h (875, 20)
|
||||
// function soundio_default_input_device_index - soundio.h (880, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_default_input_device_index([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
||||
|
||||
// function soundio_default_output_device_index - soundio.h (880, 20)
|
||||
// function soundio_default_output_device_index - soundio.h (885, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_default_output_device_index([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
||||
|
||||
// function soundio_device_ref - soundio.h (883, 21)
|
||||
// function soundio_device_ref - soundio.h (888, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_device_ref([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device);
|
||||
|
||||
// function soundio_device_unref - soundio.h (886, 21)
|
||||
// function soundio_device_unref - soundio.h (891, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_device_unref([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device);
|
||||
|
||||
// function soundio_device_equal - soundio.h (890, 21)
|
||||
// function soundio_device_equal - soundio.h (895, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern bool soundio_device_equal([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @a, [CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @b);
|
||||
|
||||
// function soundio_device_sort_channel_layouts - soundio.h (895, 21)
|
||||
// function soundio_device_sort_channel_layouts - soundio.h (900, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_device_sort_channel_layouts([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device);
|
||||
|
||||
// function soundio_device_supports_format - soundio.h (899, 21)
|
||||
// function soundio_device_supports_format - soundio.h (904, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern bool soundio_device_supports_format([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device, SoundIoFormat @format);
|
||||
|
||||
// function soundio_device_supports_layout - soundio.h (904, 21)
|
||||
// function soundio_device_supports_layout - soundio.h (909, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern bool soundio_device_supports_layout([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device, [CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @layout);
|
||||
|
||||
// function soundio_device_supports_sample_rate - soundio.h (909, 21)
|
||||
// function soundio_device_supports_sample_rate - soundio.h (914, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern bool soundio_device_supports_sample_rate([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device, int @sample_rate);
|
||||
|
||||
// function soundio_device_nearest_sample_rate - soundio.h (914, 20)
|
||||
// function soundio_device_nearest_sample_rate - soundio.h (919, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_device_nearest_sample_rate([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device, int @sample_rate);
|
||||
|
||||
// function soundio_outstream_create - soundio.h (924, 41)
|
||||
// function soundio_outstream_create - soundio.h (929, 41)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_outstream_create([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device);
|
||||
|
||||
// function soundio_outstream_destroy - soundio.h (926, 21)
|
||||
// function soundio_outstream_destroy - soundio.h (931, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_outstream_destroy([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream);
|
||||
|
||||
// function soundio_outstream_open - soundio.h (950, 20)
|
||||
// function soundio_outstream_open - soundio.h (954, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_outstream_open([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream);
|
||||
|
||||
// function soundio_outstream_start - soundio.h (961, 20)
|
||||
// function soundio_outstream_start - soundio.h (965, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_outstream_start([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream);
|
||||
|
||||
// function soundio_outstream_begin_write - soundio.h (993, 20)
|
||||
// function soundio_outstream_begin_write - soundio.h (997, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_outstream_begin_write([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream, [CTypeDetails("Pointer<System.IntPtr>")]System.IntPtr @areas, [CTypeDetails("Pointer<int>")]System.IntPtr @frame_count);
|
||||
|
||||
// function soundio_outstream_end_write - soundio.h (1005, 20)
|
||||
// function soundio_outstream_end_write - soundio.h (1009, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_outstream_end_write([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream);
|
||||
|
||||
// function soundio_outstream_clear_buffer - soundio.h (1020, 20)
|
||||
// function soundio_outstream_clear_buffer - soundio.h (1024, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_outstream_clear_buffer([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream);
|
||||
|
||||
// function soundio_outstream_pause - soundio.h (1041, 20)
|
||||
// function soundio_outstream_pause - soundio.h (1045, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_outstream_pause([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream, bool @pause);
|
||||
|
||||
// function soundio_outstream_get_latency - soundio.h (1054, 20)
|
||||
// function soundio_outstream_get_latency - soundio.h (1058, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_outstream_get_latency([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream, [CTypeDetails("Pointer<double>")]System.IntPtr @out_latency);
|
||||
|
||||
// function soundio_instream_create - soundio.h (1064, 40)
|
||||
// function soundio_outstream_set_volume - soundio.h (1061, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_outstream_set_volume([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream, double @volume);
|
||||
|
||||
// function soundio_instream_create - soundio.h (1071, 40)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_instream_create([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device);
|
||||
|
||||
// function soundio_instream_destroy - soundio.h (1066, 21)
|
||||
// function soundio_instream_destroy - soundio.h (1073, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_instream_destroy([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream);
|
||||
|
||||
// function soundio_instream_open - soundio.h (1086, 20)
|
||||
// function soundio_instream_open - soundio.h (1093, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_instream_open([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream);
|
||||
|
||||
// function soundio_instream_start - soundio.h (1095, 20)
|
||||
// function soundio_instream_start - soundio.h (1102, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_instream_start([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream);
|
||||
|
||||
// function soundio_instream_begin_read - soundio.h (1126, 20)
|
||||
// function soundio_instream_begin_read - soundio.h (1133, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_instream_begin_read([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream, [CTypeDetails("Pointer<System.IntPtr>")]System.IntPtr @areas, [CTypeDetails("Pointer<int>")]System.IntPtr @frame_count);
|
||||
|
||||
// function soundio_instream_end_read - soundio.h (1136, 20)
|
||||
// function soundio_instream_end_read - soundio.h (1143, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_instream_end_read([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream);
|
||||
|
||||
// function soundio_instream_pause - soundio.h (1149, 20)
|
||||
// function soundio_instream_pause - soundio.h (1156, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_instream_pause([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream, bool @pause);
|
||||
|
||||
// function soundio_instream_get_latency - soundio.h (1159, 20)
|
||||
// function soundio_instream_get_latency - soundio.h (1166, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_instream_get_latency([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream, [CTypeDetails("Pointer<double>")]System.IntPtr @out_latency);
|
||||
|
||||
// function soundio_ring_buffer_create - soundio.h (1173, 42)
|
||||
// function soundio_ring_buffer_create - soundio.h (1181, 42)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_ring_buffer_create([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio, int @requested_capacity);
|
||||
|
||||
// function soundio_ring_buffer_destroy - soundio.h (1174, 21)
|
||||
// function soundio_ring_buffer_destroy - soundio.h (1182, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_ring_buffer_destroy([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
|
||||
|
||||
// function soundio_ring_buffer_capacity - soundio.h (1178, 20)
|
||||
// function soundio_ring_buffer_capacity - soundio.h (1186, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_ring_buffer_capacity([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
|
||||
|
||||
// function soundio_ring_buffer_write_ptr - soundio.h (1181, 22)
|
||||
// function soundio_ring_buffer_write_ptr - soundio.h (1189, 22)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_ring_buffer_write_ptr([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
|
||||
|
||||
// function soundio_ring_buffer_advance_write_ptr - soundio.h (1183, 21)
|
||||
// function soundio_ring_buffer_advance_write_ptr - soundio.h (1191, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_ring_buffer_advance_write_ptr([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer, int @count);
|
||||
|
||||
// function soundio_ring_buffer_read_ptr - soundio.h (1186, 22)
|
||||
// function soundio_ring_buffer_read_ptr - soundio.h (1194, 22)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_ring_buffer_read_ptr([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
|
||||
|
||||
// function soundio_ring_buffer_advance_read_ptr - soundio.h (1188, 21)
|
||||
// function soundio_ring_buffer_advance_read_ptr - soundio.h (1196, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_ring_buffer_advance_read_ptr([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer, int @count);
|
||||
|
||||
// function soundio_ring_buffer_fill_count - soundio.h (1191, 20)
|
||||
// function soundio_ring_buffer_fill_count - soundio.h (1199, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_ring_buffer_fill_count([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
|
||||
|
||||
// function soundio_ring_buffer_free_count - soundio.h (1194, 20)
|
||||
// function soundio_ring_buffer_free_count - soundio.h (1202, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_ring_buffer_free_count([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
|
||||
|
||||
// function soundio_ring_buffer_clear - soundio.h (1197, 21)
|
||||
// function soundio_ring_buffer_clear - soundio.h (1205, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_ring_buffer_clear([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
|
||||
|
||||
|
|
|
@ -36,60 +36,7 @@ namespace Ryujinx.Audio
|
|||
{
|
||||
get
|
||||
{
|
||||
SoundIO context = null;
|
||||
SoundIODevice device = null;
|
||||
SoundIOOutStream stream = null;
|
||||
|
||||
bool backendDisconnected = false;
|
||||
|
||||
try
|
||||
{
|
||||
context = new SoundIO();
|
||||
|
||||
context.OnBackendDisconnect = (i) => {
|
||||
backendDisconnected = true;
|
||||
};
|
||||
|
||||
context.Connect();
|
||||
context.FlushEvents();
|
||||
|
||||
if(backendDisconnected)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
device = context.GetOutputDevice(context.DefaultOutputDeviceIndex);
|
||||
|
||||
if(device == null || backendDisconnected)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
stream = device.CreateOutStream();
|
||||
|
||||
if(stream == null || backendDisconnected)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(stream != null)
|
||||
{
|
||||
stream.Dispose();
|
||||
}
|
||||
|
||||
if(context != null)
|
||||
{
|
||||
context.Dispose();
|
||||
}
|
||||
}
|
||||
return IsSupportedInternal();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,7 +50,7 @@ namespace Ryujinx.Audio
|
|||
m_AudioContext.Connect();
|
||||
m_AudioContext.FlushEvents();
|
||||
|
||||
m_AudioDevice = m_AudioContext.GetOutputDevice(m_AudioContext.DefaultOutputDeviceIndex);
|
||||
m_AudioDevice = FindNonRawDefaultAudioDevice(m_AudioContext, true);
|
||||
m_TrackPool = new SoundIoAudioTrackPool(m_AudioContext, m_AudioDevice, MaximumTracks);
|
||||
}
|
||||
|
||||
|
@ -244,5 +191,99 @@ namespace Ryujinx.Audio
|
|||
m_AudioContext.Disconnect();
|
||||
m_AudioContext.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches for a shared version of the default audio device
|
||||
/// </summary>
|
||||
/// <param name="audioContext">The <see cref="SoundIO"/> audio context</param>
|
||||
/// <param name="fallback">Whether to fallback to the raw default audio device if a non-raw device cannot be found</param>
|
||||
private static SoundIODevice FindNonRawDefaultAudioDevice(SoundIO audioContext, bool fallback = false)
|
||||
{
|
||||
SoundIODevice defaultAudioDevice = audioContext.GetOutputDevice(audioContext.DefaultOutputDeviceIndex);
|
||||
|
||||
if(!defaultAudioDevice.IsRaw)
|
||||
{
|
||||
return defaultAudioDevice;
|
||||
}
|
||||
|
||||
for(var i = 0; i < audioContext.BackendCount; i++)
|
||||
{
|
||||
SoundIODevice audioDevice = audioContext.GetOutputDevice(i);
|
||||
|
||||
if (audioDevice.Id == defaultAudioDevice.Id && !audioDevice.IsRaw)
|
||||
{
|
||||
return audioDevice;
|
||||
}
|
||||
}
|
||||
|
||||
return fallback ? defaultAudioDevice : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if SoundIO can connect to a supported backend
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private static bool IsSupportedInternal()
|
||||
{
|
||||
SoundIO context = null;
|
||||
SoundIODevice device = null;
|
||||
SoundIOOutStream stream = null;
|
||||
|
||||
bool backendDisconnected = false;
|
||||
|
||||
try
|
||||
{
|
||||
context = new SoundIO();
|
||||
|
||||
context.OnBackendDisconnect = (i) => {
|
||||
backendDisconnected = true;
|
||||
};
|
||||
|
||||
context.Connect();
|
||||
context.FlushEvents();
|
||||
|
||||
if(backendDisconnected)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(context.OutputDeviceCount == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
device = FindNonRawDefaultAudioDevice(context);
|
||||
|
||||
if(device == null || backendDisconnected)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
stream = device.CreateOutStream();
|
||||
|
||||
if(stream == null || backendDisconnected)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(stream != null)
|
||||
{
|
||||
stream.Dispose();
|
||||
}
|
||||
|
||||
if(context != null)
|
||||
{
|
||||
context.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.Common
|
||||
{
|
||||
public static class StructIOExtension
|
||||
public static class BinaryReaderExtensions
|
||||
{
|
||||
public unsafe static T ReadStruct<T>(this BinaryReader reader) where T : struct
|
||||
public unsafe static T ReadStruct<T>(this BinaryReader reader)
|
||||
where T : struct
|
||||
{
|
||||
int size = Marshal.SizeOf<T>();
|
||||
|
||||
|
@ -20,7 +19,8 @@ namespace Ryujinx.Common
|
|||
}
|
||||
}
|
||||
|
||||
public unsafe static void WriteStruct<T>(this BinaryWriter writer, T value) where T : struct
|
||||
public unsafe static void WriteStruct<T>(this BinaryWriter writer, T value)
|
||||
where T : struct
|
||||
{
|
||||
long size = Marshal.SizeOf<T>();
|
||||
|
12
Ryujinx.Common/Extensions/EnumExtensions.cs
Normal file
12
Ryujinx.Common/Extensions/EnumExtensions.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.Common
|
||||
{
|
||||
public static class EnumExtensions
|
||||
{
|
||||
public static T[] GetValues<T>()
|
||||
{
|
||||
return (T[])Enum.GetValues(typeof(T));
|
||||
}
|
||||
}
|
||||
}
|
53
Ryujinx.Common/Logging/Formatters/DefaultLogFormatter.cs
Normal file
53
Ryujinx.Common/Logging/Formatters/DefaultLogFormatter.cs
Normal file
|
@ -0,0 +1,53 @@
|
|||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.Common.Logging
|
||||
{
|
||||
internal class DefaultLogFormatter : ILogFormatter
|
||||
{
|
||||
private static readonly ObjectPool<StringBuilder> _stringBuilderPool = SharedPools.Default<StringBuilder>();
|
||||
|
||||
public string Format(LogEventArgs args)
|
||||
{
|
||||
StringBuilder sb = _stringBuilderPool.Allocate();
|
||||
|
||||
try
|
||||
{
|
||||
sb.Clear();
|
||||
|
||||
sb.AppendFormat(@"{0:hh\:mm\:ss\.fff}", args.Time);
|
||||
sb.Append(" | ");
|
||||
sb.AppendFormat("{0:d4}", args.ThreadId);
|
||||
sb.Append(' ');
|
||||
sb.Append(args.Message);
|
||||
|
||||
if (args.Data != null)
|
||||
{
|
||||
PropertyInfo[] props = args.Data.GetType().GetProperties();
|
||||
|
||||
sb.Append(' ');
|
||||
|
||||
foreach (var prop in props)
|
||||
{
|
||||
sb.Append(prop.Name);
|
||||
sb.Append(": ");
|
||||
sb.Append(prop.GetValue(args.Data));
|
||||
sb.Append(" - ");
|
||||
}
|
||||
|
||||
// We remove the final '-' from the string
|
||||
if (props.Length > 0)
|
||||
{
|
||||
sb.Remove(sb.Length - 3, 3);
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_stringBuilderPool.Release(sb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
7
Ryujinx.Common/Logging/Formatters/ILogFormatter.cs
Normal file
7
Ryujinx.Common/Logging/Formatters/ILogFormatter.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace Ryujinx.Common.Logging
|
||||
{
|
||||
interface ILogFormatter
|
||||
{
|
||||
string Format(LogEventArgs args);
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ namespace Ryujinx.Common.Logging
|
|||
{
|
||||
public enum LogClass
|
||||
{
|
||||
Application,
|
||||
Audio,
|
||||
Cpu,
|
||||
Font,
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.Common.Logging
|
||||
|
@ -14,9 +13,9 @@ namespace Ryujinx.Common.Logging
|
|||
private static readonly bool[] m_EnabledLevels;
|
||||
private static readonly bool[] m_EnabledClasses;
|
||||
|
||||
public static event EventHandler<LogEventArgs> Updated;
|
||||
private static readonly List<ILogTarget> m_LogTargets;
|
||||
|
||||
public static bool EnableFileLog { get; set; }
|
||||
public static event EventHandler<LogEventArgs> Updated;
|
||||
|
||||
static Logger()
|
||||
{
|
||||
|
@ -33,9 +32,30 @@ namespace Ryujinx.Common.Logging
|
|||
m_EnabledClasses[index] = true;
|
||||
}
|
||||
|
||||
m_LogTargets = new List<ILogTarget>();
|
||||
|
||||
m_Time = Stopwatch.StartNew();
|
||||
}
|
||||
|
||||
public static void AddTarget(ILogTarget target)
|
||||
{
|
||||
m_LogTargets.Add(target);
|
||||
|
||||
Updated += target.Log;
|
||||
}
|
||||
|
||||
public static void Shutdown()
|
||||
{
|
||||
Updated = null;
|
||||
|
||||
foreach(var target in m_LogTargets)
|
||||
{
|
||||
target.Dispose();
|
||||
}
|
||||
|
||||
m_LogTargets.Clear();
|
||||
}
|
||||
|
||||
public static void SetEnable(LogLevel logLevel, bool enabled)
|
||||
{
|
||||
m_EnabledLevels[(int)logLevel] = enabled;
|
||||
|
|
76
Ryujinx.Common/Logging/Targets/AsyncLogTargetWrapper.cs
Normal file
76
Ryujinx.Common/Logging/Targets/AsyncLogTargetWrapper.cs
Normal file
|
@ -0,0 +1,76 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.Common.Logging
|
||||
{
|
||||
public enum AsyncLogTargetOverflowAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Block until there's more room in the queue
|
||||
/// </summary>
|
||||
Block = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Discard the overflowing item
|
||||
/// </summary>
|
||||
Discard = 1
|
||||
}
|
||||
|
||||
public class AsyncLogTargetWrapper : ILogTarget
|
||||
{
|
||||
private ILogTarget _target;
|
||||
|
||||
private Thread _messageThread;
|
||||
|
||||
private BlockingCollection<LogEventArgs> _messageQueue;
|
||||
|
||||
private readonly int _overflowTimeout;
|
||||
|
||||
public AsyncLogTargetWrapper(ILogTarget target)
|
||||
: this(target, -1, AsyncLogTargetOverflowAction.Block)
|
||||
{ }
|
||||
|
||||
public AsyncLogTargetWrapper(ILogTarget target, int queueLimit, AsyncLogTargetOverflowAction overflowAction)
|
||||
{
|
||||
_target = target;
|
||||
_messageQueue = new BlockingCollection<LogEventArgs>(queueLimit);
|
||||
_overflowTimeout = overflowAction == AsyncLogTargetOverflowAction.Block ? -1 : 0;
|
||||
|
||||
_messageThread = new Thread(() => {
|
||||
while (!_messageQueue.IsCompleted)
|
||||
{
|
||||
try
|
||||
{
|
||||
_target.Log(this, _messageQueue.Take());
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
// IOE means that Take() was called on a completed collection.
|
||||
// Some other thread can call CompleteAdding after we pass the
|
||||
// IsCompleted check but before we call Take.
|
||||
// We can simply catch the exception since the loop will break
|
||||
// on the next iteration.
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
_messageThread.IsBackground = true;
|
||||
_messageThread.Start();
|
||||
}
|
||||
|
||||
public void Log(object sender, LogEventArgs e)
|
||||
{
|
||||
if (!_messageQueue.IsAddingCompleted)
|
||||
{
|
||||
_messageQueue.TryAdd(e, _overflowTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_messageQueue.CompleteAdding();
|
||||
_messageThread.Join();
|
||||
}
|
||||
}
|
||||
}
|
48
Ryujinx.Common/Logging/Targets/ConsoleLogTarget.cs
Normal file
48
Ryujinx.Common/Logging/Targets/ConsoleLogTarget.cs
Normal file
|
@ -0,0 +1,48 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace Ryujinx.Common.Logging
|
||||
{
|
||||
public class ConsoleLogTarget : ILogTarget
|
||||
{
|
||||
private static readonly ConcurrentDictionary<LogLevel, ConsoleColor> _logColors;
|
||||
|
||||
private readonly ILogFormatter _formatter;
|
||||
|
||||
static ConsoleLogTarget()
|
||||
{
|
||||
_logColors = new ConcurrentDictionary<LogLevel, ConsoleColor> {
|
||||
[ LogLevel.Stub ] = ConsoleColor.DarkGray,
|
||||
[ LogLevel.Info ] = ConsoleColor.White,
|
||||
[ LogLevel.Warning ] = ConsoleColor.Yellow,
|
||||
[ LogLevel.Error ] = ConsoleColor.Red
|
||||
};
|
||||
}
|
||||
|
||||
public ConsoleLogTarget()
|
||||
{
|
||||
_formatter = new DefaultLogFormatter();
|
||||
}
|
||||
|
||||
public void Log(object sender, LogEventArgs args)
|
||||
{
|
||||
if (_logColors.TryGetValue(args.Level, out ConsoleColor color))
|
||||
{
|
||||
Console.ForegroundColor = color;
|
||||
|
||||
Console.WriteLine(_formatter.Format(args));
|
||||
|
||||
Console.ResetColor();
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine(_formatter.Format(args));
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Console.ResetColor();
|
||||
}
|
||||
}
|
||||
}
|
36
Ryujinx.Common/Logging/Targets/FileLogTarget.cs
Normal file
36
Ryujinx.Common/Logging/Targets/FileLogTarget.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.Common.Logging
|
||||
{
|
||||
public class FileLogTarget : ILogTarget
|
||||
{
|
||||
private static readonly ObjectPool<StringBuilder> _stringBuilderPool = SharedPools.Default<StringBuilder>();
|
||||
|
||||
private readonly StreamWriter _logWriter;
|
||||
private readonly ILogFormatter _formatter;
|
||||
|
||||
public FileLogTarget(string path)
|
||||
: this(path, FileShare.Read, FileMode.Append)
|
||||
{ }
|
||||
|
||||
public FileLogTarget(string path, FileShare fileShare, FileMode fileMode)
|
||||
{
|
||||
_logWriter = new StreamWriter(File.Open(path, fileMode, FileAccess.Write, fileShare));
|
||||
_formatter = new DefaultLogFormatter();
|
||||
}
|
||||
|
||||
public void Log(object sender, LogEventArgs args)
|
||||
{
|
||||
_logWriter.WriteLine(_formatter.Format(args));
|
||||
_logWriter.Flush();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_logWriter.WriteLine("---- End of Log ----");
|
||||
_logWriter.Flush();
|
||||
_logWriter.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
9
Ryujinx.Common/Logging/Targets/ILogTarget.cs
Normal file
9
Ryujinx.Common/Logging/Targets/ILogTarget.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.Common.Logging
|
||||
{
|
||||
public interface ILogTarget : IDisposable
|
||||
{
|
||||
void Log(object sender, LogEventArgs args);
|
||||
}
|
||||
}
|
35
Ryujinx.Common/Logging/Targets/JsonLogTarget.cs
Normal file
35
Ryujinx.Common/Logging/Targets/JsonLogTarget.cs
Normal file
|
@ -0,0 +1,35 @@
|
|||
using System.IO;
|
||||
using Utf8Json;
|
||||
|
||||
namespace Ryujinx.Common.Logging
|
||||
{
|
||||
public class JsonLogTarget : ILogTarget
|
||||
{
|
||||
private Stream _stream;
|
||||
private bool _leaveOpen;
|
||||
|
||||
public JsonLogTarget(Stream stream)
|
||||
{
|
||||
_stream = stream;
|
||||
}
|
||||
|
||||
public JsonLogTarget(Stream stream, bool leaveOpen)
|
||||
{
|
||||
_stream = stream;
|
||||
_leaveOpen = leaveOpen;
|
||||
}
|
||||
|
||||
public void Log(object sender, LogEventArgs e)
|
||||
{
|
||||
JsonSerializer.Serialize(_stream, e);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_leaveOpen)
|
||||
{
|
||||
_stream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
75
Ryujinx.Common/Pools/ObjectPool.cs
Normal file
75
Ryujinx.Common/Pools/ObjectPool.cs
Normal file
|
@ -0,0 +1,75 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.Common
|
||||
{
|
||||
public class ObjectPool<T>
|
||||
where T : class
|
||||
{
|
||||
private T _firstItem;
|
||||
private readonly T[] _items;
|
||||
|
||||
private readonly Func<T> _factory;
|
||||
|
||||
public ObjectPool(Func<T> factory, int size)
|
||||
{
|
||||
_items = new T[size - 1];
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
public T Allocate()
|
||||
{
|
||||
var instance = _firstItem;
|
||||
|
||||
if (instance == null || instance != Interlocked.CompareExchange(ref _firstItem, null, instance))
|
||||
{
|
||||
instance = AllocateInternal();
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
private T AllocateInternal()
|
||||
{
|
||||
var items = _items;
|
||||
|
||||
for (int i = 0; i < items.Length; i++)
|
||||
{
|
||||
var instance = items[i];
|
||||
|
||||
if (instance != null && instance == Interlocked.CompareExchange(ref items[i], null, instance))
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
return _factory();
|
||||
}
|
||||
|
||||
public void Release(T obj)
|
||||
{
|
||||
if (_firstItem == null)
|
||||
{
|
||||
_firstItem = obj;
|
||||
}
|
||||
else
|
||||
{
|
||||
ReleaseInternal(obj);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReleaseInternal(T obj)
|
||||
{
|
||||
var items = _items;
|
||||
|
||||
for (int i = 0; i < items.Length; i++)
|
||||
{
|
||||
if (items[i] == null)
|
||||
{
|
||||
items[i] = obj;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
17
Ryujinx.Common/Pools/SharedPools.cs
Normal file
17
Ryujinx.Common/Pools/SharedPools.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
namespace Ryujinx.Common
|
||||
{
|
||||
public static class SharedPools
|
||||
{
|
||||
private static class DefaultPool<T>
|
||||
where T : class, new()
|
||||
{
|
||||
public static readonly ObjectPool<T> Instance = new ObjectPool<T>(() => new T(), 20);
|
||||
}
|
||||
|
||||
public static ObjectPool<T> Default<T>()
|
||||
where T : class, new()
|
||||
{
|
||||
return DefaultPool<T>.Instance;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,5 +25,9 @@
|
|||
<DefineConstants>TRACE;USE_PROFILING</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Utf8Json" Version="1.3.7" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -159,25 +159,23 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
Shader.SetExtraData(New.FlipX, New.FlipY, New.Instance);
|
||||
}
|
||||
|
||||
//Note: Uncomment SetFrontFace and SetCullFace when flipping issues are solved
|
||||
if (New.FrontFace != Old.FrontFace)
|
||||
{
|
||||
GL.FrontFace(OGLEnumConverter.GetFrontFace(New.FrontFace));
|
||||
}
|
||||
|
||||
//if (New.FrontFace != Old.FrontFace)
|
||||
//{
|
||||
// GL.FrontFace(OGLEnumConverter.GetFrontFace(New.FrontFace));
|
||||
//}
|
||||
if (New.CullFaceEnabled != Old.CullFaceEnabled)
|
||||
{
|
||||
Enable(EnableCap.CullFace, New.CullFaceEnabled);
|
||||
}
|
||||
|
||||
//if (New.CullFaceEnabled != Old.CullFaceEnabled)
|
||||
//{
|
||||
// Enable(EnableCap.CullFace, New.CullFaceEnabled);
|
||||
//}
|
||||
|
||||
//if (New.CullFaceEnabled)
|
||||
//{
|
||||
// if (New.CullFace != Old.CullFace)
|
||||
// {
|
||||
// GL.CullFace(OGLEnumConverter.GetCullFace(New.CullFace));
|
||||
// }
|
||||
//}
|
||||
if (New.CullFaceEnabled)
|
||||
{
|
||||
if (New.CullFace != Old.CullFace)
|
||||
{
|
||||
GL.CullFace(OGLEnumConverter.GetCullFace(New.CullFace));
|
||||
}
|
||||
}
|
||||
|
||||
if (New.DepthTestEnabled != Old.DepthTestEnabled)
|
||||
{
|
||||
|
|
|
@ -845,9 +845,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
case GlslDecl.PointCoordAttrX: return "gl_PointCoord.x";
|
||||
case GlslDecl.PointCoordAttrY: return "gl_PointCoord.y";
|
||||
|
||||
//Note: It's a guess that Maxwell's face is 1 when gl_FrontFacing == true
|
||||
case GlslDecl.FaceAttr: return "(gl_FrontFacing ? 1 : 0)";
|
||||
case GlslDecl.FaceAttr: return "(gl_FrontFacing ? -1 : 0)";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1148,41 +1148,87 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
||||
}
|
||||
|
||||
private enum XmadMode
|
||||
{
|
||||
Cfull = 0,
|
||||
Clo = 1,
|
||||
Chi = 2,
|
||||
Csfu = 3,
|
||||
Cbcc = 4
|
||||
}
|
||||
|
||||
private static void EmitXmad(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
||||
{
|
||||
//TODO: Confirm SignAB/C, it is just a guess.
|
||||
//TODO: Implement Mode 3 (CSFU), what it does?
|
||||
bool SignAB = OpCode.Read(48);
|
||||
bool SignC = OpCode.Read(49);
|
||||
bool HighB = OpCode.Read(52);
|
||||
bool HighA = OpCode.Read(53);
|
||||
bool SignedA = OpCode.Read(48);
|
||||
bool SignedB = OpCode.Read(49);
|
||||
bool HighB = OpCode.Read(52);
|
||||
bool HighA = OpCode.Read(53);
|
||||
|
||||
int Mode = OpCode.Read(50, 7);
|
||||
|
||||
ShaderIrNode OperA = OpCode.Gpr8(), OperB, OperC;
|
||||
|
||||
ShaderIrOperImm Imm16 = new ShaderIrOperImm(16);
|
||||
ShaderIrOperImm ImmMsk = new ShaderIrOperImm(0xffff);
|
||||
|
||||
ShaderIrInst ShiftAB = SignAB ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
|
||||
ShaderIrInst ShiftC = SignC ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
|
||||
|
||||
if (HighA)
|
||||
{
|
||||
OperA = new ShaderIrOp(ShiftAB, OperA, Imm16);
|
||||
}
|
||||
|
||||
switch (Oper)
|
||||
{
|
||||
case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
|
||||
case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
|
||||
case ShaderOper.RC: OperB = OpCode.Gpr39(); break;
|
||||
case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
|
||||
case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
|
||||
case ShaderOper.Imm: OperB = OpCode.ImmU16_20(); break;
|
||||
case ShaderOper.RC: OperB = OpCode.Gpr39(); break;
|
||||
case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
|
||||
|
||||
default: throw new ArgumentException(nameof(Oper));
|
||||
}
|
||||
|
||||
bool ProductShiftLeft = false, Merge = false;
|
||||
ShaderIrNode OperB2 = OperB;
|
||||
|
||||
if (Oper == ShaderOper.Imm)
|
||||
{
|
||||
int Imm = ((ShaderIrOperImm)OperB2).Value;
|
||||
|
||||
if (!HighB)
|
||||
{
|
||||
Imm <<= 16;
|
||||
}
|
||||
|
||||
if (SignedB)
|
||||
{
|
||||
Imm >>= 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
Imm = (int)((uint)Imm >> 16);
|
||||
}
|
||||
|
||||
OperB2 = new ShaderIrOperImm(Imm);
|
||||
}
|
||||
|
||||
ShaderIrOperImm Imm16 = new ShaderIrOperImm(16);
|
||||
|
||||
//If we are working with the lower 16-bits of the A/B operands,
|
||||
//we need to shift the lower 16-bits to the top 16-bits. Later,
|
||||
//they will be right shifted. For U16 types, this will be a logical
|
||||
//right shift, and for S16 types, a arithmetic right shift.
|
||||
if (!HighA)
|
||||
{
|
||||
OperA = new ShaderIrOp(ShaderIrInst.Lsl, OperA, Imm16);
|
||||
}
|
||||
|
||||
if (!HighB && Oper != ShaderOper.Imm)
|
||||
{
|
||||
OperB2 = new ShaderIrOp(ShaderIrInst.Lsl, OperB2, Imm16);
|
||||
}
|
||||
|
||||
ShaderIrInst ShiftA = SignedA ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
|
||||
ShaderIrInst ShiftB = SignedB ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
|
||||
|
||||
OperA = new ShaderIrOp(ShiftA, OperA, Imm16);
|
||||
|
||||
if (Oper != ShaderOper.Imm)
|
||||
{
|
||||
OperB2 = new ShaderIrOp(ShiftB, OperB2, Imm16);
|
||||
}
|
||||
|
||||
bool ProductShiftLeft = false;
|
||||
bool Merge = false;
|
||||
|
||||
if (Oper == ShaderOper.RC)
|
||||
{
|
||||
|
@ -1196,40 +1242,53 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Merge = OpCode.Read(37);
|
||||
}
|
||||
|
||||
switch (Mode)
|
||||
{
|
||||
//CLO.
|
||||
case 1: OperC = ExtendTo32(OperC, SignC, 16); break;
|
||||
|
||||
//CHI.
|
||||
case 2: OperC = new ShaderIrOp(ShiftC, OperC, Imm16); break;
|
||||
}
|
||||
|
||||
ShaderIrNode OperBH = OperB;
|
||||
|
||||
if (HighB)
|
||||
{
|
||||
OperBH = new ShaderIrOp(ShiftAB, OperBH, Imm16);
|
||||
}
|
||||
|
||||
ShaderIrOp MulOp = new ShaderIrOp(ShaderIrInst.Mul, OperA, OperBH);
|
||||
ShaderIrOp MulOp = new ShaderIrOp(ShaderIrInst.Mul, OperA, OperB2);
|
||||
|
||||
if (ProductShiftLeft)
|
||||
{
|
||||
MulOp = new ShaderIrOp(ShaderIrInst.Lsl, MulOp, Imm16);
|
||||
}
|
||||
|
||||
switch ((XmadMode)Mode)
|
||||
{
|
||||
case XmadMode.Clo: OperC = ExtendTo32(OperC, Signed: false, Size: 16); break;
|
||||
|
||||
case XmadMode.Chi: OperC = new ShaderIrOp(ShaderIrInst.Lsr, OperC, Imm16); break;
|
||||
|
||||
case XmadMode.Cbcc:
|
||||
{
|
||||
ShaderIrOp OperBLsh16 = new ShaderIrOp(ShaderIrInst.Lsl, OperB, Imm16);
|
||||
|
||||
OperC = new ShaderIrOp(ShaderIrInst.Add, OperC, OperBLsh16);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case XmadMode.Csfu:
|
||||
{
|
||||
ShaderIrOperImm Imm31 = new ShaderIrOperImm(31);
|
||||
|
||||
ShaderIrOp SignAdjustA = new ShaderIrOp(ShaderIrInst.Lsr, OperA, Imm31);
|
||||
ShaderIrOp SignAdjustB = new ShaderIrOp(ShaderIrInst.Lsr, OperB2, Imm31);
|
||||
|
||||
SignAdjustA = new ShaderIrOp(ShaderIrInst.Lsl, SignAdjustA, Imm16);
|
||||
SignAdjustB = new ShaderIrOp(ShaderIrInst.Lsl, SignAdjustB, Imm16);
|
||||
|
||||
ShaderIrOp SignAdjust = new ShaderIrOp(ShaderIrInst.Add, SignAdjustA, SignAdjustB);
|
||||
|
||||
OperC = new ShaderIrOp(ShaderIrInst.Sub, OperC, SignAdjust);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ShaderIrOp AddOp = new ShaderIrOp(ShaderIrInst.Add, MulOp, OperC);
|
||||
|
||||
if (Merge)
|
||||
{
|
||||
AddOp = new ShaderIrOp(ShaderIrInst.And, AddOp, ImmMsk);
|
||||
OperB = new ShaderIrOp(ShaderIrInst.Lsl, OperB, Imm16);
|
||||
AddOp = new ShaderIrOp(ShaderIrInst.Or, AddOp, OperB);
|
||||
}
|
||||
ShaderIrOperImm Imm16Mask = new ShaderIrOperImm(0xffff);
|
||||
|
||||
if (Mode == 4)
|
||||
{
|
||||
AddOp = new ShaderIrOp(ShaderIrInst.And, AddOp, Imm16Mask);
|
||||
OperB = new ShaderIrOp(ShaderIrInst.Lsl, OperB, Imm16);
|
||||
AddOp = new ShaderIrOp(ShaderIrInst.Or, AddOp, OperB);
|
||||
}
|
||||
|
|
|
@ -138,6 +138,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
return new ShaderIrOperImmf(BitConverter.Int32BitsToSingle((int)(OpCode >> 20)));
|
||||
}
|
||||
|
||||
private static ShaderIrOperImm ImmU16_20(this long OpCode)
|
||||
{
|
||||
return new ShaderIrOperImm(OpCode.Read(20, 0xffff));
|
||||
}
|
||||
|
||||
private static ShaderIrOperImm Imm19_20(this long OpCode)
|
||||
{
|
||||
int Value = OpCode.Read(20, 0x7ffff);
|
||||
|
|
|
@ -1023,8 +1023,6 @@ namespace Ryujinx.Graphics.Graphics3d
|
|||
|
||||
long Timestamp = PerformanceCounter.ElapsedMilliseconds;
|
||||
|
||||
Timestamp = (long)(Timestamp * 615384.615385);
|
||||
|
||||
Vmm.WriteInt64(Position + 0, Counter);
|
||||
Vmm.WriteInt64(Position + 8, Timestamp);
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using Ryujinx.HLE.HOS;
|
||||
using Ryujinx.HLE.HOS.Services.FspSrv;
|
||||
using Ryujinx.HLE.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
@ -279,5 +280,34 @@ namespace Ryujinx.HLE.FileSystem
|
|||
|
||||
throw new InvalidOperationException($"Path {path} is not a child directory of {_rootPath}");
|
||||
}
|
||||
|
||||
public FileTimestamp GetFileTimeStampRaw(string name)
|
||||
{
|
||||
CheckIfDescendentOfRootPath(name);
|
||||
|
||||
DateTime creationDateTime = DateTime.UnixEpoch;
|
||||
DateTime modifiedDateTime = DateTime.UnixEpoch;
|
||||
DateTime lastAccessDateTime = DateTime.UnixEpoch;
|
||||
|
||||
if (File.Exists(name))
|
||||
{
|
||||
creationDateTime = File.GetCreationTime(name);
|
||||
modifiedDateTime = File.GetLastWriteTime(name);
|
||||
lastAccessDateTime = File.GetLastAccessTime(name);
|
||||
}
|
||||
else if (Directory.Exists(name))
|
||||
{
|
||||
creationDateTime = Directory.GetCreationTime(name);
|
||||
modifiedDateTime = Directory.GetLastWriteTime(name);
|
||||
lastAccessDateTime = Directory.GetLastAccessTime(name);
|
||||
}
|
||||
|
||||
return new FileTimestamp
|
||||
{
|
||||
CreationDateTime = creationDateTime,
|
||||
ModifiedDateTime = modifiedDateTime,
|
||||
LastAccessDateTime = lastAccessDateTime
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using Ryujinx.HLE.HOS;
|
||||
using Ryujinx.HLE.HOS.Services.FspSrv;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.FileSystem
|
||||
{
|
||||
|
@ -36,5 +37,7 @@ namespace Ryujinx.HLE.FileSystem
|
|||
long GetFreeSpace(ServiceCtx context);
|
||||
|
||||
long GetTotalSpace(ServiceCtx context);
|
||||
|
||||
FileTimestamp GetFileTimeStampRaw(string name);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -143,5 +143,10 @@ namespace Ryujinx.HLE.FileSystem
|
|||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public FileTimestamp GetFileTimeStampRaw(string name)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -160,5 +160,10 @@ namespace Ryujinx.HLE.FileSystem
|
|||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public FileTimestamp GetFileTimeStampRaw(string name)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
77
Ryujinx.HLE/HOS/HomebrewRomFsStream.cs
Normal file
77
Ryujinx.HLE/HOS/HomebrewRomFsStream.cs
Normal file
|
@ -0,0 +1,77 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS
|
||||
{
|
||||
class HomebrewRomFsStream : Stream
|
||||
{
|
||||
private Stream _baseStream;
|
||||
private long _positionOffset;
|
||||
|
||||
public HomebrewRomFsStream(Stream baseStream, long positionOffset)
|
||||
{
|
||||
_baseStream = baseStream;
|
||||
_positionOffset = positionOffset;
|
||||
|
||||
_baseStream.Position = _positionOffset;
|
||||
}
|
||||
|
||||
public override bool CanRead => _baseStream.CanRead;
|
||||
|
||||
public override bool CanSeek => _baseStream.CanSeek;
|
||||
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public override long Length => _baseStream.Length - _positionOffset;
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return _baseStream.Position - _positionOffset;
|
||||
}
|
||||
set
|
||||
{
|
||||
_baseStream.Position = value + _positionOffset;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
_baseStream.Flush();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return _baseStream.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
if (origin == SeekOrigin.Begin)
|
||||
{
|
||||
offset += _positionOffset;
|
||||
}
|
||||
|
||||
return _baseStream.Seek(offset, origin);
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_baseStream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -102,6 +102,8 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
public Horizon(Switch device)
|
||||
{
|
||||
ControlData = new Nacp();
|
||||
|
||||
Device = device;
|
||||
|
||||
State = new SystemStateMgr();
|
||||
|
@ -549,14 +551,58 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
bool isNro = Path.GetExtension(filePath).ToLower() == ".nro";
|
||||
|
||||
using (FileStream input = new FileStream(filePath, FileMode.Open))
|
||||
{
|
||||
IExecutable staticObject = isNro
|
||||
? (IExecutable)new NxRelocatableObject(input)
|
||||
: new NxStaticObject(input);
|
||||
FileStream input = new FileStream(filePath, FileMode.Open);
|
||||
|
||||
ProgramLoader.LoadStaticObjects(this, metaData, new IExecutable[] { staticObject });
|
||||
IExecutable staticObject;
|
||||
|
||||
if (isNro)
|
||||
{
|
||||
NxRelocatableObject obj = new NxRelocatableObject(input);
|
||||
staticObject = obj;
|
||||
|
||||
// homebrew NRO can actually have some data after the actual NRO
|
||||
if (input.Length > obj.FileSize)
|
||||
{
|
||||
input.Position = obj.FileSize;
|
||||
|
||||
BinaryReader reader = new BinaryReader(input);
|
||||
|
||||
uint asetMagic = reader.ReadUInt32();
|
||||
|
||||
if (asetMagic == 0x54455341)
|
||||
{
|
||||
uint asetVersion = reader.ReadUInt32();
|
||||
if (asetVersion == 0)
|
||||
{
|
||||
ulong iconOffset = reader.ReadUInt64();
|
||||
ulong iconSize = reader.ReadUInt64();
|
||||
|
||||
ulong nacpOffset = reader.ReadUInt64();
|
||||
ulong nacpSize = reader.ReadUInt64();
|
||||
|
||||
ulong romfsOffset = reader.ReadUInt64();
|
||||
ulong romfsSize = reader.ReadUInt64();
|
||||
|
||||
if (romfsSize != 0)
|
||||
{
|
||||
Device.FileSystem.SetRomFs(new HomebrewRomFsStream(input, obj.FileSize + (long)romfsOffset));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.PrintWarning(LogClass.Loader, $"Unsupported ASET header version found \"{asetVersion}\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
staticObject = new NxStaticObject(input);
|
||||
}
|
||||
|
||||
ContentManager.LoadEntries();
|
||||
|
||||
ProgramLoader.LoadStaticObjects(this, metaData, new IExecutable[] { staticObject });
|
||||
}
|
||||
|
||||
private Npdm GetDefaultNpdm()
|
||||
|
|
|
@ -386,6 +386,132 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return _process.MemoryManager.UnmapPhysicalMemory(address, size);
|
||||
}
|
||||
|
||||
public KernelResult MapProcessCodeMemory64(int handle, ulong dst, ulong src, ulong size)
|
||||
{
|
||||
return MapProcessCodeMemory(handle, dst, src, size);
|
||||
}
|
||||
|
||||
public KernelResult MapProcessCodeMemory(int handle, ulong dst, ulong src, ulong size)
|
||||
{
|
||||
if (!PageAligned(dst) || !PageAligned(src))
|
||||
{
|
||||
return KernelResult.InvalidAddress;
|
||||
}
|
||||
|
||||
if (!PageAligned(size) || size == 0)
|
||||
{
|
||||
return KernelResult.InvalidSize;
|
||||
}
|
||||
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
KProcess targetProcess = currentProcess.HandleTable.GetObject<KProcess>(handle);
|
||||
|
||||
if (targetProcess == null)
|
||||
{
|
||||
return KernelResult.InvalidHandle;
|
||||
}
|
||||
|
||||
if (targetProcess.MemoryManager.OutsideAddrSpace(dst, size) ||
|
||||
targetProcess.MemoryManager.OutsideAddrSpace(src, size) ||
|
||||
targetProcess.MemoryManager.InsideAliasRegion(dst, size) ||
|
||||
targetProcess.MemoryManager.InsideHeapRegion(dst, size))
|
||||
{
|
||||
return KernelResult.InvalidMemRange;
|
||||
}
|
||||
|
||||
if (size + dst <= dst || size + src <= src)
|
||||
{
|
||||
return KernelResult.InvalidMemState;
|
||||
}
|
||||
|
||||
return targetProcess.MemoryManager.MapProcessCodeMemory(dst, src, size);
|
||||
}
|
||||
|
||||
public KernelResult UnmapProcessCodeMemory64(int handle, ulong dst, ulong src, ulong size)
|
||||
{
|
||||
return UnmapProcessCodeMemory(handle, dst, src, size);
|
||||
}
|
||||
|
||||
public KernelResult UnmapProcessCodeMemory(int handle, ulong dst, ulong src, ulong size)
|
||||
{
|
||||
if (!PageAligned(dst) || !PageAligned(src))
|
||||
{
|
||||
return KernelResult.InvalidAddress;
|
||||
}
|
||||
|
||||
if (!PageAligned(size) || size == 0)
|
||||
{
|
||||
return KernelResult.InvalidSize;
|
||||
}
|
||||
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
KProcess targetProcess = currentProcess.HandleTable.GetObject<KProcess>(handle);
|
||||
|
||||
if (targetProcess == null)
|
||||
{
|
||||
return KernelResult.InvalidHandle;
|
||||
}
|
||||
|
||||
if (targetProcess.MemoryManager.OutsideAddrSpace(dst, size) ||
|
||||
targetProcess.MemoryManager.OutsideAddrSpace(src, size) ||
|
||||
targetProcess.MemoryManager.InsideAliasRegion(dst, size) ||
|
||||
targetProcess.MemoryManager.InsideHeapRegion(dst, size))
|
||||
{
|
||||
return KernelResult.InvalidMemRange;
|
||||
}
|
||||
|
||||
if (size + dst <= dst || size + src <= src)
|
||||
{
|
||||
return KernelResult.InvalidMemState;
|
||||
}
|
||||
|
||||
return targetProcess.MemoryManager.UnmapProcessCodeMemory(dst, src, size);
|
||||
}
|
||||
|
||||
public KernelResult SetProcessMemoryPermission64(int handle, ulong src, ulong size, MemoryPermission permission)
|
||||
{
|
||||
return SetProcessMemoryPermission(handle, src, size, permission);
|
||||
}
|
||||
|
||||
public KernelResult SetProcessMemoryPermission(int handle, ulong src, ulong size, MemoryPermission permission)
|
||||
{
|
||||
if (!PageAligned(src))
|
||||
{
|
||||
return KernelResult.InvalidAddress;
|
||||
}
|
||||
|
||||
if (!PageAligned(size) || size == 0)
|
||||
{
|
||||
return KernelResult.InvalidSize;
|
||||
}
|
||||
|
||||
if (permission != MemoryPermission.None &&
|
||||
permission != MemoryPermission.Read &&
|
||||
permission != MemoryPermission.ReadAndWrite &&
|
||||
permission != MemoryPermission.ReadAndExecute)
|
||||
{
|
||||
return KernelResult.InvalidPermission;
|
||||
}
|
||||
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
KProcess targetProcess = currentProcess.HandleTable.GetObject<KProcess>(handle);
|
||||
|
||||
if (targetProcess == null)
|
||||
{
|
||||
return KernelResult.InvalidHandle;
|
||||
}
|
||||
|
||||
if (targetProcess.MemoryManager.OutsideAddrSpace(src, size))
|
||||
{
|
||||
return KernelResult.InvalidMemState;
|
||||
}
|
||||
|
||||
return targetProcess.MemoryManager.SetProcessMemoryPermission(src, size, permission);
|
||||
}
|
||||
|
||||
private static bool PageAligned(ulong position)
|
||||
{
|
||||
return (position & (KMemoryManager.PageSize - 1)) == 0;
|
||||
|
|
|
@ -71,7 +71,10 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
{ 0x6f, nameof(SvcHandler.GetSystemInfo64) },
|
||||
{ 0x70, nameof(SvcHandler.CreatePort64) },
|
||||
{ 0x71, nameof(SvcHandler.ManageNamedPort64) },
|
||||
{ 0x72, nameof(SvcHandler.ConnectToPort64) }
|
||||
{ 0x72, nameof(SvcHandler.ConnectToPort64) },
|
||||
{ 0x73, nameof(SvcHandler.SetProcessMemoryPermission64) },
|
||||
{ 0x77, nameof(SvcHandler.MapProcessCodeMemory64) },
|
||||
{ 0x78, nameof(SvcHandler.UnmapProcessCodeMemory64) }
|
||||
};
|
||||
|
||||
_svcTable64 = new Action<SvcHandler, CpuThreadState>[0x80];
|
||||
|
|
|
@ -312,7 +312,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
|
|||
|
||||
foreach (VoiceContext voice in _voices)
|
||||
{
|
||||
if (!voice.Playing)
|
||||
if (!voice.Playing || voice.CurrentWaveBuffer.Size == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -14,20 +14,24 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
|
|||
private int _bufferIndex;
|
||||
private int _offset;
|
||||
|
||||
public int SampleRate;
|
||||
public int ChannelsCount;
|
||||
public int SampleRate { get; set; }
|
||||
public int ChannelsCount { get; set; }
|
||||
|
||||
public float Volume;
|
||||
public float Volume { get; set; }
|
||||
|
||||
public PlayState PlayState;
|
||||
public PlayState PlayState { get; set; }
|
||||
|
||||
public SampleFormat SampleFormat;
|
||||
public SampleFormat SampleFormat { get; set; }
|
||||
|
||||
public AdpcmDecoderContext AdpcmCtx;
|
||||
public AdpcmDecoderContext AdpcmCtx { get; set; }
|
||||
|
||||
public WaveBuffer[] WaveBuffers;
|
||||
public WaveBuffer[] WaveBuffers { get; }
|
||||
|
||||
public VoiceOut OutStatus;
|
||||
public WaveBuffer CurrentWaveBuffer => WaveBuffers[_bufferIndex];
|
||||
|
||||
private VoiceOut _outStatus;
|
||||
|
||||
public VoiceOut OutStatus => _outStatus;
|
||||
|
||||
private int[] _samples;
|
||||
|
||||
|
@ -56,9 +60,9 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
|
|||
_bufferIndex = 0;
|
||||
_offset = 0;
|
||||
|
||||
OutStatus.PlayedSamplesCount = 0;
|
||||
OutStatus.PlayedWaveBuffersCount = 0;
|
||||
OutStatus.VoiceDropsCount = 0;
|
||||
_outStatus.PlayedSamplesCount = 0;
|
||||
_outStatus.PlayedWaveBuffersCount = 0;
|
||||
_outStatus.VoiceDropsCount = 0;
|
||||
}
|
||||
|
||||
public int[] GetBufferData(MemoryManager memory, int maxSamples, out int samplesCount)
|
||||
|
@ -94,7 +98,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
|
|||
|
||||
samplesCount = size / AudioConsts.HostChannelsCount;
|
||||
|
||||
OutStatus.PlayedSamplesCount += samplesCount;
|
||||
_outStatus.PlayedSamplesCount += samplesCount;
|
||||
|
||||
_offset += size;
|
||||
|
||||
|
@ -107,7 +111,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
|
|||
SetBufferIndex((_bufferIndex + 1) & 3);
|
||||
}
|
||||
|
||||
OutStatus.PlayedWaveBuffersCount++;
|
||||
_outStatus.PlayedWaveBuffersCount++;
|
||||
|
||||
if (wb.LastBuffer != 0)
|
||||
{
|
||||
|
|
11
Ryujinx.HLE/HOS/Services/FspSrv/FileTimestamp.cs
Normal file
11
Ryujinx.HLE/HOS/Services/FspSrv/FileTimestamp.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.FspSrv
|
||||
{
|
||||
struct FileTimestamp
|
||||
{
|
||||
public DateTime CreationDateTime;
|
||||
public DateTime ModifiedDateTime;
|
||||
public DateTime LastAccessDateTime;
|
||||
}
|
||||
}
|
|
@ -38,8 +38,8 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
|
|||
{ 10, Commit },
|
||||
{ 11, GetFreeSpaceSize },
|
||||
{ 12, GetTotalSpaceSize },
|
||||
{ 13, CleanDirectoryRecursively }
|
||||
//{ 14, GetFileTimeStampRaw }
|
||||
{ 13, CleanDirectoryRecursively },
|
||||
{ 14, GetFileTimeStampRaw }
|
||||
};
|
||||
|
||||
_openPaths = new HashSet<string>();
|
||||
|
@ -368,6 +368,34 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
|
|||
return 0;
|
||||
}
|
||||
|
||||
// GetFileTimeStampRaw(buffer<bytes<0x301>, 0x19, 0x301> path) -> bytes<0x20> timestamp
|
||||
public long GetFileTimeStampRaw(ServiceCtx context)
|
||||
{
|
||||
string name = ReadUtf8String(context);
|
||||
|
||||
string path = _provider.GetFullPath(name);
|
||||
|
||||
if (_provider.FileExists(path) || _provider.DirectoryExists(path))
|
||||
{
|
||||
FileTimestamp timestamp = _provider.GetFileTimeStampRaw(path);
|
||||
|
||||
context.ResponseData.Write(new DateTimeOffset(timestamp.CreationDateTime).ToUnixTimeSeconds());
|
||||
context.ResponseData.Write(new DateTimeOffset(timestamp.ModifiedDateTime).ToUnixTimeSeconds());
|
||||
context.ResponseData.Write(new DateTimeOffset(timestamp.LastAccessDateTime).ToUnixTimeSeconds());
|
||||
|
||||
byte[] data = new byte[8];
|
||||
|
||||
// is valid?
|
||||
data[0] = 1;
|
||||
|
||||
context.ResponseData.Write(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
|
||||
}
|
||||
|
||||
private bool IsPathAlreadyInUse(string path)
|
||||
{
|
||||
lock (_openPaths)
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using LibHac;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Ns
|
||||
{
|
||||
|
@ -9,14 +13,211 @@ namespace Ryujinx.HLE.HOS.Services.Ns
|
|||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
|
||||
private bool _isInitialized;
|
||||
|
||||
public IApplicationManagerInterface()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
{
|
||||
|
||||
{ 400, GetApplicationControlData }
|
||||
};
|
||||
}
|
||||
|
||||
public long GetApplicationControlData(ServiceCtx context)
|
||||
{
|
||||
long position = context.Request.ReceiveBuff[0].Position;
|
||||
|
||||
Nacp nacp = context.Device.System.ControlData;
|
||||
|
||||
for (int i = 0; i < 0x10; i++)
|
||||
{
|
||||
NacpDescription description = nacp.Descriptions[i];
|
||||
|
||||
byte[] titleData = new byte[0x200];
|
||||
byte[] developerData = new byte[0x100];
|
||||
|
||||
if (description !=null && description.Title != null)
|
||||
{
|
||||
byte[] titleDescriptionData = Encoding.ASCII.GetBytes(description.Title);
|
||||
Buffer.BlockCopy(titleDescriptionData, 0, titleData, 0, titleDescriptionData.Length);
|
||||
|
||||
}
|
||||
|
||||
if (description != null && description.Developer != null)
|
||||
{
|
||||
byte[] developerDescriptionData = Encoding.ASCII.GetBytes(description.Developer);
|
||||
Buffer.BlockCopy(developerDescriptionData, 0, developerData, 0, developerDescriptionData.Length);
|
||||
}
|
||||
|
||||
context.Memory.WriteBytes(position, titleData);
|
||||
context.Memory.WriteBytes(position + 0x200, developerData);
|
||||
|
||||
position += i * 0x300;
|
||||
}
|
||||
|
||||
byte[] isbn = new byte[0x25];
|
||||
|
||||
if (nacp.Isbn != null)
|
||||
{
|
||||
byte[] isbnData = Encoding.ASCII.GetBytes(nacp.Isbn);
|
||||
Buffer.BlockCopy(isbnData, 0, isbn, 0, isbnData.Length);
|
||||
}
|
||||
|
||||
context.Memory.WriteBytes(position, isbn);
|
||||
position += isbn.Length;
|
||||
|
||||
context.Memory.WriteByte(position++, nacp.StartupUserAccount);
|
||||
context.Memory.WriteByte(position++, nacp.TouchScreenUsageMode);
|
||||
context.Memory.WriteByte(position++, nacp.AocRegistrationType);
|
||||
|
||||
context.Memory.WriteInt32(position, nacp.AttributeFlag);
|
||||
position += 4;
|
||||
|
||||
context.Memory.WriteUInt32(position, nacp.SupportedLanguageFlag);
|
||||
position += 4;
|
||||
|
||||
context.Memory.WriteUInt32(position, nacp.ParentalControlFlag);
|
||||
position += 4;
|
||||
|
||||
context.Memory.WriteByte(position++, nacp.Screenshot);
|
||||
context.Memory.WriteByte(position++, nacp.VideoCapture);
|
||||
context.Memory.WriteByte(position++, nacp.DataLossConfirmation);
|
||||
context.Memory.WriteByte(position++, nacp.PlayLogPolicy);
|
||||
|
||||
context.Memory.WriteUInt64(position, nacp.PresenceGroupId);
|
||||
position += 8;
|
||||
|
||||
for (int i = 0; i < nacp.RatingAge.Length; i++)
|
||||
{
|
||||
context.Memory.WriteSByte(position++, nacp.RatingAge[i]);
|
||||
}
|
||||
|
||||
byte[] displayVersion = new byte[0x10];
|
||||
|
||||
if (nacp.DisplayVersion != null)
|
||||
{
|
||||
byte[] displayVersionData = Encoding.ASCII.GetBytes(nacp.DisplayVersion);
|
||||
Buffer.BlockCopy(displayVersionData, 0, displayVersion, 0, displayVersionData.Length);
|
||||
}
|
||||
|
||||
context.Memory.WriteBytes(position, displayVersion);
|
||||
position += displayVersion.Length;
|
||||
|
||||
context.Memory.WriteUInt64(position, nacp.AddOnContentBaseId);
|
||||
position += 8;
|
||||
|
||||
context.Memory.WriteUInt64(position, nacp.SaveDataOwnerId);
|
||||
position += 8;
|
||||
|
||||
context.Memory.WriteInt64(position, nacp.UserAccountSaveDataSize);
|
||||
position += 8;
|
||||
|
||||
context.Memory.WriteInt64(position, nacp.UserAccountSaveDataJournalSize);
|
||||
position += 8;
|
||||
|
||||
context.Memory.WriteInt64(position, nacp.DeviceSaveDataSize);
|
||||
position += 8;
|
||||
|
||||
context.Memory.WriteInt64(position, nacp.DeviceSaveDataJournalSize);
|
||||
position += 8;
|
||||
|
||||
context.Memory.WriteInt64(position, nacp.BcatDeliveryCacheStorageSize);
|
||||
position += 8;
|
||||
|
||||
byte[] applicationErrorCodeCategory = new byte[0x8];
|
||||
|
||||
if (nacp.ApplicationErrorCodeCategory != null)
|
||||
{
|
||||
byte[] applicationErrorCodeCategoryData = Encoding.ASCII.GetBytes(nacp.ApplicationErrorCodeCategory);
|
||||
Buffer.BlockCopy(applicationErrorCodeCategoryData, 0, applicationErrorCodeCategoryData, 0, applicationErrorCodeCategoryData.Length);
|
||||
}
|
||||
|
||||
context.Memory.WriteBytes(position, applicationErrorCodeCategory);
|
||||
position += applicationErrorCodeCategory.Length;
|
||||
|
||||
for (int i = 0; i < nacp.LocalCommunicationId.Length; i++)
|
||||
{
|
||||
context.Memory.WriteUInt64(position, nacp.LocalCommunicationId[i]);
|
||||
position += 8;
|
||||
}
|
||||
|
||||
context.Memory.WriteByte(position++, nacp.LogoType);
|
||||
context.Memory.WriteByte(position++, nacp.LogoHandling);
|
||||
context.Memory.WriteByte(position++, nacp.RuntimeAddOnContentInstall);
|
||||
|
||||
byte[] reserved000 = new byte[0x3];
|
||||
context.Memory.WriteBytes(position, reserved000);
|
||||
position += reserved000.Length;
|
||||
|
||||
context.Memory.WriteByte(position++, nacp.CrashReport);
|
||||
context.Memory.WriteByte(position++, nacp.Hdcp);
|
||||
context.Memory.WriteUInt64(position, nacp.SeedForPseudoDeviceId);
|
||||
position += 8;
|
||||
|
||||
byte[] bcatPassphrase = new byte[65];
|
||||
if (nacp.BcatPassphrase != null)
|
||||
{
|
||||
byte[] bcatPassphraseData = Encoding.ASCII.GetBytes(nacp.BcatPassphrase);
|
||||
Buffer.BlockCopy(bcatPassphraseData, 0, bcatPassphrase, 0, bcatPassphraseData.Length);
|
||||
}
|
||||
|
||||
context.Memory.WriteBytes(position, bcatPassphrase);
|
||||
position += bcatPassphrase.Length;
|
||||
|
||||
context.Memory.WriteByte(position++, nacp.Reserved01);
|
||||
|
||||
byte[] reserved02 = new byte[0x6];
|
||||
context.Memory.WriteBytes(position, reserved02);
|
||||
position += reserved02.Length;
|
||||
|
||||
context.Memory.WriteInt64(position, nacp.UserAccountSaveDataSizeMax);
|
||||
position += 8;
|
||||
|
||||
context.Memory.WriteInt64(position, nacp.UserAccountSaveDataJournalSizeMax);
|
||||
position += 8;
|
||||
|
||||
context.Memory.WriteInt64(position, nacp.DeviceSaveDataSizeMax);
|
||||
position += 8;
|
||||
|
||||
context.Memory.WriteInt64(position, nacp.DeviceSaveDataJournalSizeMax);
|
||||
position += 8;
|
||||
|
||||
context.Memory.WriteInt64(position, nacp.TemporaryStorageSize);
|
||||
position += 8;
|
||||
|
||||
context.Memory.WriteInt64(position, nacp.CacheStorageSize);
|
||||
position += 8;
|
||||
|
||||
context.Memory.WriteInt64(position, nacp.CacheStorageJournalSize);
|
||||
position += 8;
|
||||
|
||||
context.Memory.WriteInt64(position, nacp.CacheStorageDataAndJournalSizeMax);
|
||||
position += 8;
|
||||
|
||||
context.Memory.WriteInt16(position, nacp.CacheStorageIndex);
|
||||
position += 2;
|
||||
|
||||
byte[] reserved03 = new byte[0x6];
|
||||
context.Memory.WriteBytes(position, reserved03);
|
||||
position += reserved03.Length;
|
||||
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
ulong value = 0;
|
||||
|
||||
if (nacp.PlayLogQueryableApplicationId.Count > i)
|
||||
{
|
||||
value = nacp.PlayLogQueryableApplicationId[i];
|
||||
}
|
||||
|
||||
context.Memory.WriteUInt64(position, value);
|
||||
position += 8;
|
||||
}
|
||||
|
||||
context.Memory.WriteByte(position++, nacp.PlayLogQueryCapability);
|
||||
context.Memory.WriteByte(position++, nacp.RepairFlag);
|
||||
context.Memory.WriteByte(position++, nacp.ProgramIndex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,8 +13,15 @@ namespace Ryujinx.HLE.HOS.Services.Ns
|
|||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
{
|
||||
//...
|
||||
{ 7996, GetApplicationManagerInterface }
|
||||
};
|
||||
}
|
||||
|
||||
public long GetApplicationManagerInterface(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new IApplicationManagerInterface());
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
34
Ryujinx.HLE/HOS/Services/Pm/IShellInterface.cs
Normal file
34
Ryujinx.HLE/HOS/Services/Pm/IShellInterface.cs
Normal file
|
@ -0,0 +1,34 @@
|
|||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Pm
|
||||
{
|
||||
class IShellInterface : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
|
||||
public IShellInterface()
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
{
|
||||
{ 6, GetApplicationPid }
|
||||
};
|
||||
}
|
||||
|
||||
// GetApplicationPid() -> u64
|
||||
public long GetApplicationPid(ServiceCtx context)
|
||||
{
|
||||
// FIXME: This is wrong but needed to make hb loader works
|
||||
// TODO: Change this when we will have a way to process via a PM like interface.
|
||||
long pid = context.Process.Pid;
|
||||
|
||||
context.ResponseData.Write(pid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@ using Ryujinx.HLE.HOS.Services.Ns;
|
|||
using Ryujinx.HLE.HOS.Services.Nv;
|
||||
using Ryujinx.HLE.HOS.Services.Pctl;
|
||||
using Ryujinx.HLE.HOS.Services.Pl;
|
||||
using Ryujinx.HLE.HOS.Services.Pm;
|
||||
using Ryujinx.HLE.HOS.Services.Prepo;
|
||||
using Ryujinx.HLE.HOS.Services.Psm;
|
||||
using Ryujinx.HLE.HOS.Services.Set;
|
||||
|
@ -131,6 +132,7 @@ namespace Ryujinx.HLE.HOS.Services
|
|||
case "ns:am":
|
||||
return new IApplicationManagerInterface();
|
||||
|
||||
case "ns:am2":
|
||||
case "ns:ec":
|
||||
return new IServiceGetterInterface();
|
||||
|
||||
|
@ -161,6 +163,9 @@ namespace Ryujinx.HLE.HOS.Services
|
|||
case "pl:u":
|
||||
return new ISharedFontManager();
|
||||
|
||||
case "pm:shell":
|
||||
return new IShellInterface();
|
||||
|
||||
case "prepo:a":
|
||||
return new IPrepoService();
|
||||
|
||||
|
|
|
@ -23,9 +23,10 @@ namespace Ryujinx.HLE.HOS.Services.Sm
|
|||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
{
|
||||
{ 0, Initialize },
|
||||
{ 1, GetService },
|
||||
{ 2, RegisterService }
|
||||
{ 0, Initialize },
|
||||
{ 1, GetService },
|
||||
{ 2, RegisterService },
|
||||
{ 3, UnregisterService }
|
||||
};
|
||||
|
||||
_registeredServices = new ConcurrentDictionary<string, KPort>();
|
||||
|
@ -128,6 +129,36 @@ namespace Ryujinx.HLE.HOS.Services.Sm
|
|||
return 0;
|
||||
}
|
||||
|
||||
public long UnregisterService(ServiceCtx context)
|
||||
{
|
||||
if (!_isInitialized)
|
||||
{
|
||||
return ErrorCode.MakeError(ErrorModule.Sm, SmErr.NotInitialized);
|
||||
}
|
||||
|
||||
long namePosition = context.RequestData.BaseStream.Position;
|
||||
|
||||
string name = ReadName(context);
|
||||
|
||||
context.RequestData.BaseStream.Seek(namePosition + 8, SeekOrigin.Begin);
|
||||
|
||||
bool isLight = (context.RequestData.ReadInt32() & 1) != 0;
|
||||
|
||||
int maxSessions = context.RequestData.ReadInt32();
|
||||
|
||||
if (name == string.Empty)
|
||||
{
|
||||
return ErrorCode.MakeError(ErrorModule.Sm, SmErr.InvalidName);
|
||||
}
|
||||
|
||||
if (!_registeredServices.TryRemove(name, out _))
|
||||
{
|
||||
return ErrorCode.MakeError(ErrorModule.Sm, SmErr.NotRegistered);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static string ReadName(ServiceCtx context)
|
||||
{
|
||||
string name = string.Empty;
|
||||
|
|
|
@ -5,5 +5,6 @@ namespace Ryujinx.HLE.HOS.Services.Sm
|
|||
public const int NotInitialized = 2;
|
||||
public const int AlreadyRegistered = 4;
|
||||
public const int InvalidName = 6;
|
||||
public const int NotRegistered = 7;
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ using System;
|
|||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
using static Ryujinx.HLE.HOS.ErrorCode;
|
||||
using static Ryujinx.HLE.HOS.Services.Android.Parcel;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Vi
|
||||
|
@ -35,6 +36,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi
|
|||
{ 2030, CreateStrayLayer },
|
||||
{ 2031, DestroyStrayLayer },
|
||||
{ 2101, SetLayerScalingMode },
|
||||
{ 2102, ConvertScalingMode },
|
||||
{ 5202, GetDisplayVSyncEvent }
|
||||
};
|
||||
|
||||
|
@ -176,6 +178,35 @@ namespace Ryujinx.HLE.HOS.Services.Vi
|
|||
return 0;
|
||||
}
|
||||
|
||||
public long ConvertScalingMode(ServiceCtx context)
|
||||
{
|
||||
SrcScalingMode scalingMode = (SrcScalingMode)context.RequestData.ReadInt32();
|
||||
DstScalingMode? destScalingMode = ConvetScalingModeImpl(scalingMode);
|
||||
|
||||
if (!destScalingMode.HasValue)
|
||||
{
|
||||
return MakeError(ErrorModule.Vi, 1);
|
||||
}
|
||||
|
||||
context.ResponseData.Write((ulong)destScalingMode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private DstScalingMode? ConvetScalingModeImpl(SrcScalingMode srcScalingMode)
|
||||
{
|
||||
switch (srcScalingMode)
|
||||
{
|
||||
case SrcScalingMode.None: return DstScalingMode.None;
|
||||
case SrcScalingMode.Freeze: return DstScalingMode.Freeze;
|
||||
case SrcScalingMode.ScaleAndCrop: return DstScalingMode.ScaleAndCrop;
|
||||
case SrcScalingMode.ScaleToWindow: return DstScalingMode.ScaleToWindow;
|
||||
case SrcScalingMode.PreserveAspectRatio: return DstScalingMode.PreserveAspectRatio;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public long GetDisplayVSyncEvent(ServiceCtx context)
|
||||
{
|
||||
string name = GetDisplayName(context);
|
||||
|
|
24
Ryujinx.HLE/HOS/Services/Vi/ScalingMode.cs
Normal file
24
Ryujinx.HLE/HOS/Services/Vi/ScalingMode.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Vi
|
||||
{
|
||||
enum SrcScalingMode
|
||||
{
|
||||
Freeze = 0,
|
||||
ScaleToWindow = 1,
|
||||
ScaleAndCrop = 2,
|
||||
None = 3,
|
||||
PreserveAspectRatio = 4
|
||||
}
|
||||
|
||||
enum DstScalingMode
|
||||
{
|
||||
None = 0,
|
||||
Freeze = 1,
|
||||
ScaleToWindow = 2,
|
||||
ScaleAndCrop = 3,
|
||||
PreserveAspectRatio = 4
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ namespace Ryujinx.HLE.Loaders.Executables
|
|||
public int RoOffset { get; private set; }
|
||||
public int DataOffset { get; private set; }
|
||||
public int BssSize { get; private set; }
|
||||
public int FileSize { get; private set; }
|
||||
|
||||
public int BssOffset => DataOffset + Data.Length;
|
||||
|
||||
|
@ -59,6 +60,8 @@ namespace Ryujinx.HLE.Loaders.Executables
|
|||
Text = Read(textOffset, textSize);
|
||||
Ro = Read(roOffset, roSize);
|
||||
Data = Read(dataOffset, dataSize);
|
||||
|
||||
FileSize = fileSize;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -112,7 +112,6 @@ namespace Ryujinx.HLE
|
|||
if (disposing)
|
||||
{
|
||||
System.Dispose();
|
||||
|
||||
VsyncEvent.Dispose();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Luea", "Ryujinx.LLE\Luea.cs
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Common", "Ryujinx.Common\Ryujinx.Common.csproj", "{5FD4E4F6-8928-4B3C-BE07-28A675C17226}"
|
||||
EndProject
|
||||
<<<<<<< HEAD
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Profiler", "Ryujinx.Profiler\Ryujinx.Profiler.csproj", "{4E69B67F-8CA7-42CF-A9E1-CCB0915DFB34}"
|
||||
=======
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{464D8AB7-B056-4A99-B207-B8DCFB47AAA9}"
|
||||
>>>>>>> original_master
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
@ -128,6 +132,10 @@ Global
|
|||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9} = {464D8AB7-B056-4A99-B207-B8DCFB47AAA9}
|
||||
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15} = {464D8AB7-B056-4A99-B207-B8DCFB47AAA9}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {110169B3-3328-4730-8AB0-BA05BEF75C1A}
|
||||
EndGlobalSection
|
||||
|
|
|
@ -1,225 +0,0 @@
|
|||
using LibHac.IO;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE;
|
||||
using Ryujinx.HLE.HOS.SystemState;
|
||||
using Ryujinx.HLE.Input;
|
||||
using Ryujinx.UI.Input;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Ryujinx.Profiler;
|
||||
using Ryujinx.Ui;
|
||||
using Ryujinx.Common;
|
||||
|
||||
namespace Ryujinx
|
||||
{
|
||||
public static class Config
|
||||
{
|
||||
public static NpadKeyboard NpadKeyboard { get; private set; }
|
||||
public static NpadController NpadController { get; private set; }
|
||||
public static NPadDebug NPadDebug { get; private set; }
|
||||
|
||||
public static void Read(Switch device)
|
||||
{
|
||||
string iniFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
||||
|
||||
string iniPath = Path.Combine(iniFolder, "Ryujinx.conf");
|
||||
|
||||
IniParser parser = new IniParser(iniPath);
|
||||
|
||||
GraphicsConfig.ShadersDumpPath = parser.Value("Graphics_Shaders_Dump_Path");
|
||||
|
||||
Logger.SetEnable(LogLevel.Debug, Convert.ToBoolean(parser.Value("Logging_Enable_Debug")));
|
||||
Logger.SetEnable(LogLevel.Stub, Convert.ToBoolean(parser.Value("Logging_Enable_Stub")));
|
||||
Logger.SetEnable(LogLevel.Info, Convert.ToBoolean(parser.Value("Logging_Enable_Info")));
|
||||
Logger.SetEnable(LogLevel.Warning, Convert.ToBoolean(parser.Value("Logging_Enable_Warn")));
|
||||
Logger.SetEnable(LogLevel.Error, Convert.ToBoolean(parser.Value("Logging_Enable_Error")));
|
||||
|
||||
string[] filteredLogClasses = parser.Value("Logging_Filtered_Classes").Split(',', StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
//When the classes are specified on the list, we only
|
||||
//enable the classes that are on the list.
|
||||
//So, first disable everything, then enable
|
||||
//the classes that the user added to the list.
|
||||
if (filteredLogClasses.Length > 0)
|
||||
{
|
||||
foreach (LogClass Class in Enum.GetValues(typeof(LogClass)))
|
||||
{
|
||||
Logger.SetEnable(Class, false);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string logClass in filteredLogClasses)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(logClass.Trim()))
|
||||
{
|
||||
foreach (LogClass Class in Enum.GetValues(typeof(LogClass)))
|
||||
{
|
||||
if (Class.ToString().ToLower().Contains(logClass.Trim().ToLower()))
|
||||
{
|
||||
Logger.SetEnable(Class, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string profilePath = parser.Value("Profile_Dump_Path");
|
||||
double updateRateHz = Convert.ToSingle(parser.Value("Profiling_Update_Rate"));
|
||||
Profile.Configure(new ProfilerSettings()
|
||||
{
|
||||
Enabled = Convert.ToBoolean(parser.Value("Profiling_Enabled")),
|
||||
FileDumpEnabled = profilePath != "",
|
||||
DumpLocation = profilePath,
|
||||
UpdateRate = (float)((updateRateHz <= 0) ? -1 : 1.0f / updateRateHz),
|
||||
History = (long)(Convert.ToDouble(parser.Value("Profiling_History")) * PerformanceCounter.TicksPerSecond),
|
||||
MaxLevel = Convert.ToInt32(parser.Value("Profiling_Max_Level")),
|
||||
});
|
||||
|
||||
Logger.EnableFileLog = Convert.ToBoolean(parser.Value("Enable_File_Log"));
|
||||
|
||||
SystemLanguage SetLanguage = Enum.Parse<SystemLanguage>(parser.Value("System_Language"));
|
||||
|
||||
device.System.State.SetLanguage(SetLanguage);
|
||||
|
||||
device.System.State.DockedMode = Convert.ToBoolean(parser.Value("Docked_Mode"));
|
||||
|
||||
device.EnableDeviceVsync = Convert.ToBoolean(parser.Value("Enable_Vsync"));
|
||||
|
||||
if (Convert.ToBoolean(parser.Value("Enable_MultiCore_Scheduling")))
|
||||
{
|
||||
device.System.EnableMultiCoreScheduling();
|
||||
}
|
||||
|
||||
device.System.FsIntegrityCheckLevel = Convert.ToBoolean(parser.Value("Enable_FS_Integrity_Checks"))
|
||||
? IntegrityCheckLevel.ErrorOnInvalid
|
||||
: IntegrityCheckLevel.None;
|
||||
|
||||
HidControllerType ControllerType = Enum.Parse<HidControllerType>(parser.Value("Controller_Type"));
|
||||
|
||||
device.Hid.InitilizePrimaryController(ControllerType);
|
||||
|
||||
NpadKeyboard = new NpadKeyboard(
|
||||
|
||||
new NpadKeyboardLeft
|
||||
{
|
||||
StickUp = Convert.ToInt16(parser.Value("Controls_Left_JoyConKeyboard_Stick_Up")),
|
||||
StickDown = Convert.ToInt16(parser.Value("Controls_Left_JoyConKeyboard_Stick_Down")),
|
||||
StickLeft = Convert.ToInt16(parser.Value("Controls_Left_JoyConKeyboard_Stick_Left")),
|
||||
StickRight = Convert.ToInt16(parser.Value("Controls_Left_JoyConKeyboard_Stick_Right")),
|
||||
StickButton = Convert.ToInt16(parser.Value("Controls_Left_JoyConKeyboard_Stick_Button")),
|
||||
DPadUp = Convert.ToInt16(parser.Value("Controls_Left_JoyConKeyboard_DPad_Up")),
|
||||
DPadDown = Convert.ToInt16(parser.Value("Controls_Left_JoyConKeyboard_DPad_Down")),
|
||||
DPadLeft = Convert.ToInt16(parser.Value("Controls_Left_JoyConKeyboard_DPad_Left")),
|
||||
DPadRight = Convert.ToInt16(parser.Value("Controls_Left_JoyConKeyboard_DPad_Right")),
|
||||
ButtonMinus = Convert.ToInt16(parser.Value("Controls_Left_JoyConKeyboard_Button_Minus")),
|
||||
ButtonL = Convert.ToInt16(parser.Value("Controls_Left_JoyConKeyboard_Button_L")),
|
||||
ButtonZl = Convert.ToInt16(parser.Value("Controls_Left_JoyConKeyboard_Button_ZL"))
|
||||
},
|
||||
|
||||
new NpadKeyboardRight
|
||||
{
|
||||
StickUp = Convert.ToInt16(parser.Value("Controls_Right_JoyConKeyboard_Stick_Up")),
|
||||
StickDown = Convert.ToInt16(parser.Value("Controls_Right_JoyConKeyboard_Stick_Down")),
|
||||
StickLeft = Convert.ToInt16(parser.Value("Controls_Right_JoyConKeyboard_Stick_Left")),
|
||||
StickRight = Convert.ToInt16(parser.Value("Controls_Right_JoyConKeyboard_Stick_Right")),
|
||||
StickButton = Convert.ToInt16(parser.Value("Controls_Right_JoyConKeyboard_Stick_Button")),
|
||||
ButtonA = Convert.ToInt16(parser.Value("Controls_Right_JoyConKeyboard_Button_A")),
|
||||
ButtonB = Convert.ToInt16(parser.Value("Controls_Right_JoyConKeyboard_Button_B")),
|
||||
ButtonX = Convert.ToInt16(parser.Value("Controls_Right_JoyConKeyboard_Button_X")),
|
||||
ButtonY = Convert.ToInt16(parser.Value("Controls_Right_JoyConKeyboard_Button_Y")),
|
||||
ButtonPlus = Convert.ToInt16(parser.Value("Controls_Right_JoyConKeyboard_Button_Plus")),
|
||||
ButtonR = Convert.ToInt16(parser.Value("Controls_Right_JoyConKeyboard_Button_R")),
|
||||
ButtonZr = Convert.ToInt16(parser.Value("Controls_Right_JoyConKeyboard_Button_ZR"))
|
||||
});
|
||||
|
||||
NpadController = new NpadController(
|
||||
Convert.ToBoolean(parser.Value("GamePad_Enable")),
|
||||
Convert.ToInt32 (parser.Value("GamePad_Index")),
|
||||
(float)Convert.ToDouble (parser.Value("GamePad_Deadzone"), CultureInfo.InvariantCulture),
|
||||
(float)Convert.ToDouble (parser.Value("GamePad_Trigger_Threshold"), CultureInfo.InvariantCulture),
|
||||
|
||||
new NpadControllerLeft
|
||||
{
|
||||
Stick = ToId(parser.Value("Controls_Left_JoyConController_Stick")),
|
||||
StickButton = ToId(parser.Value("Controls_Left_JoyConController_Stick_Button")),
|
||||
DPadUp = ToId(parser.Value("Controls_Left_JoyConController_DPad_Up")),
|
||||
DPadDown = ToId(parser.Value("Controls_Left_JoyConController_DPad_Down")),
|
||||
DPadLeft = ToId(parser.Value("Controls_Left_JoyConController_DPad_Left")),
|
||||
DPadRight = ToId(parser.Value("Controls_Left_JoyConController_DPad_Right")),
|
||||
ButtonMinus = ToId(parser.Value("Controls_Left_JoyConController_Button_Minus")),
|
||||
ButtonL = ToId(parser.Value("Controls_Left_JoyConController_Button_L")),
|
||||
ButtonZl = ToId(parser.Value("Controls_Left_JoyConController_Button_ZL"))
|
||||
},
|
||||
|
||||
new NpadControllerRight
|
||||
{
|
||||
Stick = ToId(parser.Value("Controls_Right_JoyConController_Stick")),
|
||||
StickButton = ToId(parser.Value("Controls_Right_JoyConController_Stick_Button")),
|
||||
ButtonA = ToId(parser.Value("Controls_Right_JoyConController_Button_A")),
|
||||
ButtonB = ToId(parser.Value("Controls_Right_JoyConController_Button_B")),
|
||||
ButtonX = ToId(parser.Value("Controls_Right_JoyConController_Button_X")),
|
||||
ButtonY = ToId(parser.Value("Controls_Right_JoyConController_Button_Y")),
|
||||
ButtonPlus = ToId(parser.Value("Controls_Right_JoyConController_Button_Plus")),
|
||||
ButtonR = ToId(parser.Value("Controls_Right_JoyConController_Button_R")),
|
||||
ButtonZr = ToId(parser.Value("Controls_Right_JoyConController_Button_ZR"))
|
||||
});
|
||||
|
||||
NPadDebug = new NPadDebug(
|
||||
new NPadDebugButtons()
|
||||
{
|
||||
ToggleProfiler = Convert.ToInt16(parser.Value(("Controls_Debug_Toggle_Profiler"))),
|
||||
});
|
||||
}
|
||||
|
||||
private static ControllerInputId ToId(string key)
|
||||
{
|
||||
switch (key.ToUpper())
|
||||
{
|
||||
case "LSTICK": return ControllerInputId.LStick;
|
||||
case "DPADUP": return ControllerInputId.DPadUp;
|
||||
case "DPADDOWN": return ControllerInputId.DPadDown;
|
||||
case "DPADLEFT": return ControllerInputId.DPadLeft;
|
||||
case "DPADRIGHT": return ControllerInputId.DPadRight;
|
||||
case "BACK": return ControllerInputId.Back;
|
||||
case "LSHOULDER": return ControllerInputId.LShoulder;
|
||||
case "LTRIGGER": return ControllerInputId.LTrigger;
|
||||
|
||||
case "RSTICK": return ControllerInputId.RStick;
|
||||
case "A": return ControllerInputId.A;
|
||||
case "B": return ControllerInputId.B;
|
||||
case "X": return ControllerInputId.X;
|
||||
case "Y": return ControllerInputId.Y;
|
||||
case "START": return ControllerInputId.Start;
|
||||
case "RSHOULDER": return ControllerInputId.RShoulder;
|
||||
case "RTRIGGER": return ControllerInputId.RTrigger;
|
||||
|
||||
case "LJOYSTICK": return ControllerInputId.LJoystick;
|
||||
case "RJOYSTICK": return ControllerInputId.RJoystick;
|
||||
|
||||
default: return ControllerInputId.Invalid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//https://stackoverflow.com/a/37772571
|
||||
public class IniParser
|
||||
{
|
||||
private readonly Dictionary<string, string> _values;
|
||||
|
||||
public IniParser(string path)
|
||||
{
|
||||
_values = File.ReadLines(path)
|
||||
.Where(line => !string.IsNullOrWhiteSpace(line) && !line.StartsWith('#'))
|
||||
.Select(line => line.Split('=', 2))
|
||||
.ToDictionary(parts => parts[0].Trim(), parts => parts.Length > 1 ? parts[1].Trim() : null);
|
||||
}
|
||||
|
||||
public string Value(string name)
|
||||
{
|
||||
return _values.TryGetValue(name, out string value) ? value : null;
|
||||
}
|
||||
}
|
||||
}
|
124
Ryujinx/Config.jsonc
Normal file
124
Ryujinx/Config.jsonc
Normal file
|
@ -0,0 +1,124 @@
|
|||
{
|
||||
"$schema": "./_schema.json",
|
||||
|
||||
// Dump shaders in local directory (e.g. `C:\ShaderDumps`)
|
||||
"graphics_shaders_dump_path": "",
|
||||
|
||||
// Enable print debug logs
|
||||
"logging_enable_debug": false,
|
||||
|
||||
// Enable print stubbed calls logs
|
||||
"logging_enable_stub": true,
|
||||
|
||||
// Enable print informations logs
|
||||
"logging_enable_info": true,
|
||||
|
||||
// Enable print warning logs
|
||||
"logging_enable_warn": true,
|
||||
|
||||
// Enable print error logs
|
||||
"logging_enable_error": true,
|
||||
|
||||
// Filtered log classes, in a JSON array, eg. `[ "Loader", "ServiceFs" ]`
|
||||
"logging_filtered_classes": [ ],
|
||||
|
||||
// Enable file logging
|
||||
"enable_file_log": true,
|
||||
|
||||
// Change System Language
|
||||
// System Language list: https://gist.github.com/HorrorTroll/b6e4a88d774c3c9b3bdf54d79a7ca43b
|
||||
"system_language": "AmericanEnglish",
|
||||
|
||||
// Enable or Disable Docked Mode
|
||||
"docked_mode": false,
|
||||
|
||||
// Enable or Disable Game Vsync
|
||||
"enable_vsync": true,
|
||||
|
||||
// Enable or Disable Multi-core scheduling of threads
|
||||
"enable_multicore_scheduling": false,
|
||||
|
||||
// Enable integrity checks on Switch content files
|
||||
"enable_fs_integrity_checks": true,
|
||||
|
||||
// The primary controller's type
|
||||
// Supported Values: Handheld, ProController, NpadPair, NpadLeft, NpadRight
|
||||
"controller_type": "Handheld",
|
||||
|
||||
// Keyboard Controls
|
||||
// https://github.com/opentk/opentk/blob/master/src/OpenTK/Input/Key.cs
|
||||
"keyboard_controls": {
|
||||
// Left JoyCon Keyboard Bindings
|
||||
"left_joycon": {
|
||||
"stick_up": "W",
|
||||
"stick_down": "S",
|
||||
"stick_left": "A",
|
||||
"stick_right": "D",
|
||||
"stick_button": "F",
|
||||
"dpad_up": "Up",
|
||||
"dpad_down": "Down",
|
||||
"dpad_left": "Left",
|
||||
"dpad_right": "Right",
|
||||
"button_minus": "Minus",
|
||||
"button_l": "E",
|
||||
"button_zl": "Q"
|
||||
},
|
||||
|
||||
// Right JoyCon Keyboard Bindings
|
||||
"right_joycon": {
|
||||
"stick_up": "I",
|
||||
"stick_down": "K",
|
||||
"stick_left": "J",
|
||||
"stick_right": "L",
|
||||
"stick_button": "H",
|
||||
"button_a": "Z",
|
||||
"button_b": "X",
|
||||
"button_x": "C",
|
||||
"button_y": "V",
|
||||
"button_plus": "Plus",
|
||||
"button_r": "U",
|
||||
"button_zr": "O"
|
||||
}
|
||||
},
|
||||
|
||||
// Controller Controls
|
||||
"gamepad_controls": {
|
||||
// Whether or not to enable Controller support
|
||||
"enabled": true,
|
||||
|
||||
// Controller Device Index
|
||||
"index": 0,
|
||||
|
||||
// Controller Analog Stick Deadzone
|
||||
"deadzone": 0.05,
|
||||
|
||||
// The value of how pressed down each trigger has to be in order to register a button press
|
||||
"trigger_threshold": 0.5,
|
||||
|
||||
// Left JoyCon Controller Bindings
|
||||
"left_joycon": {
|
||||
"stick": "LJoystick",
|
||||
"stick_button": "LStick",
|
||||
"dpad_up": "DPadUp",
|
||||
"dpad_down": "DPadDown",
|
||||
"dpad_left": "DPadLeft",
|
||||
"dpad_right": "DPadRight",
|
||||
"button_minus": "Back",
|
||||
"button_l": "LShoulder",
|
||||
"button_zl": "LTrigger"
|
||||
},
|
||||
|
||||
// Right JoyCon Controller Bindings
|
||||
"right_joycon": {
|
||||
"stick": "RJoystick",
|
||||
"stick_button": "RStick",
|
||||
"button_a": "B",
|
||||
"button_b": "A",
|
||||
"button_x": "Y",
|
||||
"button_y": "X",
|
||||
"button_plus": "Start",
|
||||
"button_r": "RShoulder",
|
||||
"button_zr": "RTrigger"
|
||||
}
|
||||
}
|
||||
}
|
239
Ryujinx/Configuration.cs
Normal file
239
Ryujinx/Configuration.cs
Normal file
|
@ -0,0 +1,239 @@
|
|||
using LibHac.IO;
|
||||
using OpenTK.Input;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE;
|
||||
using Ryujinx.HLE.HOS.SystemState;
|
||||
using Ryujinx.HLE.Input;
|
||||
using Ryujinx.UI.Input;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Utf8Json;
|
||||
using Utf8Json.Resolvers;
|
||||
|
||||
namespace Ryujinx
|
||||
{
|
||||
public class Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// The default configuration instance
|
||||
/// </summary>
|
||||
public static Configuration Instance { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Dumps shaders in this local directory
|
||||
/// </summary>
|
||||
public string GraphicsShadersDumpPath { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enables printing debug log messages
|
||||
/// </summary>
|
||||
public bool LoggingEnableDebug { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enables printing stub log messages
|
||||
/// </summary>
|
||||
public bool LoggingEnableStub { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enables printing info log messages
|
||||
/// </summary>
|
||||
public bool LoggingEnableInfo { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enables printing warning log messages
|
||||
/// </summary>
|
||||
public bool LoggingEnableWarn { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enables printing error log messages
|
||||
/// </summary>
|
||||
public bool LoggingEnableError { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Controls which log messages are written to the log targets
|
||||
/// </summary>
|
||||
public LogClass[] LoggingFilteredClasses { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enables or disables logging to a file on disk
|
||||
/// </summary>
|
||||
public bool EnableFileLog { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Change System Language
|
||||
/// </summary>
|
||||
public SystemLanguage SystemLanguage { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enables or disables Docked Mode
|
||||
/// </summary>
|
||||
public bool DockedMode { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enables or disables Vertical Sync
|
||||
/// </summary>
|
||||
public bool EnableVsync { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enables or disables multi-core scheduling of threads
|
||||
/// </summary>
|
||||
public bool EnableMultiCoreScheduling { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enables integrity checks on Game content files
|
||||
/// </summary>
|
||||
public bool EnableFsIntegrityChecks { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The primary controller's type
|
||||
/// </summary>
|
||||
public HidControllerType ControllerType { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Keyboard control bindings
|
||||
/// </summary>
|
||||
public NpadKeyboard KeyboardControls { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Controller control bindings
|
||||
/// </summary>
|
||||
public NpadController GamepadControls { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Loads a configuration file from disk
|
||||
/// </summary>
|
||||
/// <param name="path">The path to the JSON configuration file</param>
|
||||
public static void Load(string path)
|
||||
{
|
||||
var resolver = CompositeResolver.Create(
|
||||
new[] { new ConfigurationEnumFormatter<Key>() },
|
||||
new[] { StandardResolver.AllowPrivateSnakeCase }
|
||||
);
|
||||
|
||||
using (Stream stream = File.OpenRead(path))
|
||||
{
|
||||
Instance = JsonSerializer.Deserialize<Configuration>(stream, resolver);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads a configuration file asynchronously from disk
|
||||
/// </summary>
|
||||
/// <param name="path">The path to the JSON configuration file</param>
|
||||
public static async Task LoadAsync(string path)
|
||||
{
|
||||
var resolver = CompositeResolver.Create(
|
||||
new[] { new ConfigurationEnumFormatter<Key>() },
|
||||
new[] { StandardResolver.AllowPrivateSnakeCase }
|
||||
);
|
||||
|
||||
using (Stream stream = File.OpenRead(path))
|
||||
{
|
||||
Instance = await JsonSerializer.DeserializeAsync<Configuration>(stream, resolver);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures a <see cref="Switch"/> instance
|
||||
/// </summary>
|
||||
/// <param name="device">The instance to configure</param>
|
||||
public static void Configure(Switch device)
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
throw new InvalidOperationException("Configuration has not been loaded yet.");
|
||||
}
|
||||
|
||||
GraphicsConfig.ShadersDumpPath = Instance.GraphicsShadersDumpPath;
|
||||
|
||||
Logger.AddTarget(new AsyncLogTargetWrapper(
|
||||
new ConsoleLogTarget(),
|
||||
1000,
|
||||
AsyncLogTargetOverflowAction.Block
|
||||
));
|
||||
|
||||
if (Instance.EnableFileLog)
|
||||
{
|
||||
Logger.AddTarget(new AsyncLogTargetWrapper(
|
||||
new FileLogTarget(Path.Combine(Program.ApplicationDirectory, "Ryujinx.log")),
|
||||
1000,
|
||||
AsyncLogTargetOverflowAction.Block
|
||||
));
|
||||
}
|
||||
|
||||
Logger.SetEnable(LogLevel.Debug, Instance.LoggingEnableDebug);
|
||||
Logger.SetEnable(LogLevel.Stub, Instance.LoggingEnableStub);
|
||||
Logger.SetEnable(LogLevel.Info, Instance.LoggingEnableInfo);
|
||||
Logger.SetEnable(LogLevel.Warning, Instance.LoggingEnableWarn);
|
||||
Logger.SetEnable(LogLevel.Error, Instance.LoggingEnableError);
|
||||
|
||||
if (Instance.LoggingFilteredClasses.Length > 0)
|
||||
{
|
||||
foreach (var logClass in EnumExtensions.GetValues<LogClass>())
|
||||
{
|
||||
Logger.SetEnable(logClass, false);
|
||||
}
|
||||
|
||||
foreach (var logClass in Instance.LoggingFilteredClasses)
|
||||
{
|
||||
Logger.SetEnable(logClass, true);
|
||||
}
|
||||
}
|
||||
|
||||
device.EnableDeviceVsync = Instance.EnableVsync;
|
||||
|
||||
device.System.State.DockedMode = Instance.DockedMode;
|
||||
|
||||
device.System.State.SetLanguage(Instance.SystemLanguage);
|
||||
|
||||
if (Instance.EnableMultiCoreScheduling)
|
||||
{
|
||||
device.System.EnableMultiCoreScheduling();
|
||||
}
|
||||
|
||||
device.System.FsIntegrityCheckLevel = Instance.EnableFsIntegrityChecks
|
||||
? IntegrityCheckLevel.ErrorOnInvalid
|
||||
: IntegrityCheckLevel.None;
|
||||
|
||||
if(Instance.GamepadControls.Enabled)
|
||||
{
|
||||
if (GamePad.GetName(Instance.GamepadControls.Index) == "Unmapped Controller")
|
||||
{
|
||||
Instance.GamepadControls.SetEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
device.Hid.InitilizePrimaryController(Instance.ControllerType);
|
||||
}
|
||||
|
||||
private class ConfigurationEnumFormatter<T> : IJsonFormatter<T>
|
||||
where T : struct
|
||||
{
|
||||
public void Serialize(ref JsonWriter writer, T value, IJsonFormatterResolver formatterResolver)
|
||||
{
|
||||
formatterResolver.GetFormatterWithVerify<string>()
|
||||
.Serialize(ref writer, value.ToString(), formatterResolver);
|
||||
}
|
||||
|
||||
public T Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver)
|
||||
{
|
||||
if (reader.ReadIsNull())
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
|
||||
var enumName = formatterResolver.GetFormatterWithVerify<string>()
|
||||
.Deserialize(ref reader, formatterResolver);
|
||||
|
||||
if(Enum.TryParse<T>(enumName, out T result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return default(T);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,6 +11,8 @@ namespace Ryujinx
|
|||
{
|
||||
class Program
|
||||
{
|
||||
public static string ApplicationDirectory => AppDomain.CurrentDomain.BaseDirectory;
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Console.Title = "Ryujinx Console";
|
||||
|
@ -21,9 +23,8 @@ namespace Ryujinx
|
|||
|
||||
Switch device = new Switch(renderer, audioOut);
|
||||
|
||||
Config.Read(device);
|
||||
|
||||
Logger.Updated += Log.LogMessage;
|
||||
Configuration.Load(Path.Combine(ApplicationDirectory, "Config.jsonc"));
|
||||
Configuration.Configure(device);
|
||||
|
||||
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
||||
AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit;
|
||||
|
@ -41,13 +42,13 @@ namespace Ryujinx
|
|||
|
||||
if (romFsFiles.Length > 0)
|
||||
{
|
||||
Console.WriteLine("Loading as cart with RomFS.");
|
||||
Logger.PrintInfo(LogClass.Application, "Loading as cart with RomFS.");
|
||||
|
||||
device.LoadCart(args[0], romFsFiles[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Loading as cart WITHOUT RomFS.");
|
||||
Logger.PrintInfo(LogClass.Application, "Loading as cart WITHOUT RomFS.");
|
||||
|
||||
device.LoadCart(args[0]);
|
||||
}
|
||||
|
@ -57,20 +58,20 @@ namespace Ryujinx
|
|||
switch (Path.GetExtension(args[0]).ToLowerInvariant())
|
||||
{
|
||||
case ".xci":
|
||||
Console.WriteLine("Loading as XCI.");
|
||||
Logger.PrintInfo(LogClass.Application, "Loading as XCI.");
|
||||
device.LoadXci(args[0]);
|
||||
break;
|
||||
case ".nca":
|
||||
Console.WriteLine("Loading as NCA.");
|
||||
Logger.PrintInfo(LogClass.Application, "Loading as NCA.");
|
||||
device.LoadNca(args[0]);
|
||||
break;
|
||||
case ".nsp":
|
||||
case ".pfs0":
|
||||
Console.WriteLine("Loading as NSP.");
|
||||
Logger.PrintInfo(LogClass.Application, "Loading as NSP.");
|
||||
device.LoadNsp(args[0]);
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine("Loading as homebrew.");
|
||||
Logger.PrintInfo(LogClass.Application, "Loading as homebrew.");
|
||||
device.LoadProgram(args[0]);
|
||||
break;
|
||||
}
|
||||
|
@ -78,7 +79,7 @@ namespace Ryujinx
|
|||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Please specify the folder with the NSOs/IStorage or a NSO/NRO.");
|
||||
Logger.PrintInfo(LogClass.Application, "Please specify the folder with the NSOs/IStorage or a NSO/NRO.");
|
||||
}
|
||||
|
||||
using (GlScreen screen = new GlScreen(device, renderer))
|
||||
|
@ -91,11 +92,13 @@ namespace Ryujinx
|
|||
}
|
||||
|
||||
audioOut.Dispose();
|
||||
|
||||
Logger.Shutdown();
|
||||
}
|
||||
|
||||
private static void CurrentDomain_ProcessExit(object sender, EventArgs e)
|
||||
{
|
||||
Log.Close();
|
||||
Logger.Shutdown();
|
||||
}
|
||||
|
||||
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||
|
@ -106,7 +109,7 @@ namespace Ryujinx
|
|||
|
||||
if (e.IsTerminating)
|
||||
{
|
||||
Log.Close();
|
||||
Logger.Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,125 +0,0 @@
|
|||
#Enable cpu memory checks (slow)
|
||||
Enable_Memory_Checks = false
|
||||
|
||||
#Dump shaders in local directory (e.g. `C:\ShaderDumps`)
|
||||
Graphics_Shaders_Dump_Path =
|
||||
|
||||
#Enable print debug logs
|
||||
Logging_Enable_Debug = false
|
||||
|
||||
#Enable print stubbed calls logs
|
||||
Logging_Enable_Stub = true
|
||||
|
||||
#Enable print informations logs
|
||||
Logging_Enable_Info = true
|
||||
|
||||
#Enable print warning logs
|
||||
Logging_Enable_Warn = true
|
||||
|
||||
#Enable print error logs
|
||||
Logging_Enable_Error = true
|
||||
|
||||
#Filtered log classes, seperated by ", ", eg. `Logging_Filtered_Classes = Loader, ServiceFS`
|
||||
Logging_Filtered_Classes =
|
||||
|
||||
#Enable profiling (Only available on a profiling enabled build)
|
||||
Profiling_Enabled = true
|
||||
|
||||
#Set profile file dump location, if blank file dumping disabled. (e.g. `ProfileDump.csv`)
|
||||
Profile_Dump_Path =
|
||||
|
||||
#Update rate for profiler UI, in hertz. -1 updates every time a frame is issued
|
||||
Profiling_Update_Rate = 4
|
||||
|
||||
#Set how long to keep profiling data in seconds, reduce if profiling is taking too much RAM
|
||||
Profiling_History = 5
|
||||
|
||||
#Set the maximum profiling level. Higher values may cause a heavy load on your system but will allow you to profile in more detail.
|
||||
Profiling_Max_Level = 0
|
||||
|
||||
#Enable file logging
|
||||
Enable_File_Log = false
|
||||
|
||||
#System Language list: https://gist.github.com/HorrorTroll/b6e4a88d774c3c9b3bdf54d79a7ca43b
|
||||
#Change System Language
|
||||
System_Language = AmericanEnglish
|
||||
|
||||
#Enable or Disable Docked Mode
|
||||
Docked_Mode = false
|
||||
|
||||
#Enable Game Vsync
|
||||
Enable_Vsync = true
|
||||
|
||||
#Enable or Disable Multi-core scheduling of threads
|
||||
Enable_MultiCore_Scheduling = false
|
||||
|
||||
#Enable integrity checks on Switch content files
|
||||
Enable_FS_Integrity_Checks = true
|
||||
|
||||
#Controller Device Index
|
||||
GamePad_Index = 0
|
||||
|
||||
#Controller Analog Stick Deadzone
|
||||
GamePad_Deadzone = 0.05
|
||||
|
||||
#The value of how pressed down each trigger has to be in order to register a button press
|
||||
GamePad_Trigger_Threshold = 0.5
|
||||
|
||||
#Whether or not to enable Controller support
|
||||
GamePad_Enable = true
|
||||
|
||||
#The primary controller's type. Supported Values: ProController, Handheld, NpadPair, NpadLeft, NpadRight
|
||||
Controller_Type = Handheld
|
||||
|
||||
#https://github.com/opentk/opentk/blob/develop/src/OpenTK/Input/Key.cs
|
||||
Controls_Left_JoyConKeyboard_Stick_Up = 105
|
||||
Controls_Left_JoyConKeyboard_Stick_Down = 101
|
||||
Controls_Left_JoyConKeyboard_Stick_Left = 83
|
||||
Controls_Left_JoyConKeyboard_Stick_Right = 86
|
||||
Controls_Left_JoyConKeyboard_Stick_Button = 88
|
||||
Controls_Left_JoyConKeyboard_DPad_Up = 45
|
||||
Controls_Left_JoyConKeyboard_DPad_Down = 46
|
||||
Controls_Left_JoyConKeyboard_DPad_Left = 47
|
||||
Controls_Left_JoyConKeyboard_DPad_Right = 48
|
||||
Controls_Left_JoyConKeyboard_Button_Minus = 120
|
||||
Controls_Left_JoyConKeyboard_Button_L = 87
|
||||
Controls_Left_JoyConKeyboard_Button_ZL = 99
|
||||
|
||||
Controls_Right_JoyConKeyboard_Stick_Up = 91
|
||||
Controls_Right_JoyConKeyboard_Stick_Down = 93
|
||||
Controls_Right_JoyConKeyboard_Stick_Left = 92
|
||||
Controls_Right_JoyConKeyboard_Stick_Right = 94
|
||||
Controls_Right_JoyConKeyboard_Stick_Button = 90
|
||||
Controls_Right_JoyConKeyboard_Button_A = 108
|
||||
Controls_Right_JoyConKeyboard_Button_B = 106
|
||||
Controls_Right_JoyConKeyboard_Button_X = 85
|
||||
Controls_Right_JoyConKeyboard_Button_Y = 104
|
||||
Controls_Right_JoyConKeyboard_Button_Plus = 121
|
||||
Controls_Right_JoyConKeyboard_Button_R = 103
|
||||
Controls_Right_JoyConKeyboard_Button_ZR = 97
|
||||
|
||||
#Controller Controls
|
||||
|
||||
Controls_Left_JoyConController_Stick_Button = LStick
|
||||
Controls_Left_JoyConController_DPad_Up = DPadUp
|
||||
Controls_Left_JoyConController_DPad_Down = DPadDown
|
||||
Controls_Left_JoyConController_DPad_Left = DPadLeft
|
||||
Controls_Left_JoyConController_DPad_Right = DPadRight
|
||||
Controls_Left_JoyConController_Button_Minus = Back
|
||||
Controls_Left_JoyConController_Button_L = LShoulder
|
||||
Controls_Left_JoyConController_Button_ZL = LTrigger
|
||||
|
||||
Controls_Right_JoyConController_Stick_Button = RStick
|
||||
Controls_Right_JoyConController_Button_A = B
|
||||
Controls_Right_JoyConController_Button_B = A
|
||||
Controls_Right_JoyConController_Button_X = Y
|
||||
Controls_Right_JoyConController_Button_Y = X
|
||||
Controls_Right_JoyConController_Button_Plus = Start
|
||||
Controls_Right_JoyConController_Button_R = RShoulder
|
||||
Controls_Right_JoyConController_Button_ZR = RTrigger
|
||||
|
||||
Controls_Left_JoyConController_Stick = LJoystick
|
||||
Controls_Right_JoyConController_Stick = RJoystick
|
||||
|
||||
#Debug Controls
|
||||
Controls_Debug_Toggle_Profiler = 10
|
|
@ -32,7 +32,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Ryujinx.conf">
|
||||
<None Update="Config.jsonc">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
|
|
@ -163,24 +163,24 @@ namespace Ryujinx
|
|||
#endif
|
||||
|
||||
// Normal Input
|
||||
currentButton = Config.NpadKeyboard.GetButtons(keyboard);
|
||||
currentButton = Configuration.Instance.KeyboardControls.GetButtons(keyboard);
|
||||
|
||||
(leftJoystickDx, leftJoystickDy) = Config.NpadKeyboard.GetLeftStick(keyboard);
|
||||
(leftJoystickDx, leftJoystickDy) = Configuration.Instance.KeyboardControls.GetLeftStick(keyboard);
|
||||
|
||||
(rightJoystickDx, rightJoystickDy) = Config.NpadKeyboard.GetRightStick(keyboard);
|
||||
(rightJoystickDx, rightJoystickDy) = Configuration.Instance.KeyboardControls.GetRightStick(keyboard);
|
||||
}
|
||||
|
||||
currentButton |= Config.NpadController.GetButtons();
|
||||
currentButton |= Configuration.Instance.GamepadControls.GetButtons();
|
||||
|
||||
//Keyboard has priority stick-wise
|
||||
if (leftJoystickDx == 0 && leftJoystickDy == 0)
|
||||
{
|
||||
(leftJoystickDx, leftJoystickDy) = Config.NpadController.GetLeftStick();
|
||||
(leftJoystickDx, leftJoystickDy) = Configuration.Instance.GamepadControls.GetLeftStick();
|
||||
}
|
||||
|
||||
if (rightJoystickDx == 0 && rightJoystickDy == 0)
|
||||
{
|
||||
(rightJoystickDx, rightJoystickDy) = Config.NpadController.GetRightStick();
|
||||
(rightJoystickDx, rightJoystickDy) = Configuration.Instance.GamepadControls.GetRightStick();
|
||||
}
|
||||
|
||||
leftJoystick = new HidJoystickPosition
|
||||
|
|
|
@ -1,140 +0,0 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx
|
||||
{
|
||||
static class Log
|
||||
{
|
||||
private static readonly string _path;
|
||||
|
||||
private static StreamWriter _logWriter;
|
||||
|
||||
private static Thread _messageThread;
|
||||
|
||||
private static BlockingCollection<LogEventArgs> _messageQueue;
|
||||
|
||||
private static Dictionary<LogLevel, ConsoleColor> _logColors;
|
||||
|
||||
static Log()
|
||||
{
|
||||
_logColors = new Dictionary<LogLevel, ConsoleColor>()
|
||||
{
|
||||
{ LogLevel.Stub, ConsoleColor.DarkGray },
|
||||
{ LogLevel.Info, ConsoleColor.White },
|
||||
{ LogLevel.Warning, ConsoleColor.Yellow },
|
||||
{ LogLevel.Error, ConsoleColor.Red }
|
||||
};
|
||||
|
||||
_messageQueue = new BlockingCollection<LogEventArgs>(10);
|
||||
|
||||
_messageThread = new Thread(() =>
|
||||
{
|
||||
while (!_messageQueue.IsCompleted)
|
||||
{
|
||||
try
|
||||
{
|
||||
PrintLog(_messageQueue.Take());
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
// IOE means that Take() was called on a completed collection.
|
||||
// Some other thread can call CompleteAdding after we pass the
|
||||
// IsCompleted check but before we call Take.
|
||||
// We can simply catch the exception since the loop will break
|
||||
// on the next iteration.
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
_path = Path.Combine(Environment.CurrentDirectory, "Ryujinx.log");
|
||||
|
||||
if (Logger.EnableFileLog)
|
||||
{
|
||||
_logWriter = new StreamWriter(File.Open(_path,FileMode.Create, FileAccess.Write));
|
||||
}
|
||||
|
||||
_messageThread.IsBackground = true;
|
||||
_messageThread.Start();
|
||||
}
|
||||
|
||||
private static void PrintLog(LogEventArgs e)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.AppendFormat(@"{0:hh\:mm\:ss\.fff}", e.Time);
|
||||
sb.Append(" | ");
|
||||
sb.AppendFormat("{0:d4}", e.ThreadId);
|
||||
sb.Append(' ');
|
||||
sb.Append(e.Message);
|
||||
|
||||
if (e.Data != null)
|
||||
{
|
||||
PropertyInfo[] props = e.Data.GetType().GetProperties();
|
||||
|
||||
sb.Append(' ');
|
||||
|
||||
foreach (var prop in props)
|
||||
{
|
||||
sb.Append(prop.Name);
|
||||
sb.Append(": ");
|
||||
sb.Append(prop.GetValue(e.Data));
|
||||
sb.Append(" - ");
|
||||
}
|
||||
|
||||
// We remove the final '-' from the string
|
||||
if (props.Length > 0)
|
||||
{
|
||||
sb.Remove(sb.Length - 3, 3);
|
||||
}
|
||||
}
|
||||
|
||||
string message = sb.ToString();
|
||||
|
||||
if (_logColors.TryGetValue(e.Level, out ConsoleColor color))
|
||||
{
|
||||
Console.ForegroundColor = color;
|
||||
|
||||
Console.WriteLine(message);
|
||||
|
||||
Console.ResetColor();
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine(message);
|
||||
}
|
||||
|
||||
if (Logger.EnableFileLog)
|
||||
{
|
||||
_logWriter.WriteLine(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void LogMessage(object sender, LogEventArgs e)
|
||||
{
|
||||
if (!_messageQueue.IsAddingCompleted)
|
||||
{
|
||||
_messageQueue.Add(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Close()
|
||||
{
|
||||
_messageQueue.CompleteAdding();
|
||||
|
||||
_messageThread.Join();
|
||||
|
||||
if (Logger.EnableFileLog)
|
||||
{
|
||||
_logWriter.Flush();
|
||||
_logWriter.Close();
|
||||
_logWriter.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,28 +8,24 @@ namespace Ryujinx.UI.Input
|
|||
public enum ControllerInputId
|
||||
{
|
||||
Invalid,
|
||||
|
||||
LStick,
|
||||
RStick,
|
||||
LShoulder,
|
||||
RShoulder,
|
||||
LTrigger,
|
||||
RTrigger,
|
||||
LJoystick,
|
||||
RJoystick,
|
||||
DPadUp,
|
||||
DPadDown,
|
||||
DPadLeft,
|
||||
DPadRight,
|
||||
Start,
|
||||
Back,
|
||||
LShoulder,
|
||||
|
||||
RStick,
|
||||
A,
|
||||
B,
|
||||
X,
|
||||
Y,
|
||||
Start,
|
||||
RShoulder,
|
||||
|
||||
LTrigger,
|
||||
RTrigger,
|
||||
|
||||
LJoystick,
|
||||
RJoystick
|
||||
Y
|
||||
}
|
||||
|
||||
public struct NpadControllerLeft
|
||||
|
@ -60,34 +56,55 @@ namespace Ryujinx.UI.Input
|
|||
|
||||
public class NpadController
|
||||
{
|
||||
public bool Enabled { private set; get; }
|
||||
public int Index { private set; get; }
|
||||
public float Deadzone { private set; get; }
|
||||
public float TriggerThreshold { private set; get; }
|
||||
/// <summary>
|
||||
/// Enables or disables controller support
|
||||
/// </summary>
|
||||
public bool Enabled { get; private set; }
|
||||
|
||||
public NpadControllerLeft Left { private set; get; }
|
||||
public NpadControllerRight Right { private set; get; }
|
||||
/// <summary>
|
||||
/// Controller Device Index
|
||||
/// </summary>
|
||||
public int Index { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Controller Analog Stick Deadzone
|
||||
/// </summary>
|
||||
public float Deadzone { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Controller Trigger Threshold
|
||||
/// </summary>
|
||||
public float TriggerThreshold { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Left JoyCon Controller Bindings
|
||||
/// </summary>
|
||||
public NpadControllerLeft LeftJoycon { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Right JoyCon Controller Bindings
|
||||
/// </summary>
|
||||
public NpadControllerRight RightJoycon { get; private set; }
|
||||
|
||||
public NpadController(
|
||||
bool enabled,
|
||||
int index,
|
||||
float deadzone,
|
||||
float triggerThreshold,
|
||||
NpadControllerLeft left,
|
||||
NpadControllerRight right)
|
||||
bool enabled,
|
||||
int index,
|
||||
float deadzone,
|
||||
float triggerThreshold,
|
||||
NpadControllerLeft leftJoycon,
|
||||
NpadControllerRight rightJoycon)
|
||||
{
|
||||
Enabled = enabled;
|
||||
Index = index;
|
||||
Deadzone = deadzone;
|
||||
TriggerThreshold = triggerThreshold;
|
||||
Left = left;
|
||||
Right = right;
|
||||
LeftJoycon = leftJoycon;
|
||||
RightJoycon = rightJoycon;
|
||||
}
|
||||
|
||||
//Unmapped controllers are problematic, skip them
|
||||
if (GamePad.GetName(index) == "Unmapped Controller")
|
||||
{
|
||||
Enabled = false;
|
||||
}
|
||||
public void SetEnabled(bool enabled)
|
||||
{
|
||||
Enabled = enabled;
|
||||
}
|
||||
|
||||
public HidControllerButtons GetButtons()
|
||||
|
@ -101,23 +118,23 @@ namespace Ryujinx.UI.Input
|
|||
|
||||
HidControllerButtons buttons = 0;
|
||||
|
||||
if (IsPressed(gpState, Left.DPadUp)) buttons |= HidControllerButtons.DpadUp;
|
||||
if (IsPressed(gpState, Left.DPadDown)) buttons |= HidControllerButtons.DpadDown;
|
||||
if (IsPressed(gpState, Left.DPadLeft)) buttons |= HidControllerButtons.DpadLeft;
|
||||
if (IsPressed(gpState, Left.DPadRight)) buttons |= HidControllerButtons.DPadRight;
|
||||
if (IsPressed(gpState, Left.StickButton)) buttons |= HidControllerButtons.StickLeft;
|
||||
if (IsPressed(gpState, Left.ButtonMinus)) buttons |= HidControllerButtons.Minus;
|
||||
if (IsPressed(gpState, Left.ButtonL)) buttons |= HidControllerButtons.L;
|
||||
if (IsPressed(gpState, Left.ButtonZl)) buttons |= HidControllerButtons.Zl;
|
||||
if (IsPressed(gpState, LeftJoycon.DPadUp)) buttons |= HidControllerButtons.DpadUp;
|
||||
if (IsPressed(gpState, LeftJoycon.DPadDown)) buttons |= HidControllerButtons.DpadDown;
|
||||
if (IsPressed(gpState, LeftJoycon.DPadLeft)) buttons |= HidControllerButtons.DpadLeft;
|
||||
if (IsPressed(gpState, LeftJoycon.DPadRight)) buttons |= HidControllerButtons.DPadRight;
|
||||
if (IsPressed(gpState, LeftJoycon.StickButton)) buttons |= HidControllerButtons.StickLeft;
|
||||
if (IsPressed(gpState, LeftJoycon.ButtonMinus)) buttons |= HidControllerButtons.Minus;
|
||||
if (IsPressed(gpState, LeftJoycon.ButtonL)) buttons |= HidControllerButtons.L;
|
||||
if (IsPressed(gpState, LeftJoycon.ButtonZl)) buttons |= HidControllerButtons.Zl;
|
||||
|
||||
if (IsPressed(gpState, Right.ButtonA)) buttons |= HidControllerButtons.A;
|
||||
if (IsPressed(gpState, Right.ButtonB)) buttons |= HidControllerButtons.B;
|
||||
if (IsPressed(gpState, Right.ButtonX)) buttons |= HidControllerButtons.X;
|
||||
if (IsPressed(gpState, Right.ButtonY)) buttons |= HidControllerButtons.Y;
|
||||
if (IsPressed(gpState, Right.StickButton)) buttons |= HidControllerButtons.StickRight;
|
||||
if (IsPressed(gpState, Right.ButtonPlus)) buttons |= HidControllerButtons.Plus;
|
||||
if (IsPressed(gpState, Right.ButtonR)) buttons |= HidControllerButtons.R;
|
||||
if (IsPressed(gpState, Right.ButtonZr)) buttons |= HidControllerButtons.Zr;
|
||||
if (IsPressed(gpState, RightJoycon.ButtonA)) buttons |= HidControllerButtons.A;
|
||||
if (IsPressed(gpState, RightJoycon.ButtonB)) buttons |= HidControllerButtons.B;
|
||||
if (IsPressed(gpState, RightJoycon.ButtonX)) buttons |= HidControllerButtons.X;
|
||||
if (IsPressed(gpState, RightJoycon.ButtonY)) buttons |= HidControllerButtons.Y;
|
||||
if (IsPressed(gpState, RightJoycon.StickButton)) buttons |= HidControllerButtons.StickRight;
|
||||
if (IsPressed(gpState, RightJoycon.ButtonPlus)) buttons |= HidControllerButtons.Plus;
|
||||
if (IsPressed(gpState, RightJoycon.ButtonR)) buttons |= HidControllerButtons.R;
|
||||
if (IsPressed(gpState, RightJoycon.ButtonZr)) buttons |= HidControllerButtons.Zr;
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
@ -129,7 +146,7 @@ namespace Ryujinx.UI.Input
|
|||
return (0, 0);
|
||||
}
|
||||
|
||||
return GetStick(Left.Stick);
|
||||
return GetStick(LeftJoycon.Stick);
|
||||
}
|
||||
|
||||
public (short, short) GetRightStick()
|
||||
|
@ -139,7 +156,7 @@ namespace Ryujinx.UI.Input
|
|||
return (0, 0);
|
||||
}
|
||||
|
||||
return GetStick(Right.Stick);
|
||||
return GetStick(RightJoycon.Stick);
|
||||
}
|
||||
|
||||
private (short, short) GetStick(ControllerInputId joystick)
|
||||
|
|
|
@ -5,70 +5,69 @@ namespace Ryujinx.UI.Input
|
|||
{
|
||||
public struct NpadKeyboardLeft
|
||||
{
|
||||
public int StickUp;
|
||||
public int StickDown;
|
||||
public int StickLeft;
|
||||
public int StickRight;
|
||||
public int StickButton;
|
||||
public int DPadUp;
|
||||
public int DPadDown;
|
||||
public int DPadLeft;
|
||||
public int DPadRight;
|
||||
public int ButtonMinus;
|
||||
public int ButtonL;
|
||||
public int ButtonZl;
|
||||
public Key StickUp;
|
||||
public Key StickDown;
|
||||
public Key StickLeft;
|
||||
public Key StickRight;
|
||||
public Key StickButton;
|
||||
public Key DPadUp;
|
||||
public Key DPadDown;
|
||||
public Key DPadLeft;
|
||||
public Key DPadRight;
|
||||
public Key ButtonMinus;
|
||||
public Key ButtonL;
|
||||
public Key ButtonZl;
|
||||
}
|
||||
|
||||
public struct NpadKeyboardRight
|
||||
{
|
||||
public int StickUp;
|
||||
public int StickDown;
|
||||
public int StickLeft;
|
||||
public int StickRight;
|
||||
public int StickButton;
|
||||
public int ButtonA;
|
||||
public int ButtonB;
|
||||
public int ButtonX;
|
||||
public int ButtonY;
|
||||
public int ButtonPlus;
|
||||
public int ButtonR;
|
||||
public int ButtonZr;
|
||||
public Key StickUp;
|
||||
public Key StickDown;
|
||||
public Key StickLeft;
|
||||
public Key StickRight;
|
||||
public Key StickButton;
|
||||
public Key ButtonA;
|
||||
public Key ButtonB;
|
||||
public Key ButtonX;
|
||||
public Key ButtonY;
|
||||
public Key ButtonPlus;
|
||||
public Key ButtonR;
|
||||
public Key ButtonZr;
|
||||
}
|
||||
|
||||
public class NpadKeyboard
|
||||
{
|
||||
public NpadKeyboardLeft Left;
|
||||
public NpadKeyboardRight Right;
|
||||
/// <summary>
|
||||
/// Left JoyCon Keyboard Bindings
|
||||
/// </summary>
|
||||
public NpadKeyboardLeft LeftJoycon { get; private set; }
|
||||
|
||||
public NpadKeyboard(
|
||||
NpadKeyboardLeft left,
|
||||
NpadKeyboardRight right)
|
||||
{
|
||||
Left = left;
|
||||
Right = right;
|
||||
}
|
||||
/// <summary>
|
||||
/// Right JoyCon Keyboard Bindings
|
||||
/// </summary>
|
||||
public NpadKeyboardRight RightJoycon { get; private set; }
|
||||
|
||||
public HidControllerButtons GetButtons(KeyboardState keyboard)
|
||||
{
|
||||
HidControllerButtons buttons = 0;
|
||||
|
||||
if (keyboard[(Key)Left.StickButton]) buttons |= HidControllerButtons.StickLeft;
|
||||
if (keyboard[(Key)Left.DPadUp]) buttons |= HidControllerButtons.DpadUp;
|
||||
if (keyboard[(Key)Left.DPadDown]) buttons |= HidControllerButtons.DpadDown;
|
||||
if (keyboard[(Key)Left.DPadLeft]) buttons |= HidControllerButtons.DpadLeft;
|
||||
if (keyboard[(Key)Left.DPadRight]) buttons |= HidControllerButtons.DPadRight;
|
||||
if (keyboard[(Key)Left.ButtonMinus]) buttons |= HidControllerButtons.Minus;
|
||||
if (keyboard[(Key)Left.ButtonL]) buttons |= HidControllerButtons.L;
|
||||
if (keyboard[(Key)Left.ButtonZl]) buttons |= HidControllerButtons.Zl;
|
||||
if (keyboard[(Key)LeftJoycon.StickButton]) buttons |= HidControllerButtons.StickLeft;
|
||||
if (keyboard[(Key)LeftJoycon.DPadUp]) buttons |= HidControllerButtons.DpadUp;
|
||||
if (keyboard[(Key)LeftJoycon.DPadDown]) buttons |= HidControllerButtons.DpadDown;
|
||||
if (keyboard[(Key)LeftJoycon.DPadLeft]) buttons |= HidControllerButtons.DpadLeft;
|
||||
if (keyboard[(Key)LeftJoycon.DPadRight]) buttons |= HidControllerButtons.DPadRight;
|
||||
if (keyboard[(Key)LeftJoycon.ButtonMinus]) buttons |= HidControllerButtons.Minus;
|
||||
if (keyboard[(Key)LeftJoycon.ButtonL]) buttons |= HidControllerButtons.L;
|
||||
if (keyboard[(Key)LeftJoycon.ButtonZl]) buttons |= HidControllerButtons.Zl;
|
||||
|
||||
if (keyboard[(Key)Right.StickButton]) buttons |= HidControllerButtons.StickRight;
|
||||
if (keyboard[(Key)Right.ButtonA]) buttons |= HidControllerButtons.A;
|
||||
if (keyboard[(Key)Right.ButtonB]) buttons |= HidControllerButtons.B;
|
||||
if (keyboard[(Key)Right.ButtonX]) buttons |= HidControllerButtons.X;
|
||||
if (keyboard[(Key)Right.ButtonY]) buttons |= HidControllerButtons.Y;
|
||||
if (keyboard[(Key)Right.ButtonPlus]) buttons |= HidControllerButtons.Plus;
|
||||
if (keyboard[(Key)Right.ButtonR]) buttons |= HidControllerButtons.R;
|
||||
if (keyboard[(Key)Right.ButtonZr]) buttons |= HidControllerButtons.Zr;
|
||||
if (keyboard[(Key)RightJoycon.StickButton]) buttons |= HidControllerButtons.StickRight;
|
||||
if (keyboard[(Key)RightJoycon.ButtonA]) buttons |= HidControllerButtons.A;
|
||||
if (keyboard[(Key)RightJoycon.ButtonB]) buttons |= HidControllerButtons.B;
|
||||
if (keyboard[(Key)RightJoycon.ButtonX]) buttons |= HidControllerButtons.X;
|
||||
if (keyboard[(Key)RightJoycon.ButtonY]) buttons |= HidControllerButtons.Y;
|
||||
if (keyboard[(Key)RightJoycon.ButtonPlus]) buttons |= HidControllerButtons.Plus;
|
||||
if (keyboard[(Key)RightJoycon.ButtonR]) buttons |= HidControllerButtons.R;
|
||||
if (keyboard[(Key)RightJoycon.ButtonZr]) buttons |= HidControllerButtons.Zr;
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
@ -78,10 +77,10 @@ namespace Ryujinx.UI.Input
|
|||
short dx = 0;
|
||||
short dy = 0;
|
||||
|
||||
if (keyboard[(Key)Left.StickUp]) dy = short.MaxValue;
|
||||
if (keyboard[(Key)Left.StickDown]) dy = -short.MaxValue;
|
||||
if (keyboard[(Key)Left.StickLeft]) dx = -short.MaxValue;
|
||||
if (keyboard[(Key)Left.StickRight]) dx = short.MaxValue;
|
||||
if (keyboard[(Key)LeftJoycon.StickUp]) dy = short.MaxValue;
|
||||
if (keyboard[(Key)LeftJoycon.StickDown]) dy = -short.MaxValue;
|
||||
if (keyboard[(Key)LeftJoycon.StickLeft]) dx = -short.MaxValue;
|
||||
if (keyboard[(Key)LeftJoycon.StickRight]) dx = short.MaxValue;
|
||||
|
||||
return (dx, dy);
|
||||
}
|
||||
|
@ -91,10 +90,10 @@ namespace Ryujinx.UI.Input
|
|||
short dx = 0;
|
||||
short dy = 0;
|
||||
|
||||
if (keyboard[(Key)Right.StickUp]) dy = short.MaxValue;
|
||||
if (keyboard[(Key)Right.StickDown]) dy = -short.MaxValue;
|
||||
if (keyboard[(Key)Right.StickLeft]) dx = -short.MaxValue;
|
||||
if (keyboard[(Key)Right.StickRight]) dx = short.MaxValue;
|
||||
if (keyboard[(Key)RightJoycon.StickUp]) dy = short.MaxValue;
|
||||
if (keyboard[(Key)RightJoycon.StickDown]) dy = -short.MaxValue;
|
||||
if (keyboard[(Key)RightJoycon.StickLeft]) dx = -short.MaxValue;
|
||||
if (keyboard[(Key)RightJoycon.StickRight]) dx = short.MaxValue;
|
||||
|
||||
return (dx, dy);
|
||||
}
|
||||
|
|
823
Ryujinx/_schema.json
Normal file
823
Ryujinx/_schema.json
Normal file
|
@ -0,0 +1,823 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://ryujinx.org/_schema/config.json",
|
||||
"type": "object",
|
||||
"title": "Ryujinx Configuration Schema",
|
||||
"required": [
|
||||
"graphics_shaders_dump_path",
|
||||
"logging_enable_debug",
|
||||
"logging_enable_stub",
|
||||
"logging_enable_info",
|
||||
"logging_enable_warn",
|
||||
"logging_enable_error",
|
||||
"logging_filtered_classes",
|
||||
"enable_file_log",
|
||||
"system_language",
|
||||
"docked_mode",
|
||||
"enable_vsync",
|
||||
"enable_multicore_scheduling",
|
||||
"enable_fs_integrity_checks",
|
||||
"controller_type",
|
||||
"keyboard_controls",
|
||||
"gamepad_controls"
|
||||
],
|
||||
"definitions": {
|
||||
"key": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"ShiftLeft",
|
||||
"LShift",
|
||||
"ShiftRight",
|
||||
"RShift",
|
||||
"ControlLeft",
|
||||
"LControl",
|
||||
"ControlRight",
|
||||
"RControl",
|
||||
"AltLeft",
|
||||
"LAlt",
|
||||
"AltRight",
|
||||
"RAlt",
|
||||
"WinLeft",
|
||||
"LWin",
|
||||
"WinRight",
|
||||
"RWin",
|
||||
"Menu",
|
||||
"F1",
|
||||
"F2",
|
||||
"F3",
|
||||
"F4",
|
||||
"F5",
|
||||
"F6",
|
||||
"F7",
|
||||
"F8",
|
||||
"F9",
|
||||
"F10",
|
||||
"F11",
|
||||
"F12",
|
||||
"F13",
|
||||
"F14",
|
||||
"F15",
|
||||
"F16",
|
||||
"F17",
|
||||
"F18",
|
||||
"F19",
|
||||
"F20",
|
||||
"F21",
|
||||
"F22",
|
||||
"F23",
|
||||
"F24",
|
||||
"F25",
|
||||
"F26",
|
||||
"F27",
|
||||
"F28",
|
||||
"F29",
|
||||
"F30",
|
||||
"F31",
|
||||
"F32",
|
||||
"F33",
|
||||
"F34",
|
||||
"F35",
|
||||
"Up",
|
||||
"Down",
|
||||
"Left",
|
||||
"Right",
|
||||
"Enter",
|
||||
"Escape",
|
||||
"Space",
|
||||
"Tab",
|
||||
"BackSpace",
|
||||
"Back",
|
||||
"Insert",
|
||||
"Delete",
|
||||
"PageUp",
|
||||
"PageDown",
|
||||
"Home",
|
||||
"End",
|
||||
"CapsLock",
|
||||
"ScrollLock",
|
||||
"PrintScreen",
|
||||
"Pause",
|
||||
"NumLock",
|
||||
"Clear",
|
||||
"Sleep",
|
||||
"Keypad0",
|
||||
"Keypad1",
|
||||
"Keypad2",
|
||||
"Keypad3",
|
||||
"Keypad4",
|
||||
"Keypad5",
|
||||
"Keypad6",
|
||||
"Keypad7",
|
||||
"Keypad8",
|
||||
"Keypad9",
|
||||
"KeypadDivide",
|
||||
"KeypadMultiply",
|
||||
"KeypadSubtract",
|
||||
"KeypadMinus",
|
||||
"KeypadAdd",
|
||||
"KeypadPlus",
|
||||
"KeypadDecimal",
|
||||
"KeypadPeriod",
|
||||
"KeypadEnter",
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"E",
|
||||
"F",
|
||||
"G",
|
||||
"H",
|
||||
"I",
|
||||
"J",
|
||||
"K",
|
||||
"L",
|
||||
"M",
|
||||
"N",
|
||||
"O",
|
||||
"P",
|
||||
"Q",
|
||||
"R",
|
||||
"S",
|
||||
"T",
|
||||
"U",
|
||||
"V",
|
||||
"W",
|
||||
"X",
|
||||
"Y",
|
||||
"Z",
|
||||
"Number0",
|
||||
"Number1",
|
||||
"Number2",
|
||||
"Number3",
|
||||
"Number4",
|
||||
"Number5",
|
||||
"Number6",
|
||||
"Number7",
|
||||
"Number8",
|
||||
"Number9",
|
||||
"Tilde",
|
||||
"Grave",
|
||||
"Minus",
|
||||
"Plus",
|
||||
"BracketLeft",
|
||||
"LBracket",
|
||||
"BracketRight",
|
||||
"RBracket",
|
||||
"Semicolon",
|
||||
"Quote",
|
||||
"Comma",
|
||||
"Period",
|
||||
"Slash",
|
||||
"BackSlash",
|
||||
"NonUSBackSlash",
|
||||
"LastKey"
|
||||
]
|
||||
},
|
||||
"input": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"DPadUp",
|
||||
"DPadDown",
|
||||
"DPadLeft",
|
||||
"DPadRight",
|
||||
"LStick",
|
||||
"RStick",
|
||||
"LShoulder",
|
||||
"RShoulder",
|
||||
"LTrigger",
|
||||
"RTrigger",
|
||||
"LJoystick",
|
||||
"RJoystick",
|
||||
"A",
|
||||
"B",
|
||||
"X",
|
||||
"Y",
|
||||
"Start",
|
||||
"Back"
|
||||
]
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"graphics_shaders_dump_path": {
|
||||
"$id": "#/properties/graphics_shaders_dump_path",
|
||||
"type": "string",
|
||||
"title": "Graphics Shaders Dump Path",
|
||||
"description": "Dumps shaders in this local directory",
|
||||
"default": "",
|
||||
"examples": [
|
||||
"C:\\ShaderDumps"
|
||||
]
|
||||
},
|
||||
"logging_enable_debug": {
|
||||
"$id": "#/properties/logging_enable_debug",
|
||||
"type": "boolean",
|
||||
"title": "Logging Enable Debug",
|
||||
"description": "Enables printing debug log messages",
|
||||
"default": false,
|
||||
"examples": [
|
||||
true,
|
||||
false
|
||||
]
|
||||
},
|
||||
"logging_enable_stub": {
|
||||
"$id": "#/properties/logging_enable_stub",
|
||||
"type": "boolean",
|
||||
"title": "Logging Enable Stub",
|
||||
"description": "Enables printing stub log messages",
|
||||
"default": true,
|
||||
"examples": [
|
||||
true,
|
||||
false
|
||||
]
|
||||
},
|
||||
"logging_enable_info": {
|
||||
"$id": "#/properties/logging_enable_info",
|
||||
"type": "boolean",
|
||||
"title": "Logging Enable Info",
|
||||
"description": "Enables printing info log messages",
|
||||
"default": true,
|
||||
"examples": [
|
||||
true,
|
||||
false
|
||||
]
|
||||
},
|
||||
"logging_enable_warn": {
|
||||
"$id": "#/properties/logging_enable_warn",
|
||||
"type": "boolean",
|
||||
"title": "Logging Enable Warn",
|
||||
"description": "Enables printing warning log messages",
|
||||
"default": true,
|
||||
"examples": [
|
||||
true,
|
||||
false
|
||||
]
|
||||
},
|
||||
"logging_enable_error": {
|
||||
"$id": "#/properties/logging_enable_error",
|
||||
"type": "boolean",
|
||||
"title": "Logging Enable Error",
|
||||
"description": "Enables printing error log messages",
|
||||
"default": true,
|
||||
"examples": [
|
||||
true,
|
||||
false
|
||||
]
|
||||
},
|
||||
"logging_filtered_classes": {
|
||||
"$id": "#/properties/logging_filtered_classes",
|
||||
"type": "array",
|
||||
"title": "Logging Filtered Classes",
|
||||
"description": "Controls which log messages are written to the log targets",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Application",
|
||||
"Audio",
|
||||
"Cpu",
|
||||
"Font",
|
||||
"Emulation",
|
||||
"Gpu",
|
||||
"Hid",
|
||||
"Kernel",
|
||||
"KernelIpc",
|
||||
"KernelScheduler",
|
||||
"KernelSvc",
|
||||
"Loader",
|
||||
"Service",
|
||||
"ServiceAcc",
|
||||
"ServiceAm",
|
||||
"ServiceApm",
|
||||
"ServiceAudio",
|
||||
"ServiceBsd",
|
||||
"ServiceCaps",
|
||||
"ServiceFriend",
|
||||
"ServiceFs",
|
||||
"ServiceHid",
|
||||
"ServiceIrs",
|
||||
"ServiceLdr",
|
||||
"ServiceLm",
|
||||
"ServiceMm",
|
||||
"ServiceNfp",
|
||||
"ServiceNifm",
|
||||
"ServiceNs",
|
||||
"ServiceNv",
|
||||
"ServicePctl",
|
||||
"ServicePl",
|
||||
"ServicePrepo",
|
||||
"ServicePsm",
|
||||
"ServiceSet",
|
||||
"ServiceSfdnsres",
|
||||
"ServiceSm",
|
||||
"ServiceSsl",
|
||||
"ServiceSss",
|
||||
"ServiceTime",
|
||||
"ServiceVi"
|
||||
]
|
||||
}
|
||||
},
|
||||
"enable_file_log": {
|
||||
"$id": "#/properties/enable_file_log",
|
||||
"type": "boolean",
|
||||
"title": "Enable File Log",
|
||||
"description": "Enables logging to a file on disk",
|
||||
"default": true,
|
||||
"examples": [
|
||||
true,
|
||||
false
|
||||
]
|
||||
},
|
||||
"system_language": {
|
||||
"$id": "#/properties/system_language",
|
||||
"type": "string",
|
||||
"title": "System Language",
|
||||
"description": "Change System Language",
|
||||
"default": "AmericanEnglish",
|
||||
"enum": [
|
||||
"Japanese",
|
||||
"AmericanEnglish",
|
||||
"French",
|
||||
"German",
|
||||
"Italian",
|
||||
"Spanish",
|
||||
"Chinese",
|
||||
"Korean",
|
||||
"Dutch",
|
||||
"Portuguese",
|
||||
"Russian",
|
||||
"Taiwanese",
|
||||
"BritishEnglish",
|
||||
"CanadianFrench",
|
||||
"LatinAmericanSpanish",
|
||||
"SimplifiedChinese",
|
||||
"TraditionalChinese"
|
||||
],
|
||||
"examples": [
|
||||
"AmericanEnglish"
|
||||
]
|
||||
},
|
||||
"docked_mode": {
|
||||
"$id": "#/properties/docked_mode",
|
||||
"type": "boolean",
|
||||
"title": "Enable Docked Mode",
|
||||
"description": "Enables or disables Docked Mode",
|
||||
"default": false,
|
||||
"examples": [
|
||||
true,
|
||||
false
|
||||
]
|
||||
},
|
||||
"enable_vsync": {
|
||||
"$id": "#/properties/enable_vsync",
|
||||
"type": "boolean",
|
||||
"title": "Enable Vertical Sync",
|
||||
"description": "Enables or disables Vertical Sync",
|
||||
"default": true,
|
||||
"examples": [
|
||||
true,
|
||||
false
|
||||
]
|
||||
},
|
||||
"enable_multicore_scheduling": {
|
||||
"$id": "#/properties/enable_multicore_scheduling",
|
||||
"type": "boolean",
|
||||
"title": "Enable Multicore Scheduling",
|
||||
"description": "Enables or disables multi-core scheduling of threads",
|
||||
"default": false,
|
||||
"examples": [
|
||||
true,
|
||||
false
|
||||
]
|
||||
},
|
||||
"enable_fs_integrity_checks": {
|
||||
"$id": "#/properties/enable_fs_integrity_checks",
|
||||
"type": "boolean",
|
||||
"title": "Enable Filesystem Integrity Checks",
|
||||
"description": "Enables integrity checks on Game content files. Only applies to ROMs loaded as XCI files",
|
||||
"default": true,
|
||||
"examples": [
|
||||
true,
|
||||
false
|
||||
]
|
||||
},
|
||||
"controller_type": {
|
||||
"$id": "#/properties/controller_type",
|
||||
"type": "string",
|
||||
"title": "Controller Type",
|
||||
"default": "Handheld",
|
||||
"enum": [
|
||||
"Handheld",
|
||||
"ProController",
|
||||
"NpadPair",
|
||||
"NpadLeft",
|
||||
"NpadRight"
|
||||
],
|
||||
"examples": [
|
||||
"Handheld",
|
||||
"ProController",
|
||||
"NpadPair",
|
||||
"NpadLeft",
|
||||
"NpadRight"
|
||||
]
|
||||
},
|
||||
"keyboard_controls": {
|
||||
"$id": "#/properties/keyboard_controls",
|
||||
"type": "object",
|
||||
"title": "Keyboard Controls",
|
||||
"required": [
|
||||
"left_joycon",
|
||||
"right_joycon"
|
||||
],
|
||||
"properties": {
|
||||
"left_joycon": {
|
||||
"$id": "#/properties/keyboard_controls/properties/left_joycon",
|
||||
"type": "object",
|
||||
"title": "Left JoyCon Controls",
|
||||
"required": [
|
||||
"stick_up",
|
||||
"stick_down",
|
||||
"stick_left",
|
||||
"stick_right",
|
||||
"stick_button",
|
||||
"dpad_up",
|
||||
"dpad_down",
|
||||
"dpad_left",
|
||||
"dpad_right",
|
||||
"button_minus",
|
||||
"button_l",
|
||||
"button_zl"
|
||||
],
|
||||
"properties": {
|
||||
"stick_up": {
|
||||
"$id": "#/properties/keyboard_controls/properties/left_joycon/properties/stick_up",
|
||||
"$ref": "#/definitions/key",
|
||||
"title": "Stick Up",
|
||||
"default": "w"
|
||||
},
|
||||
"stick_down": {
|
||||
"$id": "#/properties/keyboard_controls/properties/left_joycon/properties/stick_down",
|
||||
"$ref": "#/definitions/key",
|
||||
"title": "Stick Down",
|
||||
"default": "S"
|
||||
},
|
||||
"stick_left": {
|
||||
"$id": "#/properties/keyboard_controls/properties/left_joycon/properties/stick_left",
|
||||
"$ref": "#/definitions/key",
|
||||
"title": "Stick Left",
|
||||
"default": "A"
|
||||
},
|
||||
"stick_right": {
|
||||
"$id": "#/properties/keyboard_controls/properties/left_joycon/properties/stick_right",
|
||||
"$ref": "#/definitions/key",
|
||||
"title": "Stick Right",
|
||||
"default": "D"
|
||||
},
|
||||
"stick_button": {
|
||||
"$id": "#/properties/keyboard_controls/properties/left_joycon/properties/stick_button",
|
||||
"$ref": "#/definitions/key",
|
||||
"title": "Stick Button",
|
||||
"default": "F"
|
||||
},
|
||||
"dpad_up": {
|
||||
"$id": "#/properties/keyboard_controls/properties/left_joycon/properties/dpad_up",
|
||||
"$ref": "#/definitions/key",
|
||||
"title": "Dpad Up",
|
||||
"default": "Up"
|
||||
},
|
||||
"dpad_down": {
|
||||
"$id": "#/properties/keyboard_controls/properties/left_joycon/properties/dpad_down",
|
||||
"$ref": "#/definitions/key",
|
||||
"title": "Dpad Down",
|
||||
"default": "Down"
|
||||
},
|
||||
"dpad_left": {
|
||||
"$id": "#/properties/keyboard_controls/properties/left_joycon/properties/dpad_left",
|
||||
"$ref": "#/definitions/key",
|
||||
"title": "Dpad Left",
|
||||
"default": "Left"
|
||||
},
|
||||
"dpad_right": {
|
||||
"$id": "#/properties/keyboard_controls/properties/left_joycon/properties/dpad_right",
|
||||
"$ref": "#/definitions/key",
|
||||
"title": "Dpad Right",
|
||||
"default": "Right"
|
||||
},
|
||||
"button_minus": {
|
||||
"$id": "#/properties/keyboard_controls/properties/left_joycon/properties/button_minus",
|
||||
"$ref": "#/definitions/key",
|
||||
"title": "Button Minus",
|
||||
"default": "Minus"
|
||||
},
|
||||
"button_l": {
|
||||
"$id": "#/properties/keyboard_controls/properties/left_joycon/properties/button_l",
|
||||
"$ref": "#/definitions/key",
|
||||
"title": "Button L",
|
||||
"default": "E"
|
||||
},
|
||||
"button_zl": {
|
||||
"$id": "#/properties/keyboard_controls/properties/left_joycon/properties/button_zl",
|
||||
"$ref": "#/definitions/key",
|
||||
"title": "Button ZL",
|
||||
"default": "Q"
|
||||
}
|
||||
}
|
||||
},
|
||||
"right_joycon": {
|
||||
"$id": "#/properties/keyboard_controls/properties/right_joycon",
|
||||
"type": "object",
|
||||
"title": "Right JoyCon Controls",
|
||||
"required": [
|
||||
"stick_up",
|
||||
"stick_down",
|
||||
"stick_left",
|
||||
"stick_right",
|
||||
"stick_button",
|
||||
"button_a",
|
||||
"button_b",
|
||||
"button_x",
|
||||
"button_y",
|
||||
"button_plus",
|
||||
"button_r",
|
||||
"button_zr"
|
||||
],
|
||||
"properties": {
|
||||
"stick_up": {
|
||||
"$id": "#/properties/keyboard_controls/properties/right_joycon/properties/stick_up",
|
||||
"$ref": "#/definitions/key",
|
||||
"title": "Stick Up",
|
||||
"default": "I"
|
||||
},
|
||||
"stick_down": {
|
||||
"$id": "#/properties/keyboard_controls/properties/right_joycon/properties/stick_down",
|
||||
"$ref": "#/definitions/key",
|
||||
"title": "Stick Down",
|
||||
"default": "K"
|
||||
},
|
||||
"stick_left": {
|
||||
"$id": "#/properties/keyboard_controls/properties/right_joycon/properties/stick_left",
|
||||
"$ref": "#/definitions/key",
|
||||
"title": "Stick Left",
|
||||
"default": "J"
|
||||
},
|
||||
"stick_right": {
|
||||
"$id": "#/properties/keyboard_controls/properties/right_joycon/properties/stick_right",
|
||||
"$ref": "#/definitions/key",
|
||||
"title": "Stick Right",
|
||||
"default": "L"
|
||||
},
|
||||
"stick_button": {
|
||||
"$id": "#/properties/keyboard_controls/properties/right_joycon/properties/stick_button",
|
||||
"$ref": "#/definitions/key",
|
||||
"title": "Stick Button",
|
||||
"default": "H"
|
||||
},
|
||||
"button_a": {
|
||||
"$id": "#/properties/keyboard_controls/properties/right_joycon/properties/button_a",
|
||||
"$ref": "#/definitions/key",
|
||||
"title": "Button A",
|
||||
"default": "Z"
|
||||
},
|
||||
"button_b": {
|
||||
"$id": "#/properties/keyboard_controls/properties/right_joycon/properties/button_b",
|
||||
"$ref": "#/definitions/key",
|
||||
"title": "Button B",
|
||||
"default": "X"
|
||||
},
|
||||
"button_x": {
|
||||
"$id": "#/properties/keyboard_controls/properties/right_joycon/properties/button_x",
|
||||
"$ref": "#/definitions/key",
|
||||
"title": "Button X",
|
||||
"default": "C"
|
||||
},
|
||||
"button_y": {
|
||||
"$id": "#/properties/keyboard_controls/properties/right_joycon/properties/button_y",
|
||||
"$ref": "#/definitions/key",
|
||||
"title": "Button Y",
|
||||
"default": "V"
|
||||
},
|
||||
"button_plus": {
|
||||
"$id": "#/properties/keyboard_controls/properties/right_joycon/properties/button_plus",
|
||||
"$ref": "#/definitions/key",
|
||||
"title": "Button Plus",
|
||||
"default": "Plus"
|
||||
},
|
||||
"button_r": {
|
||||
"$id": "#/properties/keyboard_controls/properties/right_joycon/properties/button_r",
|
||||
"$ref": "#/definitions/key",
|
||||
"title": "Button R",
|
||||
"default": "U"
|
||||
},
|
||||
"button_zr": {
|
||||
"$id": "#/properties/keyboard_controls/properties/right_joycon/properties/button_zr",
|
||||
"$ref": "#/definitions/key",
|
||||
"title": "Button Zr",
|
||||
"default": "O"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"gamepad_controls": {
|
||||
"$id": "#/properties/gamepad_controls",
|
||||
"type": "object",
|
||||
"title": "GamePad Controls",
|
||||
"required": [
|
||||
"left_joycon",
|
||||
"right_joycon"
|
||||
],
|
||||
"properties": {
|
||||
"enable": {
|
||||
"$id": "#/properties/gamepad_controls/properties/enable",
|
||||
"type": "boolean",
|
||||
"title": "Gamepad Enable",
|
||||
"description": "Enables or disables controller support",
|
||||
"default": true,
|
||||
"examples": [
|
||||
true,
|
||||
false
|
||||
]
|
||||
},
|
||||
"index": {
|
||||
"$id": "#/properties/gamepad_controls/properties/index",
|
||||
"type": "integer",
|
||||
"title": "Gamepad Index",
|
||||
"description": "Controller Device Index",
|
||||
"default": 0,
|
||||
"minimum": 0,
|
||||
"examples": [
|
||||
0,
|
||||
1,
|
||||
2
|
||||
]
|
||||
},
|
||||
"deadzone": {
|
||||
"$id": "#/properties/gamepad_controls/properties/deadzone",
|
||||
"type": "number",
|
||||
"title": "Gamepad Deadzone",
|
||||
"description": "Controller Analog Stick Deadzone",
|
||||
"default": 0.05,
|
||||
"minimum": -32768.0,
|
||||
"maximum": 32767.0,
|
||||
"examples": [
|
||||
0.05
|
||||
]
|
||||
},
|
||||
"trigger_threshold": {
|
||||
"$id": "#/properties/gamepad_controls/properties/trigger_threshold",
|
||||
"type": "number",
|
||||
"title": "Controller Trigger Threshold",
|
||||
"description": "The value of how pressed down each trigger has to be in order to register a button press",
|
||||
"default": 0.5,
|
||||
"minimum": 0.0,
|
||||
"maximum": 1.0,
|
||||
"examples": [
|
||||
0.5
|
||||
]
|
||||
},
|
||||
"left_joycon": {
|
||||
"$id": "#/properties/gamepad_controls/properties/left_joycon",
|
||||
"type": "object",
|
||||
"title": "Left JoyCon Controls",
|
||||
"required": [
|
||||
"stick",
|
||||
"stick_button",
|
||||
"dpad_up",
|
||||
"dpad_down",
|
||||
"dpad_left",
|
||||
"dpad_right",
|
||||
"button_minus",
|
||||
"button_l",
|
||||
"button_zl"
|
||||
],
|
||||
"properties": {
|
||||
"stick": {
|
||||
"$id": "#/properties/gamepad_controls/properties/left_joycon/properties/stick",
|
||||
"$ref": "#/definitions/input",
|
||||
"title": "Stick",
|
||||
"default": "LJoystick"
|
||||
},
|
||||
"stick_button": {
|
||||
"$id": "#/properties/gamepad_controls/properties/left_joycon/properties/stick_button",
|
||||
"$ref": "#/definitions/input",
|
||||
"title": "Stick Button",
|
||||
"default": "LStick"
|
||||
},
|
||||
"dpad_up": {
|
||||
"$id": "#/properties/gamepad_controls/properties/left_joycon/properties/dpad_up",
|
||||
"$ref": "#/definitions/input",
|
||||
"title": "Dpad Up",
|
||||
"default": "DPadUp"
|
||||
},
|
||||
"dpad_down": {
|
||||
"$id": "#/properties/gamepad_controls/properties/left_joycon/properties/dpad_down",
|
||||
"$ref": "#/definitions/input",
|
||||
"title": "Dpad Down",
|
||||
"default": "DPadDown"
|
||||
},
|
||||
"dpad_left": {
|
||||
"$id": "#/properties/gamepad_controls/properties/left_joycon/properties/dpad_left",
|
||||
"$ref": "#/definitions/input",
|
||||
"title": "Dpad Left",
|
||||
"default": "DPadLeft"
|
||||
},
|
||||
"dpad_right": {
|
||||
"$id": "#/properties/gamepad_controls/properties/left_joycon/properties/dpad_right",
|
||||
"$ref": "#/definitions/input",
|
||||
"title": "Dpad Right",
|
||||
"default": "DPadRight"
|
||||
},
|
||||
"button_minus": {
|
||||
"$id": "#/properties/gamepad_controls/properties/left_joycon/properties/button_minus",
|
||||
"$ref": "#/definitions/input",
|
||||
"title": "Button Minus",
|
||||
"default": "Back"
|
||||
},
|
||||
"button_l": {
|
||||
"$id": "#/properties/gamepad_controls/properties/left_joycon/properties/button_l",
|
||||
"$ref": "#/definitions/input",
|
||||
"title": "Button L",
|
||||
"default": "LShoulder"
|
||||
},
|
||||
"button_zl": {
|
||||
"$id": "#/properties/gamepad_controls/properties/left_joycon/properties/button_zl",
|
||||
"$ref": "#/definitions/input",
|
||||
"title": "Button ZL",
|
||||
"default": "LTrigger"
|
||||
}
|
||||
}
|
||||
},
|
||||
"right_joycon": {
|
||||
"$id": "#/properties/gamepad_controls/properties/right_joycon",
|
||||
"type": "object",
|
||||
"title": "Right JoyCon Controls",
|
||||
"required": [
|
||||
"stick",
|
||||
"stick_button",
|
||||
"button_a",
|
||||
"button_b",
|
||||
"button_x",
|
||||
"button_y",
|
||||
"button_plus",
|
||||
"button_r",
|
||||
"button_zr"
|
||||
],
|
||||
"properties": {
|
||||
"stick": {
|
||||
"$id": "#/properties/gamepad_controls/properties/right_joycon/properties/stick",
|
||||
"$ref": "#/definitions/input",
|
||||
"title": "Stick",
|
||||
"default": "RJoystick"
|
||||
},
|
||||
"stick_button": {
|
||||
"$id": "#/properties/gamepad_controls/properties/right_joycon/properties/stick_button",
|
||||
"$ref": "#/definitions/input",
|
||||
"title": "Stick Button",
|
||||
"default": "RStick"
|
||||
},
|
||||
"button_a": {
|
||||
"$id": "#/properties/gamepad_controls/properties/right_joycon/properties/button_a",
|
||||
"$ref": "#/definitions/input",
|
||||
"title": "Button A",
|
||||
"default": "B"
|
||||
},
|
||||
"button_b": {
|
||||
"$id": "#/properties/gamepad_controls/properties/right_joycon/properties/button_b",
|
||||
"$ref": "#/definitions/input",
|
||||
"title": "Button B",
|
||||
"default": "A"
|
||||
},
|
||||
"button_x": {
|
||||
"$id": "#/properties/gamepad_controls/properties/right_joycon/properties/button_x",
|
||||
"$ref": "#/definitions/input",
|
||||
"title": "Button X",
|
||||
"default": "Y"
|
||||
},
|
||||
"button_y": {
|
||||
"$id": "#/properties/gamepad_controls/properties/right_joycon/properties/button_y",
|
||||
"$ref": "#/definitions/input",
|
||||
"title": "Button Y",
|
||||
"default": "X"
|
||||
},
|
||||
"button_plus": {
|
||||
"$id": "#/properties/gamepad_controls/properties/right_joycon/properties/button_plus",
|
||||
"$ref": "#/definitions/input",
|
||||
"title": "Button Plus",
|
||||
"default": "Start"
|
||||
},
|
||||
"button_r": {
|
||||
"$id": "#/properties/gamepad_controls/properties/right_joycon/properties/button_r",
|
||||
"$ref": "#/definitions/input",
|
||||
"title": "Button R",
|
||||
"default": "RShoulder"
|
||||
},
|
||||
"button_zr": {
|
||||
"$id": "#/properties/gamepad_controls/properties/right_joycon/properties/button_zr",
|
||||
"$ref": "#/definitions/input",
|
||||
"title": "Button ZR",
|
||||
"default": "RTrigger"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue