Compare commits

...

21 Commits

Author SHA1 Message Date
TSRBerry
07fc3ded68 [Ryujinx.Graphics.Nvdec] Address dotnet-format issues (#5369)
* dotnet format style --severity info

Some changes were manually reverted.

* Restore a few unused methods and variables

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Add previously silenced warnings back

I have no clue how these disappeared

* Add comments to disabled warnings

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Address IDE0251 warnings

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* First dotnet format pass
2023-06-25 21:44:42 +02:00
TSRBerry
fd01259d2b [Ryujinx.ShaderTools] Address dotnet-format issues (#5388)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format whitespace after rebase
2023-06-25 21:37:33 +02:00
TSRBerry
7ffe7f8442 [Ryujinx.Graphics.Nvdec.FFmpeg] Address dotnet-format issues (#5370)
* dotnet format style --severity info

Some changes were manually reverted.

* Address or silence dotnet format CA1806 and a few CA1854 warnings

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Add comments to disabled warnings

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Address IDE0251 warnings

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* First dotnet format pass
2023-06-25 19:03:48 +02:00
TSRBerry
2b2ce68f07 [Ryujinx.Tests.Memory] Address dotnet-format issues (#5390)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Restore a few unused methods and variables

* Silence dotnet format IDE0060 warnings

* Address dotnet format CA1822 warnings

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Add comments to disabled warnings

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Silence IDE0060 in .editorconfig

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* Final dotnet format pass and fix naming rule violations

* Apply suggestions from code review

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Remove unused constant

---------

Co-authored-by: Ac_K <Acoustik666@gmail.com>
2023-06-25 18:37:53 +02:00
TSRBerry
bc53d00463 [Ryujinx.Graphics.Vic] Address dotnet-format issues (#5374)
* dotnet format style --severity info

Some changes were manually reverted.

* Restore a few unused methods and variables

* Address review comments

* Address most dotnet format whitespace warnings

* Add comments to disabled warnings

* Address IDE0251 warnings

* dotnet format whitespace after rebase

* Remove SuppressMessage attribute for removed rule
2023-06-25 18:37:09 +02:00
TSRBerry
bddb2a1483 [Ryujinx.Tests.Unicorn] Address dotnet-format issues (#5391)
* dotnet format style --severity info

Some changes were manually reverted.

* Restore a few unused methods and variables

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Add comments to disabled warnings

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* Final dotnet format pass and fix naming rule violations
2023-06-25 18:03:08 +02:00
Shihta Kuan
e3bacfa774 Set COMPlus_DefaultStackSize to 2M in macOS (#5349)
* Set COMPlus_DefaultStackSize to 2M in macOS

* Remove the custom thread stack size on Ryujinx.Ava
2023-06-25 14:49:53 +02:00
TSRBerry
7c2f07d124 [Ryujinx.Horizon.Common] Address dotnet-format issues (#5382)
* dotnet format style --severity info

Some changes were manually reverted.

* Address most dotnet format whitespace warnings

* Address IDE0251 warnings

* dotnet format whitespace after rebase
2023-06-25 13:40:37 +02:00
TSRBerry
ede5b3c324 [Ryujinx.Audio.Backends.SoundIo] Address dotnet-format issues (#5360)
* dotnet format style --severity info

Some changes were manually reverted.

* Address dotnet format CA1816 warnings

* Address dotnet format CA1401 warnings

* Address most dotnet format whitespace warnings

* Run dotnet format after rebase and remove unused usings

- analyzers
- style
- whitespace

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* Address review feedback
2023-06-25 02:15:56 +02:00
TSRBerry
df5be5812f [Ryujinx.Audio.Backends.OpenAL] Address dotnet-format issues (#5359)
* dotnet format style --severity info

Some changes were manually reverted.

* Restore a few unused methods and variables

* Address dotnet format CA1816 warnings

* Address most dotnet format whitespace warnings

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase
2023-06-25 01:29:40 +02:00
Marco Carvalho
bc392e55df Empty "case" clauses that fall through to the "default" should be omitted (#5353)
* Empty "case" clauses that fall through to the "default" should be omitted

* default throw exception

* format
2023-06-24 12:06:58 +00:00
Marco Carvalho
fffc3ed193 Mutable fields should not be "public static" (#5352) 2023-06-24 12:01:59 +00:00
TSRBerry
7d160e98fd MemoryManagement: Change return types for Commit/Decommit to void (#5325)
* Replace return type with void for Commit/Decommit

* Small cleanup
2023-06-24 02:46:04 +02:00
Marco Carvalho
bf96bc84a8 "Where" should be used before "OrderBy" (#5346) 2023-06-23 00:51:44 +00:00
Marco Carvalho
91e4caaa69 "StartsWith" and "EndsWith" overloads that take a "char" should be used instead of the ones that take a "string" (#5347) 2023-06-23 02:15:14 +02:00
Marco Carvalho
efbd29463d "Find" method should be used instead of the "FirstOrDefault" extension (#5344) 2023-06-23 01:42:23 +02:00
Marco Carvalho
7608cb37ab "Exists" method should be used instead of the "Any" extension (#5345) 2023-06-23 01:37:25 +02:00
Kurochi51
d604e98227 Fix regression introduced by 1.1.1733 on Intel GPUs (#5311)
* Fix regression introduced by 1.1733 on Intel iGPUs

* Should have actually figured the variable, oops.

* maybe something goes wrong here? honestly lost

* Shader cache bump
2023-06-22 21:35:06 +02:00
Marco Carvalho
58907e2c29 GetHashCode should not reference mutable fields (#5331) 2023-06-22 18:36:07 +02:00
Mary
649d372f7d misc: Implement address space size workarounds (#5191)
* misc: Implement address space size workarounds

This adds code to support userland with less than 39 bits of address
space available by testing reserving multiple sizes and reducing
guess address space when needed.

This is required for ARM64 support when the kernel is
configured to use 63..39 bits for kernel space.(meaning only 38 bits is available to userland)

* Address comments

* Fix 32 bits address space support and address more comments
2023-06-20 17:33:54 +02:00
gdkchan
f9a538bb0f Ensure shader local and shared memory sizes are not zero (#5321) 2023-06-17 16:28:27 -03:00
116 changed files with 747 additions and 564 deletions

View File

@@ -39,10 +39,15 @@
<key>CSResourcesFileMapped</key> <key>CSResourcesFileMapped</key>
<true/> <true/>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>
<string>Copyright © 2018 - 2022 Ryujinx Team and Contributors.</string> <string>Copyright © 2018 - 2023 Ryujinx Team and Contributors.</string>
<key>LSApplicationCategoryType</key> <key>LSApplicationCategoryType</key>
<string>public.app-category.games</string> <string>public.app-category.games</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
<string>11.0</string> <string>11.0</string>
<key>LSEnvironment</key>
<dict>
<key>COMPlus_DefaultStackSize</key>
<string>200000</string>
</dict>
</dict> </dict>
</plist> </plist>

View File

@@ -228,7 +228,6 @@ namespace ARMeilleure.Instructions
switch (context.Fpcr.GetRoundingMode()) switch (context.Fpcr.GetRoundingMode())
{ {
default:
case FPRoundingMode.ToNearest: case FPRoundingMode.ToNearest:
roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u)); roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u));
overflowToInf = true; overflowToInf = true;
@@ -248,6 +247,9 @@ namespace ARMeilleure.Instructions
roundUp = false; roundUp = false;
overflowToInf = false; overflowToInf = false;
break; break;
default:
throw new ArgumentException($"Invalid rounding mode \"{context.Fpcr.GetRoundingMode()}\".");
} }
if (roundUp) if (roundUp)
@@ -412,7 +414,6 @@ namespace ARMeilleure.Instructions
switch (context.Fpcr.GetRoundingMode()) switch (context.Fpcr.GetRoundingMode())
{ {
default:
case FPRoundingMode.ToNearest: case FPRoundingMode.ToNearest:
roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u)); roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u));
overflowToInf = true; overflowToInf = true;
@@ -432,6 +433,9 @@ namespace ARMeilleure.Instructions
roundUp = false; roundUp = false;
overflowToInf = false; overflowToInf = false;
break; break;
default:
throw new ArgumentException($"Invalid rounding mode \"{context.Fpcr.GetRoundingMode()}\".");
} }
if (roundUp) if (roundUp)
@@ -585,7 +589,6 @@ namespace ARMeilleure.Instructions
switch (context.Fpcr.GetRoundingMode()) switch (context.Fpcr.GetRoundingMode())
{ {
default:
case FPRoundingMode.ToNearest: case FPRoundingMode.ToNearest:
roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u)); roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u));
overflowToInf = true; overflowToInf = true;
@@ -605,6 +608,9 @@ namespace ARMeilleure.Instructions
roundUp = false; roundUp = false;
overflowToInf = false; overflowToInf = false;
break; break;
default:
throw new ArgumentException($"Invalid rounding mode \"{context.Fpcr.GetRoundingMode()}\".");
} }
if (roundUp) if (roundUp)
@@ -1433,11 +1439,24 @@ namespace ARMeilleure.Instructions
switch (fpcr.GetRoundingMode()) switch (fpcr.GetRoundingMode())
{ {
case FPRoundingMode.ToNearest:
overflowToInf = true;
break;
case FPRoundingMode.TowardsPlusInfinity:
overflowToInf = !sign;
break;
case FPRoundingMode.TowardsMinusInfinity:
overflowToInf = sign;
break;
case FPRoundingMode.TowardsZero:
overflowToInf = false;
break;
default: default:
case FPRoundingMode.ToNearest: overflowToInf = true; break; throw new ArgumentException($"Invalid rounding mode \"{fpcr.GetRoundingMode()}\".");
case FPRoundingMode.TowardsPlusInfinity: overflowToInf = !sign; break;
case FPRoundingMode.TowardsMinusInfinity: overflowToInf = sign; break;
case FPRoundingMode.TowardsZero: overflowToInf = false; break;
} }
result = overflowToInf ? FPInfinity(sign) : FPMaxNormal(sign); result = overflowToInf ? FPInfinity(sign) : FPMaxNormal(sign);
@@ -2845,11 +2864,24 @@ namespace ARMeilleure.Instructions
switch (fpcr.GetRoundingMode()) switch (fpcr.GetRoundingMode())
{ {
case FPRoundingMode.ToNearest:
overflowToInf = true;
break;
case FPRoundingMode.TowardsPlusInfinity:
overflowToInf = !sign;
break;
case FPRoundingMode.TowardsMinusInfinity:
overflowToInf = sign;
break;
case FPRoundingMode.TowardsZero:
overflowToInf = false;
break;
default: default:
case FPRoundingMode.ToNearest: overflowToInf = true; break; throw new ArgumentException($"Invalid rounding mode \"{fpcr.GetRoundingMode()}\".");
case FPRoundingMode.TowardsPlusInfinity: overflowToInf = !sign; break;
case FPRoundingMode.TowardsMinusInfinity: overflowToInf = sign; break;
case FPRoundingMode.TowardsZero: overflowToInf = false; break;
} }
result = overflowToInf ? FPInfinity(sign) : FPMaxNormal(sign); result = overflowToInf ? FPInfinity(sign) : FPMaxNormal(sign);

View File

@@ -6,7 +6,7 @@ namespace ARMeilleure.Memory
{ {
IntPtr Pointer { get; } IntPtr Pointer { get; }
bool Commit(ulong offset, ulong size); void Commit(ulong offset, ulong size);
void MapAsRx(ulong offset, ulong size); void MapAsRx(ulong offset, ulong size);
void MapAsRwx(ulong offset, ulong size); void MapAsRwx(ulong offset, ulong size);

View File

@@ -13,8 +13,8 @@ namespace ARMeilleure.State
// _e0 & _e1 could be marked as readonly, however they are not readonly because we modify them through the Unsafe // _e0 & _e1 could be marked as readonly, however they are not readonly because we modify them through the Unsafe
// APIs. This also means that one should be careful when changing the layout of this struct. // APIs. This also means that one should be careful when changing the layout of this struct.
private ulong _e0; private readonly ulong _e0;
private ulong _e1; private readonly ulong _e1;
/// <summary> /// <summary>
/// Gets a new <see cref="V128"/> with all bits set to zero. /// Gets a new <see cref="V128"/> with all bits set to zero.

View File

@@ -18,7 +18,7 @@ namespace Ryujinx.Audio.Backends.OpenAL
private readonly ManualResetEvent _pauseEvent; private readonly ManualResetEvent _pauseEvent;
private readonly ConcurrentDictionary<OpenALHardwareDeviceSession, byte> _sessions; private readonly ConcurrentDictionary<OpenALHardwareDeviceSession, byte> _sessions;
private bool _stillRunning; private bool _stillRunning;
private Thread _updaterThread; private readonly Thread _updaterThread;
public OpenALHardwareDeviceDriver() public OpenALHardwareDeviceDriver()
{ {
@@ -73,7 +73,7 @@ namespace Ryujinx.Audio.Backends.OpenAL
throw new ArgumentException($"{channelCount}"); throw new ArgumentException($"{channelCount}");
} }
OpenALHardwareDeviceSession session = new OpenALHardwareDeviceSession(this, memoryManager, sampleFormat, sampleRate, channelCount, volume); OpenALHardwareDeviceSession session = new(this, memoryManager, sampleFormat, sampleRate, channelCount, volume);
_sessions.TryAdd(session, 0); _sessions.TryAdd(session, 0);
@@ -123,6 +123,7 @@ namespace Ryujinx.Audio.Backends.OpenAL
public void Dispose() public void Dispose()
{ {
GC.SuppressFinalize(this);
Dispose(true); Dispose(true);
} }

View File

@@ -10,11 +10,11 @@ namespace Ryujinx.Audio.Backends.OpenAL
{ {
class OpenALHardwareDeviceSession : HardwareDeviceSessionOutputBase class OpenALHardwareDeviceSession : HardwareDeviceSessionOutputBase
{ {
private OpenALHardwareDeviceDriver _driver; private readonly OpenALHardwareDeviceDriver _driver;
private int _sourceId; private readonly int _sourceId;
private ALFormat _targetFormat; private readonly ALFormat _targetFormat;
private bool _isActive; private bool _isActive;
private Queue<OpenALAudioBuffer> _queuedBuffers; private readonly Queue<OpenALAudioBuffer> _queuedBuffers;
private ulong _playedSampleCount; private ulong _playedSampleCount;
private readonly object _lock = new(); private readonly object _lock = new();
@@ -32,23 +32,17 @@ namespace Ryujinx.Audio.Backends.OpenAL
private ALFormat GetALFormat() private ALFormat GetALFormat()
{ {
switch (RequestedSampleFormat) return RequestedSampleFormat switch
{ {
case SampleFormat.PcmInt16: SampleFormat.PcmInt16 => RequestedChannelCount switch
switch (RequestedChannelCount) {
{ 1 => ALFormat.Mono16,
case 1: 2 => ALFormat.Stereo16,
return ALFormat.Mono16; 6 => ALFormat.Multi51Chn16Ext,
case 2: _ => throw new NotImplementedException($"Unsupported channel config {RequestedChannelCount}"),
return ALFormat.Stereo16; },
case 6: _ => throw new NotImplementedException($"Unsupported sample format {RequestedSampleFormat}"),
return ALFormat.Multi51Chn16Ext; };
default:
throw new NotImplementedException($"Unsupported channel config {RequestedChannelCount}");
}
default:
throw new NotImplementedException($"Unsupported sample format {RequestedSampleFormat}");
}
} }
public override void PrepareToClose() { } public override void PrepareToClose() { }
@@ -69,7 +63,7 @@ namespace Ryujinx.Audio.Backends.OpenAL
{ {
lock (_lock) lock (_lock)
{ {
OpenALAudioBuffer driverBuffer = new OpenALAudioBuffer OpenALAudioBuffer driverBuffer = new()
{ {
DriverIdentifier = buffer.DataPointer, DriverIdentifier = buffer.DataPointer,
BufferId = AL.GenBuffer(), BufferId = AL.GenBuffer(),

View File

@@ -10,19 +10,19 @@ namespace Ryujinx.Audio.Backends.SoundIo.Native
private const string LibraryName = "libsoundio"; private const string LibraryName = "libsoundio";
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public unsafe delegate void OnDeviceChangeNativeDelegate(IntPtr ctx); public delegate void OnDeviceChangeNativeDelegate(IntPtr ctx);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public unsafe delegate void OnBackendDisconnectedDelegate(IntPtr ctx, SoundIoError err); public delegate void OnBackendDisconnectedDelegate(IntPtr ctx, SoundIoError err);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public unsafe delegate void OnEventsSignalDelegate(IntPtr ctx); public delegate void OnEventsSignalDelegate(IntPtr ctx);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public unsafe delegate void EmitRtPrioWarningDelegate(); public delegate void EmitRtPrioWarningDelegate();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public unsafe delegate void JackCallbackDelegate(IntPtr msg); public delegate void JackCallbackDelegate(IntPtr msg);
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct SoundIoStruct public struct SoundIoStruct
@@ -110,69 +110,69 @@ namespace Ryujinx.Audio.Backends.SoundIo.Native
} }
[LibraryImport(LibraryName)] [LibraryImport(LibraryName)]
public static partial IntPtr soundio_create(); internal static partial IntPtr soundio_create();
[LibraryImport(LibraryName)] [LibraryImport(LibraryName)]
public static partial SoundIoError soundio_connect(IntPtr ctx); internal static partial SoundIoError soundio_connect(IntPtr ctx);
[LibraryImport(LibraryName)] [LibraryImport(LibraryName)]
public static partial void soundio_disconnect(IntPtr ctx); internal static partial void soundio_disconnect(IntPtr ctx);
[LibraryImport(LibraryName)] [LibraryImport(LibraryName)]
public static partial void soundio_flush_events(IntPtr ctx); internal static partial void soundio_flush_events(IntPtr ctx);
[LibraryImport(LibraryName)] [LibraryImport(LibraryName)]
public static partial int soundio_output_device_count(IntPtr ctx); internal static partial int soundio_output_device_count(IntPtr ctx);
[LibraryImport(LibraryName)] [LibraryImport(LibraryName)]
public static partial int soundio_default_output_device_index(IntPtr ctx); internal static partial int soundio_default_output_device_index(IntPtr ctx);
[LibraryImport(LibraryName)] [LibraryImport(LibraryName)]
public static partial IntPtr soundio_get_output_device(IntPtr ctx, int index); internal static partial IntPtr soundio_get_output_device(IntPtr ctx, int index);
[LibraryImport(LibraryName)] [LibraryImport(LibraryName)]
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
public static partial bool soundio_device_supports_format(IntPtr devCtx, SoundIoFormat format); internal static partial bool soundio_device_supports_format(IntPtr devCtx, SoundIoFormat format);
[LibraryImport(LibraryName)] [LibraryImport(LibraryName)]
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
public static partial bool soundio_device_supports_layout(IntPtr devCtx, IntPtr layout); internal static partial bool soundio_device_supports_layout(IntPtr devCtx, IntPtr layout);
[LibraryImport(LibraryName)] [LibraryImport(LibraryName)]
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
public static partial bool soundio_device_supports_sample_rate(IntPtr devCtx, int sampleRate); internal static partial bool soundio_device_supports_sample_rate(IntPtr devCtx, int sampleRate);
[LibraryImport(LibraryName)] [LibraryImport(LibraryName)]
public static partial IntPtr soundio_outstream_create(IntPtr devCtx); internal static partial IntPtr soundio_outstream_create(IntPtr devCtx);
[LibraryImport(LibraryName)] [LibraryImport(LibraryName)]
public static partial SoundIoError soundio_outstream_open(IntPtr outStreamCtx); internal static partial SoundIoError soundio_outstream_open(IntPtr outStreamCtx);
[LibraryImport(LibraryName)] [LibraryImport(LibraryName)]
public static partial SoundIoError soundio_outstream_start(IntPtr outStreamCtx); internal static partial SoundIoError soundio_outstream_start(IntPtr outStreamCtx);
[LibraryImport(LibraryName)] [LibraryImport(LibraryName)]
public static partial SoundIoError soundio_outstream_begin_write(IntPtr outStreamCtx, IntPtr areas, IntPtr frameCount); internal static partial SoundIoError soundio_outstream_begin_write(IntPtr outStreamCtx, IntPtr areas, IntPtr frameCount);
[LibraryImport(LibraryName)] [LibraryImport(LibraryName)]
public static partial SoundIoError soundio_outstream_end_write(IntPtr outStreamCtx); internal static partial SoundIoError soundio_outstream_end_write(IntPtr outStreamCtx);
[LibraryImport(LibraryName)] [LibraryImport(LibraryName)]
public static partial SoundIoError soundio_outstream_pause(IntPtr devCtx, [MarshalAs(UnmanagedType.Bool)] bool pause); internal static partial SoundIoError soundio_outstream_pause(IntPtr devCtx, [MarshalAs(UnmanagedType.Bool)] bool pause);
[LibraryImport(LibraryName)] [LibraryImport(LibraryName)]
public static partial SoundIoError soundio_outstream_set_volume(IntPtr devCtx, double volume); internal static partial SoundIoError soundio_outstream_set_volume(IntPtr devCtx, double volume);
[LibraryImport(LibraryName)] [LibraryImport(LibraryName)]
public static partial void soundio_outstream_destroy(IntPtr streamCtx); internal static partial void soundio_outstream_destroy(IntPtr streamCtx);
[LibraryImport(LibraryName)] [LibraryImport(LibraryName)]
public static partial void soundio_destroy(IntPtr ctx); internal static partial void soundio_destroy(IntPtr ctx);
[LibraryImport(LibraryName)] [LibraryImport(LibraryName)]
public static partial IntPtr soundio_channel_layout_get_default(int channelCount); internal static partial IntPtr soundio_channel_layout_get_default(int channelCount);
[LibraryImport(LibraryName)] [LibraryImport(LibraryName)]
public static partial IntPtr soundio_strerror(SoundIoError err); internal static partial IntPtr soundio_strerror(SoundIoError err);
} }
} }

View File

@@ -1,5 +1,4 @@
using System; using System;
using System.Reflection.Metadata;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading; using System.Threading;

View File

@@ -141,7 +141,7 @@ namespace Ryujinx.Audio.Backends.SoundIo
throw new NotImplementedException("Input direction is currently not implemented on SoundIO backend!"); throw new NotImplementedException("Input direction is currently not implemented on SoundIO backend!");
} }
SoundIoHardwareDeviceSession session = new SoundIoHardwareDeviceSession(this, memoryManager, sampleFormat, sampleRate, channelCount, volume); SoundIoHardwareDeviceSession session = new(this, memoryManager, sampleFormat, sampleRate, channelCount, volume);
_sessions.TryAdd(session, 0); _sessions.TryAdd(session, 0);
@@ -162,7 +162,7 @@ namespace Ryujinx.Audio.Backends.SoundIo
SampleFormat.PcmInt24 => SoundIoFormat.S24LE, SampleFormat.PcmInt24 => SoundIoFormat.S24LE,
SampleFormat.PcmInt32 => SoundIoFormat.S32LE, SampleFormat.PcmInt32 => SoundIoFormat.S32LE,
SampleFormat.PcmFloat => SoundIoFormat.Float32LE, SampleFormat.PcmFloat => SoundIoFormat.Float32LE,
_ => throw new ArgumentException ($"Unsupported sample format {format}"), _ => throw new ArgumentException($"Unsupported sample format {format}"),
}; };
} }
@@ -202,6 +202,8 @@ namespace Ryujinx.Audio.Backends.SoundIo
public void Dispose() public void Dispose()
{ {
GC.SuppressFinalize(this);
if (Interlocked.CompareExchange(ref _disposeState, 1, 0) == 0) if (Interlocked.CompareExchange(ref _disposeState, 1, 0) == 0)
{ {
Dispose(true); Dispose(true);

View File

@@ -12,12 +12,12 @@ namespace Ryujinx.Audio.Backends.SoundIo
{ {
class SoundIoHardwareDeviceSession : HardwareDeviceSessionOutputBase class SoundIoHardwareDeviceSession : HardwareDeviceSessionOutputBase
{ {
private SoundIoHardwareDeviceDriver _driver; private readonly SoundIoHardwareDeviceDriver _driver;
private ConcurrentQueue<SoundIoAudioBuffer> _queuedBuffers; private readonly ConcurrentQueue<SoundIoAudioBuffer> _queuedBuffers;
private SoundIoOutStreamContext _outputStream; private SoundIoOutStreamContext _outputStream;
private DynamicRingBuffer _ringBuffer; private readonly DynamicRingBuffer _ringBuffer;
private ulong _playedSampleCount; private ulong _playedSampleCount;
private ManualResetEvent _updateRequiredEvent; private readonly ManualResetEvent _updateRequiredEvent;
private int _disposeState; private int _disposeState;
public SoundIoHardwareDeviceSession(SoundIoHardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, float requestedVolume) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount) public SoundIoHardwareDeviceSession(SoundIoHardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, float requestedVolume) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount)
@@ -54,7 +54,7 @@ namespace Ryujinx.Audio.Backends.SoundIo
public override void QueueBuffer(AudioBuffer buffer) public override void QueueBuffer(AudioBuffer buffer)
{ {
SoundIoAudioBuffer driverBuffer = new SoundIoAudioBuffer(buffer.DataPointer, GetSampleCount(buffer)); SoundIoAudioBuffer driverBuffer = new(buffer.DataPointer, GetSampleCount(buffer));
_ringBuffer.Write(buffer.Data, 0, buffer.Data.Length); _ringBuffer.Write(buffer.Data, 0, buffer.Data.Length);
@@ -81,7 +81,7 @@ namespace Ryujinx.Audio.Backends.SoundIo
_driver.FlushContextEvents(); _driver.FlushContextEvents();
} }
public override void UnregisterBuffer(AudioBuffer buffer) {} public override void UnregisterBuffer(AudioBuffer buffer) { }
public override bool WasBufferFullyConsumed(AudioBuffer buffer) public override bool WasBufferFullyConsumed(AudioBuffer buffer)
{ {

View File

@@ -164,7 +164,7 @@ namespace Ryujinx.Audio
/// <summary> /// <summary>
/// The default coefficients used for standard 5.1 surround to stereo downmixing. /// The default coefficients used for standard 5.1 surround to stereo downmixing.
/// </summary> /// </summary>
public static float[] DefaultSurroundToStereoCoefficients = new float[4] public static readonly float[] DefaultSurroundToStereoCoefficients = new float[4]
{ {
1.0f, 1.0f,
0.707f, 0.707f,

View File

@@ -134,7 +134,7 @@ namespace Ryujinx.Ava
_inputManager = inputManager; _inputManager = inputManager;
_accountManager = accountManager; _accountManager = accountManager;
_userChannelPersistence = userChannelPersistence; _userChannelPersistence = userChannelPersistence;
_renderingThread = new Thread(RenderLoop, 1 * 1024 * 1024) { Name = "GUI.RenderThread" }; _renderingThread = new Thread(RenderLoop) { Name = "GUI.RenderThread" };
_lastCursorMoveTime = Stopwatch.GetTimestamp(); _lastCursorMoveTime = Stopwatch.GetTimestamp();
_glLogLevel = ConfigurationState.Instance.Logger.GraphicsDebugLevel; _glLogLevel = ConfigurationState.Instance.Logger.GraphicsDebugLevel;
_topLevel = topLevel; _topLevel = topLevel;

View File

@@ -264,7 +264,7 @@ namespace Ryujinx.Ava.UI.ViewModels
private void SelectLastScannedAmiibo() private void SelectLastScannedAmiibo()
{ {
AmiiboApi scanned = _amiiboList.FirstOrDefault(amiibo => amiibo.GetId() == LastScannedAmiiboId); AmiiboApi scanned = _amiiboList.Find(amiibo => amiibo.GetId() == LastScannedAmiiboId);
SeriesSelectedIndex = AmiiboSeries.IndexOf(scanned.AmiiboSeries); SeriesSelectedIndex = AmiiboSeries.IndexOf(scanned.AmiiboSeries);
AmiiboSelectedIndex = AmiiboList.IndexOf(scanned); AmiiboSelectedIndex = AmiiboList.IndexOf(scanned);
@@ -325,7 +325,7 @@ namespace Ryujinx.Ava.UI.ViewModels
AmiiboApi selected = _amiibos[_amiiboSelectedIndex]; AmiiboApi selected = _amiibos[_amiiboSelectedIndex];
string imageUrl = _amiiboList.FirstOrDefault(amiibo => amiibo.Equals(selected)).Image; string imageUrl = _amiiboList.Find(amiibo => amiibo.Equals(selected)).Image;
string usageString = ""; string usageString = "";

View File

@@ -5,7 +5,7 @@ using System;
namespace Ryujinx.Cpu namespace Ryujinx.Cpu
{ {
class AddressSpace : IDisposable public class AddressSpace : IDisposable
{ {
private const ulong PageSize = 0x1000; private const ulong PageSize = 0x1000;
@@ -154,7 +154,9 @@ namespace Ryujinx.Cpu
public MemoryBlock Base { get; } public MemoryBlock Base { get; }
public MemoryBlock Mirror { get; } public MemoryBlock Mirror { get; }
public AddressSpace(MemoryBlock backingMemory, ulong asSize, bool supports4KBPages) public ulong AddressSpaceSize { get; }
public AddressSpace(MemoryBlock backingMemory, MemoryBlock baseMemory, MemoryBlock mirrorMemory, ulong addressSpaceSize, bool supports4KBPages)
{ {
if (!supports4KBPages) if (!supports4KBPages)
{ {
@@ -163,17 +165,48 @@ namespace Ryujinx.Cpu
_privateTree = new IntrusiveRedBlackTree<PrivateMapping>(); _privateTree = new IntrusiveRedBlackTree<PrivateMapping>();
_treeLock = new object(); _treeLock = new object();
_mappingTree.Add(new Mapping(0UL, asSize, MappingType.None)); _mappingTree.Add(new Mapping(0UL, addressSpaceSize, MappingType.None));
_privateTree.Add(new PrivateMapping(0UL, asSize, default)); _privateTree.Add(new PrivateMapping(0UL, addressSpaceSize, default));
} }
_backingMemory = backingMemory; _backingMemory = backingMemory;
_supports4KBPages = supports4KBPages; _supports4KBPages = supports4KBPages;
Base = baseMemory;
Mirror = mirrorMemory;
AddressSpaceSize = addressSpaceSize;
}
public static bool TryCreate(MemoryBlock backingMemory, ulong asSize, bool supports4KBPages, out AddressSpace addressSpace)
{
addressSpace = null;
MemoryAllocationFlags asFlags = MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible; MemoryAllocationFlags asFlags = MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible;
Base = new MemoryBlock(asSize, asFlags); ulong minAddressSpaceSize = Math.Min(asSize, 1UL << 36);
Mirror = new MemoryBlock(asSize, asFlags);
// Attempt to create the address space with expected size or try to reduce it until it succeed.
for (ulong addressSpaceSize = asSize; addressSpaceSize >= minAddressSpaceSize; addressSpaceSize >>= 1)
{
MemoryBlock baseMemory = null;
MemoryBlock mirrorMemory = null;
try
{
baseMemory = new MemoryBlock(addressSpaceSize, asFlags);
mirrorMemory = new MemoryBlock(addressSpaceSize, asFlags);
addressSpace = new AddressSpace(backingMemory, baseMemory, mirrorMemory, addressSpaceSize, supports4KBPages);
break;
}
catch (OutOfMemoryException)
{
baseMemory?.Dispose();
mirrorMemory?.Dispose();
}
}
return addressSpace != null;
} }
public void Map(ulong va, ulong pa, ulong size, MemoryMapFlags flags) public void Map(ulong va, ulong pa, ulong size, MemoryMapFlags flags)

View File

@@ -15,7 +15,7 @@ namespace Ryujinx.Cpu.Jit
_impl = new MemoryBlock(size, flags); _impl = new MemoryBlock(size, flags);
} }
public bool Commit(ulong offset, ulong size) => _impl.Commit(offset, size); public void Commit(ulong offset, ulong size) => _impl.Commit(offset, size);
public void MapAsRx(ulong offset, ulong size) => _impl.Reprotect(offset, size, MemoryPermission.ReadAndExecute); public void MapAsRx(ulong offset, ulong size) => _impl.Reprotect(offset, size, MemoryPermission.ReadAndExecute);
public void MapAsRwx(ulong offset, ulong size) => _impl.Reprotect(offset, size, MemoryPermission.ReadWriteExecute); public void MapAsRwx(ulong offset, ulong size) => _impl.Reprotect(offset, size, MemoryPermission.ReadWriteExecute);

View File

@@ -38,7 +38,8 @@ namespace Ryujinx.Cpu.Jit
private readonly bool _unsafeMode; private readonly bool _unsafeMode;
private readonly AddressSpace _addressSpace; private readonly AddressSpace _addressSpace;
private readonly ulong _addressSpaceSize;
public ulong AddressSpaceSize { get; }
private readonly PageTable<ulong> _pageTable; private readonly PageTable<ulong> _pageTable;
@@ -62,21 +63,21 @@ namespace Ryujinx.Cpu.Jit
/// <summary> /// <summary>
/// Creates a new instance of the host mapped memory manager. /// Creates a new instance of the host mapped memory manager.
/// </summary> /// </summary>
/// <param name="backingMemory">Physical backing memory where virtual memory will be mapped to</param> /// <param name="addressSpace">Address space instance to use</param>
/// <param name="addressSpaceSize">Size of the address space</param>
/// <param name="unsafeMode">True if unmanaged access should not be masked (unsafe), false otherwise.</param> /// <param name="unsafeMode">True if unmanaged access should not be masked (unsafe), false otherwise.</param>
/// <param name="invalidAccessHandler">Optional function to handle invalid memory accesses</param> /// <param name="invalidAccessHandler">Optional function to handle invalid memory accesses</param>
public MemoryManagerHostMapped(MemoryBlock backingMemory, ulong addressSpaceSize, bool unsafeMode, InvalidAccessHandler invalidAccessHandler = null) public MemoryManagerHostMapped(AddressSpace addressSpace, bool unsafeMode, InvalidAccessHandler invalidAccessHandler)
{ {
_addressSpace = addressSpace;
_pageTable = new PageTable<ulong>(); _pageTable = new PageTable<ulong>();
_invalidAccessHandler = invalidAccessHandler; _invalidAccessHandler = invalidAccessHandler;
_unsafeMode = unsafeMode; _unsafeMode = unsafeMode;
_addressSpaceSize = addressSpaceSize; AddressSpaceSize = addressSpace.AddressSpaceSize;
ulong asSize = PageSize; ulong asSize = PageSize;
int asBits = PageBits; int asBits = PageBits;
while (asSize < addressSpaceSize) while (asSize < AddressSpaceSize)
{ {
asSize <<= 1; asSize <<= 1;
asBits++; asBits++;
@@ -86,8 +87,6 @@ namespace Ryujinx.Cpu.Jit
_pageBitmap = new ulong[1 << (AddressSpaceBits - (PageBits + PageToPteShift))]; _pageBitmap = new ulong[1 << (AddressSpaceBits - (PageBits + PageToPteShift))];
_addressSpace = new AddressSpace(backingMemory, asSize, Supports4KBPages);
Tracking = new MemoryTracking(this, (int)MemoryBlock.GetPageSize(), invalidAccessHandler); Tracking = new MemoryTracking(this, (int)MemoryBlock.GetPageSize(), invalidAccessHandler);
_memoryEh = new MemoryEhMeilleure(_addressSpace.Base, _addressSpace.Mirror, Tracking); _memoryEh = new MemoryEhMeilleure(_addressSpace.Base, _addressSpace.Mirror, Tracking);
} }
@@ -99,7 +98,7 @@ namespace Ryujinx.Cpu.Jit
/// <returns>True if the virtual address is part of the addressable space</returns> /// <returns>True if the virtual address is part of the addressable space</returns>
private bool ValidateAddress(ulong va) private bool ValidateAddress(ulong va)
{ {
return va < _addressSpaceSize; return va < AddressSpaceSize;
} }
/// <summary> /// <summary>
@@ -111,7 +110,7 @@ namespace Ryujinx.Cpu.Jit
private bool ValidateAddressAndSize(ulong va, ulong size) private bool ValidateAddressAndSize(ulong va, ulong size)
{ {
ulong endVa = va + size; ulong endVa = va + size;
return endVa >= va && endVa >= size && endVa <= _addressSpaceSize; return endVa >= va && endVa >= size && endVa <= AddressSpaceSize;
} }
/// <summary> /// <summary>

View File

@@ -512,7 +512,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <returns>True if at least one of the handles is dirty</returns> /// <returns>True if at least one of the handles is dirty</returns>
private bool CheckDirty() private bool CheckDirty()
{ {
return Handles.Any(handle => handle.Dirty); return Array.Exists(Handles, handle => handle.Dirty);
} }
/// <summary> /// <summary>

View File

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

View File

@@ -12,8 +12,8 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg
private readonly AVCodec_decode _decodeFrame; private readonly AVCodec_decode _decodeFrame;
private static readonly FFmpegApi.av_log_set_callback_callback _logFunc; private static readonly FFmpegApi.av_log_set_callback_callback _logFunc;
private readonly AVCodec* _codec; private readonly AVCodec* _codec;
private AVPacket* _packet; private readonly AVPacket* _packet;
private AVCodecContext* _context; private readonly AVCodecContext* _context;
public FFmpegContext(AVCodecID codecId) public FFmpegContext(AVCodecID codecId)
{ {
@@ -164,7 +164,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg
FFmpegApi.av_packet_free(ppPacket); FFmpegApi.av_packet_free(ppPacket);
} }
FFmpegApi.avcodec_close(_context); _ = FFmpegApi.avcodec_close(_context);
fixed (AVCodecContext** ppContext = &_context) fixed (AVCodecContext** ppContext = &_context)
{ {

View File

@@ -12,7 +12,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
private readonly byte[] _workBuffer = new byte[WorkBufferSize]; private readonly byte[] _workBuffer = new byte[WorkBufferSize];
private FFmpegContext _context = new FFmpegContext(AVCodecID.AV_CODEC_ID_H264); private FFmpegContext _context = new(AVCodecID.AV_CODEC_ID_H264);
private int _oldOutputWidth; private int _oldOutputWidth;
private int _oldOutputHeight; private int _oldOutputHeight;
@@ -46,7 +46,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
byte[] output = new byte[data.Length + prep.Length]; byte[] output = new byte[data.Length + prep.Length];
prep.CopyTo(output); prep.CopyTo(output);
data.CopyTo(new Span<byte>(output).Slice(prep.Length)); data.CopyTo(new Span<byte>(output)[prep.Length..]);
return output; return output;
} }

View File

@@ -84,9 +84,9 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
Flush(); Flush();
} }
public Span<byte> AsSpan() public readonly Span<byte> AsSpan()
{ {
return new Span<byte>(_workBuffer).Slice(0, _offset); return new Span<byte>(_workBuffer)[.._offset];
} }
public void WriteU(uint value, int valueSize) => WriteBits((int)value, valueSize); public void WriteU(uint value, int valueSize) => WriteBits((int)value, valueSize);

View File

@@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
{ {
public static Span<byte> Reconstruct(ref H264PictureInfo pictureInfo, byte[] workBuffer) public static Span<byte> Reconstruct(ref H264PictureInfo pictureInfo, byte[] workBuffer)
{ {
H264BitStreamWriter writer = new H264BitStreamWriter(workBuffer); H264BitStreamWriter writer = new(workBuffer);
// Sequence Parameter Set. // Sequence Parameter Set.
writer.WriteU(1, 24); writer.WriteU(1, 24);

View File

@@ -4,7 +4,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
{ {
struct AVCodec struct AVCodec
{ {
#pragma warning disable CS0649 #pragma warning disable CS0649 // Field is never assigned to
public unsafe byte* Name; public unsafe byte* Name;
public unsafe byte* LongName; public unsafe byte* LongName;
public int Type; public int Type;

View File

@@ -4,7 +4,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
{ {
struct AVCodec501 struct AVCodec501
{ {
#pragma warning disable CS0649 #pragma warning disable CS0649 // Field is never assigned to
public unsafe byte* Name; public unsafe byte* Name;
public unsafe byte* LongName; public unsafe byte* LongName;
public int Type; public int Type;

View File

@@ -5,7 +5,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
{ {
struct AVCodecContext struct AVCodecContext
{ {
#pragma warning disable CS0649 #pragma warning disable CS0649 // Field is never assigned to
public unsafe IntPtr AvClass; public unsafe IntPtr AvClass;
public int LogLevelOffset; public int LogLevelOffset;
public int CodecType; public int CodecType;

View File

@@ -5,7 +5,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
{ {
struct AVFrame struct AVFrame
{ {
#pragma warning disable CS0649 #pragma warning disable CS0649 // Field is never assigned to
public Array8<IntPtr> Data; public Array8<IntPtr> Data;
public Array8<int> LineSize; public Array8<int> LineSize;
public IntPtr ExtendedData; public IntPtr ExtendedData;

View File

@@ -1,25 +1,23 @@
using System; using AVBufferRef = System.IntPtr;
using AVBufferRef = System.IntPtr;
namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
{ {
struct AVPacket struct AVPacket
{ {
#pragma warning disable CS0649 #pragma warning disable CS0649 // Field is never assigned to
public unsafe AVBufferRef *Buf; public unsafe AVBufferRef* Buf;
public long Pts; public long Pts;
public long Dts; public long Dts;
public unsafe byte* Data; public unsafe byte* Data;
public int Size; public int Size;
public int StreamIndex; public int StreamIndex;
public int Flags; public int Flags;
public IntPtr SizeData; public AVBufferRef SizeData;
public int SizeDataElems; public int SizeDataElems;
public long Duration; public long Duration;
public long Position; public long Position;
public IntPtr Opaque; public AVBufferRef Opaque;
public unsafe AVBufferRef *OpaqueRef; public unsafe AVBufferRef* OpaqueRef;
public AVRational TimeBase; public AVRational TimeBase;
#pragma warning restore CS0649 #pragma warning restore CS0649
} }

View File

@@ -2,9 +2,9 @@
namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
{ {
struct FFCodec<T> where T: struct struct FFCodec<T> where T : struct
{ {
#pragma warning disable CS0649 #pragma warning disable CS0649 // Field is never assigned to
public T Base; public T Base;
public int CapsInternalOrCbType; public int CapsInternalOrCbType;
public int PrivDataSize; public int PrivDataSize;

View File

@@ -2,9 +2,9 @@
namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
{ {
struct FFCodecLegacy<T> where T: struct struct FFCodecLegacy<T> where T : struct
{ {
#pragma warning disable CS0649 #pragma warning disable CS0649 // Field is never assigned to
public T Base; public T Base;
public uint CapsInternalOrCbType; public uint CapsInternalOrCbType;
public int PrivDataSize; public int PrivDataSize;

View File

@@ -10,7 +10,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
public const string AvCodecLibraryName = "avcodec"; public const string AvCodecLibraryName = "avcodec";
public const string AvUtilLibraryName = "avutil"; public const string AvUtilLibraryName = "avutil";
private static readonly Dictionary<string, (int, int)> _librariesWhitelist = new Dictionary<string, (int, int)> private static readonly Dictionary<string, (int, int)> _librariesWhitelist = new()
{ {
{ AvCodecLibraryName, (58, 59) }, { AvCodecLibraryName, (58, 59) },
{ AvUtilLibraryName, (56, 57) } { AvUtilLibraryName, (56, 57) }
@@ -61,9 +61,8 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
{ {
NativeLibrary.SetDllImportResolver(typeof(FFmpegApi).Assembly, (name, assembly, path) => NativeLibrary.SetDllImportResolver(typeof(FFmpegApi).Assembly, (name, assembly, path) =>
{ {
IntPtr handle;
if (name == AvUtilLibraryName && TryLoadWhitelistedLibrary(AvUtilLibraryName, assembly, path, out handle)) if (name == AvUtilLibraryName && TryLoadWhitelistedLibrary(AvUtilLibraryName, assembly, path, out nint handle))
{ {
return handle; return handle;
} }
@@ -106,7 +105,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
internal static unsafe partial AVCodecContext* avcodec_alloc_context3(AVCodec* codec); internal static unsafe partial AVCodecContext* avcodec_alloc_context3(AVCodec* codec);
[LibraryImport(AvCodecLibraryName)] [LibraryImport(AvCodecLibraryName)]
internal static unsafe partial int avcodec_open2(AVCodecContext* avctx, AVCodec* codec, void **options); internal static unsafe partial int avcodec_open2(AVCodecContext* avctx, AVCodec* codec, void** options);
[LibraryImport(AvCodecLibraryName)] [LibraryImport(AvCodecLibraryName)]
internal static unsafe partial int avcodec_close(AVCodecContext* avctx); internal static unsafe partial int avcodec_close(AVCodecContext* avctx);

View File

@@ -11,9 +11,9 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg
public int RequestedWidth { get; } public int RequestedWidth { get; }
public int RequestedHeight { get; } public int RequestedHeight { get; }
public Plane YPlane => new Plane((IntPtr)Frame->Data[0], Stride * Height); public Plane YPlane => new((IntPtr)Frame->Data[0], Stride * Height);
public Plane UPlane => new Plane((IntPtr)Frame->Data[1], UvStride * UvHeight); public Plane UPlane => new((IntPtr)Frame->Data[1], UvStride * UvHeight);
public Plane VPlane => new Plane((IntPtr)Frame->Data[2], UvStride * UvHeight); public Plane VPlane => new((IntPtr)Frame->Data[2], UvStride * UvHeight);
public FrameField Field => Frame->InterlacedFrame != 0 ? FrameField.Interlaced : FrameField.Progressive; public FrameField Field => Frame->InterlacedFrame != 0 ? FrameField.Interlaced : FrameField.Progressive;

View File

@@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.Vp8
{ {
public bool IsHardwareAccelerated => false; public bool IsHardwareAccelerated => false;
private readonly FFmpegContext _context = new FFmpegContext(AVCodecID.AV_CODEC_ID_VP8); private readonly FFmpegContext _context = new(AVCodecID.AV_CODEC_ID_VP8);
public ISurface CreateSurface(int width, int height) public ISurface CreateSurface(int width, int height)
{ {
@@ -43,7 +43,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.Vp8
frame[9] = (byte)((pictureInfo.FrameHeight >> 8) & 0x3F); frame[9] = (byte)((pictureInfo.FrameHeight >> 8) & 0x3F);
} }
bitstream.CopyTo(new Span<byte>(frame).Slice(uncompHeaderSize)); bitstream.CopyTo(new Span<byte>(frame)[uncompHeaderSize..]);
return _context.DecodeFrame(outSurf, frame) == 0; return _context.DecodeFrame(outSurf, frame) == 0;
} }

View File

@@ -17,12 +17,12 @@ namespace Ryujinx.Graphics.Nvdec
ReadOnlySpan<byte> bitstream = rm.Gmm.DeviceGetSpan(state.SetInBufBaseOffset, (int)pictureInfo.BitstreamSize); ReadOnlySpan<byte> bitstream = rm.Gmm.DeviceGetSpan(state.SetInBufBaseOffset, (int)pictureInfo.BitstreamSize);
int width = (int)pictureInfo.PicWidthInMbs * MbSizeInPixels; int width = (int)pictureInfo.PicWidthInMbs * MbSizeInPixels;
int height = (int)pictureInfo.PicHeightInMbs * MbSizeInPixels; int height = (int)pictureInfo.PicHeightInMbs * MbSizeInPixels;
int surfaceIndex = (int)pictureInfo.OutputSurfaceIndex; int surfaceIndex = (int)pictureInfo.OutputSurfaceIndex;
uint lumaOffset = state.SetPictureLumaOffset[surfaceIndex]; uint lumaOffset = state.SetPictureLumaOffset[surfaceIndex];
uint chromaOffset = state.SetPictureChromaOffset[surfaceIndex]; uint chromaOffset = state.SetPictureChromaOffset[surfaceIndex];
Decoder decoder = context.GetH264Decoder(); Decoder decoder = context.GetH264Decoder();
@@ -36,7 +36,7 @@ namespace Ryujinx.Graphics.Nvdec
SurfaceWriter.Write( SurfaceWriter.Write(
rm.Gmm, rm.Gmm,
outputSurface, outputSurface,
lumaOffset + pictureInfo.LumaFrameOffset, lumaOffset + pictureInfo.LumaFrameOffset,
chromaOffset + pictureInfo.ChromaFrameOffset); chromaOffset + pictureInfo.ChromaFrameOffset);
} }
else else
@@ -44,9 +44,9 @@ namespace Ryujinx.Graphics.Nvdec
SurfaceWriter.WriteInterlaced( SurfaceWriter.WriteInterlaced(
rm.Gmm, rm.Gmm,
outputSurface, outputSurface,
lumaOffset + pictureInfo.LumaTopFieldOffset, lumaOffset + pictureInfo.LumaTopFieldOffset,
chromaOffset + pictureInfo.ChromaTopFieldOffset, chromaOffset + pictureInfo.ChromaTopFieldOffset,
lumaOffset + pictureInfo.LumaBottomFieldOffset, lumaOffset + pictureInfo.LumaBottomFieldOffset,
chromaOffset + pictureInfo.ChromaBottomFieldOffset); chromaOffset + pictureInfo.ChromaBottomFieldOffset);
} }
} }

View File

@@ -43,7 +43,7 @@ namespace Ryujinx.Graphics.Nvdec.Image
int width, int width,
int height) int height)
{ {
OffsetCalculator calc = new OffsetCalculator(width, height, 0, false, 2, 2); OffsetCalculator calc = new(width, height, 0, false, 2, 2);
if (Sse2.IsSupported) if (Sse2.IsSupported)
{ {

View File

@@ -60,7 +60,7 @@ namespace Ryujinx.Graphics.Nvdec.Image
WriteLuma( WriteLuma(
lumaBottom.Memory.Span, lumaBottom.Memory.Span,
surface.YPlane.AsSpan().Slice(surface.Stride), surface.YPlane.AsSpan()[surface.Stride..],
surface.Stride * 2, surface.Stride * 2,
surface.Width, surface.Width,
surface.Height / 2); surface.Height / 2);
@@ -80,8 +80,8 @@ namespace Ryujinx.Graphics.Nvdec.Image
WriteChroma( WriteChroma(
chromaBottom.Memory.Span, chromaBottom.Memory.Span,
surface.UPlane.AsSpan().Slice(surface.UvStride), surface.UPlane.AsSpan()[surface.UvStride..],
surface.VPlane.AsSpan().Slice(surface.UvStride), surface.VPlane.AsSpan()[surface.UvStride..],
surface.UvStride * 2, surface.UvStride * 2,
surface.UvWidth, surface.UvWidth,
surface.UvHeight / 2); surface.UvHeight / 2);
@@ -100,7 +100,7 @@ namespace Ryujinx.Graphics.Nvdec.Image
int width, int width,
int height) int height)
{ {
OffsetCalculator calc = new OffsetCalculator(width, height, 0, false, 2, 2); OffsetCalculator calc = new(width, height, 0, false, 2, 2);
if (Sse2.IsSupported) if (Sse2.IsSupported)
{ {

View File

@@ -14,7 +14,7 @@ namespace Ryujinx.Graphics.Nvdec
private readonly DeviceState<NvdecRegisters> _state; private readonly DeviceState<NvdecRegisters> _state;
private long _currentId; private long _currentId;
private ConcurrentDictionary<long, NvdecDecoderContext> _contexts; private readonly ConcurrentDictionary<long, NvdecDecoderContext> _contexts;
private NvdecDecoderContext _currentContext; private NvdecDecoderContext _currentContext;
public NvdecDevice(MemoryManager gmm) public NvdecDevice(MemoryManager gmm)

View File

@@ -4,7 +4,7 @@ namespace Ryujinx.Graphics.Nvdec
{ {
struct NvdecRegisters struct NvdecRegisters
{ {
#pragma warning disable CS0649 #pragma warning disable CS0649 // Field is never assigned to
public Array64<uint> Reserved0; public Array64<uint> Reserved0;
public uint Nop; public uint Nop;
public Array63<uint> Reserved104; public Array63<uint> Reserved104;

View File

@@ -4,7 +4,7 @@ namespace Ryujinx.Graphics.Nvdec
{ {
struct NvdecStatus struct NvdecStatus
{ {
#pragma warning disable CS0649 #pragma warning disable CS0649 // Field is never assigned to
public uint MbsCorrectlyDecoded; public uint MbsCorrectlyDecoded;
public uint MbsInError; public uint MbsInError;
public uint Reserved; public uint Reserved;

View File

@@ -5,8 +5,9 @@ namespace Ryujinx.Graphics.Nvdec.Types.H264
{ {
struct PictureInfo struct PictureInfo
{ {
#pragma warning disable CS0169, CS0649 #pragma warning disable IDE0051, CS0169, CS0649 // Remove unused private member
Array18<uint> Unknown0; Array18<uint> Unknown0;
#pragma warning restore IDE0051
public uint BitstreamSize; public uint BitstreamSize;
public uint NumSlices; public uint NumSlices;
public uint Unknown50; public uint Unknown50;
@@ -50,24 +51,24 @@ namespace Ryujinx.Graphics.Nvdec.Types.H264
public Array10<uint> Unknown2D4; public Array10<uint> Unknown2D4;
#pragma warning restore CS0169, CS0649 #pragma warning restore CS0169, CS0649
public bool MbAdaptiveFrameFieldFlag => (Flags & (1 << 0)) != 0; public readonly bool MbAdaptiveFrameFieldFlag => (Flags & (1 << 0)) != 0;
public bool Direct8x8InferenceFlag => (Flags & (1 << 1)) != 0; public readonly bool Direct8x8InferenceFlag => (Flags & (1 << 1)) != 0;
public bool WeightedPredFlag => (Flags & (1 << 2)) != 0; public readonly bool WeightedPredFlag => (Flags & (1 << 2)) != 0;
public bool ConstrainedIntraPredFlag => (Flags & (1 << 3)) != 0; public readonly bool ConstrainedIntraPredFlag => (Flags & (1 << 3)) != 0;
public bool IsReference => (Flags & (1 << 4)) != 0; public readonly bool IsReference => (Flags & (1 << 4)) != 0;
public bool FieldPicFlag => (Flags & (1 << 5)) != 0; public readonly bool FieldPicFlag => (Flags & (1 << 5)) != 0;
public bool BottomFieldFlag => (Flags & (1 << 6)) != 0; public readonly bool BottomFieldFlag => (Flags & (1 << 6)) != 0;
public uint Log2MaxFrameNumMinus4 => (uint)(Flags >> 8) & 0xf; public readonly uint Log2MaxFrameNumMinus4 => (uint)(Flags >> 8) & 0xf;
public ushort ChromaFormatIdc => (ushort)((Flags >> 12) & 3); public readonly ushort ChromaFormatIdc => (ushort)((Flags >> 12) & 3);
public uint PicOrderCntType => (uint)(Flags >> 14) & 3; public readonly uint PicOrderCntType => (uint)(Flags >> 14) & 3;
public int PicInitQpMinus26 => ExtractSx(Flags, 16, 6); public readonly int PicInitQpMinus26 => ExtractSx(Flags, 16, 6);
public int ChromaQpIndexOffset => ExtractSx(Flags, 22, 5); public readonly int ChromaQpIndexOffset => ExtractSx(Flags, 22, 5);
public int SecondChromaQpIndexOffset => ExtractSx(Flags, 27, 5); public readonly int SecondChromaQpIndexOffset => ExtractSx(Flags, 27, 5);
public uint WeightedBipredIdc => (uint)(Flags >> 32) & 3; public readonly uint WeightedBipredIdc => (uint)(Flags >> 32) & 3;
public uint OutputSurfaceIndex => (uint)(Flags >> 34) & 0x7f; public readonly uint OutputSurfaceIndex => (uint)(Flags >> 34) & 0x7f;
public uint ColIndex => (uint)(Flags >> 41) & 0x1f; public readonly uint ColIndex => (uint)(Flags >> 41) & 0x1f;
public ushort FrameNum => (ushort)(Flags >> 46); public readonly ushort FrameNum => (ushort)(Flags >> 46);
public bool QpprimeYZeroTransformBypassFlag => (Flags2 & (1 << 1)) != 0; public readonly bool QpprimeYZeroTransformBypassFlag => (Flags2 & (1 << 1)) != 0;
private static int ExtractSx(ulong packed, int lsb, int length) private static int ExtractSx(ulong packed, int lsb, int length)
{ {

View File

@@ -4,12 +4,12 @@ namespace Ryujinx.Graphics.Nvdec.Types.H264
{ {
struct ReferenceFrame struct ReferenceFrame
{ {
#pragma warning disable CS0649 #pragma warning disable CS0649 // Field is never assigned to
public uint Flags; public uint Flags;
public Array2<uint> FieldOrderCnt; public Array2<uint> FieldOrderCnt;
public uint FrameNum; public uint FrameNum;
#pragma warning restore CS0649 #pragma warning restore CS0649
public uint OutputSurfaceIndex => (uint)Flags & 0x7f; public readonly uint OutputSurfaceIndex => (uint)Flags & 0x7f;
} }
} }

View File

@@ -5,7 +5,7 @@ namespace Ryujinx.Graphics.Nvdec.Types.Vp8
{ {
struct PictureInfo struct PictureInfo
{ {
#pragma warning disable CS0649 #pragma warning disable CS0649 // Field is never assigned to
public Array13<uint> Unknown0; public Array13<uint> Unknown0;
public uint GpTimerTimeoutValue; public uint GpTimerTimeoutValue;
public ushort FrameWidth; public ushort FrameWidth;

View File

@@ -5,7 +5,7 @@ namespace Ryujinx.Graphics.Nvdec.Types.Vp9
{ {
struct EntropyProbs struct EntropyProbs
{ {
#pragma warning disable CS0649 #pragma warning disable CS0649 // Field is never assigned to
public Array10<Array10<Array8<byte>>> KfYModeProbE0ToE7; public Array10<Array10<Array8<byte>>> KfYModeProbE0ToE7;
public Array10<Array10<byte>> KfYModeProbE8; public Array10<Array10<byte>> KfYModeProbE8;
public Array3<byte> Padding384; public Array3<byte> Padding384;

View File

@@ -2,7 +2,7 @@
{ {
struct FrameSize struct FrameSize
{ {
#pragma warning disable CS0649 #pragma warning disable CS0649 // Field is never assigned to
public ushort Width; public ushort Width;
public ushort Height; public ushort Height;
public ushort LumaPitch; public ushort LumaPitch;

View File

@@ -2,7 +2,7 @@
{ {
struct FrameStats struct FrameStats
{ {
#pragma warning disable CS0649 #pragma warning disable CS0649 // Field is never assigned to
public uint Unknown0; public uint Unknown0;
public uint Unknown4; public uint Unknown4;
public uint Pass2CycleCount; public uint Pass2CycleCount;

View File

@@ -4,7 +4,7 @@ namespace Ryujinx.Graphics.Nvdec.Types.Vp9
{ {
struct LoopFilter struct LoopFilter
{ {
#pragma warning disable CS0649 #pragma warning disable CS0649 // Field is never assigned to
public byte ModeRefDeltaEnabled; public byte ModeRefDeltaEnabled;
public Array4<sbyte> RefDeltas; public Array4<sbyte> RefDeltas;
public Array2<sbyte> ModeDeltas; public Array2<sbyte> ModeDeltas;

View File

@@ -5,7 +5,7 @@ namespace Ryujinx.Graphics.Nvdec.Types.Vp9
{ {
struct PictureInfo struct PictureInfo
{ {
#pragma warning disable CS0649 #pragma warning disable CS0649 // Field is never assigned to
public Array12<uint> Unknown0; public Array12<uint> Unknown0;
public uint BitstreamSize; public uint BitstreamSize;
public uint IsEncrypted; public uint IsEncrypted;
@@ -44,7 +44,7 @@ namespace Ryujinx.Graphics.Nvdec.Types.Vp9
public uint UnknownFC; public uint UnknownFC;
#pragma warning restore CS0649 #pragma warning restore CS0649
public uint BitDepth => (SurfaceParams >> 1) & 0xf; public readonly uint BitDepth => (SurfaceParams >> 1) & 0xf;
public Vp9PictureInfo Convert() public Vp9PictureInfo Convert()
{ {

View File

@@ -4,7 +4,7 @@ namespace Ryujinx.Graphics.Nvdec.Types.Vp9
{ {
struct Segmentation struct Segmentation
{ {
#pragma warning disable CS0649 #pragma warning disable CS0649 // Field is never assigned to
public byte Enabled; public byte Enabled;
public byte UpdateMap; public byte UpdateMap;
public byte TemporalUpdate; public byte TemporalUpdate;

View File

@@ -13,7 +13,7 @@ namespace Ryujinx.Graphics.Nvdec
{ {
static class Vp9Decoder static class Vp9Decoder
{ {
private static Decoder _decoder = new Decoder(); private static readonly Decoder _decoder = new();
public unsafe static void Decode(ResourceManager rm, ref NvdecRegisters state) public unsafe static void Decode(ResourceManager rm, ref NvdecRegisters state)
{ {
@@ -25,9 +25,9 @@ namespace Ryujinx.Graphics.Nvdec
return rm.Cache.Get(_decoder, lumaOffset, chromaOffset, size.Width, size.Height); return rm.Cache.Get(_decoder, lumaOffset, chromaOffset, size.Width, size.Height);
} }
ISurface lastSurface = Rent(state.SetPictureLumaOffset[0], state.SetPictureChromaOffset[0], pictureInfo.LastFrameSize); ISurface lastSurface = Rent(state.SetPictureLumaOffset[0], state.SetPictureChromaOffset[0], pictureInfo.LastFrameSize);
ISurface goldenSurface = Rent(state.SetPictureLumaOffset[1], state.SetPictureChromaOffset[1], pictureInfo.GoldenFrameSize); ISurface goldenSurface = Rent(state.SetPictureLumaOffset[1], state.SetPictureChromaOffset[1], pictureInfo.GoldenFrameSize);
ISurface altSurface = Rent(state.SetPictureLumaOffset[2], state.SetPictureChromaOffset[2], pictureInfo.AltFrameSize); ISurface altSurface = Rent(state.SetPictureLumaOffset[2], state.SetPictureChromaOffset[2], pictureInfo.AltFrameSize);
ISurface currentSurface = Rent(state.SetPictureLumaOffset[3], state.SetPictureChromaOffset[3], pictureInfo.CurrentFrameSize); ISurface currentSurface = Rent(state.SetPictureLumaOffset[3], state.SetPictureChromaOffset[3], pictureInfo.CurrentFrameSize);
Vp9PictureInfo info = pictureInfo.Convert(); Vp9PictureInfo info = pictureInfo.Convert();
@@ -54,7 +54,7 @@ namespace Ryujinx.Graphics.Nvdec
Span<Vp9MvRef> mvsOut = MemoryMarshal.Cast<byte, Vp9MvRef>(mvsRegion.Memory.Span); Span<Vp9MvRef> mvsOut = MemoryMarshal.Cast<byte, Vp9MvRef>(mvsRegion.Memory.Span);
uint lumaOffset = state.SetPictureLumaOffset[3]; uint lumaOffset = state.SetPictureLumaOffset[3];
uint chromaOffset = state.SetPictureChromaOffset[3]; uint chromaOffset = state.SetPictureChromaOffset[3];
if (_decoder.Decode(ref info, currentSurface, bitstream, mvsIn, mvsOut)) if (_decoder.Decode(ref info, currentSurface, bitstream, mvsIn, mvsOut))

View File

@@ -247,6 +247,17 @@ namespace Ryujinx.Graphics.Shader.Decoders
{ {
block.AddPushOp(op); block.AddPushOp(op);
} }
else if (op.Name == InstName.Ldl || op.Name == InstName.Stl)
{
config.SetUsedFeature(FeatureFlags.LocalMemory);
}
else if (op.Name == InstName.Atoms ||
op.Name == InstName.AtomsCas ||
op.Name == InstName.Lds ||
op.Name == InstName.Sts)
{
config.SetUsedFeature(FeatureFlags.SharedMemory);
}
block.OpCodes.Add(op); block.OpCodes.Add(op);

View File

@@ -166,7 +166,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
{ {
// gl_FrontFacing sometimes has incorrect (flipped) values depending how it is accessed on Intel GPUs. // gl_FrontFacing sometimes has incorrect (flipped) values depending how it is accessed on Intel GPUs.
// This weird trick makes it behave. // This weird trick makes it behave.
res = context.ICompareLess(context.INegate(context.IConvertS32ToFP32(res)), Const(0)); res = context.ICompareLess(context.INegate(context.FP32ConvertToS32(context.ConditionalSelect(res, ConstF(1f), ConstF(0f)))), Const(0));
} }
} }

View File

@@ -27,6 +27,12 @@ namespace Ryujinx.Graphics.Shader.Instructions
public static void Atoms(EmitterContext context) public static void Atoms(EmitterContext context)
{ {
if (context.Config.Stage != ShaderStage.Compute)
{
context.Config.GpuAccessor.Log($"Atoms instruction is not valid on \"{context.Config.Stage}\" stage.");
return;
}
InstAtoms op = context.GetOp<InstAtoms>(); InstAtoms op = context.GetOp<InstAtoms>();
Operand offset = context.ShiftRightU32(GetSrcReg(context, op.SrcA), Const(2)); Operand offset = context.ShiftRightU32(GetSrcReg(context, op.SrcA), Const(2));
@@ -114,6 +120,12 @@ namespace Ryujinx.Graphics.Shader.Instructions
public static void Lds(EmitterContext context) public static void Lds(EmitterContext context)
{ {
if (context.Config.Stage != ShaderStage.Compute)
{
context.Config.GpuAccessor.Log($"Lds instruction is not valid on \"{context.Config.Stage}\" stage.");
return;
}
InstLds op = context.GetOp<InstLds>(); InstLds op = context.GetOp<InstLds>();
EmitLoad(context, StorageKind.SharedMemory, op.LsSize, GetSrcReg(context, op.SrcA), op.Dest, Imm24ToSInt(op.Imm24)); EmitLoad(context, StorageKind.SharedMemory, op.LsSize, GetSrcReg(context, op.SrcA), op.Dest, Imm24ToSInt(op.Imm24));
@@ -144,6 +156,12 @@ namespace Ryujinx.Graphics.Shader.Instructions
public static void Sts(EmitterContext context) public static void Sts(EmitterContext context)
{ {
if (context.Config.Stage != ShaderStage.Compute)
{
context.Config.GpuAccessor.Log($"Sts instruction is not valid on \"{context.Config.Stage}\" stage.");
return;
}
InstSts op = context.GetOp<InstSts>(); InstSts op = context.GetOp<InstSts>();
EmitStore(context, StorageKind.SharedMemory, op.LsSize, GetSrcReg(context, op.SrcA), op.Dest, Imm24ToSInt(op.Imm24)); EmitStore(context, StorageKind.SharedMemory, op.LsSize, GetSrcReg(context, op.SrcA), op.Dest, Imm24ToSInt(op.Imm24));

View File

@@ -21,6 +21,8 @@ namespace Ryujinx.Graphics.Shader.Translation
RtLayer = 1 << 5, RtLayer = 1 << 5,
IaIndexing = 1 << 7, IaIndexing = 1 << 7,
OaIndexing = 1 << 8, OaIndexing = 1 << 8,
FixedFuncAttr = 1 << 9 FixedFuncAttr = 1 << 9,
LocalMemory = 1 << 10,
SharedMemory = 1 << 11
} }
} }

View File

@@ -8,6 +8,11 @@ namespace Ryujinx.Graphics.Shader.Translation
{ {
class ResourceManager class ResourceManager
{ {
// Those values are used if the shader as local or shared memory access,
// but for some reason the supplied size was 0.
private const int DefaultLocalMemorySize = 128;
private const int DefaultSharedMemorySize = 4096;
private static readonly string[] _stagePrefixes = new string[] { "cp", "vp", "tcp", "tep", "gp", "fp" }; private static readonly string[] _stagePrefixes = new string[] { "cp", "vp", "tcp", "tep", "gp", "fp" };
private readonly IGpuAccessor _gpuAccessor; private readonly IGpuAccessor _gpuAccessor;
@@ -23,12 +28,12 @@ namespace Ryujinx.Graphics.Shader.Translation
private readonly HashSet<int> _usedConstantBufferBindings; private readonly HashSet<int> _usedConstantBufferBindings;
public int LocalMemoryId { get; } public int LocalMemoryId { get; private set; }
public int SharedMemoryId { get; } public int SharedMemoryId { get; private set; }
public ShaderProperties Properties => _properties; public ShaderProperties Properties => _properties;
public ResourceManager(ShaderStage stage, IGpuAccessor gpuAccessor, ShaderProperties properties, int localMemorySize) public ResourceManager(ShaderStage stage, IGpuAccessor gpuAccessor, ShaderProperties properties)
{ {
_gpuAccessor = gpuAccessor; _gpuAccessor = gpuAccessor;
_properties = properties; _properties = properties;
@@ -48,21 +53,43 @@ namespace Ryujinx.Graphics.Shader.Translation
LocalMemoryId = -1; LocalMemoryId = -1;
SharedMemoryId = -1; SharedMemoryId = -1;
}
if (localMemorySize != 0) public void SetCurrentLocalMemory(int size, bool isUsed)
{
if (isUsed)
{ {
var lmem = new MemoryDefinition("local_memory", AggregateType.Array | AggregateType.U32, BitUtils.DivRoundUp(localMemorySize, sizeof(uint))); if (size <= 0)
{
size = DefaultLocalMemorySize;
}
LocalMemoryId = properties.AddLocalMemory(lmem); var lmem = new MemoryDefinition("local_memory", AggregateType.Array | AggregateType.U32, BitUtils.DivRoundUp(size, sizeof(uint)));
LocalMemoryId = Properties.AddLocalMemory(lmem);
} }
else
int sharedMemorySize = stage == ShaderStage.Compute ? gpuAccessor.QueryComputeSharedMemorySize() : 0;
if (sharedMemorySize != 0)
{ {
var smem = new MemoryDefinition("shared_memory", AggregateType.Array | AggregateType.U32, BitUtils.DivRoundUp(sharedMemorySize, sizeof(uint))); LocalMemoryId = -1;
}
}
SharedMemoryId = properties.AddSharedMemory(smem); public void SetCurrentSharedMemory(int size, bool isUsed)
{
if (isUsed)
{
if (size <= 0)
{
size = DefaultSharedMemorySize;
}
var smem = new MemoryDefinition("shared_memory", AggregateType.Array | AggregateType.U32, BitUtils.DivRoundUp(size, sizeof(uint)));
SharedMemoryId = Properties.AddSharedMemory(smem);
}
else
{
SharedMemoryId = -1;
} }
} }

View File

@@ -126,9 +126,10 @@ namespace Ryujinx.Graphics.Shader.Translation
public ShaderConfig(ShaderStage stage, IGpuAccessor gpuAccessor, TranslationOptions options, int localMemorySize) public ShaderConfig(ShaderStage stage, IGpuAccessor gpuAccessor, TranslationOptions options, int localMemorySize)
{ {
Stage = stage; Stage = stage;
GpuAccessor = gpuAccessor; GpuAccessor = gpuAccessor;
Options = options; Options = options;
LocalMemorySize = localMemorySize;
_transformFeedbackDefinitions = new Dictionary<TransformFeedbackVariable, TransformFeedbackOutput>(); _transformFeedbackDefinitions = new Dictionary<TransformFeedbackVariable, TransformFeedbackOutput>();
@@ -143,7 +144,7 @@ namespace Ryujinx.Graphics.Shader.Translation
_usedTextures = new Dictionary<TextureInfo, TextureMeta>(); _usedTextures = new Dictionary<TextureInfo, TextureMeta>();
_usedImages = new Dictionary<TextureInfo, TextureMeta>(); _usedImages = new Dictionary<TextureInfo, TextureMeta>();
ResourceManager = new ResourceManager(stage, gpuAccessor, new ShaderProperties(), localMemorySize); ResourceManager = new ResourceManager(stage, gpuAccessor, new ShaderProperties());
if (!gpuAccessor.QueryHostSupportsTransformFeedback() && gpuAccessor.QueryTransformFeedbackEnabled()) if (!gpuAccessor.QueryHostSupportsTransformFeedback() && gpuAccessor.QueryTransformFeedbackEnabled())
{ {
@@ -192,7 +193,6 @@ namespace Ryujinx.Graphics.Shader.Translation
ThreadsPerInputPrimitive = header.ThreadsPerInputPrimitive; ThreadsPerInputPrimitive = header.ThreadsPerInputPrimitive;
OutputTopology = header.OutputTopology; OutputTopology = header.OutputTopology;
MaxOutputVertices = header.MaxOutputVertexCount; MaxOutputVertices = header.MaxOutputVertexCount;
LocalMemorySize = header.ShaderLocalMemoryLowSize + header.ShaderLocalMemoryHighSize + (header.ShaderLocalMemoryCrsSize / ThreadsPerWarp);
ImapTypes = header.ImapTypes; ImapTypes = header.ImapTypes;
OmapTargets = header.OmapTargets; OmapTargets = header.OmapTargets;
OmapSampleMask = header.OmapSampleMask; OmapSampleMask = header.OmapSampleMask;

View File

@@ -140,7 +140,7 @@ namespace Ryujinx.Graphics.Shader.Translation
FunctionMatch.RunPass(program); FunctionMatch.RunPass(program);
foreach (DecodedFunction function in program.OrderBy(x => x.Address).Where(x => !x.IsCompilerGenerated)) foreach (DecodedFunction function in program.Where(x => !x.IsCompilerGenerated).OrderBy(x => x.Address))
{ {
program.AddFunctionAndSetId(function); program.AddFunctionAndSetId(function);
} }

View File

@@ -149,6 +149,17 @@ namespace Ryujinx.Graphics.Shader.Translation
public ShaderProgram Translate(TranslatorContext other = null) public ShaderProgram Translate(TranslatorContext other = null)
{ {
bool usesLocalMemory = _config.UsedFeatures.HasFlag(FeatureFlags.LocalMemory);
_config.ResourceManager.SetCurrentLocalMemory(_config.LocalMemorySize, usesLocalMemory);
if (_config.Stage == ShaderStage.Compute)
{
bool usesSharedMemory = _config.UsedFeatures.HasFlag(FeatureFlags.SharedMemory);
_config.ResourceManager.SetCurrentSharedMemory(GpuAccessor.QueryComputeSharedMemorySize(), usesSharedMemory);
}
FunctionCode[] code = EmitShader(_program, _config, initializeOutputs: other == null, out _); FunctionCode[] code = EmitShader(_program, _config, initializeOutputs: other == null, out _);
if (other != null) if (other != null)
@@ -157,6 +168,7 @@ namespace Ryujinx.Graphics.Shader.Translation
// We need to share the resource manager since both shaders accesses the same constant buffers. // We need to share the resource manager since both shaders accesses the same constant buffers.
other._config.ResourceManager = _config.ResourceManager; other._config.ResourceManager = _config.ResourceManager;
other._config.ResourceManager.SetCurrentLocalMemory(other._config.LocalMemorySize, other._config.UsedFeatures.HasFlag(FeatureFlags.LocalMemory));
FunctionCode[] otherCode = EmitShader(other._program, other._config, initializeOutputs: true, out int aStart); FunctionCode[] otherCode = EmitShader(other._program, other._config, initializeOutputs: true, out int aStart);

View File

@@ -34,7 +34,7 @@ namespace Ryujinx.Graphics.Vic.Image
{ {
int index = RentMinimum(length, out T[] bufferArray); int index = RentMinimum(length, out T[] bufferArray);
buffer = new Span<T>(bufferArray).Slice(0, length); buffer = new Span<T>(bufferArray)[..length];
return index; return index;
} }

View File

@@ -4,7 +4,7 @@ namespace Ryujinx.Graphics.Vic.Image
{ {
ref struct RentedBuffer ref struct RentedBuffer
{ {
public static RentedBuffer Empty => new RentedBuffer(Span<byte>.Empty, -1); public static RentedBuffer Empty => new(Span<byte>.Empty, -1);
public Span<byte> Data; public Span<byte> Data;
public int Index; public int Index;
@@ -15,7 +15,7 @@ namespace Ryujinx.Graphics.Vic.Image
Index = index; Index = index;
} }
public void Return(BufferPool<byte> pool) public readonly void Return(BufferPool<byte> pool)
{ {
if (Index != -1) if (Index != -1)
{ {
@@ -65,7 +65,7 @@ namespace Ryujinx.Graphics.Vic.Image
Buffer2Index = buffer.Index; Buffer2Index = buffer.Index;
} }
public void Return(BufferPool<byte> pool) public readonly void Return(BufferPool<byte> pool)
{ {
if (Buffer0Index != -1) if (Buffer0Index != -1)
{ {

View File

@@ -21,7 +21,8 @@ namespace Ryujinx.Graphics.Vic.Image
{ {
switch (surfaceConfig.SlotPixelFormat) switch (surfaceConfig.SlotPixelFormat)
{ {
case PixelFormat.Y8___V8U8_N420: return ReadNv12(rm, ref config, ref surfaceConfig, ref offsets); case PixelFormat.Y8___V8U8_N420:
return ReadNv12(rm, ref config, ref surfaceConfig, ref offsets);
} }
Logger.Error?.Print(LogClass.Vic, $"Unsupported pixel format \"{surfaceConfig.SlotPixelFormat}\"."); Logger.Error?.Print(LogClass.Vic, $"Unsupported pixel format \"{surfaceConfig.SlotPixelFormat}\".");
@@ -46,7 +47,7 @@ namespace Ryujinx.Graphics.Vic.Image
int yStride = GetPitch(width, 1); int yStride = GetPitch(width, 1);
int uvStride = GetPitch(input.UvWidth, 2); int uvStride = GetPitch(input.UvWidth, 2);
Surface output = new Surface(rm.SurfacePool, width, height); Surface output = new(rm.SurfacePool, width, height);
if (Sse41.IsSupported) if (Sse41.IsSupported)
{ {
@@ -276,7 +277,7 @@ namespace Ryujinx.Graphics.Vic.Image
int bytesPerPixel, int bytesPerPixel,
int planes) int planes)
{ {
InputSurface surface = new InputSurface(); InputSurface surface = new();
surface.Initialize(); surface.Initialize();
@@ -458,7 +459,7 @@ namespace Ryujinx.Graphics.Vic.Image
int outSize = dstStride * height; int outSize = dstStride * height;
int bufferIndex = rm.BufferPool.RentMinimum(outSize, out byte[] buffer); int bufferIndex = rm.BufferPool.RentMinimum(outSize, out byte[] buffer);
Span<byte> dst = buffer; Span<byte> dst = buffer;
dst = dst.Slice(0, outSize); dst = dst[..outSize];
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
@@ -485,9 +486,9 @@ namespace Ryujinx.Graphics.Vic.Image
int outSize = dstStride * height; int outSize = dstStride * height;
int bufferIndex = rm.BufferPool.RentMinimum(outSize, out byte[] buffer); int bufferIndex = rm.BufferPool.RentMinimum(outSize, out byte[] buffer);
Span<byte> dst = buffer; Span<byte> dst = buffer;
dst = dst.Slice(0, outSize); dst = dst[..outSize];
LayoutConverter.ConvertBlockLinearToLinear(dst.Slice(dstStart), width, height, dstStride, bytesPerPixel, gobBlocksInY, src); LayoutConverter.ConvertBlockLinearToLinear(dst[dstStart..], width, height, dstStride, bytesPerPixel, gobBlocksInY, src);
return new RentedBuffer(dst, bufferIndex); return new RentedBuffer(dst, bufferIndex);
} }

View File

@@ -2,10 +2,10 @@
namespace Ryujinx.Graphics.Vic.Types namespace Ryujinx.Graphics.Vic.Types
{ {
struct BlendingSlotStruct readonly struct BlendingSlotStruct
{ {
private long _word0; private readonly long _word0;
private long _word1; private readonly long _word1;
public int AlphaK1 => (int)_word0.Extract(0, 10); public int AlphaK1 => (int)_word0.Extract(0, 10);
public int AlphaK2 => (int)_word0.Extract(16, 10); public int AlphaK2 => (int)_word0.Extract(16, 10);

View File

@@ -2,11 +2,11 @@
namespace Ryujinx.Graphics.Vic.Types namespace Ryujinx.Graphics.Vic.Types
{ {
struct ClearRectStruct readonly struct ClearRectStruct
{ {
#pragma warning disable CS0649 #pragma warning disable CS0649 // Field is never assigned to
private long _word0; private readonly long _word0;
private long _word1; private readonly long _word1;
#pragma warning restore CS0649 #pragma warning restore CS0649
public int ClearRect0Left => (int)_word0.Extract(0, 14); public int ClearRect0Left => (int)_word0.Extract(0, 14);

View File

@@ -4,7 +4,7 @@ namespace Ryujinx.Graphics.Vic.Types
{ {
struct ConfigStruct struct ConfigStruct
{ {
#pragma warning disable CS0649 #pragma warning disable CS0649 // Field is never assigned to
public PipeConfig PipeConfig; public PipeConfig PipeConfig;
public OutputConfig OutputConfig; public OutputConfig OutputConfig;
public OutputSurfaceConfig OutputSurfaceConfig; public OutputSurfaceConfig OutputSurfaceConfig;

View File

@@ -2,10 +2,10 @@
namespace Ryujinx.Graphics.Vic.Types namespace Ryujinx.Graphics.Vic.Types
{ {
struct LumaKeyStruct readonly struct LumaKeyStruct
{ {
private long _word0; private readonly long _word0;
private long _word1; private readonly long _word1;
public int LumaCoeff0 => (int)_word0.Extract(0, 20); public int LumaCoeff0 => (int)_word0.Extract(0, 20);
public int LumaCoeff1 => (int)_word0.Extract(20, 20); public int LumaCoeff1 => (int)_word0.Extract(20, 20);

View File

@@ -2,12 +2,12 @@
namespace Ryujinx.Graphics.Vic.Types namespace Ryujinx.Graphics.Vic.Types
{ {
struct MatrixStruct readonly struct MatrixStruct
{ {
private long _word0; private readonly long _word0;
private long _word1; private readonly long _word1;
private long _word2; private readonly long _word2;
private long _word3; private readonly long _word3;
public int MatrixCoeff00 => (int)_word0.ExtractSx(0, 20); public int MatrixCoeff00 => (int)_word0.ExtractSx(0, 20);
public int MatrixCoeff10 => (int)_word0.ExtractSx(20, 20); public int MatrixCoeff10 => (int)_word0.ExtractSx(20, 20);

View File

@@ -2,11 +2,11 @@
namespace Ryujinx.Graphics.Vic.Types namespace Ryujinx.Graphics.Vic.Types
{ {
struct OutputConfig readonly struct OutputConfig
{ {
#pragma warning disable CS0649 #pragma warning disable CS0649 // Field is never assigned to
private long _word0; private readonly long _word0;
private long _word1; private readonly long _word1;
#pragma warning restore CS0649 #pragma warning restore CS0649
public int AlphaFillMode => (int)_word0.Extract(0, 3); public int AlphaFillMode => (int)_word0.Extract(0, 3);

View File

@@ -2,11 +2,11 @@
namespace Ryujinx.Graphics.Vic.Types namespace Ryujinx.Graphics.Vic.Types
{ {
struct OutputSurfaceConfig readonly struct OutputSurfaceConfig
{ {
#pragma warning disable CS0649 #pragma warning disable CS0649 // Field is never assigned to
private long _word0; private readonly long _word0;
private long _word1; private readonly long _word1;
#pragma warning restore CS0649 #pragma warning restore CS0649
public PixelFormat OutPixelFormat => (PixelFormat)_word0.Extract(0, 7); public PixelFormat OutPixelFormat => (PixelFormat)_word0.Extract(0, 7);

View File

@@ -2,12 +2,12 @@
namespace Ryujinx.Graphics.Vic.Types namespace Ryujinx.Graphics.Vic.Types
{ {
struct PipeConfig readonly struct PipeConfig
{ {
#pragma warning disable CS0169, CS0649 #pragma warning disable CS0169, CS0649, IDE0051 // Remove unused private member
private long _word0; private readonly long _word0;
private long _word1; private readonly long _word1;
#pragma warning restore CS0169, CS0649 #pragma warning restore CS0169, CS0649, IDE0051
public int DownsampleHoriz => (int)_word0.Extract(0, 11); public int DownsampleHoriz => (int)_word0.Extract(0, 11);
public int DownsampleVert => (int)_word0.Extract(16, 11); public int DownsampleVert => (int)_word0.Extract(16, 11);

View File

@@ -2,16 +2,18 @@
namespace Ryujinx.Graphics.Vic.Types namespace Ryujinx.Graphics.Vic.Types
{ {
struct SlotConfig readonly struct SlotConfig
{ {
private long _word0; private readonly long _word0;
private long _word1; private readonly long _word1;
private long _word2; private readonly long _word2;
private long _word3; private readonly long _word3;
private long _word4; private readonly long _word4;
private long _word5; private readonly long _word5;
private long _word6; private readonly long _word6;
private long _word7; #pragma warning disable IDE0051 // Remove unused private member
private readonly long _word7;
#pragma warning restore IDE0051
public bool SlotEnable => _word0.Extract(0); public bool SlotEnable => _word0.Extract(0);
public bool DeNoise => _word0.Extract(1); public bool DeNoise => _word0.Extract(1);

View File

@@ -2,10 +2,10 @@
namespace Ryujinx.Graphics.Vic.Types namespace Ryujinx.Graphics.Vic.Types
{ {
struct SlotSurfaceConfig readonly struct SlotSurfaceConfig
{ {
private long _word0; private readonly long _word0;
private long _word1; private readonly long _word1;
public PixelFormat SlotPixelFormat => (PixelFormat)_word0.Extract(0, 7); public PixelFormat SlotPixelFormat => (PixelFormat)_word0.Extract(0, 7);
public int SlotChromaLocHoriz => (int)_word0.Extract(7, 2); public int SlotChromaLocHoriz => (int)_word0.Extract(7, 2);

View File

@@ -30,7 +30,7 @@ namespace Ryujinx.Graphics.Vic
{ {
ConfigStruct config = ReadIndirect<ConfigStruct>(_state.State.SetConfigStructOffset); ConfigStruct config = ReadIndirect<ConfigStruct>(_state.State.SetConfigStructOffset);
using Surface output = new Surface( using Surface output = new(
_rm.SurfacePool, _rm.SurfacePool,
config.OutputSurfaceConfig.OutSurfaceWidth + 1, config.OutputSurfaceConfig.OutSurfaceWidth + 1,
config.OutputSurfaceConfig.OutSurfaceHeight + 1); config.OutputSurfaceConfig.OutSurfaceHeight + 1);
@@ -58,7 +58,7 @@ namespace Ryujinx.Graphics.Vic
int targetW = Math.Min(output.Width - targetX, Math.Abs(x2 - x1)); int targetW = Math.Min(output.Width - targetX, Math.Abs(x2 - x1));
int targetH = Math.Min(output.Height - targetY, Math.Abs(y2 - y1)); int targetH = Math.Min(output.Height - targetY, Math.Abs(y2 - y1));
Rectangle targetRect = new Rectangle(targetX, targetY, targetW, targetH); Rectangle targetRect = new(targetX, targetY, targetW, targetH);
Blender.BlendOne(output, src, ref slot, targetRect); Blender.BlendOne(output, src, ref slot, targetRect);
} }

View File

@@ -4,7 +4,7 @@ namespace Ryujinx.Graphics.Vic
{ {
struct PlaneOffsets struct PlaneOffsets
{ {
#pragma warning disable CS0649 #pragma warning disable CS0649 // Field is never assigned to
public uint LumaOffset; public uint LumaOffset;
public uint ChromaUOffset; public uint ChromaUOffset;
public uint ChromaVOffset; public uint ChromaVOffset;
@@ -13,7 +13,7 @@ namespace Ryujinx.Graphics.Vic
struct VicRegisters struct VicRegisters
{ {
#pragma warning disable CS0649 #pragma warning disable CS0649 // Field is never assigned to
public Array64<uint> Reserved0; public Array64<uint> Reserved0;
public uint Nop; public uint Nop;
public Array15<uint> Reserved104; public Array15<uint> Reserved104;

View File

@@ -256,7 +256,7 @@ namespace Ryujinx.Graphics.Vulkan
{ {
await Task.WhenAll(_shaders.Select(shader => shader.CompileTask)); await Task.WhenAll(_shaders.Select(shader => shader.CompileTask));
if (_shaders.Any(shader => shader.CompileStatus == ProgramLinkStatus.Failure)) if (Array.Exists(_shaders, shader => shader.CompileStatus == ProgramLinkStatus.Failure))
{ {
LinkStatus = ProgramLinkStatus.Failure; LinkStatus = ProgramLinkStatus.Failure;

View File

@@ -25,7 +25,15 @@ namespace Ryujinx.HLE.HOS
public IVirtualMemoryManager AddressSpace => _memoryManager; public IVirtualMemoryManager AddressSpace => _memoryManager;
public ArmProcessContext(ulong pid, ICpuEngine cpuEngine, GpuContext gpuContext, T memoryManager, bool for64Bit) public ulong AddressSpaceSize { get; }
public ArmProcessContext(
ulong pid,
ICpuEngine cpuEngine,
GpuContext gpuContext,
T memoryManager,
ulong addressSpaceSize,
bool for64Bit)
{ {
if (memoryManager is IRefCounted rc) if (memoryManager is IRefCounted rc)
{ {
@@ -38,6 +46,8 @@ namespace Ryujinx.HLE.HOS
_gpuContext = gpuContext; _gpuContext = gpuContext;
_cpuContext = cpuEngine.CreateCpuContext(memoryManager, for64Bit); _cpuContext = cpuEngine.CreateCpuContext(memoryManager, for64Bit);
_memoryManager = memoryManager; _memoryManager = memoryManager;
AddressSpaceSize = addressSpaceSize;
} }
public IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks) public IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks)

View File

@@ -1,4 +1,5 @@
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Cpu; using Ryujinx.Cpu;
using Ryujinx.Cpu.AppleHv; using Ryujinx.Cpu.AppleHv;
using Ryujinx.Cpu.Jit; using Ryujinx.Cpu.Jit;
@@ -49,7 +50,7 @@ namespace Ryujinx.HLE.HOS
{ {
var cpuEngine = new HvEngine(_tickSource); var cpuEngine = new HvEngine(_tickSource);
var memoryManager = new HvMemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler); var memoryManager = new HvMemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler);
processContext = new ArmProcessContext<HvMemoryManager>(pid, cpuEngine, _gpu, memoryManager, for64Bit); processContext = new ArmProcessContext<HvMemoryManager>(pid, cpuEngine, _gpu, memoryManager, addressSpaceSize, for64Bit);
} }
else else
{ {
@@ -57,23 +58,41 @@ namespace Ryujinx.HLE.HOS
if (!MemoryBlock.SupportsFlags(MemoryAllocationFlags.ViewCompatible)) if (!MemoryBlock.SupportsFlags(MemoryAllocationFlags.ViewCompatible))
{ {
Logger.Warning?.Print(LogClass.Cpu, "Host system doesn't support views, falling back to software page table");
mode = MemoryManagerMode.SoftwarePageTable; mode = MemoryManagerMode.SoftwarePageTable;
} }
var cpuEngine = new JitEngine(_tickSource); var cpuEngine = new JitEngine(_tickSource);
AddressSpace addressSpace = null;
if (mode == MemoryManagerMode.HostMapped || mode == MemoryManagerMode.HostMappedUnsafe)
{
if (!AddressSpace.TryCreate(context.Memory, addressSpaceSize, MemoryBlock.GetPageSize() == MemoryManagerHostMapped.PageSize, out addressSpace))
{
Logger.Warning?.Print(LogClass.Cpu, "Address space creation failed, falling back to software page table");
mode = MemoryManagerMode.SoftwarePageTable;
}
}
switch (mode) switch (mode)
{ {
case MemoryManagerMode.SoftwarePageTable: case MemoryManagerMode.SoftwarePageTable:
var memoryManager = new MemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler); var memoryManager = new MemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler);
processContext = new ArmProcessContext<MemoryManager>(pid, cpuEngine, _gpu, memoryManager, for64Bit); processContext = new ArmProcessContext<MemoryManager>(pid, cpuEngine, _gpu, memoryManager, addressSpaceSize, for64Bit);
break; break;
case MemoryManagerMode.HostMapped: case MemoryManagerMode.HostMapped:
case MemoryManagerMode.HostMappedUnsafe: case MemoryManagerMode.HostMappedUnsafe:
bool unsafeMode = mode == MemoryManagerMode.HostMappedUnsafe; if (addressSpaceSize != addressSpace.AddressSpaceSize)
var memoryManagerHostMapped = new MemoryManagerHostMapped(context.Memory, addressSpaceSize, unsafeMode, invalidAccessHandler); {
processContext = new ArmProcessContext<MemoryManagerHostMapped>(pid, cpuEngine, _gpu, memoryManagerHostMapped, for64Bit); Logger.Warning?.Print(LogClass.Emulation, $"Allocated address space (0x{addressSpace.AddressSpaceSize:X}) is smaller than guest application requirements (0x{addressSpaceSize:X})");
}
var memoryManagerHostMapped = new MemoryManagerHostMapped(addressSpace, mode == MemoryManagerMode.HostMappedUnsafe, invalidAccessHandler);
processContext = new ArmProcessContext<MemoryManagerHostMapped>(pid, cpuEngine, _gpu, memoryManagerHostMapped, addressSpace.AddressSpaceSize, for64Bit);
break; break;
default: default:

View File

@@ -15,7 +15,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
writer.Write(Params); writer.Write(Params);
if (Params.EndsWith(">")) if (Params.EndsWith('>'))
{ {
writer.Write(" "); writer.Write(" ");
} }

View File

@@ -13,7 +13,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
protected override bool Supports4KBPages => _cpuMemory.Supports4KBPages; protected override bool Supports4KBPages => _cpuMemory.Supports4KBPages;
public KPageTable(KernelContext context, IVirtualMemoryManager cpuMemory) : base(context) public KPageTable(KernelContext context, IVirtualMemoryManager cpuMemory, ulong reservedAddressSpaceSize) : base(context, reservedAddressSpaceSize)
{ {
_cpuMemory = cpuMemory; _cpuMemory = cpuMemory;
} }

View File

@@ -22,6 +22,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
0x40000000 0x40000000
}; };
private const ulong RegionAlignment = 0x200000;
public const int PageSize = 0x1000; public const int PageSize = 0x1000;
private const int KMemoryBlockSize = 0x40; private const int KMemoryBlockSize = 0x40;
@@ -53,6 +55,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
public ulong TlsIoRegionStart { get; private set; } public ulong TlsIoRegionStart { get; private set; }
public ulong TlsIoRegionEnd { get; private set; } public ulong TlsIoRegionEnd { get; private set; }
public ulong AslrRegionStart { get; private set; }
public ulong AslrRegionEnd { get; private set; }
private ulong _heapCapacity; private ulong _heapCapacity;
public ulong PhysicalMemoryUsage { get; private set; } public ulong PhysicalMemoryUsage { get; private set; }
@@ -61,10 +66,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
private MemoryRegion _memRegion; private MemoryRegion _memRegion;
private bool _aslrDisabled; private bool _allocateFromBack;
public int AddrSpaceWidth { get; private set; }
private bool _isKernel; private bool _isKernel;
private bool _aslrEnabled; private bool _aslrEnabled;
@@ -78,7 +80,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
private MemoryFillValue _heapFillValue; private MemoryFillValue _heapFillValue;
private MemoryFillValue _ipcFillValue; private MemoryFillValue _ipcFillValue;
public KPageTableBase(KernelContext context) private ulong _reservedAddressSpaceSize;
public KPageTableBase(KernelContext context, ulong reservedAddressSpaceSize)
{ {
Context = context; Context = context;
@@ -88,6 +92,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_heapFillValue = MemoryFillValue.Zero; _heapFillValue = MemoryFillValue.Zero;
_ipcFillValue = MemoryFillValue.Zero; _ipcFillValue = MemoryFillValue.Zero;
_reservedAddressSpaceSize = reservedAddressSpaceSize;
} }
private static readonly int[] AddrSpaceSizes = new int[] { 32, 36, 32, 39 }; private static readonly int[] AddrSpaceSizes = new int[] { 32, 36, 32, 39 };
@@ -95,7 +101,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
public Result InitializeForProcess( public Result InitializeForProcess(
AddressSpaceType addrSpaceType, AddressSpaceType addrSpaceType,
bool aslrEnabled, bool aslrEnabled,
bool aslrDisabled, bool fromBack,
MemoryRegion memRegion, MemoryRegion memRegion,
ulong address, ulong address,
ulong size, ulong size,
@@ -114,7 +120,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
Result result = CreateUserAddressSpace( Result result = CreateUserAddressSpace(
addrSpaceType, addrSpaceType,
aslrEnabled, aslrEnabled,
aslrDisabled, fromBack,
addrSpaceBase, addrSpaceBase,
addrSpaceSize, addrSpaceSize,
memRegion, memRegion,
@@ -130,7 +136,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return result; return result;
} }
private class Region private struct Region
{ {
public ulong Start; public ulong Start;
public ulong End; public ulong End;
@@ -141,7 +147,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
private Result CreateUserAddressSpace( private Result CreateUserAddressSpace(
AddressSpaceType addrSpaceType, AddressSpaceType addrSpaceType,
bool aslrEnabled, bool aslrEnabled,
bool aslrDisabled, bool fromBack,
ulong addrSpaceStart, ulong addrSpaceStart,
ulong addrSpaceEnd, ulong addrSpaceEnd,
MemoryRegion memRegion, MemoryRegion memRegion,
@@ -159,7 +165,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong codeRegionSize; ulong codeRegionSize;
ulong stackAndTlsIoStart; ulong stackAndTlsIoStart;
ulong stackAndTlsIoEnd; ulong stackAndTlsIoEnd;
ulong baseAddress;
switch (addrSpaceType) switch (addrSpaceType)
{ {
@@ -170,10 +175,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
tlsIoRegion.Size = 0; tlsIoRegion.Size = 0;
CodeRegionStart = 0x200000; CodeRegionStart = 0x200000;
codeRegionSize = 0x3fe00000; codeRegionSize = 0x3fe00000;
AslrRegionStart = 0x200000;
AslrRegionEnd = AslrRegionStart + 0xffe00000;
stackAndTlsIoStart = 0x200000; stackAndTlsIoStart = 0x200000;
stackAndTlsIoEnd = 0x40000000; stackAndTlsIoEnd = 0x40000000;
baseAddress = 0x200000;
AddrSpaceWidth = 32;
break; break;
case AddressSpaceType.Addr36Bits: case AddressSpaceType.Addr36Bits:
@@ -183,10 +188,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
tlsIoRegion.Size = 0; tlsIoRegion.Size = 0;
CodeRegionStart = 0x8000000; CodeRegionStart = 0x8000000;
codeRegionSize = 0x78000000; codeRegionSize = 0x78000000;
AslrRegionStart = 0x8000000;
AslrRegionEnd = AslrRegionStart + 0xff8000000;
stackAndTlsIoStart = 0x8000000; stackAndTlsIoStart = 0x8000000;
stackAndTlsIoEnd = 0x80000000; stackAndTlsIoEnd = 0x80000000;
baseAddress = 0x8000000;
AddrSpaceWidth = 36;
break; break;
case AddressSpaceType.Addr32BitsNoMap: case AddressSpaceType.Addr32BitsNoMap:
@@ -196,23 +201,42 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
tlsIoRegion.Size = 0; tlsIoRegion.Size = 0;
CodeRegionStart = 0x200000; CodeRegionStart = 0x200000;
codeRegionSize = 0x3fe00000; codeRegionSize = 0x3fe00000;
AslrRegionStart = 0x200000;
AslrRegionEnd = AslrRegionStart + 0xffe00000;
stackAndTlsIoStart = 0x200000; stackAndTlsIoStart = 0x200000;
stackAndTlsIoEnd = 0x40000000; stackAndTlsIoEnd = 0x40000000;
baseAddress = 0x200000;
AddrSpaceWidth = 32;
break; break;
case AddressSpaceType.Addr39Bits: case AddressSpaceType.Addr39Bits:
aliasRegion.Size = 0x1000000000; if (_reservedAddressSpaceSize < addrSpaceEnd)
heapRegion.Size = 0x180000000; {
stackRegion.Size = 0x80000000; int addressSpaceWidth = (int)ulong.Log2(_reservedAddressSpaceSize);
tlsIoRegion.Size = 0x1000000000;
CodeRegionStart = BitUtils.AlignDown<ulong>(address, 0x200000); aliasRegion.Size = 1UL << (addressSpaceWidth - 3);
codeRegionSize = BitUtils.AlignUp<ulong>(endAddr, 0x200000) - CodeRegionStart; heapRegion.Size = 0x180000000;
stackAndTlsIoStart = 0; stackRegion.Size = 1UL << (addressSpaceWidth - 8);
stackAndTlsIoEnd = 0; tlsIoRegion.Size = 1UL << (addressSpaceWidth - 3);
baseAddress = 0x8000000; CodeRegionStart = BitUtils.AlignDown<ulong>(address, RegionAlignment);
AddrSpaceWidth = 39; codeRegionSize = BitUtils.AlignUp<ulong>(endAddr, RegionAlignment) - CodeRegionStart;
stackAndTlsIoStart = 0;
stackAndTlsIoEnd = 0;
AslrRegionStart = 0x8000000;
addrSpaceEnd = 1UL << addressSpaceWidth;
AslrRegionEnd = addrSpaceEnd;
}
else
{
aliasRegion.Size = 0x1000000000;
heapRegion.Size = 0x180000000;
stackRegion.Size = 0x80000000;
tlsIoRegion.Size = 0x1000000000;
CodeRegionStart = BitUtils.AlignDown(address, RegionAlignment);
codeRegionSize = BitUtils.AlignUp(endAddr, RegionAlignment) - CodeRegionStart;
AslrRegionStart = 0x8000000;
AslrRegionEnd = AslrRegionStart + 0x7ff8000000;
stackAndTlsIoStart = 0;
stackAndTlsIoEnd = 0;
}
break; break;
default: throw new ArgumentException(nameof(addrSpaceType)); default: throw new ArgumentException(nameof(addrSpaceType));
@@ -223,11 +247,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong mapBaseAddress; ulong mapBaseAddress;
ulong mapAvailableSize; ulong mapAvailableSize;
if (CodeRegionStart - baseAddress >= addrSpaceEnd - CodeRegionEnd) if (CodeRegionStart - AslrRegionStart >= addrSpaceEnd - CodeRegionEnd)
{ {
// Has more space before the start of the code region. // Has more space before the start of the code region.
mapBaseAddress = baseAddress; mapBaseAddress = AslrRegionStart;
mapAvailableSize = CodeRegionStart - baseAddress; mapAvailableSize = CodeRegionStart - AslrRegionStart;
} }
else else
{ {
@@ -254,14 +278,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
if (aslrEnabled) if (aslrEnabled)
{ {
aliasRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset >> 21) << 21; aliasRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset / RegionAlignment) * RegionAlignment;
heapRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset >> 21) << 21; heapRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset / RegionAlignment) * RegionAlignment;
stackRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset >> 21) << 21; stackRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset / RegionAlignment) * RegionAlignment;
tlsIoRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset >> 21) << 21; tlsIoRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset / RegionAlignment) * RegionAlignment;
} }
// Regions are sorted based on ASLR offset. // Regions are sorted based on ASLR offset.
// When ASLR is disabled, the order is Map, Heap, NewMap and TlsIo. // When ASLR is disabled, the order is Alias, Heap, Stack and TlsIo.
aliasRegion.Start = mapBaseAddress + aliasRegion.AslrOffset; aliasRegion.Start = mapBaseAddress + aliasRegion.AslrOffset;
aliasRegion.End = aliasRegion.Start + aliasRegion.Size; aliasRegion.End = aliasRegion.Start + aliasRegion.Size;
heapRegion.Start = mapBaseAddress + heapRegion.AslrOffset; heapRegion.Start = mapBaseAddress + heapRegion.AslrOffset;
@@ -271,12 +295,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
tlsIoRegion.Start = mapBaseAddress + tlsIoRegion.AslrOffset; tlsIoRegion.Start = mapBaseAddress + tlsIoRegion.AslrOffset;
tlsIoRegion.End = tlsIoRegion.Start + tlsIoRegion.Size; tlsIoRegion.End = tlsIoRegion.Start + tlsIoRegion.Size;
SortRegion(heapRegion, aliasRegion); SortRegion(ref aliasRegion, ref heapRegion, true);
if (stackRegion.Size != 0) if (stackRegion.Size != 0)
{ {
SortRegion(stackRegion, aliasRegion); stackRegion.Start = mapBaseAddress + stackRegion.AslrOffset;
SortRegion(stackRegion, heapRegion); stackRegion.End = stackRegion.Start + stackRegion.Size;
SortRegion(ref aliasRegion, ref stackRegion);
SortRegion(ref heapRegion, ref stackRegion);
} }
else else
{ {
@@ -286,9 +313,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
if (tlsIoRegion.Size != 0) if (tlsIoRegion.Size != 0)
{ {
SortRegion(tlsIoRegion, aliasRegion); tlsIoRegion.Start = mapBaseAddress + tlsIoRegion.AslrOffset;
SortRegion(tlsIoRegion, heapRegion); tlsIoRegion.End = tlsIoRegion.Start + tlsIoRegion.Size;
SortRegion(tlsIoRegion, stackRegion);
SortRegion(ref aliasRegion, ref tlsIoRegion);
SortRegion(ref heapRegion, ref tlsIoRegion);
if (stackRegion.Size != 0)
{
SortRegion(ref stackRegion, ref tlsIoRegion);
}
} }
else else
{ {
@@ -312,11 +346,27 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
PhysicalMemoryUsage = 0; PhysicalMemoryUsage = 0;
_memRegion = memRegion; _memRegion = memRegion;
_aslrDisabled = aslrDisabled; _allocateFromBack = fromBack;
return _blockManager.Initialize(addrSpaceStart, addrSpaceEnd, slabManager); return _blockManager.Initialize(addrSpaceStart, addrSpaceEnd, slabManager);
} }
private static void SortRegion(ref Region lhs, ref Region rhs, bool checkForEquality = false)
{
bool res = checkForEquality ? lhs.AslrOffset <= rhs.AslrOffset : lhs.AslrOffset < rhs.AslrOffset;
if (res)
{
rhs.Start += lhs.Size;
rhs.End += lhs.Size;
}
else
{
lhs.Start += rhs.Size;
lhs.End += rhs.Size;
}
}
private ulong GetRandomValue(ulong min, ulong max) private ulong GetRandomValue(ulong min, ulong max)
{ {
return (ulong)GetRandomValue((long)min, (long)max); return (ulong)GetRandomValue((long)min, (long)max);
@@ -332,20 +382,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return _randomNumberGenerator.GenRandomNumber(min, max); return _randomNumberGenerator.GenRandomNumber(min, max);
} }
private static void SortRegion(Region lhs, Region rhs)
{
if (lhs.AslrOffset < rhs.AslrOffset)
{
rhs.Start += lhs.Size;
rhs.End += lhs.Size;
}
else
{
lhs.Start += rhs.Size;
lhs.End += rhs.Size;
}
}
public Result MapPages(ulong address, KPageList pageList, MemoryState state, KMemoryPermission permission) public Result MapPages(ulong address, KPageList pageList, MemoryState state, KMemoryPermission permission)
{ {
ulong pagesCount = pageList.GetPagesCount(); ulong pagesCount = pageList.GetPagesCount();
@@ -1827,7 +1863,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
// If not, allocate a new page and copy the unaligned chunck. // If not, allocate a new page and copy the unaligned chunck.
if (addressTruncated < addressRounded) if (addressTruncated < addressRounded)
{ {
dstFirstPagePa = GetMemoryRegionManager().AllocatePagesContiguous(Context, 1, _aslrDisabled); dstFirstPagePa = GetMemoryRegionManager().AllocatePagesContiguous(Context, 1, _allocateFromBack);
if (dstFirstPagePa == 0) if (dstFirstPagePa == 0)
{ {
@@ -1841,7 +1877,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
// If not, allocate a new page and copy the unaligned chunck. // If not, allocate a new page and copy the unaligned chunck.
if (endAddrTruncated < endAddrRounded && (addressTruncated == addressRounded || addressTruncated < endAddrTruncated)) if (endAddrTruncated < endAddrRounded && (addressTruncated == addressRounded || addressTruncated < endAddrTruncated))
{ {
dstLastPagePa = GetMemoryRegionManager().AllocatePagesContiguous(Context, 1, _aslrDisabled); dstLastPagePa = GetMemoryRegionManager().AllocatePagesContiguous(Context, 1, _allocateFromBack);
if (dstLastPagePa == 0) if (dstLastPagePa == 0)
{ {
@@ -2799,38 +2835,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
public ulong GetAddrSpaceBaseAddr() public ulong GetAddrSpaceBaseAddr()
{ {
if (AddrSpaceWidth == 36 || AddrSpaceWidth == 39) return AslrRegionStart;
{
return 0x8000000;
}
else if (AddrSpaceWidth == 32)
{
return 0x200000;
}
else
{
throw new InvalidOperationException("Invalid address space width!");
}
} }
public ulong GetAddrSpaceSize() public ulong GetAddrSpaceSize()
{ {
if (AddrSpaceWidth == 36) return AslrRegionEnd - AslrRegionStart;
{
return 0xff8000000;
}
else if (AddrSpaceWidth == 39)
{
return 0x7ff8000000;
}
else if (AddrSpaceWidth == 32)
{
return 0xffe00000;
}
else
{
throw new InvalidOperationException("Invalid address space width!");
}
} }
private static ulong GetDramAddressFromPa(ulong pa) private static ulong GetDramAddressFromPa(ulong pa)

View File

@@ -8,6 +8,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{ {
IVirtualMemoryManager AddressSpace { get; } IVirtualMemoryManager AddressSpace { get; }
ulong AddressSpaceSize { get; }
IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks); IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks);
void Execute(IExecutionContext context, ulong codeAddress); void Execute(IExecutionContext context, ulong codeAddress);
void InvalidateCacheRegion(ulong address, ulong size); void InvalidateCacheRegion(ulong address, ulong size);

View File

@@ -1082,7 +1082,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
Context = _contextFactory.Create(KernelContext, Pid, 1UL << addrSpaceBits, InvalidAccessHandler, for64Bit); Context = _contextFactory.Create(KernelContext, Pid, 1UL << addrSpaceBits, InvalidAccessHandler, for64Bit);
MemoryManager = new KPageTable(KernelContext, CpuMemory); MemoryManager = new KPageTable(KernelContext, CpuMemory, Context.AddressSpaceSize);
} }
private bool InvalidAccessHandler(ulong va) private bool InvalidAccessHandler(ulong va)

View File

@@ -8,9 +8,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{ {
public IVirtualMemoryManager AddressSpace { get; } public IVirtualMemoryManager AddressSpace { get; }
public ProcessContext(IVirtualMemoryManager asManager) public ulong AddressSpaceSize { get; }
public ProcessContext(IVirtualMemoryManager asManager, ulong addressSpaceSize)
{ {
AddressSpace = asManager; AddressSpace = asManager;
AddressSpaceSize = addressSpaceSize;
} }
public IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks) public IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks)

View File

@@ -6,7 +6,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{ {
public IProcessContext Create(KernelContext context, ulong pid, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler, bool for64Bit) public IProcessContext Create(KernelContext context, ulong pid, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler, bool for64Bit)
{ {
return new ProcessContext(new AddressSpaceManager(context.Memory, addressSpaceSize)); return new ProcessContext(new AddressSpaceManager(context.Memory, addressSpaceSize), addressSpaceSize);
} }
} }
} }

View File

@@ -206,7 +206,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
WakeThreads(_condVarThreads, count, TryAcquireMutex, x => x.CondVarAddress == address); WakeThreads(_condVarThreads, count, TryAcquireMutex, x => x.CondVarAddress == address);
if (!_condVarThreads.Any(x => x.CondVarAddress == address)) if (!_condVarThreads.Exists(x => x.CondVarAddress == address))
{ {
KernelTransfer.KernelToUser(address, 0); KernelTransfer.KernelToUser(address, 0);
} }

View File

@@ -6,7 +6,7 @@ namespace Ryujinx.HLE.HOS.Services.Mii.Types
[StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x10)] [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x10)]
struct CreateId : IEquatable<CreateId> struct CreateId : IEquatable<CreateId>
{ {
public UInt128 Raw; public readonly UInt128 Raw;
public bool IsNull => Raw == UInt128.Zero; public bool IsNull => Raw == UInt128.Zero;
public bool IsValid => !IsNull && ((Raw >> 64) & 0xC0) == 0x80; public bool IsValid => !IsNull && ((Raw >> 64) & 0xC0) == 0x80;

View File

@@ -95,7 +95,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
{ {
VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId); VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId);
if (virtualAmiiboFile.ApplicationAreas.Any(item => item.ApplicationAreaId == applicationAreaId)) if (virtualAmiiboFile.ApplicationAreas.Exists(item => item.ApplicationAreaId == applicationAreaId))
{ {
_openedApplicationAreaId = applicationAreaId; _openedApplicationAreaId = applicationAreaId;
@@ -124,7 +124,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
{ {
VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId); VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId);
if (virtualAmiiboFile.ApplicationAreas.Any(item => item.ApplicationAreaId == applicationAreaId)) if (virtualAmiiboFile.ApplicationAreas.Exists(item => item.ApplicationAreaId == applicationAreaId))
{ {
return false; return false;
} }
@@ -144,7 +144,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
{ {
VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId); VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId);
if (virtualAmiiboFile.ApplicationAreas.Any(item => item.ApplicationAreaId == _openedApplicationAreaId)) if (virtualAmiiboFile.ApplicationAreas.Exists(item => item.ApplicationAreaId == _openedApplicationAreaId))
{ {
for (int i = 0; i < virtualAmiiboFile.ApplicationAreas.Count; i++) for (int i = 0; i < virtualAmiiboFile.ApplicationAreas.Count; i++)
{ {

View File

@@ -39,7 +39,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Sfdnsres.Proxy
} }
// Ignore comments and empty lines // Ignore comments and empty lines
if (line.StartsWith("#") || line.Trim().Length == 0) if (line.StartsWith('#') || line.Trim().Length == 0)
{ {
continue; continue;
} }

View File

@@ -8,6 +8,7 @@ using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.Loaders.Executables; using Ryujinx.HLE.Loaders.Executables;
using Ryujinx.Memory; using Ryujinx.Memory;
using System;
using System.Linq; using System.Linq;
using static Ryujinx.HLE.HOS.ModLoader; using static Ryujinx.HLE.HOS.ModLoader;
@@ -99,7 +100,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
if (string.IsNullOrWhiteSpace(programName)) if (string.IsNullOrWhiteSpace(programName))
{ {
programName = nacpData.Value.Title.ItemsRo.ToArray().FirstOrDefault(x => x.Name[0] != 0).NameString.ToString(); programName = Array.Find(nacpData.Value.Title.ItemsRo.ToArray(), x => x.Name[0] != 0).NameString.ToString();
} }
} }

View File

@@ -9,6 +9,7 @@ using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.Loaders.Executables; using Ryujinx.HLE.Loaders.Executables;
using Ryujinx.HLE.Loaders.Processes.Extensions; using Ryujinx.HLE.Loaders.Processes.Extensions;
using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@@ -176,7 +177,7 @@ namespace Ryujinx.HLE.Loaders.Processes
if (string.IsNullOrWhiteSpace(programName)) if (string.IsNullOrWhiteSpace(programName))
{ {
programName = nacpData.Value.Title.ItemsRo.ToArray().FirstOrDefault(x => x.Name[0] != 0).NameString.ToString(); programName = Array.Find(nacpData.Value.Title.ItemsRo.ToArray(), x => x.Name[0] != 0).NameString.ToString();
} }
if (nacpData.Value.PresenceGroupId != 0) if (nacpData.Value.PresenceGroupId != 0)

View File

@@ -6,6 +6,7 @@ using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.HOS.SystemState;
using Ryujinx.HLE.Loaders.Processes.Extensions; using Ryujinx.HLE.Loaders.Processes.Extensions;
using Ryujinx.Horizon.Common; using Ryujinx.Horizon.Common;
using System;
using System.Linq; using System.Linq;
namespace Ryujinx.HLE.Loaders.Processes namespace Ryujinx.HLE.Loaders.Processes
@@ -59,7 +60,7 @@ namespace Ryujinx.HLE.Loaders.Processes
if (string.IsNullOrWhiteSpace(Name)) if (string.IsNullOrWhiteSpace(Name))
{ {
Name = ApplicationControlProperties.Title.ItemsRo.ToArray().FirstOrDefault(x => x.Name[0] != 0).NameString.ToString(); Name = Array.Find(ApplicationControlProperties.Title.ItemsRo.ToArray(), x => x.Name[0] != 0).NameString.ToString();
} }
DisplayVersion = ApplicationControlProperties.DisplayVersionString.ToString(); DisplayVersion = ApplicationControlProperties.DisplayVersionString.ToString();

View File

@@ -4,36 +4,36 @@
{ {
private const int ModuleId = 1; private const int ModuleId = 1;
public static Result SessionCountExceeded => new Result(ModuleId, 7); public static Result SessionCountExceeded => new(ModuleId, 7);
public static Result InvalidCapability => new Result(ModuleId, 14); public static Result InvalidCapability => new(ModuleId, 14);
public static Result ThreadNotStarted => new Result(ModuleId, 57); public static Result ThreadNotStarted => new(ModuleId, 57);
public static Result ThreadTerminating => new Result(ModuleId, 59); public static Result ThreadTerminating => new(ModuleId, 59);
public static Result InvalidSize => new Result(ModuleId, 101); public static Result InvalidSize => new(ModuleId, 101);
public static Result InvalidAddress => new Result(ModuleId, 102); public static Result InvalidAddress => new(ModuleId, 102);
public static Result OutOfResource => new Result(ModuleId, 103); public static Result OutOfResource => new(ModuleId, 103);
public static Result OutOfMemory => new Result(ModuleId, 104); public static Result OutOfMemory => new(ModuleId, 104);
public static Result HandleTableFull => new Result(ModuleId, 105); public static Result HandleTableFull => new(ModuleId, 105);
public static Result InvalidMemState => new Result(ModuleId, 106); public static Result InvalidMemState => new(ModuleId, 106);
public static Result InvalidPermission => new Result(ModuleId, 108); public static Result InvalidPermission => new(ModuleId, 108);
public static Result InvalidMemRange => new Result(ModuleId, 110); public static Result InvalidMemRange => new(ModuleId, 110);
public static Result InvalidPriority => new Result(ModuleId, 112); public static Result InvalidPriority => new(ModuleId, 112);
public static Result InvalidCpuCore => new Result(ModuleId, 113); public static Result InvalidCpuCore => new(ModuleId, 113);
public static Result InvalidHandle => new Result(ModuleId, 114); public static Result InvalidHandle => new(ModuleId, 114);
public static Result UserCopyFailed => new Result(ModuleId, 115); public static Result UserCopyFailed => new(ModuleId, 115);
public static Result InvalidCombination => new Result(ModuleId, 116); public static Result InvalidCombination => new(ModuleId, 116);
public static Result TimedOut => new Result(ModuleId, 117); public static Result TimedOut => new(ModuleId, 117);
public static Result Cancelled => new Result(ModuleId, 118); public static Result Cancelled => new(ModuleId, 118);
public static Result MaximumExceeded => new Result(ModuleId, 119); public static Result MaximumExceeded => new(ModuleId, 119);
public static Result InvalidEnumValue => new Result(ModuleId, 120); public static Result InvalidEnumValue => new(ModuleId, 120);
public static Result NotFound => new Result(ModuleId, 121); public static Result NotFound => new(ModuleId, 121);
public static Result InvalidThread => new Result(ModuleId, 122); public static Result InvalidThread => new(ModuleId, 122);
public static Result PortRemoteClosed => new Result(ModuleId, 123); public static Result PortRemoteClosed => new(ModuleId, 123);
public static Result InvalidState => new Result(ModuleId, 125); public static Result InvalidState => new(ModuleId, 125);
public static Result ReservedValue => new Result(ModuleId, 126); public static Result ReservedValue => new(ModuleId, 126);
public static Result PortClosed => new Result(ModuleId, 131); public static Result PortClosed => new(ModuleId, 131);
public static Result ResLimitExceeded => new Result(ModuleId, 132); public static Result ResLimitExceeded => new(ModuleId, 132);
public static Result ReceiveListBroken => new Result(ModuleId, 258); public static Result ReceiveListBroken => new(ModuleId, 258);
public static Result OutOfVaSpace => new Result(ModuleId, 259); public static Result OutOfVaSpace => new(ModuleId, 259);
public static Result CmdBufferTooSmall => new Result(ModuleId, 260); public static Result CmdBufferTooSmall => new(ModuleId, 260);
} }
} }

View File

@@ -2,7 +2,7 @@
namespace Ryujinx.Horizon.Common namespace Ryujinx.Horizon.Common
{ {
public struct OnScopeExit : IDisposable public readonly struct OnScopeExit : IDisposable
{ {
private readonly Action _action; private readonly Action _action;

View File

@@ -13,13 +13,13 @@ namespace Ryujinx.Horizon.Common
public int ErrorCode { get; } public int ErrorCode { get; }
public bool IsSuccess => ErrorCode == 0; public readonly bool IsSuccess => ErrorCode == 0;
public bool IsFailure => ErrorCode != 0; public readonly bool IsFailure => ErrorCode != 0;
public int Module => ErrorCode & (ModuleMax - 1); public readonly int Module => ErrorCode & (ModuleMax - 1);
public int Description => (ErrorCode >> ModuleBits) & (DescriptionMax - 1); public readonly int Description => (ErrorCode >> ModuleBits) & (DescriptionMax - 1);
public string PrintableResult => $"{2000 + Module:D4}-{Description:D4}"; public readonly string PrintableResult => $"{2000 + Module:D4}-{Description:D4}";
public Result(int module, int description) public Result(int module, int description)
{ {
@@ -36,17 +36,17 @@ namespace Ryujinx.Horizon.Common
ErrorCode = module | (description << ModuleBits); ErrorCode = module | (description << ModuleBits);
} }
public override bool Equals(object obj) public readonly override bool Equals(object obj)
{ {
return obj is Result result && result.Equals(this); return obj is Result result && result.Equals(this);
} }
public bool Equals(Result other) public readonly bool Equals(Result other)
{ {
return other.ErrorCode == ErrorCode; return other.ErrorCode == ErrorCode;
} }
public override int GetHashCode() public readonly override int GetHashCode()
{ {
return ErrorCode; return ErrorCode;
} }
@@ -61,7 +61,7 @@ namespace Ryujinx.Horizon.Common
return !lhs.Equals(rhs); return !lhs.Equals(rhs);
} }
public bool InRange(int minInclusive, int maxInclusive) public readonly bool InRange(int minInclusive, int maxInclusive)
{ {
return (uint)(Description - minInclusive) <= (uint)(maxInclusive - minInclusive); return (uint)(Description - minInclusive) <= (uint)(maxInclusive - minInclusive);
} }
@@ -105,7 +105,7 @@ namespace Ryujinx.Horizon.Common
throw new InvalidResultException(this); throw new InvalidResultException(this);
} }
public override string ToString() public readonly override string ToString()
{ {
if (ResultNames.TryGet(ErrorCode, out string name)) if (ResultNames.TryGet(ErrorCode, out string name))
{ {

View File

@@ -1,6 +1,5 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
namespace Ryujinx.Memory namespace Ryujinx.Memory
@@ -101,12 +100,12 @@ namespace Ryujinx.Memory
/// </summary> /// </summary>
/// <param name="offset">Starting offset of the range to be committed</param> /// <param name="offset">Starting offset of the range to be committed</param>
/// <param name="size">Size of the range to be committed</param> /// <param name="size">Size of the range to be committed</param>
/// <returns>True if the operation was successful, false otherwise</returns> /// <exception cref="SystemException">Throw when the operation was not successful</exception>
/// <exception cref="ObjectDisposedException">Throw when the memory block has already been disposed</exception> /// <exception cref="ObjectDisposedException">Throw when the memory block has already been disposed</exception>
/// <exception cref="InvalidMemoryRegionException">Throw when either <paramref name="offset"/> or <paramref name="size"/> are out of range</exception> /// <exception cref="InvalidMemoryRegionException">Throw when either <paramref name="offset"/> or <paramref name="size"/> are out of range</exception>
public bool Commit(ulong offset, ulong size) public void Commit(ulong offset, ulong size)
{ {
return MemoryManagement.Commit(GetPointerInternal(offset, size), size, _forJit); MemoryManagement.Commit(GetPointerInternal(offset, size), size, _forJit);
} }
/// <summary> /// <summary>
@@ -115,12 +114,12 @@ namespace Ryujinx.Memory
/// </summary> /// </summary>
/// <param name="offset">Starting offset of the range to be decommitted</param> /// <param name="offset">Starting offset of the range to be decommitted</param>
/// <param name="size">Size of the range to be decommitted</param> /// <param name="size">Size of the range to be decommitted</param>
/// <returns>True if the operation was successful, false otherwise</returns> /// <exception cref="SystemException">Throw when the operation was not successful</exception>
/// <exception cref="ObjectDisposedException">Throw when the memory block has already been disposed</exception> /// <exception cref="ObjectDisposedException">Throw when the memory block has already been disposed</exception>
/// <exception cref="InvalidMemoryRegionException">Throw when either <paramref name="offset"/> or <paramref name="size"/> are out of range</exception> /// <exception cref="InvalidMemoryRegionException">Throw when either <paramref name="offset"/> or <paramref name="size"/> are out of range</exception>
public bool Decommit(ulong offset, ulong size) public void Decommit(ulong offset, ulong size)
{ {
return MemoryManagement.Decommit(GetPointerInternal(offset, size), size); MemoryManagement.Decommit(GetPointerInternal(offset, size), size);
} }
/// <summary> /// <summary>

View File

@@ -36,15 +36,15 @@ namespace Ryujinx.Memory
} }
} }
public static bool Commit(IntPtr address, ulong size, bool forJit) public static void Commit(IntPtr address, ulong size, bool forJit)
{ {
if (OperatingSystem.IsWindows()) if (OperatingSystem.IsWindows())
{ {
return MemoryManagementWindows.Commit(address, (IntPtr)size); MemoryManagementWindows.Commit(address, (IntPtr)size);
} }
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
{ {
return MemoryManagementUnix.Commit(address, size, forJit); MemoryManagementUnix.Commit(address, size, forJit);
} }
else else
{ {
@@ -52,15 +52,15 @@ namespace Ryujinx.Memory
} }
} }
public static bool Decommit(IntPtr address, ulong size) public static void Decommit(IntPtr address, ulong size)
{ {
if (OperatingSystem.IsWindows()) if (OperatingSystem.IsWindows())
{ {
return MemoryManagementWindows.Decommit(address, (IntPtr)size); MemoryManagementWindows.Decommit(address, (IntPtr)size);
} }
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
{ {
return MemoryManagementUnix.Decommit(address, size); MemoryManagementUnix.Decommit(address, size);
} }
else else
{ {

View File

@@ -2,8 +2,6 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.Versioning; using System.Runtime.Versioning;
using System.Text;
using static Ryujinx.Memory.MemoryManagerUnixHelper; using static Ryujinx.Memory.MemoryManagerUnixHelper;
namespace Ryujinx.Memory namespace Ryujinx.Memory
@@ -12,7 +10,7 @@ namespace Ryujinx.Memory
[SupportedOSPlatform("macos")] [SupportedOSPlatform("macos")]
static class MemoryManagementUnix static class MemoryManagementUnix
{ {
private static readonly ConcurrentDictionary<IntPtr, ulong> _allocations = new ConcurrentDictionary<IntPtr, ulong>(); private static readonly ConcurrentDictionary<IntPtr, ulong> _allocations = new();
public static IntPtr Allocate(ulong size, bool forJit) public static IntPtr Allocate(ulong size, bool forJit)
{ {
@@ -68,7 +66,7 @@ namespace Ryujinx.Memory
return ptr; return ptr;
} }
public static bool Commit(IntPtr address, ulong size, bool forJit) public static void Commit(IntPtr address, ulong size, bool forJit)
{ {
MmapProts prot = MmapProts.PROT_READ | MmapProts.PROT_WRITE; MmapProts prot = MmapProts.PROT_READ | MmapProts.PROT_WRITE;
@@ -81,11 +79,9 @@ namespace Ryujinx.Memory
{ {
throw new SystemException(Marshal.GetLastPInvokeErrorMessage()); throw new SystemException(Marshal.GetLastPInvokeErrorMessage());
} }
return true;
} }
public static bool Decommit(IntPtr address, ulong size) public static void Decommit(IntPtr address, ulong size)
{ {
// Must be writable for madvise to work properly. // Must be writable for madvise to work properly.
if (mprotect(address, size, MmapProts.PROT_READ | MmapProts.PROT_WRITE) != 0) if (mprotect(address, size, MmapProts.PROT_READ | MmapProts.PROT_WRITE) != 0)
@@ -102,8 +98,6 @@ namespace Ryujinx.Memory
{ {
throw new SystemException(Marshal.GetLastPInvokeErrorMessage()); throw new SystemException(Marshal.GetLastPInvokeErrorMessage());
} }
return true;
} }
public static bool Reprotect(IntPtr address, ulong size, MemoryPermission permission) public static bool Reprotect(IntPtr address, ulong size, MemoryPermission permission)
@@ -146,7 +140,7 @@ namespace Ryujinx.Memory
if (OperatingSystem.IsMacOS()) if (OperatingSystem.IsMacOS())
{ {
byte[] memName = Encoding.ASCII.GetBytes("Ryujinx-XXXXXX"); byte[] memName = "Ryujinx-XXXXXX"u8.ToArray();
fixed (byte* pMemName = memName) fixed (byte* pMemName = memName)
{ {
@@ -164,7 +158,7 @@ namespace Ryujinx.Memory
} }
else else
{ {
byte[] fileName = Encoding.ASCII.GetBytes("/dev/shm/Ryujinx-XXXXXX"); byte[] fileName = "/dev/shm/Ryujinx-XXXXXX"u8.ToArray();
fixed (byte* pFileName = fileName) fixed (byte* pFileName = fileName)
{ {

View File

@@ -10,7 +10,7 @@ namespace Ryujinx.Memory
{ {
public const int PageSize = 0x1000; public const int PageSize = 0x1000;
private static readonly PlaceholderManager _placeholders = new PlaceholderManager(); private static readonly PlaceholderManager _placeholders = new();
public static IntPtr Allocate(IntPtr size) public static IntPtr Allocate(IntPtr size)
{ {
@@ -55,14 +55,20 @@ namespace Ryujinx.Memory
return ptr; return ptr;
} }
public static bool Commit(IntPtr location, IntPtr size) public static void Commit(IntPtr location, IntPtr size)
{ {
return WindowsApi.VirtualAlloc(location, size, AllocationType.Commit, MemoryProtection.ReadWrite) != IntPtr.Zero; if (WindowsApi.VirtualAlloc(location, size, AllocationType.Commit, MemoryProtection.ReadWrite) == IntPtr.Zero)
{
throw new SystemException(Marshal.GetLastPInvokeErrorMessage());
}
} }
public static bool Decommit(IntPtr location, IntPtr size) public static void Decommit(IntPtr location, IntPtr size)
{ {
return WindowsApi.VirtualFree(location, size, AllocationType.Decommit); if (!WindowsApi.VirtualFree(location, size, AllocationType.Decommit))
{
throw new SystemException(Marshal.GetLastPInvokeErrorMessage());
}
} }
public static void MapView(IntPtr sharedMemory, ulong srcOffset, IntPtr location, IntPtr size, MemoryBlock owner) public static void MapView(IntPtr sharedMemory, ulong srcOffset, IntPtr location, IntPtr size, MemoryBlock owner)

View File

@@ -20,7 +20,7 @@ namespace Ryujinx.ShaderTools
public ReadOnlySpan<ulong> GetCode(ulong address, int minimumSize) public ReadOnlySpan<ulong> GetCode(ulong address, int minimumSize)
{ {
return MemoryMarshal.Cast<byte, ulong>(new ReadOnlySpan<byte>(_data).Slice((int)address)); return MemoryMarshal.Cast<byte, ulong>(new ReadOnlySpan<byte>(_data)[(int)address..]);
} }
} }
@@ -53,7 +53,7 @@ namespace Ryujinx.ShaderTools
byte[] data = File.ReadAllBytes(options.InputPath); byte[] data = File.ReadAllBytes(options.InputPath);
TranslationOptions translationOptions = new TranslationOptions(options.TargetLanguage, options.TargetApi, flags); TranslationOptions translationOptions = new(options.TargetLanguage, options.TargetApi, flags);
ShaderProgram program = Translator.CreateContext(0, new GpuAccessor(data), translationOptions).Translate(); ShaderProgram program = Translator.CreateContext(0, new GpuAccessor(data), translationOptions).Translate();

View File

@@ -9,8 +9,6 @@ namespace Ryujinx.Tests.Memory
{ {
public class MultiRegionTrackingTests public class MultiRegionTrackingTests
{ {
private const int RndCnt = 3;
private const ulong MemorySize = 0x8000; private const ulong MemorySize = 0x8000;
private const int PageSize = 4096; private const int PageSize = 4096;
@@ -39,7 +37,7 @@ namespace Ryujinx.Tests.Memory
(IMultiRegionHandle)_tracking.BeginGranularTracking(address, size, null, granularity, 0); (IMultiRegionHandle)_tracking.BeginGranularTracking(address, size, null, granularity, 0);
} }
private void RandomOrder(Random random, List<int> indices, Action<int> action) private static void RandomOrder(Random random, List<int> indices, Action<int> action)
{ {
List<int> choices = indices.ToList(); List<int> choices = indices.ToList();
@@ -51,7 +49,7 @@ namespace Ryujinx.Tests.Memory
} }
} }
private int ExpectQueryInOrder(IMultiRegionHandle handle, ulong startAddress, ulong size, Func<ulong, bool> addressPredicate) private static int ExpectQueryInOrder(IMultiRegionHandle handle, ulong startAddress, ulong size, Func<ulong, bool> addressPredicate)
{ {
int regionCount = 0; int regionCount = 0;
ulong lastAddress = startAddress; ulong lastAddress = startAddress;
@@ -67,7 +65,7 @@ namespace Ryujinx.Tests.Memory
return regionCount; return regionCount;
} }
private int ExpectQueryInOrder(IMultiRegionHandle handle, ulong startAddress, ulong size, Func<ulong, bool> addressPredicate, int sequenceNumber) private static int ExpectQueryInOrder(IMultiRegionHandle handle, ulong startAddress, ulong size, Func<ulong, bool> addressPredicate, int sequenceNumber)
{ {
int regionCount = 0; int regionCount = 0;
ulong lastAddress = startAddress; ulong lastAddress = startAddress;
@@ -83,9 +81,9 @@ namespace Ryujinx.Tests.Memory
return regionCount; return regionCount;
} }
private void PreparePages(IMultiRegionHandle handle, int pageCount, ulong address = 0) private static void PreparePages(IMultiRegionHandle handle, int pageCount, ulong address = 0)
{ {
Random random = new Random(); Random random = new();
// Make sure the list has minimum granularity (smart region changes granularity based on requested ranges) // Make sure the list has minimum granularity (smart region changes granularity based on requested ranges)
RandomOrder(random, Enumerable.Range(0, pageCount).ToList(), (i) => RandomOrder(random, Enumerable.Range(0, pageCount).ToList(), (i) =>
@@ -105,7 +103,7 @@ namespace Ryujinx.Tests.Memory
const int pageCount = 32; const int pageCount = 32;
IMultiRegionHandle handle = GetGranular(smart, 0, PageSize * pageCount, PageSize); IMultiRegionHandle handle = GetGranular(smart, 0, PageSize * pageCount, PageSize);
Random random = new Random(); Random random = new();
PreparePages(handle, pageCount); PreparePages(handle, pageCount);
@@ -149,7 +147,7 @@ namespace Ryujinx.Tests.Memory
PreparePages(handle, pageCount); PreparePages(handle, pageCount);
Random random = new Random(); Random random = new();
IEnumerable<int> halfRange = Enumerable.Range(0, pageCount / 2); IEnumerable<int> halfRange = Enumerable.Range(0, pageCount / 2);
List<int> odd = halfRange.Select(x => x * 2 + 1).ToList(); List<int> odd = halfRange.Select(x => x * 2 + 1).ToList();
@@ -240,7 +238,8 @@ namespace Ryujinx.Tests.Memory
ulong expectedAddress = 0; ulong expectedAddress = 0;
// Expect each region to trigger in its entirety, in address ascending order. // Expect each region to trigger in its entirety, in address ascending order.
handle.QueryModified((address, size) => { handle.QueryModified((address, size) =>
{
int region = regionSizes[regionInd++]; int region = regionSizes[regionInd++];
Assert.AreEqual(address, expectedAddress); Assert.AreEqual(address, expectedAddress);

View File

@@ -7,14 +7,14 @@ namespace Ryujinx.Tests.Memory
{ {
public class Tests public class Tests
{ {
private static readonly ulong MemorySize = MemoryBlock.GetPageSize() * 8; private static readonly ulong _memorySize = MemoryBlock.GetPageSize() * 8;
private MemoryBlock _memoryBlock; private MemoryBlock _memoryBlock;
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
_memoryBlock = new MemoryBlock(MemorySize); _memoryBlock = new MemoryBlock(_memorySize);
} }
[TearDown] [TearDown]
@@ -47,8 +47,8 @@ namespace Ryujinx.Tests.Memory
ulong pageSize = MemoryBlock.GetPageSize(); ulong pageSize = MemoryBlock.GetPageSize();
ulong blockSize = MemoryBlock.GetPageSize() * 16; ulong blockSize = MemoryBlock.GetPageSize() * 16;
using MemoryBlock backing = new MemoryBlock(blockSize, MemoryAllocationFlags.Mirrorable); using MemoryBlock backing = new(blockSize, MemoryAllocationFlags.Mirrorable);
using MemoryBlock toAlias = new MemoryBlock(blockSize, MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible); using MemoryBlock toAlias = new(blockSize, MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible);
toAlias.MapView(backing, pageSize, 0, pageSize * 4); toAlias.MapView(backing, pageSize, 0, pageSize * 4);
toAlias.UnmapView(backing, pageSize * 3, pageSize); toAlias.UnmapView(backing, pageSize * 3, pageSize);
@@ -66,10 +66,10 @@ namespace Ryujinx.Tests.Memory
int pageBits = (int)ulong.Log2(pageSize); int pageBits = (int)ulong.Log2(pageSize);
ulong blockSize = MemoryBlock.GetPageSize() * 128; ulong blockSize = MemoryBlock.GetPageSize() * 128;
using MemoryBlock backing = new MemoryBlock(blockSize, MemoryAllocationFlags.Mirrorable); using MemoryBlock backing = new(blockSize, MemoryAllocationFlags.Mirrorable);
using MemoryBlock toAlias = new MemoryBlock(blockSize, MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible); using MemoryBlock toAlias = new(blockSize, MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible);
Random rng = new Random(123); Random rng = new(123);
for (int i = 0; i < 20000; i++) for (int i = 0; i < 20000; i++)
{ {
@@ -101,8 +101,8 @@ namespace Ryujinx.Tests.Memory
ulong pageSize = MemoryBlock.GetPageSize(); ulong pageSize = MemoryBlock.GetPageSize();
ulong size = 100000 * pageSize; // The mappings limit on Linux is usually around 65K, so let's make sure we are above that. ulong size = 100000 * pageSize; // The mappings limit on Linux is usually around 65K, so let's make sure we are above that.
using MemoryBlock backing = new MemoryBlock(pageSize, MemoryAllocationFlags.Mirrorable); using MemoryBlock backing = new(pageSize, MemoryAllocationFlags.Mirrorable);
using MemoryBlock toAlias = new MemoryBlock(size, MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible); using MemoryBlock toAlias = new(size, MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible);
for (ulong offset = 0; offset < size; offset += pageSize) for (ulong offset = 0; offset < size; offset += pageSize)
{ {

View File

@@ -102,15 +102,17 @@ namespace Ryujinx.Tests.Memory
allHandle.Reprotect(); allHandle.Reprotect();
(ulong address, ulong size)? readTrackingTriggeredAll = null; (ulong address, ulong size)? readTrackingTriggeredAll = null;
Action registerReadAction = () =>
void RegisterReadAction()
{ {
readTrackingTriggeredAll = null; readTrackingTriggeredAll = null;
allHandle.RegisterAction((address, size) => allHandle.RegisterAction((address, size) =>
{ {
readTrackingTriggeredAll = (address, size); readTrackingTriggeredAll = (address, size);
}); });
}; }
registerReadAction();
RegisterReadAction();
// Create 16 page sized handles contained within the allHandle. // Create 16 page sized handles contained within the allHandle.
RegionHandle[] containedHandles = new RegionHandle[16]; RegionHandle[] containedHandles = new RegionHandle[16];
@@ -149,7 +151,7 @@ namespace Ryujinx.Tests.Memory
} }
// Clear flags and reset read action. // Clear flags and reset read action.
registerReadAction(); RegisterReadAction();
allHandle.Reprotect(); allHandle.Reprotect();
containedHandles[i].Reprotect(); containedHandles[i].Reprotect();
} }
@@ -157,8 +159,8 @@ namespace Ryujinx.Tests.Memory
[Test] [Test]
public void PageAlignment( public void PageAlignment(
[Values(1ul, 512ul, 2048ul, 4096ul, 65536ul)] [Random(1ul, 65536ul, RndCnt)] ulong address, [Values(1ul, 512ul, 2048ul, 4096ul, 65536ul)][Random(1ul, 65536ul, RndCnt)] ulong address,
[Values(1ul, 4ul, 1024ul, 4096ul, 65536ul)] [Random(1ul, 65536ul, RndCnt)] ulong size) [Values(1ul, 4ul, 1024ul, 4096ul, 65536ul)][Random(1ul, 65536ul, RndCnt)] ulong size)
{ {
ulong alignedStart = (address / PageSize) * PageSize; ulong alignedStart = (address / PageSize) * PageSize;
ulong alignedEnd = ((address + size + PageSize - 1) / PageSize) * PageSize; ulong alignedEnd = ((address + size + PageSize - 1) / PageSize) * PageSize;
@@ -204,7 +206,7 @@ namespace Ryujinx.Tests.Memory
long finishedTime = 0; long finishedTime = 0;
RegionHandle[] handles = new RegionHandle[threadCount * handlesPerThread]; RegionHandle[] handles = new RegionHandle[threadCount * handlesPerThread];
Random globalRand = new Random(); Random globalRand = new();
for (int i = 0; i < handles.Length; i++) for (int i = 0; i < handles.Length; i++)
{ {
@@ -212,7 +214,7 @@ namespace Ryujinx.Tests.Memory
handles[i].Reprotect(); handles[i].Reprotect();
} }
List<Thread> testThreads = new List<Thread>(); List<Thread> testThreads = new();
// Dirty flag consumer threads // Dirty flag consumer threads
int dirtyFlagReprotects = 0; int dirtyFlagReprotects = 0;
@@ -224,7 +226,7 @@ namespace Ryujinx.Tests.Memory
int handleBase = randSeed * handlesPerThread; int handleBase = randSeed * handlesPerThread;
while (Stopwatch.GetTimestamp() < finishedTime) while (Stopwatch.GetTimestamp() < finishedTime)
{ {
Random random = new Random(randSeed); Random random = new(randSeed);
RegionHandle handle = handles[handleBase + random.Next(handlesPerThread)]; RegionHandle handle = handles[handleBase + random.Next(handlesPerThread)];
if (handle.Dirty) if (handle.Dirty)
@@ -243,7 +245,7 @@ namespace Ryujinx.Tests.Memory
int randSeed = i; int randSeed = i;
testThreads.Add(new Thread(() => testThreads.Add(new Thread(() =>
{ {
Random random = new Random(randSeed); Random random = new(randSeed);
ulong handleBase = (ulong)(randSeed * handlesPerThread * PageSize); ulong handleBase = (ulong)(randSeed * handlesPerThread * PageSize);
while (Stopwatch.GetTimestamp() < finishedTime) while (Stopwatch.GetTimestamp() < finishedTime)
{ {
@@ -261,7 +263,7 @@ namespace Ryujinx.Tests.Memory
testThreads.Add(new Thread(() => testThreads.Add(new Thread(() =>
{ {
int maxAddress = threadCount * handlesPerThread * PageSize; int maxAddress = threadCount * handlesPerThread * PageSize;
Random random = new Random(randSeed + 512); Random random = new(randSeed + 512);
while (Stopwatch.GetTimestamp() < finishedTime) while (Stopwatch.GetTimestamp() < finishedTime)
{ {
RegionHandle handle = _tracking.BeginTracking((ulong)random.Next(maxAddress), (ulong)random.Next(65536), 0); RegionHandle handle = _tracking.BeginTracking((ulong)random.Next(maxAddress), (ulong)random.Next(65536), 0);
@@ -303,7 +305,7 @@ namespace Ryujinx.Tests.Memory
int signalThreadsDone = 0; int signalThreadsDone = 0;
bool isRegistered = false; bool isRegistered = false;
Action registerReadAction = () => void RegisterReadAction()
{ {
registeredCount++; registeredCount++;
handle.RegisterAction((address, size) => handle.RegisterAction((address, size) =>
@@ -311,7 +313,7 @@ namespace Ryujinx.Tests.Memory
isRegistered = false; isRegistered = false;
Interlocked.Increment(ref triggeredCount); Interlocked.Increment(ref triggeredCount);
}); });
}; }
const int threadCount = 16; const int threadCount = 16;
const int iterationCount = 10000; const int iterationCount = 10000;
@@ -322,7 +324,7 @@ namespace Ryujinx.Tests.Memory
int randSeed = i; int randSeed = i;
signalThreads[i] = new Thread(() => signalThreads[i] = new Thread(() =>
{ {
Random random = new Random(randSeed); Random random = new(randSeed);
for (int j = 0; j < iterationCount; j++) for (int j = 0; j < iterationCount; j++)
{ {
_tracking.VirtualMemoryEvent((ulong)random.Next(PageSize), 4, false); _tracking.VirtualMemoryEvent((ulong)random.Next(PageSize), 4, false);
@@ -346,7 +348,7 @@ namespace Ryujinx.Tests.Memory
if (!isRegistered) if (!isRegistered)
{ {
isRegistered = true; isRegistered = true;
registerReadAction(); RegisterReadAction();
} }
} }

View File

@@ -4,12 +4,12 @@ namespace Ryujinx.Tests.Unicorn
{ {
public class IndexedProperty<TIndex, TValue> public class IndexedProperty<TIndex, TValue>
{ {
private Func<TIndex, TValue> _getFunc; private readonly Func<TIndex, TValue> _getFunc;
private Action<TIndex, TValue> _setAction; private readonly Action<TIndex, TValue> _setAction;
public IndexedProperty(Func<TIndex, TValue> getFunc, Action<TIndex, TValue> setAction) public IndexedProperty(Func<TIndex, TValue> getFunc, Action<TIndex, TValue> setAction)
{ {
_getFunc = getFunc; _getFunc = getFunc;
_setAction = setAction; _setAction = setAction;
} }

Some files were not shown because too many files have changed in this diff Show More