diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 741995cde..7bcd57417 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,6 +11,7 @@ on: - '*.yml' - 'README.md' +concurrency: release jobs: release: diff --git a/ARMeilleure/Decoders/OpCodeTable.cs b/ARMeilleure/Decoders/OpCodeTable.cs index caa93099e..3f24986c5 100644 --- a/ARMeilleure/Decoders/OpCodeTable.cs +++ b/ARMeilleure/Decoders/OpCodeTable.cs @@ -1341,7 +1341,7 @@ namespace ARMeilleure.Decoders { string reversedEncoding = encoding.Substring(16) + encoding.Substring(0, 16); MakeOp reversedMakeOp = - (InstDescriptor inst, ulong address, int opCode) + (inst, address, opCode) => makeOp(inst, address, (int)BitOperations.RotateRight((uint)opCode, 16)); Set(reversedEncoding, AllInstT32, new InstDescriptor(name, emitter), reversedMakeOp); } diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/SoundIo.cs b/Ryujinx.Audio.Backends.SoundIo/Native/SoundIo.cs new file mode 100644 index 000000000..9c3e686df --- /dev/null +++ b/Ryujinx.Audio.Backends.SoundIo/Native/SoundIo.cs @@ -0,0 +1,178 @@ +using Ryujinx.Common.Memory; +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Ryujinx.Audio.Backends.SoundIo.Native +{ + public static partial class SoundIo + { + private const string LibraryName = "libsoundio"; + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public unsafe delegate void OnDeviceChangeNativeDelegate(IntPtr ctx); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public unsafe delegate void OnBackendDisconnectedDelegate(IntPtr ctx, SoundIoError err); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public unsafe delegate void OnEventsSignalDelegate(IntPtr ctx); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public unsafe delegate void EmitRtPrioWarningDelegate(); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public unsafe delegate void JackCallbackDelegate(IntPtr msg); + + [StructLayout(LayoutKind.Sequential)] + public struct SoundIoStruct + { + public IntPtr UserData; + public IntPtr OnDeviceChange; + public IntPtr OnBackendDisconnected; + public IntPtr OnEventsSignal; + public SoundIoBackend CurrentBackend; + public IntPtr ApplicationName; + public IntPtr EmitRtPrioWarning; + public IntPtr JackInfoCallback; + public IntPtr JackErrorCallback; + } + + public struct SoundIoChannelLayout + { + public IntPtr Name; + public int ChannelCount; + public Array24 Channels; + + public static IntPtr GetDefault(int channelCount) + { + return soundio_channel_layout_get_default(channelCount); + } + + public static unsafe SoundIoChannelLayout GetDefaultValue(int channelCount) + { + return Unsafe.AsRef((SoundIoChannelLayout*)GetDefault(channelCount)); + } + } + + public struct SoundIoSampleRateRange + { + public int Min; + public int Max; + } + + public struct SoundIoDevice + { + public IntPtr SoundIo; + public IntPtr Id; + public IntPtr Name; + public SoundIoDeviceAim Aim; + public IntPtr Layouts; + public int LayoutCount; + public SoundIoChannelLayout CurrentLayout; + public IntPtr Formats; + public int FormatCount; + public SoundIoFormat CurrentFormat; + public IntPtr SampleRates; + public int SampleRateCount; + public int SampleRateCurrent; + public double SoftwareLatencyMin; + public double SoftwareLatencyMax; + public double SoftwareLatencyCurrent; + public bool IsRaw; + public int RefCount; + public SoundIoError ProbeError; + } + + public struct SoundIoOutStream + { + public IntPtr Device; + public SoundIoFormat Format; + public int SampleRate; + public SoundIoChannelLayout Layout; + public double SoftwareLatency; + public float Volume; + public IntPtr UserData; + public IntPtr WriteCallback; + public IntPtr UnderflowCallback; + public IntPtr ErrorCallback; + public IntPtr Name; + public bool NonTerminalHint; + public int BytesPerFrame; + public int BytesPerSample; + public SoundIoError LayoutError; + } + + public struct SoundIoChannelArea + { + public IntPtr Pointer; + public int Step; + } + + [LibraryImport(LibraryName)] + public static partial IntPtr soundio_create(); + + [LibraryImport(LibraryName)] + public static partial SoundIoError soundio_connect(IntPtr ctx); + + [LibraryImport(LibraryName)] + public static partial void soundio_disconnect(IntPtr ctx); + + [LibraryImport(LibraryName)] + public static partial void soundio_flush_events(IntPtr ctx); + + [LibraryImport(LibraryName)] + public static partial int soundio_output_device_count(IntPtr ctx); + + [LibraryImport(LibraryName)] + public static partial int soundio_default_output_device_index(IntPtr ctx); + + [LibraryImport(LibraryName)] + public static partial IntPtr soundio_get_output_device(IntPtr ctx, int index); + + [LibraryImport(LibraryName)] + [return: MarshalAs(UnmanagedType.Bool)] + public static partial bool soundio_device_supports_format(IntPtr devCtx, SoundIoFormat format); + + [LibraryImport(LibraryName)] + [return: MarshalAs(UnmanagedType.Bool)] + public static partial bool soundio_device_supports_layout(IntPtr devCtx, IntPtr layout); + + [LibraryImport(LibraryName)] + [return: MarshalAs(UnmanagedType.Bool)] + public static partial bool soundio_device_supports_sample_rate(IntPtr devCtx, int sampleRate); + + [LibraryImport(LibraryName)] + public static partial IntPtr soundio_outstream_create(IntPtr devCtx); + + [LibraryImport(LibraryName)] + public static partial SoundIoError soundio_outstream_open(IntPtr outStreamCtx); + + [LibraryImport(LibraryName)] + public static partial SoundIoError soundio_outstream_start(IntPtr outStreamCtx); + + [LibraryImport(LibraryName)] + public static partial SoundIoError soundio_outstream_begin_write(IntPtr outStreamCtx, IntPtr areas, IntPtr frameCount); + + [LibraryImport(LibraryName)] + public static partial SoundIoError soundio_outstream_end_write(IntPtr outStreamCtx); + + [LibraryImport(LibraryName)] + public static partial SoundIoError soundio_outstream_pause(IntPtr devCtx, [MarshalAs(UnmanagedType.Bool)] bool pause); + + [LibraryImport(LibraryName)] + public static partial SoundIoError soundio_outstream_set_volume(IntPtr devCtx, double volume); + + [LibraryImport(LibraryName)] + public static partial void soundio_outstream_destroy(IntPtr streamCtx); + + [LibraryImport(LibraryName)] + public static partial void soundio_destroy(IntPtr ctx); + + [LibraryImport(LibraryName)] + public static partial IntPtr soundio_channel_layout_get_default(int channelCount); + + [LibraryImport(LibraryName)] + public static partial IntPtr soundio_strerror(SoundIoError err); + } +} diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/SoundIoBackend.cs b/Ryujinx.Audio.Backends.SoundIo/Native/SoundIoBackend.cs new file mode 100644 index 000000000..92f8ea375 --- /dev/null +++ b/Ryujinx.Audio.Backends.SoundIo/Native/SoundIoBackend.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.Audio.Backends.SoundIo.Native +{ + public enum SoundIoBackend : int + { + None = 0, + Jack = 1, + PulseAudio = 2, + Alsa = 3, + CoreAudio = 4, + Wasapi = 5, + Dummy = 6 + } +} diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/SoundIoChannelId.cs b/Ryujinx.Audio.Backends.SoundIo/Native/SoundIoChannelId.cs new file mode 100644 index 000000000..70346e0bf --- /dev/null +++ b/Ryujinx.Audio.Backends.SoundIo/Native/SoundIoChannelId.cs @@ -0,0 +1,75 @@ +namespace Ryujinx.Audio.Backends.SoundIo.Native +{ + public enum SoundIoChannelId + { + Invalid = 0, + FrontLeft = 1, + FrontRight = 2, + FrontCenter = 3, + Lfe = 4, + BackLeft = 5, + BackRight = 6, + FrontLeftCenter = 7, + FrontRightCenter = 8, + BackCenter = 9, + SideLeft = 10, + SideRight = 11, + TopCenter = 12, + TopFrontLeft = 13, + TopFrontCenter = 14, + TopFrontRight = 15, + TopBackLeft = 16, + TopBackCenter = 17, + TopBackRight = 18, + BackLeftCenter = 19, + BackRightCenter = 20, + FrontLeftWide = 21, + FrontRightWide = 22, + FrontLeftHigh = 23, + FrontCenterHigh = 24, + FrontRightHigh = 25, + TopFrontLeftCenter = 26, + TopFrontRightCenter = 27, + TopSideLeft = 28, + TopSideRight = 29, + LeftLfe = 30, + RightLfe = 31, + Lfe2 = 32, + BottomCenter = 33, + BottomLeftCenter = 34, + BottomRightCenter = 35, + MsMid = 36, + MsSide = 37, + AmbisonicW = 38, + AmbisonicX = 39, + AmbisonicY = 40, + AmbisonicZ = 41, + XyX = 42, + XyY = 43, + HeadphonesLeft = 44, + HeadphonesRight = 45, + ClickTrack = 46, + ForeignLanguage = 47, + HearingImpaired = 48, + Narration = 49, + Haptic = 50, + DialogCentricMix = 51, + Aux = 52, + Aux0 = 53, + Aux1 = 54, + Aux2 = 55, + Aux3 = 56, + Aux4 = 57, + Aux5 = 58, + Aux6 = 59, + Aux7 = 60, + Aux8 = 61, + Aux9 = 62, + Aux10 = 63, + Aux11 = 64, + Aux12 = 65, + Aux13 = 66, + Aux14 = 67, + Aux15 = 68, + } +} diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/SoundIoContext.cs b/Ryujinx.Audio.Backends.SoundIo/Native/SoundIoContext.cs new file mode 100644 index 000000000..3744c2e64 --- /dev/null +++ b/Ryujinx.Audio.Backends.SoundIo/Native/SoundIoContext.cs @@ -0,0 +1,107 @@ +using System; +using System.Reflection.Metadata; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Threading; +using static Ryujinx.Audio.Backends.SoundIo.Native.SoundIo; + +namespace Ryujinx.Audio.Backends.SoundIo.Native +{ + public class SoundIoContext : IDisposable + { + private IntPtr _context; + private Action _onBackendDisconnect; + private OnBackendDisconnectedDelegate _onBackendDisconnectNative; + + public IntPtr Context => _context; + + internal SoundIoContext(IntPtr context) + { + _context = context; + _onBackendDisconnect = null; + _onBackendDisconnectNative = null; + } + + public SoundIoError Connect() => soundio_connect(_context); + public void Disconnect() => soundio_disconnect(_context); + + public void FlushEvents() => soundio_flush_events(_context); + + public int OutputDeviceCount => soundio_output_device_count(_context); + + public int DefaultOutputDeviceIndex => soundio_default_output_device_index(_context); + + public Action OnBackendDisconnect + { + get { return _onBackendDisconnect; } + set + { + _onBackendDisconnect = value; + + if (_onBackendDisconnect == null) + { + _onBackendDisconnectNative = null; + } + else + { + _onBackendDisconnectNative = (ctx, err) => _onBackendDisconnect(err); + } + + GetContext().OnBackendDisconnected = Marshal.GetFunctionPointerForDelegate(_onBackendDisconnectNative); + } + } + + private ref SoundIoStruct GetContext() + { + unsafe + { + return ref Unsafe.AsRef((SoundIoStruct*)_context); + } + } + + public SoundIoDeviceContext GetOutputDevice(int index) + { + IntPtr deviceContext = soundio_get_output_device(_context, index); + + if (deviceContext == IntPtr.Zero) + { + return null; + } + + return new SoundIoDeviceContext(deviceContext); + } + + public static SoundIoContext Create() + { + IntPtr context = soundio_create(); + + if (context == IntPtr.Zero) + { + return null; + } + + return new SoundIoContext(context); + } + + protected virtual void Dispose(bool disposing) + { + IntPtr currentContext = Interlocked.Exchange(ref _context, IntPtr.Zero); + + if (currentContext != IntPtr.Zero) + { + soundio_destroy(currentContext); + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + ~SoundIoContext() + { + Dispose(false); + } + } +} diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/SoundIoDeviceAim.cs b/Ryujinx.Audio.Backends.SoundIo/Native/SoundIoDeviceAim.cs new file mode 100644 index 000000000..a0689d6d6 --- /dev/null +++ b/Ryujinx.Audio.Backends.SoundIo/Native/SoundIoDeviceAim.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.Audio.Backends.SoundIo.Native +{ + public enum SoundIoDeviceAim + { + SoundIoDeviceAimInput = 0, + SoundIoDeviceAimOutput = 1 + } +} diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/SoundIoDeviceContext.cs b/Ryujinx.Audio.Backends.SoundIo/Native/SoundIoDeviceContext.cs new file mode 100644 index 000000000..42bcc6e3b --- /dev/null +++ b/Ryujinx.Audio.Backends.SoundIo/Native/SoundIoDeviceContext.cs @@ -0,0 +1,49 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using static Ryujinx.Audio.Backends.SoundIo.Native.SoundIo; + +namespace Ryujinx.Audio.Backends.SoundIo.Native +{ + public class SoundIoDeviceContext + { + private readonly IntPtr _context; + + public IntPtr Context => _context; + + internal SoundIoDeviceContext(IntPtr context) + { + _context = context; + } + + private ref SoundIoDevice GetDeviceContext() + { + unsafe + { + return ref Unsafe.AsRef((SoundIoDevice*)_context); + } + } + + public bool IsRaw => GetDeviceContext().IsRaw; + + public string Id => Marshal.PtrToStringAnsi(GetDeviceContext().Id); + + public bool SupportsSampleRate(int sampleRate) => soundio_device_supports_sample_rate(_context, sampleRate); + + public bool SupportsFormat(SoundIoFormat format) => soundio_device_supports_format(_context, format); + + public bool SupportsChannelCount(int channelCount) => soundio_device_supports_layout(_context, SoundIoChannelLayout.GetDefault(channelCount)); + + public SoundIoOutStreamContext CreateOutStream() + { + IntPtr context = soundio_outstream_create(_context); + + if (context == IntPtr.Zero) + { + return null; + } + + return new SoundIoOutStreamContext(context); + } + } +} diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/SoundIoError.cs b/Ryujinx.Audio.Backends.SoundIo/Native/SoundIoError.cs new file mode 100644 index 000000000..9e33fa194 --- /dev/null +++ b/Ryujinx.Audio.Backends.SoundIo/Native/SoundIoError.cs @@ -0,0 +1,22 @@ +namespace Ryujinx.Audio.Backends.SoundIo.Native +{ + public enum SoundIoError + { + None = 0, + NoMem = 1, + InitAudioBackend = 2, + SystemResources = 3, + OpeningDevice = 4, + NoSuchDevice = 5, + Invalid = 6, + BackendUnavailable = 7, + Streaming = 8, + IncompatibleDevice = 9, + NoSuchClient = 10, + IncompatibleBackend = 11, + BackendDisconnected = 12, + Interrupted = 13, + Underflow = 14, + EncodingString = 15, + } +} diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/SoundIoException.cs b/Ryujinx.Audio.Backends.SoundIo/Native/SoundIoException.cs new file mode 100644 index 000000000..a033356e8 --- /dev/null +++ b/Ryujinx.Audio.Backends.SoundIo/Native/SoundIoException.cs @@ -0,0 +1,11 @@ +using System; +using System.Runtime.InteropServices; +using static Ryujinx.Audio.Backends.SoundIo.Native.SoundIo; + +namespace Ryujinx.Audio.Backends.SoundIo.Native +{ + internal class SoundIoException : Exception + { + internal SoundIoException(SoundIoError error) : base(Marshal.PtrToStringAnsi(soundio_strerror(error))) { } + } +} diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/SoundIoFormat.cs b/Ryujinx.Audio.Backends.SoundIo/Native/SoundIoFormat.cs new file mode 100644 index 000000000..0eee97804 --- /dev/null +++ b/Ryujinx.Audio.Backends.SoundIo/Native/SoundIoFormat.cs @@ -0,0 +1,25 @@ +namespace Ryujinx.Audio.Backends.SoundIo.Native +{ + public enum SoundIoFormat + { + Invalid = 0, + S8 = 1, + U8 = 2, + S16LE = 3, + S16BE = 4, + U16LE = 5, + U16BE = 6, + S24LE = 7, + S24BE = 8, + U24LE = 9, + U24BE = 10, + S32LE = 11, + S32BE = 12, + U32LE = 13, + U32BE = 14, + Float32LE = 15, + Float32BE = 16, + Float64LE = 17, + Float64BE = 18, + } +} diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/SoundIoOutStreamContext.cs b/Ryujinx.Audio.Backends.SoundIo/Native/SoundIoOutStreamContext.cs new file mode 100644 index 000000000..2e432b311 --- /dev/null +++ b/Ryujinx.Audio.Backends.SoundIo/Native/SoundIoOutStreamContext.cs @@ -0,0 +1,164 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using static Ryujinx.Audio.Backends.SoundIo.Native.SoundIo; + +namespace Ryujinx.Audio.Backends.SoundIo.Native +{ + public class SoundIoOutStreamContext : IDisposable + { + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private unsafe delegate void WriteCallbackDelegate(IntPtr ctx, int frameCountMin, int frameCountMax); + + private IntPtr _context; + private IntPtr _nameStored; + private Action _writeCallback; + private WriteCallbackDelegate _writeCallbackNative; + + public IntPtr Context => _context; + + internal SoundIoOutStreamContext(IntPtr context) + { + _context = context; + _nameStored = IntPtr.Zero; + _writeCallback = null; + _writeCallbackNative = null; + } + + private ref SoundIoOutStream GetOutContext() + { + unsafe + { + return ref Unsafe.AsRef((SoundIoOutStream*)_context); + } + } + + public string Name + { + get => Marshal.PtrToStringAnsi(GetOutContext().Name); + set + { + var context = GetOutContext(); + + if (_nameStored != IntPtr.Zero && context.Name == _nameStored) + { + Marshal.FreeHGlobal(_nameStored); + } + + _nameStored = Marshal.StringToHGlobalAnsi(value); + GetOutContext().Name = _nameStored; + } + } + + public SoundIoChannelLayout Layout + { + get => GetOutContext().Layout; + set => GetOutContext().Layout = value; + } + + public SoundIoFormat Format + { + get => GetOutContext().Format; + set => GetOutContext().Format = value; + } + + public int SampleRate + { + get => GetOutContext().SampleRate; + set => GetOutContext().SampleRate = value; + } + + public float Volume + { + get => GetOutContext().Volume; + set => GetOutContext().Volume = value; + } + + public int BytesPerFrame + { + get => GetOutContext().BytesPerFrame; + set => GetOutContext().BytesPerFrame = value; + } + + public int BytesPerSample + { + get => GetOutContext().BytesPerSample; + set => GetOutContext().BytesPerSample = value; + } + + public Action WriteCallback + { + get { return _writeCallback; } + set + { + _writeCallback = value; + + if (_writeCallback == null) + { + _writeCallbackNative = null; + } + else + { + _writeCallbackNative = (ctx, frameCountMin, frameCountMax) => _writeCallback(frameCountMin, frameCountMax); + } + + GetOutContext().WriteCallback = Marshal.GetFunctionPointerForDelegate(_writeCallbackNative); + } + } + + private static void CheckError(SoundIoError error) + { + if (error != SoundIoError.None) + { + throw new SoundIoException(error); + } + } + + public void Open() => CheckError(soundio_outstream_open(_context)); + + public void Start() => CheckError(soundio_outstream_start(_context)); + + public void Pause(bool pause) => CheckError(soundio_outstream_pause(_context, pause)); + + public void SetVolume(double volume) => CheckError(soundio_outstream_set_volume(_context, volume)); + + public Span BeginWrite(ref int frameCount) + { + IntPtr arenas = default; + int nativeFrameCount = frameCount; + + unsafe + { + var frameCountPtr = &nativeFrameCount; + var arenasPtr = &arenas; + CheckError(soundio_outstream_begin_write(_context, (IntPtr)arenasPtr, (IntPtr)frameCountPtr)); + + frameCount = *frameCountPtr; + + return new Span((void*)arenas, Layout.ChannelCount); + } + } + + public void EndWrite() => CheckError(soundio_outstream_end_write(_context)); + + protected virtual void Dispose(bool disposing) + { + if (_context != IntPtr.Zero) + { + soundio_outstream_destroy(_context); + _context = IntPtr.Zero; + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + ~SoundIoOutStreamContext() + { + Dispose(false); + } + } +} diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/MarshalExtensions.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/MarshalExtensions.cs deleted file mode 100644 index 5e86263ea..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/MarshalExtensions.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -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 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 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)); - } - } -} \ No newline at end of file diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIO.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIO.cs deleted file mode 100644 index c4ce1887d..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIO.cs +++ /dev/null @@ -1,386 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; - -namespace SoundIOSharp -{ - public class SoundIO : IDisposable - { - Pointer handle; - - public SoundIO() - { - handle = Natives.soundio_create(); - } - - internal SoundIO(Pointer handle) - { - this.handle = handle; - } - - public void Dispose () - { - foreach (var h in allocated_hglobals) - { - Marshal.FreeHGlobal(h); - } - - Natives.soundio_destroy(handle); - } - - // Equality (based on handle) - - public override bool Equals(object other) - { - var d = other as SoundIO; - - return d != null && this.handle == d.handle; - } - - public override int GetHashCode() - { - return (int)(IntPtr)handle; - } - - public static bool operator == (SoundIO obj1, SoundIO obj2) - { - return obj1 is null ? obj2 is null : obj1.Equals(obj2); - } - - public static bool operator != (SoundIO obj1, SoundIO obj2) - { - return obj1 is null ? obj2 is object : !obj1.Equals(obj2); - } - - // fields - - // FIXME: this should be taken care in more centralized/decent manner... we don't want to write - // this kind of code anywhere we need string marshaling. - List allocated_hglobals = new List(); - - public string ApplicationName { - get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, app_name_offset)); } - set - { - unsafe - { - var existing = Marshal.ReadIntPtr(handle, app_name_offset); - if (allocated_hglobals.Contains (existing)) - { - allocated_hglobals.Remove(existing); - Marshal.FreeHGlobal(existing); - } - - var ptr = Marshal.StringToHGlobalAnsi(value); - Marshal.WriteIntPtr(handle, app_name_offset, ptr); - allocated_hglobals.Add(ptr); - } - } - } - - static readonly int app_name_offset = (int)Marshal.OffsetOf("app_name"); - - public SoundIOBackend CurrentBackend - { - get { return (SoundIOBackend)Marshal.ReadInt32(handle, current_backend_offset); } - } - - static readonly int current_backend_offset = (int)Marshal.OffsetOf("current_backend"); - - // emit_rtprio_warning - public Action EmitRealtimePriorityWarning - { - get { return emit_rtprio_warning; } - set - { - emit_rtprio_warning = value; - - var ptr = Marshal.GetFunctionPointerForDelegate(on_devices_change); - - Marshal.WriteIntPtr(handle, emit_rtprio_warning_offset, ptr); - } - } - - static readonly int emit_rtprio_warning_offset = (int)Marshal.OffsetOf("emit_rtprio_warning"); - - Action emit_rtprio_warning; - - // jack_error_callback - public Action JackErrorCallback - { - get { return jack_error_callback; } - set - { - jack_error_callback = value; - if (value == null) - { - jack_error_callback = null; - } - else - { - jack_error_callback_native = msg => jack_error_callback(msg); - } - - var ptr = Marshal.GetFunctionPointerForDelegate(jack_error_callback_native); - Marshal.WriteIntPtr(handle, jack_error_callback_offset, ptr); - } - } - - static readonly int jack_error_callback_offset = (int)Marshal.OffsetOf("jack_error_callback"); - - Action jack_error_callback; - delegate void jack_error_delegate(string message); - jack_error_delegate jack_error_callback_native; - - // jack_info_callback - public Action JackInfoCallback - { - get { return jack_info_callback; } - set - { - jack_info_callback = value; - if (value == null) - { - jack_info_callback = null; - } - else - { - jack_info_callback_native = msg => jack_info_callback(msg); - } - - var ptr = Marshal.GetFunctionPointerForDelegate(jack_info_callback_native); - Marshal.WriteIntPtr(handle, jack_info_callback_offset, ptr); - } - } - - static readonly int jack_info_callback_offset = (int)Marshal.OffsetOf("jack_info_callback"); - - Action jack_info_callback; - delegate void jack_info_delegate(string message); - jack_info_delegate jack_info_callback_native; - - // on_backend_disconnect - public Action OnBackendDisconnect - { - get { return on_backend_disconnect; } - set - { - on_backend_disconnect = value; - if (value == null) - { - on_backend_disconnect_native = null; - } - else - { - on_backend_disconnect_native = (sio, err) => on_backend_disconnect(err); - } - - var ptr = Marshal.GetFunctionPointerForDelegate(on_backend_disconnect_native); - Marshal.WriteIntPtr(handle, on_backend_disconnect_offset, ptr); - } - } - - static readonly int on_backend_disconnect_offset = (int)Marshal.OffsetOf("on_backend_disconnect"); - - Action on_backend_disconnect; - delegate void on_backend_disconnect_delegate(IntPtr handle, int errorCode); - on_backend_disconnect_delegate on_backend_disconnect_native; - - // on_devices_change - public Action OnDevicesChange - { - get { return on_devices_change; } - set - { - on_devices_change = value; - if (value == null) - { - on_devices_change_native = null; - } - else - { - on_devices_change_native = sio => on_devices_change(); - } - - var ptr = Marshal.GetFunctionPointerForDelegate(on_devices_change_native); - Marshal.WriteIntPtr(handle, on_devices_change_offset, ptr); - } - } - - static readonly int on_devices_change_offset = (int)Marshal.OffsetOf("on_devices_change"); - - Action on_devices_change; - delegate void on_devices_change_delegate(IntPtr handle); - on_devices_change_delegate on_devices_change_native; - - // on_events_signal - public Action OnEventsSignal - { - get { return on_events_signal; } - set - { - on_events_signal = value; - if (value == null) - { - on_events_signal_native = null; - } - else - { - on_events_signal_native = sio => on_events_signal(); - } - - var ptr = Marshal.GetFunctionPointerForDelegate(on_events_signal_native); - Marshal.WriteIntPtr(handle, on_events_signal_offset, ptr); - } - } - - static readonly int on_events_signal_offset = (int)Marshal.OffsetOf("on_events_signal"); - - Action on_events_signal; - delegate void on_events_signal_delegate(IntPtr handle); - on_events_signal_delegate on_events_signal_native; - - - // functions - - public int BackendCount - { - get { return Natives.soundio_backend_count(handle); } - } - - public int InputDeviceCount - { - get { return Natives.soundio_input_device_count(handle); } - } - - public int OutputDeviceCount - { - get { return Natives.soundio_output_device_count(handle); } - } - - public int DefaultInputDeviceIndex - { - get { return Natives.soundio_default_input_device_index(handle); } - } - - public int DefaultOutputDeviceIndex - { - get { return Natives.soundio_default_output_device_index(handle); } - } - - public SoundIOBackend GetBackend(int index) - { - return (SoundIOBackend)Natives.soundio_get_backend(handle, index); - } - - public SoundIODevice GetInputDevice(int index) - { - return new SoundIODevice(Natives.soundio_get_input_device(handle, index)); - } - - public SoundIODevice GetOutputDevice(int index) - { - return new SoundIODevice(Natives.soundio_get_output_device(handle, index)); - } - - public void Connect() - { - var ret = (SoundIoError)Natives.soundio_connect(handle); - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - } - - public void ConnectBackend(SoundIOBackend backend) - { - var ret = (SoundIoError)Natives.soundio_connect_backend(handle, (SoundIoBackend)backend); - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - } - - public void Disconnect() - { - Natives.soundio_disconnect(handle); - } - - public void FlushEvents() - { - Natives.soundio_flush_events(handle); - } - - public void WaitEvents() - { - Natives.soundio_wait_events(handle); - } - - public void Wakeup() - { - Natives.soundio_wakeup(handle); - } - - public void ForceDeviceScan() - { - Natives.soundio_force_device_scan(handle); - } - - public SoundIORingBuffer CreateRingBuffer(int capacity) - { - return new SoundIORingBuffer(Natives.soundio_ring_buffer_create(handle, capacity)); - } - - // static methods - - public static string VersionString - { - get { return Marshal.PtrToStringAnsi(Natives.soundio_version_string()); } - } - - public static int VersionMajor - { - get { return Natives.soundio_version_major(); } - } - - public static int VersionMinor - { - get { return Natives.soundio_version_minor(); } - } - - public static int VersionPatch - { - get { return Natives.soundio_version_patch(); } - } - - public static string GetBackendName(SoundIOBackend backend) - { - return Marshal.PtrToStringAnsi(Natives.soundio_backend_name((SoundIoBackend)backend)); - } - - public static bool HaveBackend(SoundIOBackend backend) - { - return Natives.soundio_have_backend((SoundIoBackend)backend); - } - - public static int GetBytesPerSample(SoundIOFormat format) - { - return Natives.soundio_get_bytes_per_sample((SoundIoFormat)format); - } - - public static int GetBytesPerFrame(SoundIOFormat format, int channelCount) - { - return Natives.soundio_get_bytes_per_frame((SoundIoFormat)format, channelCount); - } - - public static int GetBytesPerSecond(SoundIOFormat format, int channelCount, int sampleRate) - { - return Natives.soundio_get_bytes_per_second((SoundIoFormat)format, channelCount, sampleRate); - } - - public static string GetSoundFormatName(SoundIOFormat format) - { - return Marshal.PtrToStringAnsi(Natives.soundio_format_string((SoundIoFormat)format)); - } - } -} \ No newline at end of file diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOBackend.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOBackend.cs deleted file mode 100644 index fd1058047..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOBackend.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace SoundIOSharp -{ - public enum SoundIOBackend - { - None, - Jack, - PulseAudio, - Alsa, - CoreAudio, - Wasapi, - Dummy - } -} \ No newline at end of file diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelArea.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelArea.cs deleted file mode 100644 index c15fb7447..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelArea.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace SoundIOSharp -{ - public struct SoundIOChannelArea - { - internal SoundIOChannelArea(Pointer handle) - { - this.handle = handle; - } - - Pointer handle; - - public IntPtr Pointer - { - get { return Marshal.ReadIntPtr(handle, ptr_offset); } - set { Marshal.WriteIntPtr(handle, ptr_offset, value); } - } - - static readonly int ptr_offset = (int)Marshal.OffsetOf("ptr"); - - public int Step - { - get { return Marshal.ReadInt32(handle, step_offset); } - } - - static readonly int step_offset = (int)Marshal.OffsetOf("step"); - } -} \ No newline at end of file diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelAreas.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelAreas.cs deleted file mode 100644 index e0f375b96..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelAreas.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace SoundIOSharp -{ - public struct SoundIOChannelAreas - { - static readonly int native_size = Marshal.SizeOf(); - - internal SoundIOChannelAreas(IntPtr head, int channelCount, int frameCount) - { - this.head = head; - this.channel_count = channelCount; - this.frame_count = frameCount; - } - - IntPtr head; - int channel_count; - int frame_count; - - public bool IsEmpty - { - get { return head == IntPtr.Zero; } - } - - public SoundIOChannelArea GetArea(int channel) - { - return new SoundIOChannelArea(head + native_size * channel); - } - - public int ChannelCount => channel_count; - public int FrameCount => frame_count; - } -} \ No newline at end of file diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelId.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelId.cs deleted file mode 100644 index 002669dcf..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelId.cs +++ /dev/null @@ -1,75 +0,0 @@ -namespace SoundIOSharp -{ - public enum SoundIOChannelId - { - Invalid, - FrontLeft, - FrontRight, - FrontCenter, - Lfe, - BackLeft, - BackRight, - FrontLeftCenter, - FrontRightCenter, - BackCenter, - SideLeft, - SideRight, - TopCenter, - TopFrontLeft, - TopFrontCenter, - TopFrontRight, - TopBackLeft, - TopBackCenter, - TopBackRight, - BackLeftCenter, - BackRightCenter, - FrontLeftWide, - FrontRightWide, - FrontLeftHigh, - FrontCenterHigh, - FrontRightHigh, - TopFrontLeftCenter, - TopFrontRightCenter, - TopSideLeft, - TopSideRight, - LeftLfe, - RightLfe, - Lfe2, - BottomCenter, - BottomLeftCenter, - BottomRightCenter, - MsMid, - MsSide, - AmbisonicW, - AmbisonicX, - AmbisonicY, - AmbisonicZ, - XyX, - XyY, - HeadphonesLeft, - HeadphonesRight, - ClickTrack, - ForeignLanguage, - HearingImpaired, - Narration, - Haptic, - DialogCentricMix, - Aux, - Aux0, - Aux1, - Aux2, - Aux3, - Aux4, - Aux5, - Aux6, - Aux7, - Aux8, - Aux9, - Aux10, - Aux11, - Aux12, - Aux13, - Aux14, - Aux15 - } -} \ No newline at end of file diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelLayout.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelLayout.cs deleted file mode 100644 index ea617d4b4..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOChannelLayout.cs +++ /dev/null @@ -1,116 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; - -namespace SoundIOSharp -{ - public readonly struct SoundIOChannelLayout - { - public static int BuiltInCount - { - get { return Natives.soundio_channel_layout_builtin_count(); } - } - - public static SoundIOChannelLayout GetBuiltIn(int index) - { - return new SoundIOChannelLayout(Natives.soundio_channel_layout_get_builtin(index)); - } - - public static SoundIOChannelLayout GetDefault(int channelCount) - { - var handle = Natives.soundio_channel_layout_get_default(channelCount); - - return new SoundIOChannelLayout (handle); - } - - public static SoundIOChannelId ParseChannelId(string name) - { - var ptr = Marshal.StringToHGlobalAnsi(name); - - try - { - return (SoundIOChannelId)Natives.soundio_parse_channel_id(ptr, name.Length); - } - finally - { - Marshal.FreeHGlobal(ptr); - } - } - - // instance members - - internal SoundIOChannelLayout(Pointer handle) - { - this.handle = handle; - } - - readonly Pointer handle; - - public bool IsNull - { - get { return handle.Handle == IntPtr.Zero; } - } - - internal IntPtr Handle - { - get { return handle; } - } - - public int ChannelCount - { - get { return IsNull ? 0 : Marshal.ReadInt32((IntPtr)handle + channel_count_offset); } - } - - static readonly int channel_count_offset = (int)Marshal.OffsetOf("channel_count"); - - public string Name - { - get { return IsNull ? null : Marshal.PtrToStringAnsi(Marshal.ReadIntPtr((IntPtr)handle + name_offset)); } - } - - static readonly int name_offset = (int)Marshal.OffsetOf("name"); - - public IEnumerable Channels - { - get - { - if (IsNull) yield break; - - for (int i = 0; i < 24; i++) - { - yield return (SoundIOChannelId)Marshal.ReadInt32((IntPtr)handle + channels_offset + sizeof(SoundIoChannelId) * i); - } - } - } - - static readonly int channels_offset = (int)Marshal.OffsetOf("channels"); - - public override bool Equals(object other) - { - if (!(other is SoundIOChannelLayout)) return false; - - var s = (SoundIOChannelLayout) other; - - return handle == s.handle || Natives.soundio_channel_layout_equal(handle, s.handle); - } - - public override int GetHashCode() - { - return handle.GetHashCode(); - } - - public string DetectBuiltInName() - { - if (IsNull) throw new InvalidOperationException(); - - return Natives.soundio_channel_layout_detect_builtin(handle) ? Name : null; - } - - public int FindChannel(SoundIOChannelId channel) - { - if (IsNull) throw new InvalidOperationException(); - - return Natives.soundio_channel_layout_find_channel(handle, (SoundIoChannelId)channel); - } - } -} \ No newline at end of file diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIODevice.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIODevice.cs deleted file mode 100644 index 6e7c49649..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIODevice.cs +++ /dev/null @@ -1,267 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; - -namespace SoundIOSharp -{ - public class SoundIODevice - { - public static SoundIOChannelLayout BestMatchingChannelLayout(SoundIODevice device1, SoundIODevice device2) - { - var ptr1 = Marshal.ReadIntPtr(device1.handle, layouts_offset); - var ptr2 = Marshal.ReadIntPtr(device2.handle, layouts_offset); - - return new SoundIOChannelLayout(Natives.soundio_best_matching_channel_layout(ptr1, device1.LayoutCount, ptr2, device2.LayoutCount)); - } - - internal SoundIODevice(Pointer handle) - { - this.handle = handle; - } - - readonly Pointer handle; - - // Equality (based on handle and native func) - - public override bool Equals(object other) - { - var d = other as SoundIODevice; - - return d != null && (this.handle == d.handle || Natives.soundio_device_equal (this.handle, d.handle)); - } - - public override int GetHashCode() - { - return (int)(IntPtr)handle; - } - - public static bool operator == (SoundIODevice obj1, SoundIODevice obj2) - { - return obj1 is null ? obj2 is null : obj1.Equals(obj2); - } - - public static bool operator != (SoundIODevice obj1, SoundIODevice obj2) - { - return obj1 is null ? obj2 is object : !obj1.Equals(obj2); - } - - // fields - - public SoundIODeviceAim Aim - { - get { return (SoundIODeviceAim)Marshal.ReadInt32(handle, aim_offset); } - } - - static readonly int aim_offset = (int)Marshal.OffsetOf("aim"); - - public SoundIOFormat CurrentFormat - { - get { return (SoundIOFormat)Marshal.ReadInt32(handle, current_format_offset); } - } - - static readonly int current_format_offset = (int)Marshal.OffsetOf("current_format"); - - public SoundIOChannelLayout CurrentLayout - { - get { return new SoundIOChannelLayout((IntPtr)handle + current_layout_offset); } - } - - static readonly int current_layout_offset = (int)Marshal.OffsetOf("current_layout"); - - public int FormatCount - { - get { return Marshal.ReadInt32(handle, format_count_offset); } - } - - static readonly int format_count_offset = (int)Marshal.OffsetOf("format_count"); - - public IEnumerable Formats - { - get - { - var ptr = Marshal.ReadIntPtr(handle, formats_offset); - - for (int i = 0; i < FormatCount; i++) - { - yield return (SoundIOFormat)Marshal.ReadInt32(ptr, i); - } - } - } - - static readonly int formats_offset = (int)Marshal.OffsetOf("formats"); - - public string Id - { - get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, id_offset)); } - } - - static readonly int id_offset = (int)Marshal.OffsetOf("id"); - - public bool IsRaw - { - get { return Marshal.ReadInt32(handle, is_raw_offset) != 0; } - } - - static readonly int is_raw_offset = (int)Marshal.OffsetOf("is_raw"); - - public int LayoutCount - { - get { return Marshal.ReadInt32(handle, layout_count_offset); } - } - - static readonly int layout_count_offset = (int)Marshal.OffsetOf("layout_count"); - - public IEnumerable Layouts - { - get - { - var ptr = Marshal.ReadIntPtr (handle, layouts_offset); - - for (int i = 0; i < LayoutCount; i++) - { - yield return new SoundIOChannelLayout(ptr + i * Marshal.SizeOf()); - } - } - } - - static readonly int layouts_offset = (int)Marshal.OffsetOf("layouts"); - - public string Name - { - get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, name_offset)); } - } - - static readonly int name_offset = (int)Marshal.OffsetOf("name"); - - public int ProbeError - { - get { return Marshal.ReadInt32(handle, probe_error_offset); } - } - - static readonly int probe_error_offset = (int)Marshal.OffsetOf("probe_error"); - - public int ReferenceCount - { - get { return Marshal.ReadInt32(handle, ref_count_offset); } - } - - static readonly int ref_count_offset = (int)Marshal.OffsetOf("ref_count"); - - public int SampleRateCount - { - get { return Marshal.ReadInt32(handle, sample_rate_count_offset); } - } - - static readonly int sample_rate_count_offset = (int)Marshal.OffsetOf("sample_rate_count"); - - public IEnumerable SampleRates - { - get - { - var ptr = Marshal.ReadIntPtr(handle, sample_rates_offset); - - for (int i = 0; i < SampleRateCount; i++) - { - yield return new SoundIOSampleRateRange(Marshal.ReadInt32(ptr, i * 2), Marshal.ReadInt32(ptr, i * 2 + 1)); - } - } - } - - static readonly int sample_rates_offset = (int)Marshal.OffsetOf("sample_rates"); - - public double SoftwareLatencyCurrent - { - get { return MarshalEx.ReadDouble(handle, software_latency_current_offset); } - set { MarshalEx.WriteDouble(handle, software_latency_current_offset, value); } - } - - static readonly int software_latency_current_offset = (int)Marshal.OffsetOf("software_latency_current"); - - public double SoftwareLatencyMin - { - get { return MarshalEx.ReadDouble(handle, software_latency_min_offset); } - set { MarshalEx.WriteDouble(handle, software_latency_min_offset, value); } - } - - static readonly int software_latency_min_offset = (int)Marshal.OffsetOf("software_latency_min"); - - public double SoftwareLatencyMax - { - get { return MarshalEx.ReadDouble(handle, software_latency_max_offset); } - set { MarshalEx.WriteDouble(handle, software_latency_max_offset, value); } - } - - static readonly int software_latency_max_offset = (int)Marshal.OffsetOf("software_latency_max"); - - public SoundIO SoundIO - { - get { return new SoundIO(Marshal.ReadIntPtr(handle, soundio_offset)); } - } - - static readonly int soundio_offset = (int)Marshal.OffsetOf("soundio"); - - // functions - - public void AddReference() - { - Natives.soundio_device_ref(handle); - } - - public void RemoveReference() - { - Natives.soundio_device_unref(handle); - } - - public void SortDeviceChannelLayouts() - { - Natives.soundio_device_sort_channel_layouts(handle); - } - - public static readonly SoundIOFormat S16NE = BitConverter.IsLittleEndian ? SoundIOFormat.S16LE : SoundIOFormat.S16BE; - public static readonly SoundIOFormat U16NE = BitConverter.IsLittleEndian ? SoundIOFormat.U16LE : SoundIOFormat.U16BE; - public static readonly SoundIOFormat S24NE = BitConverter.IsLittleEndian ? SoundIOFormat.S24LE : SoundIOFormat.S24BE; - public static readonly SoundIOFormat U24NE = BitConverter.IsLittleEndian ? SoundIOFormat.U24LE : SoundIOFormat.U24BE; - public static readonly SoundIOFormat S32NE = BitConverter.IsLittleEndian ? SoundIOFormat.S32LE : SoundIOFormat.S32BE; - public static readonly SoundIOFormat U32NE = BitConverter.IsLittleEndian ? SoundIOFormat.U32LE : SoundIOFormat.U32BE; - public static readonly SoundIOFormat Float32NE = BitConverter.IsLittleEndian ? SoundIOFormat.Float32LE : SoundIOFormat.Float32BE; - public static readonly SoundIOFormat Float64NE = BitConverter.IsLittleEndian ? SoundIOFormat.Float64LE : SoundIOFormat.Float64BE; - public static readonly SoundIOFormat S16FE = !BitConverter.IsLittleEndian ? SoundIOFormat.S16LE : SoundIOFormat.S16BE; - public static readonly SoundIOFormat U16FE = !BitConverter.IsLittleEndian ? SoundIOFormat.U16LE : SoundIOFormat.U16BE; - public static readonly SoundIOFormat S24FE = !BitConverter.IsLittleEndian ? SoundIOFormat.S24LE : SoundIOFormat.S24BE; - public static readonly SoundIOFormat U24FE = !BitConverter.IsLittleEndian ? SoundIOFormat.U24LE : SoundIOFormat.U24BE; - public static readonly SoundIOFormat S32FE = !BitConverter.IsLittleEndian ? SoundIOFormat.S32LE : SoundIOFormat.S32BE; - public static readonly SoundIOFormat U32FE = !BitConverter.IsLittleEndian ? SoundIOFormat.U32LE : SoundIOFormat.U32BE; - public static readonly SoundIOFormat Float32FE = !BitConverter.IsLittleEndian ? SoundIOFormat.Float32LE : SoundIOFormat.Float32BE; - public static readonly SoundIOFormat Float64FE = !BitConverter.IsLittleEndian ? SoundIOFormat.Float64LE : SoundIOFormat.Float64BE; - - public bool SupportsFormat(SoundIOFormat format) - { - return Natives.soundio_device_supports_format(handle, (SoundIoFormat)format); - } - - public bool SupportsSampleRate(int sampleRate) - { - return Natives.soundio_device_supports_sample_rate(handle, sampleRate); - } - - public bool SupportsChannelCount(int channelCount) - { - return Natives.soundio_device_supports_layout(handle, SoundIOChannelLayout.GetDefault(channelCount).Handle); - } - - public int GetNearestSampleRate(int sampleRate) - { - return Natives.soundio_device_nearest_sample_rate(handle, sampleRate); - } - - public SoundIOInStream CreateInStream() - { - return new SoundIOInStream(Natives.soundio_instream_create(handle)); - } - - public SoundIOOutStream CreateOutStream() - { - return new SoundIOOutStream(Natives.soundio_outstream_create(handle)); - } - } -} \ No newline at end of file diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIODeviceAim.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIODeviceAim.cs deleted file mode 100644 index 1e596127b..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIODeviceAim.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace SoundIOSharp -{ - public enum SoundIODeviceAim // soundio.h (228, 6) - { - Input, - Output - } -} \ No newline at end of file diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOException.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOException.cs deleted file mode 100644 index 537b6cde2..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOException.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace SoundIOSharp -{ - public class SoundIOException : Exception - { - internal SoundIOException(SoundIoError errorCode) : base (Marshal.PtrToStringAnsi(Natives.soundio_strerror((int) errorCode))) { } - } -} \ No newline at end of file diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOFormat.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOFormat.cs deleted file mode 100644 index df1b71c6b..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOFormat.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace SoundIOSharp -{ - public enum SoundIOFormat - { - Invalid, - S8, - U8, - S16LE, - S16BE, - U16LE, - U16BE, - S24LE, - S24BE, - U24LE, - U24BE, - S32LE, - S32BE, - U32LE, - U32BE, - Float32LE, - Float32BE, - Float64LE, - Float64BE - } -} \ No newline at end of file diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOInStream.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOInStream.cs deleted file mode 100644 index df97d6536..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOInStream.cs +++ /dev/null @@ -1,293 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; - -namespace SoundIOSharp -{ - public class SoundIOInStream : IDisposable - { - internal SoundIOInStream(Pointer handle) - { - this.handle = handle; - } - - Pointer handle; - - public void Dispose() - { - Natives.soundio_instream_destroy(handle); - } - - // Equality (based on handle) - - public override bool Equals(object other) - { - var d = other as SoundIOInStream; - - return d != null && (this.handle == d.handle); - } - - public override int GetHashCode() - { - return (int)(IntPtr)handle; - } - - public static bool operator == (SoundIOInStream obj1, SoundIOInStream obj2) - { - return obj1 is null ? obj2 is null : obj1.Equals(obj2); - } - - public static bool operator != (SoundIOInStream obj1, SoundIOInStream obj2) - { - return obj1 is null ? obj2 is object : !obj1.Equals(obj2); - } - - // fields - - public SoundIODevice Device - { - get { return new SoundIODevice(Marshal.ReadIntPtr(handle, device_offset)); } - } - - static readonly int device_offset = (int)Marshal.OffsetOf("device"); - - public SoundIOFormat Format - { - get { return (SoundIOFormat)Marshal.ReadInt32(handle, format_offset); } - set { Marshal.WriteInt32(handle, format_offset, (int) value); } - } - - static readonly int format_offset = (int)Marshal.OffsetOf("format"); - - public int SampleRate - { - get { return Marshal.ReadInt32(handle, sample_rate_offset); } - set { Marshal.WriteInt32(handle, sample_rate_offset, value); } - } - - static readonly int sample_rate_offset = (int)Marshal.OffsetOf("sample_rate"); - - public SoundIOChannelLayout Layout - { - get { return new SoundIOChannelLayout ((IntPtr) handle + layout_offset); } - set - { - unsafe - { - Buffer.MemoryCopy((void*)((IntPtr)handle + layout_offset), (void*)value.Handle, Marshal.SizeOf(), Marshal.SizeOf()); - } - } - } - - static readonly int layout_offset = (int)Marshal.OffsetOf("layout"); - - public double SoftwareLatency - { - get { return MarshalEx.ReadDouble(handle, software_latency_offset); } - set { MarshalEx.WriteDouble(handle, software_latency_offset, value); } - } - - static readonly int software_latency_offset = (int)Marshal.OffsetOf("software_latency"); - - // error_callback - public Action ErrorCallback - { - get { return error_callback; } - set - { - error_callback = value; - error_callback_native = _ => error_callback(); - - var ptr = Marshal.GetFunctionPointerForDelegate(error_callback_native); - - Marshal.WriteIntPtr(handle, error_callback_offset, ptr); - } - } - - static readonly int error_callback_offset = (int)Marshal.OffsetOf("error_callback"); - - Action error_callback; - delegate void error_callback_delegate(IntPtr handle); - error_callback_delegate error_callback_native; - - // read_callback - public Action ReadCallback - { - get { return read_callback; } - set - { - read_callback = value; - read_callback_native = (_, minFrameCount, maxFrameCount) => read_callback(minFrameCount, maxFrameCount); - - var ptr = Marshal.GetFunctionPointerForDelegate(read_callback_native); - - Marshal.WriteIntPtr(handle, read_callback_offset, ptr); - } - } - - static readonly int read_callback_offset = (int)Marshal.OffsetOf("read_callback"); - - Action read_callback; - delegate void read_callback_delegate(IntPtr handle, int min, int max); - read_callback_delegate read_callback_native; - - // overflow_callback - public Action OverflowCallback - { - get { return overflow_callback; } - set - { - overflow_callback = value; - overflow_callback_native = _ => overflow_callback(); - - var ptr = Marshal.GetFunctionPointerForDelegate(overflow_callback_native); - - Marshal.WriteIntPtr(handle, overflow_callback_offset, ptr); - } - } - static readonly int overflow_callback_offset = (int)Marshal.OffsetOf("overflow_callback"); - - Action overflow_callback; - delegate void overflow_callback_delegate(IntPtr handle); - overflow_callback_delegate overflow_callback_native; - - // FIXME: this should be taken care in more centralized/decent manner... we don't want to write - // this kind of code anywhere we need string marshaling. - List allocated_hglobals = new List(); - - public string Name - { - get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, name_offset)); } - set - { - unsafe - { - var existing = Marshal.ReadIntPtr(handle, name_offset); - if (allocated_hglobals.Contains(existing)) - { - allocated_hglobals.Remove(existing); - Marshal.FreeHGlobal(existing); - } - - var ptr = Marshal.StringToHGlobalAnsi(value); - Marshal.WriteIntPtr(handle, name_offset, ptr); - allocated_hglobals.Add(ptr); - } - } - } - - static readonly int name_offset = (int)Marshal.OffsetOf("name"); - - public bool NonTerminalHint - { - get { return Marshal.ReadInt32(handle, non_terminal_hint_offset) != 0; } - } - - static readonly int non_terminal_hint_offset = (int)Marshal.OffsetOf("non_terminal_hint"); - - public int BytesPerFrame - { - get { return Marshal.ReadInt32(handle, bytes_per_frame_offset); } - } - - static readonly int bytes_per_frame_offset = (int)Marshal.OffsetOf("bytes_per_frame"); - - public int BytesPerSample - { - get { return Marshal.ReadInt32(handle, bytes_per_sample_offset); } - } - - static readonly int bytes_per_sample_offset = (int)Marshal.OffsetOf("bytes_per_sample"); - - public string LayoutErrorMessage - { - get - { - var code = (SoundIoError)Marshal.ReadInt32(handle, layout_error_offset); - - return code == SoundIoError.SoundIoErrorNone ? null : Marshal.PtrToStringAnsi(Natives.soundio_strerror((int)code)); - } - } - - static readonly int layout_error_offset = (int)Marshal.OffsetOf("layout_error"); - - // functions - - public void Open() - { - var ret = (SoundIoError)Natives.soundio_instream_open(handle); - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - } - - public void Start() - { - var ret = (SoundIoError)Natives.soundio_instream_start(handle); - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - } - - public SoundIOChannelAreas BeginRead(ref int frameCount) - { - IntPtr ptrs = default; - int nativeFrameCount = frameCount; - - unsafe - { - var frameCountPtr = &nativeFrameCount; - var ptrptr = &ptrs; - var ret = (SoundIoError)Natives.soundio_instream_begin_read(handle, (IntPtr)ptrptr, (IntPtr)frameCountPtr); - - frameCount = *frameCountPtr; - - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - - return new SoundIOChannelAreas(ptrs, Layout.ChannelCount, frameCount); - } - } - - public void EndRead() - { - var ret = (SoundIoError)Natives.soundio_instream_end_read(handle); - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - } - - public void Pause(bool pause) - { - var ret = (SoundIoError)Natives.soundio_instream_pause(handle, pause); - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - } - - public double GetLatency() - { - unsafe - { - double* dptr = null; - IntPtr p = new IntPtr(dptr); - - var ret = (SoundIoError)Natives.soundio_instream_get_latency(handle, p); - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - - dptr = (double*)p; - - return *dptr; - } - } - } -} diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOOutStream.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOOutStream.cs deleted file mode 100644 index 432ca42b8..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOOutStream.cs +++ /dev/null @@ -1,331 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; - -namespace SoundIOSharp -{ - public class SoundIOOutStream : IDisposable - { - internal SoundIOOutStream (Pointer handle) - { - this.handle = handle; - } - - Pointer handle; - - public void Dispose () - { - Natives.soundio_outstream_destroy (handle); - } - // Equality (based on handle) - - public override bool Equals (object other) - { - var d = other as SoundIOOutStream; - - return d != null && (this.handle == d.handle); - } - - public override int GetHashCode () - { - return (int)(IntPtr)handle; - } - - public static bool operator == (SoundIOOutStream obj1, SoundIOOutStream obj2) - { - return obj1 is null ? obj2 is null : obj1.Equals(obj2); - } - - public static bool operator != (SoundIOOutStream obj1, SoundIOOutStream obj2) - { - return obj1 is null ? obj2 is object : !obj1.Equals(obj2); - } - - // fields - - public SoundIODevice Device - { - get { return new SoundIODevice(Marshal.ReadIntPtr(handle, device_offset)); } - } - - static readonly int device_offset = (int)Marshal.OffsetOf("device"); - - public SoundIOFormat Format - { - get { return (SoundIOFormat) Marshal.ReadInt32(handle, format_offset); } - set { Marshal.WriteInt32(handle, format_offset, (int) value); } - } - - static readonly int format_offset = (int)Marshal.OffsetOf("format"); - - public int SampleRate - { - get { return Marshal.ReadInt32(handle, sample_rate_offset); } - set { Marshal.WriteInt32(handle, sample_rate_offset, value); } - } - - static readonly int sample_rate_offset = (int)Marshal.OffsetOf("sample_rate"); - - public SoundIOChannelLayout Layout - { - get { unsafe { return new SoundIOChannelLayout((IntPtr) (void*)((IntPtr)handle + layout_offset)); } } - set - { - unsafe - { - Buffer.MemoryCopy((void*)value.Handle, (void*)((IntPtr)handle + layout_offset), Marshal.SizeOf(), Marshal.SizeOf()); - } - } - } - static readonly int layout_offset = (int)Marshal.OffsetOf("layout"); - - public double SoftwareLatency - { - get { return MarshalEx.ReadDouble (handle, software_latency_offset); } - set { MarshalEx.WriteDouble (handle, software_latency_offset, value); } - } - - static readonly int software_latency_offset = (int)Marshal.OffsetOf("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("volume"); - - // error_callback - public Action ErrorCallback - { - get { return error_callback; } - set - { - error_callback = value; - if (value == null) - { - error_callback_native = null; - } - else - { - error_callback_native = stream => error_callback(); - } - - var ptr = Marshal.GetFunctionPointerForDelegate(error_callback_native); - Marshal.WriteIntPtr(handle, error_callback_offset, ptr); - } - } - - static readonly int error_callback_offset = (int)Marshal.OffsetOf("error_callback"); - - Action error_callback; - delegate void error_callback_delegate (IntPtr handle); - error_callback_delegate error_callback_native; - - // write_callback - public Action WriteCallback - { - get { return write_callback; } - set - { - write_callback = value; - if (value == null) - { - write_callback_native = null; - } - else - { - write_callback_native = (h, frame_count_min, frame_count_max) => write_callback(frame_count_min, frame_count_max); - } - - var ptr = Marshal.GetFunctionPointerForDelegate (write_callback_native); - Marshal.WriteIntPtr (handle, write_callback_offset, ptr); - } - } - - static readonly int write_callback_offset = (int)Marshal.OffsetOf("write_callback"); - - Action write_callback; - delegate void write_callback_delegate(IntPtr handle, int min, int max); - write_callback_delegate write_callback_native; - - // underflow_callback - public Action UnderflowCallback - { - get { return underflow_callback; } - set - { - underflow_callback = value; - if (value == null) - { - underflow_callback_native = null; - } - else - { - underflow_callback_native = h => underflow_callback(); - } - - var ptr = Marshal.GetFunctionPointerForDelegate (underflow_callback_native); - Marshal.WriteIntPtr (handle, underflow_callback_offset, ptr); - } - } - - static readonly int underflow_callback_offset = (int)Marshal.OffsetOf("underflow_callback"); - - Action underflow_callback; - delegate void underflow_callback_delegate(IntPtr handle); - underflow_callback_delegate underflow_callback_native; - - // FIXME: this should be taken care in more centralized/decent manner... we don't want to write - // this kind of code anywhere we need string marshaling. - List allocated_hglobals = new List(); - - public string Name { - get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, name_offset)); } - set - { - unsafe - { - var existing = Marshal.ReadIntPtr(handle, name_offset); - if (allocated_hglobals.Contains(existing)) - { - allocated_hglobals.Remove(existing); - Marshal.FreeHGlobal(existing); - } - - var ptr = Marshal.StringToHGlobalAnsi(value); - Marshal.WriteIntPtr(handle, name_offset, ptr); - allocated_hglobals.Add(ptr); - } - } - } - - static readonly int name_offset = (int)Marshal.OffsetOf("name"); - - public bool NonTerminalHint - { - get { return Marshal.ReadInt32(handle, non_terminal_hint_offset) != 0; } - } - - static readonly int non_terminal_hint_offset = (int)Marshal.OffsetOf("non_terminal_hint"); - - public int BytesPerFrame - { - get { return Marshal.ReadInt32(handle, bytes_per_frame_offset); } - } - - static readonly int bytes_per_frame_offset = (int)Marshal.OffsetOf("bytes_per_frame"); - - public int BytesPerSample - { - get { return Marshal.ReadInt32(handle, bytes_per_sample_offset); } - } - - static readonly int bytes_per_sample_offset = (int)Marshal.OffsetOf("bytes_per_sample"); - - public string LayoutErrorMessage - { - get - { - var code = (SoundIoError)Marshal.ReadInt32(handle, layout_error_offset); - - return code == SoundIoError.SoundIoErrorNone ? null : Marshal.PtrToStringAnsi(Natives.soundio_strerror((int)code)); - } - } - - static readonly int layout_error_offset = (int)Marshal.OffsetOf ("layout_error"); - - // functions - - public void Open () - { - var ret = (SoundIoError)Natives.soundio_outstream_open(handle); - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - } - - public void Start () - { - var ret = (SoundIoError)Natives.soundio_outstream_start(handle); - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - } - - public SoundIOChannelAreas BeginWrite(ref int frameCount) - { - IntPtr ptrs = default; - int nativeFrameCount = frameCount; - - unsafe - { - var frameCountPtr = &nativeFrameCount; - var ptrptr = &ptrs; - var ret = (SoundIoError)Natives.soundio_outstream_begin_write(handle, (IntPtr)ptrptr, (IntPtr)frameCountPtr); - - frameCount = *frameCountPtr; - - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - - return new SoundIOChannelAreas(ptrs, Layout.ChannelCount, frameCount); - } - } - - public void EndWrite () - { - var ret = (SoundIoError)Natives.soundio_outstream_end_write(handle); - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - } - - public void ClearBuffer () - { - _ = Natives.soundio_outstream_clear_buffer(handle); - } - - public void Pause (bool pause) - { - var ret = (SoundIoError)Natives.soundio_outstream_pause(handle, pause); - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - } - - public double GetLatency () - { - unsafe - { - double* dptr = null; - IntPtr p = new IntPtr(dptr); - - var ret = (SoundIoError)Natives.soundio_outstream_get_latency(handle, p); - if (ret != SoundIoError.SoundIoErrorNone) - { - throw new SoundIOException(ret); - } - - dptr = (double*)p; - - 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); - } - } - } -} diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIORingBuffer.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIORingBuffer.cs deleted file mode 100644 index 7530da72c..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIORingBuffer.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -namespace SoundIOSharp -{ - public class SoundIORingBuffer : IDisposable - { - internal SoundIORingBuffer(IntPtr handle) - { - this.handle = handle; - } - - IntPtr handle; - - public int Capacity - { - get { return Natives.soundio_ring_buffer_capacity(handle); } - } - - public void Clear() - { - Natives.soundio_ring_buffer_clear(handle); - } - - public void Dispose() - { - Natives.soundio_ring_buffer_destroy(handle); - } - - public int FillCount - { - get { return Natives.soundio_ring_buffer_fill_count(handle); } - } - - public int FreeCount - { - get { return Natives.soundio_ring_buffer_free_count(handle); } - } - - public IntPtr ReadPointer - { - get { return Natives.soundio_ring_buffer_read_ptr(handle); } - } - - public IntPtr WritePointer - { - get { return Natives.soundio_ring_buffer_write_ptr(handle); } - } - - public void AdvanceReadPointer(int count) - { - Natives.soundio_ring_buffer_advance_read_ptr(handle, count); - } - - public void AdvanceWritePointer(int count) - { - Natives.soundio_ring_buffer_advance_write_ptr(handle, count); - } - } -} \ No newline at end of file diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOSampleRateRange.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOSampleRateRange.cs deleted file mode 100644 index daf7921b5..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/SoundIOSampleRateRange.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace SoundIOSharp -{ - public readonly struct SoundIOSampleRateRange - { - internal SoundIOSampleRateRange(int min, int max) - { - Min = min; - Max = max; - } - - public readonly int Min; - public readonly int Max; - } -} diff --git a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/libsoundio-interop.cs b/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/libsoundio-interop.cs deleted file mode 100644 index 5377582f3..000000000 --- a/Ryujinx.Audio.Backends.SoundIo/Native/libsoundio/libsoundio-interop.cs +++ /dev/null @@ -1,643 +0,0 @@ -// This source file is generated by nclang PInvokeGenerator. -using System; -using System.Runtime.InteropServices; -using delegate0 = SoundIOSharp.Delegates.delegate0; -using delegate1 = SoundIOSharp.Delegates.delegate1; -using delegate2 = SoundIOSharp.Delegates.delegate2; -using delegate3 = SoundIOSharp.Delegates.delegate3; -using delegate4 = SoundIOSharp.Delegates.delegate4; -using delegate5 = SoundIOSharp.Delegates.delegate5; -using delegate6 = SoundIOSharp.Delegates.delegate6; -using delegate7 = SoundIOSharp.Delegates.delegate7; -using delegate8 = SoundIOSharp.Delegates.delegate8; -using delegate9 = SoundIOSharp.Delegates.delegate9; - -namespace SoundIOSharp -{ - enum SoundIoError // soundio.h (72, 6) - { - SoundIoErrorNone = 0, - SoundIoErrorNoMem = 1, - SoundIoErrorInitAudioBackend = 2, - SoundIoErrorSystemResources = 3, - SoundIoErrorOpeningDevice = 4, - SoundIoErrorNoSuchDevice = 5, - SoundIoErrorInvalid = 6, - SoundIoErrorBackendUnavailable = 7, - SoundIoErrorStreaming = 8, - SoundIoErrorIncompatibleDevice = 9, - SoundIoErrorNoSuchClient = 10, - SoundIoErrorIncompatibleBackend = 11, - SoundIoErrorBackendDisconnected = 12, - SoundIoErrorInterrupted = 13, - SoundIoErrorUnderflow = 14, - SoundIoErrorEncodingString = 15, - } - - enum SoundIoChannelId // soundio.h (106, 6) - { - SoundIoChannelIdInvalid = 0, - SoundIoChannelIdFrontLeft = 1, - SoundIoChannelIdFrontRight = 2, - SoundIoChannelIdFrontCenter = 3, - SoundIoChannelIdLfe = 4, - SoundIoChannelIdBackLeft = 5, - SoundIoChannelIdBackRight = 6, - SoundIoChannelIdFrontLeftCenter = 7, - SoundIoChannelIdFrontRightCenter = 8, - SoundIoChannelIdBackCenter = 9, - SoundIoChannelIdSideLeft = 10, - SoundIoChannelIdSideRight = 11, - SoundIoChannelIdTopCenter = 12, - SoundIoChannelIdTopFrontLeft = 13, - SoundIoChannelIdTopFrontCenter = 14, - SoundIoChannelIdTopFrontRight = 15, - SoundIoChannelIdTopBackLeft = 16, - SoundIoChannelIdTopBackCenter = 17, - SoundIoChannelIdTopBackRight = 18, - SoundIoChannelIdBackLeftCenter = 19, - SoundIoChannelIdBackRightCenter = 20, - SoundIoChannelIdFrontLeftWide = 21, - SoundIoChannelIdFrontRightWide = 22, - SoundIoChannelIdFrontLeftHigh = 23, - SoundIoChannelIdFrontCenterHigh = 24, - SoundIoChannelIdFrontRightHigh = 25, - SoundIoChannelIdTopFrontLeftCenter = 26, - SoundIoChannelIdTopFrontRightCenter = 27, - SoundIoChannelIdTopSideLeft = 28, - SoundIoChannelIdTopSideRight = 29, - SoundIoChannelIdLeftLfe = 30, - SoundIoChannelIdRightLfe = 31, - SoundIoChannelIdLfe2 = 32, - SoundIoChannelIdBottomCenter = 33, - SoundIoChannelIdBottomLeftCenter = 34, - SoundIoChannelIdBottomRightCenter = 35, - SoundIoChannelIdMsMid = 36, - SoundIoChannelIdMsSide = 37, - SoundIoChannelIdAmbisonicW = 38, - SoundIoChannelIdAmbisonicX = 39, - SoundIoChannelIdAmbisonicY = 40, - SoundIoChannelIdAmbisonicZ = 41, - SoundIoChannelIdXyX = 42, - SoundIoChannelIdXyY = 43, - SoundIoChannelIdHeadphonesLeft = 44, - SoundIoChannelIdHeadphonesRight = 45, - SoundIoChannelIdClickTrack = 46, - SoundIoChannelIdForeignLanguage = 47, - SoundIoChannelIdHearingImpaired = 48, - SoundIoChannelIdNarration = 49, - SoundIoChannelIdHaptic = 50, - SoundIoChannelIdDialogCentricMix = 51, - SoundIoChannelIdAux = 52, - SoundIoChannelIdAux0 = 53, - SoundIoChannelIdAux1 = 54, - SoundIoChannelIdAux2 = 55, - SoundIoChannelIdAux3 = 56, - SoundIoChannelIdAux4 = 57, - SoundIoChannelIdAux5 = 58, - SoundIoChannelIdAux6 = 59, - SoundIoChannelIdAux7 = 60, - SoundIoChannelIdAux8 = 61, - SoundIoChannelIdAux9 = 62, - SoundIoChannelIdAux10 = 63, - SoundIoChannelIdAux11 = 64, - SoundIoChannelIdAux12 = 65, - SoundIoChannelIdAux13 = 66, - SoundIoChannelIdAux14 = 67, - SoundIoChannelIdAux15 = 68, - } - - enum SoundIoChannelLayoutId // soundio.h (189, 6) - { - SoundIoChannelLayoutIdMono = 0, - SoundIoChannelLayoutIdStereo = 1, - SoundIoChannelLayoutId2Point1 = 2, - SoundIoChannelLayoutId3Point0 = 3, - SoundIoChannelLayoutId3Point0Back = 4, - SoundIoChannelLayoutId3Point1 = 5, - SoundIoChannelLayoutId4Point0 = 6, - SoundIoChannelLayoutIdQuad = 7, - SoundIoChannelLayoutIdQuadSide = 8, - SoundIoChannelLayoutId4Point1 = 9, - SoundIoChannelLayoutId5Point0Back = 10, - SoundIoChannelLayoutId5Point0Side = 11, - SoundIoChannelLayoutId5Point1 = 12, - SoundIoChannelLayoutId5Point1Back = 13, - SoundIoChannelLayoutId6Point0Side = 14, - SoundIoChannelLayoutId6Point0Front = 15, - SoundIoChannelLayoutIdHexagonal = 16, - SoundIoChannelLayoutId6Point1 = 17, - SoundIoChannelLayoutId6Point1Back = 18, - SoundIoChannelLayoutId6Point1Front = 19, - SoundIoChannelLayoutId7Point0 = 20, - SoundIoChannelLayoutId7Point0Front = 21, - SoundIoChannelLayoutId7Point1 = 22, - SoundIoChannelLayoutId7Point1Wide = 23, - SoundIoChannelLayoutId7Point1WideBack = 24, - SoundIoChannelLayoutIdOctagonal = 25, - } - - enum SoundIoBackend // soundio.h (218, 6) - { - SoundIoBackendNone = 0, - SoundIoBackendJack = 1, - SoundIoBackendPulseAudio = 2, - SoundIoBackendAlsa = 3, - SoundIoBackendCoreAudio = 4, - SoundIoBackendWasapi = 5, - SoundIoBackendDummy = 6, - } - - enum SoundIoDeviceAim // soundio.h (228, 6) - { - SoundIoDeviceAimInput = 0, - SoundIoDeviceAimOutput = 1, - } - - enum SoundIoFormat // soundio.h (235, 6) - { - SoundIoFormatInvalid = 0, - SoundIoFormatS8 = 1, - SoundIoFormatU8 = 2, - SoundIoFormatS16LE = 3, - SoundIoFormatS16BE = 4, - SoundIoFormatU16LE = 5, - SoundIoFormatU16BE = 6, - SoundIoFormatS24LE = 7, - SoundIoFormatS24BE = 8, - SoundIoFormatU24LE = 9, - SoundIoFormatU24BE = 10, - SoundIoFormatS32LE = 11, - SoundIoFormatS32BE = 12, - SoundIoFormatU32LE = 13, - SoundIoFormatU32BE = 14, - SoundIoFormatFloat32LE = 15, - SoundIoFormatFloat32BE = 16, - SoundIoFormatFloat64LE = 17, - SoundIoFormatFloat64BE = 18, - } - - [StructLayout(LayoutKind.Sequential)] - struct SoundIoChannelLayout // soundio.h (306, 8) - { - [CTypeDetails("Pointer")] public System.IntPtr @name; - public int @channel_count; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)] - [CTypeDetails("ConstArrayOf")] public SoundIoChannelId[] @channels; - } - - [StructLayout(LayoutKind.Sequential)] - struct SoundIoSampleRateRange // soundio.h (313, 8) - { - public int @min; - public int @max; - } - - [StructLayout(LayoutKind.Sequential)] - struct SoundIoChannelArea // soundio.h (319, 8) - { - [CTypeDetails("Pointer")] public System.IntPtr @ptr; - public int @step; - } - - [StructLayout(LayoutKind.Sequential)] - struct SoundIo // soundio.h (328, 8) - { - [CTypeDetails("Pointer")] public System.IntPtr @userdata; - [CTypeDetails("Pointer")] public delegate0 @on_devices_change; - [CTypeDetails("Pointer")] public delegate1 @on_backend_disconnect; - [CTypeDetails("Pointer")] public Delegates.delegate0 @on_events_signal; - public SoundIoBackend @current_backend; - [CTypeDetails("Pointer")] public System.IntPtr @app_name; - [CTypeDetails("Pointer")] public delegate2 @emit_rtprio_warning; - [CTypeDetails("Pointer")] public delegate3 @jack_info_callback; - [CTypeDetails("Pointer")] public Delegates.delegate3 @jack_error_callback; - } - - [StructLayout(LayoutKind.Sequential)] - struct SoundIoDevice // soundio.h (387, 8) - { - [CTypeDetails("Pointer")] public System.IntPtr @soundio; - [CTypeDetails("Pointer")] public System.IntPtr @id; - [CTypeDetails("Pointer")] public System.IntPtr @name; - public SoundIoDeviceAim @aim; - [CTypeDetails("Pointer")] public System.IntPtr @layouts; - public int @layout_count; - public SoundIoChannelLayout @current_layout; - [CTypeDetails("Pointer")] public System.IntPtr @formats; - public int @format_count; - public SoundIoFormat @current_format; - [CTypeDetails("Pointer")] public System.IntPtr @sample_rates; - public int @sample_rate_count; - public int @sample_rate_current; - public double @software_latency_min; - public double @software_latency_max; - public double @software_latency_current; - public bool @is_raw; - public int @ref_count; - public int @probe_error; - } - - [StructLayout(LayoutKind.Sequential)] - struct SoundIoOutStream // soundio.h (497, 8) - { - [CTypeDetails("Pointer")] public System.IntPtr @device; - public SoundIoFormat @format; - public int @sample_rate; - public SoundIoChannelLayout @layout; - public double @software_latency; - public float @volume; - [CTypeDetails("Pointer")] public System.IntPtr @userdata; - [CTypeDetails("Pointer")] public delegate4 @write_callback; - [CTypeDetails("Pointer")] public delegate5 @underflow_callback; - [CTypeDetails("Pointer")] public delegate6 @error_callback; - [CTypeDetails("Pointer")] public System.IntPtr @name; - public bool @non_terminal_hint; - public int @bytes_per_frame; - public int @bytes_per_sample; - public int @layout_error; - } - - [StructLayout(LayoutKind.Sequential)] - struct SoundIoInStream // soundio.h (600, 8) - { - [CTypeDetails("Pointer")] public System.IntPtr @device; - public SoundIoFormat @format; - public int @sample_rate; - public SoundIoChannelLayout @layout; - public double @software_latency; - [CTypeDetails("Pointer")] public System.IntPtr @userdata; - [CTypeDetails("Pointer")] public delegate7 @read_callback; - [CTypeDetails("Pointer")] public delegate8 @overflow_callback; - [CTypeDetails("Pointer")] public delegate9 @error_callback; - [CTypeDetails("Pointer")] public System.IntPtr @name; - public bool @non_terminal_hint; - public int @bytes_per_frame; - public int @bytes_per_sample; - public int @layout_error; - } - - [StructLayout(LayoutKind.Sequential)] - struct SoundIoRingBuffer // soundio.h (1170, 8) - { - } - - partial class Natives - { - const string LibraryName = "libsoundio"; - // function soundio_version_string - soundio.h (682, 28) - [DllImport(LibraryName)] - internal static extern System.IntPtr soundio_version_string(); - - // function soundio_version_major - soundio.h (684, 20) - [DllImport(LibraryName)] - internal static extern int soundio_version_major(); - - // function soundio_version_minor - soundio.h (686, 20) - [DllImport(LibraryName)] - internal static extern int soundio_version_minor(); - - // function soundio_version_patch - soundio.h (688, 20) - [DllImport(LibraryName)] - internal static extern int soundio_version_patch(); - - // function soundio_create - soundio.h (694, 32) - [DllImport(LibraryName)] - internal static extern System.IntPtr soundio_create(); - - // function soundio_destroy - soundio.h (695, 21) - [DllImport(LibraryName)] - internal static extern void soundio_destroy([CTypeDetails("Pointer")]System.IntPtr @soundio); - - // function soundio_connect - soundio.h (705, 20) - [DllImport(LibraryName)] - internal static extern int soundio_connect([CTypeDetails("Pointer")]System.IntPtr @soundio); - - // function soundio_connect_backend - soundio.h (717, 20) - [DllImport(LibraryName)] - internal static extern int soundio_connect_backend([CTypeDetails("Pointer")]System.IntPtr @soundio, SoundIoBackend @backend); - - // function soundio_disconnect - soundio.h (718, 21) - [DllImport(LibraryName)] - internal static extern void soundio_disconnect([CTypeDetails("Pointer")]System.IntPtr @soundio); - - // function soundio_strerror - soundio.h (721, 28) - [DllImport(LibraryName)] - internal static extern System.IntPtr soundio_strerror(int @error); - - // 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 (726, 20) - [DllImport(LibraryName)] - internal static extern int soundio_backend_count([CTypeDetails("Pointer")]System.IntPtr @soundio); - - // function soundio_get_backend - soundio.h (729, 36) - [DllImport(LibraryName)] - internal static extern SoundIoBackend soundio_get_backend([CTypeDetails("Pointer")]System.IntPtr @soundio, int @index); - - // 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 (756, 21) - [DllImport(LibraryName)] - internal static extern void soundio_flush_events([CTypeDetails("Pointer")]System.IntPtr @soundio); - - // function soundio_wait_events - soundio.h (760, 21) - [DllImport(LibraryName)] - internal static extern void soundio_wait_events([CTypeDetails("Pointer")]System.IntPtr @soundio); - - // function soundio_wakeup - soundio.h (763, 21) - [DllImport(LibraryName)] - internal static extern void soundio_wakeup([CTypeDetails("Pointer")]System.IntPtr @soundio); - - // function soundio_force_device_scan - soundio.h (780, 21) - [DllImport(LibraryName)] - internal static extern void soundio_force_device_scan([CTypeDetails("Pointer")]System.IntPtr @soundio); - - // function soundio_channel_layout_equal - soundio.h (787, 21) - [DllImport(LibraryName)] - internal static extern bool soundio_channel_layout_equal([CTypeDetails("Pointer")]System.IntPtr @a, [CTypeDetails("Pointer")]System.IntPtr @b); - - // 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 (795, 38) - [DllImport(LibraryName)] - internal static extern SoundIoChannelId soundio_parse_channel_id([CTypeDetails("Pointer")]System.IntPtr @str, int @str_len); - - // 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 (803, 51) - [DllImport(LibraryName)] - internal static extern System.IntPtr soundio_channel_layout_get_builtin(int @index); - - // 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 (809, 20) - [DllImport(LibraryName)] - internal static extern int soundio_channel_layout_find_channel([CTypeDetails("Pointer")]System.IntPtr @layout, SoundIoChannelId @channel); - - // function soundio_channel_layout_detect_builtin - soundio.h (814, 21) - [DllImport(LibraryName)] - internal static extern bool soundio_channel_layout_detect_builtin([CTypeDetails("Pointer")]System.IntPtr @layout); - - // function soundio_best_matching_channel_layout - soundio.h (819, 51) - [DllImport(LibraryName)] - internal static extern System.IntPtr soundio_best_matching_channel_layout([CTypeDetails("Pointer")]System.IntPtr @preferred_layouts, int @preferred_layout_count, [CTypeDetails("Pointer")]System.IntPtr @available_layouts, int @available_layout_count); - - // function soundio_sort_channel_layouts - soundio.h (824, 21) - [DllImport(LibraryName)] - internal static extern void soundio_sort_channel_layouts([CTypeDetails("Pointer")]System.IntPtr @layouts, int @layout_count); - - // 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 (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 (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 (845, 29) - [DllImport(LibraryName)] - internal static extern System.IntPtr soundio_format_string(SoundIoFormat @format); - - // function soundio_input_device_count - soundio.h (861, 20) - [DllImport(LibraryName)] - internal static extern int soundio_input_device_count([CTypeDetails("Pointer")]System.IntPtr @soundio); - - // function soundio_output_device_count - soundio.h (864, 20) - [DllImport(LibraryName)] - internal static extern int soundio_output_device_count([CTypeDetails("Pointer")]System.IntPtr @soundio); - - // function soundio_get_input_device - soundio.h (870, 38) - [DllImport(LibraryName)] - internal static extern System.IntPtr soundio_get_input_device([CTypeDetails("Pointer")]System.IntPtr @soundio, int @index); - - // function soundio_get_output_device - soundio.h (875, 38) - [DllImport(LibraryName)] - internal static extern System.IntPtr soundio_get_output_device([CTypeDetails("Pointer")]System.IntPtr @soundio, int @index); - - // function soundio_default_input_device_index - soundio.h (880, 20) - [DllImport(LibraryName)] - internal static extern int soundio_default_input_device_index([CTypeDetails("Pointer")]System.IntPtr @soundio); - - // function soundio_default_output_device_index - soundio.h (885, 20) - [DllImport(LibraryName)] - internal static extern int soundio_default_output_device_index([CTypeDetails("Pointer")]System.IntPtr @soundio); - - // function soundio_device_ref - soundio.h (888, 21) - [DllImport(LibraryName)] - internal static extern void soundio_device_ref([CTypeDetails("Pointer")]System.IntPtr @device); - - // function soundio_device_unref - soundio.h (891, 21) - [DllImport(LibraryName)] - internal static extern void soundio_device_unref([CTypeDetails("Pointer")]System.IntPtr @device); - - // function soundio_device_equal - soundio.h (895, 21) - [DllImport(LibraryName)] - internal static extern bool soundio_device_equal([CTypeDetails("Pointer")]System.IntPtr @a, [CTypeDetails("Pointer")]System.IntPtr @b); - - // function soundio_device_sort_channel_layouts - soundio.h (900, 21) - [DllImport(LibraryName)] - internal static extern void soundio_device_sort_channel_layouts([CTypeDetails("Pointer")]System.IntPtr @device); - - // function soundio_device_supports_format - soundio.h (904, 21) - [DllImport(LibraryName)] - internal static extern bool soundio_device_supports_format([CTypeDetails("Pointer")]System.IntPtr @device, SoundIoFormat @format); - - // function soundio_device_supports_layout - soundio.h (909, 21) - [DllImport(LibraryName)] - internal static extern bool soundio_device_supports_layout([CTypeDetails("Pointer")]System.IntPtr @device, [CTypeDetails("Pointer")]System.IntPtr @layout); - - // function soundio_device_supports_sample_rate - soundio.h (914, 21) - [DllImport(LibraryName)] - internal static extern bool soundio_device_supports_sample_rate([CTypeDetails("Pointer")]System.IntPtr @device, int @sample_rate); - - // function soundio_device_nearest_sample_rate - soundio.h (919, 20) - [DllImport(LibraryName)] - internal static extern int soundio_device_nearest_sample_rate([CTypeDetails("Pointer")]System.IntPtr @device, int @sample_rate); - - // function soundio_outstream_create - soundio.h (929, 41) - [DllImport(LibraryName)] - internal static extern System.IntPtr soundio_outstream_create([CTypeDetails("Pointer")]System.IntPtr @device); - - // function soundio_outstream_destroy - soundio.h (931, 21) - [DllImport(LibraryName)] - internal static extern void soundio_outstream_destroy([CTypeDetails("Pointer")]System.IntPtr @outstream); - - // function soundio_outstream_open - soundio.h (954, 20) - [DllImport(LibraryName)] - internal static extern int soundio_outstream_open([CTypeDetails("Pointer")]System.IntPtr @outstream); - - // function soundio_outstream_start - soundio.h (965, 20) - [DllImport(LibraryName)] - internal static extern int soundio_outstream_start([CTypeDetails("Pointer")]System.IntPtr @outstream); - - // function soundio_outstream_begin_write - soundio.h (997, 20) - [DllImport(LibraryName)] - internal static extern int soundio_outstream_begin_write([CTypeDetails("Pointer")]System.IntPtr @outstream, [CTypeDetails("Pointer")]System.IntPtr @areas, [CTypeDetails("Pointer")]System.IntPtr @frame_count); - - // function soundio_outstream_end_write - soundio.h (1009, 20) - [DllImport(LibraryName)] - internal static extern int soundio_outstream_end_write([CTypeDetails("Pointer")]System.IntPtr @outstream); - - // function soundio_outstream_clear_buffer - soundio.h (1024, 20) - [DllImport(LibraryName)] - internal static extern int soundio_outstream_clear_buffer([CTypeDetails("Pointer")]System.IntPtr @outstream); - - // function soundio_outstream_pause - soundio.h (1045, 20) - [DllImport(LibraryName)] - internal static extern int soundio_outstream_pause([CTypeDetails("Pointer")]System.IntPtr @outstream, bool @pause); - - // function soundio_outstream_get_latency - soundio.h (1058, 20) - [DllImport(LibraryName)] - internal static extern int soundio_outstream_get_latency([CTypeDetails("Pointer")]System.IntPtr @outstream, [CTypeDetails("Pointer")]System.IntPtr @out_latency); - - // function soundio_outstream_set_volume - soundio.h (1061, 20) - [DllImport(LibraryName)] - internal static extern int soundio_outstream_set_volume([CTypeDetails("Pointer")]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")]System.IntPtr @device); - - // function soundio_instream_destroy - soundio.h (1073, 21) - [DllImport(LibraryName)] - internal static extern void soundio_instream_destroy([CTypeDetails("Pointer")]System.IntPtr @instream); - - // function soundio_instream_open - soundio.h (1093, 20) - [DllImport(LibraryName)] - internal static extern int soundio_instream_open([CTypeDetails("Pointer")]System.IntPtr @instream); - - // function soundio_instream_start - soundio.h (1102, 20) - [DllImport(LibraryName)] - internal static extern int soundio_instream_start([CTypeDetails("Pointer")]System.IntPtr @instream); - - // function soundio_instream_begin_read - soundio.h (1133, 20) - [DllImport(LibraryName)] - internal static extern int soundio_instream_begin_read([CTypeDetails("Pointer")]System.IntPtr @instream, [CTypeDetails("Pointer")]System.IntPtr @areas, [CTypeDetails("Pointer")]System.IntPtr @frame_count); - - // function soundio_instream_end_read - soundio.h (1143, 20) - [DllImport(LibraryName)] - internal static extern int soundio_instream_end_read([CTypeDetails("Pointer")]System.IntPtr @instream); - - // function soundio_instream_pause - soundio.h (1156, 20) - [DllImport(LibraryName)] - internal static extern int soundio_instream_pause([CTypeDetails("Pointer")]System.IntPtr @instream, bool @pause); - - // function soundio_instream_get_latency - soundio.h (1166, 20) - [DllImport(LibraryName)] - internal static extern int soundio_instream_get_latency([CTypeDetails("Pointer")]System.IntPtr @instream, [CTypeDetails("Pointer")]System.IntPtr @out_latency); - - // function soundio_ring_buffer_create - soundio.h (1181, 42) - [DllImport(LibraryName)] - internal static extern System.IntPtr soundio_ring_buffer_create([CTypeDetails("Pointer")]System.IntPtr @soundio, int @requested_capacity); - - // function soundio_ring_buffer_destroy - soundio.h (1182, 21) - [DllImport(LibraryName)] - internal static extern void soundio_ring_buffer_destroy([CTypeDetails("Pointer")]System.IntPtr @ring_buffer); - - // function soundio_ring_buffer_capacity - soundio.h (1186, 20) - [DllImport(LibraryName)] - internal static extern int soundio_ring_buffer_capacity([CTypeDetails("Pointer")]System.IntPtr @ring_buffer); - - // function soundio_ring_buffer_write_ptr - soundio.h (1189, 22) - [DllImport(LibraryName)] - internal static extern System.IntPtr soundio_ring_buffer_write_ptr([CTypeDetails("Pointer")]System.IntPtr @ring_buffer); - - // 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")]System.IntPtr @ring_buffer, int @count); - - // function soundio_ring_buffer_read_ptr - soundio.h (1194, 22) - [DllImport(LibraryName)] - internal static extern System.IntPtr soundio_ring_buffer_read_ptr([CTypeDetails("Pointer")]System.IntPtr @ring_buffer); - - // 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")]System.IntPtr @ring_buffer, int @count); - - // function soundio_ring_buffer_fill_count - soundio.h (1199, 20) - [DllImport(LibraryName)] - internal static extern int soundio_ring_buffer_fill_count([CTypeDetails("Pointer")]System.IntPtr @ring_buffer); - - // function soundio_ring_buffer_free_count - soundio.h (1202, 20) - [DllImport(LibraryName)] - internal static extern int soundio_ring_buffer_free_count([CTypeDetails("Pointer")]System.IntPtr @ring_buffer); - - // function soundio_ring_buffer_clear - soundio.h (1205, 21) - [DllImport(LibraryName)] - internal static extern void soundio_ring_buffer_clear([CTypeDetails("Pointer")]System.IntPtr @ring_buffer); - - } - - class Delegates - { - public delegate void delegate0(System.IntPtr p0); - public delegate void delegate1(System.IntPtr p0, int p1); - public delegate void delegate2(); - public delegate void delegate3(System.IntPtr p0); - public delegate void delegate4(System.IntPtr p0, int p1, int p2); - public delegate void delegate5(System.IntPtr p0); - public delegate void delegate6(System.IntPtr p0, int p1); - public delegate void delegate7(System.IntPtr p0, int p1, int p2); - public delegate void delegate8(System.IntPtr p0); - public delegate void delegate9(System.IntPtr p0, int p1); - } - - public struct Pointer - { - public IntPtr Handle; - public static implicit operator IntPtr(Pointer value) { return value.Handle; } - public static implicit operator Pointer(IntPtr value) { return new Pointer(value); } - - public Pointer(IntPtr handle) - { - Handle = handle; - } - - public override bool Equals(object obj) - { - return obj is Pointer && this == (Pointer)obj; - } - - public override int GetHashCode() - { - return (int)Handle; - } - - public static bool operator ==(Pointer p1, Pointer p2) - { - return p1.Handle == p2.Handle; - } - - public static bool operator !=(Pointer p1, Pointer p2) - { - return p1.Handle != p2.Handle; - } - } - public struct ArrayOf { } - public struct ConstArrayOf { } - public class CTypeDetailsAttribute : Attribute - { - public CTypeDetailsAttribute(string value) - { - Value = value; - } - - public string Value { get; set; } - } - -} diff --git a/Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceDriver.cs b/Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceDriver.cs index 02a9a2287..2eab59086 100644 --- a/Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceDriver.cs +++ b/Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceDriver.cs @@ -1,19 +1,20 @@ -using Ryujinx.Audio.Common; +using Ryujinx.Audio.Backends.SoundIo.Native; +using Ryujinx.Audio.Common; using Ryujinx.Audio.Integration; using Ryujinx.Memory; -using SoundIOSharp; using System; using System.Collections.Concurrent; using System.Threading; using static Ryujinx.Audio.Integration.IHardwareDeviceDriver; +using static Ryujinx.Audio.Backends.SoundIo.Native.SoundIo; namespace Ryujinx.Audio.Backends.SoundIo { public class SoundIoHardwareDeviceDriver : IHardwareDeviceDriver { - private readonly SoundIO _audioContext; - private readonly SoundIODevice _audioDevice; + private readonly SoundIoContext _audioContext; + private readonly SoundIoDeviceContext _audioDevice; private readonly ManualResetEvent _updateRequiredEvent; private readonly ManualResetEvent _pauseEvent; private readonly ConcurrentDictionary _sessions; @@ -21,7 +22,7 @@ namespace Ryujinx.Audio.Backends.SoundIo public SoundIoHardwareDeviceDriver() { - _audioContext = new SoundIO(); + _audioContext = SoundIoContext.Create(); _updateRequiredEvent = new ManualResetEvent(false); _pauseEvent = new ManualResetEvent(true); _sessions = new ConcurrentDictionary(); @@ -29,24 +30,23 @@ namespace Ryujinx.Audio.Backends.SoundIo _audioContext.Connect(); _audioContext.FlushEvents(); - _audioDevice = FindNonRawDefaultAudioDevice(_audioContext, true); + _audioDevice = FindValidAudioDevice(_audioContext, true); } public static bool IsSupported => IsSupportedInternal(); private static bool IsSupportedInternal() { - SoundIO context = null; - SoundIODevice device = null; - SoundIOOutStream stream = null; + SoundIoContext context = null; + SoundIoDeviceContext device = null; + SoundIoOutStreamContext stream = null; bool backendDisconnected = false; try { - context = new SoundIO(); - - context.OnBackendDisconnect = (i) => + context = SoundIoContext.Create(); + context.OnBackendDisconnect = err => { backendDisconnected = true; }; @@ -64,7 +64,7 @@ namespace Ryujinx.Audio.Backends.SoundIo return false; } - device = FindNonRawDefaultAudioDevice(context); + device = FindValidAudioDevice(context); if (device == null || backendDisconnected) { @@ -86,30 +86,23 @@ namespace Ryujinx.Audio.Backends.SoundIo } finally { - if (stream != null) - { - stream.Dispose(); - } - - if (context != null) - { - context.Dispose(); - } + stream?.Dispose(); + context?.Dispose(); } } - private static SoundIODevice FindNonRawDefaultAudioDevice(SoundIO audioContext, bool fallback = false) + private static SoundIoDeviceContext FindValidAudioDevice(SoundIoContext audioContext, bool fallback = false) { - SoundIODevice defaultAudioDevice = audioContext.GetOutputDevice(audioContext.DefaultOutputDeviceIndex); + SoundIoDeviceContext defaultAudioDevice = audioContext.GetOutputDevice(audioContext.DefaultOutputDeviceIndex); if (!defaultAudioDevice.IsRaw) { return defaultAudioDevice; } - for (int i = 0; i < audioContext.BackendCount; i++) + for (int i = 0; i < audioContext.OutputDeviceCount; i++) { - SoundIODevice audioDevice = audioContext.GetOutputDevice(i); + SoundIoDeviceContext audioDevice = audioContext.GetOutputDevice(i); if (audioDevice.Id == defaultAudioDevice.Id && !audioDevice.IsRaw) { @@ -161,22 +154,22 @@ namespace Ryujinx.Audio.Backends.SoundIo return _sessions.TryRemove(session, out _); } - public static SoundIOFormat GetSoundIoFormat(SampleFormat format) + public static SoundIoFormat GetSoundIoFormat(SampleFormat format) { return format switch { - SampleFormat.PcmInt8 => SoundIOFormat.S8, - SampleFormat.PcmInt16 => SoundIOFormat.S16LE, - SampleFormat.PcmInt24 => SoundIOFormat.S24LE, - SampleFormat.PcmInt32 => SoundIOFormat.S32LE, - SampleFormat.PcmFloat => SoundIOFormat.Float32LE, + SampleFormat.PcmInt8 => SoundIoFormat.S8, + SampleFormat.PcmInt16 => SoundIoFormat.S16LE, + SampleFormat.PcmInt24 => SoundIoFormat.S24LE, + SampleFormat.PcmInt32 => SoundIoFormat.S32LE, + SampleFormat.PcmFloat => SoundIoFormat.Float32LE, _ => throw new ArgumentException ($"Unsupported sample format {format}"), }; } - internal SoundIOOutStream OpenStream(SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount) + internal SoundIoOutStreamContext OpenStream(SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount) { - SoundIOFormat driverSampleFormat = GetSoundIoFormat(requestedSampleFormat); + SoundIoFormat driverSampleFormat = GetSoundIoFormat(requestedSampleFormat); if (!_audioDevice.SupportsSampleRate((int)requestedSampleRate)) { @@ -193,10 +186,10 @@ namespace Ryujinx.Audio.Backends.SoundIo throw new ArgumentException($"This sound device does not support channel count {requestedChannelCount}"); } - SoundIOOutStream result = _audioDevice.CreateOutStream(); + SoundIoOutStreamContext result = _audioDevice.CreateOutStream(); result.Name = "Ryujinx"; - result.Layout = SoundIOChannelLayout.GetDefault((int)requestedChannelCount); + result.Layout = SoundIoChannelLayout.GetDefaultValue((int)requestedChannelCount); result.Format = driverSampleFormat; result.SampleRate = (int)requestedSampleRate; diff --git a/Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceSession.cs b/Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceSession.cs index 1e8c814e5..96d9ce970 100644 --- a/Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceSession.cs +++ b/Ryujinx.Audio.Backends.SoundIo/SoundIoHardwareDeviceSession.cs @@ -1,11 +1,12 @@ using Ryujinx.Audio.Backends.Common; +using Ryujinx.Audio.Backends.SoundIo.Native; using Ryujinx.Audio.Common; using Ryujinx.Memory; -using SoundIOSharp; using System; using System.Collections.Concurrent; using System.Runtime.CompilerServices; using System.Threading; +using static Ryujinx.Audio.Backends.SoundIo.Native.SoundIo; namespace Ryujinx.Audio.Backends.SoundIo { @@ -13,7 +14,7 @@ namespace Ryujinx.Audio.Backends.SoundIo { private SoundIoHardwareDeviceDriver _driver; private ConcurrentQueue _queuedBuffers; - private SoundIOOutStream _outputStream; + private SoundIoOutStreamContext _outputStream; private DynamicRingBuffer _ringBuffer; private ulong _playedSampleCount; private ManualResetEvent _updateRequiredEvent; @@ -106,9 +107,9 @@ namespace Ryujinx.Audio.Backends.SoundIo return; } - SoundIOChannelAreas areas = _outputStream.BeginWrite(ref frameCount); + Span areas = _outputStream.BeginWrite(ref frameCount); - int channelCount = areas.ChannelCount; + int channelCount = areas.Length; byte[] samples = new byte[frameCount * bytesPerFrame]; @@ -117,12 +118,12 @@ namespace Ryujinx.Audio.Backends.SoundIo // This is a huge ugly block of code, but we save // a significant amount of time over the generic // loop that handles other channel counts. - // TODO: Is this still right in 2021? + // TODO: Is this still right in 2022? // Mono if (channelCount == 1) { - SoundIOChannelArea area = areas.GetArea(0); + ref SoundIoChannelArea area = ref areas[0]; fixed (byte* srcptr = samples) { @@ -167,8 +168,8 @@ namespace Ryujinx.Audio.Backends.SoundIo // Stereo else if (channelCount == 2) { - SoundIOChannelArea area1 = areas.GetArea(0); - SoundIOChannelArea area2 = areas.GetArea(1); + ref SoundIoChannelArea area1 = ref areas[0]; + ref SoundIoChannelArea area2 = ref areas[1]; fixed (byte* srcptr = samples) { @@ -233,12 +234,12 @@ namespace Ryujinx.Audio.Backends.SoundIo // Surround else if (channelCount == 6) { - SoundIOChannelArea area1 = areas.GetArea(0); - SoundIOChannelArea area2 = areas.GetArea(1); - SoundIOChannelArea area3 = areas.GetArea(2); - SoundIOChannelArea area4 = areas.GetArea(3); - SoundIOChannelArea area5 = areas.GetArea(4); - SoundIOChannelArea area6 = areas.GetArea(5); + ref SoundIoChannelArea area1 = ref areas[0]; + ref SoundIoChannelArea area2 = ref areas[1]; + ref SoundIoChannelArea area3 = ref areas[2]; + ref SoundIoChannelArea area4 = ref areas[3]; + ref SoundIoChannelArea area5 = ref areas[4]; + ref SoundIoChannelArea area6 = ref areas[5]; fixed (byte* srcptr = samples) { @@ -367,24 +368,18 @@ namespace Ryujinx.Audio.Backends.SoundIo // Every other channel count else { - SoundIOChannelArea[] channels = new SoundIOChannelArea[channelCount]; - - // Obtain the channel area for each channel - for (int i = 0; i < channelCount; i++) - { - channels[i] = areas.GetArea(i); - } - fixed (byte* srcptr = samples) { for (int frame = 0; frame < frameCount; frame++) - for (int channel = 0; channel < areas.ChannelCount; channel++) + { + for (int channel = 0; channel < areas.Length; channel++) { // Copy channel by channel, frame by frame. This is slow! - Unsafe.CopyBlockUnaligned((byte*)channels[channel].Pointer, srcptr + (frame * bytesPerFrame) + (channel * bytesPerSample), bytesPerSample); + Unsafe.CopyBlockUnaligned((byte*)areas[channel].Pointer, srcptr + (frame * bytesPerFrame) + (channel * bytesPerSample), bytesPerSample); - channels[channel].Pointer += channels[channel].Step; + areas[channel].Pointer += areas[channel].Step; } + } } } diff --git a/Ryujinx.Ava/AppHost.cs b/Ryujinx.Ava/AppHost.cs index a016ebd5a..0cb3bd138 100644 --- a/Ryujinx.Ava/AppHost.cs +++ b/Ryujinx.Ava/AppHost.cs @@ -125,7 +125,7 @@ namespace Ryujinx.Ava _inputManager = inputManager; _accountManager = accountManager; _userChannelPersistence = userChannelPersistence; - _renderingThread = new Thread(RenderLoop) { Name = "GUI.RenderThread" }; + _renderingThread = new Thread(RenderLoop, 1 * 1024 * 1024) { Name = "GUI.RenderThread" }; _hideCursorOnIdle = ConfigurationState.Instance.HideCursorOnIdle; _lastCursorMoveTime = Stopwatch.GetTimestamp(); _glLogLevel = ConfigurationState.Instance.Logger.GraphicsDebugLevel; diff --git a/Ryujinx.Ava/Assets/Locales/en_US.json b/Ryujinx.Ava/Assets/Locales/en_US.json index aa49a78f0..a0507e7f1 100644 --- a/Ryujinx.Ava/Assets/Locales/en_US.json +++ b/Ryujinx.Ava/Assets/Locales/en_US.json @@ -280,7 +280,7 @@ "ControllerSettingsRemoveProfileToolTip": "Remove Profile", "ControllerSettingsSaveProfileToolTip": "Save Profile", "MenuBarFileToolsTakeScreenshot": "Take Screenshot", - "MenuBarFileToolsHideUi": "Hide Ui", + "MenuBarFileToolsHideUi": "Hide UI", "GameListContextMenuToggleFavorite": "Toggle Favorite", "GameListContextMenuToggleFavoriteToolTip": "Toggle Favorite status of Game", "SettingsTabGeneralTheme": "Theme", @@ -315,7 +315,7 @@ "DialogUpdaterConvertFailedMessage": "Failed to convert the current Ryujinx version.", "DialogUpdaterCancelUpdateMessage": "Cancelling Update!", "DialogUpdaterAlreadyOnLatestVersionMessage": "You are already using the most updated version of Ryujinx!", - "DialogUpdaterFailedToGetVersionMessage": "An error has occurred when trying to get release information from Github Release. This can be caused if a new release is being compiled by GitHub Actions. Try again in a few minutes.", + "DialogUpdaterFailedToGetVersionMessage": "An error has occurred when trying to get release information from GitHub Release. This can be caused if a new release is being compiled by GitHub Actions. Try again in a few minutes.", "DialogUpdaterConvertFailedGithubMessage": "Failed to convert the received Ryujinx version from Github Release.", "DialogUpdaterDownloadingMessage": "Downloading Update...", "DialogUpdaterExtractionMessage": "Extracting Update...", diff --git a/Ryujinx.Ava/Assets/Styles/Styles.xaml b/Ryujinx.Ava/Assets/Styles/Styles.xaml index 8f7c2e73c..de965a2a0 100644 --- a/Ryujinx.Ava/Assets/Styles/Styles.xaml +++ b/Ryujinx.Ava/Assets/Styles/Styles.xaml @@ -161,6 +161,7 @@ + diff --git a/Ryujinx.Ava/Ui/Controls/VulkanEmbeddedWindow.cs b/Ryujinx.Ava/Ui/Controls/VulkanEmbeddedWindow.cs index 236a0a166..b9c5f75f5 100644 --- a/Ryujinx.Ava/Ui/Controls/VulkanEmbeddedWindow.cs +++ b/Ryujinx.Ava/Ui/Controls/VulkanEmbeddedWindow.cs @@ -3,6 +3,7 @@ using Ryujinx.Ava.Ui.Controls; using Silk.NET.Vulkan; using SPB.Graphics.Vulkan; using SPB.Platform.GLX; +using SPB.Platform.Metal; using SPB.Platform.Win32; using SPB.Platform.X11; using SPB.Windowing; @@ -37,6 +38,10 @@ namespace Ryujinx.Ava.Ui { _window = new SimpleX11Window(new NativeHandle(X11Display), new NativeHandle(WindowHandle)); } + else if (OperatingSystem.IsMacOS()) + { + _window = new SimpleMetalWindow(new NativeHandle(NsView), new NativeHandle(MetalLayer)); + } else { throw new PlatformNotSupportedException(); diff --git a/Ryujinx.Ava/Ui/ViewModels/ControllerSettingsViewModel.cs b/Ryujinx.Ava/Ui/ViewModels/ControllerSettingsViewModel.cs index 8d0124437..c76903168 100644 --- a/Ryujinx.Ava/Ui/ViewModels/ControllerSettingsViewModel.cs +++ b/Ryujinx.Ava/Ui/ViewModels/ControllerSettingsViewModel.cs @@ -545,7 +545,7 @@ namespace Ryujinx.Ava.Ui.ViewModels config = new StandardKeyboardInputConfig { - Version = Ryujinx.Common.Configuration.Hid.InputConfig.CurrentVersion, + Version = InputConfig.CurrentVersion, Backend = InputBackendType.WindowKeyboard, Id = id, ControllerType = ControllerType.ProController, @@ -600,7 +600,7 @@ namespace Ryujinx.Ava.Ui.ViewModels config = new StandardControllerInputConfig { - Version = Ryujinx.Common.Configuration.Hid.InputConfig.CurrentVersion, + Version = InputConfig.CurrentVersion, Backend = InputBackendType.GamepadSDL2, Id = id, ControllerType = ControllerType.ProController, diff --git a/Ryujinx.Ava/Ui/ViewModels/SettingsViewModel.cs b/Ryujinx.Ava/Ui/ViewModels/SettingsViewModel.cs index bd4a55e8f..c752697b9 100644 --- a/Ryujinx.Ava/Ui/ViewModels/SettingsViewModel.cs +++ b/Ryujinx.Ava/Ui/ViewModels/SettingsViewModel.cs @@ -108,6 +108,8 @@ namespace Ryujinx.Ava.Ui.ViewModels } } + public bool IsOpenGLAvailable => !OperatingSystem.IsMacOS(); + public bool DirectoryChanged { get => _directoryChanged; diff --git a/Ryujinx.Ava/Ui/Windows/ControllerSettingsWindow.axaml.cs b/Ryujinx.Ava/Ui/Windows/ControllerSettingsWindow.axaml.cs index 82ef75ca5..8f2afc1dc 100644 --- a/Ryujinx.Ava/Ui/Windows/ControllerSettingsWindow.axaml.cs +++ b/Ryujinx.Ava/Ui/Windows/ControllerSettingsWindow.axaml.cs @@ -104,11 +104,11 @@ namespace Ryujinx.Ava.Ui.Windows var device = ViewModel.Devices[ViewModel.Device]; - if (device.Type == Models.DeviceType.Keyboard) + if (device.Type == DeviceType.Keyboard) { assigner = new KeyboardKeyAssigner((IKeyboard)ViewModel.SelectedGamepad); } - else if (device.Type == Models.DeviceType.Controller) + else if (device.Type == DeviceType.Controller) { assigner = new GamepadButtonAssigner(ViewModel.SelectedGamepad, (ViewModel.Config as StandardControllerInputConfig).TriggerThreshold, forStick); } diff --git a/Ryujinx.Ava/Ui/Windows/MainWindow.axaml b/Ryujinx.Ava/Ui/Windows/MainWindow.axaml index 5aa38418c..387587b62 100644 --- a/Ryujinx.Ava/Ui/Windows/MainWindow.axaml +++ b/Ryujinx.Ava/Ui/Windows/MainWindow.axaml @@ -12,9 +12,9 @@ xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows" Title="Ryujinx" Width="1280" - Height="785" + Height="777" MinWidth="1092" - MinHeight="680" + MinHeight="672" d:DesignHeight="720" d:DesignWidth="1280" x:CompileBindings="True" @@ -552,9 +552,8 @@ @@ -610,14 +609,14 @@ @@ -644,7 +643,7 @@ @@ -660,13 +659,13 @@ @@ -711,7 +711,7 @@ @@ -725,7 +725,7 @@ @@ -739,7 +739,7 @@ @@ -753,7 +753,7 @@ diff --git a/Ryujinx.Ava/Ui/Windows/MainWindow.axaml.cs b/Ryujinx.Ava/Ui/Windows/MainWindow.axaml.cs index a9da8d7d0..33c35c7e0 100644 --- a/Ryujinx.Ava/Ui/Windows/MainWindow.axaml.cs +++ b/Ryujinx.Ava/Ui/Windows/MainWindow.axaml.cs @@ -154,6 +154,12 @@ namespace Ryujinx.Ava.Ui.Windows } } + protected override void HandleScalingChanged(double scale) + { + Program.DesktopScaleFactor = scale; + base.HandleScalingChanged(scale); + } + public void Application_Opened(object sender, ApplicationOpenedEventArgs args) { if (args.Application != null) diff --git a/Ryujinx.Ava/Ui/Windows/SettingsWindow.axaml b/Ryujinx.Ava/Ui/Windows/SettingsWindow.axaml index c8c9f59a8..bd3dd613e 100644 --- a/Ryujinx.Ava/Ui/Windows/SettingsWindow.axaml +++ b/Ryujinx.Ava/Ui/Windows/SettingsWindow.axaml @@ -540,7 +540,7 @@ - + diff --git a/Ryujinx.Common/Configuration/AppDataManager.cs b/Ryujinx.Common/Configuration/AppDataManager.cs index 1d217f587..42b76453b 100644 --- a/Ryujinx.Common/Configuration/AppDataManager.cs +++ b/Ryujinx.Common/Configuration/AppDataManager.cs @@ -45,7 +45,14 @@ namespace Ryujinx.Common.Configuration public static void Initialize(string baseDirPath) { - string userProfilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), DefaultBaseDir); + string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + + if (appDataPath.Length == 0) + { + appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + } + + string userProfilePath = Path.Combine(appDataPath, DefaultBaseDir); string portablePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, DefaultPortableDir); if (Directory.Exists(portablePath)) diff --git a/Ryujinx.Common/GraphicsDriver/NVThreadedOptimization.cs b/Ryujinx.Common/GraphicsDriver/NVThreadedOptimization.cs index ad2236310..d21d35555 100644 --- a/Ryujinx.Common/GraphicsDriver/NVThreadedOptimization.cs +++ b/Ryujinx.Common/GraphicsDriver/NVThreadedOptimization.cs @@ -152,7 +152,7 @@ namespace Ryujinx.Common.GraphicsDriver if (ptr != IntPtr.Zero) { - return Marshal.GetDelegateForFunctionPointer(ptr, typeof(T)) as T; + return Marshal.GetDelegateForFunctionPointer(ptr); } else { diff --git a/Ryujinx.Common/Memory/PartialUnmaps/NativeReaderWriterLock.cs b/Ryujinx.Common/Memory/PartialUnmaps/NativeReaderWriterLock.cs index 5419b3405..78eeb16fb 100644 --- a/Ryujinx.Common/Memory/PartialUnmaps/NativeReaderWriterLock.cs +++ b/Ryujinx.Common/Memory/PartialUnmaps/NativeReaderWriterLock.cs @@ -8,7 +8,7 @@ namespace Ryujinx.Common.Memory.PartialUnmaps /// /// A simple implementation of a ReaderWriterLock which can be used from native code. /// - [StructLayout(LayoutKind.Sequential, Pack = 1)] + [StructLayout(LayoutKind.Sequential, Pack = 4)] public struct NativeReaderWriterLock { public int WriteLock; diff --git a/Ryujinx.Common/Ryujinx.Common.csproj b/Ryujinx.Common/Ryujinx.Common.csproj index fbf069b0c..9a83c2b4b 100644 --- a/Ryujinx.Common/Ryujinx.Common.csproj +++ b/Ryujinx.Common/Ryujinx.Common.csproj @@ -7,7 +7,6 @@ - diff --git a/Ryujinx.Common/System/ForceDpiAware.cs b/Ryujinx.Common/System/ForceDpiAware.cs index d40d5f5e6..8d19876e8 100644 --- a/Ryujinx.Common/System/ForceDpiAware.cs +++ b/Ryujinx.Common/System/ForceDpiAware.cs @@ -1,6 +1,5 @@ using Ryujinx.Common.Logging; using System; -using System.Drawing; using System.Globalization; using System.Runtime.InteropServices; @@ -51,7 +50,7 @@ namespace Ryujinx.Common.System { if (OperatingSystem.IsWindows()) { - userDpiScale = Graphics.FromHwnd(IntPtr.Zero).DpiX; + userDpiScale = GdiPlusHelper.GetDpiX(IntPtr.Zero); } else if (OperatingSystem.IsLinux()) { diff --git a/Ryujinx.Common/System/GdiPlusHelper.cs b/Ryujinx.Common/System/GdiPlusHelper.cs new file mode 100644 index 000000000..c084c6510 --- /dev/null +++ b/Ryujinx.Common/System/GdiPlusHelper.cs @@ -0,0 +1,76 @@ +using System; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; + +namespace Ryujinx.Common.System +{ + [SupportedOSPlatform("windows")] + public static class GdiPlusHelper + { + private const string LibraryName = "gdiplus.dll"; + + private static readonly IntPtr _initToken; + + static GdiPlusHelper() + { + CheckStatus(GdiplusStartup(out _initToken, StartupInputEx.Default, out _)); + } + + private static void CheckStatus(int gdiStatus) + { + if (gdiStatus != 0) + { + throw new Exception($"GDI Status Error: {gdiStatus}"); + } + } + + private struct StartupInputEx + { + public int GdiplusVersion; + +#pragma warning disable CS0649 + public IntPtr DebugEventCallback; + public int SuppressBackgroundThread; + public int SuppressExternalCodecs; + public int StartupParameters; +#pragma warning restore CS0649 + + public static StartupInputEx Default => new StartupInputEx + { + // We assume Windows 8 and upper + GdiplusVersion = 2, + DebugEventCallback = IntPtr.Zero, + SuppressBackgroundThread = 0, + SuppressExternalCodecs = 0, + StartupParameters = 0, + }; + } + + private struct StartupOutput + { + public IntPtr NotificationHook; + public IntPtr NotificationUnhook; + } + + [DllImport(LibraryName)] + private static extern int GdiplusStartup(out IntPtr token, in StartupInputEx input, out StartupOutput output); + + [DllImport(LibraryName)] + private static extern int GdipCreateFromHWND(IntPtr hwnd, out IntPtr graphics); + + [DllImport(LibraryName)] + private static extern int GdipDeleteGraphics(IntPtr graphics); + + [DllImport(LibraryName)] + private static extern int GdipGetDpiX(IntPtr graphics, out float dpi); + + public static float GetDpiX(IntPtr hwnd) + { + CheckStatus(GdipCreateFromHWND(hwnd, out IntPtr graphicsHandle)); + CheckStatus(GdipGetDpiX(graphicsHandle, out float result)); + CheckStatus(GdipDeleteGraphics(graphicsHandle)); + + return result; + } + } +} diff --git a/Ryujinx.Common/SystemInfo/WindowsSystemInfo.cs b/Ryujinx.Common/SystemInfo/WindowsSystemInfo.cs index ed301e021..ffce665e2 100644 --- a/Ryujinx.Common/SystemInfo/WindowsSystemInfo.cs +++ b/Ryujinx.Common/SystemInfo/WindowsSystemInfo.cs @@ -60,7 +60,7 @@ namespace Ryujinx.Common.SystemInfo public MemoryStatusEx() { - Length = (uint)Marshal.SizeOf(typeof(MemoryStatusEx)); + Length = (uint)Marshal.SizeOf(); } } diff --git a/Ryujinx.Graphics.Device/DeviceState.cs b/Ryujinx.Graphics.Device/DeviceState.cs index 181005715..a9b446e18 100644 --- a/Ryujinx.Graphics.Device/DeviceState.cs +++ b/Ryujinx.Graphics.Device/DeviceState.cs @@ -1,12 +1,13 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace Ryujinx.Graphics.Device { - public class DeviceState : IDeviceState where TState : unmanaged + public class DeviceState<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] TState> : IDeviceState where TState : unmanaged { private const int RegisterSize = sizeof(int); diff --git a/Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs b/Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs index b2799e099..497693296 100644 --- a/Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs +++ b/Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs @@ -50,186 +50,186 @@ namespace Ryujinx.Graphics.GAL.Multithreading private static void InitLookup() { - _lookup[(int)CommandType.Action] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.Action] = (memory, threaded, renderer) => ActionCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.CreateBuffer] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.CreateBuffer] = (memory, threaded, renderer) => CreateBufferCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.CreateProgram] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.CreateProgram] = (memory, threaded, renderer) => CreateProgramCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.CreateSampler] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.CreateSampler] = (memory, threaded, renderer) => CreateSamplerCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.CreateSync] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.CreateSync] = (memory, threaded, renderer) => CreateSyncCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.CreateTexture] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.CreateTexture] = (memory, threaded, renderer) => CreateTextureCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.GetCapabilities] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.GetCapabilities] = (memory, threaded, renderer) => GetCapabilitiesCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.PreFrame] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.PreFrame] = (memory, threaded, renderer) => PreFrameCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.ReportCounter] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.ReportCounter] = (memory, threaded, renderer) => ReportCounterCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.ResetCounter] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.ResetCounter] = (memory, threaded, renderer) => ResetCounterCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.UpdateCounters] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.UpdateCounters] = (memory, threaded, renderer) => UpdateCountersCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.BufferDispose] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.BufferDispose] = (memory, threaded, renderer) => BufferDisposeCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.BufferGetData] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.BufferGetData] = (memory, threaded, renderer) => BufferGetDataCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.BufferSetData] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.BufferSetData] = (memory, threaded, renderer) => BufferSetDataCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.CounterEventDispose] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.CounterEventDispose] = (memory, threaded, renderer) => CounterEventDisposeCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.CounterEventFlush] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.CounterEventFlush] = (memory, threaded, renderer) => CounterEventFlushCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.ProgramDispose] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.ProgramDispose] = (memory, threaded, renderer) => ProgramDisposeCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.ProgramGetBinary] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.ProgramGetBinary] = (memory, threaded, renderer) => ProgramGetBinaryCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.ProgramCheckLink] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.ProgramCheckLink] = (memory, threaded, renderer) => ProgramCheckLinkCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SamplerDispose] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SamplerDispose] = (memory, threaded, renderer) => SamplerDisposeCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.TextureCopyTo] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.TextureCopyTo] = (memory, threaded, renderer) => TextureCopyToCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.TextureCopyToScaled] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.TextureCopyToScaled] = (memory, threaded, renderer) => TextureCopyToScaledCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.TextureCopyToSlice] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.TextureCopyToSlice] = (memory, threaded, renderer) => TextureCopyToSliceCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.TextureCreateView] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.TextureCreateView] = (memory, threaded, renderer) => TextureCreateViewCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.TextureGetData] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.TextureGetData] = (memory, threaded, renderer) => TextureGetDataCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.TextureGetDataSlice] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.TextureGetDataSlice] = (memory, threaded, renderer) => TextureGetDataSliceCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.TextureRelease] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.TextureRelease] = (memory, threaded, renderer) => TextureReleaseCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.TextureSetData] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.TextureSetData] = (memory, threaded, renderer) => TextureSetDataCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.TextureSetDataSlice] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.TextureSetDataSlice] = (memory, threaded, renderer) => TextureSetDataSliceCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.TextureSetDataSliceRegion] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.TextureSetDataSliceRegion] = (memory, threaded, renderer) => TextureSetDataSliceRegionCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.TextureSetStorage] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.TextureSetStorage] = (memory, threaded, renderer) => TextureSetStorageCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.WindowPresent] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.WindowPresent] = (memory, threaded, renderer) => WindowPresentCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.Barrier] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.Barrier] = (memory, threaded, renderer) => BarrierCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.BeginTransformFeedback] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.BeginTransformFeedback] = (memory, threaded, renderer) => BeginTransformFeedbackCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.ClearBuffer] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.ClearBuffer] = (memory, threaded, renderer) => ClearBufferCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.ClearRenderTargetColor] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.ClearRenderTargetColor] = (memory, threaded, renderer) => ClearRenderTargetColorCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.ClearRenderTargetDepthStencil] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.ClearRenderTargetDepthStencil] = (memory, threaded, renderer) => ClearRenderTargetDepthStencilCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.CommandBufferBarrier] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.CommandBufferBarrier] = (memory, threaded, renderer) => CommandBufferBarrierCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.CopyBuffer] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.CopyBuffer] = (memory, threaded, renderer) => CopyBufferCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.DispatchCompute] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.DispatchCompute] = (memory, threaded, renderer) => DispatchComputeCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.Draw] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.Draw] = (memory, threaded, renderer) => DrawCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.DrawIndexed] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.DrawIndexed] = (memory, threaded, renderer) => DrawIndexedCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.DrawIndexedIndirect] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.DrawIndexedIndirect] = (memory, threaded, renderer) => DrawIndexedIndirectCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.DrawIndexedIndirectCount] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.DrawIndexedIndirectCount] = (memory, threaded, renderer) => DrawIndexedIndirectCountCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.DrawIndirect] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.DrawIndirect] = (memory, threaded, renderer) => DrawIndirectCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.DrawIndirectCount] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.DrawIndirectCount] = (memory, threaded, renderer) => DrawIndirectCountCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.DrawTexture] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.DrawTexture] = (memory, threaded, renderer) => DrawTextureCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.EndHostConditionalRendering] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.EndHostConditionalRendering] = (memory, threaded, renderer) => EndHostConditionalRenderingCommand.Run(renderer); - _lookup[(int)CommandType.EndTransformFeedback] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.EndTransformFeedback] = (memory, threaded, renderer) => EndTransformFeedbackCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetAlphaTest] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetAlphaTest] = (memory, threaded, renderer) => SetAlphaTestCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetBlendState] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetBlendState] = (memory, threaded, renderer) => SetBlendStateCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetDepthBias] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetDepthBias] = (memory, threaded, renderer) => SetDepthBiasCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetDepthClamp] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetDepthClamp] = (memory, threaded, renderer) => SetDepthClampCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetDepthMode] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetDepthMode] = (memory, threaded, renderer) => SetDepthModeCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetDepthTest] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetDepthTest] = (memory, threaded, renderer) => SetDepthTestCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetFaceCulling] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetFaceCulling] = (memory, threaded, renderer) => SetFaceCullingCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetFrontFace] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetFrontFace] = (memory, threaded, renderer) => SetFrontFaceCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetStorageBuffers] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetStorageBuffers] = (memory, threaded, renderer) => SetStorageBuffersCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetTransformFeedbackBuffers] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetTransformFeedbackBuffers] = (memory, threaded, renderer) => SetTransformFeedbackBuffersCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetUniformBuffers] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetUniformBuffers] = (memory, threaded, renderer) => SetUniformBuffersCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetImage] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetImage] = (memory, threaded, renderer) => SetImageCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetIndexBuffer] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetIndexBuffer] = (memory, threaded, renderer) => SetIndexBufferCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetLineParameters] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetLineParameters] = (memory, threaded, renderer) => SetLineParametersCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetLogicOpState] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetLogicOpState] = (memory, threaded, renderer) => SetLogicOpStateCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetMultisampleState] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetMultisampleState] = (memory, threaded, renderer) => SetMultisampleStateCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetPatchParameters] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetPatchParameters] = (memory, threaded, renderer) => SetPatchParametersCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetPointParameters] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetPointParameters] = (memory, threaded, renderer) => SetPointParametersCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetPolygonMode] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetPolygonMode] = (memory, threaded, renderer) => SetPolygonModeCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetPrimitiveRestart] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetPrimitiveRestart] = (memory, threaded, renderer) => SetPrimitiveRestartCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetPrimitiveTopology] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetPrimitiveTopology] = (memory, threaded, renderer) => SetPrimitiveTopologyCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetProgram] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetProgram] = (memory, threaded, renderer) => SetProgramCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetRasterizerDiscard] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetRasterizerDiscard] = (memory, threaded, renderer) => SetRasterizerDiscardCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetRenderTargetColorMasks] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetRenderTargetColorMasks] = (memory, threaded, renderer) => SetRenderTargetColorMasksCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetRenderTargetScale] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetRenderTargetScale] = (memory, threaded, renderer) => SetRenderTargetScaleCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetRenderTargets] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetRenderTargets] = (memory, threaded, renderer) => SetRenderTargetsCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetScissor] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetScissor] = (memory, threaded, renderer) => SetScissorsCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetStencilTest] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetStencilTest] = (memory, threaded, renderer) => SetStencilTestCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetTextureAndSampler] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetTextureAndSampler] = (memory, threaded, renderer) => SetTextureAndSamplerCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetUserClipDistance] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetUserClipDistance] = (memory, threaded, renderer) => SetUserClipDistanceCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetVertexAttribs] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetVertexAttribs] = (memory, threaded, renderer) => SetVertexAttribsCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetVertexBuffers] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetVertexBuffers] = (memory, threaded, renderer) => SetVertexBuffersCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.SetViewports] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.SetViewports] = (memory, threaded, renderer) => SetViewportsCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.TextureBarrier] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.TextureBarrier] = (memory, threaded, renderer) => TextureBarrierCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.TextureBarrierTiled] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.TextureBarrierTiled] = (memory, threaded, renderer) => TextureBarrierTiledCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.TryHostConditionalRendering] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.TryHostConditionalRendering] = (memory, threaded, renderer) => TryHostConditionalRenderingCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.TryHostConditionalRenderingFlush] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.TryHostConditionalRenderingFlush] = (memory, threaded, renderer) => TryHostConditionalRenderingFlushCommand.Run(ref GetCommand(memory), threaded, renderer); - _lookup[(int)CommandType.UpdateRenderScale] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => + _lookup[(int)CommandType.UpdateRenderScale] = (memory, threaded, renderer) => UpdateRenderScaleCommand.Run(ref GetCommand(memory), threaded, renderer); } diff --git a/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs b/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs index a9e3b75c4..62a7dae79 100644 --- a/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs +++ b/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs @@ -72,7 +72,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading { _baseRenderer = renderer; - renderer.ScreenCaptured += (object sender, ScreenCaptureImageInfo info) => ScreenCaptured?.Invoke(this, info); + renderer.ScreenCaptured += (sender, info) => ScreenCaptured?.Invoke(this, info); Pipeline = new ThreadedPipeline(this, renderer.Pipeline); Window = new ThreadedWindow(this, renderer); diff --git a/Ryujinx.Graphics.GAL/SamplerCreateInfo.cs b/Ryujinx.Graphics.GAL/SamplerCreateInfo.cs index 4c514671c..990c302e2 100644 --- a/Ryujinx.Graphics.GAL/SamplerCreateInfo.cs +++ b/Ryujinx.Graphics.GAL/SamplerCreateInfo.cs @@ -61,7 +61,7 @@ namespace Ryujinx.Graphics.GAL AddressMode.ClampToEdge, AddressMode.ClampToEdge, CompareMode.None, - GAL.CompareOp.Always, + CompareOp.Always, new ColorF(0f, 0f, 0f, 0f), 0f, 0f, diff --git a/Ryujinx.Graphics.Gpu/Engine/DeviceStateWithShadow.cs b/Ryujinx.Graphics.Gpu/Engine/DeviceStateWithShadow.cs index 3a06bc2a6..74a9aa049 100644 --- a/Ryujinx.Graphics.Gpu/Engine/DeviceStateWithShadow.cs +++ b/Ryujinx.Graphics.Gpu/Engine/DeviceStateWithShadow.cs @@ -2,6 +2,7 @@ using Ryujinx.Graphics.Device; using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; namespace Ryujinx.Graphics.Gpu.Engine @@ -21,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Engine /// Represents a device's state, with a additional shadow state. /// /// Type of the state - class DeviceStateWithShadow : IDeviceState where TState : unmanaged, IShadowState + class DeviceStateWithShadow<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] TState> : IDeviceState where TState : unmanaged, IShadowState { private readonly DeviceState _state; private readonly DeviceState _shadowState; diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/SpecializationStateUpdater.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/SpecializationStateUpdater.cs index 9e888f506..13b332f43 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Threed/SpecializationStateUpdater.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Threed/SpecializationStateUpdater.cs @@ -253,14 +253,19 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed /// Indicates that any storage buffer use is unaligned. /// /// The new value - public void SetHasUnalignedStorageBuffer(bool value) + /// True if the unaligned state changed, false otherwise + public bool SetHasUnalignedStorageBuffer(bool value) { if (value != _graphics.HasUnalignedStorageBuffer) { _graphics.HasUnalignedStorageBuffer = value; Signal(); + + return true; } + + return false; } /// diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdateTracker.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdateTracker.cs index 628eb46a7..3ed5607a4 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdateTracker.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdateTracker.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -39,7 +40,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed /// GPU state update tracker. /// /// State type - class StateUpdateTracker + class StateUpdateTracker<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] TState> { private const int BlockSize = 0xe00; private const int RegisterSize = sizeof(uint); diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs index b611f4e70..572f7fb01 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs @@ -304,14 +304,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed /// private void CommitBindings() { - var buffers = _channel.BufferManager; - var hasUnaligned = buffers.HasUnalignedStorageBuffers; - UpdateStorageBuffers(); - if (!_channel.TextureManager.CommitGraphicsBindings(_shaderSpecState) || (buffers.HasUnalignedStorageBuffers != hasUnaligned)) + bool unalignedChanged = _currentSpecState.SetHasUnalignedStorageBuffer(_channel.BufferManager.HasUnalignedStorageBuffers); + + if (!_channel.TextureManager.CommitGraphicsBindings(_shaderSpecState) || unalignedChanged) { - _currentSpecState.SetHasUnalignedStorageBuffer(buffers.HasUnalignedStorageBuffers); // Shader must be reloaded. _vtgWritesRtLayer should not change. UpdateShaderState(); } diff --git a/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs b/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs index 2bdb85bf0..e337dd9c0 100644 --- a/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs +++ b/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs @@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache private const ushort FileFormatVersionMajor = 1; private const ushort FileFormatVersionMinor = 2; private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor; - private const uint CodeGenVersion = 4037; + private const uint CodeGenVersion = 4069; private const string SharedTocFileName = "shared.toc"; private const string SharedDataFileName = "shared.data"; diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs index 872aaf67c..b0d77d8ae 100644 --- a/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs +++ b/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs @@ -110,7 +110,7 @@ namespace Ryujinx.Graphics.Gpu.Shader /// /// Texture target. /// - public Image.TextureTarget TextureTarget; + public TextureTarget TextureTarget; /// /// Indicates if the coordinates used to sample the texture are normalized or not (0.0..1.0 or 0..Width/Height). @@ -331,7 +331,7 @@ namespace Ryujinx.Graphics.Gpu.Shader int cbufSlot, uint format, bool formatSrgb, - Image.TextureTarget target, + TextureTarget target, bool coordNormalized) { Box state = GetOrCreateTextureSpecState(stageIndex, handle, cbufSlot); @@ -415,7 +415,7 @@ namespace Ryujinx.Graphics.Gpu.Shader /// Shader stage where the texture is used /// Offset in words of the texture handle on the texture buffer /// Slot of the texture buffer constant buffer - public Image.TextureTarget GetTextureTarget(int stageIndex, int handle, int cbufSlot) + public TextureTarget GetTextureTarget(int stageIndex, int handle, int cbufSlot) { return GetTextureSpecState(stageIndex, handle, cbufSlot).Value.TextureTarget; } diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/SwizzleAdd.glsl b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/SwizzleAdd.glsl index ed00dfec9..057cb6cac 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/SwizzleAdd.glsl +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/SwizzleAdd.glsl @@ -2,6 +2,6 @@ float Helper_SwizzleAdd(float x, float y, int mask) { vec4 xLut = vec4(1.0, -1.0, 1.0, 0.0); vec4 yLut = vec4(1.0, 1.0, -1.0, 1.0); - int lutIdx = mask >> int($SUBGROUP_INVOCATION$ & 3u) * 2; + int lutIdx = (mask >> (int($SUBGROUP_INVOCATION$ & 3u) * 2)) & 3; return x * xLut[lutIdx] + y * yLut[lutIdx]; } \ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs b/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs index 54b00708b..819ece416 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs @@ -10,8 +10,6 @@ using static Spv.Specification; namespace Ryujinx.Graphics.Shader.CodeGen.Spirv { - using SpvInstruction = Spv.Generator.Instruction; - static class Declarations { // At least 16 attributes are guaranteed by the spec. @@ -60,7 +58,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv for (int funcIndex = 0; funcIndex < functions.Count; funcIndex++) { StructuredFunction function = functions[funcIndex]; - SpvInstruction[] locals = new SpvInstruction[function.InArguments.Length]; + Instruction[] locals = new Instruction[function.InArguments.Length]; for (int i = 0; i < function.InArguments.Length; i++) { @@ -122,7 +120,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv context.SharedMemory = DeclareMemory(context, StorageClass.Workgroup, size); } - private static SpvInstruction DeclareMemory(CodeGenContext context, StorageClass storage, int size) + private static Instruction DeclareMemory(CodeGenContext context, StorageClass storage, int size) { var arrayType = context.TypeArray(context.TypeU32(), context.Constant(context.TypeU32(), size)); var pointerType = context.TypePointer(storage, arrayType); diff --git a/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs b/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs index d4a3102e2..ae2803779 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs @@ -1449,10 +1449,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv var xLut = context.ConstantComposite(v4float, one, minusOne, one, zero); var yLut = context.ConstantComposite(v4float, one, one, minusOne, one); + var three = context.Constant(context.TypeU32(), 3); + var threadId = context.GetAttribute(AggregateType.U32, AttributeConsts.LaneId, false); - var shift = context.BitwiseAnd(context.TypeU32(), threadId, context.Constant(context.TypeU32(), 3)); + var shift = context.BitwiseAnd(context.TypeU32(), threadId, three); shift = context.ShiftLeftLogical(context.TypeU32(), shift, context.Constant(context.TypeU32(), 1)); var lutIdx = context.ShiftRightLogical(context.TypeU32(), mask, shift); + lutIdx = context.BitwiseAnd(context.TypeU32(), lutIdx, three); var xLutValue = context.VectorExtractDynamic(context.TypeFP32(), xLut, lutIdx); var yLutValue = context.VectorExtractDynamic(context.TypeFP32(), yLut, lutIdx); diff --git a/Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs b/Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs index 863e19a0d..08efbc9fd 100644 --- a/Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs +++ b/Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs @@ -8,6 +8,7 @@ namespace Ryujinx.Graphics.Shader.Translation public const int TessLevelOuter3 = 0x00c; public const int TessLevelInner0 = 0x010; public const int TessLevelInner1 = 0x014; + public const int PrimitiveId = 0x060; public const int Layer = 0x064; public const int ViewportIndex = 0x068; public const int PointSize = 0x06c; @@ -85,8 +86,7 @@ namespace Ryujinx.Graphics.Shader.Translation public const int LaneId = 0x2000020; public const int InvocationId = 0x2000024; - public const int PrimitiveId = 0x2000028; - public const int PatchVerticesIn = 0x200002c; + public const int PatchVerticesIn = 0x2000028; public const int EqMask = 0x2000030; public const int GeMask = 0x2000034; diff --git a/Ryujinx.Graphics.Shader/Translation/GlobalMemory.cs b/Ryujinx.Graphics.Shader/Translation/GlobalMemory.cs index 1be638684..3915c0d55 100644 --- a/Ryujinx.Graphics.Shader/Translation/GlobalMemory.cs +++ b/Ryujinx.Graphics.Shader/Translation/GlobalMemory.cs @@ -48,5 +48,10 @@ namespace Ryujinx.Graphics.Shader.Translation _ => 0 }; } + + public static int GetConstantUbeOffset(int slot) + { + return UbeBaseOffset + slot * StorageDescSize; + } } } \ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs index ec8fca1da..c280a6d80 100644 --- a/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs +++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs @@ -8,11 +8,14 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations { static class GlobalToStorage { - public static void RunPass(BasicBlock block, ShaderConfig config, ref int sbUseMask) + public static void RunPass(BasicBlock block, ShaderConfig config, ref int sbUseMask, ref int ubeUseMask) { int sbStart = GetStorageBaseCbOffset(config.Stage); int sbEnd = sbStart + StorageDescsSize; + int ubeStart = UbeBaseOffset; + int ubeEnd = UbeBaseOffset + UbeDescsSize; + for (LinkedListNode node = block.Operations.First; node != null; node = node.Next) { for (int index = 0; index < node.Value.SourcesCount; index++) @@ -25,6 +28,16 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations { sbUseMask |= 1 << storageIndex; } + + if (config.Stage == ShaderStage.Compute) + { + int constantIndex = GetStorageIndex(src, ubeStart, ubeEnd); + + if (constantIndex >= 0) + { + ubeUseMask |= 1 << constantIndex; + } + } } if (!(node.Value is Operation operation)) @@ -54,7 +67,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations // so NVN "emulates" more constant buffers using global memory access. // Here we try to replace the global access back to a constant buffer // load. - storageIndex = SearchForStorageBase(block, source, UbeBaseOffset, UbeBaseOffset + UbeDescsSize); + storageIndex = SearchForStorageBase(block, source, ubeStart, ubeStart + ubeEnd); if (storageIndex >= 0) { @@ -64,7 +77,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations } } - config.SetAccessibleStorageBuffersMask(sbUseMask); + config.SetAccessibleBufferMasks(sbUseMask, ubeUseMask); } private static LinkedListNode ReplaceGlobalWithStorage(BasicBlock block, LinkedListNode node, ShaderConfig config, int storageIndex) diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs index a1a2054c0..a2219b36d 100644 --- a/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs +++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs @@ -12,16 +12,17 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations RunOptimizationPasses(blocks); int sbUseMask = 0; + int ubeUseMask = 0; // Those passes are looking for specific patterns and only needs to run once. for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++) { - GlobalToStorage.RunPass(blocks[blkIndex], config, ref sbUseMask); + GlobalToStorage.RunPass(blocks[blkIndex], config, ref sbUseMask, ref ubeUseMask); BindlessToIndexed.RunPass(blocks[blkIndex], config); BindlessElimination.RunPass(blocks[blkIndex], config); } - config.SetAccessibleStorageBuffersMask(sbUseMask); + config.SetAccessibleBufferMasks(sbUseMask, ubeUseMask); // Run optimizations one last time to remove any code that is now optimizable after above passes. RunOptimizationPasses(blocks); diff --git a/Ryujinx.Graphics.Shader/Translation/Rewriter.cs b/Ryujinx.Graphics.Shader/Translation/Rewriter.cs index c4d2c5d90..0c3c4a57d 100644 --- a/Ryujinx.Graphics.Shader/Translation/Rewriter.cs +++ b/Ryujinx.Graphics.Shader/Translation/Rewriter.cs @@ -1,3 +1,4 @@ +using Ryujinx.Graphics.Shader.Decoders; using Ryujinx.Graphics.Shader.IntermediateRepresentation; using System.Collections.Generic; using System.Diagnostics; @@ -89,12 +90,42 @@ namespace Ryujinx.Graphics.Shader.Translation return local; } + Operand PrependExistingOperation(Operation operation) + { + Operand local = Local(); + + operation.Dest = local; + node.List.AddBefore(node, operation); + + return local; + } + Operand addrLow = operation.GetSource(0); Operand addrHigh = operation.GetSource(1); Operand sbBaseAddrLow = Const(0); Operand sbSlot = Const(0); + Operand alignMask = Const(-config.GpuAccessor.QueryHostStorageBufferOffsetAlignment()); + + Operand BindingRangeCheck(int cbOffset, out Operand baseAddrLow) + { + baseAddrLow = Cbuf(0, cbOffset); + Operand baseAddrHigh = Cbuf(0, cbOffset + 1); + Operand size = Cbuf(0, cbOffset + 2); + + Operand offset = PrependOperation(Instruction.Subtract, addrLow, baseAddrLow); + Operand borrow = PrependOperation(Instruction.CompareLessU32, addrLow, baseAddrLow); + + Operand inRangeLow = PrependOperation(Instruction.CompareLessU32, offset, size); + + Operand addrHighBorrowed = PrependOperation(Instruction.Add, addrHigh, borrow); + + Operand inRangeHigh = PrependOperation(Instruction.CompareEqual, addrHighBorrowed, baseAddrHigh); + + return PrependOperation(Instruction.BitwiseAnd, inRangeLow, inRangeHigh); + } + int sbUseMask = config.AccessibleStorageBuffersMask; while (sbUseMask != 0) @@ -107,20 +138,7 @@ namespace Ryujinx.Graphics.Shader.Translation int cbOffset = GetStorageCbOffset(config.Stage, slot); - Operand baseAddrLow = Cbuf(0, cbOffset); - Operand baseAddrHigh = Cbuf(0, cbOffset + 1); - Operand size = Cbuf(0, cbOffset + 2); - - Operand offset = PrependOperation(Instruction.Subtract, addrLow, baseAddrLow); - Operand borrow = PrependOperation(Instruction.CompareLessU32, addrLow, baseAddrLow); - - Operand inRangeLow = PrependOperation(Instruction.CompareLessU32, offset, size); - - Operand addrHighBorrowed = PrependOperation(Instruction.Add, addrHigh, borrow); - - Operand inRangeHigh = PrependOperation(Instruction.CompareEqual, addrHighBorrowed, baseAddrHigh); - - Operand inRange = PrependOperation(Instruction.BitwiseAnd, inRangeLow, inRangeHigh); + Operand inRange = BindingRangeCheck(cbOffset, out Operand baseAddrLow); sbBaseAddrLow = PrependOperation(Instruction.ConditionalSelect, inRange, baseAddrLow, sbBaseAddrLow); sbSlot = PrependOperation(Instruction.ConditionalSelect, inRange, Const(slot), sbSlot); @@ -128,8 +146,6 @@ namespace Ryujinx.Graphics.Shader.Translation if (config.AccessibleStorageBuffersMask != 0) { - Operand alignMask = Const(-config.GpuAccessor.QueryHostStorageBufferOffsetAlignment()); - Operand baseAddrTrunc = PrependOperation(Instruction.BitwiseAnd, sbBaseAddrLow, alignMask); Operand byteOffset = PrependOperation(Instruction.Subtract, addrLow, baseAddrTrunc); @@ -178,6 +194,46 @@ namespace Ryujinx.Graphics.Shader.Translation storageOp = new Operation(Instruction.Copy, operation.Dest, Const(0)); } + if (operation.Inst == Instruction.LoadGlobal) + { + int cbeUseMask = config.AccessibleConstantBuffersMask; + + while (cbeUseMask != 0) + { + int slot = BitOperations.TrailingZeroCount(cbeUseMask); + int cbSlot = UbeFirstCbuf + slot; + + cbeUseMask &= ~(1 << slot); + + config.SetUsedConstantBuffer(cbSlot); + + Operand previousResult = PrependExistingOperation(storageOp); + + int cbOffset = GetConstantUbeOffset(slot); + + Operand inRange = BindingRangeCheck(cbOffset, out Operand baseAddrLow); + + Operand baseAddrTruncConst = PrependOperation(Instruction.BitwiseAnd, baseAddrLow, alignMask); + Operand byteOffsetConst = PrependOperation(Instruction.Subtract, addrLow, baseAddrTruncConst); + + Operand cbIndex = PrependOperation(Instruction.ShiftRightU32, byteOffsetConst, Const(2)); + + Operand[] sourcesCb = new Operand[operation.SourcesCount]; + + sourcesCb[0] = Const(cbSlot); + sourcesCb[1] = cbIndex; + + for (int index = 2; index < operation.SourcesCount; index++) + { + sourcesCb[index] = operation.GetSource(index); + } + + Operand ldcResult = PrependOperation(Instruction.LoadConstant, sourcesCb); + + storageOp = new Operation(Instruction.ConditionalSelect, operation.Dest, inRange, ldcResult, previousResult); + } + } + for (int index = 0; index < operation.SourcesCount; index++) { operation.SetSource(index, null); diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs index 85b56b51f..a79ef6f57 100644 --- a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs +++ b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs @@ -66,6 +66,7 @@ namespace Ryujinx.Graphics.Shader.Translation public UInt128 ThisInputAttributesComponents { get; private set; } public int AccessibleStorageBuffersMask { get; private set; } + public int AccessibleConstantBuffersMask { get; private set; } private int _usedConstantBuffers; private int _usedStorageBuffers; @@ -100,7 +101,8 @@ namespace Ryujinx.Graphics.Shader.Translation GpuAccessor = gpuAccessor; Options = options; - AccessibleStorageBuffersMask = (1 << GlobalMemory.StorageMaxCount) - 1; + AccessibleStorageBuffersMask = (1 << GlobalMemory.StorageMaxCount) - 1; + AccessibleConstantBuffersMask = (1 << GlobalMemory.UbeMaxCount) - 1; UsedInputAttributesPerPatch = new HashSet(); UsedOutputAttributesPerPatch = new HashSet(); @@ -121,6 +123,11 @@ namespace Ryujinx.Graphics.Shader.Translation OutputTopology = outputTopology; MaxOutputVertices = maxOutputVertices; TransformFeedbackEnabled = gpuAccessor.QueryTransformFeedbackEnabled(); + + if (Stage != ShaderStage.Compute) + { + AccessibleConstantBuffersMask = 0; + } } public ShaderConfig(ShaderHeader header, IGpuAccessor gpuAccessor, TranslationOptions options) : this(gpuAccessor, options) @@ -404,9 +411,10 @@ namespace Ryujinx.Graphics.Shader.Translation UsedFeatures |= flags; } - public void SetAccessibleStorageBuffersMask(int mask) + public void SetAccessibleBufferMasks(int sbMask, int ubeMask) { - AccessibleStorageBuffersMask = mask; + AccessibleStorageBuffersMask = sbMask; + AccessibleConstantBuffersMask = ubeMask; } public void SetUsedConstantBuffer(int slot) diff --git a/Ryujinx.Graphics.Vulkan/BufferHolder.cs b/Ryujinx.Graphics.Vulkan/BufferHolder.cs index 6288f16fb..055d6a59a 100644 --- a/Ryujinx.Graphics.Vulkan/BufferHolder.cs +++ b/Ryujinx.Graphics.Vulkan/BufferHolder.cs @@ -272,7 +272,7 @@ namespace Ryujinx.Graphics.Vulkan _gd, cbs.CommandBuffer, dstBuffer, - BufferHolder.DefaultAccessFlags, + DefaultAccessFlags, AccessFlags.TransferWriteBit, PipelineStageFlags.AllCommandsBit, PipelineStageFlags.TransferBit, @@ -294,7 +294,7 @@ namespace Ryujinx.Graphics.Vulkan cbs.CommandBuffer, dstBuffer, AccessFlags.TransferWriteBit, - BufferHolder.DefaultAccessFlags, + DefaultAccessFlags, PipelineStageFlags.TransferBit, PipelineStageFlags.AllCommandsBit, dstOffset, @@ -319,7 +319,7 @@ namespace Ryujinx.Graphics.Vulkan gd, cbs.CommandBuffer, dstBuffer, - BufferHolder.DefaultAccessFlags, + DefaultAccessFlags, AccessFlags.TransferWriteBit, PipelineStageFlags.AllCommandsBit, PipelineStageFlags.TransferBit, @@ -335,7 +335,7 @@ namespace Ryujinx.Graphics.Vulkan cbs.CommandBuffer, dstBuffer, AccessFlags.TransferWriteBit, - BufferHolder.DefaultAccessFlags, + DefaultAccessFlags, PipelineStageFlags.TransferBit, PipelineStageFlags.AllCommandsBit, dstOffset, diff --git a/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs b/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs index 9564d7ebc..9ac2e61de 100644 --- a/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs +++ b/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs @@ -97,7 +97,7 @@ namespace Ryujinx.Graphics.Vulkan _dummyBuffer = gd.BufferManager.Create(gd, 0x10000, forConditionalRendering: false, deviceLocal: true); } - _dummyTexture = gd.CreateTextureView(new GAL.TextureCreateInfo( + _dummyTexture = gd.CreateTextureView(new TextureCreateInfo( 1, 1, 1, diff --git a/Ryujinx.Graphics.Vulkan/DisposableBufferView.cs b/Ryujinx.Graphics.Vulkan/DisposableBufferView.cs index 28ddd7ddb..e81ca412e 100644 --- a/Ryujinx.Graphics.Vulkan/DisposableBufferView.cs +++ b/Ryujinx.Graphics.Vulkan/DisposableBufferView.cs @@ -3,7 +3,7 @@ using System; namespace Ryujinx.Graphics.Vulkan { - readonly struct DisposableBufferView : System.IDisposable + readonly struct DisposableBufferView : IDisposable { private readonly Vk _api; private readonly Device _device; diff --git a/Ryujinx.Graphics.Vulkan/PipelineLayoutFactory.cs b/Ryujinx.Graphics.Vulkan/PipelineLayoutFactory.cs index e4e2d3349..96b3b3b1c 100644 --- a/Ryujinx.Graphics.Vulkan/PipelineLayoutFactory.cs +++ b/Ryujinx.Graphics.Vulkan/PipelineLayoutFactory.cs @@ -86,7 +86,7 @@ namespace Ryujinx.Graphics.Vulkan iter++; } - DescriptorSetLayout[] layouts = new DescriptorSetLayout[PipelineFull.DescriptorSetLayouts]; + DescriptorSetLayout[] layouts = new DescriptorSetLayout[PipelineBase.DescriptorSetLayouts]; var uDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo() { @@ -117,10 +117,10 @@ namespace Ryujinx.Graphics.Vulkan BindingCount = (uint)iCount }; - gd.Api.CreateDescriptorSetLayout(device, uDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.UniformSetIndex]).ThrowOnError(); - gd.Api.CreateDescriptorSetLayout(device, sDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.StorageSetIndex]).ThrowOnError(); - gd.Api.CreateDescriptorSetLayout(device, tDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.TextureSetIndex]).ThrowOnError(); - gd.Api.CreateDescriptorSetLayout(device, iDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.ImageSetIndex]).ThrowOnError(); + gd.Api.CreateDescriptorSetLayout(device, uDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.UniformSetIndex]).ThrowOnError(); + gd.Api.CreateDescriptorSetLayout(device, sDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.StorageSetIndex]).ThrowOnError(); + gd.Api.CreateDescriptorSetLayout(device, tDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.TextureSetIndex]).ThrowOnError(); + gd.Api.CreateDescriptorSetLayout(device, iDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.ImageSetIndex]).ThrowOnError(); fixed (DescriptorSetLayout* pLayouts = layouts) { @@ -128,7 +128,7 @@ namespace Ryujinx.Graphics.Vulkan { SType = StructureType.PipelineLayoutCreateInfo, PSetLayouts = pLayouts, - SetLayoutCount = PipelineFull.DescriptorSetLayouts + SetLayoutCount = PipelineBase.DescriptorSetLayouts }; gd.Api.CreatePipelineLayout(device, &pipelineLayoutCreateInfo, null, out layout).ThrowOnError(); @@ -191,7 +191,7 @@ namespace Ryujinx.Graphics.Vulkan Set(iLayoutBindings, DescriptorType.StorageImage, ref iIndex, shader.Bindings.ImageBindings); } - DescriptorSetLayout[] layouts = new DescriptorSetLayout[PipelineFull.DescriptorSetLayouts]; + DescriptorSetLayout[] layouts = new DescriptorSetLayout[PipelineBase.DescriptorSetLayouts]; var uDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo() { @@ -221,10 +221,10 @@ namespace Ryujinx.Graphics.Vulkan BindingCount = (uint)iCount }; - gd.Api.CreateDescriptorSetLayout(device, uDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.UniformSetIndex]).ThrowOnError(); - gd.Api.CreateDescriptorSetLayout(device, sDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.StorageSetIndex]).ThrowOnError(); - gd.Api.CreateDescriptorSetLayout(device, tDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.TextureSetIndex]).ThrowOnError(); - gd.Api.CreateDescriptorSetLayout(device, iDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.ImageSetIndex]).ThrowOnError(); + gd.Api.CreateDescriptorSetLayout(device, uDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.UniformSetIndex]).ThrowOnError(); + gd.Api.CreateDescriptorSetLayout(device, sDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.StorageSetIndex]).ThrowOnError(); + gd.Api.CreateDescriptorSetLayout(device, tDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.TextureSetIndex]).ThrowOnError(); + gd.Api.CreateDescriptorSetLayout(device, iDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.ImageSetIndex]).ThrowOnError(); fixed (DescriptorSetLayout* pLayouts = layouts) { @@ -232,7 +232,7 @@ namespace Ryujinx.Graphics.Vulkan { SType = StructureType.PipelineLayoutCreateInfo, PSetLayouts = pLayouts, - SetLayoutCount = PipelineFull.DescriptorSetLayouts + SetLayoutCount = PipelineBase.DescriptorSetLayouts }; gd.Api.CreatePipelineLayout(device, &pipelineLayoutCreateInfo, null, out layout).ThrowOnError(); diff --git a/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs b/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs index 7813bb816..942970c27 100644 --- a/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs +++ b/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs @@ -1,4 +1,4 @@ -using Ryujinx.Common.Configuration; +using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using Ryujinx.Graphics.GAL; using Silk.NET.Vulkan; @@ -21,6 +21,7 @@ namespace Ryujinx.Graphics.Vulkan { ExtConditionalRendering.ExtensionName, ExtExtendedDynamicState.ExtensionName, + ExtTransformFeedback.ExtensionName, KhrDrawIndirectCount.ExtensionName, KhrPushDescriptor.ExtensionName, "VK_EXT_custom_border_color", @@ -36,8 +37,7 @@ namespace Ryujinx.Graphics.Vulkan public static string[] RequiredExtensions { get; } = new string[] { - KhrSwapchain.ExtensionName, - ExtTransformFeedback.ExtensionName + KhrSwapchain.ExtensionName }; private static string[] _excludedMessages = new string[] @@ -382,12 +382,12 @@ namespace Ryujinx.Graphics.Vulkan DepthClamp = true, DualSrcBlend = true, FragmentStoresAndAtomics = true, - GeometryShader = true, + GeometryShader = supportedFeatures.GeometryShader, ImageCubeArray = true, IndependentBlend = true, - LogicOp = true, + LogicOp = supportedFeatures.LogicOp, MultiViewport = true, - PipelineStatisticsQuery = true, + PipelineStatisticsQuery = supportedFeatures.PipelineStatisticsQuery, SamplerAnisotropy = true, ShaderClipDistance = true, ShaderFloat64 = supportedFeatures.ShaderFloat64, diff --git a/Ryujinx.HLE/FileSystem/ContentManager.cs b/Ryujinx.HLE/FileSystem/ContentManager.cs index 652c24695..9ae619adb 100644 --- a/Ryujinx.HLE/FileSystem/ContentManager.cs +++ b/Ryujinx.HLE/FileSystem/ContentManager.cs @@ -39,13 +39,11 @@ namespace Ryujinx.HLE.FileSystem { public readonly string ContainerPath; public readonly string NcaPath; - public bool Enabled; - public AocItem(string containerPath, string ncaPath, bool enabled) + public AocItem(string containerPath, string ncaPath) { ContainerPath = containerPath; NcaPath = ncaPath; - Enabled = enabled; } } @@ -53,7 +51,7 @@ namespace Ryujinx.HLE.FileSystem private VirtualFileSystem _virtualFileSystem; - private readonly object _lock = new object(); + private readonly object _lock = new(); public ContentManager(VirtualFileSystem virtualFileSystem) { @@ -226,27 +224,21 @@ namespace Ryujinx.HLE.FileSystem pfs0.OpenFile(ref cnmtFile.Ref(), pfs0.EnumerateEntries().Single().FullPath.ToU8Span(), OpenMode.Read); var cnmt = new Cnmt(cnmtFile.Get.AsStream()); - if (cnmt.Type != ContentMetaType.AddOnContent || (cnmt.TitleId & 0xFFFFFFFFFFFFE000) != aocBaseId) { continue; } string ncaId = BitConverter.ToString(cnmt.ContentEntries[0].NcaId).Replace("-", "").ToLower(); - if (!_aocData.TryAdd(cnmt.TitleId, new AocItem(containerPath, $"{ncaId}.nca", true))) - { - Logger.Warning?.Print(LogClass.Application, $"Duplicate AddOnContent detected. TitleId {cnmt.TitleId:X16}"); - } - else - { - Logger.Info?.Print(LogClass.Application, $"Found AddOnContent with TitleId {cnmt.TitleId:X16}"); - } + + AddAocItem(cnmt.TitleId, containerPath, $"{ncaId}.nca", true); } } - public void AddAocItem(ulong titleId, string containerPath, string ncaPath, bool enabled) + public void AddAocItem(ulong titleId, string containerPath, string ncaPath, bool mergedToContainer = false) { - if (!_aocData.TryAdd(titleId, new AocItem(containerPath, ncaPath, enabled))) + // TODO: Check Aoc version. + if (!_aocData.TryAdd(titleId, new AocItem(containerPath, ncaPath))) { Logger.Warning?.Print(LogClass.Application, $"Duplicate AddOnContent detected. TitleId {titleId:X16}"); } @@ -254,25 +246,27 @@ namespace Ryujinx.HLE.FileSystem { Logger.Info?.Print(LogClass.Application, $"Found AddOnContent with TitleId {titleId:X16}"); - using (FileStream fileStream = File.OpenRead(containerPath)) - using (PartitionFileSystem pfs = new PartitionFileSystem(fileStream.AsStorage())) + if (!mergedToContainer) { - _virtualFileSystem.ImportTickets(pfs); + using FileStream fileStream = File.OpenRead(containerPath); + using PartitionFileSystem partitionFileSystem = new(fileStream.AsStorage()); + + _virtualFileSystem.ImportTickets(partitionFileSystem); } } } public void ClearAocData() => _aocData.Clear(); - public int GetAocCount() => _aocData.Where(e => e.Value.Enabled).Count(); + public int GetAocCount() => _aocData.Count; - public IList GetAocTitleIds() => _aocData.Where(e => e.Value.Enabled).Select(e => e.Key).ToList(); + public IList GetAocTitleIds() => _aocData.Select(e => e.Key).ToList(); public bool GetAocDataStorage(ulong aocTitleId, out IStorage aocStorage, IntegrityCheckLevel integrityCheckLevel) { aocStorage = null; - if (_aocData.TryGetValue(aocTitleId, out AocItem aoc) && aoc.Enabled) + if (_aocData.TryGetValue(aocTitleId, out AocItem aoc)) { var file = new FileStream(aoc.ContainerPath, FileMode.Open, FileAccess.Read); using var ncaFile = new UniqueRef(); diff --git a/Ryujinx.HLE/HOS/Applets/Error/ErrorApplet.cs b/Ryujinx.HLE/HOS/Applets/Error/ErrorApplet.cs index bd321f6fe..ba7efbd7d 100644 --- a/Ryujinx.HLE/HOS/Applets/Error/ErrorApplet.cs +++ b/Ryujinx.HLE/HOS/Applets/Error/ErrorApplet.cs @@ -47,7 +47,7 @@ namespace Ryujinx.HLE.HOS.Applets.Error _errorStorage = _normalSession.Pop(); _errorCommonHeader = IApplet.ReadStruct(_errorStorage); - _errorStorage = _errorStorage.Skip(Marshal.SizeOf(typeof(ErrorCommonHeader))).ToArray(); + _errorStorage = _errorStorage.Skip(Marshal.SizeOf()).ToArray(); switch (_errorCommonHeader.Type) { diff --git a/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/Resources/Logo_Ryujinx.png b/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/Resources/Logo_Ryujinx.png new file mode 100644 index 000000000..0e8da15e6 Binary files /dev/null and b/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/Resources/Logo_Ryujinx.png differ diff --git a/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardApplet.cs b/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardApplet.cs index 74073420f..4077ad420 100644 --- a/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardApplet.cs +++ b/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardApplet.cs @@ -9,6 +9,7 @@ using Ryujinx.HLE.Ui.Input; using Ryujinx.Memory; using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -797,7 +798,7 @@ namespace Ryujinx.HLE.HOS.Applets return sb.ToString(); } - private static T ReadStruct(byte[] data) + private static T ReadStruct<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] T>(byte[] data) where T : struct { GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); diff --git a/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardRendererBase.cs b/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardRendererBase.cs index 6c0955ecc..8216a65ee 100644 --- a/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardRendererBase.cs +++ b/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardRendererBase.cs @@ -11,7 +11,6 @@ using System.Numerics; using System.Reflection; using System.Runtime.InteropServices; using SixLabors.ImageSharp.PixelFormats; -using Ryujinx.Common; namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard { @@ -68,8 +67,8 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard { int ryujinxLogoSize = 32; - Stream logoStream = EmbeddedResources.GetStream("Ryujinx.Ui.Common/Resources/Logo_Ryujinx.png"); - _ryujinxLogo = LoadResource(logoStream, ryujinxLogoSize, ryujinxLogoSize); + string ryujinxIconPath = "Ryujinx.HLE.HOS.Applets.SoftwareKeyboard.Resources.Logo_Ryujinx.png"; + _ryujinxLogo = LoadResource(Assembly.GetExecutingAssembly(), ryujinxIconPath, ryujinxLogoSize, ryujinxLogoSize); string padAcceptIconPath = "Ryujinx.HLE.HOS.Applets.SoftwareKeyboard.Resources.Icon_BtnA.png"; string padCancelIconPath = "Ryujinx.HLE.HOS.Applets.SoftwareKeyboard.Resources.Icon_BtnB.png"; @@ -117,7 +116,8 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard uiThemeFontFamily, "Liberation Sans", "FreeSans", - "DejaVu Sans" + "DejaVu Sans", + "Lucida Grande" }; foreach (string fontFamily in availableFonts) diff --git a/Ryujinx.HLE/HOS/ApplicationLoader.cs b/Ryujinx.HLE/HOS/ApplicationLoader.cs index 199da37a3..61fcd0c35 100644 --- a/Ryujinx.HLE/HOS/ApplicationLoader.cs +++ b/Ryujinx.HLE/HOS/ApplicationLoader.cs @@ -426,9 +426,9 @@ namespace Ryujinx.HLE.HOS { foreach (DownloadableContentNca downloadableContentNca in downloadableContentContainer.DownloadableContentNcaList) { - if (File.Exists(downloadableContentContainer.ContainerPath)) + if (File.Exists(downloadableContentContainer.ContainerPath) && downloadableContentNca.Enabled) { - _device.Configuration.ContentManager.AddAocItem(downloadableContentNca.TitleId, downloadableContentContainer.ContainerPath, downloadableContentNca.FullPath, downloadableContentNca.Enabled); + _device.Configuration.ContentManager.AddAocItem(downloadableContentNca.TitleId, downloadableContentContainer.ContainerPath, downloadableContentNca.FullPath); } else { diff --git a/Ryujinx.HLE/HOS/Services/Account/Acc/ApplicationServiceServer.cs b/Ryujinx.HLE/HOS/Services/Account/Acc/ApplicationServiceServer.cs index 7b474f0e7..d9f9864a0 100644 --- a/Ryujinx.HLE/HOS/Services/Account/Acc/ApplicationServiceServer.cs +++ b/Ryujinx.HLE/HOS/Services/Account/Acc/ApplicationServiceServer.cs @@ -1,8 +1,12 @@ using Ryujinx.Common; using Ryujinx.Common.Logging; using Ryujinx.Cpu; +using Ryujinx.HLE.HOS.Kernel.Threading; using Ryujinx.HLE.HOS.Services.Account.Acc.AccountService; +using Ryujinx.HLE.HOS.Services.Account.Acc.AsyncContext; using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; namespace Ryujinx.HLE.HOS.Services.Account.Acc { @@ -142,6 +146,28 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc return ResultCode.Success; } + public ResultCode CheckNetworkServiceAvailabilityAsync(ServiceCtx context, out IAsyncContext asyncContext) + { + KEvent asyncEvent = new(context.Device.System.KernelContext); + AsyncExecution asyncExecution = new(asyncEvent); + + asyncExecution.Initialize(1000, CheckNetworkServiceAvailabilityAsyncImpl); + + asyncContext = new IAsyncContext(asyncExecution); + + // return ResultCode.NullObject if the IAsyncContext pointer is null. Doesn't occur in our case. + + return ResultCode.Success; + } + + private async Task CheckNetworkServiceAvailabilityAsyncImpl(CancellationToken token) + { + Logger.Stub?.PrintStub(LogClass.ServiceAcc); + + // TODO: Use a real function instead, with the CancellationToken. + await Task.CompletedTask; + } + public ResultCode StoreSaveDataThumbnail(ServiceCtx context) { ResultCode resultCode = CheckUserId(context, out UserId _); diff --git a/Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForApplication.cs b/Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForApplication.cs index 920823229..059aba17d 100644 --- a/Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForApplication.cs +++ b/Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForApplication.cs @@ -124,6 +124,20 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc return ResultCode.Success; } + [CommandHipc(103)] // 4.0.0+ + // CheckNetworkServiceAvailabilityAsync() -> object + public ResultCode CheckNetworkServiceAvailabilityAsync(ServiceCtx context) + { + ResultCode resultCode = _applicationServiceServer.CheckNetworkServiceAvailabilityAsync(context, out IAsyncContext asyncContext); + + if (resultCode == ResultCode.Success) + { + MakeObject(context, asyncContext); + } + + return resultCode; + } + [CommandHipc(110)] // StoreSaveDataThumbnail(nn::account::Uid, buffer) public ResultCode StoreSaveDataThumbnail(ServiceCtx context) diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs b/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs index 609bba1ed..74068ad66 100644 --- a/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs +++ b/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs @@ -157,7 +157,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati int supportedLanguages = (int)context.Device.Application.ControlData.Value.SupportedLanguageFlag; int firstSupported = BitOperations.TrailingZeroCount(supportedLanguages); - if (firstSupported > (int)SystemState.TitleLanguage.BrazilianPortuguese) + if (firstSupported > (int)TitleLanguage.BrazilianPortuguese) { Logger.Warning?.Print(LogClass.ServiceAm, "Application has zero supported languages"); @@ -170,7 +170,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati // TODO: In the future, a GUI could enable user-specified search priority if (((1 << (int)context.Device.System.State.DesiredTitleLanguage) & supportedLanguages) == 0) { - SystemLanguage newLanguage = Enum.Parse(Enum.GetName(typeof(SystemState.TitleLanguage), firstSupported)); + SystemLanguage newLanguage = Enum.Parse(Enum.GetName(typeof(TitleLanguage), firstSupported)); desiredLanguageCode = SystemStateMgr.GetLanguageCode((int)newLanguage); Logger.Info?.Print(LogClass.ServiceAm, $"Application doesn't support configured language. Using {newLanguage}"); diff --git a/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs b/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs index 970aab958..d812e3741 100644 --- a/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs +++ b/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs @@ -901,7 +901,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs [CommandHipc(606)] public ResultCode GetRightsId(ServiceCtx context) { - LibHac.Ncm.StorageId storageId = (LibHac.Ncm.StorageId)context.RequestData.ReadInt64(); + StorageId storageId = (StorageId)context.RequestData.ReadInt64(); ProgramId programId = context.RequestData.ReadStruct(); Result result = _baseFileSystemProxy.Get.GetRightsId(out RightsId rightsId, programId, storageId); diff --git a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/NfpManager/INfp.cs b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/NfpManager/INfp.cs index fc0c06479..f4ad03661 100644 --- a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/NfpManager/INfp.cs +++ b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/NfpManager/INfp.cs @@ -589,9 +589,9 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp ulong outputPosition = context.Request.RecvListBuff[0].Position; - context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf(typeof(TagInfo))); + context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf()); - MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf(typeof(TagInfo))); + MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf()); uint deviceHandle = (uint)context.RequestData.ReadUInt64(); @@ -665,9 +665,9 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp ulong outputPosition = context.Request.RecvListBuff[0].Position; - context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf(typeof(RegisterInfo))); + context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf()); - MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf(typeof(RegisterInfo))); + MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf()); uint deviceHandle = (uint)context.RequestData.ReadUInt64(); @@ -728,9 +728,9 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp ulong outputPosition = context.Request.RecvListBuff[0].Position; - context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf(typeof(CommonInfo))); + context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf()); - MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf(typeof(CommonInfo))); + MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf()); uint deviceHandle = (uint)context.RequestData.ReadUInt64(); @@ -788,9 +788,9 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp ulong outputPosition = context.Request.RecvListBuff[0].Position; - context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf(typeof(ModelInfo))); + context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf()); - MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf(typeof(ModelInfo))); + MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf()); uint deviceHandle = (uint)context.RequestData.ReadUInt64(); diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/BsdContext.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/BsdContext.cs index cd78af78b..a93f176a5 100644 --- a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/BsdContext.cs +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/BsdContext.cs @@ -1,5 +1,8 @@ -using System.Collections.Concurrent; +using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types; +using System; +using System.Collections.Concurrent; using System.Collections.Generic; +using System.Numerics; namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd { @@ -41,6 +44,27 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd return null; } + public List RetrieveFileDescriptorsFromMask(ReadOnlySpan mask) + { + List fds = new(); + + for (int i = 0; i < mask.Length; i++) + { + byte current = mask[i]; + + while (current != 0) + { + int bit = BitOperations.TrailingZeroCount(current); + current &= (byte)~(1 << bit); + int fd = i * 8 + bit; + + fds.Add(RetrieveFileDescriptor(fd)); + } + } + + return fds; + } + public int RegisterFileDescriptor(IFileDescriptor file) { lock (_lock) @@ -61,6 +85,16 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd } } + public void BuildMask(List fds, Span mask) + { + foreach (IFileDescriptor descriptor in fds) + { + int fd = _fds.IndexOf(descriptor); + + mask[fd >> 3] |= (byte)(1 << (fd & 7)); + } + } + public int DuplicateFileDescriptor(int fd) { IFileDescriptor oldFile = RetrieveFileDescriptor(fd); @@ -147,4 +181,4 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd return processContext; } } -} +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/IClient.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/IClient.cs index ece5375b9..eaf65e4cc 100644 --- a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/IClient.cs +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/IClient.cs @@ -1,10 +1,13 @@ using Ryujinx.Common; using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl; +using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types; using Ryujinx.Memory; using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; +using System.Numerics; using System.Runtime.CompilerServices; using System.Text; @@ -202,12 +205,122 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd } [CommandHipc(5)] - // Select(u32 nfds, nn::socket::timeout timeout, buffer readfds_in, buffer writefds_in, buffer errorfds_in) -> (i32 ret, u32 bsd_errno, buffer readfds_out, buffer writefds_out, buffer errorfds_out) + // Select(u32 nfds, nn::socket::timeval timeout, buffer readfds_in, buffer writefds_in, buffer errorfds_in) + // -> (i32 ret, u32 bsd_errno, buffer readfds_out, buffer writefds_out, buffer errorfds_out) public ResultCode Select(ServiceCtx context) { - WriteBsdResult(context, -1, LinuxError.EOPNOTSUPP); + int fdsCount = context.RequestData.ReadInt32(); + int timeout = context.RequestData.ReadInt32(); - Logger.Stub?.PrintStub(LogClass.ServiceBsd); + (ulong readFdsInBufferPosition, ulong readFdsInBufferSize) = context.Request.GetBufferType0x21(0); + (ulong writeFdsInBufferPosition, ulong writeFdsInBufferSize) = context.Request.GetBufferType0x21(1); + (ulong errorFdsInBufferPosition, ulong errorFdsInBufferSize) = context.Request.GetBufferType0x21(2); + + (ulong readFdsOutBufferPosition, ulong readFdsOutBufferSize) = context.Request.GetBufferType0x22(0); + (ulong writeFdsOutBufferPosition, ulong writeFdsOutBufferSize) = context.Request.GetBufferType0x22(1); + (ulong errorFdsOutBufferPosition, ulong errorFdsOutBufferSize) = context.Request.GetBufferType0x22(2); + + List readFds = _context.RetrieveFileDescriptorsFromMask(context.Memory.GetSpan(readFdsInBufferPosition, (int)readFdsInBufferSize)); + List writeFds = _context.RetrieveFileDescriptorsFromMask(context.Memory.GetSpan(writeFdsInBufferPosition, (int)writeFdsInBufferSize)); + List errorFds = _context.RetrieveFileDescriptorsFromMask(context.Memory.GetSpan(errorFdsInBufferPosition, (int)errorFdsInBufferSize)); + + int actualFdsCount = readFds.Count + writeFds.Count + errorFds.Count; + + if (fdsCount == 0 || actualFdsCount == 0) + { + WriteBsdResult(context, 0); + + return ResultCode.Success; + } + + PollEvent[] events = new PollEvent[actualFdsCount]; + + int index = 0; + + foreach (IFileDescriptor fd in readFds) + { + events[index] = new PollEvent(new PollEventData { InputEvents = PollEventTypeMask.Input }, fd); + + index++; + } + + foreach (IFileDescriptor fd in writeFds) + { + events[index] = new PollEvent(new PollEventData { InputEvents = PollEventTypeMask.Output }, fd); + + index++; + } + + foreach (IFileDescriptor fd in errorFds) + { + events[index] = new PollEvent(new PollEventData { InputEvents = PollEventTypeMask.Error }, fd); + + index++; + } + + List[] eventsByPollManager = new List[_pollManagers.Count]; + + for (int i = 0; i < eventsByPollManager.Length; i++) + { + eventsByPollManager[i] = new List(); + + foreach (PollEvent evnt in events) + { + if (_pollManagers[i].IsCompatible(evnt)) + { + eventsByPollManager[i].Add(evnt); + } + } + } + + int updatedCount = 0; + + for (int i = 0; i < _pollManagers.Count; i++) + { + if (eventsByPollManager[i].Count > 0) + { + _pollManagers[i].Select(eventsByPollManager[i], timeout, out int updatedPollCount); + updatedCount += updatedPollCount; + } + } + + readFds.Clear(); + writeFds.Clear(); + errorFds.Clear(); + + foreach (PollEvent pollEvent in events) + { + for (int i = 0; i < _pollManagers.Count; i++) + { + if (eventsByPollManager[i].Contains(pollEvent)) + { + if (pollEvent.Data.OutputEvents.HasFlag(PollEventTypeMask.Input)) + { + readFds.Add(pollEvent.FileDescriptor); + } + + if (pollEvent.Data.OutputEvents.HasFlag(PollEventTypeMask.Output)) + { + writeFds.Add(pollEvent.FileDescriptor); + } + + if (pollEvent.Data.OutputEvents.HasFlag(PollEventTypeMask.Error)) + { + errorFds.Add(pollEvent.FileDescriptor); + } + } + } + } + + using var readFdsOut = context.Memory.GetWritableRegion(readFdsOutBufferPosition, (int)readFdsOutBufferSize); + using var writeFdsOut = context.Memory.GetWritableRegion(writeFdsOutBufferPosition, (int)writeFdsOutBufferSize); + using var errorFdsOut = context.Memory.GetWritableRegion(errorFdsOutBufferPosition, (int)errorFdsOutBufferSize); + + _context.BuildMask(readFds, readFdsOut.Memory.Span); + _context.BuildMask(writeFds, writeFdsOut.Memory.Span); + _context.BuildMask(errorFds, errorFdsOut.Memory.Span); + + WriteBsdResult(context, updatedCount); return ResultCode.Success; } @@ -320,14 +433,14 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd break; } - // If we are here, that mean nothing was availaible, sleep for 50ms + // If we are here, that mean nothing was available, sleep for 50ms context.Device.System.KernelContext.Syscall.SleepThread(50 * 1000000); } while (PerformanceCounter.ElapsedMilliseconds < budgetLeftMilliseconds); } else if (timeout == -1) { - // FIXME: If we get a timeout of -1 and there is no fds to wait on, this should kill the KProces. (need to check that with re) + // FIXME: If we get a timeout of -1 and there is no fds to wait on, this should kill the KProcess. (need to check that with re) throw new InvalidOperationException(); } else @@ -998,4 +1111,4 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd return WriteBsdResult(context, newSockFd, errno); } } -} +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/IFileDescriptor.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/IFileDescriptor.cs index 56f67539b..9d4f81ce2 100644 --- a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/IFileDescriptor.cs +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/IFileDescriptor.cs @@ -1,4 +1,5 @@ -using System; +using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types; +using System; namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd { @@ -11,4 +12,4 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd LinuxError Write(out int writeSize, ReadOnlySpan buffer); } -} +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/ISocket.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/ISocket.cs index b4f2bff19..058748685 100644 --- a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/ISocket.cs +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/ISocket.cs @@ -1,4 +1,5 @@ -using System; +using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types; +using System; using System.Net; using System.Net.Sockets; diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/EventFileDescriptor.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/EventFileDescriptor.cs index f84e9b93b..6514d4855 100644 --- a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/EventFileDescriptor.cs +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/EventFileDescriptor.cs @@ -1,8 +1,9 @@ -using System; +using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types; +using System; using System.Runtime.InteropServices; using System.Threading; -namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd +namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl { class EventFileDescriptor : IFileDescriptor { @@ -149,4 +150,4 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd } } } -} +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/EventFileDescriptorPollManager.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/EventFileDescriptorPollManager.cs index 6501d1117..e0ab68c62 100644 --- a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/EventFileDescriptorPollManager.cs +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/EventFileDescriptorPollManager.cs @@ -1,8 +1,9 @@ using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types; using System.Collections.Generic; using System.Threading; -namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd +namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl { class EventFileDescriptorPollManager : IPollManager { @@ -109,5 +110,13 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd return LinuxError.SUCCESS; } + + public LinuxError Select(List events, int timeout, out int updatedCount) + { + // TODO: Implement Select for event file descriptors + updatedCount = 0; + + return LinuxError.EOPNOTSUPP; + } } -} +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/ManagedSocket.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/ManagedSocket.cs index 3db7c2223..75efc49a1 100644 --- a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/ManagedSocket.cs +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/ManagedSocket.cs @@ -1,4 +1,5 @@ using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types; using System; using System.Collections.Generic; using System.Diagnostics; @@ -6,7 +7,7 @@ using System.Net; using System.Net.Sockets; using System.Runtime.InteropServices; -namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd +namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl { class ManagedSocket : ISocket { diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/ManagedSocketPollManager.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/ManagedSocketPollManager.cs index 31d93cadf..1b305dfb7 100644 --- a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/ManagedSocketPollManager.cs +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/ManagedSocketPollManager.cs @@ -1,8 +1,9 @@ using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types; using System.Collections.Generic; using System.Net.Sockets; -namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd +namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl { class ManagedSocketPollManager : IPollManager { @@ -117,5 +118,60 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd return LinuxError.SUCCESS; } + + public LinuxError Select(List events, int timeout, out int updatedCount) + { + List readEvents = new(); + List writeEvents = new(); + List errorEvents = new(); + + updatedCount = 0; + + foreach (PollEvent pollEvent in events) + { + ManagedSocket socket = (ManagedSocket)pollEvent.FileDescriptor; + + if (pollEvent.Data.InputEvents.HasFlag(PollEventTypeMask.Input)) + { + readEvents.Add(socket.Socket); + } + + if (pollEvent.Data.InputEvents.HasFlag(PollEventTypeMask.Output)) + { + writeEvents.Add(socket.Socket); + } + + if (pollEvent.Data.InputEvents.HasFlag(PollEventTypeMask.Error)) + { + errorEvents.Add(socket.Socket); + } + } + + Socket.Select(readEvents, writeEvents, errorEvents, timeout); + + updatedCount = readEvents.Count + writeEvents.Count + errorEvents.Count; + + foreach (PollEvent pollEvent in events) + { + ManagedSocket socket = (ManagedSocket)pollEvent.FileDescriptor; + + if (readEvents.Contains(socket.Socket)) + { + pollEvent.Data.OutputEvents |= PollEventTypeMask.Input; + } + + if (writeEvents.Contains(socket.Socket)) + { + pollEvent.Data.OutputEvents |= PollEventTypeMask.Output; + } + + if (errorEvents.Contains(socket.Socket)) + { + pollEvent.Data.OutputEvents |= PollEventTypeMask.Error; + } + } + + return LinuxError.SUCCESS; + } } -} +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/WSAError.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/WSAError.cs index d87e72d82..0f24a57f5 100644 --- a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/WSAError.cs +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/WSAError.cs @@ -1,6 +1,6 @@ using System.Diagnostics.CodeAnalysis; -namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd +namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl { [SuppressMessage("ReSharper", "InconsistentNaming")] enum WsaError diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/WinSockHelper.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/WinSockHelper.cs index ad12745e8..48439d7d3 100644 --- a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/WinSockHelper.cs +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/WinSockHelper.cs @@ -1,7 +1,8 @@ -using System.Collections.Generic; +using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types; +using System.Collections.Generic; using System.Net.Sockets; -namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd +namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl { static class WinSockHelper { @@ -162,4 +163,4 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd return table.TryGetValue(option, out name); } } -} +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdAddressFamily.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdAddressFamily.cs index dcc9f0fd7..37461bb25 100644 --- a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdAddressFamily.cs +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdAddressFamily.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd +namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types { enum BsdAddressFamily : uint { @@ -8,4 +8,4 @@ Unknown = uint.MaxValue } -} +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdIoctl.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdIoctl.cs index 421a255cc..1dfa5a5f9 100644 --- a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdIoctl.cs +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdIoctl.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd +namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types { enum BsdIoctl { diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdMMsgHdr.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdMMsgHdr.cs index bfcc92cd8..f97b8f5be 100644 --- a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdMMsgHdr.cs +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdMMsgHdr.cs @@ -1,6 +1,6 @@ using System; -namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd +namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types { class BsdMMsgHdr { diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdMsgHdr.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdMsgHdr.cs index bb620375c..07c97182c 100644 --- a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdMsgHdr.cs +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdMsgHdr.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.InteropServices; -namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd +namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types { class BsdMsgHdr { diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSockAddr.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSockAddr.cs index 71926ceba..67c11e54d 100644 --- a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSockAddr.cs +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSockAddr.cs @@ -3,7 +3,7 @@ using System; using System.Net; using System.Runtime.InteropServices; -namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd +namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types { [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x10)] struct BsdSockAddr diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSocketCreationFlags.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSocketCreationFlags.cs index 77718800d..be5991ff6 100644 --- a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSocketCreationFlags.cs +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSocketCreationFlags.cs @@ -1,6 +1,6 @@ using System; -namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd +namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types { [Flags] enum BsdSocketCreationFlags diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSocketFlags.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSocketFlags.cs index a92a8e2fb..905d56c20 100644 --- a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSocketFlags.cs +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSocketFlags.cs @@ -1,6 +1,5 @@ using System; -namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd { [Flags] enum BsdSocketFlags diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSocketOption.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSocketOption.cs index 726e4111e..4d0d1dcf3 100644 --- a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSocketOption.cs +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSocketOption.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd +namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types { enum BsdSocketOption { diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSocketShutdownFlags.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSocketShutdownFlags.cs index 2588376bb..13230ac39 100644 --- a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSocketShutdownFlags.cs +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSocketShutdownFlags.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd +namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types { enum BsdSocketShutdownFlags { diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSocketType.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSocketType.cs index 9b13e669a..b54c78863 100644 --- a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSocketType.cs +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSocketType.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd +namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types { enum BsdSocketType { diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/EventFdFlags.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/EventFdFlags.cs index 7d08fb24a..e01d82267 100644 --- a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/EventFdFlags.cs +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/EventFdFlags.cs @@ -1,6 +1,6 @@ using System; -namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd +namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types { [Flags] enum EventFdFlags : uint diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/IPollManager.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/IPollManager.cs index 8b0959fd0..d36638784 100644 --- a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/IPollManager.cs +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/IPollManager.cs @@ -1,11 +1,13 @@ using System.Collections.Generic; -namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd +namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types { interface IPollManager { bool IsCompatible(PollEvent evnt); LinuxError Poll(List events, int timeoutMilliseconds, out int updatedCount); + + LinuxError Select(List events, int timeout, out int updatedCount); } -} +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/LinuxError.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/LinuxError.cs index b13269852..96602830b 100644 --- a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/LinuxError.cs +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/LinuxError.cs @@ -1,6 +1,6 @@ using System.Diagnostics.CodeAnalysis; -namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd +namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types { [SuppressMessage("ReSharper", "InconsistentNaming")] enum LinuxError diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/PollEvent.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/PollEvent.cs index 8056e7a87..8b77a6c2f 100644 --- a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/PollEvent.cs +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/PollEvent.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd +namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types { class PollEvent { diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/PollEventData.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/PollEventData.cs index df084ff4a..546b738ee 100644 --- a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/PollEventData.cs +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/PollEventData.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd +namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types { struct PollEventData { @@ -8,4 +8,4 @@ #pragma warning restore CS0649 public PollEventTypeMask OutputEvents; } -} +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/PollEventTypeMask.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/PollEventTypeMask.cs index 899072bf0..f434fa032 100644 --- a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/PollEventTypeMask.cs +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/PollEventTypeMask.cs @@ -1,6 +1,6 @@ using System; -namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd +namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types { [Flags] enum PollEventTypeMask : ushort diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/TimeVal.cs b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/TimeVal.cs index c57766023..690a63aeb 100644 --- a/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/TimeVal.cs +++ b/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/TimeVal.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd +namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types { public struct TimeVal { diff --git a/Ryujinx.HLE/HOS/Services/Ssl/SslService/SslManagedSocketConnection.cs b/Ryujinx.HLE/HOS/Services/Ssl/SslService/SslManagedSocketConnection.cs index 56bfa709b..47d3eddbe 100644 --- a/Ryujinx.HLE/HOS/Services/Ssl/SslService/SslManagedSocketConnection.cs +++ b/Ryujinx.HLE/HOS/Services/Ssl/SslService/SslManagedSocketConnection.cs @@ -1,4 +1,5 @@ using Ryujinx.HLE.HOS.Services.Sockets.Bsd; +using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl; using Ryujinx.HLE.HOS.Services.Ssl.Types; using System; using System.IO; diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs index 4c9886942..f4b3a9590 100644 --- a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs +++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs @@ -130,7 +130,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone } List<(int Offset, string Location, string Abbr)> outList = new List<(int Offset, string Location, string Abbr)>(); - var now = System.DateTimeOffset.Now.ToUnixTimeSeconds(); + var now = DateTimeOffset.Now.ToUnixTimeSeconds(); using (IStorage ncaStorage = new LocalStorage(_virtualFileSystem.SwitchPathToSystemPath(tzBinaryContentPath), FileAccess.Read, FileMode.Open)) using (IFileSystem romfs = new Nca(_virtualFileSystem.KeySet, ncaStorage).OpenFileSystem(NcaSectionType.Data, _fsIntegrityCheckLevel)) { diff --git a/Ryujinx.HLE/Ryujinx.HLE.csproj b/Ryujinx.HLE/Ryujinx.HLE.csproj index 82f3483cd..ec5d26807 100644 --- a/Ryujinx.HLE/Ryujinx.HLE.csproj +++ b/Ryujinx.HLE/Ryujinx.HLE.csproj @@ -36,6 +36,7 @@ + @@ -44,6 +45,7 @@ + diff --git a/Ryujinx.Headless.SDL2/Program.cs b/Ryujinx.Headless.SDL2/Program.cs index bfc33edcf..50a90763f 100644 --- a/Ryujinx.Headless.SDL2/Program.cs +++ b/Ryujinx.Headless.SDL2/Program.cs @@ -77,6 +77,26 @@ namespace Ryujinx.Headless.SDL2 _accountManager = new AccountManager(_libHacHorizonManager.RyujinxClient); _userChannelPersistence = new UserChannelPersistence(); + if (OperatingSystem.IsMacOS()) + { + AutoResetEvent invoked = new AutoResetEvent(false); + + // MacOS must perform SDL polls from the main thread. + Ryujinx.SDL2.Common.SDL2Driver.MainThreadDispatcher = (Action action) => + { + invoked.Reset(); + + WindowBase.QueueMainThreadAction(() => + { + action(); + + invoked.Set(); + }); + + invoked.WaitOne(); + }; + } + _inputManager = new InputManager(new SDL2KeyboardDriver(), new SDL2GamepadDriver()); GraphicsConfig.EnableShaderCache = true; diff --git a/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj b/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj index 15286ea3a..6a8b38f7b 100644 --- a/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj +++ b/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj @@ -12,7 +12,7 @@ - + @@ -28,14 +28,18 @@ - + - - Always - THIRDPARTY.md - + + Always + THIRDPARTY.md + + + Always + LICENSE.txt + diff --git a/Ryujinx.Headless.SDL2/Vulkan/VulkanWindow.cs b/Ryujinx.Headless.SDL2/Vulkan/VulkanWindow.cs index 6eacadc15..183233397 100644 --- a/Ryujinx.Headless.SDL2/Vulkan/VulkanWindow.cs +++ b/Ryujinx.Headless.SDL2/Vulkan/VulkanWindow.cs @@ -1,6 +1,7 @@ using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using Ryujinx.Input.HLE; +using Ryujinx.SDL2.Common; using System; using System.Runtime.InteropServices; using static SDL2.SDL; @@ -26,15 +27,34 @@ namespace Ryujinx.Headless.SDL2.Vulkan MouseDriver.SetClientSize(DefaultWidth, DefaultHeight); } + private void BasicInvoke(Action action) + { + action(); + } + public unsafe IntPtr CreateWindowSurface(IntPtr instance) { - if (SDL_Vulkan_CreateSurface(WindowHandle, instance, out ulong surfaceHandle) == SDL_bool.SDL_FALSE) + ulong surfaceHandle = 0; + + Action createSurface = () => { - string errorMessage = $"SDL_Vulkan_CreateSurface failed with error \"{SDL_GetError()}\""; + if (SDL_Vulkan_CreateSurface(WindowHandle, instance, out surfaceHandle) == SDL_bool.SDL_FALSE) + { + string errorMessage = $"SDL_Vulkan_CreateSurface failed with error \"{SDL_GetError()}\""; - Logger.Error?.Print(LogClass.Application, errorMessage); + Logger.Error?.Print(LogClass.Application, errorMessage); - throw new Exception(errorMessage); + throw new Exception(errorMessage); + } + }; + + if (SDL2Driver.MainThreadDispatcher != null) + { + SDL2Driver.MainThreadDispatcher(createSurface); + } + else + { + createSurface(); } return (IntPtr)surfaceHandle; diff --git a/Ryujinx.Headless.SDL2/WindowBase.cs b/Ryujinx.Headless.SDL2/WindowBase.cs index 9aa17936f..88b0d5733 100644 --- a/Ryujinx.Headless.SDL2/WindowBase.cs +++ b/Ryujinx.Headless.SDL2/WindowBase.cs @@ -11,6 +11,7 @@ using Ryujinx.Input; using Ryujinx.Input.HLE; using Ryujinx.SDL2.Common; using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Threading; @@ -26,6 +27,13 @@ namespace Ryujinx.Headless.SDL2 private const SDL_WindowFlags DefaultFlags = SDL_WindowFlags.SDL_WINDOW_ALLOW_HIGHDPI | SDL_WindowFlags.SDL_WINDOW_RESIZABLE | SDL_WindowFlags.SDL_WINDOW_INPUT_FOCUS | SDL_WindowFlags.SDL_WINDOW_SHOWN; private const int TargetFps = 60; + private static ConcurrentQueue MainThreadActions = new ConcurrentQueue(); + + public static void QueueMainThreadAction(Action action) + { + MainThreadActions.Enqueue(action); + } + public NpadManager NpadManager { get; } public TouchScreenManager TouchScreenManager { get; } public Switch Device { get; private set; } @@ -168,6 +176,14 @@ namespace Ryujinx.Headless.SDL2 public void Render() { + InitializeWindowRenderer(); + + Device.Gpu.Renderer.Initialize(_glLogLevel); + + InitializeRenderer(); + + _gpuVendorName = GetGpuVendorName(); + Device.Gpu.Renderer.RunLoop(() => { Device.Gpu.SetGpuThread(); @@ -241,6 +257,14 @@ namespace Ryujinx.Headless.SDL2 _exitEvent.Dispose(); } + public void ProcessMainThreadQueue() + { + while (MainThreadActions.TryDequeue(out Action action)) + { + action(); + } + } + public void MainLoop() { while (_isActive) @@ -249,6 +273,8 @@ namespace Ryujinx.Headless.SDL2 SDL_PumpEvents(); + ProcessMainThreadQueue(); + // Polling becomes expensive if it's not slept Thread.Sleep(1); } @@ -315,14 +341,6 @@ namespace Ryujinx.Headless.SDL2 InitializeWindow(); - InitializeWindowRenderer(); - - Device.Gpu.Renderer.Initialize(_glLogLevel); - - InitializeRenderer(); - - _gpuVendorName = GetGpuVendorName(); - Thread renderLoopThread = new Thread(Render) { Name = "GUI.RenderLoop" diff --git a/Ryujinx.Memory.Tests/Ryujinx.Memory.Tests.csproj b/Ryujinx.Memory.Tests/Ryujinx.Memory.Tests.csproj index d3470def5..46478c61d 100644 --- a/Ryujinx.Memory.Tests/Ryujinx.Memory.Tests.csproj +++ b/Ryujinx.Memory.Tests/Ryujinx.Memory.Tests.csproj @@ -7,7 +7,7 @@ - + diff --git a/Ryujinx.Memory/MemoryManagerUnixHelper.cs b/Ryujinx.Memory/MemoryManagerUnixHelper.cs index 8e6e79352..dd31c328b 100644 --- a/Ryujinx.Memory/MemoryManagerUnixHelper.cs +++ b/Ryujinx.Memory/MemoryManagerUnixHelper.cs @@ -153,7 +153,8 @@ namespace Ryujinx.Memory if (OperatingSystem.IsMacOSVersionAtLeast(10, 14)) { - result |= MAP_JIT_DARWIN; + // Only to be used with the Hardened Runtime. + // result |= MAP_JIT_DARWIN; } return result; diff --git a/Ryujinx.ShaderTools/Ryujinx.ShaderTools.csproj b/Ryujinx.ShaderTools/Ryujinx.ShaderTools.csproj index 51416232e..5c6ca6fb9 100644 --- a/Ryujinx.ShaderTools/Ryujinx.ShaderTools.csproj +++ b/Ryujinx.ShaderTools/Ryujinx.ShaderTools.csproj @@ -11,7 +11,7 @@ - + diff --git a/Ryujinx.Tests.Unicorn/Native/Interface.cs b/Ryujinx.Tests.Unicorn/Native/Interface.cs index 0ecda22ea..889441aba 100644 --- a/Ryujinx.Tests.Unicorn/Native/Interface.cs +++ b/Ryujinx.Tests.Unicorn/Native/Interface.cs @@ -1,5 +1,6 @@ using Ryujinx.Tests.Unicorn.Native.Const; using System; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Reflection; using System.Runtime.InteropServices; @@ -43,9 +44,9 @@ namespace Ryujinx.Tests.Unicorn.Native } } - public static void MarshalArrayOf(IntPtr input, int length, out T[] output) + public static void MarshalArrayOf<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] T>(IntPtr input, int length, out T[] output) { - int size = Marshal.SizeOf(typeof(T)); + int size = Marshal.SizeOf(); output = new T[length]; diff --git a/Ryujinx.Tests.Unicorn/UnicornAArch32.cs b/Ryujinx.Tests.Unicorn/UnicornAArch32.cs index 8b3e79b69..3b8c1699e 100644 --- a/Ryujinx.Tests.Unicorn/UnicornAArch32.cs +++ b/Ryujinx.Tests.Unicorn/UnicornAArch32.cs @@ -122,14 +122,14 @@ namespace Ryujinx.Tests.Unicorn { if (!_isDisposed) { - Interface.Checked(Native.Interface.uc_close(uc)); + Interface.Checked(Interface.uc_close(uc)); _isDisposed = true; } } public void RunForCount(ulong count) { - Interface.Checked(Native.Interface.uc_emu_start(uc, this.PC, 0xFFFFFFFFFFFFFFFFu, 0, count)); + Interface.Checked(Interface.uc_emu_start(uc, this.PC, 0xFFFFFFFFFFFFFFFFu, 0, count)); } public void Step() @@ -222,7 +222,7 @@ namespace Ryujinx.Tests.Unicorn { byte[] data = new byte[4]; - Interface.Checked(Native.Interface.uc_reg_read(uc, (int)register, data)); + Interface.Checked(Interface.uc_reg_read(uc, (int)register, data)); return (uint)BitConverter.ToInt32(data, 0); } diff --git a/Ryujinx.Tests.Unicorn/UnicornAArch64.cs b/Ryujinx.Tests.Unicorn/UnicornAArch64.cs index 5cd5f88cb..1784e7dff 100644 --- a/Ryujinx.Tests.Unicorn/UnicornAArch64.cs +++ b/Ryujinx.Tests.Unicorn/UnicornAArch64.cs @@ -111,14 +111,14 @@ namespace Ryujinx.Tests.Unicorn { if (!_isDisposed) { - Interface.Checked(Native.Interface.uc_close(uc)); + Interface.Checked(Interface.uc_close(uc)); _isDisposed = true; } } public void RunForCount(ulong count) { - Interface.Checked(Native.Interface.uc_emu_start(uc, this.PC, 0xFFFFFFFFFFFFFFFFu, 0, count)); + Interface.Checked(Interface.uc_emu_start(uc, this.PC, 0xFFFFFFFFFFFFFFFFu, 0, count)); } public void Step() @@ -241,7 +241,7 @@ namespace Ryujinx.Tests.Unicorn { byte[] data = new byte[8]; - Interface.Checked(Native.Interface.uc_reg_read(uc, (int)register, data)); + Interface.Checked(Interface.uc_reg_read(uc, (int)register, data)); return (ulong)BitConverter.ToInt64(data, 0); } diff --git a/Ryujinx.Tests/Ryujinx.Tests.csproj b/Ryujinx.Tests/Ryujinx.Tests.csproj index d694ca7e7..e85c4f1cd 100644 --- a/Ryujinx.Tests/Ryujinx.Tests.csproj +++ b/Ryujinx.Tests/Ryujinx.Tests.csproj @@ -19,7 +19,7 @@ - + diff --git a/Ryujinx/Modules/Updater/UpdateDialog.cs b/Ryujinx/Modules/Updater/UpdateDialog.cs index cb71fafc9..4957b681b 100644 --- a/Ryujinx/Modules/Updater/UpdateDialog.cs +++ b/Ryujinx/Modules/Updater/UpdateDialog.cs @@ -25,14 +25,14 @@ namespace Ryujinx.Modules public UpdateDialog(MainWindow mainWindow, Version newVersion, string buildUrl) : this(new Builder("Ryujinx.Modules.Updater.UpdateDialog.glade"), mainWindow, newVersion, buildUrl) { } - private UpdateDialog(Builder builder, MainWindow mainWindow, Version newVersion, string buildUrl) : base(builder.GetObject("UpdateDialog").Handle) + private UpdateDialog(Builder builder, MainWindow mainWindow, Version newVersion, string buildUrl) : base(builder.GetRawOwnedObject("UpdateDialog")) { builder.Autoconnect(this); _mainWindow = mainWindow; _buildUrl = buildUrl; - Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); + Icon = new Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); MainText.Text = "Do you want to update Ryujinx to the latest version?"; SecondaryText.Text = $"{Program.Version} -> {newVersion}"; diff --git a/Ryujinx/Modules/Updater/Updater.cs b/Ryujinx/Modules/Updater/Updater.cs index ded126208..0a1cb53bc 100644 --- a/Ryujinx/Modules/Updater/Updater.cs +++ b/Ryujinx/Modules/Updater/Updater.cs @@ -293,7 +293,7 @@ namespace Ryujinx.Modules list[index] = args.Result; Interlocked.Increment(ref completedRequests); - if (Interlocked.Equals(completedRequests, ConnectionCount)) + if (Equals(completedRequests, ConnectionCount)) { byte[] mergedFileBytes = new byte[_buildSize]; for (int connectionIndex = 0, destinationOffset = 0; connectionIndex < ConnectionCount; connectionIndex++) @@ -387,16 +387,19 @@ namespace Ryujinx.Modules worker.Start(); } - [DllImport("libc", SetLastError = true)] - private static extern int chmod(string path, uint mode); - - private static void SetUnixPermissions() + private static void SetFileExecutable(string path) { - string ryuBin = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx"); + const UnixFileMode ExecutableFileMode = UnixFileMode.UserExecute | + UnixFileMode.UserWrite | + UnixFileMode.UserRead | + UnixFileMode.GroupRead | + UnixFileMode.GroupWrite | + UnixFileMode.OtherRead | + UnixFileMode.OtherWrite; - if (!OperatingSystem.IsWindows()) + if (!OperatingSystem.IsWindows() && File.Exists(path)) { - chmod(ryuBin, 493); + File.SetUnixFileMode(path, ExecutableFileMode); } } @@ -519,7 +522,7 @@ namespace Ryujinx.Modules Directory.Delete(UpdateDir, true); - SetUnixPermissions(); + SetFileExecutable(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx")); updateDialog.MainText.Text = "Update Complete!"; updateDialog.SecondaryText.Text = "Do you want to restart Ryujinx now?"; diff --git a/Ryujinx/Program.cs b/Ryujinx/Program.cs index 162bd89d5..403dde300 100644 --- a/Ryujinx/Program.cs +++ b/Ryujinx/Program.cs @@ -16,6 +16,7 @@ using Ryujinx.Ui.Widgets; using SixLabors.ImageSharp.Formats.Jpeg; using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using System.Threading.Tasks; @@ -40,6 +41,12 @@ namespace Ryujinx [DllImport("user32.dll", SetLastError = true)] public static extern int MessageBoxA(IntPtr hWnd, string text, string caption, uint type); + [DllImport("libc", SetLastError = true)] + static extern int setenv(string name, string value, int overwrite); + + [DllImport("libc")] + static extern IntPtr getenv(string name); + private const uint MB_ICONWARNING = 0x30; static Program() @@ -97,6 +104,35 @@ namespace Ryujinx XInitThreads(); } + if (OperatingSystem.IsMacOS()) + { + string baseDirectory = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory); + string resourcesDataDir; + + if (Path.GetFileName(baseDirectory) == "MacOS") + { + resourcesDataDir = Path.Combine(Directory.GetParent(baseDirectory).FullName, "Resources"); + } + else + { + resourcesDataDir = baseDirectory; + } + + void SetEnvironmentVariableNoCaching(string key, string value) + { + int res = setenv(key, value, 1); + Debug.Assert(res != -1); + } + + // On macOS, GTK3 needs XDG_DATA_DIRS to be set, otherwise it will try searching for "gschemas.compiled" in system directories. + SetEnvironmentVariableNoCaching("XDG_DATA_DIRS", Path.Combine(resourcesDataDir, "share")); + + // On macOS, GTK3 needs GDK_PIXBUF_MODULE_FILE to be set, otherwise it will try searching for "loaders.cache" in system directories. + SetEnvironmentVariableNoCaching("GDK_PIXBUF_MODULE_FILE", Path.Combine(resourcesDataDir, "lib", "gdk-pixbuf-2.0", "2.10.0", "loaders.cache")); + + SetEnvironmentVariableNoCaching("GTK_IM_MODULE_FILE", Path.Combine(resourcesDataDir, "lib", "gtk-3.0", "3.0.0", "immodules.cache")); + } + string systemPath = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.Machine); Environment.SetEnvironmentVariable("Path", $"{Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin")};{systemPath}"); @@ -115,7 +151,7 @@ namespace Ryujinx // Initialize SDL2 driver SDL2Driver.MainThreadDispatcher = action => { - Gtk.Application.Invoke(delegate + Application.Invoke(delegate { action(); }); @@ -246,7 +282,7 @@ namespace Ryujinx ? GraphicsBackend.Vulkan : GraphicsBackend.OpenGl; - ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); + ConfigurationState.Instance.ToFileFormat().SaveConfig(ConfigurationPath); } Application.Run(); diff --git a/Ryujinx/Ryujinx.csproj b/Ryujinx/Ryujinx.csproj index 31f130c4a..b4cc05162 100644 --- a/Ryujinx/Ryujinx.csproj +++ b/Ryujinx/Ryujinx.csproj @@ -19,10 +19,12 @@ - - - - + + + + + + @@ -46,14 +48,18 @@ - + Always alsoft.ini - - + + Always THIRDPARTY.md - + + + Always + LICENSE.txt + @@ -62,10 +68,6 @@ Ryujinx.ico - - $(DefineConstants);MACOS_BUILD - - diff --git a/Ryujinx/Ui/Helper/MetalHelper.cs b/Ryujinx/Ui/Helper/MetalHelper.cs new file mode 100644 index 000000000..62ca29301 --- /dev/null +++ b/Ryujinx/Ui/Helper/MetalHelper.cs @@ -0,0 +1,134 @@ +using Gdk; +using System; +using System.Runtime.Versioning; +using System.Runtime.InteropServices; + +namespace Ryujinx.Ui.Helper +{ + public delegate void UpdateBoundsCallbackDelegate(Window window); + + [SupportedOSPlatform("macos")] + static class MetalHelper + { + private const string LibObjCImport = "/usr/lib/libobjc.A.dylib"; + + private struct Selector + { + public readonly IntPtr NativePtr; + + public unsafe Selector(string value) + { + int size = System.Text.Encoding.UTF8.GetMaxByteCount(value.Length); + byte* data = stackalloc byte[size]; + + fixed (char* pValue = value) + { + System.Text.Encoding.UTF8.GetBytes(pValue, value.Length, data, size); + } + + NativePtr = sel_registerName(data); + } + + public static implicit operator Selector(string value) => new Selector(value); + } + + private static unsafe IntPtr GetClass(string value) + { + int size = System.Text.Encoding.UTF8.GetMaxByteCount(value.Length); + byte* data = stackalloc byte[size]; + + fixed (char* pValue = value) + { + System.Text.Encoding.UTF8.GetBytes(pValue, value.Length, data, size); + } + + return objc_getClass(data); + } + + private struct NSPoint + { + public double X; + public double Y; + + public NSPoint(double x, double y) + { + X = x; + Y = y; + } + } + + private struct NSRect + { + public NSPoint Pos; + public NSPoint Size; + + public NSRect(double x, double y, double width, double height) + { + Pos = new NSPoint(x, y); + Size = new NSPoint(width, height); + } + } + + public static IntPtr GetMetalLayer(Display display, Window window, out IntPtr nsView, out UpdateBoundsCallbackDelegate updateBounds) + { + nsView = gdk_quartz_window_get_nsview(window.Handle); + + // Create a new CAMetalLayer. + IntPtr layerClass = GetClass("CAMetalLayer"); + IntPtr metalLayer = IntPtr_objc_msgSend(layerClass, "alloc"); + objc_msgSend(metalLayer, "init"); + + // Create a child NSView to render into. + IntPtr nsViewClass = GetClass("NSView"); + IntPtr child = IntPtr_objc_msgSend(nsViewClass, "alloc"); + objc_msgSend(child, "init", new NSRect()); + + // Add it as a child. + objc_msgSend(nsView, "addSubview:", child); + + // Make its renderer our metal layer. + objc_msgSend(child, "setWantsLayer:", (byte)1); + objc_msgSend(child, "setLayer:", metalLayer); + objc_msgSend(metalLayer, "setContentsScale:", (double)display.GetMonitorAtWindow(window).ScaleFactor); + + // Set the frame position/location. + updateBounds = (Window window) => { + window.GetPosition(out int x, out int y); + int width = window.Width; + int height = window.Height; + objc_msgSend(child, "setFrame:", new NSRect(x, y, width, height)); + }; + + updateBounds(window); + + return metalLayer; + } + + [DllImport(LibObjCImport)] + private static unsafe extern IntPtr sel_registerName(byte* data); + + [DllImport(LibObjCImport)] + private static unsafe extern IntPtr objc_getClass(byte* data); + + [DllImport(LibObjCImport)] + private static extern void objc_msgSend(IntPtr receiver, Selector selector); + + [DllImport(LibObjCImport)] + private static extern void objc_msgSend(IntPtr receiver, Selector selector, byte value); + + [DllImport(LibObjCImport)] + private static extern void objc_msgSend(IntPtr receiver, Selector selector, IntPtr value); + + [DllImport(LibObjCImport)] + private static extern void objc_msgSend(IntPtr receiver, Selector selector, NSRect point); + + [DllImport(LibObjCImport)] + private static extern void objc_msgSend(IntPtr receiver, Selector selector, double value); + + [DllImport(LibObjCImport, EntryPoint = "objc_msgSend")] + private static extern IntPtr IntPtr_objc_msgSend(IntPtr receiver, Selector selector); + + [DllImport("libgdk-3.0.dylib")] + private static extern IntPtr gdk_quartz_window_get_nsview(IntPtr gdkWindow); + } +} \ No newline at end of file diff --git a/Ryujinx/Ui/MainWindow.cs b/Ryujinx/Ui/MainWindow.cs index 5216c7747..3a5b7723d 100644 --- a/Ryujinx/Ui/MainWindow.cs +++ b/Ryujinx/Ui/MainWindow.cs @@ -142,7 +142,7 @@ namespace Ryujinx.Ui public MainWindow() : this(new Builder("Ryujinx.Ui.MainWindow.glade")) { } - private MainWindow(Builder builder) : base(builder.GetObject("_mainWin").Handle) + private MainWindow(Builder builder) : base(builder.GetRawOwnedObject("_mainWin")) { builder.Autoconnect(this); @@ -846,9 +846,7 @@ namespace Ryujinx.Ui _deviceExitStatus.Reset(); Translator.IsReadyForTranslation.Reset(); -#if MACOS_BUILD - CreateGameWindow(); -#else + Thread windowThread = new Thread(() => { CreateGameWindow(); @@ -858,7 +856,6 @@ namespace Ryujinx.Ui }; windowThread.Start(); -#endif _gameLoaded = true; _actionMenu.Sensitive = true; diff --git a/Ryujinx/Ui/RendererWidgetBase.cs b/Ryujinx/Ui/RendererWidgetBase.cs index 576d2d121..9dabe8173 100644 --- a/Ryujinx/Ui/RendererWidgetBase.cs +++ b/Ryujinx/Ui/RendererWidgetBase.cs @@ -132,7 +132,7 @@ namespace Ryujinx.Ui private void HideCursorStateChanged(object sender, ReactiveEventArgs state) { - Gtk.Application.Invoke(delegate + Application.Invoke(delegate { _hideCursorOnIdle = state.NewValue; @@ -248,7 +248,7 @@ namespace Ryujinx.Ui && keyboard.IsPressed(Key.Enter)) || keyboard.IsPressed(Key.Escape); - bool fullScreenToggled = ParentWindow.State.HasFlag(Gdk.WindowState.Fullscreen); + bool fullScreenToggled = ParentWindow.State.HasFlag(WindowState.Fullscreen); if (toggleFullscreen != _toggleFullscreen) { @@ -340,7 +340,7 @@ namespace Ryujinx.Ui string directory = AppDataManager.Mode switch { AppDataManager.LaunchMode.Portable => System.IO.Path.Combine(AppDataManager.BaseDirPath, "screenshots"), - _ => System.IO.Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyPictures), "Ryujinx") + _ => System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "Ryujinx") }; string path = System.IO.Path.Combine(directory, filename); @@ -434,7 +434,7 @@ namespace Ryujinx.Ui if (_ticks >= _ticksPerFrame) { string dockedMode = ConfigurationState.Instance.System.EnableDockedMode ? "Docked" : "Handheld"; - float scale = Graphics.Gpu.GraphicsConfig.ResScale; + float scale = GraphicsConfig.ResScale; if (scale != 1) { dockedMode += $" ({scale}x)"; diff --git a/Ryujinx/Ui/VKRenderer.cs b/Ryujinx/Ui/VKRenderer.cs index 7e02c689d..63d0d0a62 100644 --- a/Ryujinx/Ui/VKRenderer.cs +++ b/Ryujinx/Ui/VKRenderer.cs @@ -1,9 +1,11 @@ using Gdk; using Ryujinx.Common.Configuration; using Ryujinx.Input.HLE; +using Ryujinx.Ui.Helper; using SPB.Graphics.Vulkan; using SPB.Platform.Win32; using SPB.Platform.X11; +using SPB.Platform.Metal; using SPB.Windowing; using System; using System.Runtime.InteropServices; @@ -13,6 +15,7 @@ namespace Ryujinx.Ui public class VKRenderer : RendererWidgetBase { public NativeWindowBase NativeWindow { get; private set; } + private UpdateBoundsCallbackDelegate _updateBoundsCallback; public VKRenderer(InputManager inputManager, GraphicsDebugLevel glLogLevel) : base(inputManager, glLogLevel) { } @@ -31,6 +34,12 @@ namespace Ryujinx.Ui return new SimpleX11Window(new NativeHandle(displayHandle), new NativeHandle(windowHandle)); } + else if (OperatingSystem.IsMacOS()) + { + IntPtr metalLayer = MetalHelper.GetMetalLayer(Display, Window, out IntPtr nsView, out _updateBoundsCallback); + + return new SimpleMetalWindow(new NativeHandle(nsView), new NativeHandle(metalLayer)); + } throw new NotImplementedException(); } @@ -53,7 +62,11 @@ namespace Ryujinx.Ui WaitEvent.Set(); } - return base.OnConfigureEvent(evnt); + bool result = base.OnConfigureEvent(evnt); + + _updateBoundsCallback?.Invoke(Window); + + return result; } public unsafe IntPtr CreateWindowSurface(IntPtr instance) diff --git a/Ryujinx/Ui/Widgets/ProfileDialog.cs b/Ryujinx/Ui/Widgets/ProfileDialog.cs index 8748737c7..96b44d240 100644 --- a/Ryujinx/Ui/Widgets/ProfileDialog.cs +++ b/Ryujinx/Ui/Widgets/ProfileDialog.cs @@ -18,7 +18,7 @@ namespace Ryujinx.Ui.Widgets public ProfileDialog() : this(new Builder("Ryujinx.Ui.Widgets.ProfileDialog.glade")) { } - private ProfileDialog(Builder builder) : base(builder.GetObject("_profileDialog").Handle) + private ProfileDialog(Builder builder) : base(builder.GetRawOwnedObject("_profileDialog")) { builder.Autoconnect(this); Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); diff --git a/Ryujinx/Ui/Windows/AvatarWindow.cs b/Ryujinx/Ui/Windows/AvatarWindow.cs index 6dc860f3c..c715907d7 100644 --- a/Ryujinx/Ui/Windows/AvatarWindow.cs +++ b/Ryujinx/Ui/Windows/AvatarWindow.cs @@ -46,7 +46,7 @@ namespace Ryujinx.Ui.Windows SetDefaultSize(740, 400); SetPosition(WindowPosition.Center); - VBox vbox = new VBox(false, 0); + Box vbox = new(Orientation.Vertical, 0); Add(vbox); ScrolledWindow scrolledWindow = new ScrolledWindow @@ -55,7 +55,7 @@ namespace Ryujinx.Ui.Windows }; scrolledWindow.SetPolicy(PolicyType.Automatic, PolicyType.Automatic); - HBox hbox = new HBox(false, 0); + Box hbox = new(Orientation.Horizontal, 0); Button chooseButton = new Button() { diff --git a/Ryujinx/Ui/Windows/CheatWindow.cs b/Ryujinx/Ui/Windows/CheatWindow.cs index a9dccd34f..917603b29 100644 --- a/Ryujinx/Ui/Windows/CheatWindow.cs +++ b/Ryujinx/Ui/Windows/CheatWindow.cs @@ -23,7 +23,7 @@ namespace Ryujinx.Ui.Windows public CheatWindow(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName) : this(new Builder("Ryujinx.Ui.Windows.CheatWindow.glade"), virtualFileSystem, titleId, titleName) { } - private CheatWindow(Builder builder, VirtualFileSystem virtualFileSystem, ulong titleId, string titleName) : base(builder.GetObject("_cheatWindow").Handle) + private CheatWindow(Builder builder, VirtualFileSystem virtualFileSystem, ulong titleId, string titleName) : base(builder.GetRawOwnedObject("_cheatWindow")) { builder.Autoconnect(this); _baseTitleInfoLabel.Text = $"Cheats Available for {titleName} [{titleId:X16}]"; diff --git a/Ryujinx/Ui/Windows/ControllerWindow.cs b/Ryujinx/Ui/Windows/ControllerWindow.cs index d043d0238..002f8fe22 100644 --- a/Ryujinx/Ui/Windows/ControllerWindow.cs +++ b/Ryujinx/Ui/Windows/ControllerWindow.cs @@ -119,7 +119,7 @@ namespace Ryujinx.Ui.Windows public ControllerWindow(MainWindow mainWindow, PlayerIndex controllerId) : this(mainWindow, new Builder("Ryujinx.Ui.Windows.ControllerWindow.glade"), controllerId) { } - private ControllerWindow(MainWindow mainWindow, Builder builder, PlayerIndex controllerId) : base(builder.GetObject("_controllerWin").Handle) + private ControllerWindow(MainWindow mainWindow, Builder builder, PlayerIndex controllerId) : base(builder.GetRawOwnedObject("_controllerWin")) { _mainWindow = mainWindow; _selectedGamepad = null; @@ -379,13 +379,16 @@ namespace Ryujinx.Ui.Windows break; } - _controllerImage.Pixbuf = _controllerType.ActiveId switch + if (!OperatingSystem.IsMacOS()) { - "ProController" => new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Controller_ProCon.svg", 400, 400), - "JoyconLeft" => new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Controller_JoyConLeft.svg", 400, 500), - "JoyconRight" => new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Controller_JoyConRight.svg", 400, 500), - _ => new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Controller_JoyConPair.svg", 400, 500), - }; + _controllerImage.Pixbuf = _controllerType.ActiveId switch + { + "ProController" => new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Controller_ProCon.svg", 400, 400), + "JoyconLeft" => new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Controller_JoyConLeft.svg", 400, 500), + "JoyconRight" => new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Controller_JoyConRight.svg", 400, 500), + _ => new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Controller_JoyConPair.svg", 400, 500), + }; + } } private void ClearValues() diff --git a/Ryujinx/Ui/Windows/DlcWindow.cs b/Ryujinx/Ui/Windows/DlcWindow.cs index 1a47ae414..0a97ac2a2 100644 --- a/Ryujinx/Ui/Windows/DlcWindow.cs +++ b/Ryujinx/Ui/Windows/DlcWindow.cs @@ -34,7 +34,7 @@ namespace Ryujinx.Ui.Windows public DlcWindow(VirtualFileSystem virtualFileSystem, string titleId, string titleName) : this(new Builder("Ryujinx.Ui.Windows.DlcWindow.glade"), virtualFileSystem, titleId, titleName) { } - private DlcWindow(Builder builder, VirtualFileSystem virtualFileSystem, string titleId, string titleName) : base(builder.GetObject("_dlcWindow").Handle) + private DlcWindow(Builder builder, VirtualFileSystem virtualFileSystem, string titleId, string titleName) : base(builder.GetRawOwnedObject("_dlcWindow")) { builder.Autoconnect(this); diff --git a/Ryujinx/Ui/Windows/SettingsWindow.cs b/Ryujinx/Ui/Windows/SettingsWindow.cs index 901973188..220bb82ae 100644 --- a/Ryujinx/Ui/Windows/SettingsWindow.cs +++ b/Ryujinx/Ui/Windows/SettingsWindow.cs @@ -113,7 +113,7 @@ namespace Ryujinx.Ui.Windows public SettingsWindow(MainWindow parent, VirtualFileSystem virtualFileSystem, ContentManager contentManager) : this(parent, new Builder("Ryujinx.Ui.Windows.SettingsWindow.glade"), virtualFileSystem, contentManager) { } - private SettingsWindow(MainWindow parent, Builder builder, VirtualFileSystem virtualFileSystem, ContentManager contentManager) : base(builder.GetObject("_settingsWin").Handle) + private SettingsWindow(MainWindow parent, Builder builder, VirtualFileSystem virtualFileSystem, ContentManager contentManager) : base(builder.GetRawOwnedObject("_settingsWin")) { Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); @@ -422,7 +422,7 @@ namespace Ryujinx.Ui.Windows Task.Run(() => { openAlIsSupported = OpenALHardwareDeviceDriver.IsSupported; - soundIoIsSupported = SoundIoHardwareDeviceDriver.IsSupported; + soundIoIsSupported = !OperatingSystem.IsMacOS() && SoundIoHardwareDeviceDriver.IsSupported; sdl2IsSupported = SDL2HardwareDeviceDriver.IsSupported; }); @@ -438,6 +438,15 @@ namespace Ryujinx.Ui.Windows _ => throw new ArgumentOutOfRangeException() }; }); + + if (OperatingSystem.IsMacOS()) + { + var store = (_graphicsBackend.Model as ListStore); + store.GetIter(out TreeIter openglIter, new TreePath(new int[] {1})); + store.Remove(ref openglIter); + + _graphicsBackend.Model = store; + } } private void UpdatePreferredGpuComboBox() diff --git a/Ryujinx/Ui/Windows/TitleUpdateWindow.cs b/Ryujinx/Ui/Windows/TitleUpdateWindow.cs index 94bf9e709..2618168cd 100644 --- a/Ryujinx/Ui/Windows/TitleUpdateWindow.cs +++ b/Ryujinx/Ui/Windows/TitleUpdateWindow.cs @@ -40,7 +40,7 @@ namespace Ryujinx.Ui.Windows public TitleUpdateWindow(MainWindow parent, VirtualFileSystem virtualFileSystem, string titleId, string titleName) : this(new Builder("Ryujinx.Ui.Windows.TitleUpdateWindow.glade"), parent, virtualFileSystem, titleId, titleName) { } - private TitleUpdateWindow(Builder builder, MainWindow parent, VirtualFileSystem virtualFileSystem, string titleId, string titleName) : base(builder.GetObject("_titleUpdateWindow").Handle) + private TitleUpdateWindow(Builder builder, MainWindow parent, VirtualFileSystem virtualFileSystem, string titleId, string titleName) : base(builder.GetRawOwnedObject("_titleUpdateWindow")) { _parent = parent; diff --git a/Ryujinx/Ui/Windows/UserProfilesManagerWindow.Designer.cs b/Ryujinx/Ui/Windows/UserProfilesManagerWindow.Designer.cs index 702912905..7c9ae8baa 100644 --- a/Ryujinx/Ui/Windows/UserProfilesManagerWindow.Designer.cs +++ b/Ryujinx/Ui/Windows/UserProfilesManagerWindow.Designer.cs @@ -52,7 +52,8 @@ namespace Ryujinx.Ui.Windows _selectedLabel = new Label("Selected User Profile:") { Margin = 15, - Attributes = new AttrList() + Attributes = new AttrList(), + Halign = Align.Start }; _selectedLabel.Attributes.Insert(new Pango.AttrWeight(Weight.Bold)); @@ -136,7 +137,8 @@ namespace Ryujinx.Ui.Windows _availableUsersLabel = new Label("Available User Profiles:") { Margin = 15, - Attributes = new AttrList() + Attributes = new AttrList(), + Halign = Align.Start }; _availableUsersLabel.Attributes.Insert(new Pango.AttrWeight(Weight.Bold)); @@ -226,10 +228,9 @@ namespace Ryujinx.Ui.Windows _usersTreeViewWindow.Add(_usersTreeView); _usersTreeViewBox.Add(_usersTreeViewWindow); - - _bottomBox.PackStart(new Gtk.Alignment(-1, 0, 0, 0) { _addButton }, false, false, 0); - _bottomBox.PackStart(new Gtk.Alignment(-1, 0, 0, 0) { _deleteButton }, false, false, 0); - _bottomBox.PackEnd(new Gtk.Alignment(1, 0, 0, 0) { _closeButton }, false, false, 0); + _bottomBox.PackStart(_addButton, false, false, 0); + _bottomBox.PackStart(_deleteButton, false, false, 0); + _bottomBox.PackEnd(_closeButton, false, false, 0); _selectedUserInfoBox.Add(_selectedUserNameEntry); _selectedUserInfoBox.Add(_selectedUserIdLabel); @@ -238,12 +239,12 @@ namespace Ryujinx.Ui.Windows _selectedUserButtonsBox.Add(_changeProfileImageButton); _selectedUserBox.Add(_selectedUserImage); - _selectedUserBox.PackStart(new Gtk.Alignment(-1, 0, 0, 0) { _selectedUserInfoBox }, true, true, 0); - _selectedUserBox.Add(_selectedUserButtonsBox); + _selectedUserBox.PackStart(_selectedUserInfoBox, false, false, 0); + _selectedUserBox.PackEnd(_selectedUserButtonsBox, false, false, 0); - _mainBox.PackStart(new Gtk.Alignment(-1, 0, 0, 0) { _selectedLabel }, false, false, 0); + _mainBox.PackStart(_selectedLabel, false, false, 0); _mainBox.PackStart(_selectedUserBox, false, true, 0); - _mainBox.PackStart(new Gtk.Alignment(-1, 0, 0, 0) { _availableUsersLabel }, false, false, 0); + _mainBox.PackStart(_availableUsersLabel, false, false, 0); _mainBox.Add(_usersTreeViewBox); _mainBox.Add(_bottomBox);