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)
{