AutoDeleteCache.cs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. namespace Ryujinx.Graphics.Gpu.Image
  4. {
  5. /// <summary>
  6. /// A texture cache that automatically removes older textures that are not used for some time.
  7. /// The cache works with a rotated list with a fixed size. When new textures are added, the
  8. /// old ones at the bottom of the list are deleted.
  9. /// </summary>
  10. class AutoDeleteCache : IEnumerable<Texture>
  11. {
  12. private const int MaxCapacity = 2048;
  13. private readonly LinkedList<Texture> _textures;
  14. /// <summary>
  15. /// Creates a new instance of the automatic deletion cache.
  16. /// </summary>
  17. public AutoDeleteCache()
  18. {
  19. _textures = new LinkedList<Texture>();
  20. }
  21. /// <summary>
  22. /// Adds a new texture to the cache, even if the texture added is already on the cache.
  23. /// </summary>
  24. /// <remarks>
  25. /// Using this method is only recommended if you know that the texture is not yet on the cache,
  26. /// otherwise it would store the same texture more than once.
  27. /// </remarks>
  28. /// <param name="texture">The texture to be added to the cache</param>
  29. public void Add(Texture texture)
  30. {
  31. texture.IncrementReferenceCount();
  32. texture.CacheNode = _textures.AddLast(texture);
  33. if (_textures.Count > MaxCapacity)
  34. {
  35. Texture oldestTexture = _textures.First.Value;
  36. if (!oldestTexture.CheckModified(false))
  37. {
  38. // The texture must be flushed if it falls out of the auto delete cache.
  39. // Flushes out of the auto delete cache do not trigger write tracking,
  40. // as it is expected that other overlapping textures exist that have more up-to-date contents.
  41. oldestTexture.Group.SynchronizeDependents(oldestTexture);
  42. oldestTexture.FlushModified(false);
  43. }
  44. _textures.RemoveFirst();
  45. oldestTexture.DecrementReferenceCount();
  46. oldestTexture.CacheNode = null;
  47. }
  48. }
  49. /// <summary>
  50. /// Adds a new texture to the cache, or just moves it to the top of the list if the
  51. /// texture is already on the cache.
  52. /// </summary>
  53. /// <remarks>
  54. /// Moving the texture to the top of the list prevents it from being deleted,
  55. /// as the textures on the bottom of the list are deleted when new ones are added.
  56. /// </remarks>
  57. /// <param name="texture">The texture to be added, or moved to the top</param>
  58. public void Lift(Texture texture)
  59. {
  60. if (texture.CacheNode != null)
  61. {
  62. if (texture.CacheNode != _textures.Last)
  63. {
  64. _textures.Remove(texture.CacheNode);
  65. texture.CacheNode = _textures.AddLast(texture);
  66. }
  67. }
  68. else
  69. {
  70. Add(texture);
  71. }
  72. }
  73. public bool Remove(Texture texture, bool flush)
  74. {
  75. if (texture.CacheNode == null)
  76. {
  77. return false;
  78. }
  79. // Remove our reference to this texture.
  80. if (flush)
  81. {
  82. texture.FlushModified(false);
  83. }
  84. _textures.Remove(texture.CacheNode);
  85. texture.CacheNode = null;
  86. return texture.DecrementReferenceCount();
  87. }
  88. public IEnumerator<Texture> GetEnumerator()
  89. {
  90. return _textures.GetEnumerator();
  91. }
  92. IEnumerator IEnumerable.GetEnumerator()
  93. {
  94. return _textures.GetEnumerator();
  95. }
  96. }
  97. }