diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs index 5743c89c0..b9ff060e2 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs @@ -8,6 +8,7 @@ using Ryujinx.Graphics.Texture; using Ryujinx.Memory.Range; using System; using System.Collections.Generic; +using System.Threading; namespace Ryujinx.Graphics.Gpu.Image { @@ -39,6 +40,8 @@ namespace Ryujinx.Graphics.Gpu.Image private readonly MultiRangeList _textures; private readonly HashSet _partiallyMappedTextures; + private readonly ReaderWriterLockSlim _texturesLock; + private Texture[] _textureOverlaps; private OverlapInfo[] _overlapInfo; @@ -57,6 +60,8 @@ namespace Ryujinx.Graphics.Gpu.Image _textures = new MultiRangeList(); _partiallyMappedTextures = new HashSet(); + _texturesLock = new ReaderWriterLockSlim(); + _textureOverlaps = new Texture[OverlapsBufferInitialCapacity]; _overlapInfo = new OverlapInfo[OverlapsBufferInitialCapacity]; @@ -75,10 +80,16 @@ namespace Ryujinx.Graphics.Gpu.Image MultiRange unmapped = ((MemoryManager)sender).GetPhysicalRegions(e.Address, e.Size); - lock (_textures) + _texturesLock.EnterReadLock(); + + try { overlapCount = _textures.FindOverlaps(unmapped, ref overlaps); } + finally + { + _texturesLock.ExitReadLock(); + } if (overlapCount > 0) { @@ -217,7 +228,18 @@ namespace Ryujinx.Graphics.Gpu.Image public bool UpdateMapping(Texture texture, MultiRange range) { // There cannot be an existing texture compatible with this mapping in the texture cache already. - int overlapCount = _textures.FindOverlaps(range, ref _textureOverlaps); + int overlapCount; + + _texturesLock.EnterReadLock(); + + try + { + overlapCount = _textures.FindOverlaps(range, ref _textureOverlaps); + } + finally + { + _texturesLock.ExitReadLock(); + } for (int i = 0; i < overlapCount; i++) { @@ -231,11 +253,20 @@ namespace Ryujinx.Graphics.Gpu.Image } } - _textures.Remove(texture); + _texturesLock.EnterWriteLock(); - texture.ReplaceRange(range); + try + { + _textures.Remove(texture); - _textures.Add(texture); + texture.ReplaceRange(range); + + _textures.Add(texture); + } + finally + { + _texturesLock.ExitWriteLock(); + } return true; } @@ -611,11 +642,17 @@ namespace Ryujinx.Graphics.Gpu.Image int sameAddressOverlapsCount; - lock (_textures) + _texturesLock.EnterReadLock(); + + try { // Try to find a perfect texture match, with the same address and parameters. sameAddressOverlapsCount = _textures.FindOverlaps(address, ref _textureOverlaps); } + finally + { + _texturesLock.ExitReadLock(); + } Texture texture = null; @@ -698,10 +735,16 @@ namespace Ryujinx.Graphics.Gpu.Image if (info.Target != Target.TextureBuffer) { - lock (_textures) + _texturesLock.EnterReadLock(); + + try { overlapsCount = _textures.FindOverlaps(range.Value, ref _textureOverlaps); } + finally + { + _texturesLock.ExitReadLock(); + } } if (_overlapInfo.Length != _textureOverlaps.Length) @@ -1025,10 +1068,16 @@ namespace Ryujinx.Graphics.Gpu.Image _cache.Add(texture); } - lock (_textures) + _texturesLock.EnterWriteLock(); + + try { _textures.Add(texture); } + finally + { + _texturesLock.ExitWriteLock(); + } if (partiallyMapped) { @@ -1091,7 +1140,19 @@ namespace Ryujinx.Graphics.Gpu.Image return null; } - int addressMatches = _textures.FindOverlaps(address, ref _textureOverlaps); + int addressMatches; + + _texturesLock.EnterReadLock(); + + try + { + addressMatches = _textures.FindOverlaps(address, ref _textureOverlaps); + } + finally + { + _texturesLock.ExitReadLock(); + } + Texture textureMatch = null; for (int i = 0; i < addressMatches; i++) @@ -1232,10 +1293,16 @@ namespace Ryujinx.Graphics.Gpu.Image /// The texture to be removed public void RemoveTextureFromCache(Texture texture) { - lock (_textures) + _texturesLock.EnterWriteLock(); + + try { _textures.Remove(texture); } + finally + { + _texturesLock.ExitWriteLock(); + } lock (_partiallyMappedTextures) { @@ -1324,13 +1391,19 @@ namespace Ryujinx.Graphics.Gpu.Image /// public void Dispose() { - lock (_textures) + _texturesLock.EnterReadLock(); + + try { foreach (Texture texture in _textures) { texture.Dispose(); } } + finally + { + _texturesLock.ExitReadLock(); + } } } }