Compare commits

...

4 Commits

Author SHA1 Message Date
Max
6d67a86efd 443 -libarmeillure-macos (#142)
Fixes [#443](https://github.com/Ryubing/Issues/issues/433)

Reviewed-on: https://git.ryujinx.app/projects/Ryubing/pulls/142
2026-06-15 23:20:44 +00:00
LotP
e777e3f93b fix-tests (#140)
- downgrade unicorn to last working version
- update to new cp reg struct system
- remove nonexistent register (used to silently continue)
- fix partial unmap tests
    - InitializeSignalHandler() was moved out of the translator (almost 2.5 years ago), but the test code was never updated to manually call the function as it was changed to do in the real cpu context, so the tests just started failing.
    - by manually initializing the handler we no longer cause tests to fail.

Reviewed-on: https://git.ryujinx.app/projects/Ryubing/pulls/140
2026-06-15 02:25:18 +00:00
KeatonTheBot
7b19e041cb Linux: Fix remaining file/folder picker issues (#24)
I fixed the remaining Linux file picker issues after testing on Steam Deck. User profile images, mod manager, title manager, and DLC directory were still using the old file picker methods and not the helper methods. I could only apply the helper method to user profiles, but I came up with a workaround for the others.

The reason for the draft PR: I'd ideally like to fix the other three at the helper level, so maybe @greem can help with that since since he wrote the initial implementation.

Reviewed-on: https://git.ryujinx.app/projects/Ryubing/pulls/24
2026-06-15 01:44:24 +00:00
AllieNeedsSleep
e7a3c94b9c Discord RPC grammatical changes (#139)
Adjusted wording used in Discord RPC for clarity.

Co-authored-by: Allie <barstaxjolster@gmail.com>
Co-authored-by: sh0inx <randomgirlisweird@gmail.com>
Reviewed-on: https://git.ryujinx.app/projects/Ryubing/pulls/139
2026-06-14 22:13:59 +00:00
15 changed files with 93 additions and 39 deletions

View File

@@ -63,6 +63,6 @@
<PackageVersion Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.9" />
<PackageVersion Include="SPB" Version="0.0.4-build32" />
<PackageVersion Include="System.IO.Hashing" Version="9.0.15" />
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.1.3" />
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.1.0" />
</ItemGroup>
</Project>

View File

@@ -47,12 +47,14 @@ def get_new_name(
input_component = str(input_dylib_path).replace(str(input_directory), "")[1:]
return Path(os.path.join(output_directory, input_component))
def get_archs(dylib_path: Path) -> list[str]:
res = subprocess.check_output([LIPO, "-info", str(dylib_path)]).decode("utf-8")
if res.startswith("Non-fat file"):
return [res.split(":")[-1].strip()]
else:
return res.split("are:")[-1].strip().split()
def is_fat_file(dylib_path: Path) -> str:
res = subprocess.check_output([LIPO, "-info", str(dylib_path.absolute())]).decode(
"utf-8"
)
return not res.split("\n")[0].startswith("Non-fat file")
def construct_universal_dylib(
arm64_input_dylib_path: Path, x86_64_input_dylib_path: Path, output_dylib_path: Path
@@ -67,12 +69,11 @@ def construct_universal_dylib(
os.path.basename(arm64_input_dylib_path.resolve()), output_dylib_path
)
else:
arm64_archs = get_archs(arm64_input_dylib_path)
x86_64_archs = get_archs(x86_64_input_dylib_path) if x86_64_input_dylib_path.exists() else []
if "arm64" in arm64_archs and "x86_64" in arm64_archs:
shutil.copy2(arm64_input_dylib_path, output_dylib_path)
elif x86_64_archs:
if is_fat_file(arm64_input_dylib_path) or not x86_64_input_dylib_path.exists():
with open(output_dylib_path, "wb") as dst:
with open(arm64_input_dylib_path, "rb") as src:
dst.write(src.read())
else:
subprocess.check_call(
[
LIPO,

View File

@@ -53,7 +53,7 @@ namespace Ryujinx.Cpu.Signal
public SignalHandlerRangeArray Ranges;
}
static class NativeSignalHandler
public static class NativeSignalHandler
{
private static readonly nint _handlerConfig;
private static nint _signalHandlerPtr;

View File

@@ -16,15 +16,15 @@ namespace Ryujinx.Graphics.Vulkan
{
DescriptorSetLayout[] layouts = new DescriptorSetLayout[setDescriptors.Count];
bool[] updateAfterBindFlags = new bool[setDescriptors.Count];
bool isMoltenVk = gd.IsMoltenVk;
for (int setIndex = 0; setIndex < setDescriptors.Count; setIndex++)
{
ResourceDescriptorCollection rdc = setDescriptors[setIndex];
ResourceStages activeStages = ResourceStages.None;
if (isMoltenVk)
{
for (int descIndex = 0; descIndex < rdc.Descriptors.Count; descIndex++)
@@ -48,7 +48,7 @@ namespace Ryujinx.Graphics.Vulkan
// causes invalid resource errors, allow the binding on all active stages as workaround.
// https://github.com/KhronosGroup/MoltenVK/issues/1870
stages = activeStages;
}
}
layoutBindings[descIndex] = new DescriptorSetLayoutBinding
{

View File

@@ -439,7 +439,7 @@ namespace Ryujinx.Graphics.Vulkan
features2.Features.MultiViewport && !(IsMoltenVk && Vendor == Vendor.Amd), // Workaround for AMD on MoltenVK issue
featuresRobustness2.NullDescriptor || IsMoltenVk,
supportsPushDescriptors,
IsMoltenVk ? 16 : propertiesPushDescriptor.MaxPushDescriptors, // In case an old version of MoltenVK is used, apply a limit to prevent vertex explosions.
IsMoltenVk ? 16 : propertiesPushDescriptor.MaxPushDescriptors, // Prevents vertex explosions on MoltenVK.
featuresPrimitiveTopologyListRestart.PrimitiveTopologyListRestart,
featuresPrimitiveTopologyListRestart.PrimitiveTopologyPatchListRestart,
supportsTransformFeedback,

View File

@@ -1,10 +1,23 @@
using System;
using System.Runtime.InteropServices;
using UnicornEngine.Const;
namespace Ryujinx.Tests.Unicorn
{
public class UnicornAArch32 : IDisposable
{
struct UcArmCpReg
{
public uint Cp;
public uint Is64;
public uint Sec;
public uint CRn;
public uint CRm;
public uint Opc1;
public uint Opc2;
public uint Val;
}
internal readonly UnicornEngine.Unicorn Uc;
private bool _isDisposed;
@@ -38,7 +51,7 @@ namespace Ryujinx.Tests.Unicorn
public int Fpscr
{
get => (int)GetRegister(Arm.UC_ARM_REG_FPSCR) | ((int)GetRegister(Arm.UC_ARM_REG_FPSCR_NZCV));
get => (int)GetRegister(Arm.UC_ARM_REG_FPSCR);
set => SetRegister(Arm.UC_ARM_REG_FPSCR, (uint)value);
}
@@ -85,8 +98,22 @@ namespace Ryujinx.Tests.Unicorn
public UnicornAArch32()
{
Uc = new UnicornEngine.Unicorn(Common.UC_ARCH_ARM, Common.UC_MODE_LITTLE_ENDIAN);
SetRegister(Arm.UC_ARM_REG_C1_C0_2, GetRegister(Arm.UC_ARM_REG_C1_C0_2) | 0xf00000);
UcArmCpReg reg = new()
{
Cp = 15,
Is64 = 0,
Sec = 0,
CRn = 13,
Opc1 = 0,
CRm = 0,
Opc2 = 2
};
GetRegister(Arm.UC_ARM_REG_CP_REG, ref reg);
reg.Val |= 0xf00000;
SetRegister(Arm.UC_ARM_REG_CP_REG, reg);
SetRegister(Arm.UC_ARM_REG_FPEXC, 0x40000000);
}
@@ -204,6 +231,17 @@ namespace Ryujinx.Tests.Unicorn
SetVector(Arm.UC_ARM_REG_D0 + index * 2, value);
}
public void GetRegister<T>(int register, ref T obj) where T : unmanaged
{
Span<T> span = new(ref obj);
Span<byte> dataSpan = MemoryMarshal.Cast<T, byte>(span);
byte[] data = dataSpan.ToArray();
Uc.RegRead(register, data);
data.AsSpan().CopyTo(dataSpan);
}
public uint GetRegister(int register)
{
byte[] data = new byte[4];
@@ -213,6 +251,13 @@ namespace Ryujinx.Tests.Unicorn
return BitConverter.ToUInt32(data, 0);
}
public void SetRegister<T>(int register, T obj) where T : unmanaged
{
byte[] data = MemoryMarshal.Cast<T, byte>(new Span<T>(ref obj)).ToArray();
Uc.RegWrite(register, data);
}
public void SetRegister(int register, uint value)
{
byte[] data = BitConverter.GetBytes(value);

View File

@@ -7,6 +7,7 @@ using Ryujinx.Common.Memory;
using Ryujinx.Common.Memory.PartialUnmaps;
using Ryujinx.Cpu;
using Ryujinx.Cpu.Jit;
using Ryujinx.Cpu.Signal;
using Ryujinx.Memory;
using Ryujinx.Memory.Tracking;
using System;
@@ -60,6 +61,8 @@ namespace Ryujinx.Tests.Memory
new JitMemoryAllocator(),
new MockMemoryManager(),
AddressTable<ulong>.CreateForArm(true, MemoryManagerType.SoftwarePageTable));
NativeSignalHandler.InitializeSignalHandler();
}
[Test]

View File

@@ -28,14 +28,14 @@
<PublishTrimmed>true</PublishTrimmed>
<TrimMode>partial</TrimMode>
</PropertyGroup>
<!--
FluentAvalonia, used in the Avalonia UI, requires a workaround for the json serializer used internally when using .NET 8+ System.Text.Json.
See:
https://github.com/amwx/FluentAvalonia/issues/481
https://devblogs.microsoft.com/dotnet/system-text-json-in-dotnet-8/
-->
<PropertyGroup>
<JsonSerializerIsReflectionEnabledByDefault>true</JsonSerializerIsReflectionEnabledByDefault>
</PropertyGroup>
@@ -73,7 +73,7 @@
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" />
<PackageReference Include="SPB" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Ryujinx.Graphics.RenderDocApi\Ryujinx.Graphics.RenderDocApi.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.Vulkan/Ryujinx.Graphics.Vulkan.csproj" />

View File

@@ -46,7 +46,7 @@ namespace Ryujinx.Ava.Systems
LargeImageText = TruncateToByteLength(_description)
},
Details = "Main Menu",
State = "Idling",
State = "Waiting",
Timestamps = EmulatorStartedAt
};

View File

@@ -1069,7 +1069,6 @@ namespace Ryujinx.Ava.Systems.PlayReport
_ => FormattedValue.ForceReset
};
private static FormattedValue TomodachiLifeLTD_Status(SingleValue value)
{
MessagePackObject messagePackObject = value.Matched.PackedValue;
@@ -1077,8 +1076,9 @@ namespace Ryujinx.Ava.Systems.PlayReport
int miiCount = messagePackObjectDictionary["MiiNum"].AsInt32();
int fountainLevel = messagePackObjectDictionary["FountainLevel"].AsInt32();
return $"Looking after {"Mii".ToQuantity(miiCount)}, with an island level of {fountainLevel}";
// Fountain Level should be kept consistent throughout code, so I basically made sure of it
return $"Looking after {"Mii".ToQuantity(miiCount)}, with a fountain level of {fountainLevel}";
}
private static FormattedValue AnimalCrossingNewHorizons_AppCommon(SingleValue value)

View File

@@ -13,6 +13,7 @@ using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using static Ryujinx.Ava.Utilities.StorageProviderExtensions;
namespace Ryujinx.Ava.UI.ViewModels
{
@@ -128,7 +129,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public async void Add()
{
IReadOnlyList<IStorageFile> result = await _storageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
IReadOnlyList<IStorageFile> result = await CoreDumpable(() => _storageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{
Title = LocaleManager.Instance[LocaleKeys.SelectDlcDialogTitle],
AllowMultiple = true,
@@ -141,7 +142,7 @@ namespace Ryujinx.Ava.UI.ViewModels
MimeTypes = ["application/x-nx-nsp"],
},
},
});
}));
int totalDlcAdded = 0;
foreach (IStorageFile file in result)

View File

@@ -17,6 +17,7 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using static Ryujinx.Ava.Utilities.StorageProviderExtensions;
namespace Ryujinx.Ava.UI.ViewModels
{
@@ -288,11 +289,11 @@ namespace Ryujinx.Ava.UI.ViewModels
public async void Add()
{
IReadOnlyList<IStorageFolder> result = await _storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
IReadOnlyList<IStorageFolder> result = await CoreDumpable(() => _storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
{
Title = LocaleManager.Instance[LocaleKeys.SelectModDialogTitle],
AllowMultiple = true,
});
}));
foreach (IStorageFolder folder in result)
{

View File

@@ -11,6 +11,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using static Ryujinx.Ava.Utilities.StorageProviderExtensions;
namespace Ryujinx.Ava.UI.ViewModels
{
@@ -148,7 +149,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public async Task Add()
{
IReadOnlyList<IStorageFile> result = await _storageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
IReadOnlyList<IStorageFile> result = await CoreDumpable(() => _storageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{
AllowMultiple = true,
FileTypeFilter = new List<FilePickerFileType>
@@ -160,7 +161,7 @@ namespace Ryujinx.Ava.UI.ViewModels
MimeTypes = ["application/x-nx-nsp"],
},
},
});
}));
int totalUpdatesAdded = 0;
foreach (IStorageFile file in result)

View File

@@ -4,10 +4,12 @@ using Avalonia.Platform.Storage;
using Avalonia.VisualTree;
using FluentAvalonia.UI.Controls;
using FluentAvalonia.UI.Navigation;
using Gommon;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Controls;
using Ryujinx.Ava.UI.Models;
using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Ava.Utilities;
using Ryujinx.HLE.FileSystem;
using SkiaSharp;
using System.Collections.Generic;
@@ -62,7 +64,7 @@ namespace Ryujinx.Ava.UI.Views.User
private async void Import_OnClick(object sender, RoutedEventArgs e)
{
IReadOnlyList<IStorageFile> result = await ((Window)this.GetVisualRoot()!).StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
Optional<IStorageFile> result = await ((Window)this.GetVisualRoot()!).StorageProvider.OpenSingleFilePickerAsync(new FilePickerOpenOptions
{
AllowMultiple = false,
FileTypeFilter = new List<FilePickerFileType>
@@ -76,9 +78,9 @@ namespace Ryujinx.Ava.UI.Views.User
},
});
if (result.Count > 0)
if (result.HasValue)
{
_profile.Image = ProcessProfileImage(File.ReadAllBytes(result[0].Path.LocalPath));
_profile.Image = ProcessProfileImage(File.ReadAllBytes(result.Value.Path.LocalPath));
_parent.GoBack();
}
}

View File

@@ -29,7 +29,7 @@ namespace Ryujinx.Ava.Utilities
.Then(files => files.Count > 0 ? Optional.Of(files) : default);
}
private static async Task<T> CoreDumpable<T>(Func<Task<T>> picker)
public static async Task<T> CoreDumpable<T>(Func<Task<T>> picker)
{
OsUtils.SetCoreDumpable(true);
try