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