mirror of
https://git.ryujinx.app/projects/Kenji-NX.git
synced 2026-10-07 21:39:57 +02:00
Memory Changes 3.2
Fixes a few crashes: - fixes a crash related to waking threads (priorities were wrong). - fixes a crash from reusing the SetRenderTargets texture array (left-over data causing issues). - fixes a mistake and an oversight in the buffer system. - buffers were getting updated wrong causing bad data to be stored or some times cut. - modified ranges would extend past their old buffers, crashing on syncs. Old buffers are now skipped as the new buffers already sync instead. Introduces pooling in a few more places to increase memory efficiency. simplified RangeList item logic. - removed RangeItem by making all the range objects use the I(NonOverlapping)Range interface. - BufferCache class no longer locks its RangeList, as the list is only ever accessed synchronously. Small change to how keyboard snapshots are stored. Increase ThreadedRenderer SpanPool size to fit slightly more data (4MB -> 8MB).
This commit is contained in:
@@ -37,7 +37,7 @@ namespace Ryujinx.HLE.HOS.Ipc
|
||||
|
||||
public IpcMessage(ReadOnlySpan<byte> data, long cmdPtr)
|
||||
{
|
||||
using RecyclableMemoryStream ms = MemoryStreamManager.Shared.GetStream(data);
|
||||
RecyclableMemoryStream ms = MemoryStreamManager.Shared.GetStream(data);
|
||||
|
||||
BinaryReader reader = new(ms);
|
||||
|
||||
@@ -123,6 +123,8 @@ namespace Ryujinx.HLE.HOS.Ipc
|
||||
}
|
||||
|
||||
ObjectIds = [];
|
||||
|
||||
MemoryStreamManager.Shared.ReleaseStream(ms);
|
||||
}
|
||||
|
||||
public RecyclableMemoryStream GetStream(long cmdPtr, ulong recvListAddr)
|
||||
|
||||
@@ -20,6 +20,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||
_exchangeBufferDescriptors = new List<KBufferDescriptor>(MaxInternalBuffersCount);
|
||||
}
|
||||
|
||||
public KBufferDescriptorTable Clear()
|
||||
{
|
||||
_sendBufferDescriptors.Clear();
|
||||
_receiveBufferDescriptors.Clear();
|
||||
_exchangeBufferDescriptors.Clear();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Result AddSendBuffer(ulong src, ulong dst, ulong size, MemoryState state)
|
||||
{
|
||||
return Add(_sendBufferDescriptors, src, dst, size, state);
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||
{
|
||||
KThread currentThread = KernelStatic.GetCurrentThread();
|
||||
|
||||
KSessionRequest request = new(currentThread, customCmdBuffAddr, customCmdBuffSize);
|
||||
KSessionRequest request = _parent.ServerSession.RequestPool.Allocate().Set(currentThread, customCmdBuffAddr, customCmdBuffSize);
|
||||
|
||||
KernelContext.CriticalSection.Enter();
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||
{
|
||||
KThread currentThread = KernelStatic.GetCurrentThread();
|
||||
|
||||
KSessionRequest request = new(currentThread, customCmdBuffAddr, customCmdBuffSize, asyncEvent);
|
||||
KSessionRequest request = _parent.ServerSession.RequestPool.Allocate().Set(currentThread, customCmdBuffAddr, customCmdBuffSize, asyncEvent);
|
||||
|
||||
KernelContext.CriticalSection.Enter();
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||
{
|
||||
class KServerSession : KSynchronizationObject
|
||||
{
|
||||
public readonly ObjectPool<KSessionRequest> RequestPool = new(() => new KSessionRequest());
|
||||
|
||||
private static readonly MemoryState[] _ipcMemoryStates =
|
||||
[
|
||||
MemoryState.IpcBuffer3,
|
||||
@@ -274,6 +276,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||
KernelContext.CriticalSection.Leave();
|
||||
|
||||
WakeClientThread(request, clientResult);
|
||||
|
||||
RequestPool.Release(request);
|
||||
}
|
||||
|
||||
if (clientHeader.ReceiveListType < 2 && clientHeader.ReceiveListOffset > clientMsg.Size ||
|
||||
@@ -608,6 +612,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||
CloseAllHandles(clientMsg, serverHeader, clientProcess);
|
||||
|
||||
FinishRequest(request, clientResult);
|
||||
|
||||
RequestPool.Release(request);
|
||||
}
|
||||
|
||||
if (clientHeader.ReceiveListType < 2 && clientHeader.ReceiveListOffset > clientMsg.Size ||
|
||||
@@ -827,6 +833,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||
|
||||
// Unmap buffers from server.
|
||||
FinishRequest(request, clientResult);
|
||||
|
||||
RequestPool.Release(request);
|
||||
|
||||
return serverResult;
|
||||
}
|
||||
@@ -1060,6 +1068,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||
foreach (KSessionRequest request in IterateWithRemovalOfAllRequests())
|
||||
{
|
||||
FinishRequest(request, KernelResult.PortRemoteClosed);
|
||||
|
||||
RequestPool.Release(request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1079,6 +1089,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||
{
|
||||
SendResultToAsyncRequestClient(request, KernelResult.PortRemoteClosed);
|
||||
}
|
||||
|
||||
RequestPool.Release(request);
|
||||
}
|
||||
|
||||
WakeServerThreads(KernelResult.PortRemoteClosed);
|
||||
|
||||
@@ -5,18 +5,18 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||
{
|
||||
class KSessionRequest
|
||||
{
|
||||
public KBufferDescriptorTable BufferDescriptorTable { get; }
|
||||
public KBufferDescriptorTable BufferDescriptorTable { get; private set; }
|
||||
|
||||
public KThread ClientThread { get; }
|
||||
public KThread ClientThread { get; private set; }
|
||||
|
||||
public KProcess ServerProcess { get; set; }
|
||||
|
||||
public KWritableEvent AsyncEvent { get; }
|
||||
public KWritableEvent AsyncEvent { get; private set; }
|
||||
|
||||
public ulong CustomCmdBuffAddr { get; }
|
||||
public ulong CustomCmdBuffSize { get; }
|
||||
public ulong CustomCmdBuffAddr { get; private set; }
|
||||
public ulong CustomCmdBuffSize { get; private set; }
|
||||
|
||||
public KSessionRequest(
|
||||
public KSessionRequest Set(
|
||||
KThread clientThread,
|
||||
ulong customCmdBuffAddr,
|
||||
ulong customCmdBuffSize,
|
||||
@@ -27,7 +27,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||
CustomCmdBuffSize = customCmdBuffSize;
|
||||
AsyncEvent = asyncEvent;
|
||||
|
||||
BufferDescriptorTable = new KBufferDescriptorTable();
|
||||
BufferDescriptorTable = BufferDescriptorTable?.Clear() ?? new KBufferDescriptorTable();
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using Ryujinx.Horizon.Common;
|
||||
@@ -11,12 +10,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
class KAddressArbiter
|
||||
{
|
||||
private const int HasListenersMask = 0x40000000;
|
||||
private static readonly ObjectPool<KThread[]> _threadArrayPool = new(() => []);
|
||||
|
||||
private readonly KernelContext _context;
|
||||
|
||||
private readonly List<KThread> _condVarThreads;
|
||||
private readonly List<KThread> _arbiterThreads;
|
||||
private readonly Dictionary<ulong, List<KThread>> _condVarThreads;
|
||||
private readonly Dictionary<ulong, List<KThread>> _arbiterThreads;
|
||||
private readonly ByDynamicPriority _byDynamicPriority;
|
||||
|
||||
public KAddressArbiter(KernelContext context)
|
||||
{
|
||||
@@ -24,6 +23,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
|
||||
_condVarThreads = [];
|
||||
_arbiterThreads = [];
|
||||
_byDynamicPriority = new ByDynamicPriority();
|
||||
}
|
||||
|
||||
public Result ArbitrateLock(int ownerHandle, ulong mutexAddress, int requesterHandle)
|
||||
@@ -139,9 +139,23 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
|
||||
currentThread.MutexAddress = mutexAddress;
|
||||
currentThread.ThreadHandleForUserMutex = threadHandle;
|
||||
currentThread.CondVarAddress = condVarAddress;
|
||||
|
||||
_condVarThreads.Add(currentThread);
|
||||
if (_condVarThreads.TryGetValue(condVarAddress, out List<KThread> threads))
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (threads.Count > 0)
|
||||
{
|
||||
i = threads.BinarySearch(currentThread, _byDynamicPriority);
|
||||
if (i < 0) i = ~i;
|
||||
}
|
||||
|
||||
threads.Insert(i, currentThread);
|
||||
}
|
||||
else
|
||||
{
|
||||
_condVarThreads.Add(condVarAddress, [currentThread]);
|
||||
}
|
||||
|
||||
if (timeout != 0)
|
||||
{
|
||||
@@ -164,7 +178,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
|
||||
currentThread.MutexOwner?.RemoveMutexWaiter(currentThread);
|
||||
|
||||
_condVarThreads.Remove(currentThread);
|
||||
_condVarThreads[condVarAddress].Remove(currentThread);
|
||||
|
||||
_context.CriticalSection.Leave();
|
||||
|
||||
@@ -199,13 +213,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
{
|
||||
_context.CriticalSection.Enter();
|
||||
|
||||
static bool SignalProcessWideKeyPredicate(KThread thread, ulong address)
|
||||
int validThreads = 0;
|
||||
_condVarThreads.TryGetValue(address, out List<KThread> threads);
|
||||
|
||||
if (threads is not null && threads.Count > 0)
|
||||
{
|
||||
return thread.CondVarAddress == address;
|
||||
validThreads = WakeThreads(threads, count, TryAcquireMutex);
|
||||
}
|
||||
|
||||
int validThreads = WakeThreads(_condVarThreads, count, TryAcquireMutex, SignalProcessWideKeyPredicate, address);
|
||||
|
||||
|
||||
if (validThreads == 0)
|
||||
{
|
||||
KernelTransfer.KernelToUser(address, 0);
|
||||
@@ -314,9 +329,24 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
|
||||
currentThread.MutexAddress = address;
|
||||
currentThread.WaitingInArbitration = true;
|
||||
|
||||
if (_arbiterThreads.TryGetValue(address, out List<KThread> threads))
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
_arbiterThreads.Add(currentThread);
|
||||
|
||||
if (threads.Count > 0)
|
||||
{
|
||||
i = threads.BinarySearch(currentThread, _byDynamicPriority);
|
||||
if (i < 0) i = ~i;
|
||||
}
|
||||
|
||||
threads.Insert(i, currentThread);
|
||||
}
|
||||
else
|
||||
{
|
||||
_arbiterThreads.Add(address, [currentThread]);
|
||||
}
|
||||
|
||||
currentThread.Reschedule(ThreadSchedState.Paused);
|
||||
|
||||
if (timeout > 0)
|
||||
@@ -335,7 +365,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
|
||||
if (currentThread.WaitingInArbitration)
|
||||
{
|
||||
_arbiterThreads.Remove(currentThread);
|
||||
_arbiterThreads[address].Remove(currentThread);
|
||||
|
||||
currentThread.WaitingInArbitration = false;
|
||||
}
|
||||
@@ -391,9 +421,24 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
|
||||
currentThread.MutexAddress = address;
|
||||
currentThread.WaitingInArbitration = true;
|
||||
|
||||
if (_arbiterThreads.TryGetValue(address, out List<KThread> threads))
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
_arbiterThreads.Add(currentThread);
|
||||
|
||||
if (threads.Count > 0)
|
||||
{
|
||||
i = threads.BinarySearch(currentThread, _byDynamicPriority);
|
||||
if (i < 0) i = ~i;
|
||||
}
|
||||
|
||||
threads.Insert(i, currentThread);
|
||||
}
|
||||
else
|
||||
{
|
||||
_arbiterThreads.Add(address, [currentThread]);
|
||||
}
|
||||
|
||||
currentThread.Reschedule(ThreadSchedState.Paused);
|
||||
|
||||
if (timeout > 0)
|
||||
@@ -412,7 +457,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
|
||||
if (currentThread.WaitingInArbitration)
|
||||
{
|
||||
_arbiterThreads.Remove(currentThread);
|
||||
_arbiterThreads[address].Remove(currentThread);
|
||||
|
||||
currentThread.WaitingInArbitration = false;
|
||||
}
|
||||
@@ -484,16 +529,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
// The value is decremented if the number of threads waiting is less
|
||||
// or equal to the Count of threads to be signaled, or Count is zero
|
||||
// or negative. It is incremented if there are no threads waiting.
|
||||
int waitingCount = 0;
|
||||
|
||||
foreach (KThread thread in _arbiterThreads)
|
||||
{
|
||||
if (thread.MutexAddress == address &&
|
||||
++waitingCount >= count)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
int waitingCount = _arbiterThreads[address].Count;
|
||||
|
||||
if (waitingCount > 0)
|
||||
{
|
||||
@@ -560,55 +596,38 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
thread.WaitingInArbitration = false;
|
||||
}
|
||||
|
||||
static bool ArbiterThreadPredecate(KThread thread, ulong address)
|
||||
{
|
||||
return thread.MutexAddress == address;
|
||||
}
|
||||
_arbiterThreads.TryGetValue(address, out List<KThread> threads);
|
||||
|
||||
WakeThreads(_arbiterThreads, count, RemoveArbiterThread, ArbiterThreadPredecate, address);
|
||||
if (threads is not null && threads.Count > 0)
|
||||
{
|
||||
WakeThreads(threads, count, RemoveArbiterThread);
|
||||
}
|
||||
}
|
||||
|
||||
private static int WakeThreads(
|
||||
List<KThread> threads,
|
||||
int count,
|
||||
Action<KThread> removeCallback,
|
||||
Func<KThread, ulong, bool> predicate,
|
||||
ulong address = 0)
|
||||
Action<KThread> removeCallback)
|
||||
{
|
||||
KThread[] candidates = _threadArrayPool.Allocate();
|
||||
if (candidates.Length < threads.Count)
|
||||
{
|
||||
Array.Resize(ref candidates, threads.Count);
|
||||
}
|
||||
|
||||
int validCount = 0;
|
||||
|
||||
for (int i = 0; i < threads.Count; i++)
|
||||
{
|
||||
if (predicate(threads[i], address))
|
||||
{
|
||||
candidates[validCount++] = threads[i];
|
||||
}
|
||||
}
|
||||
|
||||
Span<KThread> candidatesSpan = candidates.AsSpan(..validCount);
|
||||
|
||||
candidatesSpan.Sort((x, y) => (x.DynamicPriority.CompareTo(y.DynamicPriority)));
|
||||
int validCount = count > 0 ? Math.Min(count, threads.Count) : threads.Count;
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
candidatesSpan = candidatesSpan[..Math.Min(count, candidatesSpan.Length)];
|
||||
}
|
||||
|
||||
foreach (KThread thread in candidatesSpan)
|
||||
for (int i = 0; i < validCount; i++)
|
||||
{
|
||||
KThread thread = threads[i];
|
||||
removeCallback(thread);
|
||||
threads.Remove(thread);
|
||||
}
|
||||
|
||||
_threadArrayPool.Release(candidates);
|
||||
|
||||
threads.RemoveRange(0, validCount);
|
||||
|
||||
return validCount;
|
||||
}
|
||||
|
||||
private class ByDynamicPriority : IComparer<KThread>
|
||||
{
|
||||
public int Compare(KThread x, KThread y)
|
||||
{
|
||||
return x!.DynamicPriority.CompareTo(y!.DynamicPriority);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,8 +40,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
|
||||
public KSynchronizationObject SignaledObj { get; set; }
|
||||
|
||||
public ulong CondVarAddress { get; set; }
|
||||
|
||||
private ulong _entrypoint;
|
||||
private ThreadStart _customThreadStart;
|
||||
private bool _forcedUnschedulable;
|
||||
|
||||
@@ -21,6 +21,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)
|
||||
{
|
||||
CmifCommands = typeof(IpcService).Assembly.GetTypes()
|
||||
@@ -123,7 +126,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
|
||||
{
|
||||
@@ -176,7 +181,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
|
||||
{
|
||||
|
||||
@@ -59,6 +59,10 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
||||
|
||||
// TODO: This should call set:sys::GetDebugModeFlag
|
||||
private readonly bool _debugModeEnabled = false;
|
||||
|
||||
private byte[] _ioctl2Buffer = [];
|
||||
private byte[] _ioctlArgumentBuffer = [];
|
||||
private byte[] _ioctl3Buffer = [];
|
||||
|
||||
public INvDrvServices(ServiceCtx context) : base(context.Device.System.NvDrvServer)
|
||||
{
|
||||
@@ -128,27 +132,38 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
||||
|
||||
if (!context.Memory.TryReadUnsafe(inputDataPosition, (int)inputDataSize, out arguments))
|
||||
{
|
||||
arguments = new byte[inputDataSize];
|
||||
if (_ioctlArgumentBuffer.Length < (int)inputDataSize)
|
||||
{
|
||||
Array.Resize(ref _ioctlArgumentBuffer, (int)inputDataSize);
|
||||
}
|
||||
|
||||
arguments = _ioctlArgumentBuffer.AsSpan(0, (int)inputDataSize);
|
||||
|
||||
context.Memory.Read(inputDataPosition, arguments);
|
||||
}
|
||||
else
|
||||
{
|
||||
arguments = arguments.ToArray();
|
||||
}
|
||||
}
|
||||
else if (isWrite)
|
||||
{
|
||||
byte[] outputData = new byte[outputDataSize];
|
||||
|
||||
arguments = new Span<byte>(outputData);
|
||||
if (_ioctlArgumentBuffer.Length < (int)outputDataSize)
|
||||
{
|
||||
Array.Resize(ref _ioctlArgumentBuffer, (int)outputDataSize);
|
||||
}
|
||||
|
||||
arguments = _ioctlArgumentBuffer.AsSpan(0, (int)outputDataSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] temp = new byte[inputDataSize];
|
||||
if (!context.Memory.TryReadUnsafe(inputDataPosition, (int)inputDataSize, out arguments))
|
||||
{
|
||||
if (_ioctlArgumentBuffer.Length < (int)inputDataSize)
|
||||
{
|
||||
Array.Resize(ref _ioctlArgumentBuffer, (int)inputDataSize);
|
||||
}
|
||||
|
||||
arguments = _ioctlArgumentBuffer.AsSpan(0, (int)inputDataSize);
|
||||
|
||||
context.Memory.Read(inputDataPosition, temp);
|
||||
|
||||
arguments = new Span<byte>(temp);
|
||||
context.Memory.Read(inputDataPosition, arguments);
|
||||
}
|
||||
}
|
||||
|
||||
return NvResult.Success;
|
||||
@@ -270,7 +285,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
||||
|
||||
if ((ioctlCommand.DirectionValue & NvIoctl.Direction.Write) != 0)
|
||||
{
|
||||
context.Memory.Write(context.Request.GetBufferType0x22(0).Position, arguments.ToArray());
|
||||
context.Memory.Write(context.Request.GetBufferType0x22(0).Position, arguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -474,13 +489,15 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
||||
|
||||
errorCode = GetIoctlArgument(context, ioctlCommand, out Span<byte> arguments);
|
||||
|
||||
byte[] inlineInBuffer = null;
|
||||
|
||||
if (!context.Memory.TryReadUnsafe(inlineInBufferPosition, (int)inlineInBufferSize, out Span<byte> inlineInBufferSpan))
|
||||
{
|
||||
inlineInBuffer = _byteArrayPool.Rent((int)inlineInBufferSize);
|
||||
inlineInBufferSpan = inlineInBuffer;
|
||||
context.Memory.Read(inlineInBufferPosition, inlineInBufferSpan[..(int)inlineInBufferSize]);
|
||||
if (_ioctl2Buffer.Length < (int)inlineInBufferSize)
|
||||
{
|
||||
Array.Resize(ref _ioctl2Buffer, (int)inlineInBufferSize);
|
||||
}
|
||||
|
||||
inlineInBufferSpan = _ioctl2Buffer.AsSpan(0, (int)inlineInBufferSize);
|
||||
context.Memory.Read(inlineInBufferPosition, inlineInBufferSpan);
|
||||
}
|
||||
|
||||
if (errorCode == NvResult.Success)
|
||||
@@ -489,7 +506,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
||||
|
||||
if (errorCode == NvResult.Success)
|
||||
{
|
||||
NvInternalResult internalResult = deviceFile.Ioctl2(ioctlCommand, arguments, inlineInBufferSpan[..(int)inlineInBufferSize]);
|
||||
NvInternalResult internalResult = deviceFile.Ioctl2(ioctlCommand, arguments, inlineInBufferSpan);
|
||||
|
||||
if (internalResult == NvInternalResult.NotImplemented)
|
||||
{
|
||||
@@ -500,15 +517,10 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
||||
|
||||
if ((ioctlCommand.DirectionValue & NvIoctl.Direction.Write) != 0)
|
||||
{
|
||||
context.Memory.Write(context.Request.GetBufferType0x22(0).Position, arguments.ToArray());
|
||||
context.Memory.Write(context.Request.GetBufferType0x22(0).Position, arguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inlineInBuffer is not null)
|
||||
{
|
||||
_byteArrayPool.Return(inlineInBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
context.ResponseData.Write((uint)errorCode);
|
||||
@@ -531,13 +543,15 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
||||
|
||||
errorCode = GetIoctlArgument(context, ioctlCommand, out Span<byte> arguments);
|
||||
|
||||
byte[] inlineOutBuffer = null;
|
||||
|
||||
if (!context.Memory.TryReadUnsafe(inlineOutBufferPosition, (int)inlineOutBufferSize, out Span<byte> inlineOutBufferSpan))
|
||||
{
|
||||
inlineOutBuffer = _byteArrayPool.Rent((int)inlineOutBufferSize);
|
||||
inlineOutBufferSpan = inlineOutBuffer;
|
||||
context.Memory.Read(inlineOutBufferPosition, inlineOutBufferSpan[..(int)inlineOutBufferSize]);
|
||||
if (_ioctl3Buffer.Length < (int)inlineOutBufferSize)
|
||||
{
|
||||
Array.Resize(ref _ioctl3Buffer, (int)inlineOutBufferSize);
|
||||
}
|
||||
|
||||
inlineOutBufferSpan = _ioctl3Buffer.AsSpan(0, (int)inlineOutBufferSize);
|
||||
context.Memory.Read(inlineOutBufferPosition, inlineOutBufferSpan);
|
||||
}
|
||||
|
||||
if (errorCode == NvResult.Success)
|
||||
@@ -546,7 +560,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
||||
|
||||
if (errorCode == NvResult.Success)
|
||||
{
|
||||
NvInternalResult internalResult = deviceFile.Ioctl3(ioctlCommand, arguments, inlineOutBufferSpan[..(int)inlineOutBufferSize]);
|
||||
NvInternalResult internalResult = deviceFile.Ioctl3(ioctlCommand, arguments, inlineOutBufferSpan);
|
||||
|
||||
if (internalResult == NvInternalResult.NotImplemented)
|
||||
{
|
||||
@@ -557,16 +571,11 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
||||
|
||||
if ((ioctlCommand.DirectionValue & NvIoctl.Direction.Write) != 0)
|
||||
{
|
||||
context.Memory.Write(context.Request.GetBufferType0x22(0).Position, arguments.ToArray());
|
||||
context.Memory.Write(inlineOutBufferPosition, inlineOutBufferSpan[..(int)inlineOutBufferSize].ToArray());
|
||||
context.Memory.Write(context.Request.GetBufferType0x22(0).Position, arguments);
|
||||
context.Memory.Write(inlineOutBufferPosition, inlineOutBufferSpan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inlineOutBuffer is not null)
|
||||
{
|
||||
_byteArrayPool.Return(inlineOutBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
context.ResponseData.Write((uint)errorCode);
|
||||
|
||||
@@ -451,8 +451,9 @@ namespace Ryujinx.HLE.HOS.Services
|
||||
|
||||
response.RawData = _responseDataStream.ToArray();
|
||||
|
||||
using var responseStream = response.GetStreamTipc();
|
||||
var responseStream = response.GetStreamTipc();
|
||||
_selfProcess.CpuMemory.Write(_selfThread.TlsAddress, responseStream.GetReadOnlySequence());
|
||||
MemoryStreamManager.Shared.ReleaseStream(responseStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -461,8 +462,9 @@ namespace Ryujinx.HLE.HOS.Services
|
||||
|
||||
if (!isTipcCommunication)
|
||||
{
|
||||
using var responseStream = response.GetStream((long)_selfThread.TlsAddress, recvListAddr | ((ulong)PointerBufferSize << 48));
|
||||
var responseStream = response.GetStream((long)_selfThread.TlsAddress, recvListAddr | ((ulong)PointerBufferSize << 48));
|
||||
_selfProcess.CpuMemory.Write(_selfThread.TlsAddress, responseStream.GetReadOnlySequence());
|
||||
MemoryStreamManager.Shared.ReleaseStream(responseStream);
|
||||
}
|
||||
|
||||
return shouldReply;
|
||||
|
||||
Reference in New Issue
Block a user