Compare commits

..

5 Commits

Author SHA1 Message Date
GreemDev
ccfe4cbed7 [ci skip] groups should only be used for packages released in lockstep 2026-05-01 22:13:57 -05:00
GreemDev
933c993467 [ci skip] more changes 2026-05-01 22:11:34 -05:00
GreemDev
b80c4a1b01 some more config modifications 2026-05-01 21:40:26 -05:00
GreemDev
0de4d4f861 some config modifications 2026-05-01 21:20:20 -05:00
Renovate Bot
d8869a14ec Add .forgejo/renovate.json 2026-05-02 02:00:32 +00:00
10 changed files with 95 additions and 139 deletions

39
.forgejo/renovate.json Normal file
View File

@@ -0,0 +1,39 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"renovate/config"
],
"enabledManagers": ["nuget", "github-actions"],
"packageRules": [
{
"matchDepNames": "Avalonia.*",
"matchDepTypes": "nuget",
"dependencyDashboardApproval": true
},
{
"matchDepNames": "FluentAvaloniaUI",
"matchDepTypes": "nuget",
"dependencyDashboardApproval": true
},
{
"matchDepNames": "FluentAvaloniaUI.*",
"matchDepTypes": "nuget",
"dependencyDashboardApproval": true
},
{
"matchDepNames": "Gommon",
"matchDepTypes": "nuget",
"enabled": false
},
{
"description": "group Silk.NET packages",
"extends": ["renovate/config//groups/silkdotnet.json"],
"groupName": "Silk.NET"
},
{
"description": "group OpenTK packages",
"extends": ["renovate/config//groups/opentk.json"],
"groupName": "OpenTK"
}
]
}

View File

@@ -17,8 +17,7 @@ namespace Ryujinx.Cpu.LightningJit.Cache
private static readonly int _pageMask = _pageSize - 1;
private const int CodeAlignment = 4; // Bytes.
// TODO: JIT Cache size should be application dependent, not global.
private const int CacheSize = 1024 * (1024 * 1024); // Megabytes * Size of Megabytes (since its in bytes).
private const int CacheSize = 256 * 1024 * 1024;
private static JitCacheInvalidation _jitCacheInvalidator;
@@ -34,14 +33,6 @@ namespace Ryujinx.Cpu.LightningJit.Cache
[SupportedOSPlatform("windows")]
[LibraryImport("kernel32.dll", SetLastError = true)]
public static partial nint FlushInstructionCache(nint hProcess, nint lpAddress, nuint dwSize);
[SupportedOSPlatform("macos")]
[LibraryImport("libSystem.dylib", EntryPoint = "sys_icache_invalidate")]
internal static partial void SysICacheInvalidate(nint start, nuint len);
[SupportedOSPlatform("linux")]
[LibraryImport("libgcc_s.so.1", EntryPoint = "__clear_cache")]
internal static partial void ClearCache(nint begin, nint end);
public static void Initialize(IJitMemoryAllocator allocator)
{

View File

@@ -1,4 +1,3 @@
using Ryujinx.Common.Logging;
using System;
using System.Diagnostics;
using System.Threading;
@@ -115,7 +114,7 @@ namespace Ryujinx.Graphics.Vulkan
cbs.AddDependant(this);
// We need to add a dependency on the command buffer to all objects this object
// references as well.
// references aswell.
if (_referencedObjs != null)
{
for (int i = 0; i < _referencedObjs.Length; i++)
@@ -177,8 +176,6 @@ namespace Ryujinx.Graphics.Vulkan
}
}
// This can somehow become -1.
// Logger.Info?.PrintMsg(LogClass.Gpu, $"_referenceCount: {_referenceCount}");
Debug.Assert(_referenceCount >= 0);
}

View File

@@ -14,7 +14,6 @@ using Ryujinx.HLE.Loaders.Executables;
using Ryujinx.HLE.Loaders.Processes.Extensions;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using Path = System.IO.Path;
@@ -28,15 +27,10 @@ namespace Ryujinx.HLE.Loaders.Processes
private ulong _latestPid;
public ProcessResult? ActiveApplication
public ProcessResult ActiveApplication
{
get
{
return _processesByPid.GetValueOrDefault(_latestPid);
// Using this if statement locks up the UI and prevents a new game from loading.
// Haven't quite deduced why yet.
if (!_processesByPid.TryGetValue(_latestPid, out ProcessResult value))
throw new RyujinxException(
$"The HLE Process map did not have a process with ID {_latestPid}. Are you missing firmware?");
@@ -150,7 +144,7 @@ namespace Ryujinx.HLE.Loaders.Processes
public bool LoadUnpackedNca(string exeFsDirPath, string romFsPath = null)
{
ProcessResult processResult = new LocalFileSystem(exeFsDirPath).Load(_device, romFsPath);
if (processResult.ProcessId != 0 && _processesByPid.TryAdd(processResult.ProcessId, processResult))
{
if (processResult.Start(_device))

View File

@@ -4,6 +4,7 @@ using LibHac.Ns;
using Ryujinx.Common.Logging;
using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.SystemState;
using Ryujinx.HLE.Loaders.Processes.Extensions;
using Ryujinx.Horizon.Common;
namespace Ryujinx.HLE.Loaders.Processes
@@ -51,7 +52,6 @@ namespace Ryujinx.HLE.Loaders.Processes
if (metaLoader is not null)
{
Logger.Info?.Print(LogClass.Application,$"metaLoader: {metaLoader}");
ulong programId = metaLoader.ProgramId;
Name = ApplicationControlProperties.Title[(int)titleLanguage].NameString.ToString();
@@ -71,15 +71,8 @@ namespace Ryujinx.HLE.Loaders.Processes
ProgramId = programId;
ProgramIdText = $"{programId:x16}";
Is64Bit = metaLoader.IsProgram64Bit;
}
else
{
Logger.Error?.Print(LogClass.Application,$"metaLoader is null !!!");
ProcessId = 0;
return;
}
DiskCacheEnabled = diskCacheEnabled;
AllowCodeMemoryForJit = allowCodeMemoryForJit;
}

View File

@@ -62,7 +62,7 @@ using VSyncMode = Ryujinx.Common.Configuration.VSyncMode;
namespace Ryujinx.Ava.Systems
{
internal class AppHost : IDisposable
internal class AppHost
{
private const int CursorHideIdleTime = 5; // Hide Cursor seconds.
private const float MaxResolutionScale = 4.0f; // Max resolution hotkeys can scale to before wrapping.
@@ -438,7 +438,7 @@ namespace Ryujinx.Ava.Systems
SaveBitmapAsPng(bitmapToSave, path);
Logger.Notice.Print(LogClass.Application, $"Screenshot saved to '{path}'.", "Screenshot");
Logger.Notice.Print(LogClass.Application, $"Screenshot saved to {path}", "Screenshot");
}
});
}
@@ -611,40 +611,27 @@ namespace Ryujinx.Ava.Systems
_isActive = false;
// NOTE: The render loop is allowed to stay alive until the renderer itself is disposed, as it may handle resource dispose.
// We only need to wait for all commands submitted during the main gpu loop to be processed.
_gpuDoneEvent.WaitOne();
_gpuDoneEvent.Dispose();
DisplaySleep.Restore();
NpadManager.Dispose();
TouchScreenManager.Dispose();
Device.Dispose();
// NOTE: The render loop is allowed to stay alive until the renderer itself is disposed, as it may handle resource dispose.
// We only need to wait for all commands submitted during the main gpu loop to be processed.
// If the GPU has no work and is cancelled, we need to handle that as well.
WaitHandle.WaitAny(new[] { _gpuDoneEvent, _gpuCancellationTokenSource.Token.WaitHandle });
_gpuCancellationTokenSource.Dispose();
// Waiting for work to be finished before we dispose.
if (_renderingStarted)
{
Device.Gpu.WaitUntilGpuReady();
}
_gpuDoneEvent.Dispose();
DisposeGpu();
AppExit?.Invoke(this, EventArgs.Empty);
}
// MUST be public to inherit from IDisposable
public void Dispose()
private void Dispose()
{
if (Device.Processes != null)
{
MainWindowViewModel.UpdateGameMetadata(Device.Processes.ActiveApplication?.ProgramIdText,
_playTimer.Elapsed);
}
MainWindowViewModel.UpdateGameMetadata(Device.Processes.ActiveApplication.ProgramIdText, _playTimer.Elapsed);
ConfigurationState.Instance.System.IgnoreMissingServices.Event -= UpdateIgnoreMissingServicesState;
ConfigurationState.Instance.Graphics.AspectRatio.Event -= UpdateAspectRatioState;
ConfigurationState.Instance.System.EnableDockedMode.Event -= UpdateDockedModeState;
@@ -659,6 +646,7 @@ namespace Ryujinx.Ava.Systems
_topLevel.PointerExited -= TopLevel_PointerExited;
_gpuCancellationTokenSource.Cancel();
_gpuCancellationTokenSource.Dispose();
_chrono.Stop();
_playTimer.Stop();
@@ -684,12 +672,6 @@ namespace Ryujinx.Ava.Systems
}
else
{
// No use waiting on something that never started work
if (_renderingStarted)
{
Device.Gpu.WaitUntilGpuReady();
}
Device.DisposeGpu();
}
}
@@ -704,7 +686,7 @@ namespace Ryujinx.Ava.Systems
_cursorState = CursorStates.ForceChangeCursor;
}
public async Task LoadGuestApplication(CancellationTokenSource cts, BlitStruct<ApplicationControlProperty>? customNacpData = null)
public async Task<bool> LoadGuestApplication(BlitStruct<ApplicationControlProperty>? customNacpData = null)
{
DiscordIntegrationModule.GuestAppStartedAt = Timestamps.Now;
@@ -733,8 +715,7 @@ namespace Ryujinx.Ava.Systems
await UserErrorDialog.ShowUserErrorDialog(userError);
Device.Dispose();
cts.Cancel();
throw new OperationCanceledException(cts.Token);
return false;
}
}
@@ -743,11 +724,10 @@ namespace Ryujinx.Ava.Systems
await UserErrorDialog.ShowUserErrorDialog(userError);
Device.Dispose();
cts.Cancel();
throw new OperationCanceledException(cts.Token);
return false;
}
// Tell the user that we installed firmware for them.
// Tell the user that we installed a firmware for them.
if (userError is UserError.NoFirmware)
{
firmwareVersion = ContentManager.GetCurrentFirmwareVersion();
@@ -767,8 +747,7 @@ namespace Ryujinx.Ava.Systems
await UserErrorDialog.ShowUserErrorDialog(userError);
Device.Dispose();
cts.Cancel();
throw new OperationCanceledException(cts.Token);
return false;
}
}
}
@@ -783,8 +762,7 @@ namespace Ryujinx.Ava.Systems
{
Device.Dispose();
cts.Cancel();
throw new OperationCanceledException(cts.Token);
return false;
}
}
else if (Directory.Exists(ApplicationPath))
@@ -804,24 +782,20 @@ namespace Ryujinx.Ava.Systems
if (!Device.LoadCart(ApplicationPath, romFsFiles[0]))
{
await ContentDialogHelper.CreateErrorDialog(
"Please specify an unpacked game directory with a valid exefs or NSO/NRO.");
Device.Dispose();
cts.Cancel();
throw new OperationCanceledException(cts.Token);
return false;
}
}
else
{
Logger.Info?.Print(LogClass.Application, "Loading as cart WITHOUT RomFS.");
if (!Device.LoadCart(ApplicationPath))
{
await ContentDialogHelper.CreateErrorDialog(
"Please specify an unpacked game directory with a valid exefs or NSO/NRO.");
Device.Dispose();
cts.Cancel();
throw new OperationCanceledException(cts.Token);
return false;
}
}
}
@@ -839,8 +813,7 @@ namespace Ryujinx.Ava.Systems
{
Device.Dispose();
cts.Cancel();
throw new OperationCanceledException(cts.Token);
return false;
}
break;
@@ -853,8 +826,7 @@ namespace Ryujinx.Ava.Systems
{
Device.Dispose();
cts.Cancel();
throw new OperationCanceledException(cts.Token);
return false;
}
break;
@@ -868,8 +840,7 @@ namespace Ryujinx.Ava.Systems
{
Device.Dispose();
cts.Cancel();
throw new OperationCanceledException(cts.Token);
return false;
}
break;
@@ -884,8 +855,7 @@ namespace Ryujinx.Ava.Systems
{
Device.Dispose();
cts.Cancel();
throw new OperationCanceledException(cts.Token);
return false;
}
}
catch (ArgumentOutOfRangeException)
@@ -894,8 +864,7 @@ namespace Ryujinx.Ava.Systems
Device.Dispose();
cts.Cancel();
throw new OperationCanceledException(cts.Token);
return false;
}
break;
@@ -904,18 +873,19 @@ namespace Ryujinx.Ava.Systems
}
else
{
Logger.Warning?.Print(LogClass.Application, "Please specify a valid XCI/NCA/NSP/PFS0/NSO/NRO file.");
Logger.Warning?.Print(LogClass.Application, "Please specify a valid XCI/NCA/NSP/PFS0/NRO file.");
Device.Dispose();
cts.Cancel();
throw new OperationCanceledException(cts.Token);
return false;
}
ApplicationLibrary.LoadAndSaveMetaData(Device.Processes.ActiveApplication.ProgramIdText,
appMetadata => appMetadata.UpdatePreGame()
);
_playTimer.Start();
return true;
}
internal void Resume()
@@ -925,7 +895,7 @@ namespace Ryujinx.Ava.Systems
_viewModel.IsPaused = false;
_playTimer.Start();
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device?.Processes.ActiveApplication, Program.Version, !ConfigurationState.Instance.ShowOldUI);
Logger.Info?.Print(LogClass.Emulation, "Emulation was resumed.");
Logger.Info?.Print(LogClass.Emulation, "Emulation was resumed");
}
internal void Pause()
@@ -935,7 +905,7 @@ namespace Ryujinx.Ava.Systems
_viewModel.IsPaused = true;
_playTimer.Stop();
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device?.Processes.ActiveApplication, Program.Version, !ConfigurationState.Instance.ShowOldUI, LocaleManager.Instance[LocaleKeys.Paused]);
Logger.Info?.Print(LogClass.Emulation, "Emulation was paused.");
Logger.Info?.Print(LogClass.Emulation, "Emulation was paused");
}
private void InitEmulatedSwitch()
@@ -1134,9 +1104,7 @@ namespace Ryujinx.Ava.Systems
// Make sure all commands in the run loop are fully executed before leaving the loop.
if (Device.Gpu.Renderer is ThreadedRenderer threaded)
{
Logger.Info?.PrintMsg(LogClass.Gpu, "Flushing threaded commands...");
threaded.FlushThreadedCommands();
Logger.Info?.PrintMsg(LogClass.Gpu, "Flushed!");
}
_gpuDoneEvent.Set();

View File

@@ -849,8 +849,7 @@ namespace Ryujinx.Ava.Systems.AppLibrary
foreach (ApplicationData installedApplication in Applications.Items)
{
// this should always exist... should...
temporary += LoadAndSaveMetaData(installedApplication.IdString).Value.TimePlayed;
temporary += LoadAndSaveMetaData(installedApplication.IdString).TimePlayed;
}
TotalTimePlayed = temporary;
@@ -1160,22 +1159,15 @@ namespace Ryujinx.Ava.Systems.AppLibrary
ApplicationCountUpdated?.Invoke(null, e);
}
public static Gommon.Optional<ApplicationMetadata> LoadAndSaveMetaData(string titleId, Action<ApplicationMetadata> modifyFunction = null)
public static ApplicationMetadata LoadAndSaveMetaData(string titleId, Action<ApplicationMetadata> modifyFunction = null)
{
if (titleId is null)
{
Logger.Warning?.PrintMsg(LogClass.Application, "Cannot save metadata because title ID is invalid.");
return null;
}
string metadataFolder = Path.Combine(AppDataManager.GamesDirPath, titleId, "gui");
string metadataFile = Path.Combine(metadataFolder, "metadata.json");
ApplicationMetadata appMetadata;
if (!File.Exists(metadataFile))
{
Logger.Info?.Print(LogClass.Application, $"Metadata file does not exist. Creating metadata for {titleId}...");
Directory.CreateDirectory(metadataFolder);
appMetadata = new ApplicationMetadata();
@@ -1185,12 +1177,12 @@ namespace Ryujinx.Ava.Systems.AppLibrary
try
{
Logger.Debug?.Print(LogClass.Application, $"Deserializing metadata for {titleId}...");
appMetadata = JsonHelper.DeserializeFromFile(metadataFile, _serializerContext.ApplicationMetadata);
}
catch (JsonException)
{
Logger.Warning?.Print(LogClass.Application, $"Failed to parse metadata json for {titleId}. Loading defaults.");
appMetadata = new ApplicationMetadata();
}

View File

@@ -82,7 +82,7 @@ namespace Ryujinx.Ava.Systems
public static void Use(Optional<string> titleId)
{
if (titleId.TryGet(out string tid) && Switch.Shared.Processes.ActiveApplication is not null)
if (titleId.TryGet(out string tid))
SwitchToPlayingState(
ApplicationLibrary.LoadAndSaveMetaData(tid),
Switch.Shared.Processes.ActiveApplication

View File

@@ -57,15 +57,8 @@ namespace Ryujinx.Ava.UI.Models
}
else
{
Gommon.Optional<ApplicationMetadata> appMetadata = ApplicationLibrary.LoadAndSaveMetaData(TitleIdString);
if (appMetadata != null)
{
Title = appMetadata.Value.Title ?? TitleIdString;
}
else
{
Title = "<INVALID>";
}
ApplicationMetadata appMetadata = ApplicationLibrary.LoadAndSaveMetaData(TitleIdString);
Title = appMetadata.Title ?? TitleIdString;
}
Task.Run(() =>

View File

@@ -1760,6 +1760,11 @@ namespace Ryujinx.Ava.UI.ViewModels
Logger.RestartTime();
SelectedIcon ??= ApplicationLibrary.GetApplicationIcon(application.Path,
ConfigurationState.Instance.System.Language, application.Id);
PrepareLoadScreen();
RendererHostControl = new RendererHost();
AppHost = new AppHost(
@@ -1773,34 +1778,18 @@ namespace Ryujinx.Ava.UI.ViewModels
UserChannelPersistence,
this,
TopLevel);
CancellationTokenSource cts = new CancellationTokenSource();
try
if (!await AppHost.LoadGuestApplication(customNacpData))
{
await AppHost.LoadGuestApplication(cts, customNacpData);
}
catch (OperationCanceledException exception)
{
Logger.Info?.Print(LogClass.Application,
"LoadGuestApplication was interrupted !!! " + exception.Message);
AppHost.DisposeContext();
AppHost = null;
return;
}
finally
{
cts.Dispose();
}
CanUpdate = false;
application.Name ??= AppHost.Device.Processes.ActiveApplication.Name;
SelectedIcon ??= ApplicationLibrary.GetApplicationIcon(application.Path,
ConfigurationState.Instance.System.Language, application.Id);
PrepareLoadScreen();
LoadHeading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.LoadingHeading, application.Name);
@@ -1822,9 +1811,9 @@ namespace Ryujinx.Ava.UI.ViewModels
RendererHostControl.Focus();
});
public static void UpdateGameMetadata(string titleId, TimeSpan playTime)
public static void UpdateGameMetadata(string titleId, TimeSpan playTime)
=> ApplicationLibrary.LoadAndSaveMetaData(titleId, appMetadata => appMetadata.UpdatePostGame(playTime));
public void RefreshFirmwareStatus()
{
SystemVersion version = null;