Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
a16d582a10 | ||
|
9ef0be477b |
@@ -101,6 +101,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// </summary>
|
||||
public bool AlwaysFlushOnOverlap { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the texture was fully unmapped since the modified flag was set, and flushes should be ignored until it is modified again.
|
||||
/// </summary>
|
||||
public bool FlushStale { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Increments when the host texture is swapped, or when the texture is removed from all pools.
|
||||
/// </summary>
|
||||
@@ -149,6 +154,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// </summary>
|
||||
public bool HadPoolOwner { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Physical memory ranges where the texture data is located.
|
||||
/// </summary>
|
||||
public MultiRange Range { get; private set; }
|
||||
@@ -1411,6 +1417,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// </summary>
|
||||
public void SignalModified()
|
||||
{
|
||||
FlushStale = false;
|
||||
_scaledSetScore = Math.Max(0, _scaledSetScore - 1);
|
||||
|
||||
if (_modifiedStale || Group.HasCopyDependencies)
|
||||
@@ -1431,6 +1438,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
if (bound)
|
||||
{
|
||||
FlushStale = false;
|
||||
_scaledSetScore = Math.Max(0, _scaledSetScore - 1);
|
||||
}
|
||||
|
||||
@@ -1695,12 +1703,17 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// <param name="unmapRange">The range of memory being unmapped</param>
|
||||
public void Unmapped(MultiRange unmapRange)
|
||||
{
|
||||
if (unmapRange.Contains(Range))
|
||||
{
|
||||
// If this is a full unmap, prevent flushes until the texture is mapped again.
|
||||
FlushStale = true;
|
||||
}
|
||||
|
||||
ChangedMapping = true;
|
||||
|
||||
if (Group.Storage == this)
|
||||
{
|
||||
Group.Unmapped();
|
||||
|
||||
Group.ClearModified(unmapRange);
|
||||
}
|
||||
}
|
||||
|
@@ -107,8 +107,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
// Any texture that has been unmapped at any point or is partially unmapped
|
||||
// should update their pool references after the remap completes.
|
||||
|
||||
MultiRange unmapped = ((MemoryManager)sender).GetPhysicalRegions(e.Address, e.Size);
|
||||
|
||||
foreach (var texture in _partiallyMappedTextures)
|
||||
{
|
||||
texture.UpdatePoolMappings();
|
||||
|
@@ -1659,6 +1659,14 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
return;
|
||||
}
|
||||
|
||||
// If size is zero, we have nothing to flush.
|
||||
// If the flush is stale, we should ignore it because the texture was unmapped since the modified
|
||||
// flag was set, and flushing it is not safe anymore as the GPU might no longer own the memory.
|
||||
if (size == 0 || Storage.FlushStale)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// There is a small gap here where the action is removed but _actionRegistered is still 1.
|
||||
// In this case it will skip registering the action, but here we are already handling it,
|
||||
// so there shouldn't be any issue as it's the same handler for all actions.
|
||||
|
@@ -39,6 +39,8 @@ namespace Ryujinx.HLE.HOS.Services
|
||||
private readonly KernelContext _context;
|
||||
private KProcess _selfProcess;
|
||||
private KThread _selfThread;
|
||||
private KEvent _wakeEvent;
|
||||
private int _wakeHandle = 0;
|
||||
|
||||
private readonly ReaderWriterLockSlim _handleLock = new();
|
||||
private readonly Dictionary<int, IpcService> _sessions = new();
|
||||
@@ -125,6 +127,8 @@ namespace Ryujinx.HLE.HOS.Services
|
||||
_handleLock.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
_wakeEvent.WritableEvent.Signal();
|
||||
}
|
||||
|
||||
private IpcService GetSessionObj(int serverSessionHandle)
|
||||
@@ -195,9 +199,11 @@ namespace Ryujinx.HLE.HOS.Services
|
||||
_selfProcess.CpuMemory.Write(messagePtr + 0x0, 0);
|
||||
_selfProcess.CpuMemory.Write(messagePtr + 0x4, 2 << 10);
|
||||
_selfProcess.CpuMemory.Write(messagePtr + 0x8, heapAddr | ((ulong)PointerBufferSize << 48));
|
||||
|
||||
int replyTargetHandle = 0;
|
||||
|
||||
_wakeEvent = new KEvent(_context);
|
||||
Result result = _selfProcess.HandleTable.GenerateHandle(_wakeEvent.ReadableEvent, out _wakeHandle);
|
||||
|
||||
while (true)
|
||||
{
|
||||
int portHandleCount;
|
||||
@@ -211,13 +217,15 @@ namespace Ryujinx.HLE.HOS.Services
|
||||
|
||||
portHandleCount = _ports.Count;
|
||||
|
||||
handleCount = portHandleCount + _sessions.Count;
|
||||
handleCount = portHandleCount + _sessions.Count + 1;
|
||||
|
||||
handles = ArrayPool<int>.Shared.Rent(handleCount);
|
||||
|
||||
_ports.Keys.CopyTo(handles, 0);
|
||||
handles[0] = _wakeHandle;
|
||||
|
||||
_sessions.Keys.CopyTo(handles, portHandleCount);
|
||||
_ports.Keys.CopyTo(handles, 1);
|
||||
|
||||
_sessions.Keys.CopyTo(handles, portHandleCount + 1);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -227,8 +235,7 @@ namespace Ryujinx.HLE.HOS.Services
|
||||
}
|
||||
}
|
||||
|
||||
// We still need a timeout here to allow the service to pick up and listen new sessions...
|
||||
var rc = _context.Syscall.ReplyAndReceive(out int signaledIndex, handles.AsSpan(0, handleCount), replyTargetHandle, 1000000L);
|
||||
var rc = _context.Syscall.ReplyAndReceive(out int signaledIndex, handles.AsSpan(0, handleCount), replyTargetHandle, -1);
|
||||
|
||||
_selfThread.HandlePostSyscall();
|
||||
|
||||
@@ -239,7 +246,7 @@ namespace Ryujinx.HLE.HOS.Services
|
||||
|
||||
replyTargetHandle = 0;
|
||||
|
||||
if (rc == Result.Success && signaledIndex >= portHandleCount)
|
||||
if (rc == Result.Success && signaledIndex >= portHandleCount + 1)
|
||||
{
|
||||
// We got a IPC request, process it, pass to the appropriate service if needed.
|
||||
int signaledHandle = handles[signaledIndex];
|
||||
@@ -253,24 +260,32 @@ namespace Ryujinx.HLE.HOS.Services
|
||||
{
|
||||
if (rc == Result.Success)
|
||||
{
|
||||
// We got a new connection, accept the session to allow servicing future requests.
|
||||
if (_context.Syscall.AcceptSession(out int serverSessionHandle, handles[signaledIndex]) == Result.Success)
|
||||
if (signaledIndex > 0)
|
||||
{
|
||||
bool handleWriteLockTaken = false;
|
||||
try
|
||||
// We got a new connection, accept the session to allow servicing future requests.
|
||||
if (_context.Syscall.AcceptSession(out int serverSessionHandle, handles[signaledIndex]) == Result.Success)
|
||||
{
|
||||
handleWriteLockTaken = _handleLock.TryEnterWriteLock(Timeout.Infinite);
|
||||
IpcService obj = _ports[handles[signaledIndex]].Invoke();
|
||||
_sessions.Add(serverSessionHandle, obj);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (handleWriteLockTaken)
|
||||
bool handleWriteLockTaken = false;
|
||||
try
|
||||
{
|
||||
_handleLock.ExitWriteLock();
|
||||
handleWriteLockTaken = _handleLock.TryEnterWriteLock(Timeout.Infinite);
|
||||
IpcService obj = _ports[handles[signaledIndex]].Invoke();
|
||||
_sessions.Add(serverSessionHandle, obj);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (handleWriteLockTaken)
|
||||
{
|
||||
_handleLock.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The _wakeEvent signalled, which means we have a new session.
|
||||
_wakeEvent.WritableEvent.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
_selfProcess.CpuMemory.Write(messagePtr + 0x0, 0);
|
||||
@@ -499,6 +514,8 @@ namespace Ryujinx.HLE.HOS.Services
|
||||
|
||||
if (Interlocked.Exchange(ref _isDisposed, 1) == 0)
|
||||
{
|
||||
_selfProcess.HandleTable.CloseHandle(_wakeHandle);
|
||||
|
||||
foreach (IpcService service in _sessions.Values)
|
||||
{
|
||||
(service as IDisposable)?.Dispose();
|
||||
|
Reference in New Issue
Block a user