Revert the Metal Experiment #701
@ -3,13 +3,13 @@
|
||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageVersion Include="Avalonia" Version="11.0.10" />
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.0.10" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="11.0.10" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.0.10" />
|
||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.0.10" />
|
||||
<PackageVersion Include="Avalonia.Svg" Version="11.0.0.18" />
|
||||
<PackageVersion Include="Avalonia.Svg.Skia" Version="11.0.0.18" />
|
||||
<PackageVersion Include="Avalonia" Version="11.0.13" />
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.0.13" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="11.0.13" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.0.13" />
|
||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.0.13" />
|
||||
<PackageVersion Include="Avalonia.Svg" Version="11.0.0.19" />
|
||||
<PackageVersion Include="Avalonia.Svg.Skia" Version="11.0.0.19" />
|
||||
<PackageVersion Include="Microsoft.Build.Framework" Version="17.11.4" />
|
||||
<PackageVersion Include="Microsoft.Build.Utilities.Core" Version="17.12.6" />
|
||||
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
@ -17,7 +17,8 @@
|
||||
<PackageVersion Include="Projektanker.Icons.Avalonia.FontAwesome" Version="9.4.0"/>
|
||||
<PackageVersion Include="Projektanker.Icons.Avalonia.MaterialDesign" Version="9.4.0"/>
|
||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
||||
<PackageVersion Include="Concentus" Version="2.2.0" />
|
||||
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0"/>
|
||||
<PackageVersion Include="Concentus" Version="2.2.2" />
|
||||
<PackageVersion Include="DiscordRichPresence" Version="1.2.1.24" />
|
||||
<PackageVersion Include="DynamicData" Version="9.0.4" />
|
||||
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.5" />
|
||||
@ -25,7 +26,7 @@
|
||||
<PackageVersion Include="LibHac" Version="0.19.0" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
|
||||
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.1.2" />
|
||||
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.3.0" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
|
||||
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
||||
@ -41,15 +42,16 @@
|
||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.3-build14" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
||||
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.30.0-build32" />
|
||||
<PackageVersion Include="Gommon" Version="2.6.8" />
|
||||
<PackageVersion Include="Gommon" Version="2.7.1.1" />
|
||||
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
||||
<PackageVersion Include="Sep" Version="0.6.0" />
|
||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.21.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.21.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.21.0" />
|
||||
<PackageVersion Include="SkiaSharp" Version="2.88.7" />
|
||||
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.7" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.22.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.22.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.22.0" />
|
||||
<PackageVersion Include="SkiaSharp" Version="2.88.9" />
|
||||
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.9" />
|
||||
<PackageVersion Include="SPB" Version="0.0.4-build32" />
|
||||
<PackageVersion Include="System.IO.Hashing" Version="9.0.0" />
|
||||
<PackageVersion Include="System.Management" Version="9.0.0" />
|
||||
|
@ -57,14 +57,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.SDL2.Common", "src\
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.SDL2", "src\Ryujinx.Audio.Backends.SDL2\Ryujinx.Audio.Backends.SDL2.csproj", "{D99A395A-8569-4DB0-B336-900647890052}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Headless.SDL2", "src\Ryujinx.Headless.SDL2\Ryujinx.Headless.SDL2.csproj", "{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.FFmpeg", "src\Ryujinx.Graphics.Nvdec.FFmpeg\Ryujinx.Graphics.Nvdec.FFmpeg.csproj", "{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx", "src\Ryujinx\Ryujinx.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.UI.Common", "src\Ryujinx.UI.Common\Ryujinx.UI.Common.csproj", "{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Generators", "src\Ryujinx.Horizon.Generators\Ryujinx.Horizon.Generators.csproj", "{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Vulkan", "src\Ryujinx.Graphics.Vulkan\Ryujinx.Graphics.Vulkan.csproj", "{D4D09B08-D580-4D69-B886-C35D2853F6C8}"
|
||||
@ -206,10 +202,6 @@ Global
|
||||
{D99A395A-8569-4DB0-B336-900647890052}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
@ -3,6 +3,7 @@ using Avalonia.Controls;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Threading;
|
||||
using DiscordRPC;
|
||||
using LibHac.Common;
|
||||
using LibHac.Ns;
|
||||
using LibHac.Tools.FsSystem;
|
||||
@ -19,11 +20,15 @@ using Ryujinx.Ava.UI.Models;
|
||||
using Ryujinx.Ava.UI.Renderer;
|
||||
using Ryujinx.Ava.UI.ViewModels;
|
||||
using Ryujinx.Ava.UI.Windows;
|
||||
using Ryujinx.Ava.Utilities;
|
||||
using Ryujinx.Ava.Utilities.AppLibrary;
|
||||
using Ryujinx.Ava.Utilities.Configuration;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Configuration.Multiplayer;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.SystemInterop;
|
||||
using Ryujinx.Common.UI;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.GAL.Multithreading;
|
||||
@ -37,11 +42,6 @@ using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using Ryujinx.HLE.HOS.SystemState;
|
||||
using Ryujinx.Input;
|
||||
using Ryujinx.Input.HLE;
|
||||
using Ryujinx.UI.App.Common;
|
||||
using Ryujinx.UI.Common;
|
||||
using Ryujinx.UI.Common.Configuration;
|
||||
using Ryujinx.UI.Common.Helper;
|
||||
using Silk.NET.Vulkan;
|
||||
using SkiaSharp;
|
||||
using SPB.Graphics.Vulkan;
|
||||
using System;
|
||||
@ -238,10 +238,10 @@ namespace Ryujinx.Ava
|
||||
_lastCursorMoveTime = Stopwatch.GetTimestamp();
|
||||
}
|
||||
|
||||
var point = e.GetCurrentPoint(window).Position;
|
||||
var bounds = RendererHost.EmbeddedWindow.Bounds;
|
||||
var windowYOffset = bounds.Y + window.MenuBarHeight;
|
||||
var windowYLimit = (int)window.Bounds.Height - window.StatusBarHeight - 1;
|
||||
Point point = e.GetCurrentPoint(window).Position;
|
||||
Rect bounds = RendererHost.EmbeddedWindow.Bounds;
|
||||
double windowYOffset = bounds.Y + window.MenuBarHeight;
|
||||
double windowYLimit = (int)window.Bounds.Height - window.StatusBarHeight - 1;
|
||||
|
||||
if (!_viewModel.ShowMenuAndStatusBar)
|
||||
{
|
||||
@ -265,10 +265,10 @@ namespace Ryujinx.Ava
|
||||
|
||||
if (sender is MainWindow window)
|
||||
{
|
||||
var point = e.GetCurrentPoint(window).Position;
|
||||
var bounds = RendererHost.EmbeddedWindow.Bounds;
|
||||
var windowYOffset = bounds.Y + window.MenuBarHeight;
|
||||
var windowYLimit = (int)window.Bounds.Height - window.StatusBarHeight - 1;
|
||||
Point point = e.GetCurrentPoint(window).Position;
|
||||
Rect bounds = RendererHost.EmbeddedWindow.Bounds;
|
||||
double windowYOffset = bounds.Y + window.MenuBarHeight;
|
||||
double windowYLimit = (int)window.Bounds.Height - window.StatusBarHeight - 1;
|
||||
|
||||
if (!_viewModel.ShowMenuAndStatusBar)
|
||||
{
|
||||
@ -287,19 +287,19 @@ namespace Ryujinx.Ava
|
||||
|
||||
private void UpdateScalingFilterLevel(object sender, ReactiveEventArgs<int> e)
|
||||
{
|
||||
_renderer.Window?.SetScalingFilter((Graphics.GAL.ScalingFilter)ConfigurationState.Instance.Graphics.ScalingFilter.Value);
|
||||
_renderer.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value);
|
||||
_renderer.Window?.SetScalingFilter(ConfigurationState.Instance.Graphics.ScalingFilter);
|
||||
_renderer.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel);
|
||||
}
|
||||
|
||||
private void UpdateScalingFilter(object sender, ReactiveEventArgs<ScalingFilter> e)
|
||||
{
|
||||
_renderer.Window?.SetScalingFilter((Graphics.GAL.ScalingFilter)ConfigurationState.Instance.Graphics.ScalingFilter.Value);
|
||||
_renderer.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value);
|
||||
_renderer.Window?.SetScalingFilter(ConfigurationState.Instance.Graphics.ScalingFilter);
|
||||
_renderer.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel);
|
||||
}
|
||||
|
||||
private void UpdateColorSpacePassthrough(object sender, ReactiveEventArgs<bool> e)
|
||||
{
|
||||
_renderer.Window?.SetColorSpacePassthrough((bool)ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Value);
|
||||
_renderer.Window?.SetColorSpacePassthrough(ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough);
|
||||
}
|
||||
|
||||
public void UpdateVSyncMode(object sender, ReactiveEventArgs<VSyncMode> e)
|
||||
@ -309,39 +309,21 @@ namespace Ryujinx.Ava
|
||||
Device.VSyncMode = e.NewValue;
|
||||
Device.UpdateVSyncInterval();
|
||||
}
|
||||
_renderer.Window?.ChangeVSyncMode((Ryujinx.Graphics.GAL.VSyncMode)e.NewValue);
|
||||
|
||||
_renderer.Window?.ChangeVSyncMode(e.NewValue);
|
||||
|
||||
_viewModel.ShowCustomVSyncIntervalPicker = (e.NewValue == VSyncMode.Custom);
|
||||
_viewModel.UpdateVSyncIntervalPicker();
|
||||
}
|
||||
|
||||
public void VSyncModeToggle()
|
||||
{
|
||||
VSyncMode oldVSyncMode = Device.VSyncMode;
|
||||
VSyncMode newVSyncMode = VSyncMode.Switch;
|
||||
bool customVSyncIntervalEnabled = ConfigurationState.Instance.Graphics.EnableCustomVSyncInterval.Value;
|
||||
|
||||
switch (oldVSyncMode)
|
||||
{
|
||||
case VSyncMode.Switch:
|
||||
newVSyncMode = VSyncMode.Unbounded;
|
||||
break;
|
||||
case VSyncMode.Unbounded:
|
||||
if (customVSyncIntervalEnabled)
|
||||
{
|
||||
newVSyncMode = VSyncMode.Custom;
|
||||
}
|
||||
else
|
||||
{
|
||||
newVSyncMode = VSyncMode.Switch;
|
||||
}
|
||||
|
||||
break;
|
||||
case VSyncMode.Custom:
|
||||
newVSyncMode = VSyncMode.Switch;
|
||||
break;
|
||||
}
|
||||
|
||||
UpdateVSyncMode(this, new ReactiveEventArgs<VSyncMode>(oldVSyncMode, newVSyncMode));
|
||||
UpdateVSyncMode(this, new ReactiveEventArgs<VSyncMode>(
|
||||
oldVSyncMode,
|
||||
oldVSyncMode.Next(customVSyncIntervalEnabled))
|
||||
);
|
||||
}
|
||||
|
||||
private void UpdateCustomVSyncIntervalValue(object sender, ReactiveEventArgs<int> e)
|
||||
@ -434,7 +416,7 @@ namespace Ryujinx.Ava
|
||||
return;
|
||||
}
|
||||
|
||||
var colorType = e.IsBgra ? SKColorType.Bgra8888 : SKColorType.Rgba8888;
|
||||
SKColorType colorType = e.IsBgra ? SKColorType.Bgra8888 : SKColorType.Rgba8888;
|
||||
using SKBitmap bitmap = new(new SKImageInfo(e.Width, e.Height, colorType, SKAlphaType.Premul));
|
||||
|
||||
Marshal.Copy(e.Data, 0, bitmap.GetPixels(), e.Data.Length);
|
||||
@ -447,7 +429,7 @@ namespace Ryujinx.Ava
|
||||
float scaleX = e.FlipX ? -1 : 1;
|
||||
float scaleY = e.FlipY ? -1 : 1;
|
||||
|
||||
var matrix = SKMatrix.CreateScale(scaleX, scaleY, bitmap.Width / 2f, bitmap.Height / 2f);
|
||||
SKMatrix matrix = SKMatrix.CreateScale(scaleX, scaleY, bitmap.Width / 2f, bitmap.Height / 2f);
|
||||
|
||||
canvas.SetMatrix(matrix);
|
||||
canvas.DrawBitmap(bitmap, SKPoint.Empty);
|
||||
@ -466,8 +448,8 @@ namespace Ryujinx.Ava
|
||||
|
||||
private static void SaveBitmapAsPng(SKBitmap bitmap, string path)
|
||||
{
|
||||
using var data = bitmap.Encode(SKEncodedImageFormat.Png, 100);
|
||||
using var stream = File.OpenWrite(path);
|
||||
using SKData data = bitmap.Encode(SKEncodedImageFormat.Png, 100);
|
||||
using FileStream stream = File.OpenWrite(path);
|
||||
|
||||
data.SaveTo(stream);
|
||||
}
|
||||
@ -488,7 +470,7 @@ namespace Ryujinx.Ava
|
||||
|
||||
Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device.Processes.ActiveApplication, Program.Version);
|
||||
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device.Processes.ActiveApplication, Program.Version, !ConfigurationState.Instance.ShowTitleBar);
|
||||
});
|
||||
|
||||
_viewModel.SetUiProgressHandlers(Device);
|
||||
@ -500,6 +482,8 @@ namespace Ryujinx.Ava
|
||||
_renderingThread.Start();
|
||||
|
||||
_viewModel.Volume = ConfigurationState.Instance.System.AudioVolume.Value;
|
||||
|
||||
Rainbow.Enable();
|
||||
|
||||
MainLoop();
|
||||
|
||||
@ -524,7 +508,7 @@ namespace Ryujinx.Ava
|
||||
|
||||
private void UpdateAntiAliasing(object sender, ReactiveEventArgs<AntiAliasing> e)
|
||||
{
|
||||
_renderer?.Window?.SetAntiAliasing((Graphics.GAL.AntiAliasing)e.NewValue);
|
||||
_renderer?.Window?.SetAntiAliasing(e.NewValue);
|
||||
}
|
||||
|
||||
private void UpdateDockedModeState(object sender, ReactiveEventArgs<bool> e)
|
||||
@ -532,7 +516,7 @@ namespace Ryujinx.Ava
|
||||
Device?.System.ChangeDockedModeState(e.NewValue);
|
||||
}
|
||||
|
||||
private void UpdateAudioVolumeState(object sender, ReactiveEventArgs<float> e)
|
||||
public void UpdateAudioVolumeState(object sender, ReactiveEventArgs<float> e)
|
||||
{
|
||||
Device?.SetVolume(e.NewValue);
|
||||
|
||||
@ -575,7 +559,6 @@ namespace Ryujinx.Ava
|
||||
public void Stop()
|
||||
{
|
||||
_isActive = false;
|
||||
DiscordIntegrationModule.SwitchToMainState();
|
||||
}
|
||||
|
||||
private void Exit()
|
||||
@ -587,6 +570,17 @@ namespace Ryujinx.Ava
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (IGamepad gamepad in RyujinxApp.MainWindow.InputManager.GamepadDriver.GetGamepads())
|
||||
{
|
||||
gamepad?.ClearLed();
|
||||
gamepad?.Dispose();
|
||||
}
|
||||
|
||||
DiscordIntegrationModule.GuestAppStartedAt = null;
|
||||
|
||||
Rainbow.Disable();
|
||||
Rainbow.Reset();
|
||||
|
||||
_isStopped = true;
|
||||
Stop();
|
||||
}
|
||||
@ -674,7 +668,9 @@ namespace Ryujinx.Ava
|
||||
|
||||
public async Task<bool> LoadGuestApplication(BlitStruct<ApplicationControlProperty>? customNacpData = null)
|
||||
{
|
||||
InitializeSwitchInstance();
|
||||
DiscordIntegrationModule.GuestAppStartedAt = Timestamps.Now;
|
||||
|
||||
InitEmulatedSwitch();
|
||||
MainWindow.UpdateGraphicsConfig();
|
||||
|
||||
SystemVersion firmwareVersion = ContentManager.GetCurrentFirmwareVersion();
|
||||
@ -757,6 +753,8 @@ namespace Ryujinx.Ava
|
||||
{
|
||||
romFsFiles = Directory.GetFiles(ApplicationPath, "*.romfs");
|
||||
}
|
||||
|
||||
Logger.Notice.Print(LogClass.Application, $"Loading unpacked content archive from '{ApplicationPath}'.");
|
||||
|
||||
if (romFsFiles.Length > 0)
|
||||
{
|
||||
@ -783,6 +781,8 @@ namespace Ryujinx.Ava
|
||||
}
|
||||
else if (File.Exists(ApplicationPath))
|
||||
{
|
||||
Logger.Notice.Print(LogClass.Application, $"Loading content archive from '{ApplicationPath}'.");
|
||||
|
||||
switch (Path.GetExtension(ApplicationPath).ToLowerInvariant())
|
||||
{
|
||||
case ".xci":
|
||||
@ -859,13 +859,11 @@ namespace Ryujinx.Ava
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ApplicationMetadata appMeta = ApplicationLibrary.LoadAndSaveMetaData(Device.Processes.ActiveApplication.ProgramIdText,
|
||||
|
||||
ApplicationLibrary.LoadAndSaveMetaData(Device.Processes.ActiveApplication.ProgramIdText,
|
||||
appMetadata => appMetadata.UpdatePreGame()
|
||||
);
|
||||
|
||||
DiscordIntegrationModule.SwitchToPlayingState(appMeta, Device.Processes.ActiveApplication);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -874,7 +872,7 @@ namespace Ryujinx.Ava
|
||||
Device?.System.TogglePauseEmulation(false);
|
||||
|
||||
_viewModel.IsPaused = false;
|
||||
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device?.Processes.ActiveApplication, Program.Version);
|
||||
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device?.Processes.ActiveApplication, Program.Version, !ConfigurationState.Instance.ShowTitleBar);
|
||||
Logger.Info?.Print(LogClass.Emulation, "Emulation was resumed");
|
||||
}
|
||||
|
||||
@ -883,26 +881,30 @@ namespace Ryujinx.Ava
|
||||
Device?.System.TogglePauseEmulation(true);
|
||||
|
||||
_viewModel.IsPaused = true;
|
||||
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device?.Processes.ActiveApplication, Program.Version, LocaleManager.Instance[LocaleKeys.Paused]);
|
||||
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device?.Processes.ActiveApplication, Program.Version, !ConfigurationState.Instance.ShowTitleBar, LocaleManager.Instance[LocaleKeys.Paused]);
|
||||
Logger.Info?.Print(LogClass.Emulation, "Emulation was paused");
|
||||
}
|
||||
|
||||
private void InitializeSwitchInstance()
|
||||
private void InitEmulatedSwitch()
|
||||
{
|
||||
// Initialize KeySet.
|
||||
VirtualFileSystem.ReloadKeySet();
|
||||
|
||||
// Initialize Renderer.
|
||||
IRenderer renderer = ConfigurationState.Instance.Graphics.GraphicsBackend.Value == GraphicsBackend.OpenGl
|
||||
? new OpenGLRenderer()
|
||||
: VulkanRenderer.Create(
|
||||
GraphicsBackend backend = TitleIDs.SelectGraphicsBackend(ApplicationId.ToString("X16"), ConfigurationState.Instance.Graphics.GraphicsBackend);
|
||||
|
||||
IRenderer renderer = backend switch
|
||||
{
|
||||
GraphicsBackend.Vulkan => VulkanRenderer.Create(
|
||||
ConfigurationState.Instance.Graphics.PreferredGpu,
|
||||
(RendererHost.EmbeddedWindow as EmbeddedWindowVulkan)!.CreateSurface,
|
||||
VulkanHelper.GetRequiredInstanceExtensions);
|
||||
VulkanHelper.GetRequiredInstanceExtensions),
|
||||
_ => new OpenGLRenderer()
|
||||
};
|
||||
|
||||
BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading;
|
||||
|
||||
var isGALThreaded = threadingMode == BackendThreading.On || (threadingMode == BackendThreading.Auto && renderer.PreferThreading);
|
||||
bool isGALThreaded = threadingMode == BackendThreading.On || (threadingMode == BackendThreading.Auto && renderer.PreferThreading);
|
||||
if (isGALThreaded)
|
||||
{
|
||||
renderer = new ThreadedRenderer(renderer);
|
||||
@ -911,9 +913,9 @@ namespace Ryujinx.Ava
|
||||
Logger.Info?.PrintMsg(LogClass.Gpu, $"Backend Threading ({threadingMode}): {isGALThreaded}");
|
||||
|
||||
// Initialize Configuration.
|
||||
var memoryConfiguration = ConfigurationState.Instance.System.DramSize.Value;
|
||||
MemoryConfiguration memoryConfiguration = ConfigurationState.Instance.System.DramSize.Value;
|
||||
|
||||
Device = new HLE.Switch(new HLEConfiguration(
|
||||
Device = new Switch(new HLEConfiguration(
|
||||
VirtualFileSystem,
|
||||
_viewModel.LibHacHorizonManager,
|
||||
ContentManager,
|
||||
@ -931,7 +933,9 @@ namespace Ryujinx.Ava
|
||||
ConfigurationState.Instance.System.EnableInternetAccess,
|
||||
ConfigurationState.Instance.System.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None,
|
||||
ConfigurationState.Instance.System.FsGlobalAccessLogMode,
|
||||
ConfigurationState.Instance.System.SystemTimeOffset,
|
||||
ConfigurationState.Instance.System.MatchSystemTime
|
||||
? 0
|
||||
: ConfigurationState.Instance.System.SystemTimeOffset,
|
||||
ConfigurationState.Instance.System.TimeZone,
|
||||
ConfigurationState.Instance.System.MemoryManagerMode,
|
||||
ConfigurationState.Instance.System.IgnoreMissingServices,
|
||||
@ -942,19 +946,20 @@ namespace Ryujinx.Ava
|
||||
ConfigurationState.Instance.Multiplayer.Mode,
|
||||
ConfigurationState.Instance.Multiplayer.DisableP2p,
|
||||
ConfigurationState.Instance.Multiplayer.LdnPassphrase,
|
||||
ConfigurationState.Instance.Multiplayer.LdnServer,
|
||||
ConfigurationState.Instance.Graphics.CustomVSyncInterval.Value));
|
||||
ConfigurationState.Instance.Multiplayer.GetLdnServer(),
|
||||
ConfigurationState.Instance.Graphics.CustomVSyncInterval.Value,
|
||||
ConfigurationState.Instance.Hacks.ShowDirtyHacks ? ConfigurationState.Instance.Hacks.EnabledHacks : null));
|
||||
}
|
||||
|
||||
private static IHardwareDeviceDriver InitializeAudio()
|
||||
{
|
||||
var availableBackends = new List<AudioBackend>
|
||||
{
|
||||
List<AudioBackend> availableBackends =
|
||||
[
|
||||
AudioBackend.SDL2,
|
||||
AudioBackend.SoundIo,
|
||||
AudioBackend.OpenAl,
|
||||
AudioBackend.Dummy,
|
||||
};
|
||||
AudioBackend.Dummy
|
||||
];
|
||||
|
||||
AudioBackend preferredBackend = ConfigurationState.Instance.System.AudioBackend.Value;
|
||||
|
||||
@ -1031,9 +1036,10 @@ namespace Ryujinx.Ava
|
||||
if (_viewModel.StartGamesInFullscreen)
|
||||
{
|
||||
_viewModel.WindowState = WindowState.FullScreen;
|
||||
_viewModel.Window.TitleBar.ExtendsContentIntoTitleBar = true;
|
||||
}
|
||||
|
||||
if (_viewModel.WindowState is WindowState.FullScreen)
|
||||
if (_viewModel.WindowState is WindowState.FullScreen || _viewModel.StartGamesWithoutUI)
|
||||
{
|
||||
_viewModel.ShowMenuAndStatusBar = false;
|
||||
}
|
||||
@ -1047,10 +1053,10 @@ namespace Ryujinx.Ava
|
||||
|
||||
Device.Gpu.Renderer.Initialize(_glLogLevel);
|
||||
|
||||
_renderer?.Window?.SetAntiAliasing((Graphics.GAL.AntiAliasing)ConfigurationState.Instance.Graphics.AntiAliasing.Value);
|
||||
_renderer?.Window?.SetScalingFilter((Graphics.GAL.ScalingFilter)ConfigurationState.Instance.Graphics.ScalingFilter.Value);
|
||||
_renderer?.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value);
|
||||
_renderer?.Window?.SetColorSpacePassthrough(ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Value);
|
||||
_renderer?.Window?.SetAntiAliasing(ConfigurationState.Instance.Graphics.AntiAliasing);
|
||||
_renderer?.Window?.SetScalingFilter(ConfigurationState.Instance.Graphics.ScalingFilter);
|
||||
_renderer?.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel);
|
||||
_renderer?.Window?.SetColorSpacePassthrough(ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough);
|
||||
|
||||
Width = (int)RendererHost.Bounds.Width;
|
||||
Height = (int)RendererHost.Bounds.Height;
|
||||
@ -1064,7 +1070,7 @@ namespace Ryujinx.Ava
|
||||
Device.Gpu.SetGpuThread();
|
||||
Device.Gpu.InitializeShaderCache(_gpuCancellationTokenSource.Token);
|
||||
|
||||
_renderer.Window.ChangeVSyncMode((Ryujinx.Graphics.GAL.VSyncMode)Device.VSyncMode);
|
||||
_renderer.Window.ChangeVSyncMode(Device.VSyncMode);
|
||||
|
||||
while (_isActive)
|
||||
{
|
||||
@ -1111,7 +1117,7 @@ namespace Ryujinx.Ava
|
||||
|
||||
public void InitStatus()
|
||||
{
|
||||
_viewModel.BackendText = ConfigurationState.Instance.Graphics.GraphicsBackend.Value switch
|
||||
_viewModel.BackendText = RendererHost.Backend switch
|
||||
{
|
||||
GraphicsBackend.Vulkan => "Vulkan",
|
||||
GraphicsBackend.OpenGl => "OpenGL",
|
||||
@ -1139,8 +1145,8 @@ namespace Ryujinx.Ava
|
||||
LocaleManager.Instance[LocaleKeys.VolumeShort] + $": {(int)(Device.GetVolume() * 100)}%",
|
||||
dockedMode,
|
||||
ConfigurationState.Instance.Graphics.AspectRatio.Value.ToText(),
|
||||
$"{Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)",
|
||||
$"FIFO: {Device.Statistics.GetFifoPercent():00.00} %",
|
||||
Device.Statistics.FormatGameFrameRate(),
|
||||
Device.Statistics.FormatFifoPercent(),
|
||||
_displayCount));
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,7 +12,6 @@ using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.GAL.Multithreading;
|
||||
using Ryujinx.Graphics.Metal;
|
||||
using Ryujinx.Graphics.OpenGL;
|
||||
using Ryujinx.Graphics.Vulkan;
|
||||
using Ryujinx.HLE;
|
||||
@ -310,11 +309,6 @@ namespace Ryujinx.Headless
|
||||
preferredGpuId);
|
||||
}
|
||||
|
||||
if (options.GraphicsBackend == GraphicsBackend.Metal && window is MetalWindow metalWindow && OperatingSystem.IsMacOS())
|
||||
{
|
||||
return new MetalRenderer(metalWindow.GetLayer);
|
||||
}
|
||||
|
||||
return new OpenGLRenderer();
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,11 @@
|
||||
using CommandLine;
|
||||
using Gommon;
|
||||
using LibHac.Tools.FsSystem;
|
||||
using Ryujinx.Audio.Backends.SDL2;
|
||||
using Ryujinx.Ava;
|
||||
using Ryujinx.Ava.Utilities.Configuration;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||
using Ryujinx.Common.Configuration.Hid.Controller.Motion;
|
||||
using Ryujinx.Common.Configuration.Hid.Keyboard;
|
||||
using Ryujinx.Common.GraphicsDriver;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Logging.Targets;
|
||||
@ -15,14 +13,9 @@ using Ryujinx.Common.SystemInterop;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.GAL.Multithreading;
|
||||
using Ryujinx.Graphics.Gpu;
|
||||
using Ryujinx.Graphics.Gpu.Shader;
|
||||
using Ryujinx.Graphics.OpenGL;
|
||||
using Ryujinx.Graphics.Vulkan;
|
||||
using Ryujinx.Graphics.Vulkan.MoltenVK;
|
||||
using Ryujinx.Headless.SDL2.OpenGL;
|
||||
using Ryujinx.Headless.SDL2.Vulkan;
|
||||
using Ryujinx.HLE;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.HLE.HOS;
|
||||
@ -31,22 +24,16 @@ using Ryujinx.Input;
|
||||
using Ryujinx.Input.HLE;
|
||||
using Ryujinx.Input.SDL2;
|
||||
using Ryujinx.SDL2.Common;
|
||||
using Silk.NET.Vulkan;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.GamepadInputId;
|
||||
using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
|
||||
using Key = Ryujinx.Common.Configuration.Hid.Key;
|
||||
|
||||
namespace Ryujinx.Headless.SDL2
|
||||
namespace Ryujinx.Headless
|
||||
{
|
||||
class Program
|
||||
public partial class HeadlessRyujinx
|
||||
{
|
||||
public static string Version { get; private set; }
|
||||
|
||||
private static VirtualFileSystem _virtualFileSystem;
|
||||
private static ContentManager _contentManager;
|
||||
private static AccountManager _accountManager;
|
||||
@ -56,20 +43,18 @@ namespace Ryujinx.Headless.SDL2
|
||||
private static Switch _emulationContext;
|
||||
private static WindowBase _window;
|
||||
private static WindowsMultimediaTimerResolution _windowsMultimediaTimerResolution;
|
||||
private static List<InputConfig> _inputConfiguration;
|
||||
private static List<InputConfig> _inputConfiguration = [];
|
||||
private static bool _enableKeyboard;
|
||||
private static bool _enableMouse;
|
||||
|
||||
private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||
|
||||
static void Main(string[] args)
|
||||
public static void Entrypoint(string[] args)
|
||||
{
|
||||
Version = ReleaseInformation.Version;
|
||||
|
||||
// Make process DPI aware for proper window sizing on high-res screens.
|
||||
ForceDpiAware.Windows();
|
||||
|
||||
Console.Title = $"Ryujinx Console {Version} (Headless SDL2)";
|
||||
Console.Title = $"HeadlessRyujinx Console {Program.Version}";
|
||||
|
||||
if (OperatingSystem.IsMacOS() || OperatingSystem.IsLinux())
|
||||
{
|
||||
@ -97,7 +82,7 @@ namespace Ryujinx.Headless.SDL2
|
||||
}
|
||||
|
||||
Parser.Default.ParseArguments<Options>(args)
|
||||
.WithParsed(Load)
|
||||
.WithParsed(options => Load(args, options))
|
||||
.WithNotParsed(errors =>
|
||||
{
|
||||
Logger.Error?.PrintMsg(LogClass.Application, "Error parsing command-line arguments:");
|
||||
@ -105,239 +90,86 @@ namespace Ryujinx.Headless.SDL2
|
||||
errors.ForEach(err => Logger.Error?.PrintMsg(LogClass.Application, $" - {err.Tag}"));
|
||||
});
|
||||
}
|
||||
|
||||
private static InputConfig HandlePlayerConfiguration(string inputProfileName, string inputId, PlayerIndex index)
|
||||
|
||||
public static void ReloadConfig(string customConfigPath = null)
|
||||
{
|
||||
if (inputId == null)
|
||||
string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ReleaseInformation.ConfigName);
|
||||
string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, ReleaseInformation.ConfigName);
|
||||
|
||||
string configurationPath = null;
|
||||
|
||||
// Now load the configuration as the other subsystems are now registered
|
||||
if (customConfigPath != null && File.Exists(customConfigPath))
|
||||
{
|
||||
if (index == PlayerIndex.Player1)
|
||||
{
|
||||
Logger.Info?.Print(LogClass.Application, $"{index} not configured, defaulting to default keyboard.");
|
||||
|
||||
// Default to keyboard
|
||||
inputId = "0";
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Info?.Print(LogClass.Application, $"{index} not configured");
|
||||
|
||||
return null;
|
||||
}
|
||||
configurationPath = customConfigPath;
|
||||
}
|
||||
else if (File.Exists(localConfigurationPath))
|
||||
{
|
||||
configurationPath = localConfigurationPath;
|
||||
}
|
||||
else if (File.Exists(appDataConfigurationPath))
|
||||
{
|
||||
configurationPath = appDataConfigurationPath;
|
||||
}
|
||||
|
||||
IGamepad gamepad = _inputManager.KeyboardDriver.GetGamepad(inputId);
|
||||
|
||||
bool isKeyboard = true;
|
||||
|
||||
if (gamepad == null)
|
||||
if (configurationPath == null)
|
||||
{
|
||||
gamepad = _inputManager.GamepadDriver.GetGamepad(inputId);
|
||||
isKeyboard = false;
|
||||
// No configuration, we load the default values and save it to disk
|
||||
configurationPath = appDataConfigurationPath;
|
||||
Logger.Notice.Print(LogClass.Application, $"No configuration file found. Saving default configuration to: {configurationPath}");
|
||||
|
||||
if (gamepad == null)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"{index} gamepad not found (\"{inputId}\")");
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
string gamepadName = gamepad.Name;
|
||||
|
||||
gamepad.Dispose();
|
||||
|
||||
InputConfig config;
|
||||
|
||||
if (inputProfileName == null || inputProfileName.Equals("default"))
|
||||
{
|
||||
if (isKeyboard)
|
||||
{
|
||||
config = new StandardKeyboardInputConfig
|
||||
{
|
||||
Version = InputConfig.CurrentVersion,
|
||||
Backend = InputBackendType.WindowKeyboard,
|
||||
Id = null,
|
||||
ControllerType = ControllerType.JoyconPair,
|
||||
LeftJoycon = new LeftJoyconCommonConfig<Key>
|
||||
{
|
||||
DpadUp = Key.Up,
|
||||
DpadDown = Key.Down,
|
||||
DpadLeft = Key.Left,
|
||||
DpadRight = Key.Right,
|
||||
ButtonMinus = Key.Minus,
|
||||
ButtonL = Key.E,
|
||||
ButtonZl = Key.Q,
|
||||
ButtonSl = Key.Unbound,
|
||||
ButtonSr = Key.Unbound,
|
||||
},
|
||||
|
||||
LeftJoyconStick = new JoyconConfigKeyboardStick<Key>
|
||||
{
|
||||
StickUp = Key.W,
|
||||
StickDown = Key.S,
|
||||
StickLeft = Key.A,
|
||||
StickRight = Key.D,
|
||||
StickButton = Key.F,
|
||||
},
|
||||
|
||||
RightJoycon = new RightJoyconCommonConfig<Key>
|
||||
{
|
||||
ButtonA = Key.Z,
|
||||
ButtonB = Key.X,
|
||||
ButtonX = Key.C,
|
||||
ButtonY = Key.V,
|
||||
ButtonPlus = Key.Plus,
|
||||
ButtonR = Key.U,
|
||||
ButtonZr = Key.O,
|
||||
ButtonSl = Key.Unbound,
|
||||
ButtonSr = Key.Unbound,
|
||||
},
|
||||
|
||||
RightJoyconStick = new JoyconConfigKeyboardStick<Key>
|
||||
{
|
||||
StickUp = Key.I,
|
||||
StickDown = Key.K,
|
||||
StickLeft = Key.J,
|
||||
StickRight = Key.L,
|
||||
StickButton = Key.H,
|
||||
},
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
bool isNintendoStyle = gamepadName.Contains("Nintendo");
|
||||
|
||||
config = new StandardControllerInputConfig
|
||||
{
|
||||
Version = InputConfig.CurrentVersion,
|
||||
Backend = InputBackendType.GamepadSDL2,
|
||||
Id = null,
|
||||
ControllerType = ControllerType.JoyconPair,
|
||||
DeadzoneLeft = 0.1f,
|
||||
DeadzoneRight = 0.1f,
|
||||
RangeLeft = 1.0f,
|
||||
RangeRight = 1.0f,
|
||||
TriggerThreshold = 0.5f,
|
||||
LeftJoycon = new LeftJoyconCommonConfig<ConfigGamepadInputId>
|
||||
{
|
||||
DpadUp = ConfigGamepadInputId.DpadUp,
|
||||
DpadDown = ConfigGamepadInputId.DpadDown,
|
||||
DpadLeft = ConfigGamepadInputId.DpadLeft,
|
||||
DpadRight = ConfigGamepadInputId.DpadRight,
|
||||
ButtonMinus = ConfigGamepadInputId.Minus,
|
||||
ButtonL = ConfigGamepadInputId.LeftShoulder,
|
||||
ButtonZl = ConfigGamepadInputId.LeftTrigger,
|
||||
ButtonSl = ConfigGamepadInputId.Unbound,
|
||||
ButtonSr = ConfigGamepadInputId.Unbound,
|
||||
},
|
||||
|
||||
LeftJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
|
||||
{
|
||||
Joystick = ConfigStickInputId.Left,
|
||||
StickButton = ConfigGamepadInputId.LeftStick,
|
||||
InvertStickX = false,
|
||||
InvertStickY = false,
|
||||
Rotate90CW = false,
|
||||
},
|
||||
|
||||
RightJoycon = new RightJoyconCommonConfig<ConfigGamepadInputId>
|
||||
{
|
||||
ButtonA = isNintendoStyle ? ConfigGamepadInputId.A : ConfigGamepadInputId.B,
|
||||
ButtonB = isNintendoStyle ? ConfigGamepadInputId.B : ConfigGamepadInputId.A,
|
||||
ButtonX = isNintendoStyle ? ConfigGamepadInputId.X : ConfigGamepadInputId.Y,
|
||||
ButtonY = isNintendoStyle ? ConfigGamepadInputId.Y : ConfigGamepadInputId.X,
|
||||
ButtonPlus = ConfigGamepadInputId.Plus,
|
||||
ButtonR = ConfigGamepadInputId.RightShoulder,
|
||||
ButtonZr = ConfigGamepadInputId.RightTrigger,
|
||||
ButtonSl = ConfigGamepadInputId.Unbound,
|
||||
ButtonSr = ConfigGamepadInputId.Unbound,
|
||||
},
|
||||
|
||||
RightJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
|
||||
{
|
||||
Joystick = ConfigStickInputId.Right,
|
||||
StickButton = ConfigGamepadInputId.RightStick,
|
||||
InvertStickX = false,
|
||||
InvertStickY = false,
|
||||
Rotate90CW = false,
|
||||
},
|
||||
|
||||
Motion = new StandardMotionConfigController
|
||||
{
|
||||
MotionBackend = MotionInputBackendType.GamepadDriver,
|
||||
EnableMotion = true,
|
||||
Sensitivity = 100,
|
||||
GyroDeadzone = 1,
|
||||
},
|
||||
Rumble = new RumbleConfigController
|
||||
{
|
||||
StrongRumble = 1f,
|
||||
WeakRumble = 1f,
|
||||
EnableRumble = false,
|
||||
},
|
||||
};
|
||||
}
|
||||
ConfigurationState.Instance.LoadDefault();
|
||||
ConfigurationState.Instance.ToFileFormat().SaveConfig(configurationPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
string profileBasePath;
|
||||
Logger.Notice.Print(LogClass.Application, $"Loading configuration from: {configurationPath}");
|
||||
|
||||
if (isKeyboard)
|
||||
if (ConfigurationFileFormat.TryLoad(configurationPath, out ConfigurationFileFormat configurationFileFormat))
|
||||
{
|
||||
profileBasePath = Path.Combine(AppDataManager.ProfilesDirPath, "keyboard");
|
||||
ConfigurationState.Instance.Load(configurationFileFormat, configurationPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
profileBasePath = Path.Combine(AppDataManager.ProfilesDirPath, "controller");
|
||||
}
|
||||
Logger.Warning?.PrintMsg(LogClass.Application, $"Failed to load config! Loading the default config instead.\nFailed config location: {configurationPath}");
|
||||
|
||||
string path = Path.Combine(profileBasePath, inputProfileName + ".json");
|
||||
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"Input profile \"{inputProfileName}\" not found for \"{inputId}\"");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
config = JsonHelper.DeserializeFromFile(path, _serializerContext.InputConfig);
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"Input profile \"{inputProfileName}\" parsing failed for \"{inputId}\"");
|
||||
|
||||
return null;
|
||||
ConfigurationState.Instance.LoadDefault();
|
||||
}
|
||||
}
|
||||
|
||||
config.Id = inputId;
|
||||
config.PlayerIndex = index;
|
||||
|
||||
string inputTypeName = isKeyboard ? "Keyboard" : "Gamepad";
|
||||
|
||||
Logger.Info?.Print(LogClass.Application, $"{config.PlayerIndex} configured with {inputTypeName} \"{config.Id}\"");
|
||||
|
||||
// If both stick ranges are 0 (usually indicative of an outdated profile load) then both sticks will be set to 1.0.
|
||||
if (config is StandardControllerInputConfig controllerConfig)
|
||||
{
|
||||
if (controllerConfig.RangeLeft <= 0.0f && controllerConfig.RangeRight <= 0.0f)
|
||||
{
|
||||
controllerConfig.RangeLeft = 1.0f;
|
||||
controllerConfig.RangeRight = 1.0f;
|
||||
|
||||
Logger.Info?.Print(LogClass.Application, $"{config.PlayerIndex} stick range reset. Save the profile now to update your configuration");
|
||||
}
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
static void Load(Options option)
|
||||
static void Load(string[] originalArgs, Options option)
|
||||
{
|
||||
AppDataManager.Initialize(option.BaseDataDir);
|
||||
Initialize();
|
||||
|
||||
bool useLastUsedProfile = false;
|
||||
|
||||
if (option.InheritConfig)
|
||||
{
|
||||
option.InheritMainConfig(originalArgs, ConfigurationState.Instance, out useLastUsedProfile);
|
||||
}
|
||||
|
||||
AppDataManager.Initialize(option.BaseDataDir);
|
||||
|
||||
if (useLastUsedProfile && AccountSaveDataManager.GetLastUsedUser().TryGet(out UserProfile profile))
|
||||
option.UserProfile = profile.Name;
|
||||
|
||||
// Check if keys exists.
|
||||
if (!File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys")))
|
||||
{
|
||||
if (!(AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile && File.Exists(Path.Combine(AppDataManager.KeysDirPathUser, "prod.keys"))))
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, "Keys not found");
|
||||
}
|
||||
}
|
||||
|
||||
ReloadConfig();
|
||||
|
||||
if (option.InheritConfig)
|
||||
{
|
||||
option.InheritMainConfigInput(originalArgs, ConfigurationState.Instance);
|
||||
}
|
||||
|
||||
_virtualFileSystem = VirtualFileSystem.CreateInstance();
|
||||
_libHacHorizonManager = new LibHacHorizonManager();
|
||||
|
||||
@ -352,7 +184,7 @@ namespace Ryujinx.Headless.SDL2
|
||||
|
||||
_inputManager = new InputManager(new SDL2KeyboardDriver(), new SDL2GamepadDriver());
|
||||
|
||||
GraphicsConfig.EnableShaderCache = true;
|
||||
GraphicsConfig.EnableShaderCache = !option.DisableShaderCache;
|
||||
|
||||
if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
@ -363,15 +195,13 @@ namespace Ryujinx.Headless.SDL2
|
||||
}
|
||||
}
|
||||
|
||||
IGamepad gamepad;
|
||||
|
||||
if (option.ListInputIds)
|
||||
{
|
||||
Logger.Info?.Print(LogClass.Application, "Input Ids:");
|
||||
|
||||
foreach (string id in _inputManager.KeyboardDriver.GamepadsIds)
|
||||
{
|
||||
gamepad = _inputManager.KeyboardDriver.GetGamepad(id);
|
||||
IGamepad gamepad = _inputManager.KeyboardDriver.GetGamepad(id);
|
||||
|
||||
Logger.Info?.Print(LogClass.Application, $"- {id} (\"{gamepad.Name}\")");
|
||||
|
||||
@ -380,7 +210,7 @@ namespace Ryujinx.Headless.SDL2
|
||||
|
||||
foreach (string id in _inputManager.GamepadDriver.GamepadsIds)
|
||||
{
|
||||
gamepad = _inputManager.GamepadDriver.GetGamepad(id);
|
||||
IGamepad gamepad = _inputManager.GamepadDriver.GetGamepad(id);
|
||||
|
||||
Logger.Info?.Print(LogClass.Application, $"- {id} (\"{gamepad.Name}\")");
|
||||
|
||||
@ -397,22 +227,12 @@ namespace Ryujinx.Headless.SDL2
|
||||
return;
|
||||
}
|
||||
|
||||
_inputConfiguration = new List<InputConfig>();
|
||||
_inputConfiguration ??= [];
|
||||
_enableKeyboard = option.EnableKeyboard;
|
||||
_enableMouse = option.EnableMouse;
|
||||
|
||||
static void LoadPlayerConfiguration(string inputProfileName, string inputId, PlayerIndex index)
|
||||
{
|
||||
InputConfig inputConfig = HandlePlayerConfiguration(inputProfileName, inputId, index);
|
||||
|
||||
if (inputConfig != null)
|
||||
{
|
||||
_inputConfiguration.Add(inputConfig);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LoadPlayerConfiguration(option.InputProfile1Name, option.InputId1, PlayerIndex.Player1);
|
||||
LoadPlayerConfiguration(option.InputProfile2Name, option.InputId2, PlayerIndex.Player2);
|
||||
LoadPlayerConfiguration(option.InputProfile2Name, option.InputId2, PlayerIndex.Player2);
|
||||
LoadPlayerConfiguration(option.InputProfile3Name, option.InputId3, PlayerIndex.Player3);
|
||||
LoadPlayerConfiguration(option.InputProfile4Name, option.InputId4, PlayerIndex.Player4);
|
||||
LoadPlayerConfiguration(option.InputProfile5Name, option.InputId5, PlayerIndex.Player5);
|
||||
@ -420,7 +240,7 @@ namespace Ryujinx.Headless.SDL2
|
||||
LoadPlayerConfiguration(option.InputProfile7Name, option.InputId7, PlayerIndex.Player7);
|
||||
LoadPlayerConfiguration(option.InputProfile8Name, option.InputId8, PlayerIndex.Player8);
|
||||
LoadPlayerConfiguration(option.InputProfileHandheldName, option.InputIdHandheld, PlayerIndex.Handheld);
|
||||
|
||||
|
||||
if (_inputConfiguration.Count == 0)
|
||||
{
|
||||
return;
|
||||
@ -431,7 +251,7 @@ namespace Ryujinx.Headless.SDL2
|
||||
Logger.SetEnable(LogLevel.Stub, !option.LoggingDisableStub);
|
||||
Logger.SetEnable(LogLevel.Info, !option.LoggingDisableInfo);
|
||||
Logger.SetEnable(LogLevel.Warning, !option.LoggingDisableWarning);
|
||||
Logger.SetEnable(LogLevel.Error, option.LoggingEnableError);
|
||||
Logger.SetEnable(LogLevel.Error, !option.LoggingDisableError);
|
||||
Logger.SetEnable(LogLevel.Trace, option.LoggingEnableTrace);
|
||||
Logger.SetEnable(LogLevel.Guest, !option.LoggingDisableGuest);
|
||||
Logger.SetEnable(LogLevel.AccessLog, option.LoggingEnableFsAccessLog);
|
||||
@ -468,6 +288,10 @@ namespace Ryujinx.Headless.SDL2
|
||||
GraphicsConfig.EnableMacroHLE = !option.DisableMacroHLE;
|
||||
|
||||
DriverUtilities.InitDriverConfig(option.BackendThreading == BackendThreading.Off);
|
||||
|
||||
if (_inputConfiguration.OfType<StandardControllerInputConfig>()
|
||||
.Any(ic => ic?.Led?.UseRainbow ?? false))
|
||||
Rainbow.Enable();
|
||||
|
||||
while (true)
|
||||
{
|
||||
@ -481,7 +305,28 @@ namespace Ryujinx.Headless.SDL2
|
||||
_userChannelPersistence.ShouldRestart = false;
|
||||
}
|
||||
|
||||
_inputManager.Dispose();
|
||||
try
|
||||
{
|
||||
_inputManager.Dispose();
|
||||
} catch {}
|
||||
|
||||
return;
|
||||
|
||||
void LoadPlayerConfiguration(string inputProfileName, string inputId, PlayerIndex index)
|
||||
{
|
||||
if (index == PlayerIndex.Handheld && _inputConfiguration.Count > 0)
|
||||
{
|
||||
Logger.Info?.Print(LogClass.Configuration, "Skipping handheld configuration as there are already other players configured.");
|
||||
return;
|
||||
}
|
||||
|
||||
InputConfig inputConfig = option.InheritedInputConfigs[index] ?? HandlePlayerConfiguration(inputProfileName, inputId, index);
|
||||
|
||||
if (inputConfig != null)
|
||||
{
|
||||
_inputConfiguration.Add(inputConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetupProgressHandler()
|
||||
@ -500,96 +345,21 @@ namespace Ryujinx.Headless.SDL2
|
||||
{
|
||||
string label = state switch
|
||||
{
|
||||
LoadState => $"PTC : {current}/{total}",
|
||||
ShaderCacheState => $"Shaders : {current}/{total}",
|
||||
_ => throw new ArgumentException($"Unknown Progress Handler type {typeof(T)}"),
|
||||
LoadState => "PTC",
|
||||
ShaderCacheState => "Shaders",
|
||||
_ => throw new ArgumentException($"Unknown Progress Handler type {typeof(T)}")
|
||||
};
|
||||
|
||||
Logger.Info?.Print(LogClass.Application, label);
|
||||
Logger.Info?.Print(LogClass.Application, $"{label} : {current}/{total}");
|
||||
}
|
||||
|
||||
private static WindowBase CreateWindow(Options options)
|
||||
{
|
||||
return options.GraphicsBackend == GraphicsBackend.Vulkan
|
||||
? new VulkanWindow(_inputManager, options.LoggingGraphicsDebugLevel, options.AspectRatio, options.EnableMouse, options.HideCursorMode, options.IgnoreControllerApplet)
|
||||
: new OpenGLWindow(_inputManager, options.LoggingGraphicsDebugLevel, options.AspectRatio, options.EnableMouse, options.HideCursorMode, options.IgnoreControllerApplet);
|
||||
}
|
||||
|
||||
private static IRenderer CreateRenderer(Options options, WindowBase window)
|
||||
{
|
||||
if (options.GraphicsBackend == GraphicsBackend.Vulkan && window is VulkanWindow vulkanWindow)
|
||||
return options.GraphicsBackend switch
|
||||
{
|
||||
string preferredGpuId = string.Empty;
|
||||
Vk api = Vk.GetApi();
|
||||
|
||||
if (!string.IsNullOrEmpty(options.PreferredGPUVendor))
|
||||
{
|
||||
string preferredGpuVendor = options.PreferredGPUVendor.ToLowerInvariant();
|
||||
var devices = VulkanRenderer.GetPhysicalDevices(api);
|
||||
|
||||
foreach (var device in devices)
|
||||
{
|
||||
if (device.Vendor.ToLowerInvariant() == preferredGpuVendor)
|
||||
{
|
||||
preferredGpuId = device.Id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new VulkanRenderer(
|
||||
api,
|
||||
(instance, vk) => new SurfaceKHR((ulong)(vulkanWindow.CreateWindowSurface(instance.Handle))),
|
||||
vulkanWindow.GetRequiredInstanceExtensions,
|
||||
preferredGpuId);
|
||||
}
|
||||
|
||||
return new OpenGLRenderer();
|
||||
}
|
||||
|
||||
private static Switch InitializeEmulationContext(WindowBase window, IRenderer renderer, Options options)
|
||||
{
|
||||
BackendThreading threadingMode = options.BackendThreading;
|
||||
|
||||
bool threadedGAL = threadingMode == BackendThreading.On || (threadingMode == BackendThreading.Auto && renderer.PreferThreading);
|
||||
|
||||
if (threadedGAL)
|
||||
{
|
||||
renderer = new ThreadedRenderer(renderer);
|
||||
}
|
||||
|
||||
HLEConfiguration configuration = new(_virtualFileSystem,
|
||||
_libHacHorizonManager,
|
||||
_contentManager,
|
||||
_accountManager,
|
||||
_userChannelPersistence,
|
||||
renderer,
|
||||
new SDL2HardwareDeviceDriver(),
|
||||
options.DramSize,
|
||||
window,
|
||||
options.SystemLanguage,
|
||||
options.SystemRegion,
|
||||
options.VSyncMode,
|
||||
!options.DisableDockedMode,
|
||||
!options.DisablePTC,
|
||||
options.EnableInternetAccess,
|
||||
!options.DisableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None,
|
||||
options.FsGlobalAccessLogMode,
|
||||
options.SystemTimeOffset,
|
||||
options.SystemTimeZone,
|
||||
options.MemoryManagerMode,
|
||||
options.IgnoreMissingServices,
|
||||
options.AspectRatio,
|
||||
options.AudioVolume,
|
||||
options.UseHypervisor ?? true,
|
||||
options.MultiplayerLanInterfaceId,
|
||||
Common.Configuration.Multiplayer.MultiplayerMode.Disabled,
|
||||
false,
|
||||
string.Empty,
|
||||
string.Empty,
|
||||
options.CustomVSyncInterval);
|
||||
|
||||
return new Switch(configuration);
|
||||
GraphicsBackend.Vulkan => new VulkanWindow(_inputManager, options.LoggingGraphicsDebugLevel, options.AspectRatio, options.EnableMouse, options.HideCursorMode, options.IgnoreControllerApplet),
|
||||
_ => new OpenGLWindow(_inputManager, options.LoggingGraphicsDebugLevel, options.AspectRatio, options.EnableMouse, options.HideCursorMode, options.IgnoreControllerApplet)
|
||||
};
|
||||
}
|
||||
|
||||
private static void ExecutionEntrypoint()
|
||||
|
@ -49,6 +49,9 @@
|
||||
<PackageReference Include="Avalonia.Svg.Skia" />
|
||||
<PackageReference Include="DynamicData" />
|
||||
<PackageReference Include="FluentAvaloniaUI" />
|
||||
<PackageReference Include="CommandLineParser" />
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" />
|
||||
<PackageReference Include="DiscordRichPresence" />
|
||||
<PackageReference Include="Projektanker.Icons.Avalonia" />
|
||||
<PackageReference Include="Projektanker.Icons.Avalonia.FontAwesome" />
|
||||
<PackageReference Include="Projektanker.Icons.Avalonia.MaterialDesign" />
|
||||
@ -56,6 +59,8 @@
|
||||
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'linux-arm64' AND '$(RuntimeIdentifier)' != 'osx-x64' AND '$(RuntimeIdentifier)' != 'osx-arm64'" />
|
||||
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" />
|
||||
<PackageReference Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'linux-arm64' AND '$(RuntimeIdentifier)' != 'win-x64'" />
|
||||
<PackageReference Include="securifybv.ShellLink" />
|
||||
<PackageReference Include="Sep" />
|
||||
<PackageReference Include="Silk.NET.Vulkan" />
|
||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" />
|
||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" />
|
||||
@ -75,7 +80,6 @@
|
||||
<ProjectReference Include="..\ARMeilleure\ARMeilleure.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.Graphics.OpenGL\Ryujinx.Graphics.OpenGL.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.Graphics.Gpu\Ryujinx.Graphics.Gpu.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.UI.Common\Ryujinx.UI.Common.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.UI.LocaleGenerator\Ryujinx.UI.LocaleGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||
</ItemGroup>
|
||||
|
||||
@ -136,4 +140,4 @@
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Include="Assets\locales.json" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -1,12 +1,15 @@
|
||||
using Avalonia;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Media;
|
||||
using Ryujinx.Ava.Utilities.Configuration;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.UI.Common.Configuration;
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Renderer
|
||||
{
|
||||
public partial class RendererHost : UserControl, IDisposable
|
||||
public class RendererHost : UserControl, IDisposable
|
||||
{
|
||||
public readonly EmbeddedWindow EmbeddedWindow;
|
||||
|
||||
@ -15,20 +18,54 @@ namespace Ryujinx.Ava.UI.Renderer
|
||||
|
||||
public RendererHost()
|
||||
{
|
||||
InitializeComponent();
|
||||
Focusable = true;
|
||||
FlowDirection = FlowDirection.LeftToRight;
|
||||
|
||||
if (ConfigurationState.Instance.Graphics.GraphicsBackend.Value == GraphicsBackend.OpenGl)
|
||||
EmbeddedWindow = ConfigurationState.Instance.Graphics.GraphicsBackend.Value switch
|
||||
{
|
||||
EmbeddedWindow = new EmbeddedWindowOpenGL();
|
||||
}
|
||||
else
|
||||
{
|
||||
EmbeddedWindow = new EmbeddedWindowVulkan();
|
||||
}
|
||||
GraphicsBackend.OpenGl => new EmbeddedWindowOpenGL(),
|
||||
GraphicsBackend.Vulkan => new EmbeddedWindowVulkan(),
|
||||
_ => throw new NotSupportedException()
|
||||
};
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
public GraphicsBackend Backend =>
|
||||
EmbeddedWindow switch
|
||||
{
|
||||
EmbeddedWindowVulkan => GraphicsBackend.Vulkan,
|
||||
EmbeddedWindowOpenGL => GraphicsBackend.OpenGl,
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
|
||||
public RendererHost(string titleId)
|
||||
{
|
||||
Focusable = true;
|
||||
FlowDirection = FlowDirection.LeftToRight;
|
||||
|
||||
EmbeddedWindow =
|
||||
#pragma warning disable CS8509
|
||||
TitleIDs.SelectGraphicsBackend(titleId, ConfigurationState.Instance.Graphics.GraphicsBackend) switch
|
||||
#pragma warning restore CS8509
|
||||
{
|
||||
GraphicsBackend.OpenGl => new EmbeddedWindowOpenGL(),
|
||||
GraphicsBackend.Vulkan => new EmbeddedWindowVulkan(),
|
||||
};
|
||||
|
||||
string backendText = EmbeddedWindow switch
|
||||
{
|
||||
EmbeddedWindowVulkan => "Vulkan",
|
||||
EmbeddedWindowOpenGL => "OpenGL",
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
|
||||
Logger.Info?.PrintMsg(LogClass.Gpu, $"Backend ({ConfigurationState.Instance.Graphics.GraphicsBackend.Value}): {backendText}");
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
EmbeddedWindow.WindowCreated += CurrentWindow_WindowCreated;
|
||||
|
Loading…
x
Reference in New Issue
Block a user