Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
548bfd60a2 | ||
|
65778a6b78 | ||
|
f4e879a1e6 |
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Common
|
||||
@@ -7,49 +8,15 @@ namespace Ryujinx.Common
|
||||
public static class BinaryReaderExtensions
|
||||
{
|
||||
public unsafe static T ReadStruct<T>(this BinaryReader reader)
|
||||
where T : struct
|
||||
where T : unmanaged
|
||||
{
|
||||
int size = Marshal.SizeOf<T>();
|
||||
|
||||
byte[] data = reader.ReadBytes(size);
|
||||
|
||||
fixed (byte* ptr = data)
|
||||
{
|
||||
return Marshal.PtrToStructure<T>((IntPtr)ptr);
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe static T[] ReadStructArray<T>(this BinaryReader reader, int count)
|
||||
where T : struct
|
||||
{
|
||||
int size = Marshal.SizeOf<T>();
|
||||
|
||||
T[] result = new T[count];
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
byte[] data = reader.ReadBytes(size);
|
||||
|
||||
fixed (byte* ptr = data)
|
||||
{
|
||||
result[i] = Marshal.PtrToStructure<T>((IntPtr)ptr);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return MemoryMarshal.Cast<byte, T>(reader.ReadBytes(Unsafe.SizeOf<T>()))[0];
|
||||
}
|
||||
|
||||
public unsafe static void WriteStruct<T>(this BinaryWriter writer, T value)
|
||||
where T : struct
|
||||
where T : unmanaged
|
||||
{
|
||||
long size = Marshal.SizeOf<T>();
|
||||
|
||||
byte[] data = new byte[size];
|
||||
|
||||
fixed (byte* ptr = data)
|
||||
{
|
||||
Marshal.StructureToPtr<T>(value, (IntPtr)ptr, false);
|
||||
}
|
||||
ReadOnlySpan<byte> data = MemoryMarshal.Cast<T, byte>(MemoryMarshal.CreateReadOnlySpan(ref value, 1));
|
||||
|
||||
writer.Write(data);
|
||||
}
|
||||
|
@@ -180,6 +180,37 @@ namespace Ryujinx.Cpu.Jit
|
||||
WriteImpl(va, data);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan<byte> data)
|
||||
{
|
||||
if (data.Length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
SignalMemoryTracking(va, (ulong)data.Length, false);
|
||||
|
||||
if (IsContiguousAndMapped(va, data.Length))
|
||||
{
|
||||
var target = _backingMemory.GetSpan(GetPhysicalAddressInternal(va), data.Length);
|
||||
|
||||
bool changed = !data.SequenceEqual(target);
|
||||
|
||||
if (changed)
|
||||
{
|
||||
data.CopyTo(target);
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteImpl(va, data);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes data to CPU mapped memory.
|
||||
/// </summary>
|
||||
|
@@ -307,6 +307,34 @@ namespace Ryujinx.Cpu.Jit
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan<byte> data)
|
||||
{
|
||||
try
|
||||
{
|
||||
SignalMemoryTracking(va, (ulong)data.Length, false);
|
||||
|
||||
Span<byte> target = _addressSpaceMirror.GetSpan(va, data.Length);
|
||||
bool changed = !data.SequenceEqual(target);
|
||||
|
||||
if (changed)
|
||||
{
|
||||
data.CopyTo(target);
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
catch (InvalidMemoryRegionException)
|
||||
{
|
||||
if (_invalidAccessHandler == null || !_invalidAccessHandler(va))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
|
||||
{
|
||||
|
@@ -1,6 +1,7 @@
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
@@ -23,34 +24,18 @@ namespace Ryujinx.Cpu
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe static T Read<T>(IVirtualMemoryManager memory, ulong position) where T : struct
|
||||
public unsafe static T Read<T>(IVirtualMemoryManager memory, ulong position) where T : unmanaged
|
||||
{
|
||||
long size = Marshal.SizeOf<T>();
|
||||
|
||||
byte[] data = new byte[size];
|
||||
|
||||
memory.Read(position, data);
|
||||
|
||||
fixed (byte* ptr = data)
|
||||
{
|
||||
return Marshal.PtrToStructure<T>((IntPtr)ptr);
|
||||
}
|
||||
return MemoryMarshal.Cast<byte, T>(memory.GetSpan(position, Unsafe.SizeOf<T>()))[0];
|
||||
}
|
||||
|
||||
public unsafe static ulong Write<T>(IVirtualMemoryManager memory, ulong position, T value) where T : struct
|
||||
public unsafe static ulong Write<T>(IVirtualMemoryManager memory, ulong position, T value) where T : unmanaged
|
||||
{
|
||||
long size = Marshal.SizeOf<T>();
|
||||
|
||||
byte[] data = new byte[size];
|
||||
|
||||
fixed (byte* ptr = data)
|
||||
{
|
||||
Marshal.StructureToPtr<T>(value, (IntPtr)ptr, false);
|
||||
}
|
||||
ReadOnlySpan<byte> data = MemoryMarshal.Cast<T, byte>(MemoryMarshal.CreateReadOnlySpan(ref value, 1));
|
||||
|
||||
memory.Write(position, data);
|
||||
|
||||
return (ulong)size;
|
||||
return (ulong)data.Length;
|
||||
}
|
||||
|
||||
public static string ReadAsciiString(IVirtualMemoryManager memory, ulong position, long maxSize = -1)
|
||||
|
@@ -8,6 +8,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// </summary>
|
||||
class ConstantBufferUpdater
|
||||
{
|
||||
private const int UniformDataCacheSize = 512;
|
||||
|
||||
private readonly GpuChannel _channel;
|
||||
private readonly DeviceStateWithShadow<ThreedClassState> _state;
|
||||
|
||||
@@ -16,6 +18,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
private ulong _ubBeginCpuAddress = 0;
|
||||
private ulong _ubFollowUpAddress = 0;
|
||||
private ulong _ubByteCount = 0;
|
||||
private int _ubIndex = 0;
|
||||
private int[] _ubData = new int[UniformDataCacheSize];
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the constant buffer updater.
|
||||
@@ -108,9 +112,16 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
if (_ubFollowUpAddress != 0)
|
||||
{
|
||||
var memoryManager = _channel.MemoryManager;
|
||||
memoryManager.Physical.BufferCache.ForceDirty(memoryManager, _ubFollowUpAddress - _ubByteCount, _ubByteCount);
|
||||
|
||||
Span<byte> data = MemoryMarshal.Cast<int, byte>(_ubData.AsSpan(0, (int)(_ubByteCount / 4)));
|
||||
|
||||
if (memoryManager.Physical.WriteWithRedundancyCheck(_ubBeginCpuAddress, data))
|
||||
{
|
||||
memoryManager.Physical.BufferCache.ForceDirty(memoryManager, _ubFollowUpAddress - _ubByteCount, _ubByteCount);
|
||||
}
|
||||
|
||||
_ubFollowUpAddress = 0;
|
||||
_ubIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +135,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
ulong address = uniformBuffer.Address.Pack() + (uint)uniformBuffer.Offset;
|
||||
|
||||
if (_ubFollowUpAddress != address)
|
||||
if (_ubFollowUpAddress != address || _ubIndex == _ubData.Length)
|
||||
{
|
||||
FlushUboDirty();
|
||||
|
||||
@@ -132,8 +143,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_ubBeginCpuAddress = _channel.MemoryManager.Translate(address);
|
||||
}
|
||||
|
||||
var byteData = MemoryMarshal.Cast<int, byte>(MemoryMarshal.CreateSpan(ref argument, 1));
|
||||
_channel.MemoryManager.Physical.WriteUntracked(_ubBeginCpuAddress + _ubByteCount, byteData);
|
||||
_ubData[_ubIndex++] = argument;
|
||||
|
||||
_ubFollowUpAddress = address + 4;
|
||||
_ubByteCount += 4;
|
||||
@@ -153,7 +163,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
ulong size = (ulong)data.Length * 4;
|
||||
|
||||
if (_ubFollowUpAddress != address)
|
||||
if (_ubFollowUpAddress != address || _ubIndex + data.Length > _ubData.Length)
|
||||
{
|
||||
FlushUboDirty();
|
||||
|
||||
@@ -161,8 +171,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_ubBeginCpuAddress = _channel.MemoryManager.Translate(address);
|
||||
}
|
||||
|
||||
var byteData = MemoryMarshal.Cast<int, byte>(data);
|
||||
_channel.MemoryManager.Physical.WriteUntracked(_ubBeginCpuAddress + _ubByteCount, byteData);
|
||||
data.CopyTo(_ubData.AsSpan(_ubIndex));
|
||||
_ubIndex += data.Length;
|
||||
|
||||
_ubFollowUpAddress = address + size;
|
||||
_ubByteCount += size;
|
||||
|
@@ -242,6 +242,19 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
WriteImpl(range, data, _cpuMemory.WriteUntracked);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes data to the application process, returning false if the data was not changed.
|
||||
/// This triggers read memory tracking, as a redundancy check would be useless if the data is not up to date.
|
||||
/// </summary>
|
||||
/// <remarks>The memory manager can return that memory has changed when it hasn't to avoid expensive data copies.</remarks>
|
||||
/// <param name="address">Address to write into</param>
|
||||
/// <param name="data">Data to be written</param>
|
||||
/// <returns>True if the data was changed, false otherwise</returns>
|
||||
public bool WriteWithRedundancyCheck(ulong address, ReadOnlySpan<byte> data)
|
||||
{
|
||||
return _cpuMemory.WriteWithRedundancyCheck(address, data);
|
||||
}
|
||||
|
||||
private delegate void WriteCallback(ulong address, ReadOnlySpan<byte> data);
|
||||
|
||||
/// <summary>
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard;
|
||||
using Ryujinx.HLE.HOS.Services.Am.AppletAE;
|
||||
@@ -9,6 +10,7 @@ using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
@@ -78,13 +80,13 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
var launchParams = _normalSession.Pop();
|
||||
var keyboardConfig = _normalSession.Pop();
|
||||
|
||||
_isBackground = keyboardConfig.Length == Marshal.SizeOf<SoftwareKeyboardInitialize>();
|
||||
_isBackground = keyboardConfig.Length == Unsafe.SizeOf<SoftwareKeyboardInitialize>();
|
||||
|
||||
if (_isBackground)
|
||||
{
|
||||
// Initialize the keyboard applet in background mode.
|
||||
|
||||
_keyboardBackgroundInitialize = ReadStruct<SoftwareKeyboardInitialize>(keyboardConfig);
|
||||
_keyboardBackgroundInitialize = MemoryMarshal.Read<SoftwareKeyboardInitialize>(keyboardConfig);
|
||||
_backgroundState = InlineKeyboardState.Uninitialized;
|
||||
|
||||
if (_device.UiHandler == null)
|
||||
@@ -342,7 +344,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
else
|
||||
{
|
||||
int wordsCount = reader.ReadInt32();
|
||||
int wordSize = Marshal.SizeOf<SoftwareKeyboardUserWord>();
|
||||
int wordSize = Unsafe.SizeOf<SoftwareKeyboardUserWord>();
|
||||
remaining = stream.Length - stream.Position;
|
||||
|
||||
if (wordsCount > MaxUserWords)
|
||||
@@ -359,8 +361,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
|
||||
for (int word = 0; word < wordsCount; word++)
|
||||
{
|
||||
byte[] wordData = reader.ReadBytes(wordSize);
|
||||
_keyboardBackgroundUserWords[word] = ReadStruct<SoftwareKeyboardUserWord>(wordData);
|
||||
_keyboardBackgroundUserWords[word] = reader.ReadStruct<SoftwareKeyboardUserWord>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -369,27 +370,25 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
case InlineKeyboardRequest.SetCustomizeDic:
|
||||
// Read the custom dic data.
|
||||
remaining = stream.Length - stream.Position;
|
||||
if (remaining != Marshal.SizeOf<SoftwareKeyboardCustomizeDic>())
|
||||
if (remaining != Unsafe.SizeOf<SoftwareKeyboardCustomizeDic>())
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceAm, $"Received invalid Software Keyboard Customize Dic of {remaining} bytes");
|
||||
}
|
||||
else
|
||||
{
|
||||
var keyboardDicData = reader.ReadBytes((int)remaining);
|
||||
_keyboardBackgroundDic = ReadStruct<SoftwareKeyboardCustomizeDic>(keyboardDicData);
|
||||
_keyboardBackgroundDic = reader.ReadStruct<SoftwareKeyboardCustomizeDic>();
|
||||
}
|
||||
break;
|
||||
case InlineKeyboardRequest.SetCustomizedDictionaries:
|
||||
// Read the custom dictionaries data.
|
||||
remaining = stream.Length - stream.Position;
|
||||
if (remaining != Marshal.SizeOf<SoftwareKeyboardDictSet>())
|
||||
if (remaining != Unsafe.SizeOf<SoftwareKeyboardDictSet>())
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceAm, $"Received invalid Software Keyboard DictSet of {remaining} bytes");
|
||||
}
|
||||
else
|
||||
{
|
||||
var keyboardDictData = reader.ReadBytes((int)remaining);
|
||||
_keyboardBackgroundDictSet = ReadStruct<SoftwareKeyboardDictSet>(keyboardDictData);
|
||||
_keyboardBackgroundDictSet = reader.ReadStruct<SoftwareKeyboardDictSet>();
|
||||
}
|
||||
break;
|
||||
case InlineKeyboardRequest.Calc:
|
||||
|
@@ -5,10 +5,9 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
/// <summary>
|
||||
/// A structure used by SetCustomizeDic request to software keyboard.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x70)]
|
||||
struct SoftwareKeyboardCustomizeDic
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 112)]
|
||||
public byte[] Unknown;
|
||||
// Unknown
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
{
|
||||
@@ -21,8 +22,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
/// <summary>
|
||||
/// Array of word entries in the buffer.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)]
|
||||
public ulong[] Entries;
|
||||
public Array24<ulong> Entries;
|
||||
|
||||
/// <summary>
|
||||
/// Number of used entries in the Entries field.
|
||||
|
@@ -5,10 +5,9 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
/// <summary>
|
||||
/// A structure used by SetUserWordInfo request to the software keyboard.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x64)]
|
||||
struct SoftwareKeyboardUserWord
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
|
||||
public byte[] Unknown;
|
||||
// Unknown
|
||||
}
|
||||
}
|
||||
|
@@ -1,9 +1,12 @@
|
||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 0x8, CharSet = CharSet.Ansi)]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 0x8)]
|
||||
struct UserPresence
|
||||
{
|
||||
public UserId UserId;
|
||||
@@ -13,15 +16,20 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService
|
||||
[MarshalAs(UnmanagedType.I1)]
|
||||
public bool SamePresenceGroupApplication;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x3)]
|
||||
public char[] Unknown;
|
||||
public Array3<byte> Unknown;
|
||||
private AppKeyValueStorageHolder _appKeyValueStorage;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0xC0)]
|
||||
public char[] AppKeyValueStorage;
|
||||
public Span<byte> AppKeyValueStorage => MemoryMarshal.Cast<AppKeyValueStorageHolder, byte>(MemoryMarshal.CreateSpan(ref _appKeyValueStorage, AppKeyValueStorageHolder.Size));
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 0x1, Size = Size)]
|
||||
private struct AppKeyValueStorageHolder
|
||||
{
|
||||
public const int Size = 0xC0;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"UserPresence {{ UserId: {UserId}, LastTimeOnlineTimestamp: {LastTimeOnlineTimestamp}, Status: {Status}, AppKeyValueStorage: {AppKeyValueStorage} }}";
|
||||
return $"UserPresence {{ UserId: {UserId}, LastTimeOnlineTimestamp: {LastTimeOnlineTimestamp}, Status: {Status}, AppKeyValueStorage: {Encoding.ASCII.GetString(AppKeyValueStorage)} }}";
|
||||
}
|
||||
}
|
||||
}
|
@@ -236,23 +236,14 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
|
||||
ulong position = context.Request.PtrBuff[0].Position;
|
||||
ulong size = context.Request.PtrBuff[0].Size;
|
||||
|
||||
byte[] bufferContent = new byte[size];
|
||||
|
||||
context.Memory.Read(position, bufferContent);
|
||||
ReadOnlySpan<UserPresence> userPresenceInputArray = MemoryMarshal.Cast<byte, UserPresence>(context.Memory.GetSpan(position, (int)size));
|
||||
|
||||
if (uuid.IsNull)
|
||||
{
|
||||
return ResultCode.InvalidArgument;
|
||||
}
|
||||
|
||||
int elementCount = bufferContent.Length / Marshal.SizeOf<UserPresence>();
|
||||
|
||||
using (BinaryReader bufferReader = new BinaryReader(new MemoryStream(bufferContent)))
|
||||
{
|
||||
UserPresence[] userPresenceInputArray = bufferReader.ReadStructArray<UserPresence>(elementCount);
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = uuid.ToString(), userPresenceInputArray });
|
||||
}
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = uuid.ToString(), userPresenceInputArray = userPresenceInputArray.ToArray() });
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
@@ -1,15 +1,13 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 0x8, Size = 0x10)]
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x10)]
|
||||
struct NotificationInfo
|
||||
{
|
||||
public NotificationEventType Type;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x4)]
|
||||
public char[] Padding;
|
||||
|
||||
private Array4<byte> _padding;
|
||||
public long NetworkUserIdPlaceholder;
|
||||
}
|
||||
}
|
@@ -5,6 +5,7 @@ using Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService.Types;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService
|
||||
@@ -75,7 +76,7 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService
|
||||
|
||||
for (int i = 0; i < filteredApplicationPlayStatistics.Count(); i++)
|
||||
{
|
||||
MemoryHelper.Write(context.Memory, outputPosition + (ulong)(i * Marshal.SizeOf<ApplicationPlayStatistics>()), filteredApplicationPlayStatistics.ElementAt(i).Value);
|
||||
MemoryHelper.Write(context.Memory, outputPosition + (ulong)(i * Unsafe.SizeOf<ApplicationPlayStatistics>()), filteredApplicationPlayStatistics.ElementAt(i).Value);
|
||||
}
|
||||
|
||||
context.ResponseData.Write(filteredApplicationPlayStatistics.Count());
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
@@ -16,14 +17,22 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
public CalendarAdditionalInfo NetworkCalendarAdditionalTime;
|
||||
public SteadyClockTimePoint SteadyClockTimePoint;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x24)]
|
||||
public char[] LocationName;
|
||||
private LocationNameStorageHolder _locationName;
|
||||
|
||||
public Span<byte> LocationName => MemoryMarshal.Cast<LocationNameStorageHolder, byte>(MemoryMarshal.CreateSpan(ref _locationName, LocationNameStorageHolder.Size));
|
||||
|
||||
[MarshalAs(UnmanagedType.I1)]
|
||||
public bool IsAutomaticCorrectionEnabled;
|
||||
public byte Type;
|
||||
public ushort Unknown;
|
||||
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1, Size = Size)]
|
||||
private struct LocationNameStorageHolder
|
||||
{
|
||||
public const int Size = 0x24;
|
||||
}
|
||||
|
||||
public static ResultCode GetCurrentTime(out long currentTime, SteadyClockTimePoint steadyClockTimePoint, SystemClockContext context)
|
||||
{
|
||||
currentTime = 0;
|
||||
|
@@ -8,7 +8,9 @@ using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Time
|
||||
{
|
||||
@@ -281,7 +283,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||
{
|
||||
byte type = context.RequestData.ReadByte();
|
||||
|
||||
context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf<ClockSnapshot>());
|
||||
context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Unsafe.SizeOf<ClockSnapshot>());
|
||||
|
||||
context.RequestData.BaseStream.Position += 7;
|
||||
|
||||
@@ -372,12 +374,9 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||
return result;
|
||||
}
|
||||
|
||||
char[] tzName = deviceLocationName.ToCharArray();
|
||||
char[] locationName = new char[0x24];
|
||||
ReadOnlySpan<byte> tzName = Encoding.ASCII.GetBytes(deviceLocationName);
|
||||
|
||||
Array.Copy(tzName, locationName, tzName.Length);
|
||||
|
||||
clockSnapshot.LocationName = locationName;
|
||||
tzName.CopyTo(clockSnapshot.LocationName);
|
||||
|
||||
result = ClockSnapshot.GetCurrentTime(out clockSnapshot.UserTime, currentTimePoint, clockSnapshot.UserContext);
|
||||
|
||||
@@ -414,7 +413,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||
|
||||
private ClockSnapshot ReadClockSnapshotFromBuffer(ServiceCtx context, IpcPtrBuffDesc ipcDesc)
|
||||
{
|
||||
Debug.Assert(ipcDesc.Size == (ulong)Marshal.SizeOf<ClockSnapshot>());
|
||||
Debug.Assert(ipcDesc.Size == (ulong)Unsafe.SizeOf<ClockSnapshot>());
|
||||
|
||||
byte[] temp = new byte[ipcDesc.Size];
|
||||
|
||||
|
@@ -5,6 +5,7 @@ using Ryujinx.HLE.Utilities;
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
@@ -890,14 +891,14 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
|
||||
|
||||
long streamLength = reader.BaseStream.Length;
|
||||
|
||||
if (streamLength < Marshal.SizeOf<TzifHeader>())
|
||||
if (streamLength < Unsafe.SizeOf<TzifHeader>())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TzifHeader header = reader.ReadStruct<TzifHeader>();
|
||||
|
||||
streamLength -= Marshal.SizeOf<TzifHeader>();
|
||||
streamLength -= Unsafe.SizeOf<TzifHeader>();
|
||||
|
||||
int ttisGMTCount = Detzcode32(header.TtisGMTCount);
|
||||
int ttisSTDCount = Detzcode32(header.TtisSTDCount);
|
||||
|
@@ -40,20 +40,16 @@ namespace Ryujinx.Headless.SDL2.Vulkan
|
||||
return (IntPtr)surfaceHandle;
|
||||
}
|
||||
|
||||
// TODO: Fix this in SDL2-CS.
|
||||
[DllImport("SDL2", EntryPoint = "SDL_Vulkan_GetInstanceExtensions", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern SDL_bool SDL_Vulkan_GetInstanceExtensions_Workaround(IntPtr window, out uint count, IntPtr names);
|
||||
|
||||
public unsafe string[] GetRequiredInstanceExtensions()
|
||||
{
|
||||
if (SDL_Vulkan_GetInstanceExtensions_Workaround(WindowHandle, out uint extensionsCount, IntPtr.Zero) == SDL_bool.SDL_TRUE)
|
||||
if (SDL_Vulkan_GetInstanceExtensions(WindowHandle, out uint extensionsCount, IntPtr.Zero) == SDL_bool.SDL_TRUE)
|
||||
{
|
||||
IntPtr[] rawExtensions = new IntPtr[(int)extensionsCount];
|
||||
string[] extensions = new string[(int)extensionsCount];
|
||||
|
||||
fixed (IntPtr* rawExtensionsPtr = rawExtensions)
|
||||
{
|
||||
if (SDL_Vulkan_GetInstanceExtensions_Workaround(WindowHandle, out extensionsCount, (IntPtr)rawExtensionsPtr) == SDL_bool.SDL_TRUE)
|
||||
if (SDL_Vulkan_GetInstanceExtensions(WindowHandle, out extensionsCount, (IntPtr)rawExtensionsPtr) == SDL_bool.SDL_TRUE)
|
||||
{
|
||||
for (int i = 0; i < extensions.Length; i++)
|
||||
{
|
||||
|
@@ -1,16 +1,15 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct ControllerDataRequest
|
||||
{
|
||||
public MessageType Type;
|
||||
public MessageType Type;
|
||||
public SubscriberType SubscriberType;
|
||||
public byte Slot;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
||||
public byte[] MacAddress;
|
||||
public byte Slot;
|
||||
public Array6<byte> MacAddress;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
@@ -27,11 +26,8 @@ namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
||||
public uint DPadAnalog;
|
||||
public ulong MainButtonsAnalog;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
||||
public byte[] Touch1;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
||||
public byte[] Touch2;
|
||||
public Array6<byte> Touch1;
|
||||
public Array6<byte> Touch2;
|
||||
|
||||
public ulong MotionTimestamp;
|
||||
public float AccelerometerX;
|
||||
|
@@ -1,21 +1,20 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct ControllerInfoResponse
|
||||
{
|
||||
public SharedResponse Shared;
|
||||
private byte _zero;
|
||||
public SharedResponse Shared;
|
||||
private byte _zero;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct ControllerInfoRequest
|
||||
{
|
||||
public MessageType Type;
|
||||
public int PortsCount;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||
public byte[] PortIndices;
|
||||
public int PortsCount;
|
||||
public Array4<byte> PortIndices;
|
||||
}
|
||||
}
|
@@ -1,4 +1,5 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
||||
{
|
||||
@@ -11,8 +12,7 @@ namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
||||
public DeviceModelType ModelType;
|
||||
public ConnectionType ConnectionType;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
||||
public byte[] MacAddress;
|
||||
public Array6<byte> MacAddress;
|
||||
public BatteryStatus BatteryStatus;
|
||||
}
|
||||
|
||||
|
@@ -44,6 +44,11 @@ namespace Ryujinx.Memory.Tests
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan<byte> data)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
@@ -136,6 +136,14 @@ namespace Ryujinx.Memory
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan<byte> data)
|
||||
{
|
||||
Write(va, data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
|
||||
{
|
||||
|
@@ -58,6 +58,17 @@ namespace Ryujinx.Memory
|
||||
/// <exception cref="InvalidMemoryRegionException">Throw for unhandled invalid or unmapped memory accesses</exception>
|
||||
void Write(ulong va, ReadOnlySpan<byte> data);
|
||||
|
||||
/// <summary>
|
||||
/// Writes data to the application process, returning false if the data was not changed.
|
||||
/// This triggers read memory tracking, as a redundancy check would be useless if the data is not up to date.
|
||||
/// </summary>
|
||||
/// <remarks>The memory manager can return that memory has changed when it hasn't to avoid expensive data copies.</remarks>
|
||||
/// <param name="va">Virtual address to write the data into</param>
|
||||
/// <param name="data">Data to be written</param>
|
||||
/// <exception cref="InvalidMemoryRegionException">Throw for unhandled invalid or unmapped memory accesses</exception>
|
||||
/// <returns>True if the data was changed, false otherwise</returns>
|
||||
bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan<byte> data);
|
||||
|
||||
void Fill(ulong va, ulong size, byte value)
|
||||
{
|
||||
const int MaxChunkSize = 1 << 24;
|
||||
|
@@ -5,7 +5,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Ryujinx.SDL2-CS" Version="2.0.22-build20" />
|
||||
<PackageReference Include="Ryujinx.SDL2-CS" Version="2.24.2-build21" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@@ -43,6 +43,8 @@ namespace Ryujinx.SDL2.Common
|
||||
|
||||
private SDL2Driver() {}
|
||||
|
||||
private const string SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS = "SDL_JOYSTICK_HIDAPI_COMBINE_JOY_CONS";
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
lock (_lock)
|
||||
@@ -60,6 +62,11 @@ namespace Ryujinx.SDL2.Common
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED, "0");
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1");
|
||||
|
||||
|
||||
// NOTE: As of SDL2 2.24.0, joycons are combined by default but the motion source only come from one of them.
|
||||
// We disable this behavior for now.
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS, "0");
|
||||
|
||||
if (SDL_Init(SdlInitFlags) != 0)
|
||||
{
|
||||
string errorMessage = $"SDL2 initlaization failed with error \"{SDL_GetError()}\"";
|
||||
|
Reference in New Issue
Block a user