AutoDeleteCache.cs 3.8 KB

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