mirror of
https://git.naxdy.org/Mirror/Ryujinx.git
synced 2025-03-15 06:10:18 +00:00
Merge branch 'master' into fix-bitwise-warn
This commit is contained in:
commit
fb4893e2ed
148 changed files with 1985 additions and 2810 deletions
1
.github/workflows/release.yml
vendored
1
.github/workflows/release.yml
vendored
|
@ -11,6 +11,7 @@ on:
|
||||||
- '*.yml'
|
- '*.yml'
|
||||||
- 'README.md'
|
- 'README.md'
|
||||||
|
|
||||||
|
concurrency: release
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
|
|
|
@ -1341,7 +1341,7 @@ namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
string reversedEncoding = encoding.Substring(16) + encoding.Substring(0, 16);
|
string reversedEncoding = encoding.Substring(16) + encoding.Substring(0, 16);
|
||||||
MakeOp reversedMakeOp =
|
MakeOp reversedMakeOp =
|
||||||
(InstDescriptor inst, ulong address, int opCode)
|
(inst, address, opCode)
|
||||||
=> makeOp(inst, address, (int)BitOperations.RotateRight((uint)opCode, 16));
|
=> makeOp(inst, address, (int)BitOperations.RotateRight((uint)opCode, 16));
|
||||||
Set(reversedEncoding, AllInstT32, new InstDescriptor(name, emitter), reversedMakeOp);
|
Set(reversedEncoding, AllInstT32, new InstDescriptor(name, emitter), reversedMakeOp);
|
||||||
}
|
}
|
||||||
|
|
178
Ryujinx.Audio.Backends.SoundIo/Native/SoundIo.cs
Normal file
178
Ryujinx.Audio.Backends.SoundIo/Native/SoundIo.cs
Normal file
|
@ -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<SoundIoChannelId> 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>((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);
|
||||||
|
}
|
||||||
|
}
|
13
Ryujinx.Audio.Backends.SoundIo/Native/SoundIoBackend.cs
Normal file
13
Ryujinx.Audio.Backends.SoundIo/Native/SoundIoBackend.cs
Normal file
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
75
Ryujinx.Audio.Backends.SoundIo/Native/SoundIoChannelId.cs
Normal file
75
Ryujinx.Audio.Backends.SoundIo/Native/SoundIoChannelId.cs
Normal file
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
107
Ryujinx.Audio.Backends.SoundIo/Native/SoundIoContext.cs
Normal file
107
Ryujinx.Audio.Backends.SoundIo/Native/SoundIoContext.cs
Normal file
|
@ -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<SoundIoError> _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<SoundIoError> 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>((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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Ryujinx.Audio.Backends.SoundIo.Native
|
||||||
|
{
|
||||||
|
public enum SoundIoDeviceAim
|
||||||
|
{
|
||||||
|
SoundIoDeviceAimInput = 0,
|
||||||
|
SoundIoDeviceAimOutput = 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>((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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
Ryujinx.Audio.Backends.SoundIo/Native/SoundIoError.cs
Normal file
22
Ryujinx.Audio.Backends.SoundIo/Native/SoundIoError.cs
Normal file
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
11
Ryujinx.Audio.Backends.SoundIo/Native/SoundIoException.cs
Normal file
11
Ryujinx.Audio.Backends.SoundIo/Native/SoundIoException.cs
Normal file
|
@ -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))) { }
|
||||||
|
}
|
||||||
|
}
|
25
Ryujinx.Audio.Backends.SoundIo/Native/SoundIoFormat.cs
Normal file
25
Ryujinx.Audio.Backends.SoundIo/Native/SoundIoFormat.cs
Normal file
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
164
Ryujinx.Audio.Backends.SoundIo/Native/SoundIoOutStreamContext.cs
Normal file
164
Ryujinx.Audio.Backends.SoundIo/Native/SoundIoOutStreamContext.cs
Normal file
|
@ -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<int, int> _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>((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<int, int> 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<SoundIoChannelArea> 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<SoundIoChannelArea>((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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,386 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace SoundIOSharp
|
|
||||||
{
|
|
||||||
public class SoundIO : IDisposable
|
|
||||||
{
|
|
||||||
Pointer<SoundIo> handle;
|
|
||||||
|
|
||||||
public SoundIO()
|
|
||||||
{
|
|
||||||
handle = Natives.soundio_create();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal SoundIO(Pointer<SoundIo> 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<IntPtr> allocated_hglobals = new List<IntPtr>();
|
|
||||||
|
|
||||||
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<SoundIo>("app_name");
|
|
||||||
|
|
||||||
public SoundIOBackend CurrentBackend
|
|
||||||
{
|
|
||||||
get { return (SoundIOBackend)Marshal.ReadInt32(handle, current_backend_offset); }
|
|
||||||
}
|
|
||||||
|
|
||||||
static readonly int current_backend_offset = (int)Marshal.OffsetOf<SoundIo>("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<SoundIo>("emit_rtprio_warning");
|
|
||||||
|
|
||||||
Action emit_rtprio_warning;
|
|
||||||
|
|
||||||
// jack_error_callback
|
|
||||||
public Action<string> 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<SoundIo>("jack_error_callback");
|
|
||||||
|
|
||||||
Action<string> jack_error_callback;
|
|
||||||
delegate void jack_error_delegate(string message);
|
|
||||||
jack_error_delegate jack_error_callback_native;
|
|
||||||
|
|
||||||
// jack_info_callback
|
|
||||||
public Action<string> 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<SoundIo>("jack_info_callback");
|
|
||||||
|
|
||||||
Action<string> jack_info_callback;
|
|
||||||
delegate void jack_info_delegate(string message);
|
|
||||||
jack_info_delegate jack_info_callback_native;
|
|
||||||
|
|
||||||
// on_backend_disconnect
|
|
||||||
public Action<int> 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<SoundIo>("on_backend_disconnect");
|
|
||||||
|
|
||||||
Action<int> 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<SoundIo>("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<SoundIo>("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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
namespace SoundIOSharp
|
|
||||||
{
|
|
||||||
public enum SoundIOBackend
|
|
||||||
{
|
|
||||||
None,
|
|
||||||
Jack,
|
|
||||||
PulseAudio,
|
|
||||||
Alsa,
|
|
||||||
CoreAudio,
|
|
||||||
Wasapi,
|
|
||||||
Dummy
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace SoundIOSharp
|
|
||||||
{
|
|
||||||
public struct SoundIOChannelArea
|
|
||||||
{
|
|
||||||
internal SoundIOChannelArea(Pointer<SoundIoChannelArea> handle)
|
|
||||||
{
|
|
||||||
this.handle = handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
Pointer<SoundIoChannelArea> 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<SoundIoChannelArea>("ptr");
|
|
||||||
|
|
||||||
public int Step
|
|
||||||
{
|
|
||||||
get { return Marshal.ReadInt32(handle, step_offset); }
|
|
||||||
}
|
|
||||||
|
|
||||||
static readonly int step_offset = (int)Marshal.OffsetOf<SoundIoChannelArea>("step");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace SoundIOSharp
|
|
||||||
{
|
|
||||||
public struct SoundIOChannelAreas
|
|
||||||
{
|
|
||||||
static readonly int native_size = Marshal.SizeOf<SoundIoChannelArea>();
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<SoundIoChannelLayout> handle)
|
|
||||||
{
|
|
||||||
this.handle = handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
readonly Pointer<SoundIoChannelLayout> 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<SoundIoChannelLayout>("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<SoundIoChannelLayout>("name");
|
|
||||||
|
|
||||||
public IEnumerable<SoundIOChannelId> 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<SoundIoChannelLayout>("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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<SoundIoDevice> handle)
|
|
||||||
{
|
|
||||||
this.handle = handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
readonly Pointer<SoundIoDevice> 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<SoundIoDevice>("aim");
|
|
||||||
|
|
||||||
public SoundIOFormat CurrentFormat
|
|
||||||
{
|
|
||||||
get { return (SoundIOFormat)Marshal.ReadInt32(handle, current_format_offset); }
|
|
||||||
}
|
|
||||||
|
|
||||||
static readonly int current_format_offset = (int)Marshal.OffsetOf<SoundIoDevice>("current_format");
|
|
||||||
|
|
||||||
public SoundIOChannelLayout CurrentLayout
|
|
||||||
{
|
|
||||||
get { return new SoundIOChannelLayout((IntPtr)handle + current_layout_offset); }
|
|
||||||
}
|
|
||||||
|
|
||||||
static readonly int current_layout_offset = (int)Marshal.OffsetOf<SoundIoDevice>("current_layout");
|
|
||||||
|
|
||||||
public int FormatCount
|
|
||||||
{
|
|
||||||
get { return Marshal.ReadInt32(handle, format_count_offset); }
|
|
||||||
}
|
|
||||||
|
|
||||||
static readonly int format_count_offset = (int)Marshal.OffsetOf<SoundIoDevice>("format_count");
|
|
||||||
|
|
||||||
public IEnumerable<SoundIOFormat> 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<SoundIoDevice>("formats");
|
|
||||||
|
|
||||||
public string Id
|
|
||||||
{
|
|
||||||
get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, id_offset)); }
|
|
||||||
}
|
|
||||||
|
|
||||||
static readonly int id_offset = (int)Marshal.OffsetOf<SoundIoDevice>("id");
|
|
||||||
|
|
||||||
public bool IsRaw
|
|
||||||
{
|
|
||||||
get { return Marshal.ReadInt32(handle, is_raw_offset) != 0; }
|
|
||||||
}
|
|
||||||
|
|
||||||
static readonly int is_raw_offset = (int)Marshal.OffsetOf<SoundIoDevice>("is_raw");
|
|
||||||
|
|
||||||
public int LayoutCount
|
|
||||||
{
|
|
||||||
get { return Marshal.ReadInt32(handle, layout_count_offset); }
|
|
||||||
}
|
|
||||||
|
|
||||||
static readonly int layout_count_offset = (int)Marshal.OffsetOf<SoundIoDevice>("layout_count");
|
|
||||||
|
|
||||||
public IEnumerable<SoundIOChannelLayout> Layouts
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var ptr = Marshal.ReadIntPtr (handle, layouts_offset);
|
|
||||||
|
|
||||||
for (int i = 0; i < LayoutCount; i++)
|
|
||||||
{
|
|
||||||
yield return new SoundIOChannelLayout(ptr + i * Marshal.SizeOf<SoundIoChannelLayout>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static readonly int layouts_offset = (int)Marshal.OffsetOf<SoundIoDevice>("layouts");
|
|
||||||
|
|
||||||
public string Name
|
|
||||||
{
|
|
||||||
get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, name_offset)); }
|
|
||||||
}
|
|
||||||
|
|
||||||
static readonly int name_offset = (int)Marshal.OffsetOf<SoundIoDevice>("name");
|
|
||||||
|
|
||||||
public int ProbeError
|
|
||||||
{
|
|
||||||
get { return Marshal.ReadInt32(handle, probe_error_offset); }
|
|
||||||
}
|
|
||||||
|
|
||||||
static readonly int probe_error_offset = (int)Marshal.OffsetOf<SoundIoDevice>("probe_error");
|
|
||||||
|
|
||||||
public int ReferenceCount
|
|
||||||
{
|
|
||||||
get { return Marshal.ReadInt32(handle, ref_count_offset); }
|
|
||||||
}
|
|
||||||
|
|
||||||
static readonly int ref_count_offset = (int)Marshal.OffsetOf<SoundIoDevice>("ref_count");
|
|
||||||
|
|
||||||
public int SampleRateCount
|
|
||||||
{
|
|
||||||
get { return Marshal.ReadInt32(handle, sample_rate_count_offset); }
|
|
||||||
}
|
|
||||||
|
|
||||||
static readonly int sample_rate_count_offset = (int)Marshal.OffsetOf<SoundIoDevice>("sample_rate_count");
|
|
||||||
|
|
||||||
public IEnumerable<SoundIOSampleRateRange> 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<SoundIoDevice>("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<SoundIoDevice>("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<SoundIoDevice>("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<SoundIoDevice>("software_latency_max");
|
|
||||||
|
|
||||||
public SoundIO SoundIO
|
|
||||||
{
|
|
||||||
get { return new SoundIO(Marshal.ReadIntPtr(handle, soundio_offset)); }
|
|
||||||
}
|
|
||||||
|
|
||||||
static readonly int soundio_offset = (int)Marshal.OffsetOf<SoundIoDevice>("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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
namespace SoundIOSharp
|
|
||||||
{
|
|
||||||
public enum SoundIODeviceAim // soundio.h (228, 6)
|
|
||||||
{
|
|
||||||
Input,
|
|
||||||
Output
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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))) { }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,293 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace SoundIOSharp
|
|
||||||
{
|
|
||||||
public class SoundIOInStream : IDisposable
|
|
||||||
{
|
|
||||||
internal SoundIOInStream(Pointer<SoundIoInStream> handle)
|
|
||||||
{
|
|
||||||
this.handle = handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
Pointer<SoundIoInStream> 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<SoundIoInStream>("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<SoundIoInStream>("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<SoundIoInStream>("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<SoundIoChannelLayout>(), Marshal.SizeOf<SoundIoChannelLayout>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static readonly int layout_offset = (int)Marshal.OffsetOf<SoundIoInStream>("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<SoundIoInStream>("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<SoundIoInStream>("error_callback");
|
|
||||||
|
|
||||||
Action error_callback;
|
|
||||||
delegate void error_callback_delegate(IntPtr handle);
|
|
||||||
error_callback_delegate error_callback_native;
|
|
||||||
|
|
||||||
// read_callback
|
|
||||||
public Action<int,int> 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<SoundIoInStream>("read_callback");
|
|
||||||
|
|
||||||
Action<int, int> 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<SoundIoInStream>("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<IntPtr> allocated_hglobals = new List<IntPtr>();
|
|
||||||
|
|
||||||
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<SoundIoInStream>("name");
|
|
||||||
|
|
||||||
public bool NonTerminalHint
|
|
||||||
{
|
|
||||||
get { return Marshal.ReadInt32(handle, non_terminal_hint_offset) != 0; }
|
|
||||||
}
|
|
||||||
|
|
||||||
static readonly int non_terminal_hint_offset = (int)Marshal.OffsetOf<SoundIoInStream>("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<SoundIoInStream>("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<SoundIoInStream>("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<SoundIoInStream>("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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,331 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace SoundIOSharp
|
|
||||||
{
|
|
||||||
public class SoundIOOutStream : IDisposable
|
|
||||||
{
|
|
||||||
internal SoundIOOutStream (Pointer<SoundIoOutStream> handle)
|
|
||||||
{
|
|
||||||
this.handle = handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
Pointer<SoundIoOutStream> 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<SoundIoOutStream>("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<SoundIoOutStream>("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<SoundIoOutStream>("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<SoundIoChannelLayout>(), Marshal.SizeOf<SoundIoChannelLayout>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static readonly int layout_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("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<SoundIoOutStream>("software_latency");
|
|
||||||
|
|
||||||
public float Volume
|
|
||||||
{
|
|
||||||
get { return MarshalEx.ReadFloat(handle, volume_offset); }
|
|
||||||
set { MarshalEx.WriteFloat(handle, volume_offset, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
static readonly int volume_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("volume");
|
|
||||||
|
|
||||||
// error_callback
|
|
||||||
public Action ErrorCallback
|
|
||||||
{
|
|
||||||
get { return error_callback; }
|
|
||||||
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<SoundIoOutStream>("error_callback");
|
|
||||||
|
|
||||||
Action error_callback;
|
|
||||||
delegate void error_callback_delegate (IntPtr handle);
|
|
||||||
error_callback_delegate error_callback_native;
|
|
||||||
|
|
||||||
// write_callback
|
|
||||||
public Action<int, int> 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<SoundIoOutStream>("write_callback");
|
|
||||||
|
|
||||||
Action<int, int> 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<SoundIoOutStream>("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<IntPtr> allocated_hglobals = new List<IntPtr>();
|
|
||||||
|
|
||||||
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<SoundIoOutStream>("name");
|
|
||||||
|
|
||||||
public bool NonTerminalHint
|
|
||||||
{
|
|
||||||
get { return Marshal.ReadInt32(handle, non_terminal_hint_offset) != 0; }
|
|
||||||
}
|
|
||||||
|
|
||||||
static readonly int non_terminal_hint_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("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<SoundIoOutStream>("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<SoundIoOutStream>("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<SoundIoOutStream> ("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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<byte>")] public System.IntPtr @name;
|
|
||||||
public int @channel_count;
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)]
|
|
||||||
[CTypeDetails("ConstArrayOf<SoundIoChannelId>")] 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<byte>")] public System.IntPtr @ptr;
|
|
||||||
public int @step;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
struct SoundIo // soundio.h (328, 8)
|
|
||||||
{
|
|
||||||
[CTypeDetails("Pointer<void>")] public System.IntPtr @userdata;
|
|
||||||
[CTypeDetails("Pointer<void (SoundIo *)>")] public delegate0 @on_devices_change;
|
|
||||||
[CTypeDetails("Pointer<void (SoundIo *, int)>")] public delegate1 @on_backend_disconnect;
|
|
||||||
[CTypeDetails("Pointer<void (SoundIo *)>")] public Delegates.delegate0 @on_events_signal;
|
|
||||||
public SoundIoBackend @current_backend;
|
|
||||||
[CTypeDetails("Pointer<byte>")] public System.IntPtr @app_name;
|
|
||||||
[CTypeDetails("Pointer<void ()>")] public delegate2 @emit_rtprio_warning;
|
|
||||||
[CTypeDetails("Pointer<void (const char *)>")] public delegate3 @jack_info_callback;
|
|
||||||
[CTypeDetails("Pointer<void (const char *)>")] public Delegates.delegate3 @jack_error_callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
struct SoundIoDevice // soundio.h (387, 8)
|
|
||||||
{
|
|
||||||
[CTypeDetails("Pointer<SoundIo>")] public System.IntPtr @soundio;
|
|
||||||
[CTypeDetails("Pointer<byte>")] public System.IntPtr @id;
|
|
||||||
[CTypeDetails("Pointer<byte>")] public System.IntPtr @name;
|
|
||||||
public SoundIoDeviceAim @aim;
|
|
||||||
[CTypeDetails("Pointer<SoundIoChannelLayout>")] public System.IntPtr @layouts;
|
|
||||||
public int @layout_count;
|
|
||||||
public SoundIoChannelLayout @current_layout;
|
|
||||||
[CTypeDetails("Pointer<SoundIoFormat>")] public System.IntPtr @formats;
|
|
||||||
public int @format_count;
|
|
||||||
public SoundIoFormat @current_format;
|
|
||||||
[CTypeDetails("Pointer<SoundIoSampleRateRange>")] 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<SoundIoDevice>")] public System.IntPtr @device;
|
|
||||||
public SoundIoFormat @format;
|
|
||||||
public int @sample_rate;
|
|
||||||
public SoundIoChannelLayout @layout;
|
|
||||||
public double @software_latency;
|
|
||||||
public float @volume;
|
|
||||||
[CTypeDetails("Pointer<void>")] public System.IntPtr @userdata;
|
|
||||||
[CTypeDetails("Pointer<void (SoundIoOutStream *, int, int)>")] public delegate4 @write_callback;
|
|
||||||
[CTypeDetails("Pointer<void (SoundIoOutStream *)>")] public delegate5 @underflow_callback;
|
|
||||||
[CTypeDetails("Pointer<void (SoundIoOutStream *, int)>")] public delegate6 @error_callback;
|
|
||||||
[CTypeDetails("Pointer<byte>")] 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<SoundIoDevice>")] public System.IntPtr @device;
|
|
||||||
public SoundIoFormat @format;
|
|
||||||
public int @sample_rate;
|
|
||||||
public SoundIoChannelLayout @layout;
|
|
||||||
public double @software_latency;
|
|
||||||
[CTypeDetails("Pointer<void>")] public System.IntPtr @userdata;
|
|
||||||
[CTypeDetails("Pointer<void (SoundIoInStream *, int, int)>")] public delegate7 @read_callback;
|
|
||||||
[CTypeDetails("Pointer<void (SoundIoInStream *)>")] public delegate8 @overflow_callback;
|
|
||||||
[CTypeDetails("Pointer<void (SoundIoInStream *, int)>")] public delegate9 @error_callback;
|
|
||||||
[CTypeDetails("Pointer<byte>")] 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<SoundIo>")]System.IntPtr @soundio);
|
|
||||||
|
|
||||||
// function soundio_connect - soundio.h (705, 20)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern int soundio_connect([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
|
||||||
|
|
||||||
// function soundio_connect_backend - soundio.h (717, 20)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern int soundio_connect_backend([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio, SoundIoBackend @backend);
|
|
||||||
|
|
||||||
// function soundio_disconnect - soundio.h (718, 21)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern void soundio_disconnect([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
|
||||||
|
|
||||||
// function soundio_strerror - soundio.h (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<SoundIo>")]System.IntPtr @soundio);
|
|
||||||
|
|
||||||
// function soundio_get_backend - soundio.h (729, 36)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern SoundIoBackend soundio_get_backend([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio, int @index);
|
|
||||||
|
|
||||||
// function soundio_have_backend - soundio.h (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<SoundIo>")]System.IntPtr @soundio);
|
|
||||||
|
|
||||||
// function soundio_wait_events - soundio.h (760, 21)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern void soundio_wait_events([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
|
||||||
|
|
||||||
// function soundio_wakeup - soundio.h (763, 21)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern void soundio_wakeup([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
|
||||||
|
|
||||||
// function soundio_force_device_scan - soundio.h (780, 21)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern void soundio_force_device_scan([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
|
||||||
|
|
||||||
// function soundio_channel_layout_equal - soundio.h (787, 21)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern bool soundio_channel_layout_equal([CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @a, [CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @b);
|
|
||||||
|
|
||||||
// function soundio_get_channel_name - soundio.h (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<byte>")]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<SoundIoChannelLayout>")]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<SoundIoChannelLayout>")]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<SoundIoChannelLayout>")]System.IntPtr @preferred_layouts, int @preferred_layout_count, [CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @available_layouts, int @available_layout_count);
|
|
||||||
|
|
||||||
// function soundio_sort_channel_layouts - soundio.h (824, 21)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern void soundio_sort_channel_layouts([CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @layouts, int @layout_count);
|
|
||||||
|
|
||||||
// function soundio_get_bytes_per_sample - soundio.h (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<SoundIo>")]System.IntPtr @soundio);
|
|
||||||
|
|
||||||
// function soundio_output_device_count - soundio.h (864, 20)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern int soundio_output_device_count([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
|
||||||
|
|
||||||
// function soundio_get_input_device - soundio.h (870, 38)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern System.IntPtr soundio_get_input_device([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio, int @index);
|
|
||||||
|
|
||||||
// function soundio_get_output_device - soundio.h (875, 38)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern System.IntPtr soundio_get_output_device([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio, int @index);
|
|
||||||
|
|
||||||
// function soundio_default_input_device_index - soundio.h (880, 20)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern int soundio_default_input_device_index([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
|
||||||
|
|
||||||
// function soundio_default_output_device_index - soundio.h (885, 20)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern int soundio_default_output_device_index([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
|
||||||
|
|
||||||
// function soundio_device_ref - soundio.h (888, 21)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern void soundio_device_ref([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device);
|
|
||||||
|
|
||||||
// function soundio_device_unref - soundio.h (891, 21)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern void soundio_device_unref([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device);
|
|
||||||
|
|
||||||
// function soundio_device_equal - soundio.h (895, 21)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern bool soundio_device_equal([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @a, [CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @b);
|
|
||||||
|
|
||||||
// function soundio_device_sort_channel_layouts - soundio.h (900, 21)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern void soundio_device_sort_channel_layouts([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device);
|
|
||||||
|
|
||||||
// function soundio_device_supports_format - soundio.h (904, 21)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern bool soundio_device_supports_format([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device, SoundIoFormat @format);
|
|
||||||
|
|
||||||
// function soundio_device_supports_layout - soundio.h (909, 21)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern bool soundio_device_supports_layout([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device, [CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @layout);
|
|
||||||
|
|
||||||
// function soundio_device_supports_sample_rate - soundio.h (914, 21)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern bool soundio_device_supports_sample_rate([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device, int @sample_rate);
|
|
||||||
|
|
||||||
// function soundio_device_nearest_sample_rate - soundio.h (919, 20)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern int soundio_device_nearest_sample_rate([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device, int @sample_rate);
|
|
||||||
|
|
||||||
// function soundio_outstream_create - soundio.h (929, 41)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern System.IntPtr soundio_outstream_create([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device);
|
|
||||||
|
|
||||||
// function soundio_outstream_destroy - soundio.h (931, 21)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern void soundio_outstream_destroy([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream);
|
|
||||||
|
|
||||||
// function soundio_outstream_open - soundio.h (954, 20)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern int soundio_outstream_open([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream);
|
|
||||||
|
|
||||||
// function soundio_outstream_start - soundio.h (965, 20)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern int soundio_outstream_start([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream);
|
|
||||||
|
|
||||||
// function soundio_outstream_begin_write - soundio.h (997, 20)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern int soundio_outstream_begin_write([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream, [CTypeDetails("Pointer<System.IntPtr>")]System.IntPtr @areas, [CTypeDetails("Pointer<int>")]System.IntPtr @frame_count);
|
|
||||||
|
|
||||||
// function soundio_outstream_end_write - soundio.h (1009, 20)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern int soundio_outstream_end_write([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream);
|
|
||||||
|
|
||||||
// function soundio_outstream_clear_buffer - soundio.h (1024, 20)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern int soundio_outstream_clear_buffer([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream);
|
|
||||||
|
|
||||||
// function soundio_outstream_pause - soundio.h (1045, 20)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern int soundio_outstream_pause([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream, bool @pause);
|
|
||||||
|
|
||||||
// function soundio_outstream_get_latency - soundio.h (1058, 20)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern int soundio_outstream_get_latency([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream, [CTypeDetails("Pointer<double>")]System.IntPtr @out_latency);
|
|
||||||
|
|
||||||
// function soundio_outstream_set_volume - soundio.h (1061, 20)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern int soundio_outstream_set_volume([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream, double @volume);
|
|
||||||
|
|
||||||
// function soundio_instream_create - soundio.h (1071, 40)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern System.IntPtr soundio_instream_create([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device);
|
|
||||||
|
|
||||||
// function soundio_instream_destroy - soundio.h (1073, 21)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern void soundio_instream_destroy([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream);
|
|
||||||
|
|
||||||
// function soundio_instream_open - soundio.h (1093, 20)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern int soundio_instream_open([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream);
|
|
||||||
|
|
||||||
// function soundio_instream_start - soundio.h (1102, 20)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern int soundio_instream_start([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream);
|
|
||||||
|
|
||||||
// function soundio_instream_begin_read - soundio.h (1133, 20)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern int soundio_instream_begin_read([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream, [CTypeDetails("Pointer<System.IntPtr>")]System.IntPtr @areas, [CTypeDetails("Pointer<int>")]System.IntPtr @frame_count);
|
|
||||||
|
|
||||||
// function soundio_instream_end_read - soundio.h (1143, 20)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern int soundio_instream_end_read([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream);
|
|
||||||
|
|
||||||
// function soundio_instream_pause - soundio.h (1156, 20)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern int soundio_instream_pause([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream, bool @pause);
|
|
||||||
|
|
||||||
// function soundio_instream_get_latency - soundio.h (1166, 20)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern int soundio_instream_get_latency([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream, [CTypeDetails("Pointer<double>")]System.IntPtr @out_latency);
|
|
||||||
|
|
||||||
// function soundio_ring_buffer_create - soundio.h (1181, 42)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern System.IntPtr soundio_ring_buffer_create([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio, int @requested_capacity);
|
|
||||||
|
|
||||||
// function soundio_ring_buffer_destroy - soundio.h (1182, 21)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern void soundio_ring_buffer_destroy([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
|
|
||||||
|
|
||||||
// function soundio_ring_buffer_capacity - soundio.h (1186, 20)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern int soundio_ring_buffer_capacity([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
|
|
||||||
|
|
||||||
// function soundio_ring_buffer_write_ptr - soundio.h (1189, 22)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern System.IntPtr soundio_ring_buffer_write_ptr([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
|
|
||||||
|
|
||||||
// function soundio_ring_buffer_advance_write_ptr - soundio.h (1191, 21)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern void soundio_ring_buffer_advance_write_ptr([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer, int @count);
|
|
||||||
|
|
||||||
// function soundio_ring_buffer_read_ptr - soundio.h (1194, 22)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern System.IntPtr soundio_ring_buffer_read_ptr([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
|
|
||||||
|
|
||||||
// function soundio_ring_buffer_advance_read_ptr - soundio.h (1196, 21)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern void soundio_ring_buffer_advance_read_ptr([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer, int @count);
|
|
||||||
|
|
||||||
// function soundio_ring_buffer_fill_count - soundio.h (1199, 20)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern int soundio_ring_buffer_fill_count([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
|
|
||||||
|
|
||||||
// function soundio_ring_buffer_free_count - soundio.h (1202, 20)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern int soundio_ring_buffer_free_count([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
|
|
||||||
|
|
||||||
// function soundio_ring_buffer_clear - soundio.h (1205, 21)
|
|
||||||
[DllImport(LibraryName)]
|
|
||||||
internal static extern void soundio_ring_buffer_clear([CTypeDetails("Pointer<SoundIoRingBuffer>")]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<T>
|
|
||||||
{
|
|
||||||
public IntPtr Handle;
|
|
||||||
public static implicit operator IntPtr(Pointer<T> value) { return value.Handle; }
|
|
||||||
public static implicit operator Pointer<T>(IntPtr value) { return new Pointer<T>(value); }
|
|
||||||
|
|
||||||
public Pointer(IntPtr handle)
|
|
||||||
{
|
|
||||||
Handle = handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
return obj is Pointer<T> && this == (Pointer<T>)obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
return (int)Handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator ==(Pointer<T> p1, Pointer<T> p2)
|
|
||||||
{
|
|
||||||
return p1.Handle == p2.Handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator !=(Pointer<T> p1, Pointer<T> p2)
|
|
||||||
{
|
|
||||||
return p1.Handle != p2.Handle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public struct ArrayOf<T> { }
|
|
||||||
public struct ConstArrayOf<T> { }
|
|
||||||
public class CTypeDetailsAttribute : Attribute
|
|
||||||
{
|
|
||||||
public CTypeDetailsAttribute(string value)
|
|
||||||
{
|
|
||||||
Value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Value { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,19 +1,20 @@
|
||||||
using Ryujinx.Audio.Common;
|
using Ryujinx.Audio.Backends.SoundIo.Native;
|
||||||
|
using Ryujinx.Audio.Common;
|
||||||
using Ryujinx.Audio.Integration;
|
using Ryujinx.Audio.Integration;
|
||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using SoundIOSharp;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
using static Ryujinx.Audio.Integration.IHardwareDeviceDriver;
|
using static Ryujinx.Audio.Integration.IHardwareDeviceDriver;
|
||||||
|
using static Ryujinx.Audio.Backends.SoundIo.Native.SoundIo;
|
||||||
|
|
||||||
namespace Ryujinx.Audio.Backends.SoundIo
|
namespace Ryujinx.Audio.Backends.SoundIo
|
||||||
{
|
{
|
||||||
public class SoundIoHardwareDeviceDriver : IHardwareDeviceDriver
|
public class SoundIoHardwareDeviceDriver : IHardwareDeviceDriver
|
||||||
{
|
{
|
||||||
private readonly SoundIO _audioContext;
|
private readonly SoundIoContext _audioContext;
|
||||||
private readonly SoundIODevice _audioDevice;
|
private readonly SoundIoDeviceContext _audioDevice;
|
||||||
private readonly ManualResetEvent _updateRequiredEvent;
|
private readonly ManualResetEvent _updateRequiredEvent;
|
||||||
private readonly ManualResetEvent _pauseEvent;
|
private readonly ManualResetEvent _pauseEvent;
|
||||||
private readonly ConcurrentDictionary<SoundIoHardwareDeviceSession, byte> _sessions;
|
private readonly ConcurrentDictionary<SoundIoHardwareDeviceSession, byte> _sessions;
|
||||||
|
@ -21,7 +22,7 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
||||||
|
|
||||||
public SoundIoHardwareDeviceDriver()
|
public SoundIoHardwareDeviceDriver()
|
||||||
{
|
{
|
||||||
_audioContext = new SoundIO();
|
_audioContext = SoundIoContext.Create();
|
||||||
_updateRequiredEvent = new ManualResetEvent(false);
|
_updateRequiredEvent = new ManualResetEvent(false);
|
||||||
_pauseEvent = new ManualResetEvent(true);
|
_pauseEvent = new ManualResetEvent(true);
|
||||||
_sessions = new ConcurrentDictionary<SoundIoHardwareDeviceSession, byte>();
|
_sessions = new ConcurrentDictionary<SoundIoHardwareDeviceSession, byte>();
|
||||||
|
@ -29,24 +30,23 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
||||||
_audioContext.Connect();
|
_audioContext.Connect();
|
||||||
_audioContext.FlushEvents();
|
_audioContext.FlushEvents();
|
||||||
|
|
||||||
_audioDevice = FindNonRawDefaultAudioDevice(_audioContext, true);
|
_audioDevice = FindValidAudioDevice(_audioContext, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsSupported => IsSupportedInternal();
|
public static bool IsSupported => IsSupportedInternal();
|
||||||
|
|
||||||
private static bool IsSupportedInternal()
|
private static bool IsSupportedInternal()
|
||||||
{
|
{
|
||||||
SoundIO context = null;
|
SoundIoContext context = null;
|
||||||
SoundIODevice device = null;
|
SoundIoDeviceContext device = null;
|
||||||
SoundIOOutStream stream = null;
|
SoundIoOutStreamContext stream = null;
|
||||||
|
|
||||||
bool backendDisconnected = false;
|
bool backendDisconnected = false;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
context = new SoundIO();
|
context = SoundIoContext.Create();
|
||||||
|
context.OnBackendDisconnect = err =>
|
||||||
context.OnBackendDisconnect = (i) =>
|
|
||||||
{
|
{
|
||||||
backendDisconnected = true;
|
backendDisconnected = true;
|
||||||
};
|
};
|
||||||
|
@ -64,7 +64,7 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
device = FindNonRawDefaultAudioDevice(context);
|
device = FindValidAudioDevice(context);
|
||||||
|
|
||||||
if (device == null || backendDisconnected)
|
if (device == null || backendDisconnected)
|
||||||
{
|
{
|
||||||
|
@ -86,30 +86,23 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (stream != null)
|
stream?.Dispose();
|
||||||
{
|
context?.Dispose();
|
||||||
stream.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context != null)
|
|
||||||
{
|
|
||||||
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)
|
if (!defaultAudioDevice.IsRaw)
|
||||||
{
|
{
|
||||||
return defaultAudioDevice;
|
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)
|
if (audioDevice.Id == defaultAudioDevice.Id && !audioDevice.IsRaw)
|
||||||
{
|
{
|
||||||
|
@ -161,22 +154,22 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
||||||
return _sessions.TryRemove(session, out _);
|
return _sessions.TryRemove(session, out _);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SoundIOFormat GetSoundIoFormat(SampleFormat format)
|
public static SoundIoFormat GetSoundIoFormat(SampleFormat format)
|
||||||
{
|
{
|
||||||
return format switch
|
return format switch
|
||||||
{
|
{
|
||||||
SampleFormat.PcmInt8 => SoundIOFormat.S8,
|
SampleFormat.PcmInt8 => SoundIoFormat.S8,
|
||||||
SampleFormat.PcmInt16 => SoundIOFormat.S16LE,
|
SampleFormat.PcmInt16 => SoundIoFormat.S16LE,
|
||||||
SampleFormat.PcmInt24 => SoundIOFormat.S24LE,
|
SampleFormat.PcmInt24 => SoundIoFormat.S24LE,
|
||||||
SampleFormat.PcmInt32 => SoundIOFormat.S32LE,
|
SampleFormat.PcmInt32 => SoundIoFormat.S32LE,
|
||||||
SampleFormat.PcmFloat => SoundIOFormat.Float32LE,
|
SampleFormat.PcmFloat => SoundIoFormat.Float32LE,
|
||||||
_ => throw new ArgumentException ($"Unsupported sample format {format}"),
|
_ => 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))
|
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}");
|
throw new ArgumentException($"This sound device does not support channel count {requestedChannelCount}");
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundIOOutStream result = _audioDevice.CreateOutStream();
|
SoundIoOutStreamContext result = _audioDevice.CreateOutStream();
|
||||||
|
|
||||||
result.Name = "Ryujinx";
|
result.Name = "Ryujinx";
|
||||||
result.Layout = SoundIOChannelLayout.GetDefault((int)requestedChannelCount);
|
result.Layout = SoundIoChannelLayout.GetDefaultValue((int)requestedChannelCount);
|
||||||
result.Format = driverSampleFormat;
|
result.Format = driverSampleFormat;
|
||||||
result.SampleRate = (int)requestedSampleRate;
|
result.SampleRate = (int)requestedSampleRate;
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
using Ryujinx.Audio.Backends.Common;
|
using Ryujinx.Audio.Backends.Common;
|
||||||
|
using Ryujinx.Audio.Backends.SoundIo.Native;
|
||||||
using Ryujinx.Audio.Common;
|
using Ryujinx.Audio.Common;
|
||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using SoundIOSharp;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using static Ryujinx.Audio.Backends.SoundIo.Native.SoundIo;
|
||||||
|
|
||||||
namespace Ryujinx.Audio.Backends.SoundIo
|
namespace Ryujinx.Audio.Backends.SoundIo
|
||||||
{
|
{
|
||||||
|
@ -13,7 +14,7 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
||||||
{
|
{
|
||||||
private SoundIoHardwareDeviceDriver _driver;
|
private SoundIoHardwareDeviceDriver _driver;
|
||||||
private ConcurrentQueue<SoundIoAudioBuffer> _queuedBuffers;
|
private ConcurrentQueue<SoundIoAudioBuffer> _queuedBuffers;
|
||||||
private SoundIOOutStream _outputStream;
|
private SoundIoOutStreamContext _outputStream;
|
||||||
private DynamicRingBuffer _ringBuffer;
|
private DynamicRingBuffer _ringBuffer;
|
||||||
private ulong _playedSampleCount;
|
private ulong _playedSampleCount;
|
||||||
private ManualResetEvent _updateRequiredEvent;
|
private ManualResetEvent _updateRequiredEvent;
|
||||||
|
@ -106,9 +107,9 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundIOChannelAreas areas = _outputStream.BeginWrite(ref frameCount);
|
Span<SoundIoChannelArea> areas = _outputStream.BeginWrite(ref frameCount);
|
||||||
|
|
||||||
int channelCount = areas.ChannelCount;
|
int channelCount = areas.Length;
|
||||||
|
|
||||||
byte[] samples = new byte[frameCount * bytesPerFrame];
|
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
|
// This is a huge ugly block of code, but we save
|
||||||
// a significant amount of time over the generic
|
// a significant amount of time over the generic
|
||||||
// loop that handles other channel counts.
|
// loop that handles other channel counts.
|
||||||
// TODO: Is this still right in 2021?
|
// TODO: Is this still right in 2022?
|
||||||
|
|
||||||
// Mono
|
// Mono
|
||||||
if (channelCount == 1)
|
if (channelCount == 1)
|
||||||
{
|
{
|
||||||
SoundIOChannelArea area = areas.GetArea(0);
|
ref SoundIoChannelArea area = ref areas[0];
|
||||||
|
|
||||||
fixed (byte* srcptr = samples)
|
fixed (byte* srcptr = samples)
|
||||||
{
|
{
|
||||||
|
@ -167,8 +168,8 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
||||||
// Stereo
|
// Stereo
|
||||||
else if (channelCount == 2)
|
else if (channelCount == 2)
|
||||||
{
|
{
|
||||||
SoundIOChannelArea area1 = areas.GetArea(0);
|
ref SoundIoChannelArea area1 = ref areas[0];
|
||||||
SoundIOChannelArea area2 = areas.GetArea(1);
|
ref SoundIoChannelArea area2 = ref areas[1];
|
||||||
|
|
||||||
fixed (byte* srcptr = samples)
|
fixed (byte* srcptr = samples)
|
||||||
{
|
{
|
||||||
|
@ -233,12 +234,12 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
||||||
// Surround
|
// Surround
|
||||||
else if (channelCount == 6)
|
else if (channelCount == 6)
|
||||||
{
|
{
|
||||||
SoundIOChannelArea area1 = areas.GetArea(0);
|
ref SoundIoChannelArea area1 = ref areas[0];
|
||||||
SoundIOChannelArea area2 = areas.GetArea(1);
|
ref SoundIoChannelArea area2 = ref areas[1];
|
||||||
SoundIOChannelArea area3 = areas.GetArea(2);
|
ref SoundIoChannelArea area3 = ref areas[2];
|
||||||
SoundIOChannelArea area4 = areas.GetArea(3);
|
ref SoundIoChannelArea area4 = ref areas[3];
|
||||||
SoundIOChannelArea area5 = areas.GetArea(4);
|
ref SoundIoChannelArea area5 = ref areas[4];
|
||||||
SoundIOChannelArea area6 = areas.GetArea(5);
|
ref SoundIoChannelArea area6 = ref areas[5];
|
||||||
|
|
||||||
fixed (byte* srcptr = samples)
|
fixed (byte* srcptr = samples)
|
||||||
{
|
{
|
||||||
|
@ -367,23 +368,17 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
||||||
// Every other channel count
|
// Every other channel count
|
||||||
else
|
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)
|
fixed (byte* srcptr = samples)
|
||||||
{
|
{
|
||||||
for (int frame = 0; frame < frameCount; frame++)
|
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!
|
// 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,7 +125,7 @@ namespace Ryujinx.Ava
|
||||||
_inputManager = inputManager;
|
_inputManager = inputManager;
|
||||||
_accountManager = accountManager;
|
_accountManager = accountManager;
|
||||||
_userChannelPersistence = userChannelPersistence;
|
_userChannelPersistence = userChannelPersistence;
|
||||||
_renderingThread = new Thread(RenderLoop) { Name = "GUI.RenderThread" };
|
_renderingThread = new Thread(RenderLoop, 1 * 1024 * 1024) { Name = "GUI.RenderThread" };
|
||||||
_hideCursorOnIdle = ConfigurationState.Instance.HideCursorOnIdle;
|
_hideCursorOnIdle = ConfigurationState.Instance.HideCursorOnIdle;
|
||||||
_lastCursorMoveTime = Stopwatch.GetTimestamp();
|
_lastCursorMoveTime = Stopwatch.GetTimestamp();
|
||||||
_glLogLevel = ConfigurationState.Instance.Logger.GraphicsDebugLevel;
|
_glLogLevel = ConfigurationState.Instance.Logger.GraphicsDebugLevel;
|
||||||
|
|
|
@ -280,7 +280,7 @@
|
||||||
"ControllerSettingsRemoveProfileToolTip": "Remove Profile",
|
"ControllerSettingsRemoveProfileToolTip": "Remove Profile",
|
||||||
"ControllerSettingsSaveProfileToolTip": "Save Profile",
|
"ControllerSettingsSaveProfileToolTip": "Save Profile",
|
||||||
"MenuBarFileToolsTakeScreenshot": "Take Screenshot",
|
"MenuBarFileToolsTakeScreenshot": "Take Screenshot",
|
||||||
"MenuBarFileToolsHideUi": "Hide Ui",
|
"MenuBarFileToolsHideUi": "Hide UI",
|
||||||
"GameListContextMenuToggleFavorite": "Toggle Favorite",
|
"GameListContextMenuToggleFavorite": "Toggle Favorite",
|
||||||
"GameListContextMenuToggleFavoriteToolTip": "Toggle Favorite status of Game",
|
"GameListContextMenuToggleFavoriteToolTip": "Toggle Favorite status of Game",
|
||||||
"SettingsTabGeneralTheme": "Theme",
|
"SettingsTabGeneralTheme": "Theme",
|
||||||
|
@ -315,7 +315,7 @@
|
||||||
"DialogUpdaterConvertFailedMessage": "Failed to convert the current Ryujinx version.",
|
"DialogUpdaterConvertFailedMessage": "Failed to convert the current Ryujinx version.",
|
||||||
"DialogUpdaterCancelUpdateMessage": "Cancelling Update!",
|
"DialogUpdaterCancelUpdateMessage": "Cancelling Update!",
|
||||||
"DialogUpdaterAlreadyOnLatestVersionMessage": "You are already using the most updated version of Ryujinx!",
|
"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.",
|
"DialogUpdaterConvertFailedGithubMessage": "Failed to convert the received Ryujinx version from Github Release.",
|
||||||
"DialogUpdaterDownloadingMessage": "Downloading Update...",
|
"DialogUpdaterDownloadingMessage": "Downloading Update...",
|
||||||
"DialogUpdaterExtractionMessage": "Extracting Update...",
|
"DialogUpdaterExtractionMessage": "Extracting Update...",
|
||||||
|
|
|
@ -161,6 +161,7 @@
|
||||||
<Style Selector="MenuItem">
|
<Style Selector="MenuItem">
|
||||||
<Setter Property="Height" Value="{DynamicResource MenuItemHeight}" />
|
<Setter Property="Height" Value="{DynamicResource MenuItemHeight}" />
|
||||||
<Setter Property="Padding" Value="{DynamicResource MenuItemPadding}" />
|
<Setter Property="Padding" Value="{DynamicResource MenuItemPadding}" />
|
||||||
|
<Setter Property="FontSize" Value="12" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="MenuItem:selected /template/ Border#root">
|
<Style Selector="MenuItem:selected /template/ Border#root">
|
||||||
<Setter Property="Background" Value="{DynamicResource ThemeControlBorderColor}" />
|
<Setter Property="Background" Value="{DynamicResource ThemeControlBorderColor}" />
|
||||||
|
|
127
Ryujinx.Ava/Helper/MetalHelper.cs
Normal file
127
Ryujinx.Ava/Helper/MetalHelper.cs
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
using System;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Avalonia;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.Ui.Helper
|
||||||
|
{
|
||||||
|
public delegate void UpdateBoundsCallbackDelegate(Rect rect);
|
||||||
|
|
||||||
|
[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(out IntPtr nsView, out UpdateBoundsCallbackDelegate updateBounds)
|
||||||
|
{
|
||||||
|
// 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(0, 0, 0, 0));
|
||||||
|
|
||||||
|
// Make its renderer our metal layer.
|
||||||
|
objc_msgSend(child, "setWantsLayer:", (byte)1);
|
||||||
|
objc_msgSend(child, "setLayer:", metalLayer);
|
||||||
|
objc_msgSend(metalLayer, "setContentsScale:", Program.DesktopScaleFactor);
|
||||||
|
|
||||||
|
// Ensure the scale factor is up to date.
|
||||||
|
updateBounds = (Rect rect) => {
|
||||||
|
objc_msgSend(metalLayer, "setContentsScale:", Program.DesktopScaleFactor);
|
||||||
|
};
|
||||||
|
|
||||||
|
nsView = child;
|
||||||
|
return metalLayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DestroyMetalLayer(IntPtr nsView, IntPtr metalLayer)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,8 +7,7 @@ namespace Ryujinx.Ava.Input
|
||||||
{
|
{
|
||||||
internal static class AvaloniaKeyboardMappingHelper
|
internal static class AvaloniaKeyboardMappingHelper
|
||||||
{
|
{
|
||||||
private static readonly AvaKey[] _keyMapping = new AvaKey[(int)Key.Count]
|
private static readonly AvaKey[] _keyMapping = {
|
||||||
{
|
|
||||||
// NOTE: Invalid
|
// NOTE: Invalid
|
||||||
AvaKey.None,
|
AvaKey.None,
|
||||||
|
|
||||||
|
@ -151,16 +150,16 @@ namespace Ryujinx.Ava.Input
|
||||||
|
|
||||||
static AvaloniaKeyboardMappingHelper()
|
static AvaloniaKeyboardMappingHelper()
|
||||||
{
|
{
|
||||||
var inputKeys = Enum.GetValues(typeof(Key));
|
var inputKeys = Enum.GetValues<Key>();
|
||||||
|
|
||||||
// NOTE: Avalonia.Input.Key is not contiguous and quite large, so use a dictionary instead of an array.
|
// NOTE: Avalonia.Input.Key is not contiguous and quite large, so use a dictionary instead of an array.
|
||||||
_avaKeyMapping = new Dictionary<AvaKey, Key>();
|
_avaKeyMapping = new Dictionary<AvaKey, Key>();
|
||||||
|
|
||||||
foreach (var key in inputKeys)
|
foreach (var key in inputKeys)
|
||||||
{
|
{
|
||||||
if (TryGetAvaKey((Key)key, out var index))
|
if (TryGetAvaKey(key, out var index))
|
||||||
{
|
{
|
||||||
_avaKeyMapping[index] = (Key)key;
|
_avaKeyMapping[index] = key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ using Ryujinx.Ava.Ui.Controls;
|
||||||
using Ryujinx.Ava.Ui.Windows;
|
using Ryujinx.Ava.Ui.Windows;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.Ui.Common.Helper;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
@ -278,14 +279,15 @@ namespace Ryujinx.Modules
|
||||||
{
|
{
|
||||||
string ryuName = Path.GetFileName(Environment.ProcessPath);
|
string ryuName = Path.GetFileName(Environment.ProcessPath);
|
||||||
string ryuExe = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ryuName);
|
string ryuExe = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ryuName);
|
||||||
var ryuArg = Environment.GetCommandLineArgs().Skip(1);
|
|
||||||
|
|
||||||
if (!OperatingSystem.IsWindows())
|
if (!Path.Exists(ryuExe))
|
||||||
{
|
{
|
||||||
chmod(ryuExe, Convert.ToUInt32("0777", 8));
|
ryuExe = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, OperatingSystem.IsWindows() ? "Ryujinx.exe" : "Ryujinx");
|
||||||
}
|
}
|
||||||
|
|
||||||
Process.Start(ryuExe, ryuArg);
|
SetFileExecutable(ryuExe);
|
||||||
|
|
||||||
|
Process.Start(ryuExe, CommandLineState.Arguments);
|
||||||
|
|
||||||
Environment.Exit(0);
|
Environment.Exit(0);
|
||||||
}
|
}
|
||||||
|
@ -355,7 +357,7 @@ namespace Ryujinx.Modules
|
||||||
list[index] = args.Result;
|
list[index] = args.Result;
|
||||||
Interlocked.Increment(ref completedRequests);
|
Interlocked.Increment(ref completedRequests);
|
||||||
|
|
||||||
if (Interlocked.Equals(completedRequests, ConnectionCount))
|
if (Equals(completedRequests, ConnectionCount))
|
||||||
{
|
{
|
||||||
byte[] mergedFileBytes = new byte[_buildSize];
|
byte[] mergedFileBytes = new byte[_buildSize];
|
||||||
for (int connectionIndex = 0, destinationOffset = 0; connectionIndex < ConnectionCount; connectionIndex++)
|
for (int connectionIndex = 0, destinationOffset = 0; connectionIndex < ConnectionCount; connectionIndex++)
|
||||||
|
@ -456,16 +458,19 @@ namespace Ryujinx.Modules
|
||||||
worker.Start();
|
worker.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
[DllImport("libc", SetLastError = true)]
|
private static void SetFileExecutable(string path)
|
||||||
private static extern int chmod(string path, uint mode);
|
|
||||||
|
|
||||||
private static void SetUnixPermissions()
|
|
||||||
{
|
{
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -586,7 +591,7 @@ namespace Ryujinx.Modules
|
||||||
|
|
||||||
Directory.Delete(UpdateDir, true);
|
Directory.Delete(UpdateDir, true);
|
||||||
|
|
||||||
SetUnixPermissions();
|
SetFileExecutable(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx"));
|
||||||
|
|
||||||
UpdateSuccessful = true;
|
UpdateSuccessful = true;
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ namespace Ryujinx.Ava
|
||||||
internal class Program
|
internal class Program
|
||||||
{
|
{
|
||||||
public static double WindowScaleFactor { get; set; }
|
public static double WindowScaleFactor { get; set; }
|
||||||
|
public static double DesktopScaleFactor { get; set; } = 1.0;
|
||||||
public static string Version { get; private set; }
|
public static string Version { get; private set; }
|
||||||
public static string ConfigurationPath { get; private set; }
|
public static string ConfigurationPath { get; private set; }
|
||||||
public static bool PreviewerDetached { get; private set; }
|
public static bool PreviewerDetached { get; private set; }
|
||||||
|
@ -81,8 +82,8 @@ namespace Ryujinx.Ava
|
||||||
Console.Title = $"Ryujinx Console {Version}";
|
Console.Title = $"Ryujinx Console {Version}";
|
||||||
|
|
||||||
// Hook unhandled exception and process exit events.
|
// Hook unhandled exception and process exit events.
|
||||||
AppDomain.CurrentDomain.UnhandledException += (object sender, UnhandledExceptionEventArgs e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating);
|
AppDomain.CurrentDomain.UnhandledException += (sender, e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating);
|
||||||
AppDomain.CurrentDomain.ProcessExit += (object sender, EventArgs e) => Exit();
|
AppDomain.CurrentDomain.ProcessExit += (sender, e) => Exit();
|
||||||
|
|
||||||
// Setup base data directory.
|
// Setup base data directory.
|
||||||
AppDataManager.Initialize(CommandLineState.BaseDirPathArg);
|
AppDataManager.Initialize(CommandLineState.BaseDirPathArg);
|
||||||
|
|
|
@ -26,19 +26,23 @@
|
||||||
<PackageReference Include="Avalonia.Svg" Version="0.10.18" />
|
<PackageReference Include="Avalonia.Svg" Version="0.10.18" />
|
||||||
<PackageReference Include="Avalonia.Svg.Skia" Version="0.10.18" />
|
<PackageReference Include="Avalonia.Svg.Skia" Version="0.10.18" />
|
||||||
<PackageReference Include="jp2masa.Avalonia.Flexbox" Version="0.2.0" />
|
<PackageReference Include="jp2masa.Avalonia.Flexbox" Version="0.2.0" />
|
||||||
<PackageReference Include="DynamicData" Version="7.12.8" />
|
<PackageReference Include="DynamicData" Version="7.12.11" />
|
||||||
<PackageReference Include="FluentAvaloniaUI" Version="1.4.5" />
|
<PackageReference Include="FluentAvaloniaUI" Version="1.4.5" />
|
||||||
<PackageReference Include="XamlNameReferenceGenerator" Version="1.5.1" />
|
<PackageReference Include="XamlNameReferenceGenerator" Version="1.5.1" />
|
||||||
|
|
||||||
<PackageReference Include="OpenTK.Core" Version="4.7.5" />
|
<PackageReference Include="OpenTK.Core" Version="4.7.5" />
|
||||||
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
|
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64' AND '$(RuntimeIdentifier)' != 'osx-arm64'" />
|
||||||
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build10" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
|
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build12" />
|
||||||
|
<PackageReference Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'win10-x64'" />
|
||||||
<PackageReference Include="Silk.NET.Vulkan" Version="2.16.0" />
|
<PackageReference Include="Silk.NET.Vulkan" Version="2.16.0" />
|
||||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.16.0" />
|
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.16.0" />
|
||||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.16.0" />
|
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.16.0" />
|
||||||
<PackageReference Include="SPB" Version="0.0.4-build28" />
|
<PackageReference Include="SPB" Version="0.0.4-build28" />
|
||||||
<PackageReference Include="SharpZipLib" Version="1.4.1" />
|
<PackageReference Include="SharpZipLib" Version="1.4.1" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
|
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
|
||||||
|
|
||||||
|
<!--NOTE: DO NOT REMOVE, THIS IS REQUIRED AS A RESULT OF A TRIMMING ISSUE IN AVALONIA -->
|
||||||
|
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -57,14 +61,18 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ContentWithTargetPath Include="..\distribution\windows\alsoft.ini" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'">
|
<Content Include="..\distribution\windows\alsoft.ini" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
<TargetPath>alsoft.ini</TargetPath>
|
<TargetPath>alsoft.ini</TargetPath>
|
||||||
</ContentWithTargetPath>
|
</Content>
|
||||||
<ContentWithTargetPath Include="..\distribution\legal\THIRDPARTY.md">
|
<Content Include="..\distribution\legal\THIRDPARTY.md">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
<TargetPath>THIRDPARTY.md</TargetPath>
|
<TargetPath>THIRDPARTY.md</TargetPath>
|
||||||
</ContentWithTargetPath>
|
</Content>
|
||||||
|
<Content Include="..\LICENSE.txt">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
<TargetPath>LICENSE.txt</TargetPath>
|
||||||
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -66,7 +66,7 @@ namespace Ryujinx.Ava.Ui.Applet
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AvaloniaDynamicTextInputHandler_KeyRelease(object sender, Avalonia.Input.KeyEventArgs e)
|
private void AvaloniaDynamicTextInputHandler_KeyRelease(object sender, KeyEventArgs e)
|
||||||
{
|
{
|
||||||
var key = (HidKey)AvaloniaKeyboardMappingHelper.ToInputKey(e.Key);
|
var key = (HidKey)AvaloniaKeyboardMappingHelper.ToInputKey(e.Key);
|
||||||
|
|
||||||
|
|
|
@ -222,7 +222,7 @@ namespace Ryujinx.Ava.Ui.Controls
|
||||||
|
|
||||||
content.MinHeight = 80;
|
content.MinHeight = 80;
|
||||||
|
|
||||||
SymbolIcon icon = new SymbolIcon { Symbol = (Symbol)symbol, Margin = new Avalonia.Thickness(10) };
|
SymbolIcon icon = new SymbolIcon { Symbol = (Symbol)symbol, Margin = new Thickness(10) };
|
||||||
icon.FontSize = 40;
|
icon.FontSize = 40;
|
||||||
icon.VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center;
|
icon.VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center;
|
||||||
Grid.SetColumn(icon, 0);
|
Grid.SetColumn(icon, 0);
|
||||||
|
@ -232,15 +232,15 @@ namespace Ryujinx.Ava.Ui.Controls
|
||||||
TextBlock primaryLabel = new TextBlock()
|
TextBlock primaryLabel = new TextBlock()
|
||||||
{
|
{
|
||||||
Text = primaryText,
|
Text = primaryText,
|
||||||
Margin = new Avalonia.Thickness(5),
|
Margin = new Thickness(5),
|
||||||
TextWrapping = Avalonia.Media.TextWrapping.Wrap,
|
TextWrapping = TextWrapping.Wrap,
|
||||||
MaxWidth = 450
|
MaxWidth = 450
|
||||||
};
|
};
|
||||||
TextBlock secondaryLabel = new TextBlock()
|
TextBlock secondaryLabel = new TextBlock()
|
||||||
{
|
{
|
||||||
Text = secondaryText,
|
Text = secondaryText,
|
||||||
Margin = new Avalonia.Thickness(5),
|
Margin = new Thickness(5),
|
||||||
TextWrapping = Avalonia.Media.TextWrapping.Wrap,
|
TextWrapping = TextWrapping.Wrap,
|
||||||
MaxWidth = 450
|
MaxWidth = 450
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,10 @@ using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Platform;
|
using Avalonia.Platform;
|
||||||
|
using Ryujinx.Ava.Ui.Helper;
|
||||||
using SPB.Graphics;
|
using SPB.Graphics;
|
||||||
using SPB.Platform;
|
using SPB.Platform;
|
||||||
using SPB.Platform.GLX;
|
using SPB.Platform.GLX;
|
||||||
using SPB.Platform.X11;
|
|
||||||
using SPB.Windowing;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
|
@ -23,6 +22,10 @@ namespace Ryujinx.Ava.Ui.Controls
|
||||||
protected GLXWindow X11Window { get; set; }
|
protected GLXWindow X11Window { get; set; }
|
||||||
protected IntPtr WindowHandle { get; set; }
|
protected IntPtr WindowHandle { get; set; }
|
||||||
protected IntPtr X11Display { get; set; }
|
protected IntPtr X11Display { get; set; }
|
||||||
|
protected IntPtr NsView { get; set; }
|
||||||
|
protected IntPtr MetalLayer { get; set; }
|
||||||
|
|
||||||
|
private UpdateBoundsCallbackDelegate _updateBoundsCallback;
|
||||||
|
|
||||||
public event EventHandler<IntPtr> WindowCreated;
|
public event EventHandler<IntPtr> WindowCreated;
|
||||||
public event EventHandler<Size> SizeChanged;
|
public event EventHandler<Size> SizeChanged;
|
||||||
|
@ -36,7 +39,7 @@ namespace Ryujinx.Ava.Ui.Controls
|
||||||
|
|
||||||
public EmbeddedWindow()
|
public EmbeddedWindow()
|
||||||
{
|
{
|
||||||
var stateObserverable = this.GetObservable(Control.BoundsProperty);
|
var stateObserverable = this.GetObservable(BoundsProperty);
|
||||||
|
|
||||||
stateObserverable.Subscribe(StateChanged);
|
stateObserverable.Subscribe(StateChanged);
|
||||||
|
|
||||||
|
@ -58,6 +61,7 @@ namespace Ryujinx.Ava.Ui.Controls
|
||||||
private void StateChanged(Rect rect)
|
private void StateChanged(Rect rect)
|
||||||
{
|
{
|
||||||
SizeChanged?.Invoke(this, rect.Size);
|
SizeChanged?.Invoke(this, rect.Size);
|
||||||
|
_updateBoundsCallback?.Invoke(rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IPlatformHandle CreateNativeControlCore(IPlatformHandle parent)
|
protected override IPlatformHandle CreateNativeControlCore(IPlatformHandle parent)
|
||||||
|
@ -70,6 +74,11 @@ namespace Ryujinx.Ava.Ui.Controls
|
||||||
{
|
{
|
||||||
return CreateWin32(parent);
|
return CreateWin32(parent);
|
||||||
}
|
}
|
||||||
|
else if (OperatingSystem.IsMacOS())
|
||||||
|
{
|
||||||
|
return CreateMacOs(parent);
|
||||||
|
}
|
||||||
|
|
||||||
return base.CreateNativeControlCore(parent);
|
return base.CreateNativeControlCore(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,6 +94,10 @@ namespace Ryujinx.Ava.Ui.Controls
|
||||||
{
|
{
|
||||||
DestroyWin32(control);
|
DestroyWin32(control);
|
||||||
}
|
}
|
||||||
|
else if (OperatingSystem.IsMacOS())
|
||||||
|
{
|
||||||
|
DestroyMacOS();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
base.DestroyNativeControlCore(control);
|
base.DestroyNativeControlCore(control);
|
||||||
|
@ -152,7 +165,7 @@ namespace Ryujinx.Ava.Ui.Controls
|
||||||
isLeft = msg == WindowsMessages.LBUTTONDOWN;
|
isLeft = msg == WindowsMessages.LBUTTONDOWN;
|
||||||
this.RaiseEvent(new PointerPressedEventArgs(
|
this.RaiseEvent(new PointerPressedEventArgs(
|
||||||
this,
|
this,
|
||||||
new Avalonia.Input.Pointer(0, PointerType.Mouse, true),
|
new Pointer(0, PointerType.Mouse, true),
|
||||||
root,
|
root,
|
||||||
this.TranslatePoint(point, root).Value,
|
this.TranslatePoint(point, root).Value,
|
||||||
(ulong)Environment.TickCount64,
|
(ulong)Environment.TickCount64,
|
||||||
|
@ -164,7 +177,7 @@ namespace Ryujinx.Ava.Ui.Controls
|
||||||
isLeft = msg == WindowsMessages.LBUTTONUP;
|
isLeft = msg == WindowsMessages.LBUTTONUP;
|
||||||
this.RaiseEvent(new PointerReleasedEventArgs(
|
this.RaiseEvent(new PointerReleasedEventArgs(
|
||||||
this,
|
this,
|
||||||
new Avalonia.Input.Pointer(0, PointerType.Mouse, true),
|
new Pointer(0, PointerType.Mouse, true),
|
||||||
root,
|
root,
|
||||||
this.TranslatePoint(point, root).Value,
|
this.TranslatePoint(point, root).Value,
|
||||||
(ulong)Environment.TickCount64,
|
(ulong)Environment.TickCount64,
|
||||||
|
@ -176,7 +189,7 @@ namespace Ryujinx.Ava.Ui.Controls
|
||||||
this.RaiseEvent(new PointerEventArgs(
|
this.RaiseEvent(new PointerEventArgs(
|
||||||
PointerMovedEvent,
|
PointerMovedEvent,
|
||||||
this,
|
this,
|
||||||
new Avalonia.Input.Pointer(0, PointerType.Mouse, true),
|
new Pointer(0, PointerType.Mouse, true),
|
||||||
root,
|
root,
|
||||||
this.TranslatePoint(point, root).Value,
|
this.TranslatePoint(point, root).Value,
|
||||||
(ulong)Environment.TickCount64,
|
(ulong)Environment.TickCount64,
|
||||||
|
@ -187,6 +200,16 @@ namespace Ryujinx.Ava.Ui.Controls
|
||||||
return DefWindowProc(hWnd, msg, (IntPtr)wParam, (IntPtr)lParam);
|
return DefWindowProc(hWnd, msg, (IntPtr)wParam, (IntPtr)lParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[SupportedOSPlatform("macos")]
|
||||||
|
IPlatformHandle CreateMacOs(IPlatformHandle parent)
|
||||||
|
{
|
||||||
|
MetalLayer = MetalHelper.GetMetalLayer(out IntPtr nsView, out _updateBoundsCallback);
|
||||||
|
|
||||||
|
NsView = nsView;
|
||||||
|
|
||||||
|
return new PlatformHandle(nsView, "NSView");
|
||||||
|
}
|
||||||
|
|
||||||
void DestroyLinux()
|
void DestroyLinux()
|
||||||
{
|
{
|
||||||
X11Window?.Dispose();
|
X11Window?.Dispose();
|
||||||
|
@ -198,5 +221,11 @@ namespace Ryujinx.Ava.Ui.Controls
|
||||||
DestroyWindow(handle.Handle);
|
DestroyWindow(handle.Handle);
|
||||||
UnregisterClass(_className, GetModuleHandle(null));
|
UnregisterClass(_className, GetModuleHandle(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[SupportedOSPlatform("macos")]
|
||||||
|
void DestroyMacOS()
|
||||||
|
{
|
||||||
|
MetalHelper.DestroyMetalLayer(NsView, MetalLayer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -138,6 +138,9 @@
|
||||||
<Style Selector="ListBoxItem:selected /template/ ContentPresenter">
|
<Style Selector="ListBoxItem:selected /template/ ContentPresenter">
|
||||||
<Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
|
<Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
|
||||||
</Style>
|
</Style>
|
||||||
|
<Style Selector="ListBoxItem:selected /template/ Border#SelectionIndicator">
|
||||||
|
<Setter Property="MinHeight" Value="100" />
|
||||||
|
</Style>
|
||||||
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter">
|
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter">
|
||||||
<Setter Property="Background" Value="{DynamicResource AppListHoverBackgroundColor}" />
|
<Setter Property="Background" Value="{DynamicResource AppListHoverBackgroundColor}" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
|
@ -3,6 +3,7 @@ using Ryujinx.Ava.Ui.Controls;
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
using SPB.Graphics.Vulkan;
|
using SPB.Graphics.Vulkan;
|
||||||
using SPB.Platform.GLX;
|
using SPB.Platform.GLX;
|
||||||
|
using SPB.Platform.Metal;
|
||||||
using SPB.Platform.Win32;
|
using SPB.Platform.Win32;
|
||||||
using SPB.Platform.X11;
|
using SPB.Platform.X11;
|
||||||
using SPB.Windowing;
|
using SPB.Windowing;
|
||||||
|
@ -37,6 +38,10 @@ namespace Ryujinx.Ava.Ui
|
||||||
{
|
{
|
||||||
_window = new SimpleX11Window(new NativeHandle(X11Display), new NativeHandle(WindowHandle));
|
_window = new SimpleX11Window(new NativeHandle(X11Display), new NativeHandle(WindowHandle));
|
||||||
}
|
}
|
||||||
|
else if (OperatingSystem.IsMacOS())
|
||||||
|
{
|
||||||
|
_window = new SimpleMetalWindow(new NativeHandle(NsView), new NativeHandle(MetalLayer));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new PlatformNotSupportedException();
|
throw new PlatformNotSupportedException();
|
||||||
|
|
|
@ -545,7 +545,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
|
|
||||||
config = new StandardKeyboardInputConfig
|
config = new StandardKeyboardInputConfig
|
||||||
{
|
{
|
||||||
Version = Ryujinx.Common.Configuration.Hid.InputConfig.CurrentVersion,
|
Version = InputConfig.CurrentVersion,
|
||||||
Backend = InputBackendType.WindowKeyboard,
|
Backend = InputBackendType.WindowKeyboard,
|
||||||
Id = id,
|
Id = id,
|
||||||
ControllerType = ControllerType.ProController,
|
ControllerType = ControllerType.ProController,
|
||||||
|
@ -600,7 +600,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
|
|
||||||
config = new StandardControllerInputConfig
|
config = new StandardControllerInputConfig
|
||||||
{
|
{
|
||||||
Version = Ryujinx.Common.Configuration.Hid.InputConfig.CurrentVersion,
|
Version = InputConfig.CurrentVersion,
|
||||||
Backend = InputBackendType.GamepadSDL2,
|
Backend = InputBackendType.GamepadSDL2,
|
||||||
Id = id,
|
Id = id,
|
||||||
ControllerType = ControllerType.ProController,
|
ControllerType = ControllerType.ProController,
|
||||||
|
|
|
@ -108,6 +108,8 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsOpenGLAvailable => !OperatingSystem.IsMacOS();
|
||||||
|
|
||||||
public bool DirectoryChanged
|
public bool DirectoryChanged
|
||||||
{
|
{
|
||||||
get => _directoryChanged;
|
get => _directoryChanged;
|
||||||
|
|
|
@ -104,11 +104,11 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||||
|
|
||||||
var device = ViewModel.Devices[ViewModel.Device];
|
var device = ViewModel.Devices[ViewModel.Device];
|
||||||
|
|
||||||
if (device.Type == Models.DeviceType.Keyboard)
|
if (device.Type == DeviceType.Keyboard)
|
||||||
{
|
{
|
||||||
assigner = new KeyboardKeyAssigner((IKeyboard)ViewModel.SelectedGamepad);
|
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);
|
assigner = new GamepadButtonAssigner(ViewModel.SelectedGamepad, (ViewModel.Config as StandardControllerInputConfig).TriggerThreshold, forStick);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,9 +12,9 @@
|
||||||
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
|
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
|
||||||
Title="Ryujinx"
|
Title="Ryujinx"
|
||||||
Width="1280"
|
Width="1280"
|
||||||
Height="785"
|
Height="777"
|
||||||
MinWidth="1092"
|
MinWidth="1092"
|
||||||
MinHeight="680"
|
MinHeight="672"
|
||||||
d:DesignHeight="720"
|
d:DesignHeight="720"
|
||||||
d:DesignWidth="1280"
|
d:DesignWidth="1280"
|
||||||
x:CompileBindings="True"
|
x:CompileBindings="True"
|
||||||
|
@ -552,9 +552,8 @@
|
||||||
<Grid
|
<Grid
|
||||||
Name="StatusBar"
|
Name="StatusBar"
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
MinHeight="30"
|
Margin="0"
|
||||||
Height="30"
|
MinHeight="22"
|
||||||
Margin="0,0"
|
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Bottom"
|
VerticalAlignment="Bottom"
|
||||||
Background="{DynamicResource ThemeContentBackgroundColor}"
|
Background="{DynamicResource ThemeContentBackgroundColor}"
|
||||||
|
@ -568,7 +567,7 @@
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="10,0"
|
Margin="5"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
IsVisible="{Binding EnableNonGameRunningControls}">
|
IsVisible="{Binding EnableNonGameRunningControls}">
|
||||||
<Grid Margin="0">
|
<Grid Margin="0">
|
||||||
|
@ -610,14 +609,14 @@
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="10,0"
|
Margin="0,2"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
IsVisible="{Binding IsGameRunning}"
|
IsVisible="{Binding IsGameRunning}"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Name="VsyncStatus"
|
Name="VsyncStatus"
|
||||||
Margin="0,0,5,0"
|
Margin="5,0,5,0"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Foreground="{Binding VsyncColor}"
|
Foreground="{Binding VsyncColor}"
|
||||||
|
@ -628,7 +627,7 @@
|
||||||
<Border
|
<Border
|
||||||
Width="2"
|
Width="2"
|
||||||
Height="12"
|
Height="12"
|
||||||
Margin="2,0"
|
Margin="0"
|
||||||
BorderBrush="Gray"
|
BorderBrush="Gray"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
IsVisible="{Binding !ShowLoadProgress}" />
|
IsVisible="{Binding !ShowLoadProgress}" />
|
||||||
|
@ -644,7 +643,7 @@
|
||||||
<Border
|
<Border
|
||||||
Width="2"
|
Width="2"
|
||||||
Height="12"
|
Height="12"
|
||||||
Margin="2,0"
|
Margin="0"
|
||||||
BorderBrush="Gray"
|
BorderBrush="Gray"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
IsVisible="{Binding !ShowLoadProgress}" />
|
IsVisible="{Binding !ShowLoadProgress}" />
|
||||||
|
@ -660,13 +659,13 @@
|
||||||
<Border
|
<Border
|
||||||
Width="2"
|
Width="2"
|
||||||
Height="12"
|
Height="12"
|
||||||
Margin="2,0"
|
Margin="0"
|
||||||
BorderBrush="Gray"
|
BorderBrush="Gray"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
IsVisible="{Binding !ShowLoadProgress}" />
|
IsVisible="{Binding !ShowLoadProgress}" />
|
||||||
<ui:ToggleSplitButton
|
<ui:ToggleSplitButton
|
||||||
Name="VolumeStatus"
|
Name="VolumeStatus"
|
||||||
Padding="5"
|
Padding="5,0,5,0"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
VerticalContentAlignment="Center"
|
VerticalContentAlignment="Center"
|
||||||
|
@ -679,6 +678,7 @@
|
||||||
<Flyout Placement="Bottom" ShowMode="TransientWithDismissOnPointerMoveAway">
|
<Flyout Placement="Bottom" ShowMode="TransientWithDismissOnPointerMoveAway">
|
||||||
<Grid Margin="0">
|
<Grid Margin="0">
|
||||||
<Slider
|
<Slider
|
||||||
|
MaxHeight="40"
|
||||||
Width="150"
|
Width="150"
|
||||||
Margin="0"
|
Margin="0"
|
||||||
Padding="0"
|
Padding="0"
|
||||||
|
@ -697,7 +697,7 @@
|
||||||
<Border
|
<Border
|
||||||
Width="2"
|
Width="2"
|
||||||
Height="12"
|
Height="12"
|
||||||
Margin="2,0"
|
Margin="0"
|
||||||
BorderBrush="Gray"
|
BorderBrush="Gray"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
IsVisible="{Binding !ShowLoadProgress}" />
|
IsVisible="{Binding !ShowLoadProgress}" />
|
||||||
|
@ -711,7 +711,7 @@
|
||||||
<Border
|
<Border
|
||||||
Width="2"
|
Width="2"
|
||||||
Height="12"
|
Height="12"
|
||||||
Margin="2,0"
|
Margin="0"
|
||||||
BorderBrush="Gray"
|
BorderBrush="Gray"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
IsVisible="{Binding !ShowLoadProgress}" />
|
IsVisible="{Binding !ShowLoadProgress}" />
|
||||||
|
@ -725,7 +725,7 @@
|
||||||
<Border
|
<Border
|
||||||
Width="2"
|
Width="2"
|
||||||
Height="12"
|
Height="12"
|
||||||
Margin="2,0"
|
Margin="0"
|
||||||
BorderBrush="Gray"
|
BorderBrush="Gray"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
IsVisible="{Binding !ShowLoadProgress}" />
|
IsVisible="{Binding !ShowLoadProgress}" />
|
||||||
|
@ -739,7 +739,7 @@
|
||||||
<Border
|
<Border
|
||||||
Width="2"
|
Width="2"
|
||||||
Height="12"
|
Height="12"
|
||||||
Margin="2,0"
|
Margin="0"
|
||||||
BorderBrush="Gray"
|
BorderBrush="Gray"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
IsVisible="{Binding !ShowLoadProgress}" />
|
IsVisible="{Binding !ShowLoadProgress}" />
|
||||||
|
@ -753,7 +753,7 @@
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Grid.Column="3"
|
Grid.Column="3"
|
||||||
Margin="10,0"
|
Margin="0,0,5,0"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
IsVisible="{Binding ShowFirmwareStatus}"
|
IsVisible="{Binding ShowFirmwareStatus}"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
|
|
|
@ -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)
|
public void Application_Opened(object sender, ApplicationOpenedEventArgs args)
|
||||||
{
|
{
|
||||||
if (args.Application != null)
|
if (args.Application != null)
|
||||||
|
|
|
@ -540,7 +540,7 @@
|
||||||
<ComboBoxItem IsVisible="{Binding IsVulkanAvailable}">
|
<ComboBoxItem IsVisible="{Binding IsVulkanAvailable}">
|
||||||
<TextBlock Text="Vulkan" />
|
<TextBlock Text="Vulkan" />
|
||||||
</ComboBoxItem>
|
</ComboBoxItem>
|
||||||
<ComboBoxItem>
|
<ComboBoxItem IsEnabled="{Binding IsOpenGLAvailable}">
|
||||||
<TextBlock Text="OpenGL" />
|
<TextBlock Text="OpenGL" />
|
||||||
</ComboBoxItem>
|
</ComboBoxItem>
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
|
|
|
@ -45,7 +45,14 @@ namespace Ryujinx.Common.Configuration
|
||||||
|
|
||||||
public static void Initialize(string baseDirPath)
|
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);
|
string portablePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, DefaultPortableDir);
|
||||||
|
|
||||||
if (Directory.Exists(portablePath))
|
if (Directory.Exists(portablePath))
|
||||||
|
|
|
@ -152,7 +152,7 @@ namespace Ryujinx.Common.GraphicsDriver
|
||||||
|
|
||||||
if (ptr != IntPtr.Zero)
|
if (ptr != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
return Marshal.GetDelegateForFunctionPointer(ptr, typeof(T)) as T;
|
return Marshal.GetDelegateForFunctionPointer<T>(ptr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A simple implementation of a ReaderWriterLock which can be used from native code.
|
/// A simple implementation of a ReaderWriterLock which can be used from native code.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||||
public struct NativeReaderWriterLock
|
public struct NativeReaderWriterLock
|
||||||
{
|
{
|
||||||
public int WriteLock;
|
public int WriteLock;
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="MsgPack.Cli" Version="1.0.1" />
|
<PackageReference Include="MsgPack.Cli" Version="1.0.1" />
|
||||||
<PackageReference Include="System.Drawing.Common" Version="6.0.0" />
|
|
||||||
<PackageReference Include="System.Management" Version="7.0.0" />
|
<PackageReference Include="System.Management" Version="7.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using System;
|
using System;
|
||||||
using System.Drawing;
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
@ -51,7 +50,7 @@ namespace Ryujinx.Common.System
|
||||||
{
|
{
|
||||||
if (OperatingSystem.IsWindows())
|
if (OperatingSystem.IsWindows())
|
||||||
{
|
{
|
||||||
userDpiScale = Graphics.FromHwnd(IntPtr.Zero).DpiX;
|
userDpiScale = GdiPlusHelper.GetDpiX(IntPtr.Zero);
|
||||||
}
|
}
|
||||||
else if (OperatingSystem.IsLinux())
|
else if (OperatingSystem.IsLinux())
|
||||||
{
|
{
|
||||||
|
|
76
Ryujinx.Common/System/GdiPlusHelper.cs
Normal file
76
Ryujinx.Common/System/GdiPlusHelper.cs
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -60,7 +60,7 @@ namespace Ryujinx.Common.SystemInfo
|
||||||
|
|
||||||
public MemoryStatusEx()
|
public MemoryStatusEx()
|
||||||
{
|
{
|
||||||
Length = (uint)Marshal.SizeOf(typeof(MemoryStatusEx));
|
Length = (uint)Marshal.SizeOf<MemoryStatusEx>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Device
|
namespace Ryujinx.Graphics.Device
|
||||||
{
|
{
|
||||||
public class DeviceState<TState> : IDeviceState where TState : unmanaged
|
public class DeviceState<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] TState> : IDeviceState where TState : unmanaged
|
||||||
{
|
{
|
||||||
private const int RegisterSize = sizeof(int);
|
private const int RegisterSize = sizeof(int);
|
||||||
|
|
||||||
|
|
|
@ -50,186 +50,186 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||||
|
|
||||||
private static void InitLookup()
|
private static void InitLookup()
|
||||||
{
|
{
|
||||||
_lookup[(int)CommandType.Action] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.Action] = (memory, threaded, renderer) =>
|
||||||
ActionCommand.Run(ref GetCommand<ActionCommand>(memory), threaded, renderer);
|
ActionCommand.Run(ref GetCommand<ActionCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.CreateBuffer] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.CreateBuffer] = (memory, threaded, renderer) =>
|
||||||
CreateBufferCommand.Run(ref GetCommand<CreateBufferCommand>(memory), threaded, renderer);
|
CreateBufferCommand.Run(ref GetCommand<CreateBufferCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.CreateProgram] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.CreateProgram] = (memory, threaded, renderer) =>
|
||||||
CreateProgramCommand.Run(ref GetCommand<CreateProgramCommand>(memory), threaded, renderer);
|
CreateProgramCommand.Run(ref GetCommand<CreateProgramCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.CreateSampler] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.CreateSampler] = (memory, threaded, renderer) =>
|
||||||
CreateSamplerCommand.Run(ref GetCommand<CreateSamplerCommand>(memory), threaded, renderer);
|
CreateSamplerCommand.Run(ref GetCommand<CreateSamplerCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.CreateSync] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.CreateSync] = (memory, threaded, renderer) =>
|
||||||
CreateSyncCommand.Run(ref GetCommand<CreateSyncCommand>(memory), threaded, renderer);
|
CreateSyncCommand.Run(ref GetCommand<CreateSyncCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.CreateTexture] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.CreateTexture] = (memory, threaded, renderer) =>
|
||||||
CreateTextureCommand.Run(ref GetCommand<CreateTextureCommand>(memory), threaded, renderer);
|
CreateTextureCommand.Run(ref GetCommand<CreateTextureCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.GetCapabilities] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.GetCapabilities] = (memory, threaded, renderer) =>
|
||||||
GetCapabilitiesCommand.Run(ref GetCommand<GetCapabilitiesCommand>(memory), threaded, renderer);
|
GetCapabilitiesCommand.Run(ref GetCommand<GetCapabilitiesCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.PreFrame] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.PreFrame] = (memory, threaded, renderer) =>
|
||||||
PreFrameCommand.Run(ref GetCommand<PreFrameCommand>(memory), threaded, renderer);
|
PreFrameCommand.Run(ref GetCommand<PreFrameCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.ReportCounter] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.ReportCounter] = (memory, threaded, renderer) =>
|
||||||
ReportCounterCommand.Run(ref GetCommand<ReportCounterCommand>(memory), threaded, renderer);
|
ReportCounterCommand.Run(ref GetCommand<ReportCounterCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.ResetCounter] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.ResetCounter] = (memory, threaded, renderer) =>
|
||||||
ResetCounterCommand.Run(ref GetCommand<ResetCounterCommand>(memory), threaded, renderer);
|
ResetCounterCommand.Run(ref GetCommand<ResetCounterCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.UpdateCounters] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.UpdateCounters] = (memory, threaded, renderer) =>
|
||||||
UpdateCountersCommand.Run(ref GetCommand<UpdateCountersCommand>(memory), threaded, renderer);
|
UpdateCountersCommand.Run(ref GetCommand<UpdateCountersCommand>(memory), threaded, renderer);
|
||||||
|
|
||||||
_lookup[(int)CommandType.BufferDispose] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.BufferDispose] = (memory, threaded, renderer) =>
|
||||||
BufferDisposeCommand.Run(ref GetCommand<BufferDisposeCommand>(memory), threaded, renderer);
|
BufferDisposeCommand.Run(ref GetCommand<BufferDisposeCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.BufferGetData] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.BufferGetData] = (memory, threaded, renderer) =>
|
||||||
BufferGetDataCommand.Run(ref GetCommand<BufferGetDataCommand>(memory), threaded, renderer);
|
BufferGetDataCommand.Run(ref GetCommand<BufferGetDataCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.BufferSetData] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.BufferSetData] = (memory, threaded, renderer) =>
|
||||||
BufferSetDataCommand.Run(ref GetCommand<BufferSetDataCommand>(memory), threaded, renderer);
|
BufferSetDataCommand.Run(ref GetCommand<BufferSetDataCommand>(memory), threaded, renderer);
|
||||||
|
|
||||||
_lookup[(int)CommandType.CounterEventDispose] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.CounterEventDispose] = (memory, threaded, renderer) =>
|
||||||
CounterEventDisposeCommand.Run(ref GetCommand<CounterEventDisposeCommand>(memory), threaded, renderer);
|
CounterEventDisposeCommand.Run(ref GetCommand<CounterEventDisposeCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.CounterEventFlush] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.CounterEventFlush] = (memory, threaded, renderer) =>
|
||||||
CounterEventFlushCommand.Run(ref GetCommand<CounterEventFlushCommand>(memory), threaded, renderer);
|
CounterEventFlushCommand.Run(ref GetCommand<CounterEventFlushCommand>(memory), threaded, renderer);
|
||||||
|
|
||||||
_lookup[(int)CommandType.ProgramDispose] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.ProgramDispose] = (memory, threaded, renderer) =>
|
||||||
ProgramDisposeCommand.Run(ref GetCommand<ProgramDisposeCommand>(memory), threaded, renderer);
|
ProgramDisposeCommand.Run(ref GetCommand<ProgramDisposeCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.ProgramGetBinary] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.ProgramGetBinary] = (memory, threaded, renderer) =>
|
||||||
ProgramGetBinaryCommand.Run(ref GetCommand<ProgramGetBinaryCommand>(memory), threaded, renderer);
|
ProgramGetBinaryCommand.Run(ref GetCommand<ProgramGetBinaryCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.ProgramCheckLink] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.ProgramCheckLink] = (memory, threaded, renderer) =>
|
||||||
ProgramCheckLinkCommand.Run(ref GetCommand<ProgramCheckLinkCommand>(memory), threaded, renderer);
|
ProgramCheckLinkCommand.Run(ref GetCommand<ProgramCheckLinkCommand>(memory), threaded, renderer);
|
||||||
|
|
||||||
_lookup[(int)CommandType.SamplerDispose] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SamplerDispose] = (memory, threaded, renderer) =>
|
||||||
SamplerDisposeCommand.Run(ref GetCommand<SamplerDisposeCommand>(memory), threaded, renderer);
|
SamplerDisposeCommand.Run(ref GetCommand<SamplerDisposeCommand>(memory), threaded, renderer);
|
||||||
|
|
||||||
_lookup[(int)CommandType.TextureCopyTo] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TextureCopyTo] = (memory, threaded, renderer) =>
|
||||||
TextureCopyToCommand.Run(ref GetCommand<TextureCopyToCommand>(memory), threaded, renderer);
|
TextureCopyToCommand.Run(ref GetCommand<TextureCopyToCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.TextureCopyToScaled] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TextureCopyToScaled] = (memory, threaded, renderer) =>
|
||||||
TextureCopyToScaledCommand.Run(ref GetCommand<TextureCopyToScaledCommand>(memory), threaded, renderer);
|
TextureCopyToScaledCommand.Run(ref GetCommand<TextureCopyToScaledCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.TextureCopyToSlice] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TextureCopyToSlice] = (memory, threaded, renderer) =>
|
||||||
TextureCopyToSliceCommand.Run(ref GetCommand<TextureCopyToSliceCommand>(memory), threaded, renderer);
|
TextureCopyToSliceCommand.Run(ref GetCommand<TextureCopyToSliceCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.TextureCreateView] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TextureCreateView] = (memory, threaded, renderer) =>
|
||||||
TextureCreateViewCommand.Run(ref GetCommand<TextureCreateViewCommand>(memory), threaded, renderer);
|
TextureCreateViewCommand.Run(ref GetCommand<TextureCreateViewCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.TextureGetData] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TextureGetData] = (memory, threaded, renderer) =>
|
||||||
TextureGetDataCommand.Run(ref GetCommand<TextureGetDataCommand>(memory), threaded, renderer);
|
TextureGetDataCommand.Run(ref GetCommand<TextureGetDataCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.TextureGetDataSlice] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TextureGetDataSlice] = (memory, threaded, renderer) =>
|
||||||
TextureGetDataSliceCommand.Run(ref GetCommand<TextureGetDataSliceCommand>(memory), threaded, renderer);
|
TextureGetDataSliceCommand.Run(ref GetCommand<TextureGetDataSliceCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.TextureRelease] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TextureRelease] = (memory, threaded, renderer) =>
|
||||||
TextureReleaseCommand.Run(ref GetCommand<TextureReleaseCommand>(memory), threaded, renderer);
|
TextureReleaseCommand.Run(ref GetCommand<TextureReleaseCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.TextureSetData] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TextureSetData] = (memory, threaded, renderer) =>
|
||||||
TextureSetDataCommand.Run(ref GetCommand<TextureSetDataCommand>(memory), threaded, renderer);
|
TextureSetDataCommand.Run(ref GetCommand<TextureSetDataCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.TextureSetDataSlice] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TextureSetDataSlice] = (memory, threaded, renderer) =>
|
||||||
TextureSetDataSliceCommand.Run(ref GetCommand<TextureSetDataSliceCommand>(memory), threaded, renderer);
|
TextureSetDataSliceCommand.Run(ref GetCommand<TextureSetDataSliceCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.TextureSetDataSliceRegion] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TextureSetDataSliceRegion] = (memory, threaded, renderer) =>
|
||||||
TextureSetDataSliceRegionCommand.Run(ref GetCommand<TextureSetDataSliceRegionCommand>(memory), threaded, renderer);
|
TextureSetDataSliceRegionCommand.Run(ref GetCommand<TextureSetDataSliceRegionCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.TextureSetStorage] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TextureSetStorage] = (memory, threaded, renderer) =>
|
||||||
TextureSetStorageCommand.Run(ref GetCommand<TextureSetStorageCommand>(memory), threaded, renderer);
|
TextureSetStorageCommand.Run(ref GetCommand<TextureSetStorageCommand>(memory), threaded, renderer);
|
||||||
|
|
||||||
_lookup[(int)CommandType.WindowPresent] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.WindowPresent] = (memory, threaded, renderer) =>
|
||||||
WindowPresentCommand.Run(ref GetCommand<WindowPresentCommand>(memory), threaded, renderer);
|
WindowPresentCommand.Run(ref GetCommand<WindowPresentCommand>(memory), threaded, renderer);
|
||||||
|
|
||||||
_lookup[(int)CommandType.Barrier] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.Barrier] = (memory, threaded, renderer) =>
|
||||||
BarrierCommand.Run(ref GetCommand<BarrierCommand>(memory), threaded, renderer);
|
BarrierCommand.Run(ref GetCommand<BarrierCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.BeginTransformFeedback] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.BeginTransformFeedback] = (memory, threaded, renderer) =>
|
||||||
BeginTransformFeedbackCommand.Run(ref GetCommand<BeginTransformFeedbackCommand>(memory), threaded, renderer);
|
BeginTransformFeedbackCommand.Run(ref GetCommand<BeginTransformFeedbackCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.ClearBuffer] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.ClearBuffer] = (memory, threaded, renderer) =>
|
||||||
ClearBufferCommand.Run(ref GetCommand<ClearBufferCommand>(memory), threaded, renderer);
|
ClearBufferCommand.Run(ref GetCommand<ClearBufferCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.ClearRenderTargetColor] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.ClearRenderTargetColor] = (memory, threaded, renderer) =>
|
||||||
ClearRenderTargetColorCommand.Run(ref GetCommand<ClearRenderTargetColorCommand>(memory), threaded, renderer);
|
ClearRenderTargetColorCommand.Run(ref GetCommand<ClearRenderTargetColorCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.ClearRenderTargetDepthStencil] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.ClearRenderTargetDepthStencil] = (memory, threaded, renderer) =>
|
||||||
ClearRenderTargetDepthStencilCommand.Run(ref GetCommand<ClearRenderTargetDepthStencilCommand>(memory), threaded, renderer);
|
ClearRenderTargetDepthStencilCommand.Run(ref GetCommand<ClearRenderTargetDepthStencilCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.CommandBufferBarrier] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.CommandBufferBarrier] = (memory, threaded, renderer) =>
|
||||||
CommandBufferBarrierCommand.Run(ref GetCommand<CommandBufferBarrierCommand>(memory), threaded, renderer);
|
CommandBufferBarrierCommand.Run(ref GetCommand<CommandBufferBarrierCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.CopyBuffer] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.CopyBuffer] = (memory, threaded, renderer) =>
|
||||||
CopyBufferCommand.Run(ref GetCommand<CopyBufferCommand>(memory), threaded, renderer);
|
CopyBufferCommand.Run(ref GetCommand<CopyBufferCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.DispatchCompute] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.DispatchCompute] = (memory, threaded, renderer) =>
|
||||||
DispatchComputeCommand.Run(ref GetCommand<DispatchComputeCommand>(memory), threaded, renderer);
|
DispatchComputeCommand.Run(ref GetCommand<DispatchComputeCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.Draw] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.Draw] = (memory, threaded, renderer) =>
|
||||||
DrawCommand.Run(ref GetCommand<DrawCommand>(memory), threaded, renderer);
|
DrawCommand.Run(ref GetCommand<DrawCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.DrawIndexed] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.DrawIndexed] = (memory, threaded, renderer) =>
|
||||||
DrawIndexedCommand.Run(ref GetCommand<DrawIndexedCommand>(memory), threaded, renderer);
|
DrawIndexedCommand.Run(ref GetCommand<DrawIndexedCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.DrawIndexedIndirect] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.DrawIndexedIndirect] = (memory, threaded, renderer) =>
|
||||||
DrawIndexedIndirectCommand.Run(ref GetCommand<DrawIndexedIndirectCommand>(memory), threaded, renderer);
|
DrawIndexedIndirectCommand.Run(ref GetCommand<DrawIndexedIndirectCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.DrawIndexedIndirectCount] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.DrawIndexedIndirectCount] = (memory, threaded, renderer) =>
|
||||||
DrawIndexedIndirectCountCommand.Run(ref GetCommand<DrawIndexedIndirectCountCommand>(memory), threaded, renderer);
|
DrawIndexedIndirectCountCommand.Run(ref GetCommand<DrawIndexedIndirectCountCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.DrawIndirect] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.DrawIndirect] = (memory, threaded, renderer) =>
|
||||||
DrawIndirectCommand.Run(ref GetCommand<DrawIndirectCommand>(memory), threaded, renderer);
|
DrawIndirectCommand.Run(ref GetCommand<DrawIndirectCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.DrawIndirectCount] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.DrawIndirectCount] = (memory, threaded, renderer) =>
|
||||||
DrawIndirectCountCommand.Run(ref GetCommand<DrawIndirectCountCommand>(memory), threaded, renderer);
|
DrawIndirectCountCommand.Run(ref GetCommand<DrawIndirectCountCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.DrawTexture] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.DrawTexture] = (memory, threaded, renderer) =>
|
||||||
DrawTextureCommand.Run(ref GetCommand<DrawTextureCommand>(memory), threaded, renderer);
|
DrawTextureCommand.Run(ref GetCommand<DrawTextureCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.EndHostConditionalRendering] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.EndHostConditionalRendering] = (memory, threaded, renderer) =>
|
||||||
EndHostConditionalRenderingCommand.Run(renderer);
|
EndHostConditionalRenderingCommand.Run(renderer);
|
||||||
_lookup[(int)CommandType.EndTransformFeedback] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.EndTransformFeedback] = (memory, threaded, renderer) =>
|
||||||
EndTransformFeedbackCommand.Run(ref GetCommand<EndTransformFeedbackCommand>(memory), threaded, renderer);
|
EndTransformFeedbackCommand.Run(ref GetCommand<EndTransformFeedbackCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetAlphaTest] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetAlphaTest] = (memory, threaded, renderer) =>
|
||||||
SetAlphaTestCommand.Run(ref GetCommand<SetAlphaTestCommand>(memory), threaded, renderer);
|
SetAlphaTestCommand.Run(ref GetCommand<SetAlphaTestCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetBlendState] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetBlendState] = (memory, threaded, renderer) =>
|
||||||
SetBlendStateCommand.Run(ref GetCommand<SetBlendStateCommand>(memory), threaded, renderer);
|
SetBlendStateCommand.Run(ref GetCommand<SetBlendStateCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetDepthBias] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetDepthBias] = (memory, threaded, renderer) =>
|
||||||
SetDepthBiasCommand.Run(ref GetCommand<SetDepthBiasCommand>(memory), threaded, renderer);
|
SetDepthBiasCommand.Run(ref GetCommand<SetDepthBiasCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetDepthClamp] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetDepthClamp] = (memory, threaded, renderer) =>
|
||||||
SetDepthClampCommand.Run(ref GetCommand<SetDepthClampCommand>(memory), threaded, renderer);
|
SetDepthClampCommand.Run(ref GetCommand<SetDepthClampCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetDepthMode] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetDepthMode] = (memory, threaded, renderer) =>
|
||||||
SetDepthModeCommand.Run(ref GetCommand<SetDepthModeCommand>(memory), threaded, renderer);
|
SetDepthModeCommand.Run(ref GetCommand<SetDepthModeCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetDepthTest] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetDepthTest] = (memory, threaded, renderer) =>
|
||||||
SetDepthTestCommand.Run(ref GetCommand<SetDepthTestCommand>(memory), threaded, renderer);
|
SetDepthTestCommand.Run(ref GetCommand<SetDepthTestCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetFaceCulling] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetFaceCulling] = (memory, threaded, renderer) =>
|
||||||
SetFaceCullingCommand.Run(ref GetCommand<SetFaceCullingCommand>(memory), threaded, renderer);
|
SetFaceCullingCommand.Run(ref GetCommand<SetFaceCullingCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetFrontFace] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetFrontFace] = (memory, threaded, renderer) =>
|
||||||
SetFrontFaceCommand.Run(ref GetCommand<SetFrontFaceCommand>(memory), threaded, renderer);
|
SetFrontFaceCommand.Run(ref GetCommand<SetFrontFaceCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetStorageBuffers] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetStorageBuffers] = (memory, threaded, renderer) =>
|
||||||
SetStorageBuffersCommand.Run(ref GetCommand<SetStorageBuffersCommand>(memory), threaded, renderer);
|
SetStorageBuffersCommand.Run(ref GetCommand<SetStorageBuffersCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetTransformFeedbackBuffers] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetTransformFeedbackBuffers] = (memory, threaded, renderer) =>
|
||||||
SetTransformFeedbackBuffersCommand.Run(ref GetCommand<SetTransformFeedbackBuffersCommand>(memory), threaded, renderer);
|
SetTransformFeedbackBuffersCommand.Run(ref GetCommand<SetTransformFeedbackBuffersCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetUniformBuffers] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetUniformBuffers] = (memory, threaded, renderer) =>
|
||||||
SetUniformBuffersCommand.Run(ref GetCommand<SetUniformBuffersCommand>(memory), threaded, renderer);
|
SetUniformBuffersCommand.Run(ref GetCommand<SetUniformBuffersCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetImage] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetImage] = (memory, threaded, renderer) =>
|
||||||
SetImageCommand.Run(ref GetCommand<SetImageCommand>(memory), threaded, renderer);
|
SetImageCommand.Run(ref GetCommand<SetImageCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetIndexBuffer] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetIndexBuffer] = (memory, threaded, renderer) =>
|
||||||
SetIndexBufferCommand.Run(ref GetCommand<SetIndexBufferCommand>(memory), threaded, renderer);
|
SetIndexBufferCommand.Run(ref GetCommand<SetIndexBufferCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetLineParameters] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetLineParameters] = (memory, threaded, renderer) =>
|
||||||
SetLineParametersCommand.Run(ref GetCommand<SetLineParametersCommand>(memory), threaded, renderer);
|
SetLineParametersCommand.Run(ref GetCommand<SetLineParametersCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetLogicOpState] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetLogicOpState] = (memory, threaded, renderer) =>
|
||||||
SetLogicOpStateCommand.Run(ref GetCommand<SetLogicOpStateCommand>(memory), threaded, renderer);
|
SetLogicOpStateCommand.Run(ref GetCommand<SetLogicOpStateCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetMultisampleState] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetMultisampleState] = (memory, threaded, renderer) =>
|
||||||
SetMultisampleStateCommand.Run(ref GetCommand<SetMultisampleStateCommand>(memory), threaded, renderer);
|
SetMultisampleStateCommand.Run(ref GetCommand<SetMultisampleStateCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetPatchParameters] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetPatchParameters] = (memory, threaded, renderer) =>
|
||||||
SetPatchParametersCommand.Run(ref GetCommand<SetPatchParametersCommand>(memory), threaded, renderer);
|
SetPatchParametersCommand.Run(ref GetCommand<SetPatchParametersCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetPointParameters] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetPointParameters] = (memory, threaded, renderer) =>
|
||||||
SetPointParametersCommand.Run(ref GetCommand<SetPointParametersCommand>(memory), threaded, renderer);
|
SetPointParametersCommand.Run(ref GetCommand<SetPointParametersCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetPolygonMode] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetPolygonMode] = (memory, threaded, renderer) =>
|
||||||
SetPolygonModeCommand.Run(ref GetCommand<SetPolygonModeCommand>(memory), threaded, renderer);
|
SetPolygonModeCommand.Run(ref GetCommand<SetPolygonModeCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetPrimitiveRestart] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetPrimitiveRestart] = (memory, threaded, renderer) =>
|
||||||
SetPrimitiveRestartCommand.Run(ref GetCommand<SetPrimitiveRestartCommand>(memory), threaded, renderer);
|
SetPrimitiveRestartCommand.Run(ref GetCommand<SetPrimitiveRestartCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetPrimitiveTopology] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetPrimitiveTopology] = (memory, threaded, renderer) =>
|
||||||
SetPrimitiveTopologyCommand.Run(ref GetCommand<SetPrimitiveTopologyCommand>(memory), threaded, renderer);
|
SetPrimitiveTopologyCommand.Run(ref GetCommand<SetPrimitiveTopologyCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetProgram] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetProgram] = (memory, threaded, renderer) =>
|
||||||
SetProgramCommand.Run(ref GetCommand<SetProgramCommand>(memory), threaded, renderer);
|
SetProgramCommand.Run(ref GetCommand<SetProgramCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetRasterizerDiscard] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetRasterizerDiscard] = (memory, threaded, renderer) =>
|
||||||
SetRasterizerDiscardCommand.Run(ref GetCommand<SetRasterizerDiscardCommand>(memory), threaded, renderer);
|
SetRasterizerDiscardCommand.Run(ref GetCommand<SetRasterizerDiscardCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetRenderTargetColorMasks] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetRenderTargetColorMasks] = (memory, threaded, renderer) =>
|
||||||
SetRenderTargetColorMasksCommand.Run(ref GetCommand<SetRenderTargetColorMasksCommand>(memory), threaded, renderer);
|
SetRenderTargetColorMasksCommand.Run(ref GetCommand<SetRenderTargetColorMasksCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetRenderTargetScale] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetRenderTargetScale] = (memory, threaded, renderer) =>
|
||||||
SetRenderTargetScaleCommand.Run(ref GetCommand<SetRenderTargetScaleCommand>(memory), threaded, renderer);
|
SetRenderTargetScaleCommand.Run(ref GetCommand<SetRenderTargetScaleCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetRenderTargets] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetRenderTargets] = (memory, threaded, renderer) =>
|
||||||
SetRenderTargetsCommand.Run(ref GetCommand<SetRenderTargetsCommand>(memory), threaded, renderer);
|
SetRenderTargetsCommand.Run(ref GetCommand<SetRenderTargetsCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetScissor] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetScissor] = (memory, threaded, renderer) =>
|
||||||
SetScissorsCommand.Run(ref GetCommand<SetScissorsCommand>(memory), threaded, renderer);
|
SetScissorsCommand.Run(ref GetCommand<SetScissorsCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetStencilTest] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetStencilTest] = (memory, threaded, renderer) =>
|
||||||
SetStencilTestCommand.Run(ref GetCommand<SetStencilTestCommand>(memory), threaded, renderer);
|
SetStencilTestCommand.Run(ref GetCommand<SetStencilTestCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetTextureAndSampler] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetTextureAndSampler] = (memory, threaded, renderer) =>
|
||||||
SetTextureAndSamplerCommand.Run(ref GetCommand<SetTextureAndSamplerCommand>(memory), threaded, renderer);
|
SetTextureAndSamplerCommand.Run(ref GetCommand<SetTextureAndSamplerCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetUserClipDistance] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetUserClipDistance] = (memory, threaded, renderer) =>
|
||||||
SetUserClipDistanceCommand.Run(ref GetCommand<SetUserClipDistanceCommand>(memory), threaded, renderer);
|
SetUserClipDistanceCommand.Run(ref GetCommand<SetUserClipDistanceCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetVertexAttribs] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetVertexAttribs] = (memory, threaded, renderer) =>
|
||||||
SetVertexAttribsCommand.Run(ref GetCommand<SetVertexAttribsCommand>(memory), threaded, renderer);
|
SetVertexAttribsCommand.Run(ref GetCommand<SetVertexAttribsCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetVertexBuffers] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetVertexBuffers] = (memory, threaded, renderer) =>
|
||||||
SetVertexBuffersCommand.Run(ref GetCommand<SetVertexBuffersCommand>(memory), threaded, renderer);
|
SetVertexBuffersCommand.Run(ref GetCommand<SetVertexBuffersCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.SetViewports] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.SetViewports] = (memory, threaded, renderer) =>
|
||||||
SetViewportsCommand.Run(ref GetCommand<SetViewportsCommand>(memory), threaded, renderer);
|
SetViewportsCommand.Run(ref GetCommand<SetViewportsCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.TextureBarrier] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TextureBarrier] = (memory, threaded, renderer) =>
|
||||||
TextureBarrierCommand.Run(ref GetCommand<TextureBarrierCommand>(memory), threaded, renderer);
|
TextureBarrierCommand.Run(ref GetCommand<TextureBarrierCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.TextureBarrierTiled] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TextureBarrierTiled] = (memory, threaded, renderer) =>
|
||||||
TextureBarrierTiledCommand.Run(ref GetCommand<TextureBarrierTiledCommand>(memory), threaded, renderer);
|
TextureBarrierTiledCommand.Run(ref GetCommand<TextureBarrierTiledCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.TryHostConditionalRendering] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TryHostConditionalRendering] = (memory, threaded, renderer) =>
|
||||||
TryHostConditionalRenderingCommand.Run(ref GetCommand<TryHostConditionalRenderingCommand>(memory), threaded, renderer);
|
TryHostConditionalRenderingCommand.Run(ref GetCommand<TryHostConditionalRenderingCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.TryHostConditionalRenderingFlush] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.TryHostConditionalRenderingFlush] = (memory, threaded, renderer) =>
|
||||||
TryHostConditionalRenderingFlushCommand.Run(ref GetCommand<TryHostConditionalRenderingFlushCommand>(memory), threaded, renderer);
|
TryHostConditionalRenderingFlushCommand.Run(ref GetCommand<TryHostConditionalRenderingFlushCommand>(memory), threaded, renderer);
|
||||||
_lookup[(int)CommandType.UpdateRenderScale] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
_lookup[(int)CommandType.UpdateRenderScale] = (memory, threaded, renderer) =>
|
||||||
UpdateRenderScaleCommand.Run(ref GetCommand<UpdateRenderScaleCommand>(memory), threaded, renderer);
|
UpdateRenderScaleCommand.Run(ref GetCommand<UpdateRenderScaleCommand>(memory), threaded, renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||||
{
|
{
|
||||||
_baseRenderer = renderer;
|
_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);
|
Pipeline = new ThreadedPipeline(this, renderer.Pipeline);
|
||||||
Window = new ThreadedWindow(this, renderer);
|
Window = new ThreadedWindow(this, renderer);
|
||||||
|
|
|
@ -61,7 +61,7 @@ namespace Ryujinx.Graphics.GAL
|
||||||
AddressMode.ClampToEdge,
|
AddressMode.ClampToEdge,
|
||||||
AddressMode.ClampToEdge,
|
AddressMode.ClampToEdge,
|
||||||
CompareMode.None,
|
CompareMode.None,
|
||||||
GAL.CompareOp.Always,
|
CompareOp.Always,
|
||||||
new ColorF(0f, 0f, 0f, 0f),
|
new ColorF(0f, 0f, 0f, 0f),
|
||||||
0f,
|
0f,
|
||||||
0f,
|
0f,
|
||||||
|
|
|
@ -2,6 +2,7 @@ using Ryujinx.Graphics.Device;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Engine
|
namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
|
@ -21,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
/// Represents a device's state, with a additional shadow state.
|
/// Represents a device's state, with a additional shadow state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TState">Type of the state</typeparam>
|
/// <typeparam name="TState">Type of the state</typeparam>
|
||||||
class DeviceStateWithShadow<TState> : IDeviceState where TState : unmanaged, IShadowState
|
class DeviceStateWithShadow<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] TState> : IDeviceState where TState : unmanaged, IShadowState
|
||||||
{
|
{
|
||||||
private readonly DeviceState<TState> _state;
|
private readonly DeviceState<TState> _state;
|
||||||
private readonly DeviceState<TState> _shadowState;
|
private readonly DeviceState<TState> _shadowState;
|
||||||
|
|
|
@ -253,14 +253,19 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
/// Indicates that any storage buffer use is unaligned.
|
/// Indicates that any storage buffer use is unaligned.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value">The new value</param>
|
/// <param name="value">The new value</param>
|
||||||
public void SetHasUnalignedStorageBuffer(bool value)
|
/// <returns>True if the unaligned state changed, false otherwise</returns>
|
||||||
|
public bool SetHasUnalignedStorageBuffer(bool value)
|
||||||
{
|
{
|
||||||
if (value != _graphics.HasUnalignedStorageBuffer)
|
if (value != _graphics.HasUnalignedStorageBuffer)
|
||||||
{
|
{
|
||||||
_graphics.HasUnalignedStorageBuffer = value;
|
_graphics.HasUnalignedStorageBuffer = value;
|
||||||
|
|
||||||
Signal();
|
Signal();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
@ -39,7 +40,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
/// GPU state update tracker.
|
/// GPU state update tracker.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TState">State type</typeparam>
|
/// <typeparam name="TState">State type</typeparam>
|
||||||
class StateUpdateTracker<TState>
|
class StateUpdateTracker<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] TState>
|
||||||
{
|
{
|
||||||
private const int BlockSize = 0xe00;
|
private const int BlockSize = 0xe00;
|
||||||
private const int RegisterSize = sizeof(uint);
|
private const int RegisterSize = sizeof(uint);
|
||||||
|
|
|
@ -304,14 +304,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void CommitBindings()
|
private void CommitBindings()
|
||||||
{
|
{
|
||||||
var buffers = _channel.BufferManager;
|
|
||||||
var hasUnaligned = buffers.HasUnalignedStorageBuffers;
|
|
||||||
|
|
||||||
UpdateStorageBuffers();
|
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.
|
// Shader must be reloaded. _vtgWritesRtLayer should not change.
|
||||||
UpdateShaderState();
|
UpdateShaderState();
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||||
private const ushort FileFormatVersionMajor = 1;
|
private const ushort FileFormatVersionMajor = 1;
|
||||||
private const ushort FileFormatVersionMinor = 2;
|
private const ushort FileFormatVersionMinor = 2;
|
||||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
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 SharedTocFileName = "shared.toc";
|
||||||
private const string SharedDataFileName = "shared.data";
|
private const string SharedDataFileName = "shared.data";
|
||||||
|
|
|
@ -110,7 +110,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Texture target.
|
/// Texture target.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Image.TextureTarget TextureTarget;
|
public TextureTarget TextureTarget;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates if the coordinates used to sample the texture are normalized or not (0.0..1.0 or 0..Width/Height).
|
/// 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,
|
int cbufSlot,
|
||||||
uint format,
|
uint format,
|
||||||
bool formatSrgb,
|
bool formatSrgb,
|
||||||
Image.TextureTarget target,
|
TextureTarget target,
|
||||||
bool coordNormalized)
|
bool coordNormalized)
|
||||||
{
|
{
|
||||||
Box<TextureSpecializationState> state = GetOrCreateTextureSpecState(stageIndex, handle, cbufSlot);
|
Box<TextureSpecializationState> state = GetOrCreateTextureSpecState(stageIndex, handle, cbufSlot);
|
||||||
|
@ -415,7 +415,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
/// <param name="stageIndex">Shader stage where the texture is used</param>
|
/// <param name="stageIndex">Shader stage where the texture is used</param>
|
||||||
/// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
|
/// <param name="handle">Offset in words of the texture handle on the texture buffer</param>
|
||||||
/// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
|
/// <param name="cbufSlot">Slot of the texture buffer constant buffer</param>
|
||||||
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;
|
return GetTextureSpecState(stageIndex, handle, cbufSlot).Value.TextureTarget;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 xLut = vec4(1.0, -1.0, 1.0, 0.0);
|
||||||
vec4 yLut = vec4(1.0, 1.0, -1.0, 1.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];
|
return x * xLut[lutIdx] + y * yLut[lutIdx];
|
||||||
}
|
}
|
|
@ -10,8 +10,6 @@ using static Spv.Specification;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
{
|
{
|
||||||
using SpvInstruction = Spv.Generator.Instruction;
|
|
||||||
|
|
||||||
static class Declarations
|
static class Declarations
|
||||||
{
|
{
|
||||||
// At least 16 attributes are guaranteed by the spec.
|
// 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++)
|
for (int funcIndex = 0; funcIndex < functions.Count; funcIndex++)
|
||||||
{
|
{
|
||||||
StructuredFunction function = functions[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++)
|
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);
|
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 arrayType = context.TypeArray(context.TypeU32(), context.Constant(context.TypeU32(), size));
|
||||||
var pointerType = context.TypePointer(storage, arrayType);
|
var pointerType = context.TypePointer(storage, arrayType);
|
||||||
|
|
|
@ -1449,10 +1449,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
var xLut = context.ConstantComposite(v4float, one, minusOne, one, zero);
|
var xLut = context.ConstantComposite(v4float, one, minusOne, one, zero);
|
||||||
var yLut = context.ConstantComposite(v4float, one, one, minusOne, one);
|
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 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));
|
shift = context.ShiftLeftLogical(context.TypeU32(), shift, context.Constant(context.TypeU32(), 1));
|
||||||
var lutIdx = context.ShiftRightLogical(context.TypeU32(), mask, shift);
|
var lutIdx = context.ShiftRightLogical(context.TypeU32(), mask, shift);
|
||||||
|
lutIdx = context.BitwiseAnd(context.TypeU32(), lutIdx, three);
|
||||||
|
|
||||||
var xLutValue = context.VectorExtractDynamic(context.TypeFP32(), xLut, lutIdx);
|
var xLutValue = context.VectorExtractDynamic(context.TypeFP32(), xLut, lutIdx);
|
||||||
var yLutValue = context.VectorExtractDynamic(context.TypeFP32(), yLut, lutIdx);
|
var yLutValue = context.VectorExtractDynamic(context.TypeFP32(), yLut, lutIdx);
|
||||||
|
|
|
@ -8,6 +8,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
public const int TessLevelOuter3 = 0x00c;
|
public const int TessLevelOuter3 = 0x00c;
|
||||||
public const int TessLevelInner0 = 0x010;
|
public const int TessLevelInner0 = 0x010;
|
||||||
public const int TessLevelInner1 = 0x014;
|
public const int TessLevelInner1 = 0x014;
|
||||||
|
public const int PrimitiveId = 0x060;
|
||||||
public const int Layer = 0x064;
|
public const int Layer = 0x064;
|
||||||
public const int ViewportIndex = 0x068;
|
public const int ViewportIndex = 0x068;
|
||||||
public const int PointSize = 0x06c;
|
public const int PointSize = 0x06c;
|
||||||
|
@ -85,8 +86,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
public const int LaneId = 0x2000020;
|
public const int LaneId = 0x2000020;
|
||||||
|
|
||||||
public const int InvocationId = 0x2000024;
|
public const int InvocationId = 0x2000024;
|
||||||
public const int PrimitiveId = 0x2000028;
|
public const int PatchVerticesIn = 0x2000028;
|
||||||
public const int PatchVerticesIn = 0x200002c;
|
|
||||||
|
|
||||||
public const int EqMask = 0x2000030;
|
public const int EqMask = 0x2000030;
|
||||||
public const int GeMask = 0x2000034;
|
public const int GeMask = 0x2000034;
|
||||||
|
|
|
@ -48,5 +48,10 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
_ => 0
|
_ => 0
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int GetConstantUbeOffset(int slot)
|
||||||
|
{
|
||||||
|
return UbeBaseOffset + slot * StorageDescSize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -8,11 +8,14 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||||
{
|
{
|
||||||
static class GlobalToStorage
|
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 sbStart = GetStorageBaseCbOffset(config.Stage);
|
||||||
int sbEnd = sbStart + StorageDescsSize;
|
int sbEnd = sbStart + StorageDescsSize;
|
||||||
|
|
||||||
|
int ubeStart = UbeBaseOffset;
|
||||||
|
int ubeEnd = UbeBaseOffset + UbeDescsSize;
|
||||||
|
|
||||||
for (LinkedListNode<INode> node = block.Operations.First; node != null; node = node.Next)
|
for (LinkedListNode<INode> node = block.Operations.First; node != null; node = node.Next)
|
||||||
{
|
{
|
||||||
for (int index = 0; index < node.Value.SourcesCount; index++)
|
for (int index = 0; index < node.Value.SourcesCount; index++)
|
||||||
|
@ -25,6 +28,16 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||||
{
|
{
|
||||||
sbUseMask |= 1 << storageIndex;
|
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))
|
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.
|
// so NVN "emulates" more constant buffers using global memory access.
|
||||||
// Here we try to replace the global access back to a constant buffer
|
// Here we try to replace the global access back to a constant buffer
|
||||||
// load.
|
// load.
|
||||||
storageIndex = SearchForStorageBase(block, source, UbeBaseOffset, UbeBaseOffset + UbeDescsSize);
|
storageIndex = SearchForStorageBase(block, source, ubeStart, ubeStart + ubeEnd);
|
||||||
|
|
||||||
if (storageIndex >= 0)
|
if (storageIndex >= 0)
|
||||||
{
|
{
|
||||||
|
@ -64,7 +77,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
config.SetAccessibleStorageBuffersMask(sbUseMask);
|
config.SetAccessibleBufferMasks(sbUseMask, ubeUseMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static LinkedListNode<INode> ReplaceGlobalWithStorage(BasicBlock block, LinkedListNode<INode> node, ShaderConfig config, int storageIndex)
|
private static LinkedListNode<INode> ReplaceGlobalWithStorage(BasicBlock block, LinkedListNode<INode> node, ShaderConfig config, int storageIndex)
|
||||||
|
|
|
@ -12,16 +12,17 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||||
RunOptimizationPasses(blocks);
|
RunOptimizationPasses(blocks);
|
||||||
|
|
||||||
int sbUseMask = 0;
|
int sbUseMask = 0;
|
||||||
|
int ubeUseMask = 0;
|
||||||
|
|
||||||
// Those passes are looking for specific patterns and only needs to run once.
|
// Those passes are looking for specific patterns and only needs to run once.
|
||||||
for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++)
|
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);
|
BindlessToIndexed.RunPass(blocks[blkIndex], config);
|
||||||
BindlessElimination.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.
|
// Run optimizations one last time to remove any code that is now optimizable after above passes.
|
||||||
RunOptimizationPasses(blocks);
|
RunOptimizationPasses(blocks);
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using Ryujinx.Graphics.Shader.Decoders;
|
||||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
@ -89,12 +90,42 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
return local;
|
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 addrLow = operation.GetSource(0);
|
||||||
Operand addrHigh = operation.GetSource(1);
|
Operand addrHigh = operation.GetSource(1);
|
||||||
|
|
||||||
Operand sbBaseAddrLow = Const(0);
|
Operand sbBaseAddrLow = Const(0);
|
||||||
Operand sbSlot = 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;
|
int sbUseMask = config.AccessibleStorageBuffersMask;
|
||||||
|
|
||||||
while (sbUseMask != 0)
|
while (sbUseMask != 0)
|
||||||
|
@ -107,20 +138,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
|
||||||
int cbOffset = GetStorageCbOffset(config.Stage, slot);
|
int cbOffset = GetStorageCbOffset(config.Stage, slot);
|
||||||
|
|
||||||
Operand baseAddrLow = Cbuf(0, cbOffset);
|
Operand inRange = BindingRangeCheck(cbOffset, out Operand baseAddrLow);
|
||||||
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);
|
|
||||||
|
|
||||||
sbBaseAddrLow = PrependOperation(Instruction.ConditionalSelect, inRange, baseAddrLow, sbBaseAddrLow);
|
sbBaseAddrLow = PrependOperation(Instruction.ConditionalSelect, inRange, baseAddrLow, sbBaseAddrLow);
|
||||||
sbSlot = PrependOperation(Instruction.ConditionalSelect, inRange, Const(slot), sbSlot);
|
sbSlot = PrependOperation(Instruction.ConditionalSelect, inRange, Const(slot), sbSlot);
|
||||||
|
@ -128,8 +146,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
|
||||||
if (config.AccessibleStorageBuffersMask != 0)
|
if (config.AccessibleStorageBuffersMask != 0)
|
||||||
{
|
{
|
||||||
Operand alignMask = Const(-config.GpuAccessor.QueryHostStorageBufferOffsetAlignment());
|
|
||||||
|
|
||||||
Operand baseAddrTrunc = PrependOperation(Instruction.BitwiseAnd, sbBaseAddrLow, alignMask);
|
Operand baseAddrTrunc = PrependOperation(Instruction.BitwiseAnd, sbBaseAddrLow, alignMask);
|
||||||
Operand byteOffset = PrependOperation(Instruction.Subtract, addrLow, baseAddrTrunc);
|
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));
|
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++)
|
for (int index = 0; index < operation.SourcesCount; index++)
|
||||||
{
|
{
|
||||||
operation.SetSource(index, null);
|
operation.SetSource(index, null);
|
||||||
|
|
|
@ -66,6 +66,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
public UInt128 ThisInputAttributesComponents { get; private set; }
|
public UInt128 ThisInputAttributesComponents { get; private set; }
|
||||||
|
|
||||||
public int AccessibleStorageBuffersMask { get; private set; }
|
public int AccessibleStorageBuffersMask { get; private set; }
|
||||||
|
public int AccessibleConstantBuffersMask { get; private set; }
|
||||||
|
|
||||||
private int _usedConstantBuffers;
|
private int _usedConstantBuffers;
|
||||||
private int _usedStorageBuffers;
|
private int _usedStorageBuffers;
|
||||||
|
@ -101,6 +102,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
Options = options;
|
Options = options;
|
||||||
|
|
||||||
AccessibleStorageBuffersMask = (1 << GlobalMemory.StorageMaxCount) - 1;
|
AccessibleStorageBuffersMask = (1 << GlobalMemory.StorageMaxCount) - 1;
|
||||||
|
AccessibleConstantBuffersMask = (1 << GlobalMemory.UbeMaxCount) - 1;
|
||||||
|
|
||||||
UsedInputAttributesPerPatch = new HashSet<int>();
|
UsedInputAttributesPerPatch = new HashSet<int>();
|
||||||
UsedOutputAttributesPerPatch = new HashSet<int>();
|
UsedOutputAttributesPerPatch = new HashSet<int>();
|
||||||
|
@ -121,6 +123,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
OutputTopology = outputTopology;
|
OutputTopology = outputTopology;
|
||||||
MaxOutputVertices = maxOutputVertices;
|
MaxOutputVertices = maxOutputVertices;
|
||||||
TransformFeedbackEnabled = gpuAccessor.QueryTransformFeedbackEnabled();
|
TransformFeedbackEnabled = gpuAccessor.QueryTransformFeedbackEnabled();
|
||||||
|
|
||||||
|
if (Stage != ShaderStage.Compute)
|
||||||
|
{
|
||||||
|
AccessibleConstantBuffersMask = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShaderConfig(ShaderHeader header, IGpuAccessor gpuAccessor, TranslationOptions options) : this(gpuAccessor, options)
|
public ShaderConfig(ShaderHeader header, IGpuAccessor gpuAccessor, TranslationOptions options) : this(gpuAccessor, options)
|
||||||
|
@ -404,9 +411,10 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
UsedFeatures |= flags;
|
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)
|
public void SetUsedConstantBuffer(int slot)
|
||||||
|
|
|
@ -272,7 +272,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_gd,
|
_gd,
|
||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
dstBuffer,
|
dstBuffer,
|
||||||
BufferHolder.DefaultAccessFlags,
|
DefaultAccessFlags,
|
||||||
AccessFlags.TransferWriteBit,
|
AccessFlags.TransferWriteBit,
|
||||||
PipelineStageFlags.AllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
PipelineStageFlags.TransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
|
@ -294,7 +294,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
dstBuffer,
|
dstBuffer,
|
||||||
AccessFlags.TransferWriteBit,
|
AccessFlags.TransferWriteBit,
|
||||||
BufferHolder.DefaultAccessFlags,
|
DefaultAccessFlags,
|
||||||
PipelineStageFlags.TransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
PipelineStageFlags.AllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
dstOffset,
|
dstOffset,
|
||||||
|
@ -319,7 +319,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
gd,
|
gd,
|
||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
dstBuffer,
|
dstBuffer,
|
||||||
BufferHolder.DefaultAccessFlags,
|
DefaultAccessFlags,
|
||||||
AccessFlags.TransferWriteBit,
|
AccessFlags.TransferWriteBit,
|
||||||
PipelineStageFlags.AllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
PipelineStageFlags.TransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
|
@ -335,7 +335,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
dstBuffer,
|
dstBuffer,
|
||||||
AccessFlags.TransferWriteBit,
|
AccessFlags.TransferWriteBit,
|
||||||
BufferHolder.DefaultAccessFlags,
|
DefaultAccessFlags,
|
||||||
PipelineStageFlags.TransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
PipelineStageFlags.AllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
dstOffset,
|
dstOffset,
|
||||||
|
|
|
@ -97,7 +97,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_dummyBuffer = gd.BufferManager.Create(gd, 0x10000, forConditionalRendering: false, deviceLocal: true);
|
_dummyBuffer = gd.BufferManager.Create(gd, 0x10000, forConditionalRendering: false, deviceLocal: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
_dummyTexture = gd.CreateTextureView(new GAL.TextureCreateInfo(
|
_dummyTexture = gd.CreateTextureView(new TextureCreateInfo(
|
||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
|
|
|
@ -3,7 +3,7 @@ using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Vulkan
|
namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
readonly struct DisposableBufferView : System.IDisposable
|
readonly struct DisposableBufferView : IDisposable
|
||||||
{
|
{
|
||||||
private readonly Vk _api;
|
private readonly Vk _api;
|
||||||
private readonly Device _device;
|
private readonly Device _device;
|
||||||
|
|
|
@ -86,7 +86,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
iter++;
|
iter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
DescriptorSetLayout[] layouts = new DescriptorSetLayout[PipelineFull.DescriptorSetLayouts];
|
DescriptorSetLayout[] layouts = new DescriptorSetLayout[PipelineBase.DescriptorSetLayouts];
|
||||||
|
|
||||||
var uDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo()
|
var uDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo()
|
||||||
{
|
{
|
||||||
|
@ -117,10 +117,10 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
BindingCount = (uint)iCount
|
BindingCount = (uint)iCount
|
||||||
};
|
};
|
||||||
|
|
||||||
gd.Api.CreateDescriptorSetLayout(device, uDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.UniformSetIndex]).ThrowOnError();
|
gd.Api.CreateDescriptorSetLayout(device, uDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.UniformSetIndex]).ThrowOnError();
|
||||||
gd.Api.CreateDescriptorSetLayout(device, sDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.StorageSetIndex]).ThrowOnError();
|
gd.Api.CreateDescriptorSetLayout(device, sDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.StorageSetIndex]).ThrowOnError();
|
||||||
gd.Api.CreateDescriptorSetLayout(device, tDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.TextureSetIndex]).ThrowOnError();
|
gd.Api.CreateDescriptorSetLayout(device, tDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.TextureSetIndex]).ThrowOnError();
|
||||||
gd.Api.CreateDescriptorSetLayout(device, iDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.ImageSetIndex]).ThrowOnError();
|
gd.Api.CreateDescriptorSetLayout(device, iDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.ImageSetIndex]).ThrowOnError();
|
||||||
|
|
||||||
fixed (DescriptorSetLayout* pLayouts = layouts)
|
fixed (DescriptorSetLayout* pLayouts = layouts)
|
||||||
{
|
{
|
||||||
|
@ -128,7 +128,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
SType = StructureType.PipelineLayoutCreateInfo,
|
SType = StructureType.PipelineLayoutCreateInfo,
|
||||||
PSetLayouts = pLayouts,
|
PSetLayouts = pLayouts,
|
||||||
SetLayoutCount = PipelineFull.DescriptorSetLayouts
|
SetLayoutCount = PipelineBase.DescriptorSetLayouts
|
||||||
};
|
};
|
||||||
|
|
||||||
gd.Api.CreatePipelineLayout(device, &pipelineLayoutCreateInfo, null, out layout).ThrowOnError();
|
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);
|
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()
|
var uDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo()
|
||||||
{
|
{
|
||||||
|
@ -221,10 +221,10 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
BindingCount = (uint)iCount
|
BindingCount = (uint)iCount
|
||||||
};
|
};
|
||||||
|
|
||||||
gd.Api.CreateDescriptorSetLayout(device, uDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.UniformSetIndex]).ThrowOnError();
|
gd.Api.CreateDescriptorSetLayout(device, uDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.UniformSetIndex]).ThrowOnError();
|
||||||
gd.Api.CreateDescriptorSetLayout(device, sDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.StorageSetIndex]).ThrowOnError();
|
gd.Api.CreateDescriptorSetLayout(device, sDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.StorageSetIndex]).ThrowOnError();
|
||||||
gd.Api.CreateDescriptorSetLayout(device, tDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.TextureSetIndex]).ThrowOnError();
|
gd.Api.CreateDescriptorSetLayout(device, tDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.TextureSetIndex]).ThrowOnError();
|
||||||
gd.Api.CreateDescriptorSetLayout(device, iDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.ImageSetIndex]).ThrowOnError();
|
gd.Api.CreateDescriptorSetLayout(device, iDescriptorSetLayoutCreateInfo, null, out layouts[PipelineBase.ImageSetIndex]).ThrowOnError();
|
||||||
|
|
||||||
fixed (DescriptorSetLayout* pLayouts = layouts)
|
fixed (DescriptorSetLayout* pLayouts = layouts)
|
||||||
{
|
{
|
||||||
|
@ -232,7 +232,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
SType = StructureType.PipelineLayoutCreateInfo,
|
SType = StructureType.PipelineLayoutCreateInfo,
|
||||||
PSetLayouts = pLayouts,
|
PSetLayouts = pLayouts,
|
||||||
SetLayoutCount = PipelineFull.DescriptorSetLayouts
|
SetLayoutCount = PipelineBase.DescriptorSetLayouts
|
||||||
};
|
};
|
||||||
|
|
||||||
gd.Api.CreatePipelineLayout(device, &pipelineLayoutCreateInfo, null, out layout).ThrowOnError();
|
gd.Api.CreatePipelineLayout(device, &pipelineLayoutCreateInfo, null, out layout).ThrowOnError();
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
|
@ -21,6 +21,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
ExtConditionalRendering.ExtensionName,
|
ExtConditionalRendering.ExtensionName,
|
||||||
ExtExtendedDynamicState.ExtensionName,
|
ExtExtendedDynamicState.ExtensionName,
|
||||||
|
ExtTransformFeedback.ExtensionName,
|
||||||
KhrDrawIndirectCount.ExtensionName,
|
KhrDrawIndirectCount.ExtensionName,
|
||||||
KhrPushDescriptor.ExtensionName,
|
KhrPushDescriptor.ExtensionName,
|
||||||
"VK_EXT_custom_border_color",
|
"VK_EXT_custom_border_color",
|
||||||
|
@ -36,8 +37,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
public static string[] RequiredExtensions { get; } = new string[]
|
public static string[] RequiredExtensions { get; } = new string[]
|
||||||
{
|
{
|
||||||
KhrSwapchain.ExtensionName,
|
KhrSwapchain.ExtensionName
|
||||||
ExtTransformFeedback.ExtensionName
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private static string[] _excludedMessages = new string[]
|
private static string[] _excludedMessages = new string[]
|
||||||
|
@ -382,12 +382,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
DepthClamp = true,
|
DepthClamp = true,
|
||||||
DualSrcBlend = true,
|
DualSrcBlend = true,
|
||||||
FragmentStoresAndAtomics = true,
|
FragmentStoresAndAtomics = true,
|
||||||
GeometryShader = true,
|
GeometryShader = supportedFeatures.GeometryShader,
|
||||||
ImageCubeArray = true,
|
ImageCubeArray = true,
|
||||||
IndependentBlend = true,
|
IndependentBlend = true,
|
||||||
LogicOp = true,
|
LogicOp = supportedFeatures.LogicOp,
|
||||||
MultiViewport = true,
|
MultiViewport = true,
|
||||||
PipelineStatisticsQuery = true,
|
PipelineStatisticsQuery = supportedFeatures.PipelineStatisticsQuery,
|
||||||
SamplerAnisotropy = true,
|
SamplerAnisotropy = true,
|
||||||
ShaderClipDistance = true,
|
ShaderClipDistance = true,
|
||||||
ShaderFloat64 = supportedFeatures.ShaderFloat64,
|
ShaderFloat64 = supportedFeatures.ShaderFloat64,
|
||||||
|
|
|
@ -39,13 +39,11 @@ namespace Ryujinx.HLE.FileSystem
|
||||||
{
|
{
|
||||||
public readonly string ContainerPath;
|
public readonly string ContainerPath;
|
||||||
public readonly string NcaPath;
|
public readonly string NcaPath;
|
||||||
public bool Enabled;
|
|
||||||
|
|
||||||
public AocItem(string containerPath, string ncaPath, bool enabled)
|
public AocItem(string containerPath, string ncaPath)
|
||||||
{
|
{
|
||||||
ContainerPath = containerPath;
|
ContainerPath = containerPath;
|
||||||
NcaPath = ncaPath;
|
NcaPath = ncaPath;
|
||||||
Enabled = enabled;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +51,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||||
|
|
||||||
private VirtualFileSystem _virtualFileSystem;
|
private VirtualFileSystem _virtualFileSystem;
|
||||||
|
|
||||||
private readonly object _lock = new object();
|
private readonly object _lock = new();
|
||||||
|
|
||||||
public ContentManager(VirtualFileSystem virtualFileSystem)
|
public ContentManager(VirtualFileSystem virtualFileSystem)
|
||||||
{
|
{
|
||||||
|
@ -226,27 +224,21 @@ namespace Ryujinx.HLE.FileSystem
|
||||||
pfs0.OpenFile(ref cnmtFile.Ref(), pfs0.EnumerateEntries().Single().FullPath.ToU8Span(), OpenMode.Read);
|
pfs0.OpenFile(ref cnmtFile.Ref(), pfs0.EnumerateEntries().Single().FullPath.ToU8Span(), OpenMode.Read);
|
||||||
|
|
||||||
var cnmt = new Cnmt(cnmtFile.Get.AsStream());
|
var cnmt = new Cnmt(cnmtFile.Get.AsStream());
|
||||||
|
|
||||||
if (cnmt.Type != ContentMetaType.AddOnContent || (cnmt.TitleId & 0xFFFFFFFFFFFFE000) != aocBaseId)
|
if (cnmt.Type != ContentMetaType.AddOnContent || (cnmt.TitleId & 0xFFFFFFFFFFFFE000) != aocBaseId)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
string ncaId = BitConverter.ToString(cnmt.ContentEntries[0].NcaId).Replace("-", "").ToLower();
|
string ncaId = BitConverter.ToString(cnmt.ContentEntries[0].NcaId).Replace("-", "").ToLower();
|
||||||
if (!_aocData.TryAdd(cnmt.TitleId, new AocItem(containerPath, $"{ncaId}.nca", true)))
|
|
||||||
{
|
AddAocItem(cnmt.TitleId, 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}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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}");
|
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}");
|
Logger.Info?.Print(LogClass.Application, $"Found AddOnContent with TitleId {titleId:X16}");
|
||||||
|
|
||||||
using (FileStream fileStream = File.OpenRead(containerPath))
|
if (!mergedToContainer)
|
||||||
using (PartitionFileSystem pfs = new PartitionFileSystem(fileStream.AsStorage()))
|
|
||||||
{
|
{
|
||||||
_virtualFileSystem.ImportTickets(pfs);
|
using FileStream fileStream = File.OpenRead(containerPath);
|
||||||
|
using PartitionFileSystem partitionFileSystem = new(fileStream.AsStorage());
|
||||||
|
|
||||||
|
_virtualFileSystem.ImportTickets(partitionFileSystem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearAocData() => _aocData.Clear();
|
public void ClearAocData() => _aocData.Clear();
|
||||||
|
|
||||||
public int GetAocCount() => _aocData.Where(e => e.Value.Enabled).Count();
|
public int GetAocCount() => _aocData.Count;
|
||||||
|
|
||||||
public IList<ulong> GetAocTitleIds() => _aocData.Where(e => e.Value.Enabled).Select(e => e.Key).ToList();
|
public IList<ulong> GetAocTitleIds() => _aocData.Select(e => e.Key).ToList();
|
||||||
|
|
||||||
public bool GetAocDataStorage(ulong aocTitleId, out IStorage aocStorage, IntegrityCheckLevel integrityCheckLevel)
|
public bool GetAocDataStorage(ulong aocTitleId, out IStorage aocStorage, IntegrityCheckLevel integrityCheckLevel)
|
||||||
{
|
{
|
||||||
aocStorage = null;
|
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);
|
var file = new FileStream(aoc.ContainerPath, FileMode.Open, FileAccess.Read);
|
||||||
using var ncaFile = new UniqueRef<IFile>();
|
using var ncaFile = new UniqueRef<IFile>();
|
||||||
|
|
|
@ -47,7 +47,7 @@ namespace Ryujinx.HLE.HOS.Applets.Error
|
||||||
|
|
||||||
_errorStorage = _normalSession.Pop();
|
_errorStorage = _normalSession.Pop();
|
||||||
_errorCommonHeader = IApplet.ReadStruct<ErrorCommonHeader>(_errorStorage);
|
_errorCommonHeader = IApplet.ReadStruct<ErrorCommonHeader>(_errorStorage);
|
||||||
_errorStorage = _errorStorage.Skip(Marshal.SizeOf(typeof(ErrorCommonHeader))).ToArray();
|
_errorStorage = _errorStorage.Skip(Marshal.SizeOf<ErrorCommonHeader>()).ToArray();
|
||||||
|
|
||||||
switch (_errorCommonHeader.Type)
|
switch (_errorCommonHeader.Type)
|
||||||
{
|
{
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 52 KiB |
|
@ -9,6 +9,7 @@ using Ryujinx.HLE.Ui.Input;
|
||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
@ -797,7 +798,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static T ReadStruct<T>(byte[] data)
|
private static T ReadStruct<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] T>(byte[] data)
|
||||||
where T : struct
|
where T : struct
|
||||||
{
|
{
|
||||||
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||||
|
|
|
@ -11,7 +11,6 @@ using System.Numerics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using SixLabors.ImageSharp.PixelFormats;
|
using SixLabors.ImageSharp.PixelFormats;
|
||||||
using Ryujinx.Common;
|
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||||
{
|
{
|
||||||
|
@ -68,8 +67,8 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||||
{
|
{
|
||||||
int ryujinxLogoSize = 32;
|
int ryujinxLogoSize = 32;
|
||||||
|
|
||||||
Stream logoStream = EmbeddedResources.GetStream("Ryujinx.Ui.Common/Resources/Logo_Ryujinx.png");
|
string ryujinxIconPath = "Ryujinx.HLE.HOS.Applets.SoftwareKeyboard.Resources.Logo_Ryujinx.png";
|
||||||
_ryujinxLogo = LoadResource(logoStream, ryujinxLogoSize, ryujinxLogoSize);
|
_ryujinxLogo = LoadResource(Assembly.GetExecutingAssembly(), ryujinxIconPath, ryujinxLogoSize, ryujinxLogoSize);
|
||||||
|
|
||||||
string padAcceptIconPath = "Ryujinx.HLE.HOS.Applets.SoftwareKeyboard.Resources.Icon_BtnA.png";
|
string padAcceptIconPath = "Ryujinx.HLE.HOS.Applets.SoftwareKeyboard.Resources.Icon_BtnA.png";
|
||||||
string padCancelIconPath = "Ryujinx.HLE.HOS.Applets.SoftwareKeyboard.Resources.Icon_BtnB.png";
|
string padCancelIconPath = "Ryujinx.HLE.HOS.Applets.SoftwareKeyboard.Resources.Icon_BtnB.png";
|
||||||
|
@ -117,7 +116,8 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||||
uiThemeFontFamily,
|
uiThemeFontFamily,
|
||||||
"Liberation Sans",
|
"Liberation Sans",
|
||||||
"FreeSans",
|
"FreeSans",
|
||||||
"DejaVu Sans"
|
"DejaVu Sans",
|
||||||
|
"Lucida Grande"
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (string fontFamily in availableFonts)
|
foreach (string fontFamily in availableFonts)
|
||||||
|
|
|
@ -426,9 +426,9 @@ namespace Ryujinx.HLE.HOS
|
||||||
{
|
{
|
||||||
foreach (DownloadableContentNca downloadableContentNca in downloadableContentContainer.DownloadableContentNcaList)
|
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
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Cpu;
|
using Ryujinx.Cpu;
|
||||||
|
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||||
using Ryujinx.HLE.HOS.Services.Account.Acc.AccountService;
|
using Ryujinx.HLE.HOS.Services.Account.Acc.AccountService;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Account.Acc.AsyncContext;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||||
{
|
{
|
||||||
|
@ -142,6 +146,28 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||||
return ResultCode.Success;
|
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)
|
public ResultCode StoreSaveDataThumbnail(ServiceCtx context)
|
||||||
{
|
{
|
||||||
ResultCode resultCode = CheckUserId(context, out UserId _);
|
ResultCode resultCode = CheckUserId(context, out UserId _);
|
||||||
|
|
|
@ -124,6 +124,20 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[CommandHipc(103)] // 4.0.0+
|
||||||
|
// CheckNetworkServiceAvailabilityAsync() -> object<nn::account::detail::IAsyncContext>
|
||||||
|
public ResultCode CheckNetworkServiceAvailabilityAsync(ServiceCtx context)
|
||||||
|
{
|
||||||
|
ResultCode resultCode = _applicationServiceServer.CheckNetworkServiceAvailabilityAsync(context, out IAsyncContext asyncContext);
|
||||||
|
|
||||||
|
if (resultCode == ResultCode.Success)
|
||||||
|
{
|
||||||
|
MakeObject(context, asyncContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultCode;
|
||||||
|
}
|
||||||
|
|
||||||
[CommandHipc(110)]
|
[CommandHipc(110)]
|
||||||
// StoreSaveDataThumbnail(nn::account::Uid, buffer<bytes, 5>)
|
// StoreSaveDataThumbnail(nn::account::Uid, buffer<bytes, 5>)
|
||||||
public ResultCode StoreSaveDataThumbnail(ServiceCtx context)
|
public ResultCode StoreSaveDataThumbnail(ServiceCtx context)
|
||||||
|
|
|
@ -157,7 +157,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
|
||||||
int supportedLanguages = (int)context.Device.Application.ControlData.Value.SupportedLanguageFlag;
|
int supportedLanguages = (int)context.Device.Application.ControlData.Value.SupportedLanguageFlag;
|
||||||
int firstSupported = BitOperations.TrailingZeroCount(supportedLanguages);
|
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");
|
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
|
// TODO: In the future, a GUI could enable user-specified search priority
|
||||||
if (((1 << (int)context.Device.System.State.DesiredTitleLanguage) & supportedLanguages) == 0)
|
if (((1 << (int)context.Device.System.State.DesiredTitleLanguage) & supportedLanguages) == 0)
|
||||||
{
|
{
|
||||||
SystemLanguage newLanguage = Enum.Parse<SystemLanguage>(Enum.GetName(typeof(SystemState.TitleLanguage), firstSupported));
|
SystemLanguage newLanguage = Enum.Parse<SystemLanguage>(Enum.GetName(typeof(TitleLanguage), firstSupported));
|
||||||
desiredLanguageCode = SystemStateMgr.GetLanguageCode((int)newLanguage);
|
desiredLanguageCode = SystemStateMgr.GetLanguageCode((int)newLanguage);
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.ServiceAm, $"Application doesn't support configured language. Using {newLanguage}");
|
Logger.Info?.Print(LogClass.ServiceAm, $"Application doesn't support configured language. Using {newLanguage}");
|
||||||
|
|
|
@ -901,7 +901,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
|
||||||
[CommandHipc(606)]
|
[CommandHipc(606)]
|
||||||
public ResultCode GetRightsId(ServiceCtx context)
|
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<ProgramId>();
|
ProgramId programId = context.RequestData.ReadStruct<ProgramId>();
|
||||||
|
|
||||||
Result result = _baseFileSystemProxy.Get.GetRightsId(out RightsId rightsId, programId, storageId);
|
Result result = _baseFileSystemProxy.Get.GetRightsId(out RightsId rightsId, programId, storageId);
|
||||||
|
|
|
@ -589,9 +589,9 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
||||||
|
|
||||||
ulong outputPosition = context.Request.RecvListBuff[0].Position;
|
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<TagInfo>());
|
||||||
|
|
||||||
MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf(typeof(TagInfo)));
|
MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf<TagInfo>());
|
||||||
|
|
||||||
uint deviceHandle = (uint)context.RequestData.ReadUInt64();
|
uint deviceHandle = (uint)context.RequestData.ReadUInt64();
|
||||||
|
|
||||||
|
@ -665,9 +665,9 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
||||||
|
|
||||||
ulong outputPosition = context.Request.RecvListBuff[0].Position;
|
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<RegisterInfo>());
|
||||||
|
|
||||||
MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf(typeof(RegisterInfo)));
|
MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf<RegisterInfo>());
|
||||||
|
|
||||||
uint deviceHandle = (uint)context.RequestData.ReadUInt64();
|
uint deviceHandle = (uint)context.RequestData.ReadUInt64();
|
||||||
|
|
||||||
|
@ -728,9 +728,9 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
||||||
|
|
||||||
ulong outputPosition = context.Request.RecvListBuff[0].Position;
|
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<CommonInfo>());
|
||||||
|
|
||||||
MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf(typeof(CommonInfo)));
|
MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf<CommonInfo>());
|
||||||
|
|
||||||
uint deviceHandle = (uint)context.RequestData.ReadUInt64();
|
uint deviceHandle = (uint)context.RequestData.ReadUInt64();
|
||||||
|
|
||||||
|
@ -788,9 +788,9 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
||||||
|
|
||||||
ulong outputPosition = context.Request.RecvListBuff[0].Position;
|
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<ModelInfo>());
|
||||||
|
|
||||||
MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf(typeof(ModelInfo)));
|
MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf<ModelInfo>());
|
||||||
|
|
||||||
uint deviceHandle = (uint)context.RequestData.ReadUInt64();
|
uint deviceHandle = (uint)context.RequestData.ReadUInt64();
|
||||||
|
|
||||||
|
|
|
@ -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.Collections.Generic;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
||||||
{
|
{
|
||||||
|
@ -41,6 +44,27 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<IFileDescriptor> RetrieveFileDescriptorsFromMask(ReadOnlySpan<byte> mask)
|
||||||
|
{
|
||||||
|
List<IFileDescriptor> 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)
|
public int RegisterFileDescriptor(IFileDescriptor file)
|
||||||
{
|
{
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
|
@ -61,6 +85,16 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void BuildMask(List<IFileDescriptor> fds, Span<byte> mask)
|
||||||
|
{
|
||||||
|
foreach (IFileDescriptor descriptor in fds)
|
||||||
|
{
|
||||||
|
int fd = _fds.IndexOf(descriptor);
|
||||||
|
|
||||||
|
mask[fd >> 3] |= (byte)(1 << (fd & 7));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public int DuplicateFileDescriptor(int fd)
|
public int DuplicateFileDescriptor(int fd)
|
||||||
{
|
{
|
||||||
IFileDescriptor oldFile = RetrieveFileDescriptor(fd);
|
IFileDescriptor oldFile = RetrieveFileDescriptor(fd);
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
|
||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
|
@ -202,12 +205,122 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
||||||
}
|
}
|
||||||
|
|
||||||
[CommandHipc(5)]
|
[CommandHipc(5)]
|
||||||
// Select(u32 nfds, nn::socket::timeout timeout, buffer<nn::socket::fd_set, 0x21, 0> readfds_in, buffer<nn::socket::fd_set, 0x21, 0> writefds_in, buffer<nn::socket::fd_set, 0x21, 0> errorfds_in) -> (i32 ret, u32 bsd_errno, buffer<nn::socket::fd_set, 0x22, 0> readfds_out, buffer<nn::socket::fd_set, 0x22, 0> writefds_out, buffer<nn::socket::fd_set, 0x22, 0> errorfds_out)
|
// Select(u32 nfds, nn::socket::timeval timeout, buffer<nn::socket::fd_set, 0x21, 0> readfds_in, buffer<nn::socket::fd_set, 0x21, 0> writefds_in, buffer<nn::socket::fd_set, 0x21, 0> errorfds_in)
|
||||||
|
// -> (i32 ret, u32 bsd_errno, buffer<nn::socket::fd_set, 0x22, 0> readfds_out, buffer<nn::socket::fd_set, 0x22, 0> writefds_out, buffer<nn::socket::fd_set, 0x22, 0> errorfds_out)
|
||||||
public ResultCode Select(ServiceCtx context)
|
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<IFileDescriptor> readFds = _context.RetrieveFileDescriptorsFromMask(context.Memory.GetSpan(readFdsInBufferPosition, (int)readFdsInBufferSize));
|
||||||
|
List<IFileDescriptor> writeFds = _context.RetrieveFileDescriptorsFromMask(context.Memory.GetSpan(writeFdsInBufferPosition, (int)writeFdsInBufferSize));
|
||||||
|
List<IFileDescriptor> 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<PollEvent>[] eventsByPollManager = new List<PollEvent>[_pollManagers.Count];
|
||||||
|
|
||||||
|
for (int i = 0; i < eventsByPollManager.Length; i++)
|
||||||
|
{
|
||||||
|
eventsByPollManager[i] = new List<PollEvent>();
|
||||||
|
|
||||||
|
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;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
@ -320,14 +433,14 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
||||||
break;
|
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);
|
context.Device.System.KernelContext.Syscall.SleepThread(50 * 1000000);
|
||||||
}
|
}
|
||||||
while (PerformanceCounter.ElapsedMilliseconds < budgetLeftMilliseconds);
|
while (PerformanceCounter.ElapsedMilliseconds < budgetLeftMilliseconds);
|
||||||
}
|
}
|
||||||
else if (timeout == -1)
|
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();
|
throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
|
||||||
|
using System;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
using System;
|
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
|
||||||
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||||
{
|
{
|
||||||
class EventFileDescriptor : IFileDescriptor
|
class EventFileDescriptor : IFileDescriptor
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||||
{
|
{
|
||||||
class EventFileDescriptorPollManager : IPollManager
|
class EventFileDescriptorPollManager : IPollManager
|
||||||
{
|
{
|
||||||
|
@ -109,5 +110,13 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
||||||
|
|
||||||
return LinuxError.SUCCESS;
|
return LinuxError.SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LinuxError Select(List<PollEvent> events, int timeout, out int updatedCount)
|
||||||
|
{
|
||||||
|
// TODO: Implement Select for event file descriptors
|
||||||
|
updatedCount = 0;
|
||||||
|
|
||||||
|
return LinuxError.EOPNOTSUPP;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
@ -6,7 +7,7 @@ using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||||
{
|
{
|
||||||
class ManagedSocket : ISocket
|
class ManagedSocket : ISocket
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||||
{
|
{
|
||||||
class ManagedSocketPollManager : IPollManager
|
class ManagedSocketPollManager : IPollManager
|
||||||
{
|
{
|
||||||
|
@ -117,5 +118,60 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
||||||
|
|
||||||
return LinuxError.SUCCESS;
|
return LinuxError.SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LinuxError Select(List<PollEvent> events, int timeout, out int updatedCount)
|
||||||
|
{
|
||||||
|
List<Socket> readEvents = new();
|
||||||
|
List<Socket> writeEvents = new();
|
||||||
|
List<Socket> 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||||
{
|
{
|
||||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||||
enum WsaError
|
enum WsaError
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue