diff options
-rw-r--r-- | Ryujinx.Audio/Renderer/Server/StateUpdater.cs | 9 | ||||
-rw-r--r-- | Ryujinx.Audio/Renderer/Server/Voice/VoiceState.cs | 4 | ||||
-rw-r--r-- | Ryujinx.Common/Memory/ByteMemoryPool.ByteMemoryPoolBuffer.cs | 51 | ||||
-rw-r--r-- | Ryujinx.Common/Memory/ByteMemoryPool.cs | 108 | ||||
-rw-r--r-- | Ryujinx.HLE/HOS/Ipc/IpcMessage.cs | 123 | ||||
-rw-r--r-- | Ryujinx.HLE/HOS/Kernel/Common/KTimeManager.cs | 17 | ||||
-rw-r--r-- | Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs | 7 | ||||
-rw-r--r-- | Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs | 7 | ||||
-rw-r--r-- | Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs | 35 | ||||
-rw-r--r-- | Ryujinx.HLE/HOS/Services/IpcService.cs | 2 | ||||
-rw-r--r-- | Ryujinx.HLE/HOS/Services/ServerBase.cs | 2 | ||||
-rw-r--r-- | Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs | 21 | ||||
-rw-r--r-- | Ryujinx.Input.SDL2/SDL2Gamepad.cs | 14 |
13 files changed, 297 insertions, 103 deletions
diff --git a/Ryujinx.Audio/Renderer/Server/StateUpdater.cs b/Ryujinx.Audio/Renderer/Server/StateUpdater.cs index 0446cd8c..5cf539c6 100644 --- a/Ryujinx.Audio/Renderer/Server/StateUpdater.cs +++ b/Ryujinx.Audio/Renderer/Server/StateUpdater.cs @@ -11,6 +11,7 @@ using Ryujinx.Audio.Renderer.Server.Voice; using Ryujinx.Audio.Renderer.Utils; using Ryujinx.Common.Logging; using System; +using System.Buffers; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -149,12 +150,16 @@ namespace Ryujinx.Audio.Renderer.Server state.InUse = false; } + Memory<VoiceUpdateState>[] voiceUpdateStatesArray = ArrayPool<Memory<VoiceUpdateState>>.Shared.Rent(Constants.VoiceChannelCountMax); + + Span<Memory<VoiceUpdateState>> voiceUpdateStates = voiceUpdateStatesArray.AsSpan(0, Constants.VoiceChannelCountMax); + // Start processing for (int i = 0; i < context.GetCount(); i++) { VoiceInParameter parameter = parameters[i]; - Memory<VoiceUpdateState>[] voiceUpdateStates = new Memory<VoiceUpdateState>[Constants.VoiceChannelCountMax]; + voiceUpdateStates.Fill(Memory<VoiceUpdateState>.Empty); ref VoiceOutStatus outStatus = ref SpanIOHelper.GetWriteRef<VoiceOutStatus>(ref _output)[0]; @@ -197,6 +202,8 @@ namespace Ryujinx.Audio.Renderer.Server } } + ArrayPool<Memory<VoiceUpdateState>>.Shared.Return(voiceUpdateStatesArray); + int currentOutputSize = _output.Length; OutputHeader.VoicesSize = (uint)(Unsafe.SizeOf<VoiceOutStatus>() * context.GetCount()); diff --git a/Ryujinx.Audio/Renderer/Server/Voice/VoiceState.cs b/Ryujinx.Audio/Renderer/Server/Voice/VoiceState.cs index 006d6dd3..0bf53c54 100644 --- a/Ryujinx.Audio/Renderer/Server/Voice/VoiceState.cs +++ b/Ryujinx.Audio/Renderer/Server/Voice/VoiceState.cs @@ -378,7 +378,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice /// <param name="outStatus">The given user output.</param> /// <param name="parameter">The user parameter.</param> /// <param name="voiceUpdateStates">The voice states associated to the <see cref="VoiceState"/>.</param> - public void WriteOutStatus(ref VoiceOutStatus outStatus, ref VoiceInParameter parameter, Memory<VoiceUpdateState>[] voiceUpdateStates) + public void WriteOutStatus(ref VoiceOutStatus outStatus, ref VoiceInParameter parameter, ReadOnlySpan<Memory<VoiceUpdateState>> voiceUpdateStates) { #if DEBUG // Sanity check in debug mode of the internal state @@ -424,7 +424,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice /// <param name="voiceUpdateStates">The voice states associated to the <see cref="VoiceState"/>.</param> /// <param name="mapper">The mapper to use.</param> /// <param name="behaviourContext">The behaviour context.</param> - public void UpdateWaveBuffers(out ErrorInfo[] errorInfos, ref VoiceInParameter parameter, Memory<VoiceUpdateState>[] voiceUpdateStates, ref PoolMapper mapper, ref BehaviourContext behaviourContext) + public void UpdateWaveBuffers(out ErrorInfo[] errorInfos, ref VoiceInParameter parameter, ReadOnlySpan<Memory<VoiceUpdateState>> voiceUpdateStates, ref PoolMapper mapper, ref BehaviourContext behaviourContext) { errorInfos = new ErrorInfo[Constants.VoiceWaveBufferCount * 2]; diff --git a/Ryujinx.Common/Memory/ByteMemoryPool.ByteMemoryPoolBuffer.cs b/Ryujinx.Common/Memory/ByteMemoryPool.ByteMemoryPoolBuffer.cs new file mode 100644 index 00000000..eda350bd --- /dev/null +++ b/Ryujinx.Common/Memory/ByteMemoryPool.ByteMemoryPoolBuffer.cs @@ -0,0 +1,51 @@ +using System; +using System.Buffers; +using System.Threading; + +namespace Ryujinx.Common.Memory +{ + public sealed partial class ByteMemoryPool + { + /// <summary> + /// Represents a <see cref="IMemoryOwner{Byte}"/> that wraps an array rented from + /// <see cref="ArrayPool{Byte}.Shared"/> and exposes it as <see cref="Memory{Byte}"/> + /// with a length of the requested size. + /// </summary> + private sealed class ByteMemoryPoolBuffer : IMemoryOwner<byte> + { + private byte[] _array; + private readonly int _length; + + public ByteMemoryPoolBuffer(int length) + { + _array = ArrayPool<byte>.Shared.Rent(length); + _length = length; + } + + /// <summary> + /// Returns a <see cref="Memory{Byte}"/> belonging to this owner. + /// </summary> + public Memory<byte> Memory + { + get + { + byte[] array = _array; + + ObjectDisposedException.ThrowIf(array is null, this); + + return new Memory<byte>(array, 0, _length); + } + } + + public void Dispose() + { + var array = Interlocked.Exchange(ref _array, null); + + if (array != null) + { + ArrayPool<byte>.Shared.Return(array); + } + } + } + } +} diff --git a/Ryujinx.Common/Memory/ByteMemoryPool.cs b/Ryujinx.Common/Memory/ByteMemoryPool.cs new file mode 100644 index 00000000..2910f408 --- /dev/null +++ b/Ryujinx.Common/Memory/ByteMemoryPool.cs @@ -0,0 +1,108 @@ +using System; +using System.Buffers; + +namespace Ryujinx.Common.Memory +{ + /// <summary> + /// Provides a pool of re-usable byte array instances. + /// </summary> + public sealed partial class ByteMemoryPool + { + private static readonly ByteMemoryPool _shared = new ByteMemoryPool(); + + /// <summary> + /// Constructs a <see cref="ByteMemoryPool"/> instance. Private to force access through + /// the <see cref="ByteMemoryPool.Shared"/> instance. + /// </summary> + private ByteMemoryPool() + { + // No implementation + } + + /// <summary> + /// Retrieves a shared <see cref="ByteMemoryPool"/> instance. + /// </summary> + public static ByteMemoryPool Shared => _shared; + + /// <summary> + /// Returns the maximum buffer size supported by this pool. + /// </summary> + public int MaxBufferSize => Array.MaxLength; + + /// <summary> + /// Rents a byte memory buffer from <see cref="ArrayPool{Byte}.Shared"/>. + /// The buffer may contain data from a prior use. + /// </summary> + /// <param name="length">The buffer's required length in bytes</param> + /// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns> + /// <exception cref="ArgumentOutOfRangeException"></exception> + public IMemoryOwner<byte> Rent(long length) + => RentImpl(checked((int)length)); + + /// <summary> + /// Rents a byte memory buffer from <see cref="ArrayPool{Byte}.Shared"/>. + /// The buffer may contain data from a prior use. + /// </summary> + /// <param name="length">The buffer's required length in bytes</param> + /// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns> + /// <exception cref="ArgumentOutOfRangeException"></exception> + public IMemoryOwner<byte> Rent(ulong length) + => RentImpl(checked((int)length)); + + /// <summary> + /// Rents a byte memory buffer from <see cref="ArrayPool{Byte}.Shared"/>. + /// The buffer may contain data from a prior use. + /// </summary> + /// <param name="length">The buffer's required length in bytes</param> + /// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns> + /// <exception cref="ArgumentOutOfRangeException"></exception> + public IMemoryOwner<byte> Rent(int length) + => RentImpl(length); + + /// <summary> + /// Rents a byte memory buffer from <see cref="ArrayPool{Byte}.Shared"/>. + /// The buffer's contents are cleared (set to all 0s) before returning. + /// </summary> + /// <param name="length">The buffer's required length in bytes</param> + /// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns> + /// <exception cref="ArgumentOutOfRangeException"></exception> + public IMemoryOwner<byte> RentCleared(long length) + => RentCleared(checked((int)length)); + + /// <summary> + /// Rents a byte memory buffer from <see cref="ArrayPool{Byte}.Shared"/>. + /// The buffer's contents are cleared (set to all 0s) before returning. + /// </summary> + /// <param name="length">The buffer's required length in bytes</param> + /// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns> + /// <exception cref="ArgumentOutOfRangeException"></exception> + public IMemoryOwner<byte> RentCleared(ulong length) + => RentCleared(checked((int)length)); + + /// <summary> + /// Rents a byte memory buffer from <see cref="ArrayPool{Byte}.Shared"/>. + /// The buffer's contents are cleared (set to all 0s) before returning. + /// </summary> + /// <param name="length">The buffer's required length in bytes</param> + /// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns> + /// <exception cref="ArgumentOutOfRangeException"></exception> + public IMemoryOwner<byte> RentCleared(int length) + { + var buffer = RentImpl(length); + + buffer.Memory.Span.Clear(); + + return buffer; + } + + private static ByteMemoryPoolBuffer RentImpl(int length) + { + if ((uint)length > Array.MaxLength) + { + throw new ArgumentOutOfRangeException(nameof(length), length, null); + } + + return new ByteMemoryPoolBuffer(length); + } + } +} diff --git a/Ryujinx.HLE/HOS/Ipc/IpcMessage.cs b/Ryujinx.HLE/HOS/Ipc/IpcMessage.cs index 394bf888..21630c42 100644 --- a/Ryujinx.HLE/HOS/Ipc/IpcMessage.cs +++ b/Ryujinx.HLE/HOS/Ipc/IpcMessage.cs @@ -27,98 +27,103 @@ namespace Ryujinx.HLE.HOS.Ipc public IpcMessage() { - PtrBuff = new List<IpcPtrBuffDesc>(); - SendBuff = new List<IpcBuffDesc>(); - ReceiveBuff = new List<IpcBuffDesc>(); - ExchangeBuff = new List<IpcBuffDesc>(); - RecvListBuff = new List<IpcRecvListBuffDesc>(); + PtrBuff = new List<IpcPtrBuffDesc>(0); + SendBuff = new List<IpcBuffDesc>(0); + ReceiveBuff = new List<IpcBuffDesc>(0); + ExchangeBuff = new List<IpcBuffDesc>(0); + RecvListBuff = new List<IpcRecvListBuffDesc>(0); - ObjectIds = new List<int>(); + ObjectIds = new List<int>(0); } - public IpcMessage(ReadOnlySpan<byte> data, long cmdPtr) : this() + public IpcMessage(ReadOnlySpan<byte> data, long cmdPtr) { using (RecyclableMemoryStream ms = MemoryStreamManager.Shared.GetStream(data)) { BinaryReader reader = new BinaryReader(ms); - Initialize(reader, cmdPtr); - } - } + int word0 = reader.ReadInt32(); + int word1 = reader.ReadInt32(); - private void Initialize(BinaryReader reader, long cmdPtr) - { - int word0 = reader.ReadInt32(); - int word1 = reader.ReadInt32(); + Type = (IpcMessageType)(word0 & 0xffff); - Type = (IpcMessageType)(word0 & 0xffff); + int ptrBuffCount = (word0 >> 16) & 0xf; + int sendBuffCount = (word0 >> 20) & 0xf; + int recvBuffCount = (word0 >> 24) & 0xf; + int xchgBuffCount = (word0 >> 28) & 0xf; - int ptrBuffCount = (word0 >> 16) & 0xf; - int sendBuffCount = (word0 >> 20) & 0xf; - int recvBuffCount = (word0 >> 24) & 0xf; - int xchgBuffCount = (word0 >> 28) & 0xf; + int rawDataSize = (word1 >> 0) & 0x3ff; + int recvListFlags = (word1 >> 10) & 0xf; + bool hndDescEnable = ((word1 >> 31) & 0x1) != 0; - int rawDataSize = (word1 >> 0) & 0x3ff; - int recvListFlags = (word1 >> 10) & 0xf; - bool hndDescEnable = ((word1 >> 31) & 0x1) != 0; + if (hndDescEnable) + { + HandleDesc = new IpcHandleDesc(reader); + } - if (hndDescEnable) - { - HandleDesc = new IpcHandleDesc(reader); - } + PtrBuff = new List<IpcPtrBuffDesc>(ptrBuffCount); - for (int index = 0; index < ptrBuffCount; index++) - { - PtrBuff.Add(new IpcPtrBuffDesc(reader)); - } + for (int index = 0; index < ptrBuffCount; index++) + { + PtrBuff.Add(new IpcPtrBuffDesc(reader)); + } - void ReadBuff(List<IpcBuffDesc> buff, int count) - { - for (int index = 0; index < count; index++) + static List<IpcBuffDesc> ReadBuff(BinaryReader reader, int count) { - buff.Add(new IpcBuffDesc(reader)); + List<IpcBuffDesc> buff = new List<IpcBuffDesc>(count); + + for (int index = 0; index < count; index++) + { + buff.Add(new IpcBuffDesc(reader)); + } + + return buff; } - } - ReadBuff(SendBuff, sendBuffCount); - ReadBuff(ReceiveBuff, recvBuffCount); - ReadBuff(ExchangeBuff, xchgBuffCount); + SendBuff = ReadBuff(reader, sendBuffCount); + ReceiveBuff = ReadBuff(reader, recvBuffCount); + ExchangeBuff = ReadBuff(reader, xchgBuffCount); - rawDataSize *= 4; + rawDataSize *= 4; - long recvListPos = reader.BaseStream.Position + rawDataSize; + long recvListPos = reader.BaseStream.Position + rawDataSize; // Only CMIF has the padding requirements. if (Type < IpcMessageType.TipcCloseSession) { long pad0 = GetPadSize16(reader.BaseStream.Position + cmdPtr); - if (rawDataSize != 0) - { - rawDataSize -= (int)pad0; + if (rawDataSize != 0) + { + rawDataSize -= (int)pad0; + } + + reader.BaseStream.Seek(pad0, SeekOrigin.Current); } - reader.BaseStream.Seek(pad0, SeekOrigin.Current); - } + int recvListCount = recvListFlags - 2; - int recvListCount = recvListFlags - 2; + if (recvListCount == 0) + { + recvListCount = 1; + } + else if (recvListCount < 0) + { + recvListCount = 0; + } - if (recvListCount == 0) - { - recvListCount = 1; - } - else if (recvListCount < 0) - { - recvListCount = 0; - } + RawData = reader.ReadBytes(rawDataSize); - RawData = reader.ReadBytes(rawDataSize); + reader.BaseStream.Seek(recvListPos, SeekOrigin.Begin); - reader.BaseStream.Seek(recvListPos, SeekOrigin.Begin); + RecvListBuff = new List<IpcRecvListBuffDesc>(recvListCount); - for (int index = 0; index < recvListCount; index++) - { - RecvListBuff.Add(new IpcRecvListBuffDesc(reader.ReadUInt64())); + for (int index = 0; index < recvListCount; index++) + { + RecvListBuff.Add(new IpcRecvListBuffDesc(reader.ReadUInt64())); + } + + ObjectIds = new List<int>(0); } } diff --git a/Ryujinx.HLE/HOS/Kernel/Common/KTimeManager.cs b/Ryujinx.HLE/HOS/Kernel/Common/KTimeManager.cs index 1af171b9..c0cd9ce9 100644 --- a/Ryujinx.HLE/HOS/Kernel/Common/KTimeManager.cs +++ b/Ryujinx.HLE/HOS/Kernel/Common/KTimeManager.cs @@ -71,7 +71,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Common { lock (_context.CriticalSection.Lock) { - _waitingObjects.RemoveAll(x => x.Object == schedulerObj); + for (int index = _waitingObjects.Count - 1; index >= 0; index--) + { + if (_waitingObjects[index].Object == schedulerObj) + { + _waitingObjects.RemoveAt(index); + } + } } } @@ -105,16 +111,19 @@ namespace Ryujinx.HLE.HOS.Kernel.Common } else { - while (Interlocked.Read(ref _enforceWakeupFromSpinWait) != 1 && PerformanceCounter.ElapsedTicks <= next.TimePoint) + while (Interlocked.Read(ref _enforceWakeupFromSpinWait) != 1 && PerformanceCounter.ElapsedTicks < next.TimePoint) { + // Our time is close - don't let SpinWait go off and potentially Thread.Sleep(). if (spinWait.NextSpinWillYield) { Thread.Yield(); spinWait.Reset(); } - - spinWait.SpinOnce(); + else + { + spinWait.SpinOnce(); + } } spinWait.Reset(); diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs index c6467208..3163c348 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs @@ -9,6 +9,7 @@ using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.HLE.HOS.Kernel.Threading; using Ryujinx.Horizon.Common; using System; +using System.Buffers; using System.Threading; namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall @@ -553,7 +554,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall KProcess currentProcess = KernelStatic.GetCurrentProcess(); - KSynchronizationObject[] syncObjs = handles.Length == 0 ? Array.Empty<KSynchronizationObject>() : new KSynchronizationObject[handles.Length]; + KSynchronizationObject[] syncObjsArray = ArrayPool<KSynchronizationObject>.Shared.Rent(handles.Length); + + Span<KSynchronizationObject> syncObjs = syncObjsArray.AsSpan(0, handles.Length); for (int index = 0; index < handles.Length; index++) { @@ -606,6 +609,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } } + ArrayPool<KSynchronizationObject>.Shared.Return(syncObjsArray); + return result; } diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs index 973d5f6a..d42f9003 100644 --- a/Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs +++ b/Ryujinx.HLE/HOS/Kernel/Threading/KSynchronization.cs @@ -1,6 +1,7 @@ using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.Horizon.Common; using System; +using System.Buffers; using System.Collections.Generic; namespace Ryujinx.HLE.HOS.Kernel.Threading @@ -59,7 +60,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading } else { - LinkedListNode<KThread>[] syncNodes = syncObjs.Length == 0 ? Array.Empty<LinkedListNode<KThread>>() : new LinkedListNode<KThread>[syncObjs.Length]; + LinkedListNode<KThread>[] syncNodesArray = ArrayPool<LinkedListNode<KThread>>.Shared.Rent(syncObjs.Length); + + Span<LinkedListNode<KThread>> syncNodes = syncNodesArray.AsSpan(0, syncObjs.Length); for (int index = 0; index < syncObjs.Length; index++) { @@ -101,6 +104,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading handleIndex = index; } } + + ArrayPool<LinkedListNode<KThread>>.Shared.Return(syncNodesArray); } _context.CriticalSection.Leave(); diff --git a/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs index 81321046..a137c413 100644 --- a/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs +++ b/Ryujinx.HLE/HOS/Services/Audio/AudioRenderer/AudioRendererServer.cs @@ -1,4 +1,5 @@ using Ryujinx.Common.Logging; +using Ryujinx.Common.Memory; using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Kernel.Threading; using Ryujinx.Horizon.Common; @@ -68,25 +69,29 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer ReadOnlyMemory<byte> input = context.Memory.GetSpan(inputPosition, (int)inputSize).ToArray(); - Memory<byte> output = new byte[outputSize]; - Memory<byte> performanceOutput = new byte[performanceOutputSize]; + using (IMemoryOwner<byte> outputOwner = ByteMemoryPool.Shared.RentCleared(outputSize)) + using (IMemoryOwner<byte> performanceOutputOwner = ByteMemoryPool.Shared.RentCleared(performanceOutputSize)) + { + Memory<byte> output = outputOwner.Memory; + Memory<byte> performanceOutput = performanceOutputOwner.Memory; - using MemoryHandle outputHandle = output.Pin(); - using MemoryHandle performanceOutputHandle = performanceOutput.Pin(); + using MemoryHandle outputHandle = output.Pin(); + using MemoryHandle performanceOutputHandle = performanceOutput.Pin(); - ResultCode result = _impl.RequestUpdate(output, performanceOutput, input); + ResultCode result = _impl.RequestUpdate(output, performanceOutput, input); - if (result == ResultCode.Success) - { - context.Memory.Write(outputPosition, output.Span); - context.Memory.Write(performanceOutputPosition, performanceOutput.Span); - } - else - { - Logger.Error?.Print(LogClass.ServiceAudio, $"Error while processing renderer update: 0x{(int)result:X}"); - } + if (result == ResultCode.Success) + { + context.Memory.Write(outputPosition, output.Span); + context.Memory.Write(performanceOutputPosition, performanceOutput.Span); + } + else + { + Logger.Error?.Print(LogClass.ServiceAudio, $"Error while processing renderer update: 0x{(int)result:X}"); + } - return result; + return result; + } } [CommandCmif(5)] diff --git a/Ryujinx.HLE/HOS/Services/IpcService.cs b/Ryujinx.HLE/HOS/Services/IpcService.cs index f42fd0e2..048a68a9 100644 --- a/Ryujinx.HLE/HOS/Services/IpcService.cs +++ b/Ryujinx.HLE/HOS/Services/IpcService.cs @@ -76,6 +76,8 @@ namespace Ryujinx.HLE.HOS.Services context.RequestData.BaseStream.Seek(0x10 + dataPayloadSize, SeekOrigin.Begin); + context.Request.ObjectIds.EnsureCapacity(inputObjCount); + for (int index = 0; index < inputObjCount; index++) { context.Request.ObjectIds.Add(context.RequestData.ReadInt32()); diff --git a/Ryujinx.HLE/HOS/Services/ServerBase.cs b/Ryujinx.HLE/HOS/Services/ServerBase.cs index 762b4fa4..b994679a 100644 --- a/Ryujinx.HLE/HOS/Services/ServerBase.cs +++ b/Ryujinx.HLE/HOS/Services/ServerBase.cs @@ -217,6 +217,8 @@ namespace Ryujinx.HLE.HOS.Services if (noReceive) { + response.PtrBuff.EnsureCapacity(request.RecvListBuff.Count); + for (int i = 0; i < request.RecvListBuff.Count; i++) { ulong size = (ulong)BinaryPrimitives.ReadInt16LittleEndian(request.RawData.AsSpan(sizesOffset + i * 2, 2)); diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs index 0724c83e..42fc2761 100644 --- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs +++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/IHOSBinderDriver.cs @@ -1,7 +1,9 @@ -using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.Common.Memory; +using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Kernel.Threading; using Ryujinx.Horizon.Common; using System; +using System.Buffers; namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger { @@ -83,16 +85,19 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger ReadOnlySpan<byte> inputParcel = context.Memory.GetSpan(dataPos, (int)dataSize); - Span<byte> outputParcel = new Span<byte>(new byte[replySize]); + using (IMemoryOwner<byte> outputParcelOwner = ByteMemoryPool.Shared.RentCleared(replySize)) + { + Span<byte> outputParcel = outputParcelOwner.Memory.Span; + + ResultCode result = OnTransact(binderId, code, flags, inputParcel, outputParcel); - ResultCode result = OnTransact(binderId, code, flags, inputParcel, outputParcel); + if (result == ResultCode.Success) + { + context.Memory.Write(replyPos, outputParcel); + } - if (result == ResultCode.Success) - { - context.Memory.Write(replyPos, outputParcel); + return result; } - - return result; } protected abstract ResultCode AdjustRefcount(int binderId, int addVal, int type); diff --git a/Ryujinx.Input.SDL2/SDL2Gamepad.cs b/Ryujinx.Input.SDL2/SDL2Gamepad.cs index eec4e07e..92552673 100644 --- a/Ryujinx.Input.SDL2/SDL2Gamepad.cs +++ b/Ryujinx.Input.SDL2/SDL2Gamepad.cs @@ -12,17 +12,7 @@ namespace Ryujinx.Input.SDL2 { private bool HasConfiguration => _configuration != null; - private class ButtonMappingEntry - { - public readonly GamepadButtonInputId To; - public readonly GamepadButtonInputId From; - - public ButtonMappingEntry(GamepadButtonInputId to, GamepadButtonInputId from) - { - To = to; - From = from; - } - } + private record struct ButtonMappingEntry(GamepadButtonInputId To, GamepadButtonInputId From); private StandardControllerInputConfig _configuration; @@ -85,7 +75,7 @@ namespace Ryujinx.Input.SDL2 public SDL2Gamepad(IntPtr gamepadHandle, string driverId) { _gamepadHandle = gamepadHandle; - _buttonsUserMapping = new List<ButtonMappingEntry>(); + _buttonsUserMapping = new List<ButtonMappingEntry>(20); Name = SDL_GameControllerName(_gamepadHandle); Id = driverId; |