Eliminate boxing allocations caused by ISampledData structs (#4556)
* Redesign use of ISampledData for accessing the SamplingNumber value on input data structs. * Always read SamplingNumber as little-endian * Restored field order for SixAxisSensorState. Rework to allow possibility of non-zero offsets for the SamplingNumber field. Set StructLayout Pack=8 - the KeyboardState struct is 4 bytes shorter with any other value. * fix spelling Co-authored-by: riperiperi <rhy3756547@hotmail.com> * set Pack = 1 for ISampledDataStruct types, added Unknown field to KeyboardState * extend size of KeyboardModifier --------- Co-authored-by: riperiperi <rhy3756547@hotmail.com>
This commit is contained in:
parent
c95be55091
commit
49be977588
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common
|
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common
|
||||||
{
|
{
|
||||||
struct AtomicStorage<T> where T: unmanaged
|
struct AtomicStorage<T> where T: unmanaged, ISampledDataStruct
|
||||||
{
|
{
|
||||||
public ulong SamplingNumber;
|
public ulong SamplingNumber;
|
||||||
public T Object;
|
public T Object;
|
||||||
@ -14,9 +14,9 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common
|
|||||||
|
|
||||||
public void SetObject(ref T obj)
|
public void SetObject(ref T obj)
|
||||||
{
|
{
|
||||||
ISampledData samplingProvider = obj as ISampledData;
|
ulong samplingNumber = ISampledDataStruct.GetSamplingNumber(ref obj);
|
||||||
|
|
||||||
Interlocked.Exchange(ref SamplingNumber, samplingProvider.SamplingNumber);
|
Interlocked.Exchange(ref SamplingNumber, samplingNumber);
|
||||||
|
|
||||||
Thread.MemoryBarrier();
|
Thread.MemoryBarrier();
|
||||||
|
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common
|
|
||||||
{
|
|
||||||
interface ISampledData
|
|
||||||
{
|
|
||||||
ulong SamplingNumber { get; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,65 @@
|
|||||||
|
using System;
|
||||||
|
using System.Buffers.Binary;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This is a "marker interface" to add some compile-time safety to a convention-based optimization.
|
||||||
|
///
|
||||||
|
/// Any struct implementing this interface should:
|
||||||
|
/// - use <c>StructLayoutAttribute</c> (and related attributes) to explicity control how the struct is laid out in memory.
|
||||||
|
/// - ensure that the method <c>ISampledDataStruct.GetSamplingNumberFieldOffset()</c> correctly returns the offset, in bytes,
|
||||||
|
/// to the ulong "Sampling Number" field within the struct. Most types have it as the first field, so the default offset is 0.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
///
|
||||||
|
/// <c>
|
||||||
|
/// [StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||||
|
/// struct DebugPadState : ISampledDataStruct
|
||||||
|
/// {
|
||||||
|
/// public ulong SamplingNumber; // 1st field, so no need to add special handling to GetSamplingNumberFieldOffset()
|
||||||
|
/// // other members...
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// [StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||||
|
/// struct SixAxisSensorState : ISampledDataStruct
|
||||||
|
/// {
|
||||||
|
/// public ulong DeltaTime;
|
||||||
|
/// public ulong SamplingNumber; // Not the first field - needs special handling in GetSamplingNumberFieldOffset()
|
||||||
|
/// // other members...
|
||||||
|
/// }
|
||||||
|
/// </c>
|
||||||
|
/// </summary>
|
||||||
|
internal interface ISampledDataStruct
|
||||||
|
{
|
||||||
|
// No Instance Members - marker interface only
|
||||||
|
|
||||||
|
public static ulong GetSamplingNumber<T>(ref T sampledDataStruct) where T : unmanaged, ISampledDataStruct
|
||||||
|
{
|
||||||
|
ReadOnlySpan<T> structSpan = MemoryMarshal.CreateReadOnlySpan(ref sampledDataStruct, 1);
|
||||||
|
|
||||||
|
ReadOnlySpan<byte> byteSpan = MemoryMarshal.Cast<T, byte>(structSpan);
|
||||||
|
|
||||||
|
int fieldOffset = GetSamplingNumberFieldOffset(ref sampledDataStruct);
|
||||||
|
|
||||||
|
if (fieldOffset > 0)
|
||||||
|
{
|
||||||
|
byteSpan = byteSpan.Slice(fieldOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
ulong value = BinaryPrimitives.ReadUInt64LittleEndian(byteSpan);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int GetSamplingNumberFieldOffset<T>(ref T sampledDataStruct) where T : unmanaged, ISampledDataStruct
|
||||||
|
{
|
||||||
|
return sampledDataStruct switch
|
||||||
|
{
|
||||||
|
Npad.SixAxisSensorState _ => sizeof(ulong),
|
||||||
|
_ => 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,7 @@ using System.Threading;
|
|||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common
|
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common
|
||||||
{
|
{
|
||||||
struct RingLifo<T> where T: unmanaged
|
struct RingLifo<T> where T: unmanaged, ISampledDataStruct
|
||||||
{
|
{
|
||||||
private const ulong MaxEntries = 17;
|
private const ulong MaxEntries = 17;
|
||||||
|
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common;
|
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.DebugPad
|
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.DebugPad
|
||||||
{
|
{
|
||||||
struct DebugPadState : ISampledData
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
|
struct DebugPadState : ISampledDataStruct
|
||||||
{
|
{
|
||||||
public ulong SamplingNumber;
|
public ulong SamplingNumber;
|
||||||
public DebugPadAttribute Attributes;
|
public DebugPadAttribute Attributes;
|
||||||
public DebugPadButton Buttons;
|
public DebugPadButton Buttons;
|
||||||
public AnalogStickState AnalogStickR;
|
public AnalogStickState AnalogStickR;
|
||||||
public AnalogStickState AnalogStickL;
|
public AnalogStickState AnalogStickL;
|
||||||
|
|
||||||
ulong ISampledData.SamplingNumber => SamplingNumber;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,8 @@
|
|||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Keyboard
|
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Keyboard
|
||||||
{
|
{
|
||||||
// TODO: This seems entirely wrong
|
|
||||||
[Flags]
|
[Flags]
|
||||||
enum KeyboardModifier : uint
|
enum KeyboardModifier : ulong
|
||||||
{
|
{
|
||||||
None = 0,
|
None = 0,
|
||||||
Control = 1 << 0,
|
Control = 1 << 0,
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common;
|
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Keyboard
|
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Keyboard
|
||||||
{
|
{
|
||||||
struct KeyboardState : ISampledData
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
|
struct KeyboardState : ISampledDataStruct
|
||||||
{
|
{
|
||||||
public ulong SamplingNumber;
|
public ulong SamplingNumber;
|
||||||
public KeyboardModifier Modifiers;
|
public KeyboardModifier Modifiers;
|
||||||
public KeyboardKey Keys;
|
public KeyboardKey Keys;
|
||||||
|
|
||||||
ulong ISampledData.SamplingNumber => SamplingNumber;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common;
|
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Mouse
|
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Mouse
|
||||||
{
|
{
|
||||||
struct MouseState : ISampledData
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
|
struct MouseState : ISampledDataStruct
|
||||||
{
|
{
|
||||||
public ulong SamplingNumber;
|
public ulong SamplingNumber;
|
||||||
public int X;
|
public int X;
|
||||||
@ -13,7 +15,5 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Mouse
|
|||||||
public int WheelDeltaY;
|
public int WheelDeltaY;
|
||||||
public MouseButton Buttons;
|
public MouseButton Buttons;
|
||||||
public MouseAttribute Attributes;
|
public MouseAttribute Attributes;
|
||||||
|
|
||||||
ulong ISampledData.SamplingNumber => SamplingNumber;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common;
|
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad
|
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad
|
||||||
{
|
{
|
||||||
struct NpadCommonState : ISampledData
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
|
struct NpadCommonState : ISampledDataStruct
|
||||||
{
|
{
|
||||||
public ulong SamplingNumber;
|
public ulong SamplingNumber;
|
||||||
public NpadButton Buttons;
|
public NpadButton Buttons;
|
||||||
@ -10,7 +12,5 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad
|
|||||||
public AnalogStickState AnalogStickR;
|
public AnalogStickState AnalogStickR;
|
||||||
public NpadAttribute Attributes;
|
public NpadAttribute Attributes;
|
||||||
private uint _reserved;
|
private uint _reserved;
|
||||||
|
|
||||||
ulong ISampledData.SamplingNumber => SamplingNumber;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common;
|
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad
|
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad
|
||||||
{
|
{
|
||||||
struct NpadGcTriggerState : ISampledData
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
|
struct NpadGcTriggerState : ISampledDataStruct
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0649
|
#pragma warning disable CS0649
|
||||||
public ulong SamplingNumber;
|
public ulong SamplingNumber;
|
||||||
public uint TriggerL;
|
public uint TriggerL;
|
||||||
public uint TriggerR;
|
public uint TriggerR;
|
||||||
#pragma warning restore CS0649
|
#pragma warning restore CS0649
|
||||||
|
|
||||||
ulong ISampledData.SamplingNumber => SamplingNumber;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,9 +1,11 @@
|
|||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common;
|
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad
|
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad
|
||||||
{
|
{
|
||||||
struct SixAxisSensorState : ISampledData
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
|
struct SixAxisSensorState : ISampledDataStruct
|
||||||
{
|
{
|
||||||
public ulong DeltaTime;
|
public ulong DeltaTime;
|
||||||
public ulong SamplingNumber;
|
public ulong SamplingNumber;
|
||||||
@ -13,7 +15,5 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad
|
|||||||
public Array9<float> Direction;
|
public Array9<float> Direction;
|
||||||
public SixAxisSensorAttribute Attributes;
|
public SixAxisSensorAttribute Attributes;
|
||||||
private uint _reserved;
|
private uint _reserved;
|
||||||
|
|
||||||
ulong ISampledData.SamplingNumber => SamplingNumber;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,15 +1,15 @@
|
|||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common;
|
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.TouchScreen
|
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.TouchScreen
|
||||||
{
|
{
|
||||||
struct TouchScreenState : ISampledData
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
|
struct TouchScreenState : ISampledDataStruct
|
||||||
{
|
{
|
||||||
public ulong SamplingNumber;
|
public ulong SamplingNumber;
|
||||||
public int TouchesCount;
|
public int TouchesCount;
|
||||||
private int _reserved;
|
private int _reserved;
|
||||||
public Array16<TouchState> Touches;
|
public Array16<TouchState> Touches;
|
||||||
|
|
||||||
ulong ISampledData.SamplingNumber => SamplingNumber;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user