mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2026-05-02 19:35:46 +00:00
Compare commits
9 Commits
Canary-1.3
...
Canary-1.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c9c4ed67b9 | ||
|
|
44d77f8e59 | ||
|
|
bd11cbde08 | ||
|
|
f749cf90b6 | ||
|
|
1b1ceeaa11 | ||
|
|
3f9d37da83 | ||
|
|
0c0b6404b1 | ||
|
|
47c0180ba4 | ||
|
|
8705fabdb0 |
35
.forgejo/renovate.json
Normal file
35
.forgejo/renovate.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"renovate/config"
|
||||
],
|
||||
"enabledManagers": ["nuget", "github-actions"],
|
||||
"packageRules": [
|
||||
{
|
||||
// require approval for *all* NuGet package updates, not just major versions.
|
||||
"matchDepTypes": "nuget",
|
||||
"dependencyDashboardApproval": true
|
||||
},
|
||||
{
|
||||
// Ignore Gommon for automatic updates. I make breaking changes on minor updates not infrequently.
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"description": "group Svg.Controls packages",
|
||||
"extends": ["renovate/config//groups/svgcontrols.json"],
|
||||
"groupName": "Svg.Controls"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -35,9 +35,9 @@ jobs:
|
||||
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-dotnet@v4
|
||||
- uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
@@ -94,7 +94,7 @@ jobs:
|
||||
shell: bash
|
||||
|
||||
- name: Upload Ryujinx Windows artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: ryujinx-${{ matrix.configuration }}-${{ steps.version_info.outputs.result }}+${{ steps.version_info.outputs.git_short_hash }}-${{ matrix.platform.zip_os_name }}
|
||||
path: artifact
|
||||
@@ -133,7 +133,7 @@ jobs:
|
||||
shell: bash
|
||||
|
||||
- name: Upload Ryujinx AppImage artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
if: forgejo.event_name == 'pull_request' && contains(matrix.platform.name, 'linux')
|
||||
with:
|
||||
name: ryujinx-${{ matrix.configuration }}-${{ steps.version_info.outputs.result }}+${{ steps.version_info.outputs.git_short_hash }}-${{ matrix.platform.zip_os_name }}-AppImage
|
||||
@@ -148,9 +148,9 @@ jobs:
|
||||
configuration: [ Release ]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-dotnet@v4
|
||||
- uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
@@ -197,7 +197,7 @@ jobs:
|
||||
shell: bash
|
||||
|
||||
- name: Upload Ryujinx artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: ryujinx-${{ matrix.configuration }}-${{ steps.version_info.outputs.result }}+${{ steps.version_info.outputs.git_short_hash }}-macos_universal
|
||||
path: "publish/*.tar.gz"
|
||||
|
||||
@@ -217,7 +217,7 @@ jobs:
|
||||
- macos_release
|
||||
- release
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Install GLI
|
||||
uses: actions/setup-gli@v1
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
steps:
|
||||
# Grab sources to get latest labeler.yml
|
||||
- name: Fetch sources
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
# Ensure we pin the source origin as pull_request_target run under forks.
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -212,7 +212,7 @@ jobs:
|
||||
- macos_release
|
||||
- release
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Install GLI
|
||||
uses: actions/setup-gli@v1
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/github-script@v6
|
||||
- uses: actions/github-script@v9
|
||||
with:
|
||||
script: |
|
||||
const {owner, repo} = context.repo;
|
||||
|
||||
@@ -9,45 +9,49 @@
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.14" />
|
||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.3.14" />
|
||||
<PackageVersion Include="SharpCompress" Version="0.47.4" />
|
||||
<PackageVersion Include="Svg.Controls.Avalonia" Version="11.3.9.4" />
|
||||
<PackageVersion Include="Svg.Controls.Skia.Avalonia" Version="11.3.9.4" />
|
||||
<PackageVersion Include="Svg.Controls.Avalonia" Version="11.3.9.5" />
|
||||
<PackageVersion Include="Svg.Controls.Skia.Avalonia" Version="11.3.9.5" />
|
||||
<PackageVersion Include="Microsoft.Build.Framework" Version="17.11.4" />
|
||||
<PackageVersion Include="Microsoft.Build.Utilities.Core" Version="17.12.6" />
|
||||
<PackageVersion Include="Microsoft.Build.Utilities.Core" Version="17.12.50" />
|
||||
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageVersion Include="Projektanker.Icons.Avalonia" Version="9.6.2" />
|
||||
<PackageVersion Include="Projektanker.Icons.Avalonia.FontAwesome" Version="9.6.2" />
|
||||
<PackageVersion Include="Projektanker.Icons.Avalonia.MaterialDesign" Version="9.6.2" />
|
||||
<PackageVersion Include="Ryujinx.SDL3-CS" Version="2026.501.0" />
|
||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
||||
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.2" />
|
||||
<PackageVersion Include="Concentus" Version="2.2.2" />
|
||||
<PackageVersion Include="DiscordRichPresence" Version="1.6.1.70" />
|
||||
<PackageVersion Include="DynamicData" Version="9.4.1" />
|
||||
<PackageVersion Include="FluentAvaloniaUI" Version="2.5.0" />
|
||||
<PackageVersion Include="DynamicData" Version="9.4.31" />
|
||||
<PackageVersion Include="FluentAvaloniaUI" Version="2.5.1" />
|
||||
<PackageVersion Include="Humanizer" Version="2.14.1" />
|
||||
<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.3.0" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.17.0" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
|
||||
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
||||
<PackageVersion Include="NetCoreServer" Version="8.0.7" />
|
||||
<PackageVersion Include="NUnit" Version="3.13.3" />
|
||||
<PackageVersion Include="NUnit3TestAdapter" Version="4.1.0" />
|
||||
<PackageVersion Include="OpenTK.Core" Version="4.8.2" />
|
||||
<PackageVersion Include="OpenTK.Graphics" Version="4.8.2" />
|
||||
<PackageVersion Include="OpenTK.Audio.OpenAL" Version="4.8.2" />
|
||||
<PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.8.2" />
|
||||
<PackageVersion Include="NUnit" Version="3.14.0" />
|
||||
<PackageVersion Include="NUnit3TestAdapter" Version="4.6.0" />
|
||||
<PackageVersion Include="OpenTK.Core" Version="4.9.4" />
|
||||
<PackageVersion Include="OpenTK.Graphics" Version="4.9.4" />
|
||||
<!-- OpenTk.Audio.OpenAL has moved to OpenTk.Audio -->
|
||||
<!--<PackageVersion Include="OpenTK.Audio" Version="5.0.0-pre.15" />-->
|
||||
<PackageVersion Include="OpenTK.Audio.OpenAL" Version="4.9.4" />
|
||||
<PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.9.4" />
|
||||
<PackageVersion Include="Open.NAT.Core" Version="2.1.0.5" />
|
||||
<PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.AllArch" Version="6.1.2-build3" />
|
||||
<!-- Ryujinx.Audio.OpenAL.Dependencies is from the original project, last updated 12/30/20 -->
|
||||
<!--<PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" />-->
|
||||
<PackageVersion Include="Ryujinx.Audio.OpenAL" Version="1.25.1" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.AllArch" Version="6.1.4-build6" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
||||
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.129" />
|
||||
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.133" />
|
||||
<PackageVersion Include="Ryujinx.UpdateClient" Version="2.0.6" />
|
||||
<PackageVersion Include="Ryujinx.Systems.Update.Common" Version="2.0.6" />
|
||||
<PackageVersion Include="Gommon" Version="2.8.0.1" />
|
||||
<PackageVersion Include="Gommon" Version="2.8.1.2" />
|
||||
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
||||
<PackageVersion Include="Sep" Version="0.11.1" />
|
||||
<PackageVersion Include="Sep" Version="0.13.0" />
|
||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.22.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.22.0" />
|
||||
@@ -55,7 +59,7 @@
|
||||
<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.2" />
|
||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
||||
<PackageVersion Include="System.IO.Hashing" Version="9.0.15" />
|
||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.1.3" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -17,7 +17,8 @@ namespace Ryujinx.Cpu.LightningJit.Cache
|
||||
private static readonly int _pageMask = _pageSize - 1;
|
||||
|
||||
private const int CodeAlignment = 4; // Bytes.
|
||||
private const int CacheSize = 256 * 1024 * 1024;
|
||||
// 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 static JitCacheInvalidation _jitCacheInvalidator;
|
||||
|
||||
@@ -33,6 +34,14 @@ 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)
|
||||
{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
@@ -114,7 +115,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
cbs.AddDependant(this);
|
||||
|
||||
// We need to add a dependency on the command buffer to all objects this object
|
||||
// references aswell.
|
||||
// references as well.
|
||||
if (_referencedObjs != null)
|
||||
{
|
||||
for (int i = 0; i < _referencedObjs.Length; i++)
|
||||
@@ -176,6 +177,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
}
|
||||
|
||||
// This can somehow become -1.
|
||||
// Logger.Info?.PrintMsg(LogClass.Gpu, $"_referenceCount: {_referenceCount}");
|
||||
Debug.Assert(_referenceCount >= 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ 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;
|
||||
|
||||
@@ -27,10 +28,15 @@ 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?");
|
||||
@@ -144,7 +150,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))
|
||||
|
||||
@@ -4,7 +4,6 @@ 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
|
||||
@@ -52,6 +51,7 @@ 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,8 +71,15 @@ 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;
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
<PackageReference Include="Projektanker.Icons.Avalonia.FontAwesome" />
|
||||
<PackageReference Include="Projektanker.Icons.Avalonia.MaterialDesign" />
|
||||
<PackageReference Include="OpenTK.Core" />
|
||||
<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.Audio.OpenAL" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'linux-arm64' AND '$(RuntimeIdentifier)' != 'osx-x64' AND '$(RuntimeIdentifier)' != 'osx-arm64'" />
|
||||
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies.AllArch" />
|
||||
<PackageReference Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'linux-arm64' AND '$(RuntimeIdentifier)' != 'win-x64' AND '$(RuntimeIdentifier)' != 'win-arm64'" />
|
||||
<PackageReference Include="Ryujinx.UpdateClient" />
|
||||
|
||||
@@ -62,7 +62,7 @@ using VSyncMode = Ryujinx.Common.Configuration.VSyncMode;
|
||||
|
||||
namespace Ryujinx.Ava.Systems
|
||||
{
|
||||
internal class AppHost
|
||||
internal class AppHost : IDisposable
|
||||
{
|
||||
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,27 +611,40 @@ 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);
|
||||
}
|
||||
|
||||
private void Dispose()
|
||||
// MUST be public to inherit from IDisposable
|
||||
public 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;
|
||||
@@ -646,7 +659,6 @@ namespace Ryujinx.Ava.Systems
|
||||
_topLevel.PointerExited -= TopLevel_PointerExited;
|
||||
|
||||
_gpuCancellationTokenSource.Cancel();
|
||||
_gpuCancellationTokenSource.Dispose();
|
||||
|
||||
_chrono.Stop();
|
||||
_playTimer.Stop();
|
||||
@@ -672,6 +684,12 @@ namespace Ryujinx.Ava.Systems
|
||||
}
|
||||
else
|
||||
{
|
||||
// No use waiting on something that never started work
|
||||
if (_renderingStarted)
|
||||
{
|
||||
Device.Gpu.WaitUntilGpuReady();
|
||||
}
|
||||
|
||||
Device.DisposeGpu();
|
||||
}
|
||||
}
|
||||
@@ -686,7 +704,7 @@ namespace Ryujinx.Ava.Systems
|
||||
_cursorState = CursorStates.ForceChangeCursor;
|
||||
}
|
||||
|
||||
public async Task<bool> LoadGuestApplication(BlitStruct<ApplicationControlProperty>? customNacpData = null)
|
||||
public async Task LoadGuestApplication(CancellationTokenSource cts, BlitStruct<ApplicationControlProperty>? customNacpData = null)
|
||||
{
|
||||
DiscordIntegrationModule.GuestAppStartedAt = Timestamps.Now;
|
||||
|
||||
@@ -715,7 +733,8 @@ namespace Ryujinx.Ava.Systems
|
||||
await UserErrorDialog.ShowUserErrorDialog(userError);
|
||||
Device.Dispose();
|
||||
|
||||
return false;
|
||||
cts.Cancel();
|
||||
throw new OperationCanceledException(cts.Token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -724,10 +743,11 @@ namespace Ryujinx.Ava.Systems
|
||||
await UserErrorDialog.ShowUserErrorDialog(userError);
|
||||
Device.Dispose();
|
||||
|
||||
return false;
|
||||
cts.Cancel();
|
||||
throw new OperationCanceledException(cts.Token);
|
||||
}
|
||||
|
||||
// Tell the user that we installed a firmware for them.
|
||||
// Tell the user that we installed firmware for them.
|
||||
if (userError is UserError.NoFirmware)
|
||||
{
|
||||
firmwareVersion = ContentManager.GetCurrentFirmwareVersion();
|
||||
@@ -747,7 +767,8 @@ namespace Ryujinx.Ava.Systems
|
||||
await UserErrorDialog.ShowUserErrorDialog(userError);
|
||||
Device.Dispose();
|
||||
|
||||
return false;
|
||||
cts.Cancel();
|
||||
throw new OperationCanceledException(cts.Token);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -762,7 +783,8 @@ namespace Ryujinx.Ava.Systems
|
||||
{
|
||||
Device.Dispose();
|
||||
|
||||
return false;
|
||||
cts.Cancel();
|
||||
throw new OperationCanceledException(cts.Token);
|
||||
}
|
||||
}
|
||||
else if (Directory.Exists(ApplicationPath))
|
||||
@@ -782,20 +804,24 @@ 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();
|
||||
|
||||
return false;
|
||||
cts.Cancel();
|
||||
throw new OperationCanceledException(cts.Token);
|
||||
}
|
||||
}
|
||||
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();
|
||||
|
||||
return false;
|
||||
cts.Cancel();
|
||||
throw new OperationCanceledException(cts.Token);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -813,7 +839,8 @@ namespace Ryujinx.Ava.Systems
|
||||
{
|
||||
Device.Dispose();
|
||||
|
||||
return false;
|
||||
cts.Cancel();
|
||||
throw new OperationCanceledException(cts.Token);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -826,7 +853,8 @@ namespace Ryujinx.Ava.Systems
|
||||
{
|
||||
Device.Dispose();
|
||||
|
||||
return false;
|
||||
cts.Cancel();
|
||||
throw new OperationCanceledException(cts.Token);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -840,7 +868,8 @@ namespace Ryujinx.Ava.Systems
|
||||
{
|
||||
Device.Dispose();
|
||||
|
||||
return false;
|
||||
cts.Cancel();
|
||||
throw new OperationCanceledException(cts.Token);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -855,7 +884,8 @@ namespace Ryujinx.Ava.Systems
|
||||
{
|
||||
Device.Dispose();
|
||||
|
||||
return false;
|
||||
cts.Cancel();
|
||||
throw new OperationCanceledException(cts.Token);
|
||||
}
|
||||
}
|
||||
catch (ArgumentOutOfRangeException)
|
||||
@@ -864,7 +894,8 @@ namespace Ryujinx.Ava.Systems
|
||||
|
||||
Device.Dispose();
|
||||
|
||||
return false;
|
||||
cts.Cancel();
|
||||
throw new OperationCanceledException(cts.Token);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -873,19 +904,18 @@ namespace Ryujinx.Ava.Systems
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, "Please specify a valid XCI/NCA/NSP/PFS0/NRO file.");
|
||||
Logger.Warning?.Print(LogClass.Application, "Please specify a valid XCI/NCA/NSP/PFS0/NSO/NRO file.");
|
||||
|
||||
Device.Dispose();
|
||||
|
||||
return false;
|
||||
cts.Cancel();
|
||||
throw new OperationCanceledException(cts.Token);
|
||||
}
|
||||
|
||||
ApplicationLibrary.LoadAndSaveMetaData(Device.Processes.ActiveApplication.ProgramIdText,
|
||||
appMetadata => appMetadata.UpdatePreGame()
|
||||
);
|
||||
_playTimer.Start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal void Resume()
|
||||
@@ -895,7 +925,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()
|
||||
@@ -905,7 +935,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()
|
||||
@@ -1104,7 +1134,9 @@ 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();
|
||||
|
||||
@@ -849,7 +849,8 @@ namespace Ryujinx.Ava.Systems.AppLibrary
|
||||
|
||||
foreach (ApplicationData installedApplication in Applications.Items)
|
||||
{
|
||||
temporary += LoadAndSaveMetaData(installedApplication.IdString).TimePlayed;
|
||||
// this should always exist... should...
|
||||
temporary += LoadAndSaveMetaData(installedApplication.IdString).Value.TimePlayed;
|
||||
}
|
||||
|
||||
TotalTimePlayed = temporary;
|
||||
@@ -1159,15 +1160,22 @@ namespace Ryujinx.Ava.Systems.AppLibrary
|
||||
ApplicationCountUpdated?.Invoke(null, e);
|
||||
}
|
||||
|
||||
public static ApplicationMetadata LoadAndSaveMetaData(string titleId, Action<ApplicationMetadata> modifyFunction = null)
|
||||
public static Gommon.Optional<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();
|
||||
@@ -1177,12 +1185,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();
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace Ryujinx.Ava.Systems
|
||||
|
||||
public static void Use(Optional<string> titleId)
|
||||
{
|
||||
if (titleId.TryGet(out string tid))
|
||||
if (titleId.TryGet(out string tid) && Switch.Shared.Processes.ActiveApplication is not null)
|
||||
SwitchToPlayingState(
|
||||
ApplicationLibrary.LoadAndSaveMetaData(tid),
|
||||
Switch.Shared.Processes.ActiveApplication
|
||||
|
||||
@@ -57,8 +57,15 @@ namespace Ryujinx.Ava.UI.Models
|
||||
}
|
||||
else
|
||||
{
|
||||
ApplicationMetadata appMetadata = ApplicationLibrary.LoadAndSaveMetaData(TitleIdString);
|
||||
Title = appMetadata.Title ?? TitleIdString;
|
||||
Gommon.Optional<ApplicationMetadata> appMetadata = ApplicationLibrary.LoadAndSaveMetaData(TitleIdString);
|
||||
if (appMetadata != null)
|
||||
{
|
||||
Title = appMetadata.Value.Title ?? TitleIdString;
|
||||
}
|
||||
else
|
||||
{
|
||||
Title = "<INVALID>";
|
||||
}
|
||||
}
|
||||
|
||||
Task.Run(() =>
|
||||
|
||||
@@ -1760,11 +1760,6 @@ 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(
|
||||
@@ -1778,18 +1773,34 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
UserChannelPersistence,
|
||||
this,
|
||||
TopLevel);
|
||||
|
||||
CancellationTokenSource cts = new CancellationTokenSource();
|
||||
|
||||
if (!await AppHost.LoadGuestApplication(customNacpData))
|
||||
try
|
||||
{
|
||||
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);
|
||||
|
||||
@@ -1811,9 +1822,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;
|
||||
|
||||
Reference in New Issue
Block a user