diff --git a/src/Ryujinx.Common/Memory/MemoryStreamManager.cs b/src/Ryujinx.Common/Memory/MemoryStreamManager.cs index 834210e07..88f5956e9 100644 --- a/src/Ryujinx.Common/Memory/MemoryStreamManager.cs +++ b/src/Ryujinx.Common/Memory/MemoryStreamManager.cs @@ -7,6 +7,9 @@ namespace Ryujinx.Common.Memory { private static readonly RecyclableMemoryStreamManager _shared = new(); + private static readonly ObjectPool _streamPool = + new(() => new RecyclableMemoryStream(_shared, Guid.NewGuid(), null, 0)); + /// /// We don't expose the RecyclableMemoryStreamManager directly because version 2.x /// returns them as MemoryStream. This Shared class is here to a) offer only the GetStream() versions we use @@ -19,7 +22,12 @@ namespace Ryujinx.Common.Memory /// /// A RecyclableMemoryStream public static RecyclableMemoryStream GetStream() - => new(_shared); + { + RecyclableMemoryStream stream = _streamPool.Allocate(); + stream.SetLength(0); + + return stream; + } /// /// Retrieve a new MemoryStream object with the contents copied from the provided @@ -55,7 +63,8 @@ namespace Ryujinx.Common.Memory RecyclableMemoryStream stream = null; try { - stream = new RecyclableMemoryStream(_shared, id, tag, buffer.Length); + stream = _streamPool.Allocate(); + stream.SetLength(0); stream.Write(buffer); stream.Position = 0; return stream; @@ -83,7 +92,8 @@ namespace Ryujinx.Common.Memory RecyclableMemoryStream stream = null; try { - stream = new RecyclableMemoryStream(_shared, id, tag, count); + stream = _streamPool.Allocate(); + stream.SetLength(0); stream.Write(buffer, offset, count); stream.Position = 0; return stream; @@ -94,6 +104,11 @@ namespace Ryujinx.Common.Memory throw; } } + + public static void ReleaseStream(RecyclableMemoryStream stream) + { + _streamPool.Release(stream); + } } } } diff --git a/src/Ryujinx.HLE/HOS/Ipc/IpcMessage.cs b/src/Ryujinx.HLE/HOS/Ipc/IpcMessage.cs index 7df2b778f..13a93db39 100644 --- a/src/Ryujinx.HLE/HOS/Ipc/IpcMessage.cs +++ b/src/Ryujinx.HLE/HOS/Ipc/IpcMessage.cs @@ -2,6 +2,7 @@ using Microsoft.IO; using Ryujinx.Common; using Ryujinx.Common.Memory; using System; +using System.Buffers; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -37,7 +38,7 @@ namespace Ryujinx.HLE.HOS.Ipc public IpcMessage(ReadOnlySpan data, long cmdPtr) { - using RecyclableMemoryStream ms = MemoryStreamManager.Shared.GetStream(data); + RecyclableMemoryStream ms = MemoryStreamManager.Shared.GetStream(data); BinaryReader reader = new(ms); @@ -123,6 +124,8 @@ namespace Ryujinx.HLE.HOS.Ipc } ObjectIds = []; + + MemoryStreamManager.Shared.ReleaseStream(ms); } public RecyclableMemoryStream GetStream(long cmdPtr, ulong recvListAddr) diff --git a/src/Ryujinx.HLE/HOS/Services/IpcService.cs b/src/Ryujinx.HLE/HOS/Services/IpcService.cs index 4c354ebc6..c7dee64fb 100644 --- a/src/Ryujinx.HLE/HOS/Services/IpcService.cs +++ b/src/Ryujinx.HLE/HOS/Services/IpcService.cs @@ -23,6 +23,9 @@ namespace Ryujinx.HLE.HOS.Services private int _selfId; private bool _isDomain; + // cache array so we don't recreate it all the time + private object[] _parameters = [null]; + public IpcService(ServerBase server = null, bool registerTipc = false) { Stopwatch sw = Stopwatch.StartNew(); @@ -146,7 +149,9 @@ namespace Ryujinx.HLE.HOS.Services { Logger.Trace?.Print(LogClass.KernelIpc, $"{service.GetType().Name}: {processRequest.Name}"); - result = (ResultCode)processRequest.Invoke(service, [context]); + _parameters[0] = context; + + result = (ResultCode)processRequest.Invoke(service, _parameters); } else { @@ -196,7 +201,9 @@ namespace Ryujinx.HLE.HOS.Services { Logger.Debug?.Print(LogClass.KernelIpc, $"{GetType().Name}: {processRequest.Name}"); - result = (ResultCode)processRequest.Invoke(this, [context]); + _parameters[0] = context; + + result = (ResultCode)processRequest.Invoke(this, _parameters); } else { diff --git a/src/Ryujinx.HLE/HOS/Services/ServerBase.cs b/src/Ryujinx.HLE/HOS/Services/ServerBase.cs index dcc01bf38..a54dc637e 100644 --- a/src/Ryujinx.HLE/HOS/Services/ServerBase.cs +++ b/src/Ryujinx.HLE/HOS/Services/ServerBase.cs @@ -454,8 +454,9 @@ namespace Ryujinx.HLE.HOS.Services response.RawData = _responseDataStream.ToArray(); - using RecyclableMemoryStream responseStream = response.GetStreamTipc(); + RecyclableMemoryStream responseStream = response.GetStreamTipc(); _selfProcess.CpuMemory.Write(_selfThread.TlsAddress, responseStream.GetReadOnlySequence()); + MemoryStreamManager.Shared.ReleaseStream(responseStream); } else { @@ -464,8 +465,9 @@ namespace Ryujinx.HLE.HOS.Services if (!isTipcCommunication) { - using RecyclableMemoryStream responseStream = response.GetStream((long)_selfThread.TlsAddress, recvListAddr | ((ulong)PointerBufferSize << 48)); + RecyclableMemoryStream responseStream = response.GetStream((long)_selfThread.TlsAddress, recvListAddr | ((ulong)PointerBufferSize << 48)); _selfProcess.CpuMemory.Write(_selfThread.TlsAddress, responseStream.GetReadOnlySequence()); + MemoryStreamManager.Shared.ReleaseStream(responseStream); } return shouldReply;