diff --git a/Ryujinx.Graphics.Gpu/Image/Texture.cs b/Ryujinx.Graphics.Gpu/Image/Texture.cs index 363f0f73a..b784a5455 100644 --- a/Ryujinx.Graphics.Gpu/Image/Texture.cs +++ b/Ryujinx.Graphics.Gpu/Image/Texture.cs @@ -360,7 +360,7 @@ namespace Ryujinx.Graphics.Gpu.Image texture._viewStorage = this; - Group.UpdateViews(_views); + Group.UpdateViews(_views, texture); if (texture.Group != null && texture.Group != Group) { @@ -384,6 +384,8 @@ namespace Ryujinx.Graphics.Gpu.Image { _views.Remove(texture); + Group.RemoveView(texture); + texture._viewStorage = texture; DecrementReferenceCount(); diff --git a/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs b/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs index d9b620aae..b59a9d086 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs @@ -989,7 +989,8 @@ namespace Ryujinx.Graphics.Gpu.Image /// Update the views in this texture group, rebuilding the memory tracking if required. /// /// The views list of the storage texture - public void UpdateViews(List views) + /// The texture that has been added, if that is the only change, otherwise null + public void UpdateViews(List views, Texture texture) { // This is saved to calculate overlapping views for each handle. _views = views; @@ -1027,17 +1028,44 @@ namespace Ryujinx.Graphics.Gpu.Image if (!regionsRebuilt) { - // Must update the overlapping views on all handles, but only if they were not just recreated. - - foreach (TextureGroupHandle handle in _handles) + if (texture != null) { - handle.RecalculateOverlaps(this, views); + int offset = FindOffset(texture); + + foreach (TextureGroupHandle handle in _handles) + { + handle.AddOverlap(offset, texture); + } + } + else + { + // Must update the overlapping views on all handles, but only if they were not just recreated. + + foreach (TextureGroupHandle handle in _handles) + { + handle.RecalculateOverlaps(this, views); + } } } SignalAllDirty(); } + + /// + /// Removes a view from the group, removing it from all overlap lists. + /// + /// View to remove from the group + public void RemoveView(Texture view) + { + int offset = FindOffset(view); + + foreach (TextureGroupHandle handle in _handles) + { + handle.RemoveOverlap(offset, view); + } + } + /// /// Inherit handle state from an old set of handles, such as modified and dirty flags. /// diff --git a/Ryujinx.Graphics.Gpu/Image/TextureGroupHandle.cs b/Ryujinx.Graphics.Gpu/Image/TextureGroupHandle.cs index 1b83cb558..ebb4e9aeb 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureGroupHandle.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureGroupHandle.cs @@ -159,6 +159,42 @@ namespace Ryujinx.Graphics.Gpu.Image } } + /// + /// Adds a single texture view as an overlap if its range overlaps. + /// + /// The offset of the view in the group + /// The texture to add as an overlap + public void AddOverlap(int offset, Texture view) + { + // Overlaps can be accessed from the memory tracking signal handler, so access must be atomic. + + if (OverlapsWith(offset, (int)view.Size)) + { + lock (Overlaps) + { + Overlaps.Add(view); + } + } + } + + /// + /// Removes a single texture view as an overlap if its range overlaps. + /// + /// The offset of the view in the group + /// The texture to add as an overlap + public void RemoveOverlap(int offset, Texture view) + { + // Overlaps can be accessed from the memory tracking signal handler, so access must be atomic. + + if (OverlapsWith(offset, (int)view.Size)) + { + lock (Overlaps) + { + Overlaps.Remove(view); + } + } + } + /// /// Registers a sync action to happen for this handle, and an interim flush action on the tracking handle. ///