Compare commits

..

20 Commits

Author SHA1 Message Date
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
gdkchan
f92921a6d1 Implement Load/Store Local/Shared and Atomic shared using new instructions (#5241)
* Implement Load/Store Local/Shared and Atomic shared using new instructions

* Remove now unused code

* Fix base offset register overwrite

* Fix missing storage buffer set index when generating GLSL for Vulkan

* Shader cache version bump

* Remove more unused code

* Some PR feedback
2023-06-15 17:31:53 -03:00
Marco Carvalho
32d21ddf17 Inheritance list should not be redundant (#5230) 2023-06-15 03:54:27 +00:00
Marco Carvalho
82f90704a0 Blocks should be synchronized on read-only fields (#5212)
* Blocks should be synchronized on read-only fields

* more readonlys

* fix alignment

* more

* Update ISelfController.cs

* simplify new

* simplify new
2023-06-15 00:34:55 +00:00
dependabot[bot]
f978d3726a nuget: bump System.Management from 7.0.1 to 7.0.2 (#5302)
Bumps [System.Management](https://github.com/dotnet/runtime) from 7.0.1 to 7.0.2.
- [Release notes](https://github.com/dotnet/runtime/releases)
- [Commits](https://github.com/dotnet/runtime/compare/v7.0.1...v7.0.2)

---
updated-dependencies:
- dependency-name: System.Management
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-14 18:21:17 +02:00
Mary
6f28c4abad test: Make tests runnable on system without 4KiB page size (#5184)
* ARMeilleure: Do not hardcode 4KiB page size in JitCache

* test: Do not hardcode page size to 4KiB for Ryujinx.Tests.Memory.Tests

Fix running tests on Asahi Linux with 16KiB pages.

* test: Do not hardcode page size to 4KiB for Ryujinx.Tests.Cpu

Fix running tests on Asahi Linux.

Test runner still crash when trying to run all test suite.

* test: Do not hardcode page size to 4KiB for Ryujinx.Tests.Cpu

Fix somecrashes on Asahi Linux.

* test: Ignore Vshl test on ARM64 due to unicorn crashes

* test: Workaround hardcoded size on some tests

Change mapping of code and data in case of non 4KiB configuration.

* test: Make CpuTestT32Flow depends on code address

Fix failure with different page size.

* test: Disable CpuTestThumb.TestRandomTestCases when page size isn't 4KiB

The test data needs to be reevaluated to take different page size into account.

* Address gdkchan's comments
2023-06-14 18:02:41 +02:00
153 changed files with 1123 additions and 996 deletions

View File

@@ -46,7 +46,7 @@
<PackageVersion Include="System.Drawing.Common" Version="7.0.0" /> <PackageVersion Include="System.Drawing.Common" Version="7.0.0" />
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.31.0" /> <PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.31.0" />
<PackageVersion Include="System.IO.Hashing" Version="7.0.0" /> <PackageVersion Include="System.IO.Hashing" Version="7.0.0" />
<PackageVersion Include="System.Management" Version="7.0.1" /> <PackageVersion Include="System.Management" Version="7.0.2" />
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" /> <PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
<PackageVersion Include="XamlNameReferenceGenerator" Version="1.6.1" /> <PackageVersion Include="XamlNameReferenceGenerator" Version="1.6.1" />
</ItemGroup> </ItemGroup>

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

@@ -13,7 +13,7 @@
} }
} }
enum OpCode32SimdSelMode : int enum OpCode32SimdSelMode
{ {
Eq = 0, Eq = 0,
Vs, Vs,

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,9 +6,9 @@ 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

@@ -78,7 +78,7 @@ namespace ARMeilleure.Signal
private static IntPtr _signalHandlerPtr; private static IntPtr _signalHandlerPtr;
private static IntPtr _signalHandlerHandle; private static IntPtr _signalHandlerHandle;
private static readonly object _lock = new object(); private static readonly object _lock = new();
private static bool _initialized; private static bool _initialized;
static NativeSignalHandler() static NativeSignalHandler()

View File

@@ -1,6 +1,6 @@
namespace ARMeilleure.State namespace ARMeilleure.State
{ {
enum ExecutionMode : int enum ExecutionMode
{ {
Aarch32Arm = 0, Aarch32Arm = 0,
Aarch32Thumb = 1, Aarch32Thumb = 1,

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

@@ -2,6 +2,7 @@ using ARMeilleure.CodeGen;
using ARMeilleure.CodeGen.Unwinding; using ARMeilleure.CodeGen.Unwinding;
using ARMeilleure.Memory; using ARMeilleure.Memory;
using ARMeilleure.Native; using ARMeilleure.Native;
using Ryujinx.Memory;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
@@ -12,8 +13,8 @@ namespace ARMeilleure.Translation.Cache
{ {
static partial class JitCache static partial class JitCache
{ {
private const int PageSize = 4 * 1024; private static readonly int PageSize = (int)MemoryBlock.GetPageSize();
private const int PageMask = PageSize - 1; private static readonly int PageMask = PageSize - 1;
private const int CodeAlignment = 4; // Bytes. private const int CodeAlignment = 4; // Bytes.
private const int CacheSize = 2047 * 1024 * 1024; private const int CacheSize = 2047 * 1024 * 1024;
@@ -25,7 +26,7 @@ namespace ARMeilleure.Translation.Cache
private static readonly List<CacheEntry> _cacheEntries = new List<CacheEntry>(); private static readonly List<CacheEntry> _cacheEntries = new List<CacheEntry>();
private static readonly object _lock = new object(); private static readonly object _lock = new();
private static bool _initialized; private static bool _initialized;
[SupportedOSPlatform("windows")] [SupportedOSPlatform("windows")]

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,14 +10,14 @@ 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 object _lock = new object(); private readonly object _lock = new();
public OpenALHardwareDeviceSession(OpenALHardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, float requestedVolume) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount) public OpenALHardwareDeviceSession(OpenALHardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, float requestedVolume) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount)
{ {
@@ -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,6 +1,6 @@
namespace Ryujinx.Audio.Backends.SoundIo.Native namespace Ryujinx.Audio.Backends.SoundIo.Native
{ {
public enum SoundIoBackend : int public enum SoundIoBackend
{ {
None = 0, None = 0,
Jack = 1, Jack = 1,

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

@@ -11,7 +11,7 @@ namespace Ryujinx.Audio
/// <summary> /// <summary>
/// Lock used to control the waiters registration. /// Lock used to control the waiters registration.
/// </summary> /// </summary>
private object _lock = new object(); private readonly object _lock = new();
/// <summary> /// <summary>
/// Events signaled when the driver played audio buffers. /// Events signaled when the driver played audio buffers.

View File

@@ -10,7 +10,7 @@ namespace Ryujinx.Audio.Backends.Common
{ {
private const int RingBufferAlignment = 2048; private const int RingBufferAlignment = 2048;
private object _lock = new object(); private readonly object _lock = new();
private byte[] _buffer; private byte[] _buffer;
private int _size; private int _size;

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

@@ -14,12 +14,12 @@ namespace Ryujinx.Audio.Input
/// </summary> /// </summary>
public class AudioInputManager : IDisposable public class AudioInputManager : IDisposable
{ {
private object _lock = new object(); private readonly object _lock = new();
/// <summary> /// <summary>
/// Lock used for session allocation. /// Lock used for session allocation.
/// </summary> /// </summary>
private object _sessionLock = new object(); private readonly object _sessionLock = new();
/// <summary> /// <summary>
/// The session ids allocation table. /// The session ids allocation table.

View File

@@ -48,7 +48,7 @@ namespace Ryujinx.Audio.Input
/// <summary> /// <summary>
/// The lock of the parent. /// The lock of the parent.
/// </summary> /// </summary>
private object _parentLock; private readonly object _parentLock;
/// <summary> /// <summary>
/// The dispose state. /// The dispose state.

View File

@@ -14,12 +14,12 @@ namespace Ryujinx.Audio.Output
/// </summary> /// </summary>
public class AudioOutputManager : IDisposable public class AudioOutputManager : IDisposable
{ {
private object _lock = new object(); private readonly object _lock = new();
/// <summary> /// <summary>
/// Lock used for session allocation. /// Lock used for session allocation.
/// </summary> /// </summary>
private object _sessionLock = new object(); private readonly object _sessionLock = new();
/// <summary> /// <summary>
/// The session ids allocation table. /// The session ids allocation table.

View File

@@ -48,7 +48,7 @@ namespace Ryujinx.Audio.Output
/// <summary> /// <summary>
/// THe lock of the parent. /// THe lock of the parent.
/// </summary> /// </summary>
private object _parentLock; private readonly object _parentLock;
/// <summary> /// <summary>
/// The dispose state. /// The dispose state.

View File

@@ -26,7 +26,7 @@ namespace Ryujinx.Audio.Renderer.Server
{ {
public class AudioRenderSystem : IDisposable public class AudioRenderSystem : IDisposable
{ {
private object _lock = new object(); private readonly object _lock = new();
private AudioRendererRenderingDevice _renderingDevice; private AudioRendererRenderingDevice _renderingDevice;
private AudioRendererExecutionMode _executionMode; private AudioRendererExecutionMode _executionMode;

View File

@@ -19,12 +19,12 @@ namespace Ryujinx.Audio.Renderer.Server
/// <summary> /// <summary>
/// Lock used for session allocation. /// Lock used for session allocation.
/// </summary> /// </summary>
private object _sessionLock = new object(); private readonly object _sessionLock = new();
/// <summary> /// <summary>
/// Lock used to control the <see cref="AudioProcessor"/> running state. /// Lock used to control the <see cref="AudioProcessor"/> running state.
/// </summary> /// </summary>
private object _audioProcessorLock = new object(); private readonly object _audioProcessorLock = new();
/// <summary> /// <summary>
/// The session ids allocation table. /// The session ids allocation table.

View File

@@ -16,7 +16,7 @@ namespace Ryujinx.Audio.Renderer.Server.Upsampler
/// <summary> /// <summary>
/// Global lock of the object. /// Global lock of the object.
/// </summary> /// </summary>
private object Lock = new object(); private readonly object Lock = new();
/// <summary> /// <summary>
/// The upsamplers instances. /// The upsamplers instances.

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

@@ -7,7 +7,7 @@ namespace Ryujinx.Common.Configuration.Hid
// This enum was duplicated from Ryujinx.HLE.HOS.Services.Hid.PlayerIndex and should be kept identical // This enum was duplicated from Ryujinx.HLE.HOS.Services.Hid.PlayerIndex and should be kept identical
[Flags] [Flags]
[JsonConverter(typeof(TypedStringEnumConverter<ControllerType>))] [JsonConverter(typeof(TypedStringEnumConverter<ControllerType>))]
public enum ControllerType : int public enum ControllerType
{ {
None, None,
ProController = 1 << 0, ProController = 1 << 0,

View File

@@ -5,7 +5,7 @@ namespace Ryujinx.Common.Configuration.Hid
{ {
// This enum was duplicated from Ryujinx.HLE.HOS.Services.Hid.PlayerIndex and should be kept identical // This enum was duplicated from Ryujinx.HLE.HOS.Services.Hid.PlayerIndex and should be kept identical
[JsonConverter(typeof(TypedStringEnumConverter<PlayerIndex>))] [JsonConverter(typeof(TypedStringEnumConverter<PlayerIndex>))]
public enum PlayerIndex : int public enum PlayerIndex
{ {
Player1 = 0, Player1 = 0,
Player2 = 1, Player2 = 1,

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,10 +15,10 @@ 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);
public void Dispose() => _impl.Dispose(); public void Dispose() => _impl.Dispose();
} }
} }

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

@@ -56,7 +56,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
private int _refConsumerPtr; private int _refConsumerPtr;
private Action _interruptAction; private Action _interruptAction;
private object _interruptLock = new(); private readonly object _interruptLock = new();
public event EventHandler<ScreenCaptureImageInfo> ScreenCaptured; public event EventHandler<ScreenCaptureImageInfo> ScreenCaptured;

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

@@ -78,7 +78,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
private List<BufferMigration> _sources; private List<BufferMigration> _sources;
private BufferMigration _migrationTarget; private BufferMigration _migrationTarget;
private object _lock = new object(); private readonly object _lock = new();
/// <summary> /// <summary>
/// Whether the modified range list has any entries or not. /// Whether the modified range list has any entries or not.
@@ -125,7 +125,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
BufferModifiedRange overlap = overlaps[i]; BufferModifiedRange overlap = overlaps[i];
if (overlap.Address > address) if (overlap.Address > address)
{ {
// The start of the remaining region is uncovered by this overlap. Call the action for it. // The start of the remaining region is uncovered by this overlap. Call the action for it.

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 = 5080; 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

@@ -21,7 +21,7 @@ namespace Ryujinx.Graphics.OpenGL.Queries
private ulong _accumulatedCounter; private ulong _accumulatedCounter;
private int _waiterCount; private int _waiterCount;
private object _lock = new object(); private readonly object _lock = new();
private Queue<BufferedQuery> _queryPool; private Queue<BufferedQuery> _queryPool;
private AutoResetEvent _queuedEvent = new AutoResetEvent(false); private AutoResetEvent _queuedEvent = new AutoResetEvent(false);

View File

@@ -24,7 +24,7 @@ namespace Ryujinx.Graphics.OpenGL.Queries
private bool _hostAccessReserved = false; private bool _hostAccessReserved = false;
private int _refCount = 1; // Starts with a reference from the counter queue. private int _refCount = 1; // Starts with a reference from the counter queue.
private object _lock = new object(); private readonly object _lock = new();
private ulong _result = ulong.MaxValue; private ulong _result = ulong.MaxValue;
private double _divisor = 1f; private double _divisor = 1f;

View File

@@ -20,7 +20,7 @@ namespace Ryujinx.Graphics.OpenGL
{ {
private const int DisposedLiveFrames = 2; private const int DisposedLiveFrames = 2;
private readonly object _lock = new object(); private readonly object _lock = new();
private readonly Dictionary<TextureCreateInfo, List<DisposedTexture>> _textures = new Dictionary<TextureCreateInfo, List<DisposedTexture>>(); private readonly Dictionary<TextureCreateInfo, List<DisposedTexture>> _textures = new Dictionary<TextureCreateInfo, List<DisposedTexture>>();
/// <summary> /// <summary>

View File

@@ -71,40 +71,10 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
context.AppendLine($"const int {DefaultNames.UndefinedName} = 0;"); context.AppendLine($"const int {DefaultNames.UndefinedName} = 0;");
context.AppendLine(); context.AppendLine();
if (context.Config.Stage == ShaderStage.Compute)
{
int localMemorySize = BitUtils.DivRoundUp(context.Config.GpuAccessor.QueryComputeLocalMemorySize(), 4);
if (localMemorySize != 0)
{
string localMemorySizeStr = NumberFormatter.FormatInt(localMemorySize);
context.AppendLine($"uint {DefaultNames.LocalMemoryName}[{localMemorySizeStr}];");
context.AppendLine();
}
int sharedMemorySize = BitUtils.DivRoundUp(context.Config.GpuAccessor.QueryComputeSharedMemorySize(), 4);
if (sharedMemorySize != 0)
{
string sharedMemorySizeStr = NumberFormatter.FormatInt(sharedMemorySize);
context.AppendLine($"shared uint {DefaultNames.SharedMemoryName}[{sharedMemorySizeStr}];");
context.AppendLine();
}
}
else if (context.Config.LocalMemorySize != 0)
{
int localMemorySize = BitUtils.DivRoundUp(context.Config.LocalMemorySize, 4);
string localMemorySizeStr = NumberFormatter.FormatInt(localMemorySize);
context.AppendLine($"uint {DefaultNames.LocalMemoryName}[{localMemorySizeStr}];");
context.AppendLine();
}
DeclareConstantBuffers(context, context.Config.Properties.ConstantBuffers.Values); DeclareConstantBuffers(context, context.Config.Properties.ConstantBuffers.Values);
DeclareStorageBuffers(context, context.Config.Properties.StorageBuffers.Values); DeclareStorageBuffers(context, context.Config.Properties.StorageBuffers.Values);
DeclareMemories(context, context.Config.Properties.LocalMemories.Values, isShared: false);
DeclareMemories(context, context.Config.Properties.SharedMemories.Values, isShared: true);
var textureDescriptors = context.Config.GetTextureDescriptors(); var textureDescriptors = context.Config.GetTextureDescriptors();
if (textureDescriptors.Length != 0) if (textureDescriptors.Length != 0)
@@ -238,11 +208,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
context.AppendLine(); context.AppendLine();
} }
if ((info.HelperFunctionsMask & HelperFunctionsMask.AtomicMinMaxS32Shared) != 0)
{
AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/AtomicMinMaxS32Shared.glsl");
}
if ((info.HelperFunctionsMask & HelperFunctionsMask.MultiplyHighS32) != 0) if ((info.HelperFunctionsMask & HelperFunctionsMask.MultiplyHighS32) != 0)
{ {
AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/MultiplyHighS32.glsl"); AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/MultiplyHighS32.glsl");
@@ -273,11 +238,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleXor.glsl"); AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleXor.glsl");
} }
if ((info.HelperFunctionsMask & HelperFunctionsMask.StoreSharedSmallInt) != 0)
{
AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/StoreSharedSmallInt.glsl");
}
if ((info.HelperFunctionsMask & HelperFunctionsMask.SwizzleAdd) != 0) if ((info.HelperFunctionsMask & HelperFunctionsMask.SwizzleAdd) != 0)
{ {
AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/SwizzleAdd.glsl"); AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/SwizzleAdd.glsl");
@@ -358,7 +318,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
_ => "std430" _ => "std430"
}; };
context.AppendLine($"layout (binding = {buffer.Binding}, {layout}) {declType} _{buffer.Name}"); string set = string.Empty;
if (context.Config.Options.TargetApi == TargetApi.Vulkan)
{
set = $"set = {buffer.Set}, ";
}
context.AppendLine($"layout ({set}binding = {buffer.Binding}, {layout}) {declType} _{buffer.Name}");
context.EnterScope(); context.EnterScope();
foreach (StructureField field in buffer.Type.Fields) foreach (StructureField field in buffer.Type.Fields)
@@ -391,6 +358,27 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
} }
} }
private static void DeclareMemories(CodeGenContext context, IEnumerable<MemoryDefinition> memories, bool isShared)
{
string prefix = isShared ? "shared " : string.Empty;
foreach (MemoryDefinition memory in memories)
{
string typeName = GetVarTypeName(context, memory.Type & ~AggregateType.Array);
if (memory.ArrayLength > 0)
{
string arraySize = memory.ArrayLength.ToString(CultureInfo.InvariantCulture);
context.AppendLine($"{prefix}{typeName} {memory.Name}[{arraySize}];");
}
else
{
context.AppendLine($"{prefix}{typeName} {memory.Name}[];");
}
}
}
private static void DeclareSamplers(CodeGenContext context, TextureDescriptor[] descriptors) private static void DeclareSamplers(CodeGenContext context, TextureDescriptor[] descriptors)
{ {
int arraySize = 0; int arraySize = 0;
@@ -717,7 +705,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
string code = EmbeddedResources.ReadAllText(filename); string code = EmbeddedResources.ReadAllText(filename);
code = code.Replace("\t", CodeGenContext.Tab); code = code.Replace("\t", CodeGenContext.Tab);
code = code.Replace("$SHARED_MEM$", DefaultNames.SharedMemoryName);
if (context.Config.GpuAccessor.QueryHostSupportsShaderBallot()) if (context.Config.GpuAccessor.QueryHostSupportsShaderBallot())
{ {

View File

@@ -11,9 +11,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
public const string IAttributePrefix = "in_attr"; public const string IAttributePrefix = "in_attr";
public const string OAttributePrefix = "out_attr"; public const string OAttributePrefix = "out_attr";
public const string LocalMemoryName = "local_mem";
public const string SharedMemoryName = "shared_mem";
public const string ArgumentNamePrefix = "a"; public const string ArgumentNamePrefix = "a";
public const string UndefinedName = "undef"; public const string UndefinedName = "undef";

View File

@@ -1,21 +0,0 @@
int Helper_AtomicMaxS32(int offset, int value)
{
uint oldValue, newValue;
do
{
oldValue = $SHARED_MEM$[offset];
newValue = uint(max(int(oldValue), value));
} while (atomicCompSwap($SHARED_MEM$[offset], oldValue, newValue) != oldValue);
return int(oldValue);
}
int Helper_AtomicMinS32(int offset, int value)
{
uint oldValue, newValue;
do
{
oldValue = $SHARED_MEM$[offset];
newValue = uint(min(int(oldValue), value));
} while (atomicCompSwap($SHARED_MEM$[offset], oldValue, newValue) != oldValue);
return int(oldValue);
}

View File

@@ -2,9 +2,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
{ {
static class HelperFunctionNames static class HelperFunctionNames
{ {
public static string AtomicMaxS32 = "Helper_AtomicMaxS32";
public static string AtomicMinS32 = "Helper_AtomicMinS32";
public static string MultiplyHighS32 = "Helper_MultiplyHighS32"; public static string MultiplyHighS32 = "Helper_MultiplyHighS32";
public static string MultiplyHighU32 = "Helper_MultiplyHighU32"; public static string MultiplyHighU32 = "Helper_MultiplyHighU32";
@@ -13,10 +10,5 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
public static string ShuffleUp = "Helper_ShuffleUp"; public static string ShuffleUp = "Helper_ShuffleUp";
public static string ShuffleXor = "Helper_ShuffleXor"; public static string ShuffleXor = "Helper_ShuffleXor";
public static string SwizzleAdd = "Helper_SwizzleAdd"; public static string SwizzleAdd = "Helper_SwizzleAdd";
public static string StoreShared16 = "Helper_StoreShared16";
public static string StoreShared8 = "Helper_StoreShared8";
public static string StoreStorage16 = "Helper_StoreStorage16";
public static string StoreStorage8 = "Helper_StoreStorage8";
} }
} }

View File

@@ -1,23 +0,0 @@
void Helper_StoreShared16(int offset, uint value)
{
int wordOffset = offset >> 2;
int bitOffset = (offset & 3) * 8;
uint oldValue, newValue;
do
{
oldValue = $SHARED_MEM$[wordOffset];
newValue = bitfieldInsert(oldValue, value, bitOffset, 16);
} while (atomicCompSwap($SHARED_MEM$[wordOffset], oldValue, newValue) != oldValue);
}
void Helper_StoreShared8(int offset, uint value)
{
int wordOffset = offset >> 2;
int bitOffset = (offset & 3) * 8;
uint oldValue, newValue;
do
{
oldValue = $SHARED_MEM$[wordOffset];
newValue = bitfieldInsert(oldValue, value, bitOffset, 8);
} while (atomicCompSwap($SHARED_MEM$[wordOffset], oldValue, newValue) != oldValue);
}

View File

@@ -68,7 +68,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
string args = string.Empty; string args = string.Empty;
if (atomic && operation.StorageKind == StorageKind.StorageBuffer) if (atomic && (operation.StorageKind == StorageKind.StorageBuffer || operation.StorageKind == StorageKind.SharedMemory))
{ {
args = GenerateLoadOrStore(context, operation, isStore: false); args = GenerateLoadOrStore(context, operation, isStore: false);
@@ -81,23 +81,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
args += ", " + GetSoureExpr(context, operation.GetSource(argIndex), dstType); args += ", " + GetSoureExpr(context, operation.GetSource(argIndex), dstType);
} }
} }
else if (atomic && operation.StorageKind == StorageKind.SharedMemory)
{
args = LoadShared(context, operation);
// For shared memory access, the second argument is unused and should be ignored.
// It is there to make both storage and shared access have the same number of arguments.
// For storage, both inputs are consumed when the argument index is 0, so we should skip it here.
for (int argIndex = 2; argIndex < arity; argIndex++)
{
args += ", ";
AggregateType dstType = GetSrcVarType(inst, argIndex);
args += GetSoureExpr(context, operation.GetSource(argIndex), dstType);
}
}
else else
{ {
for (int argIndex = 0; argIndex < arity; argIndex++) for (int argIndex = 0; argIndex < arity; argIndex++)
@@ -179,12 +162,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
case Instruction.Load: case Instruction.Load:
return Load(context, operation); return Load(context, operation);
case Instruction.LoadLocal:
return LoadLocal(context, operation);
case Instruction.LoadShared:
return LoadShared(context, operation);
case Instruction.Lod: case Instruction.Lod:
return Lod(context, operation); return Lod(context, operation);
@@ -200,18 +177,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
case Instruction.Store: case Instruction.Store:
return Store(context, operation); return Store(context, operation);
case Instruction.StoreLocal:
return StoreLocal(context, operation);
case Instruction.StoreShared:
return StoreShared(context, operation);
case Instruction.StoreShared16:
return StoreShared16(context, operation);
case Instruction.StoreShared8:
return StoreShared8(context, operation);
case Instruction.TextureSample: case Instruction.TextureSample:
return TextureSample(context, operation); return TextureSample(context, operation);

View File

@@ -17,9 +17,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
Add(Instruction.AtomicAdd, InstType.AtomicBinary, "atomicAdd"); Add(Instruction.AtomicAdd, InstType.AtomicBinary, "atomicAdd");
Add(Instruction.AtomicAnd, InstType.AtomicBinary, "atomicAnd"); Add(Instruction.AtomicAnd, InstType.AtomicBinary, "atomicAnd");
Add(Instruction.AtomicCompareAndSwap, InstType.AtomicTernary, "atomicCompSwap"); Add(Instruction.AtomicCompareAndSwap, InstType.AtomicTernary, "atomicCompSwap");
Add(Instruction.AtomicMaxS32, InstType.CallTernary, HelperFunctionNames.AtomicMaxS32);
Add(Instruction.AtomicMaxU32, InstType.AtomicBinary, "atomicMax"); Add(Instruction.AtomicMaxU32, InstType.AtomicBinary, "atomicMax");
Add(Instruction.AtomicMinS32, InstType.CallTernary, HelperFunctionNames.AtomicMinS32);
Add(Instruction.AtomicMinU32, InstType.AtomicBinary, "atomicMin"); Add(Instruction.AtomicMinU32, InstType.AtomicBinary, "atomicMin");
Add(Instruction.AtomicOr, InstType.AtomicBinary, "atomicOr"); Add(Instruction.AtomicOr, InstType.AtomicBinary, "atomicOr");
Add(Instruction.AtomicSwap, InstType.AtomicBinary, "atomicExchange"); Add(Instruction.AtomicSwap, InstType.AtomicBinary, "atomicExchange");
@@ -83,8 +81,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
Add(Instruction.ImageAtomic, InstType.Special); Add(Instruction.ImageAtomic, InstType.Special);
Add(Instruction.IsNan, InstType.CallUnary, "isnan"); Add(Instruction.IsNan, InstType.CallUnary, "isnan");
Add(Instruction.Load, InstType.Special); Add(Instruction.Load, InstType.Special);
Add(Instruction.LoadLocal, InstType.Special);
Add(Instruction.LoadShared, InstType.Special);
Add(Instruction.Lod, InstType.Special); Add(Instruction.Lod, InstType.Special);
Add(Instruction.LogarithmB2, InstType.CallUnary, "log2"); Add(Instruction.LogarithmB2, InstType.CallUnary, "log2");
Add(Instruction.LogicalAnd, InstType.OpBinaryCom, "&&", 9); Add(Instruction.LogicalAnd, InstType.OpBinaryCom, "&&", 9);
@@ -118,10 +114,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
Add(Instruction.Sine, InstType.CallUnary, "sin"); Add(Instruction.Sine, InstType.CallUnary, "sin");
Add(Instruction.SquareRoot, InstType.CallUnary, "sqrt"); Add(Instruction.SquareRoot, InstType.CallUnary, "sqrt");
Add(Instruction.Store, InstType.Special); Add(Instruction.Store, InstType.Special);
Add(Instruction.StoreLocal, InstType.Special);
Add(Instruction.StoreShared, InstType.Special);
Add(Instruction.StoreShared16, InstType.Special);
Add(Instruction.StoreShared8, InstType.Special);
Add(Instruction.Subtract, InstType.OpBinary, "-", 2); Add(Instruction.Subtract, InstType.OpBinary, "-", 2);
Add(Instruction.SwizzleAdd, InstType.CallTernary, HelperFunctionNames.SwizzleAdd); Add(Instruction.SwizzleAdd, InstType.CallTernary, HelperFunctionNames.SwizzleAdd);
Add(Instruction.TextureSample, InstType.Special); Add(Instruction.TextureSample, InstType.Special);

View File

@@ -191,25 +191,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
return GenerateLoadOrStore(context, operation, isStore: false); return GenerateLoadOrStore(context, operation, isStore: false);
} }
public static string LoadLocal(CodeGenContext context, AstOperation operation)
{
return LoadLocalOrShared(context, operation, DefaultNames.LocalMemoryName);
}
public static string LoadShared(CodeGenContext context, AstOperation operation)
{
return LoadLocalOrShared(context, operation, DefaultNames.SharedMemoryName);
}
private static string LoadLocalOrShared(CodeGenContext context, AstOperation operation, string arrayName)
{
IAstNode src1 = operation.GetSource(0);
string offsetExpr = GetSoureExpr(context, src1, GetSrcVarType(operation.Inst, 0));
return $"{arrayName}[{offsetExpr}]";
}
public static string Lod(CodeGenContext context, AstOperation operation) public static string Lod(CodeGenContext context, AstOperation operation)
{ {
AstTextureOperation texOp = (AstTextureOperation)operation; AstTextureOperation texOp = (AstTextureOperation)operation;
@@ -263,58 +244,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
return GenerateLoadOrStore(context, operation, isStore: true); return GenerateLoadOrStore(context, operation, isStore: true);
} }
public static string StoreLocal(CodeGenContext context, AstOperation operation)
{
return StoreLocalOrShared(context, operation, DefaultNames.LocalMemoryName);
}
public static string StoreShared(CodeGenContext context, AstOperation operation)
{
return StoreLocalOrShared(context, operation, DefaultNames.SharedMemoryName);
}
private static string StoreLocalOrShared(CodeGenContext context, AstOperation operation, string arrayName)
{
IAstNode src1 = operation.GetSource(0);
IAstNode src2 = operation.GetSource(1);
string offsetExpr = GetSoureExpr(context, src1, GetSrcVarType(operation.Inst, 0));
AggregateType srcType = OperandManager.GetNodeDestType(context, src2);
string src = TypeConversion.ReinterpretCast(context, src2, srcType, AggregateType.U32);
return $"{arrayName}[{offsetExpr}] = {src}";
}
public static string StoreShared16(CodeGenContext context, AstOperation operation)
{
IAstNode src1 = operation.GetSource(0);
IAstNode src2 = operation.GetSource(1);
string offsetExpr = GetSoureExpr(context, src1, GetSrcVarType(operation.Inst, 0));
AggregateType srcType = OperandManager.GetNodeDestType(context, src2);
string src = TypeConversion.ReinterpretCast(context, src2, srcType, AggregateType.U32);
return $"{HelperFunctionNames.StoreShared16}({offsetExpr}, {src})";
}
public static string StoreShared8(CodeGenContext context, AstOperation operation)
{
IAstNode src1 = operation.GetSource(0);
IAstNode src2 = operation.GetSource(1);
string offsetExpr = GetSoureExpr(context, src1, GetSrcVarType(operation.Inst, 0));
AggregateType srcType = OperandManager.GetNodeDestType(context, src2);
string src = TypeConversion.ReinterpretCast(context, src2, srcType, AggregateType.U32);
return $"{HelperFunctionNames.StoreShared8}({offsetExpr}, {src})";
}
public static string TextureSample(CodeGenContext context, AstOperation operation) public static string TextureSample(CodeGenContext context, AstOperation operation)
{ {
AstTextureOperation texOp = (AstTextureOperation)operation; AstTextureOperation texOp = (AstTextureOperation)operation;
@@ -675,6 +604,21 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
varType = field.Type; varType = field.Type;
break; break;
case StorageKind.LocalMemory:
case StorageKind.SharedMemory:
if (!(operation.GetSource(srcIndex++) is AstOperand bindingId) || bindingId.Type != OperandType.Constant)
{
throw new InvalidOperationException($"First input of {operation.Inst} with {storageKind} storage must be a constant operand.");
}
MemoryDefinition memory = storageKind == StorageKind.LocalMemory
? context.Config.Properties.LocalMemories[bindingId.Value]
: context.Config.Properties.SharedMemories[bindingId.Value];
varName = memory.Name;
varType = memory.Type;
break;
case StorageKind.Input: case StorageKind.Input:
case StorageKind.InputPerPatch: case StorageKind.InputPerPatch:
case StorageKind.Output: case StorageKind.Output:

View File

@@ -113,7 +113,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
if (node is AstOperation operation) if (node is AstOperation operation)
{ {
if (operation.Inst == Instruction.Load) if (operation.Inst == Instruction.Load || operation.Inst.IsAtomic())
{ {
switch (operation.StorageKind) switch (operation.StorageKind)
{ {
@@ -136,6 +136,19 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
return field.Type & AggregateType.ElementTypeMask; return field.Type & AggregateType.ElementTypeMask;
case StorageKind.LocalMemory:
case StorageKind.SharedMemory:
if (!(operation.GetSource(0) is AstOperand bindingId) || bindingId.Type != OperandType.Constant)
{
throw new InvalidOperationException($"First input of {operation.Inst} with {operation.StorageKind} storage must be a constant operand.");
}
MemoryDefinition memory = operation.StorageKind == StorageKind.LocalMemory
? context.Config.Properties.LocalMemories[bindingId.Value]
: context.Config.Properties.SharedMemories[bindingId.Value];
return memory.Type & AggregateType.ElementTypeMask;
case StorageKind.Input: case StorageKind.Input:
case StorageKind.InputPerPatch: case StorageKind.InputPerPatch:
case StorageKind.Output: case StorageKind.Output:

View File

@@ -25,8 +25,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
public Dictionary<int, Instruction> ConstantBuffers { get; } = new Dictionary<int, Instruction>(); public Dictionary<int, Instruction> ConstantBuffers { get; } = new Dictionary<int, Instruction>();
public Dictionary<int, Instruction> StorageBuffers { get; } = new Dictionary<int, Instruction>(); public Dictionary<int, Instruction> StorageBuffers { get; } = new Dictionary<int, Instruction>();
public Instruction LocalMemory { get; set; } public Dictionary<int, Instruction> LocalMemories { get; } = new Dictionary<int, Instruction>();
public Instruction SharedMemory { get; set; } public Dictionary<int, Instruction> SharedMemories { get; } = new Dictionary<int, Instruction>();
public Dictionary<TextureMeta, SamplerType> SamplersTypes { get; } = new Dictionary<TextureMeta, SamplerType>(); public Dictionary<TextureMeta, SamplerType> SamplersTypes { get; } = new Dictionary<TextureMeta, SamplerType>();
public Dictionary<TextureMeta, (Instruction, Instruction, Instruction)> Samplers { get; } = new Dictionary<TextureMeta, (Instruction, Instruction, Instruction)>(); public Dictionary<TextureMeta, (Instruction, Instruction, Instruction)> Samplers { get; } = new Dictionary<TextureMeta, (Instruction, Instruction, Instruction)>();
public Dictionary<TextureMeta, (Instruction, Instruction)> Images { get; } = new Dictionary<TextureMeta, (Instruction, Instruction)>(); public Dictionary<TextureMeta, (Instruction, Instruction)> Images { get; } = new Dictionary<TextureMeta, (Instruction, Instruction)>();
@@ -35,7 +35,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
public Dictionary<IoDefinition, Instruction> InputsPerPatch { get; } = new Dictionary<IoDefinition, Instruction>(); public Dictionary<IoDefinition, Instruction> InputsPerPatch { get; } = new Dictionary<IoDefinition, Instruction>();
public Dictionary<IoDefinition, Instruction> OutputsPerPatch { get; } = new Dictionary<IoDefinition, Instruction>(); public Dictionary<IoDefinition, Instruction> OutputsPerPatch { get; } = new Dictionary<IoDefinition, Instruction>();
public Instruction CoordTemp { get; set; }
public StructuredFunction CurrentFunction { get; set; } public StructuredFunction CurrentFunction { get; set; }
private readonly Dictionary<AstOperand, Instruction> _locals = new Dictionary<AstOperand, Instruction>(); private readonly Dictionary<AstOperand, Instruction> _locals = new Dictionary<AstOperand, Instruction>();
private readonly Dictionary<int, Instruction[]> _localForArgs = new Dictionary<int, Instruction[]>(); private readonly Dictionary<int, Instruction[]> _localForArgs = new Dictionary<int, Instruction[]>();

View File

@@ -6,7 +6,6 @@ using Spv.Generator;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using System.Numerics; using System.Numerics;
using static Spv.Specification; using static Spv.Specification;
using SpvInstruction = Spv.Generator.Instruction; using SpvInstruction = Spv.Generator.Instruction;
@@ -44,13 +43,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
context.AddLocalVariable(spvLocal); context.AddLocalVariable(spvLocal);
context.DeclareLocal(local, spvLocal); context.DeclareLocal(local, spvLocal);
} }
var ivector2Type = context.TypeVector(context.TypeS32(), 2);
var coordTempPointerType = context.TypePointer(StorageClass.Function, ivector2Type);
var coordTemp = context.Variable(coordTempPointerType, StorageClass.Function);
context.AddLocalVariable(coordTemp);
context.CoordTemp = coordTemp;
} }
public static void DeclareLocalForArgs(CodeGenContext context, List<StructuredFunction> functions) public static void DeclareLocalForArgs(CodeGenContext context, List<StructuredFunction> functions)
@@ -77,54 +69,30 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
public static void DeclareAll(CodeGenContext context, StructuredProgramInfo info) public static void DeclareAll(CodeGenContext context, StructuredProgramInfo info)
{ {
if (context.Config.Stage == ShaderStage.Compute)
{
int localMemorySize = BitUtils.DivRoundUp(context.Config.GpuAccessor.QueryComputeLocalMemorySize(), 4);
if (localMemorySize != 0)
{
DeclareLocalMemory(context, localMemorySize);
}
int sharedMemorySize = BitUtils.DivRoundUp(context.Config.GpuAccessor.QueryComputeSharedMemorySize(), 4);
if (sharedMemorySize != 0)
{
DeclareSharedMemory(context, sharedMemorySize);
}
}
else if (context.Config.LocalMemorySize != 0)
{
int localMemorySize = BitUtils.DivRoundUp(context.Config.LocalMemorySize, 4);
DeclareLocalMemory(context, localMemorySize);
}
DeclareConstantBuffers(context, context.Config.Properties.ConstantBuffers.Values); DeclareConstantBuffers(context, context.Config.Properties.ConstantBuffers.Values);
DeclareStorageBuffers(context, context.Config.Properties.StorageBuffers.Values); DeclareStorageBuffers(context, context.Config.Properties.StorageBuffers.Values);
DeclareMemories(context, context.Config.Properties.LocalMemories, context.LocalMemories, StorageClass.Private);
DeclareMemories(context, context.Config.Properties.SharedMemories, context.SharedMemories, StorageClass.Workgroup);
DeclareSamplers(context, context.Config.GetTextureDescriptors()); DeclareSamplers(context, context.Config.GetTextureDescriptors());
DeclareImages(context, context.Config.GetImageDescriptors()); DeclareImages(context, context.Config.GetImageDescriptors());
DeclareInputsAndOutputs(context, info); DeclareInputsAndOutputs(context, info);
} }
private static void DeclareLocalMemory(CodeGenContext context, int size) private static void DeclareMemories(
CodeGenContext context,
IReadOnlyDictionary<int, MemoryDefinition> memories,
Dictionary<int, SpvInstruction> dict,
StorageClass storage)
{ {
context.LocalMemory = DeclareMemory(context, StorageClass.Private, size); foreach ((int id, MemoryDefinition memory) in memories)
} {
var pointerType = context.TypePointer(storage, context.GetType(memory.Type, memory.ArrayLength));
var variable = context.Variable(pointerType, storage);
private static void DeclareSharedMemory(CodeGenContext context, int size) context.AddGlobalVariable(variable);
{
context.SharedMemory = DeclareMemory(context, StorageClass.Workgroup, size);
}
private static SpvInstruction DeclareMemory(CodeGenContext context, StorageClass storage, int size) dict.Add(id, variable);
{ }
var arrayType = context.TypeArray(context.TypeU32(), context.Constant(context.TypeU32(), size));
var pointerType = context.TypePointer(storage, arrayType);
var variable = context.Variable(pointerType, storage);
context.AddGlobalVariable(variable);
return variable;
} }
private static void DeclareConstantBuffers(CodeGenContext context, IEnumerable<BufferDefinition> buffers) private static void DeclareConstantBuffers(CodeGenContext context, IEnumerable<BufferDefinition> buffers)

View File

@@ -97,8 +97,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
Add(Instruction.ImageStore, GenerateImageStore); Add(Instruction.ImageStore, GenerateImageStore);
Add(Instruction.IsNan, GenerateIsNan); Add(Instruction.IsNan, GenerateIsNan);
Add(Instruction.Load, GenerateLoad); Add(Instruction.Load, GenerateLoad);
Add(Instruction.LoadLocal, GenerateLoadLocal);
Add(Instruction.LoadShared, GenerateLoadShared);
Add(Instruction.Lod, GenerateLod); Add(Instruction.Lod, GenerateLod);
Add(Instruction.LogarithmB2, GenerateLogarithmB2); Add(Instruction.LogarithmB2, GenerateLogarithmB2);
Add(Instruction.LogicalAnd, GenerateLogicalAnd); Add(Instruction.LogicalAnd, GenerateLogicalAnd);
@@ -132,10 +130,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
Add(Instruction.Sine, GenerateSine); Add(Instruction.Sine, GenerateSine);
Add(Instruction.SquareRoot, GenerateSquareRoot); Add(Instruction.SquareRoot, GenerateSquareRoot);
Add(Instruction.Store, GenerateStore); Add(Instruction.Store, GenerateStore);
Add(Instruction.StoreLocal, GenerateStoreLocal);
Add(Instruction.StoreShared, GenerateStoreShared);
Add(Instruction.StoreShared16, GenerateStoreShared16);
Add(Instruction.StoreShared8, GenerateStoreShared8);
Add(Instruction.Subtract, GenerateSubtract); Add(Instruction.Subtract, GenerateSubtract);
Add(Instruction.SwizzleAdd, GenerateSwizzleAdd); Add(Instruction.SwizzleAdd, GenerateSwizzleAdd);
Add(Instruction.TextureSample, GenerateTextureSample); Add(Instruction.TextureSample, GenerateTextureSample);
@@ -871,30 +865,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
return GenerateLoadOrStore(context, operation, isStore: false); return GenerateLoadOrStore(context, operation, isStore: false);
} }
private static OperationResult GenerateLoadLocal(CodeGenContext context, AstOperation operation)
{
return GenerateLoadLocalOrShared(context, operation, StorageClass.Private, context.LocalMemory);
}
private static OperationResult GenerateLoadShared(CodeGenContext context, AstOperation operation)
{
return GenerateLoadLocalOrShared(context, operation, StorageClass.Workgroup, context.SharedMemory);
}
private static OperationResult GenerateLoadLocalOrShared(
CodeGenContext context,
AstOperation operation,
StorageClass storageClass,
SpvInstruction memory)
{
var offset = context.Get(AggregateType.S32, operation.GetSource(0));
var elemPointer = context.AccessChain(context.TypePointer(storageClass, context.TypeU32()), memory, offset);
var value = context.Load(context.TypeU32(), elemPointer);
return new OperationResult(AggregateType.U32, value);
}
private static OperationResult GenerateLod(CodeGenContext context, AstOperation operation) private static OperationResult GenerateLod(CodeGenContext context, AstOperation operation)
{ {
AstTextureOperation texOp = (AstTextureOperation)operation; AstTextureOperation texOp = (AstTextureOperation)operation;
@@ -1268,45 +1238,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
return GenerateLoadOrStore(context, operation, isStore: true); return GenerateLoadOrStore(context, operation, isStore: true);
} }
private static OperationResult GenerateStoreLocal(CodeGenContext context, AstOperation operation)
{
return GenerateStoreLocalOrShared(context, operation, StorageClass.Private, context.LocalMemory);
}
private static OperationResult GenerateStoreShared(CodeGenContext context, AstOperation operation)
{
return GenerateStoreLocalOrShared(context, operation, StorageClass.Workgroup, context.SharedMemory);
}
private static OperationResult GenerateStoreLocalOrShared(
CodeGenContext context,
AstOperation operation,
StorageClass storageClass,
SpvInstruction memory)
{
var offset = context.Get(AggregateType.S32, operation.GetSource(0));
var value = context.Get(AggregateType.U32, operation.GetSource(1));
var elemPointer = context.AccessChain(context.TypePointer(storageClass, context.TypeU32()), memory, offset);
context.Store(elemPointer, value);
return OperationResult.Invalid;
}
private static OperationResult GenerateStoreShared16(CodeGenContext context, AstOperation operation)
{
GenerateStoreSharedSmallInt(context, operation, 16);
return OperationResult.Invalid;
}
private static OperationResult GenerateStoreShared8(CodeGenContext context, AstOperation operation)
{
GenerateStoreSharedSmallInt(context, operation, 8);
return OperationResult.Invalid;
}
private static OperationResult GenerateSubtract(CodeGenContext context, AstOperation operation) private static OperationResult GenerateSubtract(CodeGenContext context, AstOperation operation)
{ {
return GenerateBinary(context, operation, context.Delegates.FSub, context.Delegates.ISub); return GenerateBinary(context, operation, context.Delegates.FSub, context.Delegates.ISub);
@@ -1827,55 +1758,27 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
AstOperation operation, AstOperation operation,
Func<SpvInstruction, SpvInstruction, SpvInstruction, SpvInstruction, SpvInstruction, SpvInstruction> emitU) Func<SpvInstruction, SpvInstruction, SpvInstruction, SpvInstruction, SpvInstruction, SpvInstruction> emitU)
{ {
var value = context.GetU32(operation.GetSource(operation.SourcesCount - 1)); SpvInstruction elemPointer = GetStoragePointer(context, operation, out AggregateType varType);
SpvInstruction elemPointer; var value = context.Get(varType, operation.GetSource(operation.SourcesCount - 1));
if (operation.StorageKind == StorageKind.StorageBuffer)
{
elemPointer = GetStoragePointer(context, operation, out _);
}
else if (operation.StorageKind == StorageKind.SharedMemory)
{
var offset = context.GetU32(operation.GetSource(0));
elemPointer = context.AccessChain(context.TypePointer(StorageClass.Workgroup, context.TypeU32()), context.SharedMemory, offset);
}
else
{
throw new InvalidOperationException($"Invalid storage kind \"{operation.StorageKind}\".");
}
var one = context.Constant(context.TypeU32(), 1); var one = context.Constant(context.TypeU32(), 1);
var zero = context.Constant(context.TypeU32(), 0); var zero = context.Constant(context.TypeU32(), 0);
return new OperationResult(AggregateType.U32, emitU(context.TypeU32(), elemPointer, one, zero, value)); return new OperationResult(varType, emitU(context.GetType(varType), elemPointer, one, zero, value));
} }
private static OperationResult GenerateAtomicMemoryCas(CodeGenContext context, AstOperation operation) private static OperationResult GenerateAtomicMemoryCas(CodeGenContext context, AstOperation operation)
{ {
var value0 = context.GetU32(operation.GetSource(operation.SourcesCount - 2)); SpvInstruction elemPointer = GetStoragePointer(context, operation, out AggregateType varType);
var value1 = context.GetU32(operation.GetSource(operation.SourcesCount - 1));
SpvInstruction elemPointer; var value0 = context.Get(varType, operation.GetSource(operation.SourcesCount - 2));
var value1 = context.Get(varType, operation.GetSource(operation.SourcesCount - 1));
if (operation.StorageKind == StorageKind.StorageBuffer)
{
elemPointer = GetStoragePointer(context, operation, out _);
}
else if (operation.StorageKind == StorageKind.SharedMemory)
{
var offset = context.GetU32(operation.GetSource(0));
elemPointer = context.AccessChain(context.TypePointer(StorageClass.Workgroup, context.TypeU32()), context.SharedMemory, offset);
}
else
{
throw new InvalidOperationException($"Invalid storage kind \"{operation.StorageKind}\".");
}
var one = context.Constant(context.TypeU32(), 1); var one = context.Constant(context.TypeU32(), 1);
var zero = context.Constant(context.TypeU32(), 0); var zero = context.Constant(context.TypeU32(), 0);
return new OperationResult(AggregateType.U32, context.AtomicCompareExchange(context.TypeU32(), elemPointer, one, zero, zero, value1, value0)); return new OperationResult(varType, context.AtomicCompareExchange(context.GetType(varType), elemPointer, one, zero, zero, value1, value0));
} }
private static OperationResult GenerateLoadOrStore(CodeGenContext context, AstOperation operation, bool isStore) private static OperationResult GenerateLoadOrStore(CodeGenContext context, AstOperation operation, bool isStore)
@@ -1928,6 +1831,27 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
: context.StorageBuffers[bindingIndex.Value]; : context.StorageBuffers[bindingIndex.Value];
break; break;
case StorageKind.LocalMemory:
case StorageKind.SharedMemory:
if (!(operation.GetSource(srcIndex++) is AstOperand bindingId) || bindingId.Type != OperandType.Constant)
{
throw new InvalidOperationException($"First input of {operation.Inst} with {storageKind} storage must be a constant operand.");
}
if (storageKind == StorageKind.LocalMemory)
{
storageClass = StorageClass.Private;
varType = context.Config.Properties.LocalMemories[bindingId.Value].Type & AggregateType.ElementTypeMask;
baseObj = context.LocalMemories[bindingId.Value];
}
else
{
storageClass = StorageClass.Workgroup;
varType = context.Config.Properties.SharedMemories[bindingId.Value].Type & AggregateType.ElementTypeMask;
baseObj = context.SharedMemories[bindingId.Value];
}
break;
case StorageKind.Input: case StorageKind.Input:
case StorageKind.InputPerPatch: case StorageKind.InputPerPatch:
case StorageKind.Output: case StorageKind.Output:
@@ -2048,50 +1972,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
return context.Load(context.GetType(varType), context.Inputs[ioDefinition]); return context.Load(context.GetType(varType), context.Inputs[ioDefinition]);
} }
private static void GenerateStoreSharedSmallInt(CodeGenContext context, AstOperation operation, int bitSize)
{
var offset = context.Get(AggregateType.U32, operation.GetSource(0));
var value = context.Get(AggregateType.U32, operation.GetSource(1));
var wordOffset = context.ShiftRightLogical(context.TypeU32(), offset, context.Constant(context.TypeU32(), 2));
var bitOffset = context.BitwiseAnd(context.TypeU32(), offset, context.Constant(context.TypeU32(), 3));
bitOffset = context.ShiftLeftLogical(context.TypeU32(), bitOffset, context.Constant(context.TypeU32(), 3));
var memory = context.SharedMemory;
var elemPointer = context.AccessChain(context.TypePointer(StorageClass.Workgroup, context.TypeU32()), memory, wordOffset);
GenerateStoreSmallInt(context, elemPointer, bitOffset, value, bitSize);
}
private static void GenerateStoreSmallInt(
CodeGenContext context,
SpvInstruction elemPointer,
SpvInstruction bitOffset,
SpvInstruction value,
int bitSize)
{
var loopStart = context.Label();
var loopEnd = context.Label();
context.Branch(loopStart);
context.AddLabel(loopStart);
var oldValue = context.Load(context.TypeU32(), elemPointer);
var newValue = context.BitFieldInsert(context.TypeU32(), oldValue, value, bitOffset, context.Constant(context.TypeU32(), bitSize));
var one = context.Constant(context.TypeU32(), 1);
var zero = context.Constant(context.TypeU32(), 0);
var result = context.AtomicCompareExchange(context.TypeU32(), elemPointer, one, zero, zero, newValue, oldValue);
var failed = context.INotEqual(context.TypeBool(), result, oldValue);
context.LoopMerge(loopEnd, loopStart, LoopControlMask.MaskNone);
context.BranchConditional(failed, loopStart, loopEnd);
context.AddLabel(loopEnd);
}
private static OperationResult GetZeroOperationResult( private static OperationResult GetZeroOperationResult(
CodeGenContext context, CodeGenContext context,
AstTextureOperation texOp, AstTextureOperation texOp,

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

@@ -10,12 +10,6 @@ namespace Ryujinx.Graphics.Shader.Instructions
{ {
static partial class InstEmit static partial class InstEmit
{ {
private enum MemoryRegion
{
Local,
Shared
}
public static void Atom(EmitterContext context) public static void Atom(EmitterContext context)
{ {
InstAtom op = context.GetOp<InstAtom>(); InstAtom op = context.GetOp<InstAtom>();
@@ -33,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));
@@ -51,7 +51,8 @@ namespace Ryujinx.Graphics.Shader.Instructions
_ => AtomSize.U32 _ => AtomSize.U32
}; };
Operand res = EmitAtomicOp(context, StorageKind.SharedMemory, op.AtomOp, size, offset, Const(0), value); Operand id = Const(context.Config.ResourceManager.SharedMemoryId);
Operand res = EmitAtomicOp(context, StorageKind.SharedMemory, op.AtomOp, size, id, offset, value);
context.Copy(GetDest(op.Dest), res); context.Copy(GetDest(op.Dest), res);
} }
@@ -114,14 +115,20 @@ namespace Ryujinx.Graphics.Shader.Instructions
{ {
InstLdl op = context.GetOp<InstLdl>(); InstLdl op = context.GetOp<InstLdl>();
EmitLoad(context, MemoryRegion.Local, op.LsSize, GetSrcReg(context, op.SrcA), op.Dest, Imm24ToSInt(op.Imm24)); EmitLoad(context, StorageKind.LocalMemory, op.LsSize, GetSrcReg(context, op.SrcA), op.Dest, Imm24ToSInt(op.Imm24));
} }
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, MemoryRegion.Shared, 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));
} }
public static void Red(EmitterContext context) public static void Red(EmitterContext context)
@@ -144,14 +151,20 @@ namespace Ryujinx.Graphics.Shader.Instructions
{ {
InstStl op = context.GetOp<InstStl>(); InstStl op = context.GetOp<InstStl>();
EmitStore(context, MemoryRegion.Local, op.LsSize, GetSrcReg(context, op.SrcA), op.Dest, Imm24ToSInt(op.Imm24)); EmitStore(context, StorageKind.LocalMemory, op.LsSize, GetSrcReg(context, op.SrcA), op.Dest, Imm24ToSInt(op.Imm24));
} }
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, MemoryRegion.Shared, 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));
} }
private static Operand EmitLoadConstant(EmitterContext context, Operand slot, Operand offset) private static Operand EmitLoadConstant(EmitterContext context, Operand slot, Operand offset)
@@ -192,8 +205,8 @@ namespace Ryujinx.Graphics.Shader.Instructions
StorageKind storageKind, StorageKind storageKind,
AtomOp op, AtomOp op,
AtomSize type, AtomSize type,
Operand addrLow, Operand e0,
Operand addrHigh, Operand e1,
Operand value) Operand value)
{ {
Operand res = Const(0); Operand res = Const(0);
@@ -203,7 +216,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
case AtomOp.Add: case AtomOp.Add:
if (type == AtomSize.S32 || type == AtomSize.U32) if (type == AtomSize.S32 || type == AtomSize.U32)
{ {
res = context.AtomicAdd(storageKind, addrLow, addrHigh, value); res = context.AtomicAdd(storageKind, e0, e1, value);
} }
else else
{ {
@@ -213,7 +226,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
case AtomOp.And: case AtomOp.And:
if (type == AtomSize.S32 || type == AtomSize.U32) if (type == AtomSize.S32 || type == AtomSize.U32)
{ {
res = context.AtomicAnd(storageKind, addrLow, addrHigh, value); res = context.AtomicAnd(storageKind, e0, e1, value);
} }
else else
{ {
@@ -223,7 +236,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
case AtomOp.Xor: case AtomOp.Xor:
if (type == AtomSize.S32 || type == AtomSize.U32) if (type == AtomSize.S32 || type == AtomSize.U32)
{ {
res = context.AtomicXor(storageKind, addrLow, addrHigh, value); res = context.AtomicXor(storageKind, e0, e1, value);
} }
else else
{ {
@@ -233,7 +246,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
case AtomOp.Or: case AtomOp.Or:
if (type == AtomSize.S32 || type == AtomSize.U32) if (type == AtomSize.S32 || type == AtomSize.U32)
{ {
res = context.AtomicOr(storageKind, addrLow, addrHigh, value); res = context.AtomicOr(storageKind, e0, e1, value);
} }
else else
{ {
@@ -243,11 +256,11 @@ namespace Ryujinx.Graphics.Shader.Instructions
case AtomOp.Max: case AtomOp.Max:
if (type == AtomSize.S32) if (type == AtomSize.S32)
{ {
res = context.AtomicMaxS32(storageKind, addrLow, addrHigh, value); res = context.AtomicMaxS32(storageKind, e0, e1, value);
} }
else if (type == AtomSize.U32) else if (type == AtomSize.U32)
{ {
res = context.AtomicMaxU32(storageKind, addrLow, addrHigh, value); res = context.AtomicMaxU32(storageKind, e0, e1, value);
} }
else else
{ {
@@ -257,11 +270,11 @@ namespace Ryujinx.Graphics.Shader.Instructions
case AtomOp.Min: case AtomOp.Min:
if (type == AtomSize.S32) if (type == AtomSize.S32)
{ {
res = context.AtomicMinS32(storageKind, addrLow, addrHigh, value); res = context.AtomicMinS32(storageKind, e0, e1, value);
} }
else if (type == AtomSize.U32) else if (type == AtomSize.U32)
{ {
res = context.AtomicMinU32(storageKind, addrLow, addrHigh, value); res = context.AtomicMinU32(storageKind, e0, e1, value);
} }
else else
{ {
@@ -275,7 +288,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
private static void EmitLoad( private static void EmitLoad(
EmitterContext context, EmitterContext context,
MemoryRegion region, StorageKind storageKind,
LsSize2 size, LsSize2 size,
Operand srcA, Operand srcA,
int rd, int rd,
@@ -287,19 +300,19 @@ namespace Ryujinx.Graphics.Shader.Instructions
return; return;
} }
int id = storageKind == StorageKind.LocalMemory
? context.Config.ResourceManager.LocalMemoryId
: context.Config.ResourceManager.SharedMemoryId;
bool isSmallInt = size < LsSize2.B32; bool isSmallInt = size < LsSize2.B32;
int count = 1; int count = size switch
switch (size)
{ {
case LsSize2.B64: count = 2; break; LsSize2.B64 => 2,
case LsSize2.B128: count = 4; break; LsSize2.B128 => 4,
} _ => 1
};
Operand baseOffset = context.IAdd(srcA, Const(offset)); Operand baseOffset = context.Copy(srcA);
Operand wordOffset = context.ShiftRightU32(baseOffset, Const(2)); // Word offset = byte offset / 4 (one word = 4 bytes).
Operand bitOffset = GetBitOffset(context, baseOffset);
for (int index = 0; index < count; index++) for (int index = 0; index < count; index++)
{ {
@@ -310,14 +323,10 @@ namespace Ryujinx.Graphics.Shader.Instructions
break; break;
} }
Operand elemOffset = context.IAdd(wordOffset, Const(index)); Operand byteOffset = context.IAdd(baseOffset, Const(offset + index * 4));
Operand value = null; Operand wordOffset = context.ShiftRightU32(byteOffset, Const(2)); // Word offset = byte offset / 4 (one word = 4 bytes).
Operand bitOffset = GetBitOffset(context, byteOffset);
switch (region) Operand value = context.Load(storageKind, id, wordOffset);
{
case MemoryRegion.Local: value = context.LoadLocal(elemOffset); break;
case MemoryRegion.Shared: value = context.LoadShared(elemOffset); break;
}
if (isSmallInt) if (isSmallInt)
{ {
@@ -360,7 +369,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
private static void EmitStore( private static void EmitStore(
EmitterContext context, EmitterContext context,
MemoryRegion region, StorageKind storageKind,
LsSize2 size, LsSize2 size,
Operand srcA, Operand srcA,
int rd, int rd,
@@ -372,52 +381,54 @@ namespace Ryujinx.Graphics.Shader.Instructions
return; return;
} }
int id = storageKind == StorageKind.LocalMemory
? context.Config.ResourceManager.LocalMemoryId
: context.Config.ResourceManager.SharedMemoryId;
bool isSmallInt = size < LsSize2.B32; bool isSmallInt = size < LsSize2.B32;
int count = 1; int count = size switch
switch (size)
{ {
case LsSize2.B64: count = 2; break; LsSize2.B64 => 2,
case LsSize2.B128: count = 4; break; LsSize2.B128 => 4,
} _ => 1
};
Operand baseOffset = context.IAdd(srcA, Const(offset)); Operand baseOffset = context.Copy(srcA);
Operand wordOffset = context.ShiftRightU32(baseOffset, Const(2));
Operand bitOffset = GetBitOffset(context, baseOffset);
for (int index = 0; index < count; index++) for (int index = 0; index < count; index++)
{ {
bool isRz = rd + index >= RegisterConsts.RegisterZeroIndex; bool isRz = rd + index >= RegisterConsts.RegisterZeroIndex;
Operand value = Register(isRz ? rd : rd + index, RegisterType.Gpr); Operand value = Register(isRz ? rd : rd + index, RegisterType.Gpr);
Operand elemOffset = context.IAdd(wordOffset, Const(index)); Operand byteOffset = context.IAdd(baseOffset, Const(offset + index * 4));
Operand wordOffset = context.ShiftRightU32(byteOffset, Const(2));
Operand bitOffset = GetBitOffset(context, byteOffset);
if (isSmallInt && region == MemoryRegion.Local) if (isSmallInt && storageKind == StorageKind.LocalMemory)
{ {
Operand word = context.LoadLocal(elemOffset); Operand word = context.Load(storageKind, id, wordOffset);
value = InsertSmallInt(context, (LsSize)size, bitOffset, word, value); value = InsertSmallInt(context, (LsSize)size, bitOffset, word, value);
} }
if (region == MemoryRegion.Local) if (storageKind == StorageKind.LocalMemory)
{ {
context.StoreLocal(elemOffset, value); context.Store(storageKind, id, wordOffset, value);
} }
else if (region == MemoryRegion.Shared) else if (storageKind == StorageKind.SharedMemory)
{ {
switch (size) switch (size)
{ {
case LsSize2.U8: case LsSize2.U8:
case LsSize2.S8: case LsSize2.S8:
context.StoreShared8(baseOffset, value); context.Store(StorageKind.SharedMemory8, id, byteOffset, value);
break; break;
case LsSize2.U16: case LsSize2.U16:
case LsSize2.S16: case LsSize2.S16:
context.StoreShared16(baseOffset, value); context.Store(StorageKind.SharedMemory16, id, byteOffset, value);
break; break;
default: default:
context.StoreShared(elemOffset, value); context.Store(storageKind, id, wordOffset, value);
break; break;
} }
} }

View File

@@ -79,8 +79,6 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
ImageAtomic, ImageAtomic,
IsNan, IsNan,
Load, Load,
LoadLocal,
LoadShared,
Lod, Lod,
LogarithmB2, LogarithmB2,
LogicalAnd, LogicalAnd,
@@ -115,10 +113,6 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
Sine, Sine,
SquareRoot, SquareRoot,
Store, Store,
StoreLocal,
StoreShared,
StoreShared16,
StoreShared8,
Subtract, Subtract,
SwizzleAdd, SwizzleAdd,
TextureSample, TextureSample,

View File

@@ -11,12 +11,13 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
StorageBuffer, StorageBuffer,
LocalMemory, LocalMemory,
SharedMemory, SharedMemory,
SharedMemory8, // TODO: Remove this and store type as a field on the Operation class itself.
SharedMemory16, // TODO: Remove this and store type as a field on the Operation class itself.
GlobalMemory, GlobalMemory,
// TODO: Remove those and store type as a field on the Operation class itself. GlobalMemoryS8, // TODO: Remove this and store type as a field on the Operation class itself.
GlobalMemoryS8, GlobalMemoryS16, // TODO: Remove this and store type as a field on the Operation class itself.
GlobalMemoryS16, GlobalMemoryU8, // TODO: Remove this and store type as a field on the Operation class itself.
GlobalMemoryU8, GlobalMemoryU16 // TODO: Remove this and store type as a field on the Operation class itself.
GlobalMemoryU16
} }
static class StorageKindExtensions static class StorageKindExtensions

View File

@@ -10,14 +10,12 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\AtomicMinMaxS32Shared.glsl" />
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\MultiplyHighS32.glsl" /> <EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\MultiplyHighS32.glsl" />
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\MultiplyHighU32.glsl" /> <EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\MultiplyHighU32.glsl" />
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\Shuffle.glsl" /> <EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\Shuffle.glsl" />
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\ShuffleDown.glsl" /> <EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\ShuffleDown.glsl" />
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\ShuffleUp.glsl" /> <EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\ShuffleUp.glsl" />
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\ShuffleXor.glsl" /> <EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\ShuffleXor.glsl" />
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\StoreSharedSmallInt.glsl" />
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\SwizzleAdd.glsl" /> <EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\SwizzleAdd.glsl" />
</ItemGroup> </ItemGroup>

View File

@@ -5,15 +5,13 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
[Flags] [Flags]
enum HelperFunctionsMask enum HelperFunctionsMask
{ {
AtomicMinMaxS32Shared = 1 << 0, MultiplyHighS32 = 1 << 2,
MultiplyHighS32 = 1 << 2, MultiplyHighU32 = 1 << 3,
MultiplyHighU32 = 1 << 3, Shuffle = 1 << 4,
Shuffle = 1 << 4, ShuffleDown = 1 << 5,
ShuffleDown = 1 << 5, ShuffleUp = 1 << 6,
ShuffleUp = 1 << 6, ShuffleXor = 1 << 7,
ShuffleXor = 1 << 7, SwizzleAdd = 1 << 10,
StoreSharedSmallInt = 1 << 8, FSI = 1 << 11
SwizzleAdd = 1 << 10,
FSI = 1 << 11
} }
} }

View File

@@ -90,8 +90,6 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
Add(Instruction.ImageAtomic, AggregateType.S32); Add(Instruction.ImageAtomic, AggregateType.S32);
Add(Instruction.IsNan, AggregateType.Bool, AggregateType.Scalar); Add(Instruction.IsNan, AggregateType.Bool, AggregateType.Scalar);
Add(Instruction.Load, AggregateType.FP32); Add(Instruction.Load, AggregateType.FP32);
Add(Instruction.LoadLocal, AggregateType.U32, AggregateType.S32);
Add(Instruction.LoadShared, AggregateType.U32, AggregateType.S32);
Add(Instruction.Lod, AggregateType.FP32); Add(Instruction.Lod, AggregateType.FP32);
Add(Instruction.LogarithmB2, AggregateType.Scalar, AggregateType.Scalar); Add(Instruction.LogarithmB2, AggregateType.Scalar, AggregateType.Scalar);
Add(Instruction.LogicalAnd, AggregateType.Bool, AggregateType.Bool, AggregateType.Bool); Add(Instruction.LogicalAnd, AggregateType.Bool, AggregateType.Bool, AggregateType.Bool);
@@ -121,10 +119,6 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
Add(Instruction.Sine, AggregateType.Scalar, AggregateType.Scalar); Add(Instruction.Sine, AggregateType.Scalar, AggregateType.Scalar);
Add(Instruction.SquareRoot, AggregateType.Scalar, AggregateType.Scalar); Add(Instruction.SquareRoot, AggregateType.Scalar, AggregateType.Scalar);
Add(Instruction.Store, AggregateType.Void); Add(Instruction.Store, AggregateType.Void);
Add(Instruction.StoreLocal, AggregateType.Void, AggregateType.S32, AggregateType.U32);
Add(Instruction.StoreShared, AggregateType.Void, AggregateType.S32, AggregateType.U32);
Add(Instruction.StoreShared16, AggregateType.Void, AggregateType.S32, AggregateType.U32);
Add(Instruction.StoreShared8, AggregateType.Void, AggregateType.S32, AggregateType.U32);
Add(Instruction.Subtract, AggregateType.Scalar, AggregateType.Scalar, AggregateType.Scalar); Add(Instruction.Subtract, AggregateType.Scalar, AggregateType.Scalar, AggregateType.Scalar);
Add(Instruction.SwizzleAdd, AggregateType.FP32, AggregateType.FP32, AggregateType.FP32, AggregateType.S32); Add(Instruction.SwizzleAdd, AggregateType.FP32, AggregateType.FP32, AggregateType.FP32, AggregateType.S32);
Add(Instruction.TextureSample, AggregateType.FP32); Add(Instruction.TextureSample, AggregateType.FP32);

View File

@@ -0,0 +1,18 @@
using Ryujinx.Graphics.Shader.Translation;
namespace Ryujinx.Graphics.Shader.StructuredIr
{
readonly struct MemoryDefinition
{
public string Name { get; }
public AggregateType Type { get; }
public int ArrayLength { get; }
public MemoryDefinition(string name, AggregateType type, int arrayLength = 1)
{
Name = name;
Type = type;
ArrayLength = arrayLength;
}
}
}

View File

@@ -6,14 +6,20 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
{ {
private readonly Dictionary<int, BufferDefinition> _constantBuffers; private readonly Dictionary<int, BufferDefinition> _constantBuffers;
private readonly Dictionary<int, BufferDefinition> _storageBuffers; private readonly Dictionary<int, BufferDefinition> _storageBuffers;
private readonly Dictionary<int, MemoryDefinition> _localMemories;
private readonly Dictionary<int, MemoryDefinition> _sharedMemories;
public IReadOnlyDictionary<int, BufferDefinition> ConstantBuffers => _constantBuffers; public IReadOnlyDictionary<int, BufferDefinition> ConstantBuffers => _constantBuffers;
public IReadOnlyDictionary<int, BufferDefinition> StorageBuffers => _storageBuffers; public IReadOnlyDictionary<int, BufferDefinition> StorageBuffers => _storageBuffers;
public IReadOnlyDictionary<int, MemoryDefinition> LocalMemories => _localMemories;
public IReadOnlyDictionary<int, MemoryDefinition> SharedMemories => _sharedMemories;
public ShaderProperties() public ShaderProperties()
{ {
_constantBuffers = new Dictionary<int, BufferDefinition>(); _constantBuffers = new Dictionary<int, BufferDefinition>();
_storageBuffers = new Dictionary<int, BufferDefinition>(); _storageBuffers = new Dictionary<int, BufferDefinition>();
_localMemories = new Dictionary<int, MemoryDefinition>();
_sharedMemories = new Dictionary<int, MemoryDefinition>();
} }
public void AddConstantBuffer(int binding, BufferDefinition definition) public void AddConstantBuffer(int binding, BufferDefinition definition)
@@ -25,5 +31,21 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
{ {
_storageBuffers[binding] = definition; _storageBuffers[binding] = definition;
} }
public int AddLocalMemory(MemoryDefinition definition)
{
int id = _localMemories.Count;
_localMemories.Add(id, definition);
return id;
}
public int AddSharedMemory(MemoryDefinition definition)
{
int id = _sharedMemories.Count;
_sharedMemories.Add(id, definition);
return id;
}
} }
} }

View File

@@ -274,13 +274,6 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
// decide which helper functions are needed on the final generated code. // decide which helper functions are needed on the final generated code.
switch (operation.Inst) switch (operation.Inst)
{ {
case Instruction.AtomicMaxS32:
case Instruction.AtomicMinS32:
if (operation.StorageKind == StorageKind.SharedMemory)
{
context.Info.HelperFunctionsMask |= HelperFunctionsMask.AtomicMinMaxS32Shared;
}
break;
case Instruction.MultiplyHighS32: case Instruction.MultiplyHighS32:
context.Info.HelperFunctionsMask |= HelperFunctionsMask.MultiplyHighS32; context.Info.HelperFunctionsMask |= HelperFunctionsMask.MultiplyHighS32;
break; break;
@@ -299,10 +292,6 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
case Instruction.ShuffleXor: case Instruction.ShuffleXor:
context.Info.HelperFunctionsMask |= HelperFunctionsMask.ShuffleXor; context.Info.HelperFunctionsMask |= HelperFunctionsMask.ShuffleXor;
break; break;
case Instruction.StoreShared16:
case Instruction.StoreShared8:
context.Info.HelperFunctionsMask |= HelperFunctionsMask.StoreSharedSmallInt;
break;
case Instruction.SwizzleAdd: case Instruction.SwizzleAdd:
context.Info.HelperFunctionsMask |= HelperFunctionsMask.SwizzleAdd; context.Info.HelperFunctionsMask |= HelperFunctionsMask.SwizzleAdd;
break; break;

View File

@@ -67,6 +67,11 @@ namespace Ryujinx.Graphics.Shader.Translation
return context.Add(Instruction.AtomicAnd, storageKind, Local(), Const(binding), e0, e1, value); return context.Add(Instruction.AtomicAnd, storageKind, Local(), Const(binding), e0, e1, value);
} }
public static Operand AtomicCompareAndSwap(this EmitterContext context, StorageKind storageKind, int binding, Operand e0, Operand compare, Operand value)
{
return context.Add(Instruction.AtomicCompareAndSwap, storageKind, Local(), Const(binding), e0, compare, value);
}
public static Operand AtomicCompareAndSwap(this EmitterContext context, StorageKind storageKind, int binding, Operand e0, Operand e1, Operand compare, Operand value) public static Operand AtomicCompareAndSwap(this EmitterContext context, StorageKind storageKind, int binding, Operand e0, Operand e1, Operand compare, Operand value)
{ {
return context.Add(Instruction.AtomicCompareAndSwap, storageKind, Local(), Const(binding), e0, e1, compare, value); return context.Add(Instruction.AtomicCompareAndSwap, storageKind, Local(), Const(binding), e0, e1, compare, value);
@@ -661,16 +666,6 @@ namespace Ryujinx.Graphics.Shader.Translation
: context.Load(storageKind, (int)ioVariable, arrayIndex, elemIndex); : context.Load(storageKind, (int)ioVariable, arrayIndex, elemIndex);
} }
public static Operand LoadLocal(this EmitterContext context, Operand a)
{
return context.Add(Instruction.LoadLocal, Local(), a);
}
public static Operand LoadShared(this EmitterContext context, Operand a)
{
return context.Add(Instruction.LoadShared, Local(), a);
}
public static Operand MemoryBarrier(this EmitterContext context) public static Operand MemoryBarrier(this EmitterContext context)
{ {
return context.Add(Instruction.MemoryBarrier); return context.Add(Instruction.MemoryBarrier);
@@ -753,6 +748,11 @@ namespace Ryujinx.Graphics.Shader.Translation
return context.Add(Instruction.Store, storageKind, null, e0, e1, value); return context.Add(Instruction.Store, storageKind, null, e0, e1, value);
} }
public static Operand Store(this EmitterContext context, StorageKind storageKind, int binding, Operand e0, Operand value)
{
return context.Add(Instruction.Store, storageKind, null, Const(binding), e0, value);
}
public static Operand Store(this EmitterContext context, StorageKind storageKind, int binding, Operand e0, Operand e1, Operand value) public static Operand Store(this EmitterContext context, StorageKind storageKind, int binding, Operand e0, Operand e1, Operand value)
{ {
return context.Add(Instruction.Store, storageKind, null, Const(binding), e0, e1, value); return context.Add(Instruction.Store, storageKind, null, Const(binding), e0, e1, value);
@@ -797,26 +797,6 @@ namespace Ryujinx.Graphics.Shader.Translation
: context.Add(Instruction.Store, storageKind, null, Const((int)ioVariable), arrayIndex, elemIndex, value); : context.Add(Instruction.Store, storageKind, null, Const((int)ioVariable), arrayIndex, elemIndex, value);
} }
public static Operand StoreLocal(this EmitterContext context, Operand a, Operand b)
{
return context.Add(Instruction.StoreLocal, null, a, b);
}
public static Operand StoreShared(this EmitterContext context, Operand a, Operand b)
{
return context.Add(Instruction.StoreShared, null, a, b);
}
public static Operand StoreShared16(this EmitterContext context, Operand a, Operand b)
{
return context.Add(Instruction.StoreShared16, null, a, b);
}
public static Operand StoreShared8(this EmitterContext context, Operand a, Operand b)
{
return context.Add(Instruction.StoreShared8, null, a, b);
}
public static Operand UnpackDouble2x32High(this EmitterContext context, Operand a) public static Operand UnpackDouble2x32High(this EmitterContext context, Operand a)
{ {
return UnpackDouble2x32(context, a, 1); return UnpackDouble2x32(context, a, 1);

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

@@ -9,13 +9,13 @@ namespace Ryujinx.Graphics.Shader.Translation
class HelperFunctionManager class HelperFunctionManager
{ {
private readonly List<Function> _functionList; private readonly List<Function> _functionList;
private readonly Dictionary<HelperFunctionName, int> _functionIds; private readonly Dictionary<int, int> _functionIds;
private readonly ShaderStage _stage; private readonly ShaderStage _stage;
public HelperFunctionManager(List<Function> functionList, ShaderStage stage) public HelperFunctionManager(List<Function> functionList, ShaderStage stage)
{ {
_functionList = functionList; _functionList = functionList;
_functionIds = new Dictionary<HelperFunctionName, int>(); _functionIds = new Dictionary<int, int>();
_stage = stage; _stage = stage;
} }
@@ -29,14 +29,30 @@ namespace Ryujinx.Graphics.Shader.Translation
public int GetOrCreateFunctionId(HelperFunctionName functionName) public int GetOrCreateFunctionId(HelperFunctionName functionName)
{ {
if (_functionIds.TryGetValue(functionName, out int functionId)) if (_functionIds.TryGetValue((int)functionName, out int functionId))
{ {
return functionId; return functionId;
} }
Function function = GenerateFunction(functionName); Function function = GenerateFunction(functionName);
functionId = AddFunction(function); functionId = AddFunction(function);
_functionIds.Add(functionName, functionId); _functionIds.Add((int)functionName, functionId);
return functionId;
}
public int GetOrCreateFunctionId(HelperFunctionName functionName, int id)
{
int key = (int)functionName | (id << 16);
if (_functionIds.TryGetValue(key, out int functionId))
{
return functionId;
}
Function function = GenerateFunction(functionName, id);
functionId = AddFunction(function);
_functionIds.Add(key, functionId);
return functionId; return functionId;
} }
@@ -140,6 +156,67 @@ namespace Ryujinx.Graphics.Shader.Translation
return new Function(ControlFlowGraph.Create(context.GetOperations()).Blocks, "ConvertFloatToDouble", false, 1, 2); return new Function(ControlFlowGraph.Create(context.GetOperations()).Blocks, "ConvertFloatToDouble", false, 1, 2);
} }
private static Function GenerateFunction(HelperFunctionName functionName, int id)
{
return functionName switch
{
HelperFunctionName.SharedAtomicMaxS32 => GenerateSharedAtomicSigned(id, isMin: false),
HelperFunctionName.SharedAtomicMinS32 => GenerateSharedAtomicSigned(id, isMin: true),
HelperFunctionName.SharedStore8 => GenerateSharedStore8(id),
HelperFunctionName.SharedStore16 => GenerateSharedStore16(id),
_ => throw new ArgumentException($"Invalid function name {functionName}")
};
}
private static Function GenerateSharedAtomicSigned(int id, bool isMin)
{
EmitterContext context = new EmitterContext();
Operand wordOffset = Argument(0);
Operand value = Argument(1);
Operand result = GenerateSharedAtomicCasLoop(context, wordOffset, id, (memValue) =>
{
return isMin
? context.IMinimumS32(memValue, value)
: context.IMaximumS32(memValue, value);
});
context.Return(result);
return new Function(ControlFlowGraph.Create(context.GetOperations()).Blocks, $"SharedAtomic{(isMin ? "Min" : "Max")}_{id}", true, 2, 0);
}
private static Function GenerateSharedStore8(int id)
{
return GenerateSharedStore(id, 8);
}
private static Function GenerateSharedStore16(int id)
{
return GenerateSharedStore(id, 16);
}
private static Function GenerateSharedStore(int id, int bitSize)
{
EmitterContext context = new EmitterContext();
Operand offset = Argument(0);
Operand value = Argument(1);
Operand wordOffset = context.ShiftRightU32(offset, Const(2));
Operand bitOffset = GetBitOffset(context, offset);
GenerateSharedAtomicCasLoop(context, wordOffset, id, (memValue) =>
{
return context.BitfieldInsert(memValue, value, bitOffset, Const(bitSize));
});
context.Return();
return new Function(ControlFlowGraph.Create(context.GetOperations()).Blocks, $"SharedStore{bitSize}_{id}", false, 2, 0);
}
private Function GenerateTexelFetchScaleFunction() private Function GenerateTexelFetchScaleFunction()
{ {
EmitterContext context = new EmitterContext(); EmitterContext context = new EmitterContext();
@@ -226,5 +303,29 @@ namespace Ryujinx.Graphics.Shader.Translation
return context.IAdd(Const(1), index); return context.IAdd(Const(1), index);
} }
} }
public static Operand GetBitOffset(EmitterContext context, Operand offset)
{
return context.ShiftLeft(context.BitwiseAnd(offset, Const(3)), Const(3));
}
private static Operand GenerateSharedAtomicCasLoop(EmitterContext context, Operand wordOffset, int id, Func<Operand, Operand> opCallback)
{
Operand lblLoopHead = Label();
context.MarkLabel(lblLoopHead);
Operand oldValue = context.Load(StorageKind.SharedMemory, id, wordOffset);
Operand newValue = opCallback(oldValue);
Operand casResult = context.AtomicCompareAndSwap(StorageKind.SharedMemory, id, wordOffset, oldValue, newValue);
Operand casFail = context.ICompareNotEqual(casResult, oldValue);
context.BranchIfTrue(lblLoopHead, casFail);
return oldValue;
}
} }
} }

View File

@@ -4,6 +4,10 @@ namespace Ryujinx.Graphics.Shader.Translation
{ {
ConvertDoubleToFloat, ConvertDoubleToFloat,
ConvertFloatToDouble, ConvertFloatToDouble,
SharedAtomicMaxS32,
SharedAtomicMinS32,
SharedStore8,
SharedStore16,
TexelFetchScale, TexelFetchScale,
TextureSizeUnscale TextureSizeUnscale
} }

View File

@@ -244,7 +244,9 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
node = nextNode; node = nextNode;
} }
} }
else if (operation.Inst == Instruction.StoreShared || operation.Inst == Instruction.StoreLocal) else if (operation.Inst == Instruction.Store &&
(operation.StorageKind == StorageKind.SharedMemory ||
operation.StorageKind == StorageKind.LocalMemory))
{ {
// The NVIDIA compiler can sometimes use shared or local memory as temporary // The NVIDIA compiler can sometimes use shared or local memory as temporary
// storage to place the base address and size on, so we need // storage to place the base address and size on, so we need
@@ -874,7 +876,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
if (bitSize < 32) if (bitSize < 32)
{ {
Operand bitOffset = GetBitOffset(context, offset); Operand bitOffset = HelperFunctionManager.GetBitOffset(context, offset);
GenerateAtomicCasLoop(context, wordOffset, binding, (memValue) => GenerateAtomicCasLoop(context, wordOffset, binding, (memValue) =>
{ {
@@ -892,7 +894,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
if (IsSmallInt(storageKind)) if (IsSmallInt(storageKind))
{ {
Operand bitOffset = GetBitOffset(context, offset); Operand bitOffset = HelperFunctionManager.GetBitOffset(context, offset);
switch (storageKind) switch (storageKind)
{ {
@@ -921,11 +923,6 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
return true; return true;
} }
private static Operand GetBitOffset(EmitterContext context, Operand offset)
{
return context.ShiftLeft(context.BitwiseAnd(offset, Const(3)), Const(3));
}
private static Operand GenerateAtomicCasLoop(EmitterContext context, Operand wordOffset, int binding, Func<Operand, Operand> opCallback) private static Operand GenerateAtomicCasLoop(EmitterContext context, Operand wordOffset, int binding, Func<Operand, Operand> opCallback)
{ {
Operand lblLoopHead = Label(); Operand lblLoopHead = Label();
@@ -1070,15 +1067,18 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
{ {
baseOffset = null; baseOffset = null;
if (operation.Inst == Instruction.LoadShared || operation.Inst == Instruction.StoreShared) if (operation.Inst == Instruction.Load || operation.Inst == Instruction.Store)
{ {
type = LsMemoryType.Shared; if (operation.StorageKind == StorageKind.SharedMemory)
return TryGetSharedMemoryOffsets(operation, out baseOffset, out constOffset); {
} type = LsMemoryType.Shared;
else if (operation.Inst == Instruction.LoadLocal || operation.Inst == Instruction.StoreLocal) return TryGetSharedMemoryOffsets(operation, out baseOffset, out constOffset);
{ }
type = LsMemoryType.Local; else if (operation.StorageKind == StorageKind.LocalMemory)
return TryGetLocalMemoryOffset(operation, out constOffset); {
type = LsMemoryType.Local;
return TryGetLocalMemoryOffset(operation, out constOffset);
}
} }
type = default; type = default;

View File

@@ -1,3 +1,4 @@
using Ryujinx.Common;
using Ryujinx.Graphics.Shader.StructuredIr; using Ryujinx.Graphics.Shader.StructuredIr;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -7,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;
@@ -22,6 +28,9 @@ namespace Ryujinx.Graphics.Shader.Translation
private readonly HashSet<int> _usedConstantBufferBindings; private readonly HashSet<int> _usedConstantBufferBindings;
public int LocalMemoryId { get; private set; }
public int SharedMemoryId { get; private set; }
public ShaderProperties Properties => _properties; public ShaderProperties Properties => _properties;
public ResourceManager(ShaderStage stage, IGpuAccessor gpuAccessor, ShaderProperties properties) public ResourceManager(ShaderStage stage, IGpuAccessor gpuAccessor, ShaderProperties properties)
@@ -41,6 +50,47 @@ namespace Ryujinx.Graphics.Shader.Translation
_usedConstantBufferBindings = new HashSet<int>(); _usedConstantBufferBindings = new HashSet<int>();
properties.AddConstantBuffer(0, new BufferDefinition(BufferLayout.Std140, 0, 0, "support_buffer", SupportBuffer.GetStructureType())); properties.AddConstantBuffer(0, new BufferDefinition(BufferLayout.Std140, 0, 0, "support_buffer", SupportBuffer.GetStructureType()));
LocalMemoryId = -1;
SharedMemoryId = -1;
}
public void SetCurrentLocalMemory(int size, bool isUsed)
{
if (isUsed)
{
if (size <= 0)
{
size = DefaultLocalMemorySize;
}
var lmem = new MemoryDefinition("local_memory", AggregateType.Array | AggregateType.U32, BitUtils.DivRoundUp(size, sizeof(uint)));
LocalMemoryId = Properties.AddLocalMemory(lmem);
}
else
{
LocalMemoryId = -1;
}
}
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;
}
} }
public int GetConstantBufferBinding(int slot) public int GetConstantBufferBinding(int slot)

View File

@@ -1,6 +1,8 @@
using Ryujinx.Graphics.Shader.IntermediateRepresentation; using Ryujinx.Graphics.Shader.IntermediateRepresentation;
using Ryujinx.Graphics.Shader.StructuredIr; using Ryujinx.Graphics.Shader.StructuredIr;
using Ryujinx.Graphics.Shader.Translation.Optimizations;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
@@ -70,6 +72,15 @@ namespace Ryujinx.Graphics.Shader.Translation
} }
} }
} }
else
{
node = InsertSharedStoreSmallInt(hfm, node);
if (config.Options.TargetLanguage != TargetLanguage.Spirv)
{
node = InsertSharedAtomicSigned(hfm, node);
}
}
} }
} }
} }
@@ -171,6 +182,87 @@ namespace Ryujinx.Graphics.Shader.Translation
operation.TurnIntoCopy(result); operation.TurnIntoCopy(result);
} }
private static LinkedListNode<INode> InsertSharedStoreSmallInt(HelperFunctionManager hfm, LinkedListNode<INode> node)
{
Operation operation = (Operation)node.Value;
HelperFunctionName name;
if (operation.StorageKind == StorageKind.SharedMemory8)
{
name = HelperFunctionName.SharedStore8;
}
else if (operation.StorageKind == StorageKind.SharedMemory16)
{
name = HelperFunctionName.SharedStore16;
}
else
{
return node;
}
if (operation.Inst != Instruction.Store)
{
return node;
}
Operand memoryId = operation.GetSource(0);
Operand byteOffset = operation.GetSource(1);
Operand value = operation.GetSource(2);
Debug.Assert(memoryId.Type == OperandType.Constant);
int functionId = hfm.GetOrCreateFunctionId(name, memoryId.Value);
Operand[] callArgs = new Operand[] { Const(functionId), byteOffset, value };
LinkedListNode<INode> newNode = node.List.AddBefore(node, new Operation(Instruction.Call, 0, (Operand)null, callArgs));
Utils.DeleteNode(node, operation);
return newNode;
}
private static LinkedListNode<INode> InsertSharedAtomicSigned(HelperFunctionManager hfm, LinkedListNode<INode> node)
{
Operation operation = (Operation)node.Value;
HelperFunctionName name;
if (operation.Inst == Instruction.AtomicMaxS32)
{
name = HelperFunctionName.SharedAtomicMaxS32;
}
else if (operation.Inst == Instruction.AtomicMinS32)
{
name = HelperFunctionName.SharedAtomicMinS32;
}
else
{
return node;
}
if (operation.StorageKind != StorageKind.SharedMemory)
{
return node;
}
Operand result = operation.Dest;
Operand memoryId = operation.GetSource(0);
Operand byteOffset = operation.GetSource(1);
Operand value = operation.GetSource(2);
Debug.Assert(memoryId.Type == OperandType.Constant);
int functionId = hfm.GetOrCreateFunctionId(name, memoryId.Value);
Operand[] callArgs = new Operand[] { Const(functionId), byteOffset, value };
LinkedListNode<INode> newNode = node.List.AddBefore(node, new Operation(Instruction.Call, 0, result, callArgs));
Utils.DeleteNode(node, operation);
return newNode;
}
private static LinkedListNode<INode> InsertTexelFetchScale(HelperFunctionManager hfm, LinkedListNode<INode> node, ShaderConfig config) private static LinkedListNode<INode> InsertTexelFetchScale(HelperFunctionManager hfm, LinkedListNode<INode> node, ShaderConfig config)
{ {
TextureOperation texOp = (TextureOperation)node.Value; TextureOperation texOp = (TextureOperation)node.Value;

View File

@@ -124,11 +124,12 @@ namespace Ryujinx.Graphics.Shader.Translation
private TextureDescriptor[] _cachedTextureDescriptors; private TextureDescriptor[] _cachedTextureDescriptors;
private TextureDescriptor[] _cachedImageDescriptors; private TextureDescriptor[] _cachedImageDescriptors;
public ShaderConfig(ShaderStage stage, IGpuAccessor gpuAccessor, TranslationOptions options) 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>();
@@ -176,20 +177,22 @@ namespace Ryujinx.Graphics.Shader.Translation
OutputTopology outputTopology, OutputTopology outputTopology,
int maxOutputVertices, int maxOutputVertices,
IGpuAccessor gpuAccessor, IGpuAccessor gpuAccessor,
TranslationOptions options) : this(stage, gpuAccessor, options) TranslationOptions options) : this(stage, gpuAccessor, options, 0)
{ {
ThreadsPerInputPrimitive = 1; ThreadsPerInputPrimitive = 1;
OutputTopology = outputTopology; OutputTopology = outputTopology;
MaxOutputVertices = maxOutputVertices; MaxOutputVertices = maxOutputVertices;
} }
public ShaderConfig(ShaderHeader header, IGpuAccessor gpuAccessor, TranslationOptions options) : this(header.Stage, gpuAccessor, options) public ShaderConfig(
ShaderHeader header,
IGpuAccessor gpuAccessor,
TranslationOptions options) : this(header.Stage, gpuAccessor, options, GetLocalMemorySize(header))
{ {
GpPassthrough = header.Stage == ShaderStage.Geometry && header.GpPassthrough; GpPassthrough = header.Stage == ShaderStage.Geometry && header.GpPassthrough;
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;
@@ -197,6 +200,11 @@ namespace Ryujinx.Graphics.Shader.Translation
LastInVertexPipeline = header.Stage < ShaderStage.Fragment; LastInVertexPipeline = header.Stage < ShaderStage.Fragment;
} }
private static int GetLocalMemorySize(ShaderHeader header)
{
return header.ShaderLocalMemoryLowSize + header.ShaderLocalMemoryHighSize + (header.ShaderLocalMemoryCrsSize / ThreadsPerWarp);
}
private void EnsureTransformFeedbackInitialized() private void EnsureTransformFeedbackInitialized()
{ {
if (HasTransformFeedbackOutputs() && _transformFeedbackOutputs == null) if (HasTransformFeedbackOutputs() && _transformFeedbackOutputs == null)

View File

@@ -107,7 +107,7 @@ namespace Ryujinx.Graphics.Shader.Translation
if (options.Flags.HasFlag(TranslationFlags.Compute)) if (options.Flags.HasFlag(TranslationFlags.Compute))
{ {
config = new ShaderConfig(ShaderStage.Compute, gpuAccessor, options); config = new ShaderConfig(ShaderStage.Compute, gpuAccessor, options, gpuAccessor.QueryComputeLocalMemorySize());
program = Decoder.Decode(config, address); program = Decoder.Decode(config, address);
} }
@@ -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

@@ -3,7 +3,7 @@ using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Vulkan.MoltenVK namespace Ryujinx.Graphics.Vulkan.MoltenVK
{ {
enum MVKConfigLogLevel : int enum MVKConfigLogLevel
{ {
None = 0, None = 0,
Error = 1, Error = 1,
@@ -12,7 +12,7 @@ namespace Ryujinx.Graphics.Vulkan.MoltenVK
Debug = 4 Debug = 4
} }
enum MVKConfigTraceVulkanCalls : int enum MVKConfigTraceVulkanCalls
{ {
None = 0, None = 0,
Enter = 1, Enter = 1,
@@ -20,7 +20,7 @@ namespace Ryujinx.Graphics.Vulkan.MoltenVK
Duration = 3 Duration = 3
} }
enum MVKConfigAutoGPUCaptureScope : int enum MVKConfigAutoGPUCaptureScope
{ {
None = 0, None = 0,
Device = 1, Device = 1,
@@ -28,7 +28,7 @@ namespace Ryujinx.Graphics.Vulkan.MoltenVK
} }
[Flags] [Flags]
enum MVKConfigAdvertiseExtensions : int enum MVKConfigAdvertiseExtensions
{ {
All = 0x00000001, All = 0x00000001,
MoltenVK = 0x00000002, MoltenVK = 0x00000002,
@@ -36,7 +36,7 @@ namespace Ryujinx.Graphics.Vulkan.MoltenVK
Portability = 0x00000008 Portability = 0x00000008
} }
enum MVKVkSemaphoreSupportStyle : int enum MVKVkSemaphoreSupportStyle
{ {
MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE = 0, MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE = 0,
MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_METAL_EVENTS_WHERE_SAFE = 1, MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_METAL_EVENTS_WHERE_SAFE = 1,

View File

@@ -24,7 +24,7 @@ namespace Ryujinx.Graphics.Vulkan.Queries
private ulong _accumulatedCounter; private ulong _accumulatedCounter;
private int _waiterCount; private int _waiterCount;
private object _lock = new object(); private readonly object _lock = new();
private Queue<BufferedQuery> _queryPool; private Queue<BufferedQuery> _queryPool;
private AutoResetEvent _queuedEvent = new AutoResetEvent(false); private AutoResetEvent _queuedEvent = new AutoResetEvent(false);

View File

@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Vulkan.Queries
private bool _hostAccessReserved = false; private bool _hostAccessReserved = false;
private int _refCount = 1; // Starts with a reference from the counter queue. private int _refCount = 1; // Starts with a reference from the counter queue.
private object _lock = new object(); private readonly object _lock = new();
private ulong _result = ulong.MaxValue; private ulong _result = ulong.MaxValue;
private double _divisor = 1f; private double _divisor = 1f;

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

@@ -60,7 +60,7 @@ namespace Ryujinx.HLE.HOS.Applets
private bool _canAcceptController = false; private bool _canAcceptController = false;
private KeyboardInputMode _inputMode = KeyboardInputMode.ControllerAndKeyboard; private KeyboardInputMode _inputMode = KeyboardInputMode.ControllerAndKeyboard;
private object _lock = new object(); private readonly object _lock = new();
public event EventHandler AppletStateChanged; public event EventHandler AppletStateChanged;

View File

@@ -13,7 +13,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
private const int TextBoxBlinkSleepMilliseconds = 100; private const int TextBoxBlinkSleepMilliseconds = 100;
private const int RendererWaitTimeoutMilliseconds = 100; private const int RendererWaitTimeoutMilliseconds = 100;
private readonly object _stateLock = new object(); private readonly object _stateLock = new();
private SoftwareKeyboardUiState _state = new SoftwareKeyboardUiState(); private SoftwareKeyboardUiState _state = new SoftwareKeyboardUiState();
private SoftwareKeyboardRendererBase _renderer; private SoftwareKeyboardRendererBase _renderer;

View File

@@ -26,7 +26,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
const string CancelText = "Cancel"; const string CancelText = "Cancel";
const string ControllerToggleText = "Toggle input"; const string ControllerToggleText = "Toggle input";
private readonly object _bufferLock = new object(); private readonly object _bufferLock = new();
private RenderingSurfaceInfo _surfaceInfo = null; private RenderingSurfaceInfo _surfaceInfo = null;
private Image<Argb32> _surface = null; private Image<Argb32> _surface = null;
@@ -311,7 +311,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
private static RectangleF MeasureString(ReadOnlySpan<char> text, Font font) private static RectangleF MeasureString(ReadOnlySpan<char> text, Font font)
{ {
RendererOptions options = new RendererOptions(font); RendererOptions options = new RendererOptions(font);
if (text == "") if (text == "")
{ {
FontRectangle emptyRectangle = TextMeasurer.Measure(" ", options); FontRectangle emptyRectangle = TextMeasurer.Measure(" ", options);

View File

@@ -26,8 +26,8 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
} }
private TRef<bool> _cancelled = null; private TRef<bool> _cancelled = null;
private Thread _thread = null; private Thread _thread = null;
private object _lock = new object(); private readonly object _lock = new();
public bool IsRunning public bool IsRunning
{ {

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

@@ -40,8 +40,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
public ProcessState State { get; private set; } public ProcessState State { get; private set; }
private object _processLock; private readonly object _processLock = new();
private object _threadingLock; private readonly object _threadingLock = new();
public KAddressArbiter AddressArbiter { get; private set; } public KAddressArbiter AddressArbiter { get; private set; }
@@ -94,9 +94,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
public KProcess(KernelContext context, bool allowCodeMemoryForJit = false) : base(context) public KProcess(KernelContext context, bool allowCodeMemoryForJit = false) : base(context)
{ {
_processLock = new object();
_threadingLock = new object();
AddressArbiter = new KAddressArbiter(context); AddressArbiter = new KAddressArbiter(context);
_fullTlsPages = new SortedDictionary<ulong, KTlsPageInfo>(); _fullTlsPages = new SortedDictionary<ulong, KTlsPageInfo>();
@@ -1085,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

@@ -112,7 +112,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
public bool WaitingInArbitration { get; set; } public bool WaitingInArbitration { get; set; }
private object _activityOperationLock; private readonly object _activityOperationLock = new();
public KThread(KernelContext context) : base(context) public KThread(KernelContext context) : base(context)
{ {
@@ -123,8 +123,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
_mutexWaiters = new LinkedList<KThread>(); _mutexWaiters = new LinkedList<KThread>();
_pinnedWaiters = new LinkedList<KThread>(); _pinnedWaiters = new LinkedList<KThread>();
_activityOperationLock = new object();
} }
public Result Initialize( public Result Initialize(

View File

@@ -17,8 +17,8 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
private KEvent _accumulatedSuspendedTickChangedEvent; private KEvent _accumulatedSuspendedTickChangedEvent;
private int _accumulatedSuspendedTickChangedEventHandle; private int _accumulatedSuspendedTickChangedEventHandle;
private object _fatalSectionLock = new object(); private readonly object _fatalSectionLock = new();
private int _fatalSectionCount; private int _fatalSectionCount;
// TODO: Set this when the game goes in suspension (go back to home menu ect), we currently don't support that so we can keep it set to 0. // TODO: Set this when the game goes in suspension (go back to home menu ect), we currently don't support that so we can keep it set to 0.
private ulong _accumulatedSuspendedTickValue = 0; private ulong _accumulatedSuspendedTickValue = 0;
@@ -429,4 +429,4 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
return ResultCode.Success; return ResultCode.Success;
} }
} }
} }

View File

@@ -14,7 +14,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
private readonly UserId _userId; private readonly UserId _userId;
private readonly FriendServicePermissionLevel _permissionLevel; private readonly FriendServicePermissionLevel _permissionLevel;
private readonly object _lock = new object(); private readonly object _lock = new();
private KEvent _notificationEvent; private KEvent _notificationEvent;
private int _notificationEventHandle = 0; private int _notificationEventHandle = 0;

View File

@@ -3,7 +3,7 @@ using System;
namespace Ryujinx.HLE.HOS.Services.Hid namespace Ryujinx.HLE.HOS.Services.Hid
{ {
[Flags] [Flags]
public enum ControllerType : int public enum ControllerType
{ {
None, None,
ProController = 1 << 0, ProController = 1 << 0,

View File

@@ -1,6 +1,6 @@
namespace Ryujinx.HLE.HOS.Services.Hid namespace Ryujinx.HLE.HOS.Services.Hid
{ {
public enum NpadIdType : int public enum NpadIdType
{ {
Player1 = 0, Player1 = 0,
Player2 = 1, Player2 = 1,

View File

@@ -1,6 +1,6 @@
namespace Ryujinx.HLE.HOS.Services.Hid namespace Ryujinx.HLE.HOS.Services.Hid
{ {
public enum PlayerIndex : int public enum PlayerIndex
{ {
Player1 = 0, Player1 = 0,
Player2 = 1, Player2 = 1,

View File

@@ -3,7 +3,7 @@
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad
{ {
[Flags] [Flags]
enum DeviceType : int enum DeviceType
{ {
None = 0, None = 0,

View File

@@ -1,6 +1,6 @@
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad
{ {
enum NpadBatteryLevel : int enum NpadBatteryLevel
{ {
Percent0, Percent0,
Percent25, Percent25,

View File

@@ -775,7 +775,7 @@ namespace Ryujinx.HLE.HOS.Services.Mii.Types
private static ReadOnlySpan<ElementInfo> ElementInfos => MemoryMarshal.Cast<byte, ElementInfo>(ElementInfoArray); private static ReadOnlySpan<ElementInfo> ElementInfos => MemoryMarshal.Cast<byte, ElementInfo>(ElementInfoArray);
private enum ElementInfoIndex : int private enum ElementInfoIndex
{ {
HairType, HairType,
Height, Height,

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