Compare commits

..

8 Commits

Author SHA1 Message Date
59ddb26628 replace ByteMemoryPool usage in Ryujinx.Graphics (#7129)
* chore: replace `ByteMemoryPool` usage with `MemoryOwner<byte>`

* refactor: `PixelConverter.ConvertR4G4ToR4G4B4A4()` - rename old `outputSpan` to `outputSpanUInt16`, reuse same output `Span<byte>` as newly-freed name `outputSpan`

* eliminate temporary buffer allocations

* chore, perf: use MemoryOwner<byte> instead of IMemoryOwner<byte>
2024-08-03 19:50:53 +01:00
83fda10f6e Fix FileNotFoundException in TryGetApplicationsFromFile() and improve loading applications (#7145)
* Don't load files from hidden subdirectories

* Catch FileNotFoundException in TryGetApplicationsFromFile()

* Skip non-existent files and bad symlinks when loading applications
2024-08-03 19:46:59 +02:00
d97e995e59 Fix off-by-one on audio renderer PerformanceManager.GetNextEntry (#7139) 2024-07-31 22:22:11 -03:00
56b2f84702 Fix shader RegisterUsage pass only taking first operation dest into account (#7131)
* Fix shader RegisterUsage pass only taking first operation dest into account

* Shader cache version bump
2024-07-30 21:57:55 -03:00
698e36bbd2 Vulkan: Force topology to PatchList for Tessellation (#7102)
Vulkan spec states that input topology should always be PatchList when a tessellation pipeline is present. The AMD GPU on windows crashes so hard it BSODs the machine if this isn't the case, so it's forced here just in case.

I'm not sure what providing a different topology here would even do, as you'd think it would always be a patch list input.
2024-07-30 21:48:30 -03:00
6ce49a2dc7 Ava UI: Handle updates containing non numeric characters (#7043)
* Handle updates containing non numeric characters

Smh

Dont be stupid

* Use Berry’s method

* Thanks gdk

* Remove using
2024-07-25 16:44:33 -03:00
ccd330ba0f Vulkan: Add missing barriers for texture to buffer copy (#7092)
This barrier has always been missing, but it only became apparent when #7012 merged.

I also added some barriers in case the target buffer used here is used by other commands, though right now it isn't.

Fixes a regression where water would turn white on AMD GPUs with the proprietary driver. May fix other issues on this driver.
2024-07-25 16:34:30 -03:00
95d252b7b8 Update kernel GetInfo SVC for firmware 18.0.0 (#7075)
* Implement kernel GetInfo AliasRegionExtraSize

* Implement IsSvcPermitted

* Remove warning supressions that are no longer needed

* Remove useless cast
2024-07-22 12:46:04 -03:00
30 changed files with 274 additions and 290 deletions

View File

@ -18,16 +18,12 @@ namespace Ryujinx.Audio.Renderer.Server.Performance
if (version == 2)
{
return (ulong)PerformanceManagerGeneric<PerformanceFrameHeaderVersion2,
PerformanceEntryVersion2,
PerformanceDetailVersion2>.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter);
return (ulong)PerformanceManagerGeneric<PerformanceFrameHeaderVersion2, PerformanceEntryVersion2, PerformanceDetailVersion2>.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter);
}
if (version == 1)
{
return (ulong)PerformanceManagerGeneric<PerformanceFrameHeaderVersion1,
PerformanceEntryVersion1,
PerformanceDetailVersion1>.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter);
return (ulong)PerformanceManagerGeneric<PerformanceFrameHeaderVersion1, PerformanceEntryVersion1, PerformanceDetailVersion1>.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter);
}
throw new NotImplementedException($"Unknown Performance metrics data format version {version}");

View File

@ -234,7 +234,7 @@ namespace Ryujinx.Audio.Renderer.Server.Performance
{
performanceEntry = null;
if (_entryDetailIndex > MaxFrameDetailCount)
if (_entryDetailIndex >= MaxFrameDetailCount)
{
return false;
}
@ -245,7 +245,7 @@ namespace Ryujinx.Audio.Renderer.Server.Performance
EntryCountOffset = (uint)CurrentHeader.GetEntryCountOffset(),
};
uint baseEntryOffset = (uint)(Unsafe.SizeOf<THeader>() + GetEntriesSize() + Unsafe.SizeOf<IPerformanceDetailEntry>() * _entryDetailIndex);
uint baseEntryOffset = (uint)(Unsafe.SizeOf<THeader>() + GetEntriesSize() + Unsafe.SizeOf<TEntryDetail>() * _entryDetailIndex);
ref TEntryDetail entryDetail = ref EntriesDetail[_entryDetailIndex];

View File

@ -1,7 +1,6 @@
using Ryujinx.Common.Memory;
using Ryujinx.Memory;
using System;
using System.Buffers;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -145,9 +144,9 @@ namespace Ryujinx.Graphics.Device
}
else
{
IMemoryOwner<byte> memoryOwner = ByteMemoryPool.Rent(size);
MemoryOwner<byte> memoryOwner = MemoryOwner<byte>.Rent(size);
GetSpan(va, size).CopyTo(memoryOwner.Memory.Span);
ReadImpl(va, memoryOwner.Span);
return new WritableRegion(this, va, memoryOwner, tracked: true);
}

View File

@ -199,7 +199,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.InlineToMemory
if (target != null)
{
target.SynchronizeMemory();
var dataCopy = ByteMemoryPool.RentCopy(data);
var dataCopy = MemoryOwner<byte>.RentCopy(data);
target.SetData(dataCopy, 0, 0, new GAL.Rectangle<int>(_dstX, _dstY, _lineLengthIn / target.Info.FormatInfo.BytesPerPixel, _lineCount));
target.SignalModified();

View File

@ -1,4 +1,5 @@
using Ryujinx.Common.Logging;
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Texture;
@ -805,7 +806,7 @@ namespace Ryujinx.Graphics.Gpu.Image
sliceDepth,
levels,
layers,
out IMemoryOwner<byte> decoded))
out MemoryOwner<byte> decoded))
{
string texInfo = $"{Info.Target} {Info.FormatInfo.Format} {Info.Width}x{Info.Height}x{Info.DepthOrLayers} levels {Info.Levels}";

View File

@ -2,7 +2,6 @@ using Ryujinx.Common.Memory;
using Ryujinx.Memory;
using Ryujinx.Memory.Range;
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -242,9 +241,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
else
{
IMemoryOwner<byte> memoryOwner = ByteMemoryPool.Rent(size);
MemoryOwner<byte> memoryOwner = MemoryOwner<byte>.Rent(size);
GetSpan(va, size).CopyTo(memoryOwner.Memory.Span);
ReadImpl(va, memoryOwner.Span, tracked);
return new WritableRegion(this, va, memoryOwner, tracked);
}

View File

@ -192,9 +192,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
else
{
IMemoryOwner<byte> memoryOwner = ByteMemoryPool.Rent(range.GetSize());
MemoryOwner<byte> memoryOwner = MemoryOwner<byte>.Rent(checked((int)range.GetSize()));
Memory<byte> memory = memoryOwner.Memory;
Span<byte> memorySpan = memoryOwner.Span;
int offset = 0;
for (int i = 0; i < range.Count; i++)
@ -203,7 +203,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
int size = (int)currentRange.Size;
if (currentRange.Address != MemoryManager.PteUnmapped)
{
GetSpan(currentRange.Address, size).CopyTo(memory.Span.Slice(offset, size));
GetSpan(currentRange.Address, size).CopyTo(memorySpan.Slice(offset, size));
}
offset += size;
}

View File

@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
private const ushort FileFormatVersionMajor = 1;
private const ushort FileFormatVersionMinor = 2;
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
private const uint CodeGenVersion = 6921;
private const uint CodeGenVersion = 7131;
private const string SharedTocFileName = "shared.toc";
private const string SharedDataFileName = "shared.data";

View File

@ -1,6 +1,5 @@
using Ryujinx.Common.Memory;
using System;
using System.Buffers;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
@ -10,11 +9,11 @@ namespace Ryujinx.Graphics.OpenGL.Image
{
static class FormatConverter
{
public unsafe static IMemoryOwner<byte> ConvertS8D24ToD24S8(ReadOnlySpan<byte> data)
public unsafe static MemoryOwner<byte> ConvertS8D24ToD24S8(ReadOnlySpan<byte> data)
{
IMemoryOwner<byte> outputMemory = ByteMemoryPool.Rent(data.Length);
MemoryOwner<byte> outputMemory = MemoryOwner<byte>.Rent(data.Length);
Span<byte> output = outputMemory.Memory.Span;
Span<byte> output = outputMemory.Span;
int start = 0;

View File

@ -155,9 +155,14 @@ namespace Ryujinx.Graphics.Shader.Translation
localInputs[block.Index] |= GetMask(register) & ~localOutputs[block.Index];
}
if (operation.Dest != null && operation.Dest.Type == OperandType.Register)
for (int dstIndex = 0; dstIndex < operation.DestsCount; dstIndex++)
{
localOutputs[block.Index] |= GetMask(operation.Dest.GetRegister());
Operand dest = operation.GetDest(dstIndex);
if (dest != null && dest.Type == OperandType.Register)
{
localOutputs[block.Index] |= GetMask(dest.GetRegister());
}
}
}
}

View File

@ -1,7 +1,6 @@
using Ryujinx.Common.Memory;
using Ryujinx.Common.Utilities;
using System;
using System.Buffers;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
@ -293,9 +292,9 @@ namespace Ryujinx.Graphics.Texture.Astc
int depth,
int levels,
int layers,
out IMemoryOwner<byte> decoded)
out MemoryOwner<byte> decoded)
{
decoded = ByteMemoryPool.Rent(QueryDecompressedSize(width, height, depth, levels, layers));
decoded = MemoryOwner<byte>.Rent(QueryDecompressedSize(width, height, depth, levels, layers));
AstcDecoder decoder = new(data, decoded.Memory, blockWidth, blockHeight, width, height, depth, levels, layers);

View File

@ -1,7 +1,6 @@
using Ryujinx.Common;
using Ryujinx.Common.Memory;
using System;
using System.Buffers;
using System.Buffers.Binary;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
@ -14,7 +13,7 @@ namespace Ryujinx.Graphics.Texture
private const int BlockWidth = 4;
private const int BlockHeight = 4;
public static IMemoryOwner<byte> DecodeBC1(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
public static MemoryOwner<byte> DecodeBC1(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
{
int size = 0;
@ -23,12 +22,12 @@ namespace Ryujinx.Graphics.Texture
size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 4;
}
IMemoryOwner<byte> output = ByteMemoryPool.Rent(size);
MemoryOwner<byte> output = MemoryOwner<byte>.Rent(size);
Span<byte> tile = stackalloc byte[BlockWidth * BlockHeight * 4];
Span<uint> tileAsUint = MemoryMarshal.Cast<byte, uint>(tile);
Span<uint> outputAsUint = MemoryMarshal.Cast<byte, uint>(output.Memory.Span);
Span<uint> outputAsUint = MemoryMarshal.Cast<byte, uint>(output.Span);
Span<Vector128<byte>> tileAsVector128 = MemoryMarshal.Cast<byte, Vector128<byte>>(tile);
@ -102,7 +101,7 @@ namespace Ryujinx.Graphics.Texture
return output;
}
public static IMemoryOwner<byte> DecodeBC2(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
public static MemoryOwner<byte> DecodeBC2(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
{
int size = 0;
@ -111,12 +110,12 @@ namespace Ryujinx.Graphics.Texture
size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 4;
}
IMemoryOwner<byte> output = ByteMemoryPool.Rent(size);
MemoryOwner<byte> output = MemoryOwner<byte>.Rent(size);
Span<byte> tile = stackalloc byte[BlockWidth * BlockHeight * 4];
Span<uint> tileAsUint = MemoryMarshal.Cast<byte, uint>(tile);
Span<uint> outputAsUint = MemoryMarshal.Cast<byte, uint>(output.Memory.Span);
Span<uint> outputAsUint = MemoryMarshal.Cast<byte, uint>(output.Span);
Span<Vector128<byte>> tileAsVector128 = MemoryMarshal.Cast<byte, Vector128<byte>>(tile);
@ -197,7 +196,7 @@ namespace Ryujinx.Graphics.Texture
return output;
}
public static IMemoryOwner<byte> DecodeBC3(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
public static MemoryOwner<byte> DecodeBC3(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
{
int size = 0;
@ -206,13 +205,13 @@ namespace Ryujinx.Graphics.Texture
size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 4;
}
IMemoryOwner<byte> output = ByteMemoryPool.Rent(size);
MemoryOwner<byte> output = MemoryOwner<byte>.Rent(size);
Span<byte> tile = stackalloc byte[BlockWidth * BlockHeight * 4];
Span<byte> rPal = stackalloc byte[8];
Span<uint> tileAsUint = MemoryMarshal.Cast<byte, uint>(tile);
Span<uint> outputAsUint = MemoryMarshal.Cast<byte, uint>(output.Memory.Span);
Span<uint> outputAsUint = MemoryMarshal.Cast<byte, uint>(output.Span);
Span<Vector128<byte>> tileAsVector128 = MemoryMarshal.Cast<byte, Vector128<byte>>(tile);
@ -294,7 +293,7 @@ namespace Ryujinx.Graphics.Texture
return output;
}
public static IMemoryOwner<byte> DecodeBC4(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers, bool signed)
public static MemoryOwner<byte> DecodeBC4(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers, bool signed)
{
int size = 0;
@ -306,8 +305,8 @@ namespace Ryujinx.Graphics.Texture
// Backends currently expect a stride alignment of 4 bytes, so output width must be aligned.
int alignedWidth = BitUtils.AlignUp(width, 4);
IMemoryOwner<byte> output = ByteMemoryPool.Rent(size);
Span<byte> outputSpan = output.Memory.Span;
MemoryOwner<byte> output = MemoryOwner<byte>.Rent(size);
Span<byte> outputSpan = output.Span;
ReadOnlySpan<ulong> data64 = MemoryMarshal.Cast<byte, ulong>(data);
@ -402,7 +401,7 @@ namespace Ryujinx.Graphics.Texture
return output;
}
public static IMemoryOwner<byte> DecodeBC5(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers, bool signed)
public static MemoryOwner<byte> DecodeBC5(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers, bool signed)
{
int size = 0;
@ -414,7 +413,7 @@ namespace Ryujinx.Graphics.Texture
// Backends currently expect a stride alignment of 4 bytes, so output width must be aligned.
int alignedWidth = BitUtils.AlignUp(width, 2);
IMemoryOwner<byte> output = ByteMemoryPool.Rent(size);
MemoryOwner<byte> output = MemoryOwner<byte>.Rent(size);
ReadOnlySpan<ulong> data64 = MemoryMarshal.Cast<byte, ulong>(data);
@ -423,7 +422,7 @@ namespace Ryujinx.Graphics.Texture
Span<byte> rPal = stackalloc byte[8];
Span<byte> gPal = stackalloc byte[8];
Span<ushort> outputAsUshort = MemoryMarshal.Cast<byte, ushort>(output.Memory.Span);
Span<ushort> outputAsUshort = MemoryMarshal.Cast<byte, ushort>(output.Span);
Span<uint> rTileAsUint = MemoryMarshal.Cast<byte, uint>(rTile);
Span<uint> gTileAsUint = MemoryMarshal.Cast<byte, uint>(gTile);
@ -527,7 +526,7 @@ namespace Ryujinx.Graphics.Texture
return output;
}
public static IMemoryOwner<byte> DecodeBC6(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers, bool signed)
public static MemoryOwner<byte> DecodeBC6(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers, bool signed)
{
int size = 0;
@ -536,8 +535,8 @@ namespace Ryujinx.Graphics.Texture
size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 8;
}
IMemoryOwner<byte> output = ByteMemoryPool.Rent(size);
Span<byte> outputSpan = output.Memory.Span;
MemoryOwner<byte> output = MemoryOwner<byte>.Rent(size);
Span<byte> outputSpan = output.Span;
int inputOffset = 0;
int outputOffset = 0;
@ -566,7 +565,7 @@ namespace Ryujinx.Graphics.Texture
return output;
}
public static IMemoryOwner<byte> DecodeBC7(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
public static MemoryOwner<byte> DecodeBC7(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
{
int size = 0;
@ -575,8 +574,8 @@ namespace Ryujinx.Graphics.Texture
size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 4;
}
IMemoryOwner<byte> output = ByteMemoryPool.Rent(size);
Span<byte> outputSpan = output.Memory.Span;
MemoryOwner<byte> output = MemoryOwner<byte>.Rent(size);
Span<byte> outputSpan = output.Span;
int inputOffset = 0;
int outputOffset = 0;

View File

@ -2,7 +2,6 @@ using Ryujinx.Common;
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.Texture.Encoders;
using System;
using System.Buffers;
namespace Ryujinx.Graphics.Texture
{
@ -11,7 +10,7 @@ namespace Ryujinx.Graphics.Texture
private const int BlockWidth = 4;
private const int BlockHeight = 4;
public static IMemoryOwner<byte> EncodeBC7(Memory<byte> data, int width, int height, int depth, int levels, int layers)
public static MemoryOwner<byte> EncodeBC7(Memory<byte> data, int width, int height, int depth, int levels, int layers)
{
int size = 0;
@ -23,7 +22,7 @@ namespace Ryujinx.Graphics.Texture
size += w * h * 16 * Math.Max(1, depth >> l) * layers;
}
IMemoryOwner<byte> output = ByteMemoryPool.Rent(size);
MemoryOwner<byte> output = MemoryOwner<byte>.Rent(size);
Memory<byte> outputMemory = output.Memory;
int imageBaseIOffs = 0;

View File

@ -1,7 +1,6 @@
using Ryujinx.Common;
using Ryujinx.Common.Memory;
using System;
using System.Buffers;
using System.Buffers.Binary;
using System.Runtime.InteropServices;
@ -51,15 +50,15 @@ namespace Ryujinx.Graphics.Texture
new int[] { -3, -5, -7, -9, 2, 4, 6, 8 },
};
public static IMemoryOwner<byte> DecodeRgb(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
public static MemoryOwner<byte> DecodeRgb(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
{
ReadOnlySpan<ulong> dataUlong = MemoryMarshal.Cast<byte, ulong>(data);
int inputOffset = 0;
IMemoryOwner<byte> output = ByteMemoryPool.Rent(CalculateOutputSize(width, height, depth, levels, layers));
MemoryOwner<byte> output = MemoryOwner<byte>.Rent(CalculateOutputSize(width, height, depth, levels, layers));
Span<uint> outputUint = MemoryMarshal.Cast<byte, uint>(output.Memory.Span);
Span<uint> outputUint = MemoryMarshal.Cast<byte, uint>(output.Span);
Span<uint> tile = stackalloc uint[BlockWidth * BlockHeight];
int imageBaseOOffs = 0;
@ -113,15 +112,15 @@ namespace Ryujinx.Graphics.Texture
return output;
}
public static IMemoryOwner<byte> DecodePta(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
public static MemoryOwner<byte> DecodePta(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
{
ReadOnlySpan<ulong> dataUlong = MemoryMarshal.Cast<byte, ulong>(data);
int inputOffset = 0;
IMemoryOwner<byte> output = ByteMemoryPool.Rent(CalculateOutputSize(width, height, depth, levels, layers));
MemoryOwner<byte> output = MemoryOwner<byte>.Rent(CalculateOutputSize(width, height, depth, levels, layers));
Span<uint> outputUint = MemoryMarshal.Cast<byte, uint>(output.Memory.Span);
Span<uint> outputUint = MemoryMarshal.Cast<byte, uint>(output.Span);
Span<uint> tile = stackalloc uint[BlockWidth * BlockHeight];
int imageBaseOOffs = 0;
@ -170,15 +169,15 @@ namespace Ryujinx.Graphics.Texture
return output;
}
public static IMemoryOwner<byte> DecodeRgba(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
public static MemoryOwner<byte> DecodeRgba(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
{
ReadOnlySpan<ulong> dataUlong = MemoryMarshal.Cast<byte, ulong>(data);
int inputOffset = 0;
IMemoryOwner<byte> output = ByteMemoryPool.Rent(CalculateOutputSize(width, height, depth, levels, layers));
MemoryOwner<byte> output = MemoryOwner<byte>.Rent(CalculateOutputSize(width, height, depth, levels, layers));
Span<uint> outputUint = MemoryMarshal.Cast<byte, uint>(output.Memory.Span);
Span<uint> outputUint = MemoryMarshal.Cast<byte, uint>(output.Span);
Span<uint> tile = stackalloc uint[BlockWidth * BlockHeight];
int imageBaseOOffs = 0;

View File

@ -1,7 +1,6 @@
using Ryujinx.Common;
using Ryujinx.Common.Memory;
using System;
using System.Buffers;
using System.Runtime.Intrinsics;
using static Ryujinx.Graphics.Texture.BlockLinearConstants;
@ -95,7 +94,7 @@ namespace Ryujinx.Graphics.Texture
};
}
public static IMemoryOwner<byte> ConvertBlockLinearToLinear(
public static MemoryOwner<byte> ConvertBlockLinearToLinear(
int width,
int height,
int depth,
@ -121,8 +120,8 @@ namespace Ryujinx.Graphics.Texture
blockHeight,
bytesPerPixel);
IMemoryOwner<byte> outputOwner = ByteMemoryPool.Rent(outSize);
Span<byte> output = outputOwner.Memory.Span;
MemoryOwner<byte> outputOwner = MemoryOwner<byte>.Rent(outSize);
Span<byte> output = outputOwner.Span;
int outOffs = 0;
@ -249,7 +248,7 @@ namespace Ryujinx.Graphics.Texture
return outputOwner;
}
public static IMemoryOwner<byte> ConvertLinearStridedToLinear(
public static MemoryOwner<byte> ConvertLinearStridedToLinear(
int width,
int height,
int blockWidth,
@ -265,8 +264,8 @@ namespace Ryujinx.Graphics.Texture
int outStride = BitUtils.AlignUp(w * bytesPerPixel, HostStrideAlignment);
lineSize = Math.Min(lineSize, outStride);
IMemoryOwner<byte> output = ByteMemoryPool.Rent(h * outStride);
Span<byte> outSpan = output.Memory.Span;
MemoryOwner<byte> output = MemoryOwner<byte>.Rent(h * outStride);
Span<byte> outSpan = output.Span;
int outOffs = 0;
int inOffs = 0;

View File

@ -1,7 +1,6 @@
using Ryujinx.Common;
using Ryujinx.Common.Memory;
using System;
using System.Buffers;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
@ -21,13 +20,14 @@ namespace Ryujinx.Graphics.Texture
return (remainder, outRemainder, length / stride);
}
public unsafe static IMemoryOwner<byte> ConvertR4G4ToR4G4B4A4(ReadOnlySpan<byte> data, int width)
public unsafe static MemoryOwner<byte> ConvertR4G4ToR4G4B4A4(ReadOnlySpan<byte> data, int width)
{
IMemoryOwner<byte> output = ByteMemoryPool.Rent(data.Length * 2);
MemoryOwner<byte> output = MemoryOwner<byte>.Rent(data.Length * 2);
Span<byte> outputSpan = output.Span;
(int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 1, 2);
Span<ushort> outputSpan = MemoryMarshal.Cast<byte, ushort>(output.Memory.Span);
Span<ushort> outputSpanUInt16 = MemoryMarshal.Cast<byte, ushort>(outputSpan);
if (remainder == 0)
{
@ -38,7 +38,7 @@ namespace Ryujinx.Graphics.Texture
int sizeTrunc = data.Length & ~7;
start = sizeTrunc;
fixed (byte* inputPtr = data, outputPtr = output.Memory.Span)
fixed (byte* inputPtr = data, outputPtr = outputSpan)
{
for (ulong offset = 0; offset < (ulong)sizeTrunc; offset += 8)
{
@ -49,7 +49,7 @@ namespace Ryujinx.Graphics.Texture
for (int i = start; i < data.Length; i++)
{
outputSpan[i] = data[i];
outputSpanUInt16[i] = data[i];
}
}
else
@ -61,7 +61,7 @@ namespace Ryujinx.Graphics.Texture
{
for (int x = 0; x < width; x++)
{
outputSpan[outOffset++] = data[offset++];
outputSpanUInt16[outOffset++] = data[offset++];
}
offset += remainder;
@ -72,16 +72,16 @@ namespace Ryujinx.Graphics.Texture
return output;
}
public static IMemoryOwner<byte> ConvertR5G6B5ToR8G8B8A8(ReadOnlySpan<byte> data, int width)
public static MemoryOwner<byte> ConvertR5G6B5ToR8G8B8A8(ReadOnlySpan<byte> data, int width)
{
IMemoryOwner<byte> output = ByteMemoryPool.Rent(data.Length * 2);
MemoryOwner<byte> output = MemoryOwner<byte>.Rent(data.Length * 2);
int offset = 0;
int outOffset = 0;
(int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4);
ReadOnlySpan<ushort> inputSpan = MemoryMarshal.Cast<byte, ushort>(data);
Span<uint> outputSpan = MemoryMarshal.Cast<byte, uint>(output.Memory.Span);
Span<uint> outputSpan = MemoryMarshal.Cast<byte, uint>(output.Span);
for (int y = 0; y < height; y++)
{
@ -109,16 +109,16 @@ namespace Ryujinx.Graphics.Texture
return output;
}
public static IMemoryOwner<byte> ConvertR5G5B5ToR8G8B8A8(ReadOnlySpan<byte> data, int width, bool forceAlpha)
public static MemoryOwner<byte> ConvertR5G5B5ToR8G8B8A8(ReadOnlySpan<byte> data, int width, bool forceAlpha)
{
IMemoryOwner<byte> output = ByteMemoryPool.Rent(data.Length * 2);
MemoryOwner<byte> output = MemoryOwner<byte>.Rent(data.Length * 2);
int offset = 0;
int outOffset = 0;
(int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4);
ReadOnlySpan<ushort> inputSpan = MemoryMarshal.Cast<byte, ushort>(data);
Span<uint> outputSpan = MemoryMarshal.Cast<byte, uint>(output.Memory.Span);
Span<uint> outputSpan = MemoryMarshal.Cast<byte, uint>(output.Span);
for (int y = 0; y < height; y++)
{
@ -146,16 +146,16 @@ namespace Ryujinx.Graphics.Texture
return output;
}
public static IMemoryOwner<byte> ConvertA1B5G5R5ToR8G8B8A8(ReadOnlySpan<byte> data, int width)
public static MemoryOwner<byte> ConvertA1B5G5R5ToR8G8B8A8(ReadOnlySpan<byte> data, int width)
{
IMemoryOwner<byte> output = ByteMemoryPool.Rent(data.Length * 2);
MemoryOwner<byte> output = MemoryOwner<byte>.Rent(data.Length * 2);
int offset = 0;
int outOffset = 0;
(int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4);
ReadOnlySpan<ushort> inputSpan = MemoryMarshal.Cast<byte, ushort>(data);
Span<uint> outputSpan = MemoryMarshal.Cast<byte, uint>(output.Memory.Span);
Span<uint> outputSpan = MemoryMarshal.Cast<byte, uint>(output.Span);
for (int y = 0; y < height; y++)
{
@ -183,16 +183,16 @@ namespace Ryujinx.Graphics.Texture
return output;
}
public static IMemoryOwner<byte> ConvertR4G4B4A4ToR8G8B8A8(ReadOnlySpan<byte> data, int width)
public static MemoryOwner<byte> ConvertR4G4B4A4ToR8G8B8A8(ReadOnlySpan<byte> data, int width)
{
IMemoryOwner<byte> output = ByteMemoryPool.Rent(data.Length * 2);
MemoryOwner<byte> output = MemoryOwner<byte>.Rent(data.Length * 2);
int offset = 0;
int outOffset = 0;
(int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4);
ReadOnlySpan<ushort> inputSpan = MemoryMarshal.Cast<byte, ushort>(data);
Span<uint> outputSpan = MemoryMarshal.Cast<byte, uint>(output.Memory.Span);
Span<uint> outputSpan = MemoryMarshal.Cast<byte, uint>(output.Span);
for (int y = 0; y < height; y++)
{

View File

@ -211,7 +211,7 @@ namespace Ryujinx.Graphics.Vulkan
public void Initialize()
{
IMemoryOwner<byte> dummyTextureData = ByteMemoryPool.RentCleared(4);
MemoryOwner<byte> dummyTextureData = MemoryOwner<byte>.RentCleared(4);
_dummyTexture.SetData(dummyTextureData);
}

View File

@ -439,7 +439,7 @@ namespace Ryujinx.Graphics.Vulkan
{
SType = StructureType.PipelineInputAssemblyStateCreateInfo,
PrimitiveRestartEnable = primitiveRestartEnable,
Topology = Topology,
Topology = HasTessellationControlShader ? PrimitiveTopology.PatchList : Topology,
};
var tessellationState = new PipelineTessellationStateCreateInfo

View File

@ -667,8 +667,36 @@ namespace Ryujinx.Graphics.Vulkan
if (PrepareOutputBuffer(cbs, hostSize, buffer, out VkBuffer copyToBuffer, out BufferHolder tempCopyHolder))
{
// No barrier necessary, as this is a temporary copy buffer.
offset = 0;
}
else
{
BufferHolder.InsertBufferBarrier(
_gd,
cbs.CommandBuffer,
copyToBuffer,
BufferHolder.DefaultAccessFlags,
AccessFlags.TransferWriteBit,
PipelineStageFlags.AllCommandsBit,
PipelineStageFlags.TransferBit,
offset,
outSize);
}
InsertImageBarrier(
_gd.Api,
cbs.CommandBuffer,
image,
TextureStorage.DefaultAccessMask,
AccessFlags.TransferReadBit,
PipelineStageFlags.AllCommandsBit,
PipelineStageFlags.TransferBit,
Info.Format.ConvertAspectFlags(),
FirstLayer + layer,
FirstLevel + level,
1,
1);
CopyFromOrToBuffer(cbs.CommandBuffer, copyToBuffer, image, hostSize, true, layer, level, 1, 1, singleSlice: true, offset, stride);
@ -677,6 +705,19 @@ namespace Ryujinx.Graphics.Vulkan
CopyDataToOutputBuffer(cbs, tempCopyHolder, autoBuffer, hostSize, range.Offset);
tempCopyHolder.Dispose();
}
else
{
BufferHolder.InsertBufferBarrier(
_gd,
cbs.CommandBuffer,
copyToBuffer,
AccessFlags.TransferWriteBit,
BufferHolder.DefaultAccessFlags,
PipelineStageFlags.TransferBit,
PipelineStageFlags.AllCommandsBit,
offset,
outSize);
}
}
private ReadOnlySpan<byte> GetData(CommandBufferPool cbp, PersistentFlushBuffer flushBuffer)

View File

@ -1,10 +0,0 @@
namespace Ryujinx.HLE.HOS.Kernel.Memory
{
enum AddressSpaceType
{
Addr32Bits = 0,
Addr36Bits = 1,
Addr32BitsNoMap = 2,
Addr39Bits = 3,
}
}

View File

@ -58,11 +58,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
public ulong AslrRegionStart { get; private set; }
public ulong AslrRegionEnd { get; private set; }
#pragma warning disable IDE0052 // Remove unread private member
private ulong _heapCapacity;
#pragma warning restore IDE0052
public ulong PhysicalMemoryUsage { get; private set; }
public ulong AliasRegionExtraSize { get; private set; }
private readonly KMemoryBlockManager _blockManager;
@ -98,30 +97,21 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_reservedAddressSpaceSize = reservedAddressSpaceSize;
}
private static readonly int[] _addrSpaceSizes = { 32, 36, 32, 39 };
public Result InitializeForProcess(
AddressSpaceType addrSpaceType,
bool aslrEnabled,
ProcessCreationFlags flags,
bool fromBack,
MemoryRegion memRegion,
ulong address,
ulong size,
KMemoryBlockSlabManager slabManager)
{
if ((uint)addrSpaceType > (uint)AddressSpaceType.Addr39Bits)
{
throw new ArgumentException($"AddressSpaceType bigger than {(uint)AddressSpaceType.Addr39Bits}: {(uint)addrSpaceType}", nameof(addrSpaceType));
}
_contextId = Context.ContextIdManager.GetId();
ulong addrSpaceBase = 0;
ulong addrSpaceSize = 1UL << _addrSpaceSizes[(int)addrSpaceType];
ulong addrSpaceSize = 1UL << GetAddressSpaceWidth(flags);
Result result = CreateUserAddressSpace(
addrSpaceType,
aslrEnabled,
flags,
fromBack,
addrSpaceBase,
addrSpaceSize,
@ -138,6 +128,22 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return result;
}
private static int GetAddressSpaceWidth(ProcessCreationFlags flags)
{
switch (flags & ProcessCreationFlags.AddressSpaceMask)
{
case ProcessCreationFlags.AddressSpace32Bit:
case ProcessCreationFlags.AddressSpace32BitWithoutAlias:
return 32;
case ProcessCreationFlags.AddressSpace64BitDeprecated:
return 36;
case ProcessCreationFlags.AddressSpace64Bit:
return 39;
}
throw new ArgumentException($"Invalid process flags {flags}", nameof(flags));
}
private struct Region
{
public ulong Start;
@ -147,8 +153,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
private Result CreateUserAddressSpace(
AddressSpaceType addrSpaceType,
bool aslrEnabled,
ProcessCreationFlags flags,
bool fromBack,
ulong addrSpaceStart,
ulong addrSpaceEnd,
@ -168,9 +173,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong stackAndTlsIoStart;
ulong stackAndTlsIoEnd;
switch (addrSpaceType)
AliasRegionExtraSize = 0;
switch (flags & ProcessCreationFlags.AddressSpaceMask)
{
case AddressSpaceType.Addr32Bits:
case ProcessCreationFlags.AddressSpace32Bit:
aliasRegion.Size = 0x40000000;
heapRegion.Size = 0x40000000;
stackRegion.Size = 0;
@ -183,7 +190,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
stackAndTlsIoEnd = 0x40000000;
break;
case AddressSpaceType.Addr36Bits:
case ProcessCreationFlags.AddressSpace64BitDeprecated:
aliasRegion.Size = 0x180000000;
heapRegion.Size = 0x180000000;
stackRegion.Size = 0;
@ -196,7 +203,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
stackAndTlsIoEnd = 0x80000000;
break;
case AddressSpaceType.Addr32BitsNoMap:
case ProcessCreationFlags.AddressSpace32BitWithoutAlias:
aliasRegion.Size = 0;
heapRegion.Size = 0x80000000;
stackRegion.Size = 0;
@ -209,7 +216,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
stackAndTlsIoEnd = 0x40000000;
break;
case AddressSpaceType.Addr39Bits:
case ProcessCreationFlags.AddressSpace64Bit:
if (_reservedAddressSpaceSize < addrSpaceEnd)
{
int addressSpaceWidth = (int)ulong.Log2(_reservedAddressSpaceSize);
@ -218,8 +225,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
heapRegion.Size = 0x180000000;
stackRegion.Size = 1UL << (addressSpaceWidth - 8);
tlsIoRegion.Size = 1UL << (addressSpaceWidth - 3);
CodeRegionStart = BitUtils.AlignDown<ulong>(address, RegionAlignment);
codeRegionSize = BitUtils.AlignUp<ulong>(endAddr, RegionAlignment) - CodeRegionStart;
CodeRegionStart = BitUtils.AlignDown(address, RegionAlignment);
codeRegionSize = BitUtils.AlignUp(endAddr, RegionAlignment) - CodeRegionStart;
stackAndTlsIoStart = 0;
stackAndTlsIoEnd = 0;
AslrRegionStart = 0x8000000;
@ -239,9 +246,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
stackAndTlsIoStart = 0;
stackAndTlsIoEnd = 0;
}
if (flags.HasFlag(ProcessCreationFlags.EnableAliasRegionExtraSize))
{
AliasRegionExtraSize = addrSpaceEnd / 8;
aliasRegion.Size += AliasRegionExtraSize;
}
break;
default:
throw new ArgumentException($"AddressSpaceType bigger than {(uint)AddressSpaceType.Addr39Bits}: {(uint)addrSpaceType}", nameof(addrSpaceType));
throw new ArgumentException($"Invalid process flags {flags}", nameof(flags));
}
CodeRegionEnd = CodeRegionStart + codeRegionSize;
@ -266,6 +280,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong aslrMaxOffset = mapAvailableSize - mapTotalSize;
bool aslrEnabled = flags.HasFlag(ProcessCreationFlags.EnableAslr);
_aslrEnabled = aslrEnabled;
AddrSpaceStart = addrSpaceStart;
@ -725,7 +741,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
{
address = 0;
if (size > HeapRegionEnd - HeapRegionStart)
if (size > HeapRegionEnd - HeapRegionStart || size > _heapCapacity)
{
return KernelResult.OutOfMemory;
}

View File

@ -126,8 +126,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
_contextFactory = contextFactory ?? new ProcessContextFactory();
_customThreadStart = customThreadStart;
AddressSpaceType addrSpaceType = (AddressSpaceType)((int)(creationInfo.Flags & ProcessCreationFlags.AddressSpaceMask) >> (int)ProcessCreationFlags.AddressSpaceShift);
Pid = KernelContext.NewKipId();
if (Pid == 0 || Pid >= KernelConstants.InitialProcessId)
@ -137,8 +135,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
InitializeMemoryManager(creationInfo.Flags);
bool aslrEnabled = creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr);
ulong codeAddress = creationInfo.CodeAddress;
ulong codeSize = (ulong)creationInfo.CodePagesCount * KPageTableBase.PageSize;
@ -148,9 +144,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
: KernelContext.SmallMemoryBlockSlabManager;
Result result = MemoryManager.InitializeForProcess(
addrSpaceType,
aslrEnabled,
!aslrEnabled,
creationInfo.Flags,
!creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr),
memRegion,
codeAddress,
codeSize,
@ -234,8 +229,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
: KernelContext.SmallMemoryBlockSlabManager;
}
AddressSpaceType addrSpaceType = (AddressSpaceType)((int)(creationInfo.Flags & ProcessCreationFlags.AddressSpaceMask) >> (int)ProcessCreationFlags.AddressSpaceShift);
Pid = KernelContext.NewProcessId();
if (Pid == ulong.MaxValue || Pid < KernelConstants.InitialProcessId)
@ -245,16 +238,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
InitializeMemoryManager(creationInfo.Flags);
bool aslrEnabled = creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr);
ulong codeAddress = creationInfo.CodeAddress;
ulong codeSize = codePagesCount * KPageTableBase.PageSize;
Result result = MemoryManager.InitializeForProcess(
addrSpaceType,
aslrEnabled,
!aslrEnabled,
creationInfo.Flags,
!creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr),
memRegion,
codeAddress,
codeSize,
@ -309,8 +299,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
private Result ParseProcessInfo(ProcessCreationInfo creationInfo)
{
// Ensure that the current kernel version is equal or above to the minimum required.
uint requiredKernelVersionMajor = (uint)Capabilities.KernelReleaseVersion >> 19;
uint requiredKernelVersionMinor = ((uint)Capabilities.KernelReleaseVersion >> 15) & 0xf;
uint requiredKernelVersionMajor = Capabilities.KernelReleaseVersion >> 19;
uint requiredKernelVersionMinor = (Capabilities.KernelReleaseVersion >> 15) & 0xf;
if (KernelContext.EnableVersionChecks)
{
@ -519,12 +509,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
return result;
}
#pragma warning disable CA1822 // Mark member as static
private void GenerateRandomEntropy()
{
// TODO.
}
#pragma warning restore CA1822
public Result Start(int mainThreadPriority, ulong stackSize)
{
@ -1182,5 +1170,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
// TODO
return false;
}
public bool IsSvcPermitted(int svcId)
{
return Capabilities.IsSvcPermitted(svcId);
}
}
}

View File

@ -8,6 +8,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{
class KProcessCapabilities
{
private const int SvcMaskElementBits = 8;
public byte[] SvcAccessMask { get; }
public byte[] IrqAccessMask { get; }
@ -22,7 +24,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
public KProcessCapabilities()
{
// length / number of bits of the underlying type
SvcAccessMask = new byte[KernelConstants.SupervisorCallCount / 8];
SvcAccessMask = new byte[KernelConstants.SupervisorCallCount / SvcMaskElementBits];
IrqAccessMask = new byte[0x80];
}
@ -208,7 +210,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
return KernelResult.MaximumExceeded;
}
SvcAccessMask[svcId / 8] |= (byte)(1 << (svcId & 7));
SvcAccessMask[svcId / SvcMaskElementBits] |= (byte)(1 << (svcId % SvcMaskElementBits));
}
break;
@ -324,5 +326,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
return mask << (int)min;
}
public bool IsSvcPermitted(int svcId)
{
int index = svcId / SvcMaskElementBits;
int mask = 1 << (svcId % SvcMaskElementBits);
return (uint)svcId < KernelConstants.SupervisorCallCount && (SvcAccessMask[index] & mask) != 0;
}
}
}

View File

@ -29,6 +29,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
PoolPartitionMask = 0xf << PoolPartitionShift,
OptimizeMemoryAllocation = 1 << 11,
DisableDeviceAddressSpaceMerge = 1 << 12,
EnableAliasRegionExtraSize = 1 << 13,
All =
Is64Bit |
@ -38,6 +40,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
IsApplication |
DeprecatedUseSecureMemory |
PoolPartitionMask |
OptimizeMemoryAllocation,
OptimizeMemoryAllocation |
DisableDeviceAddressSpaceMerge |
EnableAliasRegionExtraSize,
}
}

View File

@ -21,14 +21,17 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
SystemResourceSizeTotal,
SystemResourceSizeUsed,
ProgramId,
// NOTE: Added in 4.0.0, removed in 5.0.0.
InitialProcessIdRange,
InitialProcessIdRange, // NOTE: Added in 4.0.0, removed in 5.0.0.
UserExceptionContextAddress,
TotalNonSystemMemorySize,
UsedNonSystemMemorySize,
IsApplication,
FreeThreadCount,
ThreadTickCount,
IsSvcPermitted,
IoRegionHint,
AliasRegionExtraSize,
MesosphereCurrentProcess = 65001,
}
}

View File

@ -84,6 +84,17 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.InvalidSize;
}
if (info.Flags.HasFlag(ProcessCreationFlags.EnableAliasRegionExtraSize))
{
if ((info.Flags & ProcessCreationFlags.AddressSpaceMask) != ProcessCreationFlags.AddressSpace64Bit ||
info.SystemResourcePagesCount <= 0)
{
return KernelResult.InvalidState;
}
// TODO: Check that we are in debug mode.
}
if (info.Flags.HasFlag(ProcessCreationFlags.OptimizeMemoryAllocation) &&
!info.Flags.HasFlag(ProcessCreationFlags.IsApplication))
{
@ -139,7 +150,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return handleTable.GenerateHandle(process, out handle);
}
#pragma warning disable CA1822 // Mark member as static
public Result StartProcess(int handle, int priority, int cpuCore, ulong mainThreadStackSize)
{
KProcess process = KernelStatic.GetCurrentProcess().HandleTable.GetObject<KProcess>(handle);
@ -172,17 +182,14 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return Result.Success;
}
#pragma warning restore CA1822
[Svc(0x5f)]
#pragma warning disable CA1822 // Mark member as static
public Result FlushProcessDataCache(int processHandle, ulong address, ulong size)
{
// FIXME: This needs to be implemented as ARMv7 doesn't have any way to do cache maintenance operations on EL0.
// As we don't support (and don't actually need) to flush the cache, this is stubbed.
return Result.Success;
}
#pragma warning restore CA1822
// IPC
@ -256,7 +263,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x22)]
#pragma warning disable CA1822 // Mark member as static
public Result SendSyncRequestWithUserBuffer(
[PointerSized] ulong messagePtr,
[PointerSized] ulong messageSize,
@ -306,7 +312,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return result;
}
#pragma warning restore CA1822
[Svc(0x23)]
public Result SendAsyncRequestWithUserBuffer(
@ -896,7 +901,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(2)]
#pragma warning disable CA1822 // Mark member as static
public Result SetMemoryPermission([PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
{
if (!PageAligned(address))
@ -928,10 +932,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return currentProcess.MemoryManager.SetMemoryPermission(address, size, permission);
}
#pragma warning restore CA1822
[Svc(3)]
#pragma warning disable CA1822 // Mark member as static
public Result SetMemoryAttribute(
[PointerSized] ulong address,
[PointerSized] ulong size,
@ -979,10 +981,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return result;
}
#pragma warning restore CA1822
[Svc(4)]
#pragma warning disable CA1822 // Mark member as static
public Result MapMemory([PointerSized] ulong dst, [PointerSized] ulong src, [PointerSized] ulong size)
{
if (!PageAligned(src | dst))
@ -1018,10 +1018,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return process.MemoryManager.Map(dst, src, size);
}
#pragma warning restore CA1822
[Svc(5)]
#pragma warning disable CA1822 // Mark member as static
public Result UnmapMemory([PointerSized] ulong dst, [PointerSized] ulong src, [PointerSized] ulong size)
{
if (!PageAligned(src | dst))
@ -1057,7 +1055,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return process.MemoryManager.Unmap(dst, src, size);
}
#pragma warning restore CA1822
[Svc(6)]
public Result QueryMemory([PointerSized] ulong infoPtr, [PointerSized] out ulong pageInfo, [PointerSized] ulong address)
@ -1074,7 +1071,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return result;
}
#pragma warning disable CA1822 // Mark member as static
public Result QueryMemory(out MemoryInfo info, out ulong pageInfo, ulong address)
{
KProcess process = KernelStatic.GetCurrentProcess();
@ -1094,10 +1090,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return Result.Success;
}
#pragma warning restore CA1822
[Svc(0x13)]
#pragma warning disable CA1822 // Mark member as static
public Result MapSharedMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
{
if (!PageAligned(address))
@ -1143,10 +1137,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
currentProcess,
permission);
}
#pragma warning restore CA1822
[Svc(0x14)]
#pragma warning disable CA1822 // Mark member as static
public Result UnmapSharedMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size)
{
if (!PageAligned(address))
@ -1186,7 +1178,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
size,
currentProcess);
}
#pragma warning restore CA1822
[Svc(0x15)]
public Result CreateTransferMemory(out int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
@ -1253,7 +1244,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x51)]
#pragma warning disable CA1822 // Mark member as static
public Result MapTransferMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
{
if (!PageAligned(address))
@ -1299,10 +1289,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
currentProcess,
permission);
}
#pragma warning restore CA1822
[Svc(0x52)]
#pragma warning disable CA1822 // Mark member as static
public Result UnmapTransferMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size)
{
if (!PageAligned(address))
@ -1342,10 +1330,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
size,
currentProcess);
}
#pragma warning restore CA1822
[Svc(0x2c)]
#pragma warning disable CA1822 // Mark member as static
public Result MapPhysicalMemory([PointerSized] ulong address, [PointerSized] ulong size)
{
if (!PageAligned(address))
@ -1380,10 +1366,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return process.MemoryManager.MapPhysicalMemory(address, size);
}
#pragma warning restore CA1822
[Svc(0x2d)]
#pragma warning disable CA1822 // Mark member as static
public Result UnmapPhysicalMemory([PointerSized] ulong address, [PointerSized] ulong size)
{
if (!PageAligned(address))
@ -1418,7 +1402,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return process.MemoryManager.UnmapPhysicalMemory(address, size);
}
#pragma warning restore CA1822
[Svc(0x4b)]
public Result CreateCodeMemory(out int handle, [PointerSized] ulong address, [PointerSized] ulong size)
@ -1462,7 +1445,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x4c)]
#pragma warning disable CA1822 // Mark member as static
public Result ControlCodeMemory(
int handle,
CodeMemoryOperation op,
@ -1540,10 +1522,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.InvalidEnumValue;
}
}
#pragma warning restore CA1822
[Svc(0x73)]
#pragma warning disable CA1822 // Mark member as static
public Result SetProcessMemoryPermission(
int handle,
ulong src,
@ -1584,10 +1564,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return targetProcess.MemoryManager.SetProcessMemoryPermission(src, size, permission);
}
#pragma warning restore CA1822
[Svc(0x74)]
#pragma warning disable CA1822 // Mark member as static
public Result MapProcessMemory(
[PointerSized] ulong dst,
int handle,
@ -1643,10 +1621,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return dstProcess.MemoryManager.MapPages(dst, pageList, MemoryState.ProcessMemory, KMemoryPermission.ReadAndWrite);
}
#pragma warning restore CA1822
[Svc(0x75)]
#pragma warning disable CA1822 // Mark member as static
public Result UnmapProcessMemory(
[PointerSized] ulong dst,
int handle,
@ -1691,10 +1667,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return Result.Success;
}
#pragma warning restore CA1822
[Svc(0x77)]
#pragma warning disable CA1822 // Mark member as static
public Result MapProcessCodeMemory(int handle, ulong dst, ulong src, ulong size)
{
if (!PageAligned(dst) || !PageAligned(src))
@ -1731,10 +1705,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return targetProcess.MemoryManager.MapProcessCodeMemory(dst, src, size);
}
#pragma warning restore CA1822
[Svc(0x78)]
#pragma warning disable CA1822 // Mark member as static
public Result UnmapProcessCodeMemory(int handle, ulong dst, ulong src, ulong size)
{
if (!PageAligned(dst) || !PageAligned(src))
@ -1771,7 +1743,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return targetProcess.MemoryManager.UnmapProcessCodeMemory(dst, src, size);
}
#pragma warning restore CA1822
private static bool PageAligned(ulong address)
{
@ -1781,7 +1752,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
// System
[Svc(0x7b)]
#pragma warning disable CA1822 // Mark member as static
public Result TerminateProcess(int handle)
{
KProcess process = KernelStatic.GetCurrentProcess();
@ -1810,15 +1780,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return result;
}
#pragma warning restore CA1822
[Svc(7)]
#pragma warning disable CA1822 // Mark member as static
public void ExitProcess()
{
KernelStatic.GetCurrentProcess().TerminateCurrentProcess();
}
#pragma warning restore CA1822
[Svc(0x11)]
public Result SignalEvent(int handle)
@ -1911,7 +1878,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x26)]
#pragma warning disable CA1822 // Mark member as static
public void Break(ulong reason)
{
KThread currentThread = KernelStatic.GetCurrentThread();
@ -1937,10 +1903,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
Logger.Debug?.Print(LogClass.KernelSvc, "Debugger triggered.");
}
}
#pragma warning restore CA1822
[Svc(0x27)]
#pragma warning disable CA1822 // Mark member as static
public void OutputDebugString([PointerSized] ulong strPtr, [PointerSized] ulong size)
{
KProcess process = KernelStatic.GetCurrentProcess();
@ -1949,7 +1913,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
Logger.Warning?.Print(LogClass.KernelSvc, str);
}
#pragma warning restore CA1822
[Svc(0x29)]
public Result GetInfo(out ulong value, InfoType id, int handle, long subId)
@ -1978,6 +1941,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
case InfoType.UsedNonSystemMemorySize:
case InfoType.IsApplication:
case InfoType.FreeThreadCount:
case InfoType.AliasRegionExtraSize:
{
if (subId != 0)
{
@ -2006,22 +1970,19 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
value = process.MemoryManager.AliasRegionStart;
break;
case InfoType.AliasRegionSize:
value = (process.MemoryManager.AliasRegionEnd -
process.MemoryManager.AliasRegionStart);
value = process.MemoryManager.AliasRegionEnd - process.MemoryManager.AliasRegionStart;
break;
case InfoType.HeapRegionAddress:
value = process.MemoryManager.HeapRegionStart;
break;
case InfoType.HeapRegionSize:
value = (process.MemoryManager.HeapRegionEnd -
process.MemoryManager.HeapRegionStart);
value = process.MemoryManager.HeapRegionEnd - process.MemoryManager.HeapRegionStart;
break;
case InfoType.TotalMemorySize:
value = process.GetMemoryCapacity();
break;
case InfoType.UsedMemorySize:
value = process.GetMemoryUsage();
break;
@ -2029,7 +1990,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
case InfoType.AslrRegionAddress:
value = process.MemoryManager.GetAddrSpaceBaseAddr();
break;
case InfoType.AslrRegionSize:
value = process.MemoryManager.GetAddrSpaceSize();
break;
@ -2038,20 +1998,17 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
value = process.MemoryManager.StackRegionStart;
break;
case InfoType.StackRegionSize:
value = (process.MemoryManager.StackRegionEnd -
process.MemoryManager.StackRegionStart);
value = process.MemoryManager.StackRegionEnd - process.MemoryManager.StackRegionStart;
break;
case InfoType.SystemResourceSizeTotal:
value = process.PersonalMmHeapPagesCount * KPageTableBase.PageSize;
break;
case InfoType.SystemResourceSizeUsed:
if (process.PersonalMmHeapPagesCount != 0)
{
value = process.MemoryManager.GetMmUsedPages() * KPageTableBase.PageSize;
}
break;
case InfoType.ProgramId:
@ -2065,7 +2022,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
case InfoType.TotalNonSystemMemorySize:
value = process.GetMemoryCapacityWithoutPersonalMmHeap();
break;
case InfoType.UsedNonSystemMemorySize:
value = process.GetMemoryUsageWithoutPersonalMmHeap();
break;
@ -2084,10 +2040,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
value = 0;
}
break;
case InfoType.AliasRegionExtraSize:
value = process.MemoryManager.AliasRegionExtraSize;
break;
}
break;
}
@ -2104,7 +2062,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
value = KernelStatic.GetCurrentProcess().Debug ? 1UL : 0UL;
break;
}
@ -2136,7 +2093,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
value = (uint)resLimHandle;
}
break;
}
@ -2155,7 +2111,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
value = (ulong)KTimeManager.ConvertHostTicksToTicks(_context.Schedulers[currentCore].TotalIdleTimeTicks);
break;
}
@ -2174,7 +2129,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
KProcess currentProcess = KernelStatic.GetCurrentProcess();
value = currentProcess.RandomEntropy[subId];
break;
}
@ -2220,7 +2174,22 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
value = (ulong)KTimeManager.ConvertHostTicksToTicks(totalTimeRunning);
}
break;
}
case InfoType.IsSvcPermitted:
{
if (handle != 0)
{
return KernelResult.InvalidHandle;
}
if (subId != 0x36)
{
return KernelResult.InvalidCombination;
}
value = KernelStatic.GetCurrentProcess().IsSvcPermitted((int)subId) ? 1UL : 0UL;
break;
}
@ -2231,7 +2200,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.InvalidHandle;
}
if ((ulong)subId != 0)
if (subId != 0)
{
return KernelResult.InvalidCombination;
}
@ -2246,8 +2215,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return result;
}
value = (ulong)outHandle;
value = (uint)outHandle;
break;
}
@ -2398,7 +2366,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x30)]
#pragma warning disable CA1822 // Mark member as static
public Result GetResourceLimitLimitValue(out long limitValue, int handle, LimitableResource resource)
{
limitValue = 0;
@ -2419,10 +2386,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return Result.Success;
}
#pragma warning restore CA1822
[Svc(0x31)]
#pragma warning disable CA1822 // Mark member as static
public Result GetResourceLimitCurrentValue(out long limitValue, int handle, LimitableResource resource)
{
limitValue = 0;
@ -2443,10 +2408,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return Result.Success;
}
#pragma warning restore CA1822
[Svc(0x37)]
#pragma warning disable CA1822 // Mark member as static
public Result GetResourceLimitPeakValue(out long peak, int handle, LimitableResource resource)
{
peak = 0;
@ -2467,7 +2430,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return Result.Success;
}
#pragma warning restore CA1822
[Svc(0x7d)]
public Result CreateResourceLimit(out int handle)
@ -2480,7 +2442,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x7e)]
#pragma warning disable CA1822 // Mark member as static
public Result SetResourceLimitLimitValue(int handle, LimitableResource resource, long limitValue)
{
if (resource >= LimitableResource.Count)
@ -2497,7 +2458,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return resourceLimit.SetLimitValue(resource, limitValue);
}
#pragma warning restore CA1822
// Thread
@ -2577,7 +2537,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(9)]
#pragma warning disable CA1822 // Mark member as static
public Result StartThread(int handle)
{
KProcess process = KernelStatic.GetCurrentProcess();
@ -2604,17 +2563,14 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.InvalidHandle;
}
}
#pragma warning restore CA1822
[Svc(0xa)]
#pragma warning disable CA1822 // Mark member as static
public void ExitThread()
{
KThread currentThread = KernelStatic.GetCurrentThread();
currentThread.Exit();
}
#pragma warning restore CA1822
[Svc(0xb)]
public void SleepThread(long timeout)
@ -2641,7 +2597,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0xc)]
#pragma warning disable CA1822 // Mark member as static
public Result GetThreadPriority(out int priority, int handle)
{
KProcess process = KernelStatic.GetCurrentProcess();
@ -2661,10 +2616,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.InvalidHandle;
}
}
#pragma warning restore CA1822
[Svc(0xd)]
#pragma warning disable CA1822 // Mark member as static
public Result SetThreadPriority(int handle, int priority)
{
// TODO: NPDM check.
@ -2682,10 +2635,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return Result.Success;
}
#pragma warning restore CA1822
[Svc(0xe)]
#pragma warning disable CA1822 // Mark member as static
public Result GetThreadCoreMask(out int preferredCore, out ulong affinityMask, int handle)
{
KProcess process = KernelStatic.GetCurrentProcess();
@ -2707,10 +2658,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.InvalidHandle;
}
}
#pragma warning restore CA1822
[Svc(0xf)]
#pragma warning disable CA1822 // Mark member as static
public Result SetThreadCoreMask(int handle, int preferredCore, ulong affinityMask)
{
KProcess currentProcess = KernelStatic.GetCurrentProcess();
@ -2758,18 +2707,14 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return thread.SetCoreAndAffinityMask(preferredCore, affinityMask);
}
#pragma warning restore CA1822
[Svc(0x10)]
#pragma warning disable CA1822 // Mark member as static
public int GetCurrentProcessorNumber()
{
return KernelStatic.GetCurrentThread().CurrentCore;
}
#pragma warning restore CA1822
[Svc(0x25)]
#pragma warning disable CA1822 // Mark member as static
public Result GetThreadId(out ulong threadUid, int handle)
{
KProcess process = KernelStatic.GetCurrentProcess();
@ -2789,10 +2734,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.InvalidHandle;
}
}
#pragma warning restore CA1822
[Svc(0x32)]
#pragma warning disable CA1822 // Mark member as static
public Result SetThreadActivity(int handle, bool pause)
{
KProcess process = KernelStatic.GetCurrentProcess();
@ -2816,10 +2759,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return thread.SetActivity(pause);
}
#pragma warning restore CA1822
[Svc(0x33)]
#pragma warning disable CA1822 // Mark member as static
public Result GetThreadContext3([PointerSized] ulong address, int handle)
{
KProcess currentProcess = KernelStatic.GetCurrentProcess();
@ -2853,7 +2794,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return result;
}
#pragma warning restore CA1822
// Thread synchronization
@ -2986,7 +2926,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
[Svc(0x1a)]
#pragma warning disable CA1822 // Mark member as static
public Result ArbitrateLock(int ownerHandle, [PointerSized] ulong mutexAddress, int requesterHandle)
{
if (IsPointingInsideKernel(mutexAddress))
@ -3003,10 +2942,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return currentProcess.AddressArbiter.ArbitrateLock(ownerHandle, mutexAddress, requesterHandle);
}
#pragma warning restore CA1822
[Svc(0x1b)]
#pragma warning disable CA1822 // Mark member as static
public Result ArbitrateUnlock([PointerSized] ulong mutexAddress)
{
if (IsPointingInsideKernel(mutexAddress))
@ -3023,10 +2960,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return currentProcess.AddressArbiter.ArbitrateUnlock(mutexAddress);
}
#pragma warning restore CA1822
[Svc(0x1c)]
#pragma warning disable CA1822 // Mark member as static
public Result WaitProcessWideKeyAtomic(
[PointerSized] ulong mutexAddress,
[PointerSized] ulong condVarAddress,
@ -3056,10 +2991,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
handle,
timeout);
}
#pragma warning restore CA1822
[Svc(0x1d)]
#pragma warning disable CA1822 // Mark member as static
public Result SignalProcessWideKey([PointerSized] ulong address, int count)
{
KProcess currentProcess = KernelStatic.GetCurrentProcess();
@ -3068,10 +3001,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return Result.Success;
}
#pragma warning restore CA1822
[Svc(0x34)]
#pragma warning disable CA1822 // Mark member as static
public Result WaitForAddress([PointerSized] ulong address, ArbitrationType type, int value, long timeout)
{
if (IsPointingInsideKernel(address))
@ -3102,10 +3033,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
_ => KernelResult.InvalidEnumValue,
};
}
#pragma warning restore CA1822
[Svc(0x35)]
#pragma warning disable CA1822 // Mark member as static
public Result SignalToAddress([PointerSized] ulong address, SignalType type, int value, int count)
{
if (IsPointingInsideKernel(address))
@ -3131,17 +3060,14 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
_ => KernelResult.InvalidEnumValue,
};
}
#pragma warning restore CA1822
[Svc(0x36)]
#pragma warning disable CA1822 // Mark member as static
public Result SynchronizePreemptionState()
{
KernelStatic.GetCurrentThread().SynchronizePreemptionState();
return Result.Success;
}
#pragma warning restore CA1822
// Not actual syscalls, used by HLE services and such.

View File

@ -9,5 +9,6 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu.Types
public byte Sm0TpcIndex;
public byte Sm1GpcIndex;
public byte Sm1TpcIndex;
public uint Reserved;
}
}

View File

@ -266,8 +266,18 @@ namespace Ryujinx.UI.App.Common
public bool TryGetApplicationsFromFile(string applicationPath, out List<ApplicationData> applications)
{
applications = [];
long fileSize;
long fileSize = new FileInfo(applicationPath).Length;
try
{
fileSize = new FileInfo(applicationPath).Length;
}
catch (FileNotFoundException)
{
Logger.Warning?.Print(LogClass.Application, $"The file was not found: '{applicationPath}'");
return false;
}
BlitStruct<ApplicationControlProperty> controlHolder = new(1);
@ -502,7 +512,13 @@ namespace Ryujinx.UI.App.Common
try
{
IEnumerable<string> files = Directory.EnumerateFiles(appDir, "*", SearchOption.AllDirectories).Where(file =>
EnumerationOptions options = new()
{
RecurseSubdirectories = true,
IgnoreInaccessible = false,
};
IEnumerable<string> files = Directory.EnumerateFiles(appDir, "*", options).Where(file =>
{
return
(Path.GetExtension(file).ToLower() is ".nsp" && ConfigurationState.Instance.UI.ShownFileTypes.NSP.Value) ||
@ -521,14 +537,18 @@ namespace Ryujinx.UI.App.Common
}
var fileInfo = new FileInfo(app);
string extension = fileInfo.Extension.ToLower();
if (!fileInfo.Attributes.HasFlag(FileAttributes.Hidden) && extension is ".nsp" or ".pfs0" or ".xci" or ".nca" or ".nro" or ".nso")
try
{
var fullPath = fileInfo.ResolveLinkTarget(true)?.FullName ?? fileInfo.FullName;
applicationPaths.Add(fullPath);
numApplicationsFound++;
}
catch (IOException exception)
{
Logger.Warning?.Print(LogClass.Application, $"Failed to resolve the full path to file: \"{app}\" Error: {exception}");
}
}
}
catch (UnauthorizedAccessException)

View File

@ -1,21 +1,20 @@
using LibHac.Ns;
using Ryujinx.Ava.Common.Locale;
namespace Ryujinx.Ava.UI.Models
{
public class TitleUpdateModel
{
public ApplicationControlProperty Control { get; }
public uint Version { get; }
public string Path { get; }
public string Label { get; }
public string Label => LocaleManager.Instance.UpdateAndGetDynamicValue(
System.IO.Path.GetExtension(Path)?.ToLower() == ".xci" ? LocaleKeys.TitleBundledUpdateVersionLabel : LocaleKeys.TitleUpdateVersionLabel,
Control.DisplayVersionString.ToString()
);
public TitleUpdateModel(ApplicationControlProperty control, string path)
public TitleUpdateModel(uint version, string displayVersion, string path)
{
Control = control;
Version = version;
Label = LocaleManager.Instance.UpdateAndGetDynamicValue(
System.IO.Path.GetExtension(path)?.ToLower() == ".xci" ? LocaleKeys.TitleBundledUpdateVersionLabel : LocaleKeys.TitleUpdateVersionLabel,
displayVersion
);
Path = path;
}
}

View File

@ -131,26 +131,11 @@ namespace Ryujinx.Ava.UI.ViewModels
public void SortUpdates()
{
var list = TitleUpdates.ToList();
list.Sort((first, second) =>
{
if (string.IsNullOrEmpty(first.Control.DisplayVersionString.ToString()))
{
return -1;
}
if (string.IsNullOrEmpty(second.Control.DisplayVersionString.ToString()))
{
return 1;
}
return Version.Parse(first.Control.DisplayVersionString.ToString()).CompareTo(Version.Parse(second.Control.DisplayVersionString.ToString())) * -1;
});
var sortedUpdates = TitleUpdates.OrderByDescending(update => update.Version);
Views.Clear();
Views.Add(new BaseModel());
Views.AddRange(list);
Views.AddRange(sortedUpdates);
if (SelectedUpdate == null)
{
@ -204,7 +189,9 @@ namespace Ryujinx.Ava.UI.ViewModels
controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(ref nacpFile.Ref, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure();
var update = new TitleUpdateModel(controlData, path);
var displayVersion = controlData.DisplayVersionString.ToString();
var update = new TitleUpdateModel(content.Version.Version, displayVersion, path);
TitleUpdates.Add(update);
if (selected)