Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
7969fb6bba | ||
![]() |
4a4b11871e | ||
![]() |
e85ee673b1 | ||
![]() |
42f22fe5d7 |
@@ -20,7 +20,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="7.6.2" />
|
||||
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.0.1" />
|
||||
<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" />
|
||||
|
@@ -1,51 +0,0 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.Common.Memory
|
||||
{
|
||||
public partial class ByteMemoryPool
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a <see cref="IMemoryOwner{Byte}"/> that wraps an array rented from
|
||||
/// <see cref="ArrayPool{Byte}.Shared"/> and exposes it as <see cref="Memory{Byte}"/>
|
||||
/// with a length of the requested size.
|
||||
/// </summary>
|
||||
private sealed class ByteMemoryPoolBuffer : IMemoryOwner<byte>
|
||||
{
|
||||
private byte[] _array;
|
||||
private readonly int _length;
|
||||
|
||||
public ByteMemoryPoolBuffer(int length)
|
||||
{
|
||||
_array = ArrayPool<byte>.Shared.Rent(length);
|
||||
_length = length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="Memory{Byte}"/> belonging to this owner.
|
||||
/// </summary>
|
||||
public Memory<byte> Memory
|
||||
{
|
||||
get
|
||||
{
|
||||
byte[] array = _array;
|
||||
|
||||
ObjectDisposedException.ThrowIf(array is null, this);
|
||||
|
||||
return new Memory<byte>(array, 0, _length);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
var array = Interlocked.Exchange(ref _array, null);
|
||||
|
||||
if (array != null)
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(array);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,106 +0,0 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
|
||||
namespace Ryujinx.Common.Memory
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a pool of re-usable byte array instances.
|
||||
/// </summary>
|
||||
public static partial class ByteMemoryPool
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the maximum buffer size supported by this pool.
|
||||
/// </summary>
|
||||
public static int MaxBufferSize => Array.MaxLength;
|
||||
|
||||
/// <summary>
|
||||
/// Rents a byte memory buffer from <see cref="ArrayPool{Byte}.Shared"/>.
|
||||
/// The buffer may contain data from a prior use.
|
||||
/// </summary>
|
||||
/// <param name="length">The buffer's required length in bytes</param>
|
||||
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public static IMemoryOwner<byte> Rent(long length)
|
||||
=> RentImpl(checked((int)length));
|
||||
|
||||
/// <summary>
|
||||
/// Rents a byte memory buffer from <see cref="ArrayPool{Byte}.Shared"/>.
|
||||
/// The buffer may contain data from a prior use.
|
||||
/// </summary>
|
||||
/// <param name="length">The buffer's required length in bytes</param>
|
||||
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public static IMemoryOwner<byte> Rent(ulong length)
|
||||
=> RentImpl(checked((int)length));
|
||||
|
||||
/// <summary>
|
||||
/// Rents a byte memory buffer from <see cref="ArrayPool{Byte}.Shared"/>.
|
||||
/// The buffer may contain data from a prior use.
|
||||
/// </summary>
|
||||
/// <param name="length">The buffer's required length in bytes</param>
|
||||
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public static IMemoryOwner<byte> Rent(int length)
|
||||
=> RentImpl(length);
|
||||
|
||||
/// <summary>
|
||||
/// Rents a byte memory buffer from <see cref="ArrayPool{Byte}.Shared"/>.
|
||||
/// The buffer's contents are cleared (set to all 0s) before returning.
|
||||
/// </summary>
|
||||
/// <param name="length">The buffer's required length in bytes</param>
|
||||
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public static IMemoryOwner<byte> RentCleared(long length)
|
||||
=> RentCleared(checked((int)length));
|
||||
|
||||
/// <summary>
|
||||
/// Rents a byte memory buffer from <see cref="ArrayPool{Byte}.Shared"/>.
|
||||
/// The buffer's contents are cleared (set to all 0s) before returning.
|
||||
/// </summary>
|
||||
/// <param name="length">The buffer's required length in bytes</param>
|
||||
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public static IMemoryOwner<byte> RentCleared(ulong length)
|
||||
=> RentCleared(checked((int)length));
|
||||
|
||||
/// <summary>
|
||||
/// Rents a byte memory buffer from <see cref="ArrayPool{Byte}.Shared"/>.
|
||||
/// The buffer's contents are cleared (set to all 0s) before returning.
|
||||
/// </summary>
|
||||
/// <param name="length">The buffer's required length in bytes</param>
|
||||
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public static IMemoryOwner<byte> RentCleared(int length)
|
||||
{
|
||||
var buffer = RentImpl(length);
|
||||
|
||||
buffer.Memory.Span.Clear();
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies <paramref name="buffer"/> into a newly rented byte memory buffer.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The byte buffer to copy</param>
|
||||
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory with <paramref name="buffer"/> copied to it</returns>
|
||||
public static IMemoryOwner<byte> RentCopy(ReadOnlySpan<byte> buffer)
|
||||
{
|
||||
var copy = RentImpl(buffer.Length);
|
||||
|
||||
buffer.CopyTo(copy.Memory.Span);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
private static ByteMemoryPoolBuffer RentImpl(int length)
|
||||
{
|
||||
if ((uint)length > Array.MaxLength)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(length), length, null);
|
||||
}
|
||||
|
||||
return new ByteMemoryPoolBuffer(length);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
@@ -42,14 +42,14 @@ namespace Ryujinx.Common
|
||||
return StreamUtils.StreamToBytes(stream);
|
||||
}
|
||||
|
||||
public static IMemoryOwner<byte> ReadFileToRentedMemory(string filename)
|
||||
public static MemoryOwner<byte> ReadFileToRentedMemory(string filename)
|
||||
{
|
||||
var (assembly, path) = ResolveManifestPath(filename);
|
||||
|
||||
return ReadFileToRentedMemory(assembly, path);
|
||||
}
|
||||
|
||||
public static IMemoryOwner<byte> ReadFileToRentedMemory(Assembly assembly, string filename)
|
||||
public static MemoryOwner<byte> ReadFileToRentedMemory(Assembly assembly, string filename)
|
||||
{
|
||||
using var stream = GetStream(assembly, filename);
|
||||
|
||||
|
@@ -1,6 +1,5 @@
|
||||
using Microsoft.IO;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System.Buffers;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -16,7 +15,7 @@ namespace Ryujinx.Common.Utilities
|
||||
return output.ToArray();
|
||||
}
|
||||
|
||||
public static IMemoryOwner<byte> StreamToRentedMemory(Stream input)
|
||||
public static MemoryOwner<byte> StreamToRentedMemory(Stream input)
|
||||
{
|
||||
if (input is MemoryStream inputMemoryStream)
|
||||
{
|
||||
@@ -26,9 +25,9 @@ namespace Ryujinx.Common.Utilities
|
||||
{
|
||||
long bytesExpected = input.Length;
|
||||
|
||||
IMemoryOwner<byte> ownedMemory = ByteMemoryPool.Rent(bytesExpected);
|
||||
MemoryOwner<byte> ownedMemory = MemoryOwner<byte>.Rent(checked((int)bytesExpected));
|
||||
|
||||
var destSpan = ownedMemory.Memory.Span;
|
||||
var destSpan = ownedMemory.Span;
|
||||
|
||||
int totalBytesRead = 0;
|
||||
|
||||
@@ -66,14 +65,14 @@ namespace Ryujinx.Common.Utilities
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
private static IMemoryOwner<byte> MemoryStreamToRentedMemory(MemoryStream input)
|
||||
private static MemoryOwner<byte> MemoryStreamToRentedMemory(MemoryStream input)
|
||||
{
|
||||
input.Position = 0;
|
||||
|
||||
IMemoryOwner<byte> ownedMemory = ByteMemoryPool.Rent(input.Length);
|
||||
MemoryOwner<byte> ownedMemory = MemoryOwner<byte>.Rent(checked((int)input.Length));
|
||||
|
||||
// Discard the return value because we assume reading a MemoryStream always succeeds completely.
|
||||
_ = input.Read(ownedMemory.Memory.Span);
|
||||
_ = input.Read(ownedMemory.Span);
|
||||
|
||||
return ownedMemory;
|
||||
}
|
||||
|
@@ -303,9 +303,9 @@ namespace Ryujinx.Cpu.Jit
|
||||
}
|
||||
else
|
||||
{
|
||||
IMemoryOwner<byte> memoryOwner = ByteMemoryPool.Rent(size);
|
||||
MemoryOwner<byte> memoryOwner = MemoryOwner<byte>.Rent(size);
|
||||
|
||||
Read(va, memoryOwner.Memory.Span);
|
||||
Read(va, memoryOwner.Span);
|
||||
|
||||
return new WritableRegion(this, va, memoryOwner);
|
||||
}
|
||||
|
@@ -4,6 +4,22 @@ namespace Ryujinx.Memory.Range
|
||||
{
|
||||
MultiRange Range { get; }
|
||||
|
||||
ulong BaseAddress => Range.GetSubRange(0).Address;
|
||||
ulong BaseAddress
|
||||
{
|
||||
get
|
||||
{
|
||||
for (int index = 0; index < Range.Count; index++)
|
||||
{
|
||||
MemoryRange subRange = Range.GetSubRange(index);
|
||||
|
||||
if (!MemoryRange.IsInvalid(ref subRange))
|
||||
{
|
||||
return subRange.Address;
|
||||
}
|
||||
}
|
||||
|
||||
return MemoryRange.InvalidAddress;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -5,6 +5,11 @@ namespace Ryujinx.Memory.Range
|
||||
/// </summary>
|
||||
public readonly record struct MemoryRange
|
||||
{
|
||||
/// <summary>
|
||||
/// Special address value used to indicate than an address is invalid.
|
||||
/// </summary>
|
||||
internal const ulong InvalidAddress = ulong.MaxValue;
|
||||
|
||||
/// <summary>
|
||||
/// An empty memory range, with a null address and zero size.
|
||||
/// </summary>
|
||||
@@ -58,13 +63,24 @@ namespace Ryujinx.Memory.Range
|
||||
return thisAddress < otherEndAddress && otherAddress < thisEndAddress;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a given sub-range of memory is invalid.
|
||||
/// Those are used to represent unmapped memory regions (holes in the region mapping).
|
||||
/// </summary>
|
||||
/// <param name="subRange">Memory range to check</param>
|
||||
/// <returns>True if the memory range is considered invalid, false otherwise</returns>
|
||||
internal static bool IsInvalid(ref MemoryRange subRange)
|
||||
{
|
||||
return subRange.Address == InvalidAddress;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string summary of the memory range.
|
||||
/// </summary>
|
||||
/// <returns>A string summary of the memory range</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
if (Address == ulong.MaxValue)
|
||||
if (Address == InvalidAddress)
|
||||
{
|
||||
return $"[Unmapped 0x{Size:X}]";
|
||||
}
|
||||
|
@@ -30,7 +30,7 @@ namespace Ryujinx.Memory.Range
|
||||
{
|
||||
var subrange = range.GetSubRange(i);
|
||||
|
||||
if (IsInvalid(ref subrange))
|
||||
if (MemoryRange.IsInvalid(ref subrange))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -56,7 +56,7 @@ namespace Ryujinx.Memory.Range
|
||||
{
|
||||
var subrange = range.GetSubRange(i);
|
||||
|
||||
if (IsInvalid(ref subrange))
|
||||
if (MemoryRange.IsInvalid(ref subrange))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -99,7 +99,7 @@ namespace Ryujinx.Memory.Range
|
||||
{
|
||||
var subrange = range.GetSubRange(i);
|
||||
|
||||
if (IsInvalid(ref subrange))
|
||||
if (MemoryRange.IsInvalid(ref subrange))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -142,17 +142,6 @@ namespace Ryujinx.Memory.Range
|
||||
return overlapCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a given sub-range of memory is invalid.
|
||||
/// Those are used to represent unmapped memory regions (holes in the region mapping).
|
||||
/// </summary>
|
||||
/// <param name="subRange">Memory range to checl</param>
|
||||
/// <returns>True if the memory range is considered invalid, false otherwise</returns>
|
||||
private static bool IsInvalid(ref MemoryRange subRange)
|
||||
{
|
||||
return subRange.Address == ulong.MaxValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all items on the list starting at the specified memory address.
|
||||
/// </summary>
|
||||
|
@@ -130,9 +130,9 @@ namespace Ryujinx.Memory
|
||||
}
|
||||
else
|
||||
{
|
||||
IMemoryOwner<byte> memoryOwner = ByteMemoryPool.Rent(size);
|
||||
MemoryOwner<byte> memoryOwner = MemoryOwner<byte>.Rent(size);
|
||||
|
||||
Read(va, memoryOwner.Memory.Span);
|
||||
Read(va, memoryOwner.Span);
|
||||
|
||||
return new WritableRegion(this, va, memoryOwner);
|
||||
}
|
||||
|
@@ -21,7 +21,7 @@ namespace Ryujinx.Ava.Common.Locale
|
||||
|
||||
var builder = new CompiledBindingPathBuilder();
|
||||
|
||||
builder.SetRawSource(LocaleManager.Instance)
|
||||
builder
|
||||
.Property(new ClrPropertyInfo("Item",
|
||||
obj => (LocaleManager.Instance[keyToUse]),
|
||||
null,
|
||||
@@ -32,7 +32,10 @@ namespace Ryujinx.Ava.Common.Locale
|
||||
|
||||
var path = builder.Build();
|
||||
|
||||
var binding = new CompiledBindingExtension(path);
|
||||
var binding = new CompiledBindingExtension(path)
|
||||
{
|
||||
Source = LocaleManager.Instance
|
||||
};
|
||||
|
||||
return binding.ProvideValue(serviceProvider);
|
||||
}
|
||||
|
@@ -139,9 +139,11 @@ namespace Ryujinx.Ava.Common.Locale
|
||||
|
||||
foreach (var item in locale)
|
||||
{
|
||||
this[item.Key] = item.Value;
|
||||
_localeStrings[item.Key] = item.Value;
|
||||
}
|
||||
|
||||
OnPropertyChanged("Item");
|
||||
|
||||
LocaleChanged?.Invoke();
|
||||
}
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Ryujinx.Ava.UI.Models;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
@@ -11,7 +11,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
Profiles = new ObservableCollection<BaseModel>();
|
||||
LostProfiles = new ObservableCollection<UserProfile>();
|
||||
IsEmpty = LostProfiles.IsNullOrEmpty();
|
||||
IsEmpty = !LostProfiles.Any();
|
||||
}
|
||||
|
||||
public ObservableCollection<BaseModel> Profiles { get; set; }
|
||||
|
Reference in New Issue
Block a user