diff --git a/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs b/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs index be0abea21..4bdc50788 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs @@ -1393,6 +1393,12 @@ namespace Ryujinx.Graphics.Gpu.Image /// The size of the flushing memory access public void FlushAction(TextureGroupHandle handle, ulong address, ulong size) { + // 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. + + handle.ClearActionRegistered(); + if (!handle.Modified) { return; diff --git a/Ryujinx.Graphics.Gpu/Image/TextureGroupHandle.cs b/Ryujinx.Graphics.Gpu/Image/TextureGroupHandle.cs index 7d4aec411..34b59cffe 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureGroupHandle.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureGroupHandle.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; namespace Ryujinx.Graphics.Gpu.Image { @@ -32,9 +33,9 @@ namespace Ryujinx.Graphics.Gpu.Image private ulong _modifiedSync; /// - /// Whether a tracking action is currently registered or not. + /// Whether a tracking action is currently registered or not. (0/1) /// - private bool _actionRegistered; + private int _actionRegistered; /// /// Whether a sync action is currently registered or not. @@ -171,11 +172,9 @@ namespace Ryujinx.Graphics.Gpu.Image _syncActionRegistered = true; } - if (!_actionRegistered) + if (Interlocked.Exchange(ref _actionRegistered, 1) == 0) { _group.RegisterAction(this); - - _actionRegistered = true; } } @@ -233,8 +232,6 @@ namespace Ryujinx.Graphics.Gpu.Image /// The GPU context used to wait for sync public void Sync(GpuContext context) { - _actionRegistered = false; - bool needsSync = !context.IsGpuThread(); if (needsSync) @@ -263,21 +260,39 @@ namespace Ryujinx.Graphics.Gpu.Image } } + /// + /// Clears the action registered variable, indicating that the tracking action should be + /// re-registered on the next modification. + /// + public void ClearActionRegistered() + { + Interlocked.Exchange(ref _actionRegistered, 0); + } + /// /// Action to perform when a sync number is registered after modification. /// This action will register a read tracking action on the memory tracking handle so that a flush from CPU can happen. /// private void SyncAction() { + // The storage will need to signal modified again to update the sync number in future. + _group.Storage.SignalModifiedDirty(); + + lock (Overlaps) + { + foreach (Texture texture in Overlaps) + { + texture.SignalModifiedDirty(); + } + } + // Register region tracking for CPU? (again) _registeredSync = _modifiedSync; _syncActionRegistered = false; - if (!_actionRegistered) + if (Interlocked.Exchange(ref _actionRegistered, 1) == 0) { _group.RegisterAction(this); - - _actionRegistered = true; } } diff --git a/Ryujinx.Memory/Tracking/RegionHandle.cs b/Ryujinx.Memory/Tracking/RegionHandle.cs index 5ecd53a2b..b30dcbc25 100644 --- a/Ryujinx.Memory/Tracking/RegionHandle.cs +++ b/Ryujinx.Memory/Tracking/RegionHandle.cs @@ -144,9 +144,9 @@ namespace Ryujinx.Memory.Tracking { lock (_preActionLock) { - _preAction?.Invoke(address, size); + RegionSignal action = Interlocked.Exchange(ref _preAction, null); - _preAction = null; + action?.Invoke(address, size); } } finally @@ -252,8 +252,7 @@ namespace Ryujinx.Memory.Tracking lock (_preActionLock) { - RegionSignal lastAction = _preAction; - _preAction = action; + RegionSignal lastAction = Interlocked.Exchange(ref _preAction, action); if (lastAction == null && action != lastAction) {