Merge remote-tracking branch 'origin/master2' into SDL3

# Conflicts:
#	src/Ryujinx/Headless/Windows/OpenGLWindow.cs
#	src/Ryujinx/Headless/Windows/WindowBase.cs
This commit is contained in:
madwind 2025-01-19 11:01:09 +08:00
commit 8fd97963e9
14 changed files with 269 additions and 221 deletions

View File

@ -3348,7 +3348,7 @@
01001C400482C000,"Wunderling DX",audio;crash,ingame,2022-09-10 13:20:12 01001C400482C000,"Wunderling DX",audio;crash,ingame,2022-09-10 13:20:12
01003B401148E000,"Wurroom",,playable,2020-10-07 22:46:21 01003B401148E000,"Wurroom",,playable,2020-10-07 22:46:21
010081700EDF4000,"WWE 2K Battlegrounds",nvdec;online-broken;UE4,playable,2022-10-07 12:44:40 010081700EDF4000,"WWE 2K Battlegrounds",nvdec;online-broken;UE4,playable,2022-10-07 12:44:40
010009800203E000,"WWE 2K18",nvdec,playable,2023-10-21 17:22:01 010009800203E000,"WWE 2K18",nvdec;online-broken,ingame,2025-01-17 11:36:56
0100DF100B97C000,"X-Morph: Defense",,playable,2020-06-22 11:05:31 0100DF100B97C000,"X-Morph: Defense",,playable,2020-06-22 11:05:31
0100D0B00FB74000,"XCOM® 2 Collection",gpu;crash,ingame,2022-10-04 09:38:30 0100D0B00FB74000,"XCOM® 2 Collection",gpu;crash,ingame,2022-10-04 09:38:30
0100CC9015360000,"XEL",gpu,ingame,2022-10-03 10:19:39 0100CC9015360000,"XEL",gpu,ingame,2022-10-03 10:19:39

1 title_id game_name labels status last_updated
3348 01001C400482C000 Wunderling DX audio;crash ingame 2022-09-10 13:20:12
3349 01003B401148E000 Wurroom playable 2020-10-07 22:46:21
3350 010081700EDF4000 WWE 2K Battlegrounds nvdec;online-broken;UE4 playable 2022-10-07 12:44:40
3351 010009800203E000 WWE 2K18 nvdec nvdec;online-broken playable ingame 2023-10-21 17:22:01 2025-01-17 11:36:56
3352 0100DF100B97C000 X-Morph: Defense playable 2020-06-22 11:05:31
3353 0100D0B00FB74000 XCOM® 2 Collection gpu;crash ingame 2022-10-04 09:38:30
3354 0100CC9015360000 XEL gpu ingame 2022-10-03 10:19:39

File diff suppressed because it is too large Load Diff

View File

@ -229,8 +229,6 @@ namespace Ryujinx.Headless
_enableKeyboard = option.EnableKeyboard; _enableKeyboard = option.EnableKeyboard;
_enableMouse = option.EnableMouse; _enableMouse = option.EnableMouse;
LoadPlayerConfiguration(option.InputProfile1Name, option.InputId1, PlayerIndex.Player1); 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.InputProfile3Name, option.InputId3, PlayerIndex.Player3);
@ -301,7 +299,10 @@ namespace Ryujinx.Headless
_userChannelPersistence.ShouldRestart = false; _userChannelPersistence.ShouldRestart = false;
} }
try
{
_inputManager.Dispose(); _inputManager.Dispose();
} catch {}
return; return;
@ -338,12 +339,12 @@ namespace Ryujinx.Headless
{ {
string label = state switch string label = state switch
{ {
LoadState => $"PTC : {current}/{total}", LoadState => "PTC",
ShaderCacheState => $"Shaders : {current}/{total}", ShaderCacheState => "Shaders",
_ => throw new ArgumentException($"Unknown Progress Handler type {typeof(T)}"), _ => 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) private static WindowBase CreateWindow(Options options)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -1,21 +0,0 @@
using System;
namespace Ryujinx.Headless
{
class StatusUpdatedEventArgs(
string vSyncMode,
string dockedMode,
string aspectRatio,
string gameStatus,
string fifoStatus,
string gpuName)
: EventArgs
{
public string VSyncMode = vSyncMode;
public string DockedMode = dockedMode;
public string AspectRatio = aspectRatio;
public string GameStatus = gameStatus;
public string FifoStatus = fifoStatus;
public string GpuName = gpuName;
}
}

View File

@ -26,7 +26,7 @@ namespace Ryujinx.Headless
bool ignoreControllerApplet) bool ignoreControllerApplet)
: base(inputManager, glLogLevel, aspectRatio, enableMouse, hideCursorMode, ignoreControllerApplet) { } : base(inputManager, glLogLevel, aspectRatio, enableMouse, hideCursorMode, ignoreControllerApplet) { }
public override SDL_WindowFlags GetWindowFlags() => SDL_WindowFlags.SDL_WINDOW_METAL; public override SDL_WindowFlags WindowFlags => SDL_WindowFlags.SDL_WINDOW_METAL;
protected override void InitializeWindowRenderer() protected override void InitializeWindowRenderer()
{ {

View File

@ -119,10 +119,9 @@ namespace Ryujinx.Headless
bool ignoreControllerApplet) bool ignoreControllerApplet)
: base(inputManager, glLogLevel, aspectRatio, enableMouse, hideCursorMode, ignoreControllerApplet) : base(inputManager, glLogLevel, aspectRatio, enableMouse, hideCursorMode, ignoreControllerApplet)
{ {
_glLogLevel = glLogLevel;
} }
public override SDL_WindowFlags GetWindowFlags() => SDL_WindowFlags.SDL_WINDOW_OPENGL; public override SDL_WindowFlags WindowFlags() => SDL_WindowFlags.SDL_WINDOW_OPENGL;
protected override void InitializeWindowRenderer() protected override void InitializeWindowRenderer()
{ {

View File

@ -10,8 +10,6 @@ namespace Ryujinx.Headless
{ {
class VulkanWindow : WindowBase class VulkanWindow : WindowBase
{ {
private readonly GraphicsDebugLevel _glLogLevel;
public VulkanWindow( public VulkanWindow(
InputManager inputManager, InputManager inputManager,
GraphicsDebugLevel glLogLevel, GraphicsDebugLevel glLogLevel,
@ -21,10 +19,9 @@ namespace Ryujinx.Headless
bool ignoreControllerApplet) bool ignoreControllerApplet)
: base(inputManager, glLogLevel, aspectRatio, enableMouse, hideCursorMode, ignoreControllerApplet) : base(inputManager, glLogLevel, aspectRatio, enableMouse, hideCursorMode, ignoreControllerApplet)
{ {
_glLogLevel = glLogLevel;
} }
public override SDL_WindowFlags GetWindowFlags() => SDL_WindowFlags.SDL_WINDOW_VULKAN; public override SDL_WindowFlags WindowFlags => SDL_WindowFlags.SDL_WINDOW_VULKAN;
protected override void InitializeWindowRenderer() { } protected override void InitializeWindowRenderer() { }

View File

@ -1,12 +1,12 @@
using Humanizer; using Humanizer;
using LibHac.Util;
using Ryujinx.Ava; using Ryujinx.Ava;
using Ryujinx.Ava.UI.Models;
using Ryujinx.Common;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.GAL.Multithreading; using Ryujinx.Graphics.GAL.Multithreading;
using Ryujinx.Graphics.Gpu;
using Ryujinx.Graphics.OpenGL; using Ryujinx.Graphics.OpenGL;
using Ryujinx.HLE.HOS.Applets; using Ryujinx.HLE.HOS.Applets;
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types; using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
@ -43,6 +43,10 @@ namespace Ryujinx.Headless
private static readonly ConcurrentQueue<Action> _mainThreadActions = new(); private static readonly ConcurrentQueue<Action> _mainThreadActions = new();
[LibraryImport("SDL2")]
// TODO: Remove this as soon as SDL2-CS was updated to expose this method publicly
private static partial nint SDL_LoadBMP_RW(nint src, int freesrc);
public static void QueueMainThreadAction(Action action) public static void QueueMainThreadAction(Action action)
{ {
_mainThreadActions.Enqueue(action); _mainThreadActions.Enqueue(action);
@ -72,7 +76,7 @@ namespace Ryujinx.Headless
protected SDL3MouseDriver MouseDriver; protected SDL3MouseDriver MouseDriver;
private readonly InputManager _inputManager; private readonly InputManager _inputManager;
private readonly IKeyboard _keyboardInterface; private readonly IKeyboard _keyboardInterface;
private readonly GraphicsDebugLevel _glLogLevel; protected readonly GraphicsDebugLevel GlLogLevel;
private readonly Stopwatch _chrono; private readonly Stopwatch _chrono;
private readonly long _ticksPerFrame; private readonly long _ticksPerFrame;
private readonly CancellationTokenSource _gpuCancellationTokenSource; private readonly CancellationTokenSource _gpuCancellationTokenSource;
@ -104,7 +108,7 @@ namespace Ryujinx.Headless
NpadManager = _inputManager.CreateNpadManager(); NpadManager = _inputManager.CreateNpadManager();
TouchScreenManager = _inputManager.CreateTouchScreenManager(); TouchScreenManager = _inputManager.CreateTouchScreenManager();
_keyboardInterface = (IKeyboard)_inputManager.KeyboardDriver.GetGamepad("0"); _keyboardInterface = (IKeyboard)_inputManager.KeyboardDriver.GetGamepad("0");
_glLogLevel = glLogLevel; GlLogLevel = glLogLevel;
_chrono = new Stopwatch(); _chrono = new Stopwatch();
_ticksPerFrame = Stopwatch.Frequency / TargetFps; _ticksPerFrame = Stopwatch.Frequency / TargetFps;
_gpuCancellationTokenSource = new CancellationTokenSource(); _gpuCancellationTokenSource = new CancellationTokenSource();
@ -137,7 +141,7 @@ namespace Ryujinx.Headless
private void SetWindowIcon() private void SetWindowIcon()
{ {
Stream iconStream = typeof(Program).Assembly.GetManifestResourceStream("HeadlessLogo"); Stream iconStream = EmbeddedResources.GetStream("Ryujinx/Assets/UIImages/Logo_Ryujinx.png");
byte[] iconBytes = new byte[iconStream!.Length]; byte[] iconBytes = new byte[iconStream!.Length];
if (iconStream.Read(iconBytes, 0, iconBytes.Length) != iconBytes.Length) if (iconStream.Read(iconBytes, 0, iconBytes.Length) != iconBytes.Length)
@ -169,15 +173,9 @@ namespace Ryujinx.Headless
var nacp = activeProcess.ApplicationControlProperties; var nacp = activeProcess.ApplicationControlProperties;
int desiredLanguage = (int)Device.System.State.DesiredTitleLanguage; int desiredLanguage = (int)Device.System.State.DesiredTitleLanguage;
string titleNameSection = string.IsNullOrWhiteSpace(nacp.Title[desiredLanguage].NameString.ToString()) string titleNameSection = string.IsNullOrWhiteSpace(nacp.Title[desiredLanguage].NameString.ToString()) ? string.Empty : $" - {nacp.Title[desiredLanguage].NameString.ToString()}";
? string.Empty string titleVersionSection = string.IsNullOrWhiteSpace(nacp.DisplayVersionString.ToString()) ? string.Empty : $" v{nacp.DisplayVersionString.ToString()}";
: $" - {nacp.Title[desiredLanguage].NameString.ToString()}"; string titleIdSection = string.IsNullOrWhiteSpace(activeProcess.ProgramIdText) ? string.Empty : $" ({activeProcess.ProgramIdText.ToUpper()})";
string titleVersionSection = string.IsNullOrWhiteSpace(nacp.DisplayVersionString.ToString())
? string.Empty
: $" v{nacp.DisplayVersionString.ToString()}";
string titleIdSection = string.IsNullOrWhiteSpace(activeProcess.ProgramIdText)
? string.Empty
: $" ({activeProcess.ProgramIdText.ToUpper()})";
string titleArchSection = activeProcess.Is64Bit ? " (64-bit)" : " (32-bit)"; string titleArchSection = activeProcess.Is64Bit ? " (64-bit)" : " (32-bit)";
Width = DefaultWidth; Width = DefaultWidth;
@ -197,10 +195,7 @@ namespace Ryujinx.Headless
FullscreenFlag = SDL_WindowFlags.SDL_WINDOW_FULLSCREEN; FullscreenFlag = SDL_WindowFlags.SDL_WINDOW_FULLSCREEN;
} }
WindowHandle = WindowHandle = SDL_CreateWindow($"Ryujinx {Program.Version}{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}", Width, Height, DefaultFlags | FullscreenFlag | WindowFlags());
SDL_CreateWindow(
$"Ryujinx {Program.Version}{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}",
Width, Height, DefaultFlags | FullscreenFlag | GetWindowFlags());
if (WindowHandle == nint.Zero) if (WindowHandle == nint.Zero)
{ {
@ -236,7 +231,6 @@ namespace Ryujinx.Headless
Renderer?.Window.SetSize(Width, Height); Renderer?.Window.SetSize(Width, Height);
MouseDriver.SetClientSize(Width, Height); MouseDriver.SetClientSize(Width, Height);
} }
break; break;
case SDL_EventType.SDL_EVENT_WINDOW_CLOSE_REQUESTED: case SDL_EventType.SDL_EVENT_WINDOW_CLOSE_REQUESTED:
@ -258,7 +252,7 @@ namespace Ryujinx.Headless
protected abstract void SwapBuffers(); protected abstract void SwapBuffers();
public abstract SDL_WindowFlags GetWindowFlags(); public abstract SDL_WindowFlags WindowFlags { get; }
private string GetGpuDriverName() private string GetGpuDriverName()
{ {
@ -280,7 +274,7 @@ namespace Ryujinx.Headless
{ {
InitializeWindowRenderer(); InitializeWindowRenderer();
Device.Gpu.Renderer.Initialize(_glLogLevel); Device.Gpu.Renderer.Initialize(GlLogLevel);
InitializeRenderer(); InitializeRenderer();
@ -320,21 +314,6 @@ namespace Ryujinx.Headless
if (_ticks >= _ticksPerFrame) if (_ticks >= _ticksPerFrame)
{ {
string dockedMode = Device.System.State.DockedMode ? "Docked" : "Handheld";
float scale = GraphicsConfig.ResScale;
if (scale != 1)
{
dockedMode += $" ({scale}x)";
}
StatusUpdatedEvent?.Invoke(this, new StatusUpdatedEventArgs(
Device.VSyncMode.ToString(),
dockedMode,
Device.Configuration.AspectRatio.ToText(),
$"{Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)",
$"FIFO: {Device.Statistics.GetFifoPercent():0.00} %",
$"GPU: {_gpuDriverName}"));
_ticks = Math.Min(_ticks - _ticksPerFrame, _ticksPerFrame); _ticks = Math.Min(_ticks - _ticksPerFrame, _ticksPerFrame);
} }
} }
@ -434,9 +413,7 @@ namespace Ryujinx.Headless
// Get screen touch position // Get screen touch position
if (!_enableMouse) if (!_enableMouse)
{ {
hasTouch = TouchScreenManager.Update(true, hasTouch = TouchScreenManager.Update(true, (_inputManager.MouseDriver as SDL3MouseDriver).IsButtonPressed(MouseButton.Button1), _aspectRatio.ToFloat());
(_inputManager.MouseDriver as SDL3MouseDriver).IsButtonPressed(MouseButton.Button1),
_aspectRatio.ToFloat());
} }
if (!hasTouch) if (!hasTouch)
@ -459,13 +436,19 @@ namespace Ryujinx.Headless
InitializeWindow(); InitializeWindow();
Thread renderLoopThread = new(Render) { Name = "GUI.RenderLoop", }; Thread renderLoopThread = new(Render)
{
Name = "GUI.RenderLoop",
};
renderLoopThread.Start(); renderLoopThread.Start();
Thread nvidiaStutterWorkaround = null; Thread nvidiaStutterWorkaround = null;
if (Renderer is OpenGLRenderer) if (Renderer is OpenGLRenderer)
{ {
nvidiaStutterWorkaround = new Thread(NvidiaStutterWorkaround) { Name = "GUI.NvidiaStutterWorkaround", }; nvidiaStutterWorkaround = new Thread(NvidiaStutterWorkaround)
{
Name = "GUI.NvidiaStutterWorkaround",
};
nvidiaStutterWorkaround.Start(); nvidiaStutterWorkaround.Start();
} }
@ -505,20 +488,16 @@ namespace Ryujinx.Headless
public void DisplayCabinetMessageDialog() public void DisplayCabinetMessageDialog()
{ {
SDL_ShowSimpleMessageBox(SDL_MessageBoxFlags.SDL_MESSAGEBOX_INFORMATION, "Cabinet Dialog", SDL_ShowSimpleMessageBox(SDL_MessageBoxFlags.SDL_MESSAGEBOX_INFORMATION, "Cabinet Dialog", "Please scan your Amiibo now.", WindowHandle);
"Please scan your Amiibo now.", WindowHandle);
} }
public bool DisplayMessageDialog(ControllerAppletUIArgs args) public bool DisplayMessageDialog(ControllerAppletUIArgs args)
{ {
if (_ignoreControllerApplet) return false; if (_ignoreControllerApplet) return false;
string playerCount = args.PlayerCountMin == args.PlayerCountMax string playerCount = args.PlayerCountMin == args.PlayerCountMax ? $"exactly {args.PlayerCountMin}" : $"{args.PlayerCountMin}-{args.PlayerCountMax}";
? $"exactly {args.PlayerCountMin}"
: $"{args.PlayerCountMin}-{args.PlayerCountMax}";
string message = string message = $"Application requests {playerCount} {"player".ToQuantity(args.PlayerCountMin + args.PlayerCountMax, ShowQuantityAs.None)} with:\n\n"
$"Application requests {playerCount} {"player".ToQuantity(args.PlayerCountMin + args.PlayerCountMax, ShowQuantityAs.None)} with:\n\n"
+ $"TYPES: {args.SupportedStyles}\n\n" + $"TYPES: {args.SupportedStyles}\n\n"
+ $"PLAYERS: {string.Join(", ", args.SupportedPlayers)}\n\n" + $"PLAYERS: {string.Join(", ", args.SupportedPlayers)}\n\n"
+ (args.IsDocked ? "Docked mode set. Handheld is also invalid.\n\n" : string.Empty) + (args.IsDocked ? "Docked mode set. Handheld is also invalid.\n\n" : string.Empty)

View File

@ -170,7 +170,6 @@
<EmbeddedResource Include="Assets\UIImages\Logo_GitHub_Light.png" /> <EmbeddedResource Include="Assets\UIImages\Logo_GitHub_Light.png" />
<EmbeddedResource Include="Assets\UIImages\Logo_Ryujinx.png" /> <EmbeddedResource Include="Assets\UIImages\Logo_Ryujinx.png" />
<EmbeddedResource Include="Assets\UIImages\Logo_Ryujinx_AntiAlias.png" /> <EmbeddedResource Include="Assets\UIImages\Logo_Ryujinx_AntiAlias.png" />
<EmbeddedResource Include="Headless\Ryujinx.bmp" LogicalName="HeadlessLogo" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<AdditionalFiles Include="Assets\locales.json" /> <AdditionalFiles Include="Assets\locales.json" />

View File

@ -7,6 +7,7 @@
Title="Ryujinx - Waiting" Title="Ryujinx - Waiting"
SizeToContent="WidthAndHeight" SizeToContent="WidthAndHeight"
WindowStartupLocation="CenterOwner" WindowStartupLocation="CenterOwner"
CanResize="False"
mc:Ignorable="d" mc:Ignorable="d"
Focusable="True"> Focusable="True">
<Grid <Grid

View File

@ -22,5 +22,22 @@ namespace Ryujinx.Ava.UI.Models
FifoStatus = fifoStatus; FifoStatus = fifoStatus;
ShaderCount = shaderCount; ShaderCount = shaderCount;
} }
public override bool Equals(object obj)
{
if (obj is not StatusUpdatedEventArgs suea) return false;
return
VSyncMode == suea.VSyncMode &&
VolumeStatus == suea.VolumeStatus &&
DockedMode == suea.DockedMode &&
AspectRatio == suea.AspectRatio &&
GameStatus == suea.GameStatus &&
FifoStatus == suea.FifoStatus &&
ShaderCount == suea.ShaderCount;
}
public override int GetHashCode()
=> HashCode.Combine(VSyncMode, VolumeStatus, AspectRatio, DockedMode, FifoStatus, GameStatus, ShaderCount);
} }
} }

View File

@ -136,6 +136,12 @@
<ComboBoxItem> <ComboBoxItem>
<TextBlock Text="{ext:Locale SettingsTabSystemSystemLanguageBrazilianPortuguese}" /> <TextBlock Text="{ext:Locale SettingsTabSystemSystemLanguageBrazilianPortuguese}" />
</ComboBoxItem> </ComboBoxItem>
<ComboBoxItem>
<TextBlock Text="{ext:Locale SettingsTabSystemSystemLanguageSwedish}" />
</ComboBoxItem>
<ComboBoxItem>
<TextBlock Text="{ext:Locale SettingsTabSystemSystemLanguageNorwegian}" />
</ComboBoxItem>
</ComboBox> </ComboBox>
</StackPanel> </StackPanel>
<StackPanel <StackPanel

View File

@ -32,6 +32,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Versioning; using System.Runtime.Versioning;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -136,6 +137,8 @@ namespace Ryujinx.Ava.UI.Windows
base.OnApplyTemplate(e); base.OnApplyTemplate(e);
NotificationHelper.SetNotificationManager(this); NotificationHelper.SetNotificationManager(this);
Executor.ExecuteBackgroundAsync(ShowIntelMacWarningAsync);
} }
private void OnScalingChanged(object sender, EventArgs e) private void OnScalingChanged(object sender, EventArgs e)
@ -731,5 +734,22 @@ namespace Ryujinx.Ava.UI.Windows
(int)Symbol.Checkmark); (int)Symbol.Checkmark);
}); });
} }
private static bool _intelMacWarningShown;
public static async Task ShowIntelMacWarningAsync()
{
if (!_intelMacWarningShown &&
(OperatingSystem.IsMacOS() &&
(RuntimeInformation.OSArchitecture == Architecture.X64 ||
RuntimeInformation.OSArchitecture == Architecture.X86)))
{
_intelMacWarningShown = true;
await Dispatcher.UIThread.InvokeAsync(async () => await ContentDialogHelper.CreateWarningDialog(
"Intel Mac Warning",
"Intel Macs are not supported and will not work properly.\nIf you continue, do not come to our Discord asking for support."));
}
}
} }
} }