Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
bf96bc84a8 | |||
91e4caaa69 | |||
efbd29463d | |||
7608cb37ab | |||
d604e98227 | |||
58907e2c29 | |||
649d372f7d | |||
f9a538bb0f | |||
f92921a6d1 | |||
32d21ddf17 | |||
82f90704a0 | |||
f978d3726a | |||
6f28c4abad |
@ -46,7 +46,7 @@
|
||||
<PackageVersion Include="System.Drawing.Common" Version="7.0.0" />
|
||||
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.31.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="XamlNameReferenceGenerator" Version="1.6.1" />
|
||||
</ItemGroup>
|
||||
|
@ -13,7 +13,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
enum OpCode32SimdSelMode : int
|
||||
enum OpCode32SimdSelMode
|
||||
{
|
||||
Eq = 0,
|
||||
Vs,
|
||||
|
@ -78,7 +78,7 @@ namespace ARMeilleure.Signal
|
||||
private static IntPtr _signalHandlerPtr;
|
||||
private static IntPtr _signalHandlerHandle;
|
||||
|
||||
private static readonly object _lock = new object();
|
||||
private static readonly object _lock = new();
|
||||
private static bool _initialized;
|
||||
|
||||
static NativeSignalHandler()
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace ARMeilleure.State
|
||||
{
|
||||
enum ExecutionMode : int
|
||||
enum ExecutionMode
|
||||
{
|
||||
Aarch32Arm = 0,
|
||||
Aarch32Thumb = 1,
|
||||
|
@ -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
|
||||
// APIs. This also means that one should be careful when changing the layout of this struct.
|
||||
|
||||
private ulong _e0;
|
||||
private ulong _e1;
|
||||
private readonly ulong _e0;
|
||||
private readonly ulong _e1;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a new <see cref="V128"/> with all bits set to zero.
|
||||
|
@ -2,6 +2,7 @@ using ARMeilleure.CodeGen;
|
||||
using ARMeilleure.CodeGen.Unwinding;
|
||||
using ARMeilleure.Memory;
|
||||
using ARMeilleure.Native;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
@ -12,8 +13,8 @@ namespace ARMeilleure.Translation.Cache
|
||||
{
|
||||
static partial class JitCache
|
||||
{
|
||||
private const int PageSize = 4 * 1024;
|
||||
private const int PageMask = PageSize - 1;
|
||||
private static readonly int PageSize = (int)MemoryBlock.GetPageSize();
|
||||
private static readonly int PageMask = PageSize - 1;
|
||||
|
||||
private const int CodeAlignment = 4; // Bytes.
|
||||
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 object _lock = new object();
|
||||
private static readonly object _lock = new();
|
||||
private static bool _initialized;
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
|
@ -17,7 +17,7 @@ namespace Ryujinx.Audio.Backends.OpenAL
|
||||
private Queue<OpenALAudioBuffer> _queuedBuffers;
|
||||
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)
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.Audio.Backends.SoundIo.Native
|
||||
{
|
||||
public enum SoundIoBackend : int
|
||||
public enum SoundIoBackend
|
||||
{
|
||||
None = 0,
|
||||
Jack = 1,
|
||||
|
@ -11,7 +11,7 @@ namespace Ryujinx.Audio
|
||||
/// <summary>
|
||||
/// Lock used to control the waiters registration.
|
||||
/// </summary>
|
||||
private object _lock = new object();
|
||||
private readonly object _lock = new();
|
||||
|
||||
/// <summary>
|
||||
/// Events signaled when the driver played audio buffers.
|
||||
|
@ -10,7 +10,7 @@ namespace Ryujinx.Audio.Backends.Common
|
||||
{
|
||||
private const int RingBufferAlignment = 2048;
|
||||
|
||||
private object _lock = new object();
|
||||
private readonly object _lock = new();
|
||||
|
||||
private byte[] _buffer;
|
||||
private int _size;
|
||||
|
@ -14,12 +14,12 @@ namespace Ryujinx.Audio.Input
|
||||
/// </summary>
|
||||
public class AudioInputManager : IDisposable
|
||||
{
|
||||
private object _lock = new object();
|
||||
private readonly object _lock = new();
|
||||
|
||||
/// <summary>
|
||||
/// Lock used for session allocation.
|
||||
/// </summary>
|
||||
private object _sessionLock = new object();
|
||||
private readonly object _sessionLock = new();
|
||||
|
||||
/// <summary>
|
||||
/// The session ids allocation table.
|
||||
|
@ -48,7 +48,7 @@ namespace Ryujinx.Audio.Input
|
||||
/// <summary>
|
||||
/// The lock of the parent.
|
||||
/// </summary>
|
||||
private object _parentLock;
|
||||
private readonly object _parentLock;
|
||||
|
||||
/// <summary>
|
||||
/// The dispose state.
|
||||
|
@ -14,12 +14,12 @@ namespace Ryujinx.Audio.Output
|
||||
/// </summary>
|
||||
public class AudioOutputManager : IDisposable
|
||||
{
|
||||
private object _lock = new object();
|
||||
private readonly object _lock = new();
|
||||
|
||||
/// <summary>
|
||||
/// Lock used for session allocation.
|
||||
/// </summary>
|
||||
private object _sessionLock = new object();
|
||||
private readonly object _sessionLock = new();
|
||||
|
||||
/// <summary>
|
||||
/// The session ids allocation table.
|
||||
|
@ -48,7 +48,7 @@ namespace Ryujinx.Audio.Output
|
||||
/// <summary>
|
||||
/// THe lock of the parent.
|
||||
/// </summary>
|
||||
private object _parentLock;
|
||||
private readonly object _parentLock;
|
||||
|
||||
/// <summary>
|
||||
/// The dispose state.
|
||||
|
@ -26,7 +26,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
public class AudioRenderSystem : IDisposable
|
||||
{
|
||||
private object _lock = new object();
|
||||
private readonly object _lock = new();
|
||||
|
||||
private AudioRendererRenderingDevice _renderingDevice;
|
||||
private AudioRendererExecutionMode _executionMode;
|
||||
|
@ -19,12 +19,12 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
/// <summary>
|
||||
/// Lock used for session allocation.
|
||||
/// </summary>
|
||||
private object _sessionLock = new object();
|
||||
private readonly object _sessionLock = new();
|
||||
|
||||
/// <summary>
|
||||
/// Lock used to control the <see cref="AudioProcessor"/> running state.
|
||||
/// </summary>
|
||||
private object _audioProcessorLock = new object();
|
||||
private readonly object _audioProcessorLock = new();
|
||||
|
||||
/// <summary>
|
||||
/// The session ids allocation table.
|
||||
|
@ -16,7 +16,7 @@ namespace Ryujinx.Audio.Renderer.Server.Upsampler
|
||||
/// <summary>
|
||||
/// Global lock of the object.
|
||||
/// </summary>
|
||||
private object Lock = new object();
|
||||
private readonly object Lock = new();
|
||||
|
||||
/// <summary>
|
||||
/// The upsamplers instances.
|
||||
|
@ -264,7 +264,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
private void SelectLastScannedAmiibo()
|
||||
{
|
||||
AmiiboApi scanned = _amiiboList.FirstOrDefault(amiibo => amiibo.GetId() == LastScannedAmiiboId);
|
||||
AmiiboApi scanned = _amiiboList.Find(amiibo => amiibo.GetId() == LastScannedAmiiboId);
|
||||
|
||||
SeriesSelectedIndex = AmiiboSeries.IndexOf(scanned.AmiiboSeries);
|
||||
AmiiboSelectedIndex = AmiiboList.IndexOf(scanned);
|
||||
@ -325,7 +325,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
AmiiboApi selected = _amiibos[_amiiboSelectedIndex];
|
||||
|
||||
string imageUrl = _amiiboList.FirstOrDefault(amiibo => amiibo.Equals(selected)).Image;
|
||||
string imageUrl = _amiiboList.Find(amiibo => amiibo.Equals(selected)).Image;
|
||||
|
||||
string usageString = "";
|
||||
|
||||
|
@ -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
|
||||
[Flags]
|
||||
[JsonConverter(typeof(TypedStringEnumConverter<ControllerType>))]
|
||||
public enum ControllerType : int
|
||||
public enum ControllerType
|
||||
{
|
||||
None,
|
||||
ProController = 1 << 0,
|
||||
|
@ -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
|
||||
[JsonConverter(typeof(TypedStringEnumConverter<PlayerIndex>))]
|
||||
public enum PlayerIndex : int
|
||||
public enum PlayerIndex
|
||||
{
|
||||
Player1 = 0,
|
||||
Player2 = 1,
|
||||
|
@ -5,7 +5,7 @@ using System;
|
||||
|
||||
namespace Ryujinx.Cpu
|
||||
{
|
||||
class AddressSpace : IDisposable
|
||||
public class AddressSpace : IDisposable
|
||||
{
|
||||
private const ulong PageSize = 0x1000;
|
||||
|
||||
@ -154,7 +154,9 @@ namespace Ryujinx.Cpu
|
||||
public MemoryBlock Base { 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)
|
||||
{
|
||||
@ -163,17 +165,48 @@ namespace Ryujinx.Cpu
|
||||
_privateTree = new IntrusiveRedBlackTree<PrivateMapping>();
|
||||
_treeLock = new object();
|
||||
|
||||
_mappingTree.Add(new Mapping(0UL, asSize, MappingType.None));
|
||||
_privateTree.Add(new PrivateMapping(0UL, asSize, default));
|
||||
_mappingTree.Add(new Mapping(0UL, addressSpaceSize, MappingType.None));
|
||||
_privateTree.Add(new PrivateMapping(0UL, addressSpaceSize, default));
|
||||
}
|
||||
|
||||
_backingMemory = backingMemory;
|
||||
_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;
|
||||
|
||||
Base = new MemoryBlock(asSize, asFlags);
|
||||
Mirror = new MemoryBlock(asSize, asFlags);
|
||||
ulong minAddressSpaceSize = Math.Min(asSize, 1UL << 36);
|
||||
|
||||
// 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)
|
||||
|
@ -38,7 +38,8 @@ namespace Ryujinx.Cpu.Jit
|
||||
private readonly bool _unsafeMode;
|
||||
|
||||
private readonly AddressSpace _addressSpace;
|
||||
private readonly ulong _addressSpaceSize;
|
||||
|
||||
public ulong AddressSpaceSize { get; }
|
||||
|
||||
private readonly PageTable<ulong> _pageTable;
|
||||
|
||||
@ -62,21 +63,21 @@ namespace Ryujinx.Cpu.Jit
|
||||
/// <summary>
|
||||
/// Creates a new instance of the host mapped memory manager.
|
||||
/// </summary>
|
||||
/// <param name="backingMemory">Physical backing memory where virtual memory will be mapped to</param>
|
||||
/// <param name="addressSpaceSize">Size of the address space</param>
|
||||
/// <param name="addressSpace">Address space instance to use</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>
|
||||
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>();
|
||||
_invalidAccessHandler = invalidAccessHandler;
|
||||
_unsafeMode = unsafeMode;
|
||||
_addressSpaceSize = addressSpaceSize;
|
||||
AddressSpaceSize = addressSpace.AddressSpaceSize;
|
||||
|
||||
ulong asSize = PageSize;
|
||||
int asBits = PageBits;
|
||||
|
||||
while (asSize < addressSpaceSize)
|
||||
while (asSize < AddressSpaceSize)
|
||||
{
|
||||
asSize <<= 1;
|
||||
asBits++;
|
||||
@ -86,8 +87,6 @@ namespace Ryujinx.Cpu.Jit
|
||||
|
||||
_pageBitmap = new ulong[1 << (AddressSpaceBits - (PageBits + PageToPteShift))];
|
||||
|
||||
_addressSpace = new AddressSpace(backingMemory, asSize, Supports4KBPages);
|
||||
|
||||
Tracking = new MemoryTracking(this, (int)MemoryBlock.GetPageSize(), invalidAccessHandler);
|
||||
_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>
|
||||
private bool ValidateAddress(ulong va)
|
||||
{
|
||||
return va < _addressSpaceSize;
|
||||
return va < AddressSpaceSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -111,7 +110,7 @@ namespace Ryujinx.Cpu.Jit
|
||||
private bool ValidateAddressAndSize(ulong va, ulong size)
|
||||
{
|
||||
ulong endVa = va + size;
|
||||
return endVa >= va && endVa >= size && endVa <= _addressSpaceSize;
|
||||
return endVa >= va && endVa >= size && endVa <= AddressSpaceSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -56,7 +56,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
private int _refConsumerPtr;
|
||||
|
||||
private Action _interruptAction;
|
||||
private object _interruptLock = new();
|
||||
private readonly object _interruptLock = new();
|
||||
|
||||
public event EventHandler<ScreenCaptureImageInfo> ScreenCaptured;
|
||||
|
||||
|
@ -512,7 +512,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// <returns>True if at least one of the handles is dirty</returns>
|
||||
private bool CheckDirty()
|
||||
{
|
||||
return Handles.Any(handle => handle.Dirty);
|
||||
return Array.Exists(Handles, handle => handle.Dirty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -78,7 +78,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
private List<BufferMigration> _sources;
|
||||
private BufferMigration _migrationTarget;
|
||||
|
||||
private object _lock = new object();
|
||||
private readonly object _lock = new();
|
||||
|
||||
/// <summary>
|
||||
/// 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++)
|
||||
{
|
||||
BufferModifiedRange overlap = overlaps[i];
|
||||
|
||||
|
||||
if (overlap.Address > address)
|
||||
{
|
||||
// The start of the remaining region is uncovered by this overlap. Call the action for it.
|
||||
|
@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
private const ushort FileFormatVersionMajor = 1;
|
||||
private const ushort FileFormatVersionMinor = 2;
|
||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||
private const uint CodeGenVersion = 5080;
|
||||
private const uint CodeGenVersion = 5311;
|
||||
|
||||
private const string SharedTocFileName = "shared.toc";
|
||||
private const string SharedDataFileName = "shared.data";
|
||||
|
@ -21,7 +21,7 @@ namespace Ryujinx.Graphics.OpenGL.Queries
|
||||
private ulong _accumulatedCounter;
|
||||
private int _waiterCount;
|
||||
|
||||
private object _lock = new object();
|
||||
private readonly object _lock = new();
|
||||
|
||||
private Queue<BufferedQuery> _queryPool;
|
||||
private AutoResetEvent _queuedEvent = new AutoResetEvent(false);
|
||||
|
@ -24,7 +24,7 @@ namespace Ryujinx.Graphics.OpenGL.Queries
|
||||
private bool _hostAccessReserved = false;
|
||||
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 double _divisor = 1f;
|
||||
|
||||
|
@ -20,7 +20,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
{
|
||||
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>>();
|
||||
|
||||
/// <summary>
|
||||
|
@ -71,40 +71,10 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
context.AppendLine($"const int {DefaultNames.UndefinedName} = 0;");
|
||||
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);
|
||||
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();
|
||||
if (textureDescriptors.Length != 0)
|
||||
@ -238,11 +208,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
context.AppendLine();
|
||||
}
|
||||
|
||||
if ((info.HelperFunctionsMask & HelperFunctionsMask.AtomicMinMaxS32Shared) != 0)
|
||||
{
|
||||
AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/AtomicMinMaxS32Shared.glsl");
|
||||
}
|
||||
|
||||
if ((info.HelperFunctionsMask & HelperFunctionsMask.MultiplyHighS32) != 0)
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
if ((info.HelperFunctionsMask & HelperFunctionsMask.StoreSharedSmallInt) != 0)
|
||||
{
|
||||
AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/StoreSharedSmallInt.glsl");
|
||||
}
|
||||
|
||||
if ((info.HelperFunctionsMask & HelperFunctionsMask.SwizzleAdd) != 0)
|
||||
{
|
||||
AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/SwizzleAdd.glsl");
|
||||
@ -358,7 +318,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
_ => "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();
|
||||
|
||||
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)
|
||||
{
|
||||
int arraySize = 0;
|
||||
@ -717,7 +705,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
string code = EmbeddedResources.ReadAllText(filename);
|
||||
|
||||
code = code.Replace("\t", CodeGenContext.Tab);
|
||||
code = code.Replace("$SHARED_MEM$", DefaultNames.SharedMemoryName);
|
||||
|
||||
if (context.Config.GpuAccessor.QueryHostSupportsShaderBallot())
|
||||
{
|
||||
|
@ -11,9 +11,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
public const string IAttributePrefix = "in_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 UndefinedName = "undef";
|
||||
|
@ -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);
|
||||
}
|
@ -2,9 +2,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
{
|
||||
static class HelperFunctionNames
|
||||
{
|
||||
public static string AtomicMaxS32 = "Helper_AtomicMaxS32";
|
||||
public static string AtomicMinS32 = "Helper_AtomicMinS32";
|
||||
|
||||
public static string MultiplyHighS32 = "Helper_MultiplyHighS32";
|
||||
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 ShuffleXor = "Helper_ShuffleXor";
|
||||
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";
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -68,7 +68,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
|
||||
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);
|
||||
|
||||
@ -81,23 +81,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
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
|
||||
{
|
||||
for (int argIndex = 0; argIndex < arity; argIndex++)
|
||||
@ -179,12 +162,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
case Instruction.Load:
|
||||
return Load(context, operation);
|
||||
|
||||
case Instruction.LoadLocal:
|
||||
return LoadLocal(context, operation);
|
||||
|
||||
case Instruction.LoadShared:
|
||||
return LoadShared(context, operation);
|
||||
|
||||
case Instruction.Lod:
|
||||
return Lod(context, operation);
|
||||
|
||||
@ -200,18 +177,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
case Instruction.Store:
|
||||
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:
|
||||
return TextureSample(context, operation);
|
||||
|
||||
|
@ -17,9 +17,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
Add(Instruction.AtomicAdd, InstType.AtomicBinary, "atomicAdd");
|
||||
Add(Instruction.AtomicAnd, InstType.AtomicBinary, "atomicAnd");
|
||||
Add(Instruction.AtomicCompareAndSwap, InstType.AtomicTernary, "atomicCompSwap");
|
||||
Add(Instruction.AtomicMaxS32, InstType.CallTernary, HelperFunctionNames.AtomicMaxS32);
|
||||
Add(Instruction.AtomicMaxU32, InstType.AtomicBinary, "atomicMax");
|
||||
Add(Instruction.AtomicMinS32, InstType.CallTernary, HelperFunctionNames.AtomicMinS32);
|
||||
Add(Instruction.AtomicMinU32, InstType.AtomicBinary, "atomicMin");
|
||||
Add(Instruction.AtomicOr, InstType.AtomicBinary, "atomicOr");
|
||||
Add(Instruction.AtomicSwap, InstType.AtomicBinary, "atomicExchange");
|
||||
@ -83,8 +81,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
Add(Instruction.ImageAtomic, InstType.Special);
|
||||
Add(Instruction.IsNan, InstType.CallUnary, "isnan");
|
||||
Add(Instruction.Load, InstType.Special);
|
||||
Add(Instruction.LoadLocal, InstType.Special);
|
||||
Add(Instruction.LoadShared, InstType.Special);
|
||||
Add(Instruction.Lod, InstType.Special);
|
||||
Add(Instruction.LogarithmB2, InstType.CallUnary, "log2");
|
||||
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.SquareRoot, InstType.CallUnary, "sqrt");
|
||||
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.SwizzleAdd, InstType.CallTernary, HelperFunctionNames.SwizzleAdd);
|
||||
Add(Instruction.TextureSample, InstType.Special);
|
||||
|
@ -191,25 +191,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
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)
|
||||
{
|
||||
AstTextureOperation texOp = (AstTextureOperation)operation;
|
||||
@ -263,58 +244,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
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)
|
||||
{
|
||||
AstTextureOperation texOp = (AstTextureOperation)operation;
|
||||
@ -675,6 +604,21 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
varType = field.Type;
|
||||
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.InputPerPatch:
|
||||
case StorageKind.Output:
|
||||
|
@ -113,7 +113,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
|
||||
if (node is AstOperation operation)
|
||||
{
|
||||
if (operation.Inst == Instruction.Load)
|
||||
if (operation.Inst == Instruction.Load || operation.Inst.IsAtomic())
|
||||
{
|
||||
switch (operation.StorageKind)
|
||||
{
|
||||
@ -136,6 +136,19 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
|
||||
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.InputPerPatch:
|
||||
case StorageKind.Output:
|
||||
|
@ -25,8 +25,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
public Dictionary<int, Instruction> ConstantBuffers { get; } = new Dictionary<int, Instruction>();
|
||||
public Dictionary<int, Instruction> StorageBuffers { get; } = new Dictionary<int, Instruction>();
|
||||
public Instruction LocalMemory { get; set; }
|
||||
public Instruction SharedMemory { get; set; }
|
||||
public Dictionary<int, Instruction> LocalMemories { get; } = new Dictionary<int, Instruction>();
|
||||
public Dictionary<int, Instruction> SharedMemories { get; } = new Dictionary<int, Instruction>();
|
||||
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)> 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> OutputsPerPatch { get; } = new Dictionary<IoDefinition, Instruction>();
|
||||
|
||||
public Instruction CoordTemp { get; set; }
|
||||
public StructuredFunction CurrentFunction { get; set; }
|
||||
private readonly Dictionary<AstOperand, Instruction> _locals = new Dictionary<AstOperand, Instruction>();
|
||||
private readonly Dictionary<int, Instruction[]> _localForArgs = new Dictionary<int, Instruction[]>();
|
||||
|
@ -6,7 +6,6 @@ using Spv.Generator;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using static Spv.Specification;
|
||||
using SpvInstruction = Spv.Generator.Instruction;
|
||||
@ -44,13 +43,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
context.AddLocalVariable(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)
|
||||
@ -77,54 +69,30 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
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);
|
||||
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());
|
||||
DeclareImages(context, context.Config.GetImageDescriptors());
|
||||
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.SharedMemory = DeclareMemory(context, StorageClass.Workgroup, size);
|
||||
}
|
||||
context.AddGlobalVariable(variable);
|
||||
|
||||
private static SpvInstruction DeclareMemory(CodeGenContext context, StorageClass storage, int size)
|
||||
{
|
||||
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;
|
||||
dict.Add(id, variable);
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeclareConstantBuffers(CodeGenContext context, IEnumerable<BufferDefinition> buffers)
|
||||
|
@ -97,8 +97,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
Add(Instruction.ImageStore, GenerateImageStore);
|
||||
Add(Instruction.IsNan, GenerateIsNan);
|
||||
Add(Instruction.Load, GenerateLoad);
|
||||
Add(Instruction.LoadLocal, GenerateLoadLocal);
|
||||
Add(Instruction.LoadShared, GenerateLoadShared);
|
||||
Add(Instruction.Lod, GenerateLod);
|
||||
Add(Instruction.LogarithmB2, GenerateLogarithmB2);
|
||||
Add(Instruction.LogicalAnd, GenerateLogicalAnd);
|
||||
@ -132,10 +130,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
Add(Instruction.Sine, GenerateSine);
|
||||
Add(Instruction.SquareRoot, GenerateSquareRoot);
|
||||
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.SwizzleAdd, GenerateSwizzleAdd);
|
||||
Add(Instruction.TextureSample, GenerateTextureSample);
|
||||
@ -871,30 +865,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
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)
|
||||
{
|
||||
AstTextureOperation texOp = (AstTextureOperation)operation;
|
||||
@ -1268,45 +1238,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
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)
|
||||
{
|
||||
return GenerateBinary(context, operation, context.Delegates.FSub, context.Delegates.ISub);
|
||||
@ -1827,55 +1758,27 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
AstOperation operation,
|
||||
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;
|
||||
|
||||
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 value = context.Get(varType, operation.GetSource(operation.SourcesCount - 1));
|
||||
|
||||
var one = context.Constant(context.TypeU32(), 1);
|
||||
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)
|
||||
{
|
||||
var value0 = context.GetU32(operation.GetSource(operation.SourcesCount - 2));
|
||||
var value1 = context.GetU32(operation.GetSource(operation.SourcesCount - 1));
|
||||
SpvInstruction elemPointer = GetStoragePointer(context, operation, out AggregateType varType);
|
||||
|
||||
SpvInstruction elemPointer;
|
||||
|
||||
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 value0 = context.Get(varType, operation.GetSource(operation.SourcesCount - 2));
|
||||
var value1 = context.Get(varType, operation.GetSource(operation.SourcesCount - 1));
|
||||
|
||||
var one = context.Constant(context.TypeU32(), 1);
|
||||
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)
|
||||
@ -1928,6 +1831,27 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
: context.StorageBuffers[bindingIndex.Value];
|
||||
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.InputPerPatch:
|
||||
case StorageKind.Output:
|
||||
@ -2048,50 +1972,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
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(
|
||||
CodeGenContext context,
|
||||
AstTextureOperation texOp,
|
||||
|
@ -247,6 +247,17 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
||||
{
|
||||
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);
|
||||
|
||||
|
@ -166,7 +166,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
{
|
||||
// gl_FrontFacing sometimes has incorrect (flipped) values depending how it is accessed on Intel GPUs.
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,12 +10,6 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
{
|
||||
static partial class InstEmit
|
||||
{
|
||||
private enum MemoryRegion
|
||||
{
|
||||
Local,
|
||||
Shared
|
||||
}
|
||||
|
||||
public static void Atom(EmitterContext context)
|
||||
{
|
||||
InstAtom op = context.GetOp<InstAtom>();
|
||||
@ -33,6 +27,12 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
|
||||
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>();
|
||||
|
||||
Operand offset = context.ShiftRightU32(GetSrcReg(context, op.SrcA), Const(2));
|
||||
@ -51,7 +51,8 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
_ => 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);
|
||||
}
|
||||
@ -114,14 +115,20 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
{
|
||||
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)
|
||||
{
|
||||
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>();
|
||||
|
||||
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)
|
||||
@ -144,14 +151,20 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
{
|
||||
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)
|
||||
{
|
||||
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>();
|
||||
|
||||
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)
|
||||
@ -192,8 +205,8 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
StorageKind storageKind,
|
||||
AtomOp op,
|
||||
AtomSize type,
|
||||
Operand addrLow,
|
||||
Operand addrHigh,
|
||||
Operand e0,
|
||||
Operand e1,
|
||||
Operand value)
|
||||
{
|
||||
Operand res = Const(0);
|
||||
@ -203,7 +216,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
case AtomOp.Add:
|
||||
if (type == AtomSize.S32 || type == AtomSize.U32)
|
||||
{
|
||||
res = context.AtomicAdd(storageKind, addrLow, addrHigh, value);
|
||||
res = context.AtomicAdd(storageKind, e0, e1, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -213,7 +226,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
case AtomOp.And:
|
||||
if (type == AtomSize.S32 || type == AtomSize.U32)
|
||||
{
|
||||
res = context.AtomicAnd(storageKind, addrLow, addrHigh, value);
|
||||
res = context.AtomicAnd(storageKind, e0, e1, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -223,7 +236,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
case AtomOp.Xor:
|
||||
if (type == AtomSize.S32 || type == AtomSize.U32)
|
||||
{
|
||||
res = context.AtomicXor(storageKind, addrLow, addrHigh, value);
|
||||
res = context.AtomicXor(storageKind, e0, e1, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -233,7 +246,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
case AtomOp.Or:
|
||||
if (type == AtomSize.S32 || type == AtomSize.U32)
|
||||
{
|
||||
res = context.AtomicOr(storageKind, addrLow, addrHigh, value);
|
||||
res = context.AtomicOr(storageKind, e0, e1, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -243,11 +256,11 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
case AtomOp.Max:
|
||||
if (type == AtomSize.S32)
|
||||
{
|
||||
res = context.AtomicMaxS32(storageKind, addrLow, addrHigh, value);
|
||||
res = context.AtomicMaxS32(storageKind, e0, e1, value);
|
||||
}
|
||||
else if (type == AtomSize.U32)
|
||||
{
|
||||
res = context.AtomicMaxU32(storageKind, addrLow, addrHigh, value);
|
||||
res = context.AtomicMaxU32(storageKind, e0, e1, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -257,11 +270,11 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
case AtomOp.Min:
|
||||
if (type == AtomSize.S32)
|
||||
{
|
||||
res = context.AtomicMinS32(storageKind, addrLow, addrHigh, value);
|
||||
res = context.AtomicMinS32(storageKind, e0, e1, value);
|
||||
}
|
||||
else if (type == AtomSize.U32)
|
||||
{
|
||||
res = context.AtomicMinU32(storageKind, addrLow, addrHigh, value);
|
||||
res = context.AtomicMinU32(storageKind, e0, e1, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -275,7 +288,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
|
||||
private static void EmitLoad(
|
||||
EmitterContext context,
|
||||
MemoryRegion region,
|
||||
StorageKind storageKind,
|
||||
LsSize2 size,
|
||||
Operand srcA,
|
||||
int rd,
|
||||
@ -287,19 +300,19 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
return;
|
||||
}
|
||||
|
||||
int id = storageKind == StorageKind.LocalMemory
|
||||
? context.Config.ResourceManager.LocalMemoryId
|
||||
: context.Config.ResourceManager.SharedMemoryId;
|
||||
bool isSmallInt = size < LsSize2.B32;
|
||||
|
||||
int count = 1;
|
||||
|
||||
switch (size)
|
||||
int count = size switch
|
||||
{
|
||||
case LsSize2.B64: count = 2; break;
|
||||
case LsSize2.B128: count = 4; break;
|
||||
}
|
||||
LsSize2.B64 => 2,
|
||||
LsSize2.B128 => 4,
|
||||
_ => 1
|
||||
};
|
||||
|
||||
Operand baseOffset = context.IAdd(srcA, Const(offset));
|
||||
Operand wordOffset = context.ShiftRightU32(baseOffset, Const(2)); // Word offset = byte offset / 4 (one word = 4 bytes).
|
||||
Operand bitOffset = GetBitOffset(context, baseOffset);
|
||||
Operand baseOffset = context.Copy(srcA);
|
||||
|
||||
for (int index = 0; index < count; index++)
|
||||
{
|
||||
@ -310,14 +323,10 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
break;
|
||||
}
|
||||
|
||||
Operand elemOffset = context.IAdd(wordOffset, Const(index));
|
||||
Operand value = null;
|
||||
|
||||
switch (region)
|
||||
{
|
||||
case MemoryRegion.Local: value = context.LoadLocal(elemOffset); break;
|
||||
case MemoryRegion.Shared: value = context.LoadShared(elemOffset); break;
|
||||
}
|
||||
Operand byteOffset = context.IAdd(baseOffset, Const(offset + index * 4));
|
||||
Operand wordOffset = context.ShiftRightU32(byteOffset, Const(2)); // Word offset = byte offset / 4 (one word = 4 bytes).
|
||||
Operand bitOffset = GetBitOffset(context, byteOffset);
|
||||
Operand value = context.Load(storageKind, id, wordOffset);
|
||||
|
||||
if (isSmallInt)
|
||||
{
|
||||
@ -360,7 +369,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
|
||||
private static void EmitStore(
|
||||
EmitterContext context,
|
||||
MemoryRegion region,
|
||||
StorageKind storageKind,
|
||||
LsSize2 size,
|
||||
Operand srcA,
|
||||
int rd,
|
||||
@ -372,52 +381,54 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
return;
|
||||
}
|
||||
|
||||
int id = storageKind == StorageKind.LocalMemory
|
||||
? context.Config.ResourceManager.LocalMemoryId
|
||||
: context.Config.ResourceManager.SharedMemoryId;
|
||||
bool isSmallInt = size < LsSize2.B32;
|
||||
|
||||
int count = 1;
|
||||
|
||||
switch (size)
|
||||
int count = size switch
|
||||
{
|
||||
case LsSize2.B64: count = 2; break;
|
||||
case LsSize2.B128: count = 4; break;
|
||||
}
|
||||
LsSize2.B64 => 2,
|
||||
LsSize2.B128 => 4,
|
||||
_ => 1
|
||||
};
|
||||
|
||||
Operand baseOffset = context.IAdd(srcA, Const(offset));
|
||||
Operand wordOffset = context.ShiftRightU32(baseOffset, Const(2));
|
||||
Operand bitOffset = GetBitOffset(context, baseOffset);
|
||||
Operand baseOffset = context.Copy(srcA);
|
||||
|
||||
for (int index = 0; index < count; index++)
|
||||
{
|
||||
bool isRz = rd + index >= RegisterConsts.RegisterZeroIndex;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
case LsSize2.U8:
|
||||
case LsSize2.S8:
|
||||
context.StoreShared8(baseOffset, value);
|
||||
context.Store(StorageKind.SharedMemory8, id, byteOffset, value);
|
||||
break;
|
||||
case LsSize2.U16:
|
||||
case LsSize2.S16:
|
||||
context.StoreShared16(baseOffset, value);
|
||||
context.Store(StorageKind.SharedMemory16, id, byteOffset, value);
|
||||
break;
|
||||
default:
|
||||
context.StoreShared(elemOffset, value);
|
||||
context.Store(storageKind, id, wordOffset, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -79,8 +79,6 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||
ImageAtomic,
|
||||
IsNan,
|
||||
Load,
|
||||
LoadLocal,
|
||||
LoadShared,
|
||||
Lod,
|
||||
LogarithmB2,
|
||||
LogicalAnd,
|
||||
@ -115,10 +113,6 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||
Sine,
|
||||
SquareRoot,
|
||||
Store,
|
||||
StoreLocal,
|
||||
StoreShared,
|
||||
StoreShared16,
|
||||
StoreShared8,
|
||||
Subtract,
|
||||
SwizzleAdd,
|
||||
TextureSample,
|
||||
|
@ -11,12 +11,13 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||
StorageBuffer,
|
||||
LocalMemory,
|
||||
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,
|
||||
// TODO: Remove those and store type as a field on the Operation class itself.
|
||||
GlobalMemoryS8,
|
||||
GlobalMemoryS16,
|
||||
GlobalMemoryU8,
|
||||
GlobalMemoryU16
|
||||
GlobalMemoryS8, // TODO: Remove this and store type as a field on the Operation class itself.
|
||||
GlobalMemoryS16, // TODO: Remove this and store type as a field on the Operation class itself.
|
||||
GlobalMemoryU8, // TODO: Remove this and store type as a field on the Operation class itself.
|
||||
GlobalMemoryU16 // TODO: Remove this and store type as a field on the Operation class itself.
|
||||
}
|
||||
|
||||
static class StorageKindExtensions
|
||||
|
@ -10,14 +10,12 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\AtomicMinMaxS32Shared.glsl" />
|
||||
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\MultiplyHighS32.glsl" />
|
||||
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\MultiplyHighU32.glsl" />
|
||||
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\Shuffle.glsl" />
|
||||
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\ShuffleDown.glsl" />
|
||||
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\ShuffleUp.glsl" />
|
||||
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\ShuffleXor.glsl" />
|
||||
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\StoreSharedSmallInt.glsl" />
|
||||
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\SwizzleAdd.glsl" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -5,15 +5,13 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
[Flags]
|
||||
enum HelperFunctionsMask
|
||||
{
|
||||
AtomicMinMaxS32Shared = 1 << 0,
|
||||
MultiplyHighS32 = 1 << 2,
|
||||
MultiplyHighU32 = 1 << 3,
|
||||
Shuffle = 1 << 4,
|
||||
ShuffleDown = 1 << 5,
|
||||
ShuffleUp = 1 << 6,
|
||||
ShuffleXor = 1 << 7,
|
||||
StoreSharedSmallInt = 1 << 8,
|
||||
SwizzleAdd = 1 << 10,
|
||||
FSI = 1 << 11
|
||||
MultiplyHighS32 = 1 << 2,
|
||||
MultiplyHighU32 = 1 << 3,
|
||||
Shuffle = 1 << 4,
|
||||
ShuffleDown = 1 << 5,
|
||||
ShuffleUp = 1 << 6,
|
||||
ShuffleXor = 1 << 7,
|
||||
SwizzleAdd = 1 << 10,
|
||||
FSI = 1 << 11
|
||||
}
|
||||
}
|
@ -90,8 +90,6 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
Add(Instruction.ImageAtomic, AggregateType.S32);
|
||||
Add(Instruction.IsNan, AggregateType.Bool, AggregateType.Scalar);
|
||||
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.LogarithmB2, AggregateType.Scalar, AggregateType.Scalar);
|
||||
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.SquareRoot, AggregateType.Scalar, AggregateType.Scalar);
|
||||
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.SwizzleAdd, AggregateType.FP32, AggregateType.FP32, AggregateType.FP32, AggregateType.S32);
|
||||
Add(Instruction.TextureSample, AggregateType.FP32);
|
||||
|
18
src/Ryujinx.Graphics.Shader/StructuredIr/MemoryDefinition.cs
Normal file
18
src/Ryujinx.Graphics.Shader/StructuredIr/MemoryDefinition.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -6,14 +6,20 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
{
|
||||
private readonly Dictionary<int, BufferDefinition> _constantBuffers;
|
||||
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> StorageBuffers => _storageBuffers;
|
||||
public IReadOnlyDictionary<int, MemoryDefinition> LocalMemories => _localMemories;
|
||||
public IReadOnlyDictionary<int, MemoryDefinition> SharedMemories => _sharedMemories;
|
||||
|
||||
public ShaderProperties()
|
||||
{
|
||||
_constantBuffers = 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)
|
||||
@ -25,5 +31,21 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
{
|
||||
_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;
|
||||
}
|
||||
}
|
||||
}
|
@ -274,13 +274,6 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
// decide which helper functions are needed on the final generated code.
|
||||
switch (operation.Inst)
|
||||
{
|
||||
case Instruction.AtomicMaxS32:
|
||||
case Instruction.AtomicMinS32:
|
||||
if (operation.StorageKind == StorageKind.SharedMemory)
|
||||
{
|
||||
context.Info.HelperFunctionsMask |= HelperFunctionsMask.AtomicMinMaxS32Shared;
|
||||
}
|
||||
break;
|
||||
case Instruction.MultiplyHighS32:
|
||||
context.Info.HelperFunctionsMask |= HelperFunctionsMask.MultiplyHighS32;
|
||||
break;
|
||||
@ -299,10 +292,6 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
case Instruction.ShuffleXor:
|
||||
context.Info.HelperFunctionsMask |= HelperFunctionsMask.ShuffleXor;
|
||||
break;
|
||||
case Instruction.StoreShared16:
|
||||
case Instruction.StoreShared8:
|
||||
context.Info.HelperFunctionsMask |= HelperFunctionsMask.StoreSharedSmallInt;
|
||||
break;
|
||||
case Instruction.SwizzleAdd:
|
||||
context.Info.HelperFunctionsMask |= HelperFunctionsMask.SwizzleAdd;
|
||||
break;
|
||||
|
@ -67,6 +67,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return context.Add(Instruction.MemoryBarrier);
|
||||
@ -753,6 +748,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return UnpackDouble2x32(context, a, 1);
|
||||
|
@ -21,6 +21,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
RtLayer = 1 << 5,
|
||||
IaIndexing = 1 << 7,
|
||||
OaIndexing = 1 << 8,
|
||||
FixedFuncAttr = 1 << 9
|
||||
FixedFuncAttr = 1 << 9,
|
||||
LocalMemory = 1 << 10,
|
||||
SharedMemory = 1 << 11
|
||||
}
|
||||
}
|
||||
|
@ -9,13 +9,13 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
class HelperFunctionManager
|
||||
{
|
||||
private readonly List<Function> _functionList;
|
||||
private readonly Dictionary<HelperFunctionName, int> _functionIds;
|
||||
private readonly Dictionary<int, int> _functionIds;
|
||||
private readonly ShaderStage _stage;
|
||||
|
||||
public HelperFunctionManager(List<Function> functionList, ShaderStage stage)
|
||||
{
|
||||
_functionList = functionList;
|
||||
_functionIds = new Dictionary<HelperFunctionName, int>();
|
||||
_functionIds = new Dictionary<int, int>();
|
||||
_stage = stage;
|
||||
}
|
||||
|
||||
@ -29,14 +29,30 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
|
||||
public int GetOrCreateFunctionId(HelperFunctionName functionName)
|
||||
{
|
||||
if (_functionIds.TryGetValue(functionName, out int functionId))
|
||||
if (_functionIds.TryGetValue((int)functionName, out int functionId))
|
||||
{
|
||||
return functionId;
|
||||
}
|
||||
|
||||
Function function = GenerateFunction(functionName);
|
||||
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;
|
||||
}
|
||||
@ -140,6 +156,67 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
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()
|
||||
{
|
||||
EmitterContext context = new EmitterContext();
|
||||
@ -226,5 +303,29 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -4,6 +4,10 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
{
|
||||
ConvertDoubleToFloat,
|
||||
ConvertFloatToDouble,
|
||||
SharedAtomicMaxS32,
|
||||
SharedAtomicMinS32,
|
||||
SharedStore8,
|
||||
SharedStore16,
|
||||
TexelFetchScale,
|
||||
TextureSizeUnscale
|
||||
}
|
||||
|
@ -244,7 +244,9 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
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
|
||||
// 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)
|
||||
{
|
||||
Operand bitOffset = GetBitOffset(context, offset);
|
||||
Operand bitOffset = HelperFunctionManager.GetBitOffset(context, offset);
|
||||
|
||||
GenerateAtomicCasLoop(context, wordOffset, binding, (memValue) =>
|
||||
{
|
||||
@ -892,7 +894,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
|
||||
if (IsSmallInt(storageKind))
|
||||
{
|
||||
Operand bitOffset = GetBitOffset(context, offset);
|
||||
Operand bitOffset = HelperFunctionManager.GetBitOffset(context, offset);
|
||||
|
||||
switch (storageKind)
|
||||
{
|
||||
@ -921,11 +923,6 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
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)
|
||||
{
|
||||
Operand lblLoopHead = Label();
|
||||
@ -1070,15 +1067,18 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
{
|
||||
baseOffset = null;
|
||||
|
||||
if (operation.Inst == Instruction.LoadShared || operation.Inst == Instruction.StoreShared)
|
||||
if (operation.Inst == Instruction.Load || operation.Inst == Instruction.Store)
|
||||
{
|
||||
type = LsMemoryType.Shared;
|
||||
return TryGetSharedMemoryOffsets(operation, out baseOffset, out constOffset);
|
||||
}
|
||||
else if (operation.Inst == Instruction.LoadLocal || operation.Inst == Instruction.StoreLocal)
|
||||
{
|
||||
type = LsMemoryType.Local;
|
||||
return TryGetLocalMemoryOffset(operation, out constOffset);
|
||||
if (operation.StorageKind == StorageKind.SharedMemory)
|
||||
{
|
||||
type = LsMemoryType.Shared;
|
||||
return TryGetSharedMemoryOffsets(operation, out baseOffset, out constOffset);
|
||||
}
|
||||
else if (operation.StorageKind == StorageKind.LocalMemory)
|
||||
{
|
||||
type = LsMemoryType.Local;
|
||||
return TryGetLocalMemoryOffset(operation, out constOffset);
|
||||
}
|
||||
}
|
||||
|
||||
type = default;
|
||||
|
@ -1,3 +1,4 @@
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Graphics.Shader.StructuredIr;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@ -7,6 +8,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
{
|
||||
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 readonly IGpuAccessor _gpuAccessor;
|
||||
@ -22,6 +28,9 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
|
||||
private readonly HashSet<int> _usedConstantBufferBindings;
|
||||
|
||||
public int LocalMemoryId { get; private set; }
|
||||
public int SharedMemoryId { get; private set; }
|
||||
|
||||
public ShaderProperties Properties => _properties;
|
||||
|
||||
public ResourceManager(ShaderStage stage, IGpuAccessor gpuAccessor, ShaderProperties properties)
|
||||
@ -41,6 +50,47 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
_usedConstantBufferBindings = new HashSet<int>();
|
||||
|
||||
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)
|
||||
|
@ -1,6 +1,8 @@
|
||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using Ryujinx.Graphics.Shader.StructuredIr;
|
||||
using Ryujinx.Graphics.Shader.Translation.Optimizations;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
TextureOperation texOp = (TextureOperation)node.Value;
|
||||
|
@ -124,11 +124,12 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
private TextureDescriptor[] _cachedTextureDescriptors;
|
||||
private TextureDescriptor[] _cachedImageDescriptors;
|
||||
|
||||
public ShaderConfig(ShaderStage stage, IGpuAccessor gpuAccessor, TranslationOptions options)
|
||||
public ShaderConfig(ShaderStage stage, IGpuAccessor gpuAccessor, TranslationOptions options, int localMemorySize)
|
||||
{
|
||||
Stage = stage;
|
||||
GpuAccessor = gpuAccessor;
|
||||
Options = options;
|
||||
Stage = stage;
|
||||
GpuAccessor = gpuAccessor;
|
||||
Options = options;
|
||||
LocalMemorySize = localMemorySize;
|
||||
|
||||
_transformFeedbackDefinitions = new Dictionary<TransformFeedbackVariable, TransformFeedbackOutput>();
|
||||
|
||||
@ -176,20 +177,22 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
OutputTopology outputTopology,
|
||||
int maxOutputVertices,
|
||||
IGpuAccessor gpuAccessor,
|
||||
TranslationOptions options) : this(stage, gpuAccessor, options)
|
||||
TranslationOptions options) : this(stage, gpuAccessor, options, 0)
|
||||
{
|
||||
ThreadsPerInputPrimitive = 1;
|
||||
OutputTopology = outputTopology;
|
||||
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;
|
||||
ThreadsPerInputPrimitive = header.ThreadsPerInputPrimitive;
|
||||
OutputTopology = header.OutputTopology;
|
||||
MaxOutputVertices = header.MaxOutputVertexCount;
|
||||
LocalMemorySize = header.ShaderLocalMemoryLowSize + header.ShaderLocalMemoryHighSize + (header.ShaderLocalMemoryCrsSize / ThreadsPerWarp);
|
||||
ImapTypes = header.ImapTypes;
|
||||
OmapTargets = header.OmapTargets;
|
||||
OmapSampleMask = header.OmapSampleMask;
|
||||
@ -197,6 +200,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
LastInVertexPipeline = header.Stage < ShaderStage.Fragment;
|
||||
}
|
||||
|
||||
private static int GetLocalMemorySize(ShaderHeader header)
|
||||
{
|
||||
return header.ShaderLocalMemoryLowSize + header.ShaderLocalMemoryHighSize + (header.ShaderLocalMemoryCrsSize / ThreadsPerWarp);
|
||||
}
|
||||
|
||||
private void EnsureTransformFeedbackInitialized()
|
||||
{
|
||||
if (HasTransformFeedbackOutputs() && _transformFeedbackOutputs == null)
|
||||
|
@ -107,7 +107,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
|
||||
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);
|
||||
}
|
||||
@ -140,7 +140,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -149,6 +149,17 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
|
||||
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 _);
|
||||
|
||||
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.
|
||||
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);
|
||||
|
||||
|
@ -3,7 +3,7 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Graphics.Vulkan.MoltenVK
|
||||
{
|
||||
enum MVKConfigLogLevel : int
|
||||
enum MVKConfigLogLevel
|
||||
{
|
||||
None = 0,
|
||||
Error = 1,
|
||||
@ -12,7 +12,7 @@ namespace Ryujinx.Graphics.Vulkan.MoltenVK
|
||||
Debug = 4
|
||||
}
|
||||
|
||||
enum MVKConfigTraceVulkanCalls : int
|
||||
enum MVKConfigTraceVulkanCalls
|
||||
{
|
||||
None = 0,
|
||||
Enter = 1,
|
||||
@ -20,7 +20,7 @@ namespace Ryujinx.Graphics.Vulkan.MoltenVK
|
||||
Duration = 3
|
||||
}
|
||||
|
||||
enum MVKConfigAutoGPUCaptureScope : int
|
||||
enum MVKConfigAutoGPUCaptureScope
|
||||
{
|
||||
None = 0,
|
||||
Device = 1,
|
||||
@ -28,7 +28,7 @@ namespace Ryujinx.Graphics.Vulkan.MoltenVK
|
||||
}
|
||||
|
||||
[Flags]
|
||||
enum MVKConfigAdvertiseExtensions : int
|
||||
enum MVKConfigAdvertiseExtensions
|
||||
{
|
||||
All = 0x00000001,
|
||||
MoltenVK = 0x00000002,
|
||||
@ -36,7 +36,7 @@ namespace Ryujinx.Graphics.Vulkan.MoltenVK
|
||||
Portability = 0x00000008
|
||||
}
|
||||
|
||||
enum MVKVkSemaphoreSupportStyle : int
|
||||
enum MVKVkSemaphoreSupportStyle
|
||||
{
|
||||
MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE = 0,
|
||||
MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_METAL_EVENTS_WHERE_SAFE = 1,
|
||||
|
@ -24,7 +24,7 @@ namespace Ryujinx.Graphics.Vulkan.Queries
|
||||
private ulong _accumulatedCounter;
|
||||
private int _waiterCount;
|
||||
|
||||
private object _lock = new object();
|
||||
private readonly object _lock = new();
|
||||
|
||||
private Queue<BufferedQuery> _queryPool;
|
||||
private AutoResetEvent _queuedEvent = new AutoResetEvent(false);
|
||||
|
@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Vulkan.Queries
|
||||
private bool _hostAccessReserved = false;
|
||||
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 double _divisor = 1f;
|
||||
|
||||
|
@ -256,7 +256,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
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;
|
||||
|
||||
|
@ -60,7 +60,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
private bool _canAcceptController = false;
|
||||
private KeyboardInputMode _inputMode = KeyboardInputMode.ControllerAndKeyboard;
|
||||
|
||||
private object _lock = new object();
|
||||
private readonly object _lock = new();
|
||||
|
||||
public event EventHandler AppletStateChanged;
|
||||
|
||||
|
@ -13,7 +13,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
private const int TextBoxBlinkSleepMilliseconds = 100;
|
||||
private const int RendererWaitTimeoutMilliseconds = 100;
|
||||
|
||||
private readonly object _stateLock = new object();
|
||||
private readonly object _stateLock = new();
|
||||
|
||||
private SoftwareKeyboardUiState _state = new SoftwareKeyboardUiState();
|
||||
private SoftwareKeyboardRendererBase _renderer;
|
||||
|
@ -26,7 +26,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
const string CancelText = "Cancel";
|
||||
const string ControllerToggleText = "Toggle input";
|
||||
|
||||
private readonly object _bufferLock = new object();
|
||||
private readonly object _bufferLock = new();
|
||||
|
||||
private RenderingSurfaceInfo _surfaceInfo = 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)
|
||||
{
|
||||
RendererOptions options = new RendererOptions(font);
|
||||
|
||||
|
||||
if (text == "")
|
||||
{
|
||||
FontRectangle emptyRectangle = TextMeasurer.Measure(" ", options);
|
||||
|
@ -26,8 +26,8 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
}
|
||||
|
||||
private TRef<bool> _cancelled = null;
|
||||
private Thread _thread = null;
|
||||
private object _lock = new object();
|
||||
private Thread _thread = null;
|
||||
private readonly object _lock = new();
|
||||
|
||||
public bool IsRunning
|
||||
{
|
||||
|
@ -25,7 +25,15 @@ namespace Ryujinx.HLE.HOS
|
||||
|
||||
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)
|
||||
{
|
||||
@ -38,6 +46,8 @@ namespace Ryujinx.HLE.HOS
|
||||
_gpuContext = gpuContext;
|
||||
_cpuContext = cpuEngine.CreateCpuContext(memoryManager, for64Bit);
|
||||
_memoryManager = memoryManager;
|
||||
|
||||
AddressSpaceSize = addressSpaceSize;
|
||||
}
|
||||
|
||||
public IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks)
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Cpu.AppleHv;
|
||||
using Ryujinx.Cpu.Jit;
|
||||
@ -49,7 +50,7 @@ namespace Ryujinx.HLE.HOS
|
||||
{
|
||||
var cpuEngine = new HvEngine(_tickSource);
|
||||
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
|
||||
{
|
||||
@ -57,23 +58,41 @@ namespace Ryujinx.HLE.HOS
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
case MemoryManagerMode.SoftwarePageTable:
|
||||
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;
|
||||
|
||||
case MemoryManagerMode.HostMapped:
|
||||
case MemoryManagerMode.HostMappedUnsafe:
|
||||
bool unsafeMode = mode == MemoryManagerMode.HostMappedUnsafe;
|
||||
var memoryManagerHostMapped = new MemoryManagerHostMapped(context.Memory, addressSpaceSize, unsafeMode, invalidAccessHandler);
|
||||
processContext = new ArmProcessContext<MemoryManagerHostMapped>(pid, cpuEngine, _gpu, memoryManagerHostMapped, for64Bit);
|
||||
if (addressSpaceSize != addressSpace.AddressSpaceSize)
|
||||
{
|
||||
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;
|
||||
|
||||
default:
|
||||
|
@ -15,7 +15,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
|
||||
writer.Write(Params);
|
||||
|
||||
if (Params.EndsWith(">"))
|
||||
if (Params.EndsWith('>'))
|
||||
{
|
||||
writer.Write(" ");
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -22,6 +22,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
0x40000000
|
||||
};
|
||||
|
||||
private const ulong RegionAlignment = 0x200000;
|
||||
|
||||
public const int PageSize = 0x1000;
|
||||
|
||||
private const int KMemoryBlockSize = 0x40;
|
||||
@ -53,6 +55,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
public ulong TlsIoRegionStart { get; private set; }
|
||||
public ulong TlsIoRegionEnd { get; private set; }
|
||||
|
||||
public ulong AslrRegionStart { get; private set; }
|
||||
public ulong AslrRegionEnd { get; private set; }
|
||||
|
||||
private ulong _heapCapacity;
|
||||
|
||||
public ulong PhysicalMemoryUsage { get; private set; }
|
||||
@ -61,10 +66,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
|
||||
private MemoryRegion _memRegion;
|
||||
|
||||
private bool _aslrDisabled;
|
||||
|
||||
public int AddrSpaceWidth { get; private set; }
|
||||
|
||||
private bool _allocateFromBack;
|
||||
private bool _isKernel;
|
||||
|
||||
private bool _aslrEnabled;
|
||||
@ -78,7 +80,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
private MemoryFillValue _heapFillValue;
|
||||
private MemoryFillValue _ipcFillValue;
|
||||
|
||||
public KPageTableBase(KernelContext context)
|
||||
private ulong _reservedAddressSpaceSize;
|
||||
|
||||
public KPageTableBase(KernelContext context, ulong reservedAddressSpaceSize)
|
||||
{
|
||||
Context = context;
|
||||
|
||||
@ -88,6 +92,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
|
||||
_heapFillValue = MemoryFillValue.Zero;
|
||||
_ipcFillValue = MemoryFillValue.Zero;
|
||||
|
||||
_reservedAddressSpaceSize = reservedAddressSpaceSize;
|
||||
}
|
||||
|
||||
private static readonly int[] AddrSpaceSizes = new int[] { 32, 36, 32, 39 };
|
||||
@ -95,7 +101,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
public Result InitializeForProcess(
|
||||
AddressSpaceType addrSpaceType,
|
||||
bool aslrEnabled,
|
||||
bool aslrDisabled,
|
||||
bool fromBack,
|
||||
MemoryRegion memRegion,
|
||||
ulong address,
|
||||
ulong size,
|
||||
@ -114,7 +120,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
Result result = CreateUserAddressSpace(
|
||||
addrSpaceType,
|
||||
aslrEnabled,
|
||||
aslrDisabled,
|
||||
fromBack,
|
||||
addrSpaceBase,
|
||||
addrSpaceSize,
|
||||
memRegion,
|
||||
@ -130,7 +136,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
return result;
|
||||
}
|
||||
|
||||
private class Region
|
||||
private struct Region
|
||||
{
|
||||
public ulong Start;
|
||||
public ulong End;
|
||||
@ -141,7 +147,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
private Result CreateUserAddressSpace(
|
||||
AddressSpaceType addrSpaceType,
|
||||
bool aslrEnabled,
|
||||
bool aslrDisabled,
|
||||
bool fromBack,
|
||||
ulong addrSpaceStart,
|
||||
ulong addrSpaceEnd,
|
||||
MemoryRegion memRegion,
|
||||
@ -159,7 +165,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
ulong codeRegionSize;
|
||||
ulong stackAndTlsIoStart;
|
||||
ulong stackAndTlsIoEnd;
|
||||
ulong baseAddress;
|
||||
|
||||
switch (addrSpaceType)
|
||||
{
|
||||
@ -170,10 +175,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
tlsIoRegion.Size = 0;
|
||||
CodeRegionStart = 0x200000;
|
||||
codeRegionSize = 0x3fe00000;
|
||||
AslrRegionStart = 0x200000;
|
||||
AslrRegionEnd = AslrRegionStart + 0xffe00000;
|
||||
stackAndTlsIoStart = 0x200000;
|
||||
stackAndTlsIoEnd = 0x40000000;
|
||||
baseAddress = 0x200000;
|
||||
AddrSpaceWidth = 32;
|
||||
break;
|
||||
|
||||
case AddressSpaceType.Addr36Bits:
|
||||
@ -183,10 +188,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
tlsIoRegion.Size = 0;
|
||||
CodeRegionStart = 0x8000000;
|
||||
codeRegionSize = 0x78000000;
|
||||
AslrRegionStart = 0x8000000;
|
||||
AslrRegionEnd = AslrRegionStart + 0xff8000000;
|
||||
stackAndTlsIoStart = 0x8000000;
|
||||
stackAndTlsIoEnd = 0x80000000;
|
||||
baseAddress = 0x8000000;
|
||||
AddrSpaceWidth = 36;
|
||||
break;
|
||||
|
||||
case AddressSpaceType.Addr32BitsNoMap:
|
||||
@ -196,23 +201,42 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
tlsIoRegion.Size = 0;
|
||||
CodeRegionStart = 0x200000;
|
||||
codeRegionSize = 0x3fe00000;
|
||||
AslrRegionStart = 0x200000;
|
||||
AslrRegionEnd = AslrRegionStart + 0xffe00000;
|
||||
stackAndTlsIoStart = 0x200000;
|
||||
stackAndTlsIoEnd = 0x40000000;
|
||||
baseAddress = 0x200000;
|
||||
AddrSpaceWidth = 32;
|
||||
break;
|
||||
|
||||
case AddressSpaceType.Addr39Bits:
|
||||
aliasRegion.Size = 0x1000000000;
|
||||
heapRegion.Size = 0x180000000;
|
||||
stackRegion.Size = 0x80000000;
|
||||
tlsIoRegion.Size = 0x1000000000;
|
||||
CodeRegionStart = BitUtils.AlignDown<ulong>(address, 0x200000);
|
||||
codeRegionSize = BitUtils.AlignUp<ulong>(endAddr, 0x200000) - CodeRegionStart;
|
||||
stackAndTlsIoStart = 0;
|
||||
stackAndTlsIoEnd = 0;
|
||||
baseAddress = 0x8000000;
|
||||
AddrSpaceWidth = 39;
|
||||
if (_reservedAddressSpaceSize < addrSpaceEnd)
|
||||
{
|
||||
int addressSpaceWidth = (int)ulong.Log2(_reservedAddressSpaceSize);
|
||||
|
||||
aliasRegion.Size = 1UL << (addressSpaceWidth - 3);
|
||||
heapRegion.Size = 0x180000000;
|
||||
stackRegion.Size = 1UL << (addressSpaceWidth - 8);
|
||||
tlsIoRegion.Size = 1UL << (addressSpaceWidth - 3);
|
||||
CodeRegionStart = BitUtils.AlignDown<ulong>(address, RegionAlignment);
|
||||
codeRegionSize = BitUtils.AlignUp<ulong>(endAddr, RegionAlignment) - CodeRegionStart;
|
||||
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;
|
||||
|
||||
default: throw new ArgumentException(nameof(addrSpaceType));
|
||||
@ -223,11 +247,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
ulong mapBaseAddress;
|
||||
ulong mapAvailableSize;
|
||||
|
||||
if (CodeRegionStart - baseAddress >= addrSpaceEnd - CodeRegionEnd)
|
||||
if (CodeRegionStart - AslrRegionStart >= addrSpaceEnd - CodeRegionEnd)
|
||||
{
|
||||
// Has more space before the start of the code region.
|
||||
mapBaseAddress = baseAddress;
|
||||
mapAvailableSize = CodeRegionStart - baseAddress;
|
||||
mapBaseAddress = AslrRegionStart;
|
||||
mapAvailableSize = CodeRegionStart - AslrRegionStart;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -254,14 +278,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
|
||||
if (aslrEnabled)
|
||||
{
|
||||
aliasRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset >> 21) << 21;
|
||||
heapRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset >> 21) << 21;
|
||||
stackRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset >> 21) << 21;
|
||||
tlsIoRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset >> 21) << 21;
|
||||
aliasRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset / RegionAlignment) * RegionAlignment;
|
||||
heapRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset / RegionAlignment) * RegionAlignment;
|
||||
stackRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset / RegionAlignment) * RegionAlignment;
|
||||
tlsIoRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset / RegionAlignment) * RegionAlignment;
|
||||
}
|
||||
|
||||
// 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.End = aliasRegion.Start + aliasRegion.Size;
|
||||
heapRegion.Start = mapBaseAddress + heapRegion.AslrOffset;
|
||||
@ -271,12 +295,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
tlsIoRegion.Start = mapBaseAddress + tlsIoRegion.AslrOffset;
|
||||
tlsIoRegion.End = tlsIoRegion.Start + tlsIoRegion.Size;
|
||||
|
||||
SortRegion(heapRegion, aliasRegion);
|
||||
SortRegion(ref aliasRegion, ref heapRegion, true);
|
||||
|
||||
if (stackRegion.Size != 0)
|
||||
{
|
||||
SortRegion(stackRegion, aliasRegion);
|
||||
SortRegion(stackRegion, heapRegion);
|
||||
stackRegion.Start = mapBaseAddress + stackRegion.AslrOffset;
|
||||
stackRegion.End = stackRegion.Start + stackRegion.Size;
|
||||
|
||||
SortRegion(ref aliasRegion, ref stackRegion);
|
||||
SortRegion(ref heapRegion, ref stackRegion);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -286,9 +313,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
|
||||
if (tlsIoRegion.Size != 0)
|
||||
{
|
||||
SortRegion(tlsIoRegion, aliasRegion);
|
||||
SortRegion(tlsIoRegion, heapRegion);
|
||||
SortRegion(tlsIoRegion, stackRegion);
|
||||
tlsIoRegion.Start = mapBaseAddress + tlsIoRegion.AslrOffset;
|
||||
tlsIoRegion.End = tlsIoRegion.Start + tlsIoRegion.Size;
|
||||
|
||||
SortRegion(ref aliasRegion, ref tlsIoRegion);
|
||||
SortRegion(ref heapRegion, ref tlsIoRegion);
|
||||
|
||||
if (stackRegion.Size != 0)
|
||||
{
|
||||
SortRegion(ref stackRegion, ref tlsIoRegion);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -312,11 +346,27 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
PhysicalMemoryUsage = 0;
|
||||
|
||||
_memRegion = memRegion;
|
||||
_aslrDisabled = aslrDisabled;
|
||||
_allocateFromBack = fromBack;
|
||||
|
||||
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)
|
||||
{
|
||||
return (ulong)GetRandomValue((long)min, (long)max);
|
||||
@ -332,20 +382,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
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)
|
||||
{
|
||||
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 (addressTruncated < addressRounded)
|
||||
{
|
||||
dstFirstPagePa = GetMemoryRegionManager().AllocatePagesContiguous(Context, 1, _aslrDisabled);
|
||||
dstFirstPagePa = GetMemoryRegionManager().AllocatePagesContiguous(Context, 1, _allocateFromBack);
|
||||
|
||||
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 (endAddrTruncated < endAddrRounded && (addressTruncated == addressRounded || addressTruncated < endAddrTruncated))
|
||||
{
|
||||
dstLastPagePa = GetMemoryRegionManager().AllocatePagesContiguous(Context, 1, _aslrDisabled);
|
||||
dstLastPagePa = GetMemoryRegionManager().AllocatePagesContiguous(Context, 1, _allocateFromBack);
|
||||
|
||||
if (dstLastPagePa == 0)
|
||||
{
|
||||
@ -2799,38 +2835,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
|
||||
public ulong GetAddrSpaceBaseAddr()
|
||||
{
|
||||
if (AddrSpaceWidth == 36 || AddrSpaceWidth == 39)
|
||||
{
|
||||
return 0x8000000;
|
||||
}
|
||||
else if (AddrSpaceWidth == 32)
|
||||
{
|
||||
return 0x200000;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Invalid address space width!");
|
||||
}
|
||||
return AslrRegionStart;
|
||||
}
|
||||
|
||||
public ulong GetAddrSpaceSize()
|
||||
{
|
||||
if (AddrSpaceWidth == 36)
|
||||
{
|
||||
return 0xff8000000;
|
||||
}
|
||||
else if (AddrSpaceWidth == 39)
|
||||
{
|
||||
return 0x7ff8000000;
|
||||
}
|
||||
else if (AddrSpaceWidth == 32)
|
||||
{
|
||||
return 0xffe00000;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Invalid address space width!");
|
||||
}
|
||||
return AslrRegionEnd - AslrRegionStart;
|
||||
}
|
||||
|
||||
private static ulong GetDramAddressFromPa(ulong pa)
|
||||
|
@ -8,6 +8,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
{
|
||||
IVirtualMemoryManager AddressSpace { get; }
|
||||
|
||||
ulong AddressSpaceSize { get; }
|
||||
|
||||
IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks);
|
||||
void Execute(IExecutionContext context, ulong codeAddress);
|
||||
void InvalidateCacheRegion(ulong address, ulong size);
|
||||
|
@ -40,8 +40,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
|
||||
public ProcessState State { get; private set; }
|
||||
|
||||
private object _processLock;
|
||||
private object _threadingLock;
|
||||
private readonly object _processLock = new();
|
||||
private readonly object _threadingLock = new();
|
||||
|
||||
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)
|
||||
{
|
||||
_processLock = new object();
|
||||
_threadingLock = new object();
|
||||
|
||||
AddressArbiter = new KAddressArbiter(context);
|
||||
|
||||
_fullTlsPages = new SortedDictionary<ulong, KTlsPageInfo>();
|
||||
@ -1085,7 +1082,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
|
||||
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)
|
||||
|
@ -8,9 +8,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
{
|
||||
public IVirtualMemoryManager AddressSpace { get; }
|
||||
|
||||
public ProcessContext(IVirtualMemoryManager asManager)
|
||||
public ulong AddressSpaceSize { get; }
|
||||
|
||||
public ProcessContext(IVirtualMemoryManager asManager, ulong addressSpaceSize)
|
||||
{
|
||||
AddressSpace = asManager;
|
||||
AddressSpaceSize = addressSpaceSize;
|
||||
}
|
||||
|
||||
public IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks)
|
||||
|
@ -6,7 +6,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -206,7 +206,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
|
||||
public bool WaitingInArbitration { get; set; }
|
||||
|
||||
private object _activityOperationLock;
|
||||
private readonly object _activityOperationLock = new();
|
||||
|
||||
public KThread(KernelContext context) : base(context)
|
||||
{
|
||||
@ -123,8 +123,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
|
||||
_mutexWaiters = new LinkedList<KThread>();
|
||||
_pinnedWaiters = new LinkedList<KThread>();
|
||||
|
||||
_activityOperationLock = new object();
|
||||
}
|
||||
|
||||
public Result Initialize(
|
||||
|
@ -17,8 +17,8 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
||||
private KEvent _accumulatedSuspendedTickChangedEvent;
|
||||
private int _accumulatedSuspendedTickChangedEventHandle;
|
||||
|
||||
private object _fatalSectionLock = new object();
|
||||
private int _fatalSectionCount;
|
||||
private readonly object _fatalSectionLock = new();
|
||||
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.
|
||||
private ulong _accumulatedSuspendedTickValue = 0;
|
||||
@ -429,4 +429,4 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
||||
return ResultCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
|
||||
private readonly UserId _userId;
|
||||
private readonly FriendServicePermissionLevel _permissionLevel;
|
||||
|
||||
private readonly object _lock = new object();
|
||||
private readonly object _lock = new();
|
||||
|
||||
private KEvent _notificationEvent;
|
||||
private int _notificationEventHandle = 0;
|
||||
|
@ -3,7 +3,7 @@ using System;
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
[Flags]
|
||||
public enum ControllerType : int
|
||||
public enum ControllerType
|
||||
{
|
||||
None,
|
||||
ProController = 1 << 0,
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
public enum NpadIdType : int
|
||||
public enum NpadIdType
|
||||
{
|
||||
Player1 = 0,
|
||||
Player2 = 1,
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
public enum PlayerIndex : int
|
||||
public enum PlayerIndex
|
||||
{
|
||||
Player1 = 0,
|
||||
Player2 = 1,
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad
|
||||
{
|
||||
[Flags]
|
||||
enum DeviceType : int
|
||||
enum DeviceType
|
||||
{
|
||||
None = 0,
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad
|
||||
{
|
||||
enum NpadBatteryLevel : int
|
||||
enum NpadBatteryLevel
|
||||
{
|
||||
Percent0,
|
||||
Percent25,
|
||||
|
@ -775,7 +775,7 @@ namespace Ryujinx.HLE.HOS.Services.Mii.Types
|
||||
|
||||
private static ReadOnlySpan<ElementInfo> ElementInfos => MemoryMarshal.Cast<byte, ElementInfo>(ElementInfoArray);
|
||||
|
||||
private enum ElementInfoIndex : int
|
||||
private enum ElementInfoIndex
|
||||
{
|
||||
HairType,
|
||||
Height,
|
||||
|
@ -6,7 +6,7 @@ namespace Ryujinx.HLE.HOS.Services.Mii.Types
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x10)]
|
||||
struct CreateId : IEquatable<CreateId>
|
||||
{
|
||||
public UInt128 Raw;
|
||||
public readonly UInt128 Raw;
|
||||
|
||||
public bool IsNull => Raw == UInt128.Zero;
|
||||
public bool IsValid => !IsNull && ((Raw >> 64) & 0xC0) == 0x80;
|
||||
|
@ -21,7 +21,7 @@ namespace Ryujinx.HLE.HOS.Services.Mii.Types
|
||||
};
|
||||
|
||||
[Flags]
|
||||
public enum BeardAndMustacheFlag : int
|
||||
public enum BeardAndMustacheFlag
|
||||
{
|
||||
Beard = 1,
|
||||
Mustache
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.HLE.HOS.Services.Mii.Types
|
||||
{
|
||||
enum Source : int
|
||||
enum Source
|
||||
{
|
||||
Database,
|
||||
Default
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace Ryujinx.HLE.HOS.Services.Mii.Types
|
||||
{
|
||||
[Flags]
|
||||
enum SourceFlag : int
|
||||
enum SourceFlag
|
||||
{
|
||||
Database = 1 << Source.Database,
|
||||
Default = 1 << Source.Default,
|
||||
|
@ -95,7 +95,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
||||
{
|
||||
VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId);
|
||||
|
||||
if (virtualAmiiboFile.ApplicationAreas.Any(item => item.ApplicationAreaId == applicationAreaId))
|
||||
if (virtualAmiiboFile.ApplicationAreas.Exists(item => item.ApplicationAreaId == applicationAreaId))
|
||||
{
|
||||
_openedApplicationAreaId = applicationAreaId;
|
||||
|
||||
@ -124,7 +124,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
||||
{
|
||||
VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId);
|
||||
|
||||
if (virtualAmiiboFile.ApplicationAreas.Any(item => item.ApplicationAreaId == applicationAreaId))
|
||||
if (virtualAmiiboFile.ApplicationAreas.Exists(item => item.ApplicationAreaId == applicationAreaId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -144,7 +144,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
||||
{
|
||||
VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId);
|
||||
|
||||
if (virtualAmiiboFile.ApplicationAreas.Any(item => item.ApplicationAreaId == _openedApplicationAreaId))
|
||||
if (virtualAmiiboFile.ApplicationAreas.Exists(item => item.ApplicationAreaId == _openedApplicationAreaId))
|
||||
{
|
||||
for (int i = 0; i < virtualAmiiboFile.ApplicationAreas.Count; i++)
|
||||
{
|
||||
|
@ -24,7 +24,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl
|
||||
private NvFence _previousFailingFence;
|
||||
private uint _failingCount;
|
||||
|
||||
public readonly object Lock = new object();
|
||||
public readonly object Lock = new();
|
||||
|
||||
/// <summary>
|
||||
/// Max failing count until waiting on CPU.
|
||||
|
@ -17,7 +17,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl
|
||||
|
||||
private Switch _device;
|
||||
|
||||
private object _syncpointAllocatorLock = new object();
|
||||
private readonly object _syncpointAllocatorLock = new();
|
||||
|
||||
public NvHostSyncpt(Switch device)
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices
|
||||
{
|
||||
enum NvInternalResult : int
|
||||
enum NvInternalResult
|
||||
{
|
||||
Success = 0,
|
||||
OperationNotPermitted = -1,
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
|
||||
{
|
||||
enum NvMapHandleParam : int
|
||||
enum NvMapHandleParam
|
||||
{
|
||||
Size = 1,
|
||||
Align = 2,
|
||||
|
@ -10,7 +10,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
||||
{
|
||||
private static ConcurrentDictionary<ulong, BsdContext> _registry = new ConcurrentDictionary<ulong, BsdContext>();
|
||||
|
||||
private readonly object _lock = new object();
|
||||
private readonly object _lock = new();
|
||||
|
||||
private List<IFileDescriptor> _fds;
|
||||
|
||||
|
@ -5,7 +5,7 @@ using System.Net.Sockets;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
||||
{
|
||||
interface ISocket : IDisposable, IFileDescriptor
|
||||
interface ISocket : IFileDescriptor
|
||||
{
|
||||
IPEndPoint RemoteEndPoint { get; }
|
||||
IPEndPoint LocalEndPoint { get; }
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user