blob: 4a1615f043f456d9e724e636fffdac3dc219c1e3 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
namespace Ryujinx.Graphics.Gpu.Image
{
/// <summary>
/// A texture cache that automatically removes older textures that are not used for some time.
/// The cache works with a rotated list with a fixed size. When new textures are added, the
/// old ones at the bottom of the list are deleted.
/// </summary>
class AutoDeleteCache : IEnumerable<Texture>
{
private const int MaxCapacity = 2048;
private readonly LinkedList<Texture> _textures;
private readonly ConcurrentQueue<Texture> _deferredRemovals;
/// <summary>
/// Creates a new instance of the automatic deletion cache.
/// </summary>
public AutoDeleteCache()
{
_textures = new LinkedList<Texture>();
_deferredRemovals = new ConcurrentQueue<Texture>();
}
/// <summary>
/// Adds a new texture to the cache, even if the texture added is already on the cache.
/// </summary>
/// <remarks>
/// Using this method is only recommended if you know that the texture is not yet on the cache,
/// otherwise it would store the same texture more than once.
/// </remarks>
/// <param name="texture">The texture to be added to the cache</param>
public void Add(Texture texture)
{
texture.IncrementReferenceCount();
texture.CacheNode = _textures.AddLast(texture);
if (_textures.Count > MaxCapacity)
{
Texture oldestTexture = _textures.First.Value;
if (!oldestTexture.CheckModified(false))
{
// The texture must be flushed if it falls out of the auto delete cache.
// Flushes out of the auto delete cache do not trigger write tracking,
// as it is expected that other overlapping textures exist that have more up-to-date contents.
oldestTexture.Group.SynchronizeDependents(oldestTexture);
oldestTexture.FlushModified(false);
}
_textures.RemoveFirst();
oldestTexture.DecrementReferenceCount();
oldestTexture.CacheNode = null;
}
if (_deferredRemovals.Count > 0)
{
while (_deferredRemovals.TryDequeue(out Texture textureToRemove))
{
Remove(textureToRemove, false);
}
}
}
/// <summary>
/// Adds a new texture to the cache, or just moves it to the top of the list if the
/// texture is already on the cache.
/// </summary>
/// <remarks>
/// Moving the texture to the top of the list prevents it from being deleted,
/// as the textures on the bottom of the list are deleted when new ones are added.
/// </remarks>
/// <param name="texture">The texture to be added, or moved to the top</param>
public void Lift(Texture texture)
{
if (texture.CacheNode != null)
{
if (texture.CacheNode != _textures.Last)
{
_textures.Remove(texture.CacheNode);
texture.CacheNode = _textures.AddLast(texture);
}
}
else
{
Add(texture);
}
}
/// <summary>
/// Removes a texture from the cache.
/// </summary>
/// <param name="texture">The texture to be removed from the cache</param>
/// <param name="flush">True to remove the texture if it was on the cache</param>
/// <returns>True if the texture was found and removed, false otherwise</returns>
public bool Remove(Texture texture, bool flush)
{
if (texture.CacheNode == null)
{
return false;
}
// Remove our reference to this texture.
if (flush)
{
texture.FlushModified(false);
}
_textures.Remove(texture.CacheNode);
texture.CacheNode = null;
return texture.DecrementReferenceCount();
}
/// <summary>
/// Queues removal of a texture from the cache in a thread safe way.
/// </summary>
/// <param name="texture">The texture to be removed from the cache</param>
public void RemoveDeferred(Texture texture)
{
_deferredRemovals.Enqueue(texture);
}
public IEnumerator<Texture> GetEnumerator()
{
return _textures.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _textures.GetEnumerator();
}
}
}
|