CacheByRange.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. using System;
  2. using System.Collections.Generic;
  3. namespace Ryujinx.Graphics.Vulkan
  4. {
  5. interface ICacheKey : IDisposable
  6. {
  7. bool KeyEqual(ICacheKey other);
  8. }
  9. struct I8ToI16CacheKey : ICacheKey
  10. {
  11. // Used to notify the pipeline that bindings have invalidated on dispose.
  12. private readonly VulkanRenderer _gd;
  13. private Auto<DisposableBuffer> _buffer;
  14. public I8ToI16CacheKey(VulkanRenderer gd)
  15. {
  16. _gd = gd;
  17. _buffer = null;
  18. }
  19. public bool KeyEqual(ICacheKey other)
  20. {
  21. return other is I8ToI16CacheKey;
  22. }
  23. public void SetBuffer(Auto<DisposableBuffer> buffer)
  24. {
  25. _buffer = buffer;
  26. }
  27. public void Dispose()
  28. {
  29. _gd.PipelineInternal.DirtyIndexBuffer(_buffer);
  30. }
  31. }
  32. struct AlignedVertexBufferCacheKey : ICacheKey
  33. {
  34. private readonly int _stride;
  35. private readonly int _alignment;
  36. // Used to notify the pipeline that bindings have invalidated on dispose.
  37. private readonly VulkanRenderer _gd;
  38. private Auto<DisposableBuffer> _buffer;
  39. public AlignedVertexBufferCacheKey(VulkanRenderer gd, int stride, int alignment)
  40. {
  41. _gd = gd;
  42. _stride = stride;
  43. _alignment = alignment;
  44. _buffer = null;
  45. }
  46. public bool KeyEqual(ICacheKey other)
  47. {
  48. return other is AlignedVertexBufferCacheKey entry &&
  49. entry._stride == _stride &&
  50. entry._alignment == _alignment;
  51. }
  52. public void SetBuffer(Auto<DisposableBuffer> buffer)
  53. {
  54. _buffer = buffer;
  55. }
  56. public void Dispose()
  57. {
  58. _gd.PipelineInternal.DirtyVertexBuffer(_buffer);
  59. }
  60. }
  61. struct TopologyConversionCacheKey : ICacheKey
  62. {
  63. private IndexBufferPattern _pattern;
  64. private int _indexSize;
  65. // Used to notify the pipeline that bindings have invalidated on dispose.
  66. private readonly VulkanRenderer _gd;
  67. private Auto<DisposableBuffer> _buffer;
  68. public TopologyConversionCacheKey(VulkanRenderer gd, IndexBufferPattern pattern, int indexSize)
  69. {
  70. _gd = gd;
  71. _pattern = pattern;
  72. _indexSize = indexSize;
  73. _buffer = null;
  74. }
  75. public bool KeyEqual(ICacheKey other)
  76. {
  77. return other is TopologyConversionCacheKey entry &&
  78. entry._pattern == _pattern &&
  79. entry._indexSize == _indexSize;
  80. }
  81. public void SetBuffer(Auto<DisposableBuffer> buffer)
  82. {
  83. _buffer = buffer;
  84. }
  85. public void Dispose()
  86. {
  87. _gd.PipelineInternal.DirtyIndexBuffer(_buffer);
  88. }
  89. }
  90. readonly struct TopologyConversionIndirectCacheKey : ICacheKey
  91. {
  92. private readonly TopologyConversionCacheKey _baseKey;
  93. private readonly BufferHolder _indirectDataBuffer;
  94. private readonly int _indirectDataOffset;
  95. private readonly int _indirectDataSize;
  96. public TopologyConversionIndirectCacheKey(
  97. VulkanRenderer gd,
  98. IndexBufferPattern pattern,
  99. int indexSize,
  100. BufferHolder indirectDataBuffer,
  101. int indirectDataOffset,
  102. int indirectDataSize)
  103. {
  104. _baseKey = new TopologyConversionCacheKey(gd, pattern, indexSize);
  105. _indirectDataBuffer = indirectDataBuffer;
  106. _indirectDataOffset = indirectDataOffset;
  107. _indirectDataSize = indirectDataSize;
  108. }
  109. public bool KeyEqual(ICacheKey other)
  110. {
  111. return other is TopologyConversionIndirectCacheKey entry &&
  112. entry._baseKey.KeyEqual(_baseKey) &&
  113. entry._indirectDataBuffer == _indirectDataBuffer &&
  114. entry._indirectDataOffset == _indirectDataOffset &&
  115. entry._indirectDataSize == _indirectDataSize;
  116. }
  117. public void SetBuffer(Auto<DisposableBuffer> buffer)
  118. {
  119. _baseKey.SetBuffer(buffer);
  120. }
  121. public void Dispose()
  122. {
  123. _baseKey.Dispose();
  124. }
  125. }
  126. struct IndirectDataCacheKey : ICacheKey
  127. {
  128. private IndexBufferPattern _pattern;
  129. public IndirectDataCacheKey(IndexBufferPattern pattern)
  130. {
  131. _pattern = pattern;
  132. }
  133. public bool KeyEqual(ICacheKey other)
  134. {
  135. return other is IndirectDataCacheKey entry && entry._pattern == _pattern;
  136. }
  137. public void Dispose()
  138. {
  139. }
  140. }
  141. struct DrawCountCacheKey : ICacheKey
  142. {
  143. public bool KeyEqual(ICacheKey other)
  144. {
  145. return other is DrawCountCacheKey;
  146. }
  147. public void Dispose()
  148. {
  149. }
  150. }
  151. readonly struct Dependency
  152. {
  153. private readonly BufferHolder _buffer;
  154. private readonly int _offset;
  155. private readonly int _size;
  156. private readonly ICacheKey _key;
  157. public Dependency(BufferHolder buffer, int offset, int size, ICacheKey key)
  158. {
  159. _buffer = buffer;
  160. _offset = offset;
  161. _size = size;
  162. _key = key;
  163. }
  164. public void RemoveFromOwner()
  165. {
  166. _buffer.RemoveCachedConvertedBuffer(_offset, _size, _key);
  167. }
  168. }
  169. struct CacheByRange<T> where T : IDisposable
  170. {
  171. private struct Entry
  172. {
  173. public ICacheKey Key;
  174. public T Value;
  175. public List<Dependency> DependencyList;
  176. public Entry(ICacheKey key, T value)
  177. {
  178. Key = key;
  179. Value = value;
  180. DependencyList = null;
  181. }
  182. public void InvalidateDependencies()
  183. {
  184. if (DependencyList != null)
  185. {
  186. foreach (Dependency dependency in DependencyList)
  187. {
  188. dependency.RemoveFromOwner();
  189. }
  190. DependencyList.Clear();
  191. }
  192. }
  193. }
  194. private Dictionary<ulong, List<Entry>> _ranges;
  195. public void Add(int offset, int size, ICacheKey key, T value)
  196. {
  197. List<Entry> entries = GetEntries(offset, size);
  198. entries.Add(new Entry(key, value));
  199. }
  200. public void AddDependency(int offset, int size, ICacheKey key, Dependency dependency)
  201. {
  202. List<Entry> entries = GetEntries(offset, size);
  203. for (int i = 0; i < entries.Count; i++)
  204. {
  205. Entry entry = entries[i];
  206. if (entry.Key.KeyEqual(key))
  207. {
  208. if (entry.DependencyList == null)
  209. {
  210. entry.DependencyList = new List<Dependency>();
  211. entries[i] = entry;
  212. }
  213. entry.DependencyList.Add(dependency);
  214. break;
  215. }
  216. }
  217. }
  218. public void Remove(int offset, int size, ICacheKey key)
  219. {
  220. List<Entry> entries = GetEntries(offset, size);
  221. for (int i = 0; i < entries.Count; i++)
  222. {
  223. Entry entry = entries[i];
  224. if (entry.Key.KeyEqual(key))
  225. {
  226. entries.RemoveAt(i--);
  227. DestroyEntry(entry);
  228. }
  229. }
  230. if (entries.Count == 0)
  231. {
  232. _ranges.Remove(PackRange(offset, size));
  233. }
  234. }
  235. public bool TryGetValue(int offset, int size, ICacheKey key, out T value)
  236. {
  237. List<Entry> entries = GetEntries(offset, size);
  238. foreach (Entry entry in entries)
  239. {
  240. if (entry.Key.KeyEqual(key))
  241. {
  242. value = entry.Value;
  243. return true;
  244. }
  245. }
  246. value = default;
  247. return false;
  248. }
  249. public void Clear()
  250. {
  251. if (_ranges != null)
  252. {
  253. foreach (List<Entry> entries in _ranges.Values)
  254. {
  255. foreach (Entry entry in entries)
  256. {
  257. DestroyEntry(entry);
  258. }
  259. }
  260. _ranges.Clear();
  261. _ranges = null;
  262. }
  263. }
  264. public void ClearRange(int offset, int size)
  265. {
  266. if (_ranges != null && _ranges.Count > 0)
  267. {
  268. int end = offset + size;
  269. List<ulong> toRemove = null;
  270. foreach (KeyValuePair<ulong, List<Entry>> range in _ranges)
  271. {
  272. (int rOffset, int rSize) = UnpackRange(range.Key);
  273. int rEnd = rOffset + rSize;
  274. if (rEnd > offset && rOffset < end)
  275. {
  276. List<Entry> entries = range.Value;
  277. foreach (Entry entry in entries)
  278. {
  279. DestroyEntry(entry);
  280. }
  281. (toRemove ??= new List<ulong>()).Add(range.Key);
  282. }
  283. }
  284. if (toRemove != null)
  285. {
  286. foreach (ulong range in toRemove)
  287. {
  288. _ranges.Remove(range);
  289. }
  290. }
  291. }
  292. }
  293. private List<Entry> GetEntries(int offset, int size)
  294. {
  295. if (_ranges == null)
  296. {
  297. _ranges = new Dictionary<ulong, List<Entry>>();
  298. }
  299. ulong key = PackRange(offset, size);
  300. List<Entry> value;
  301. if (!_ranges.TryGetValue(key, out value))
  302. {
  303. value = new List<Entry>();
  304. _ranges.Add(key, value);
  305. }
  306. return value;
  307. }
  308. private static void DestroyEntry(Entry entry)
  309. {
  310. entry.Key.Dispose();
  311. entry.Value?.Dispose();
  312. entry.InvalidateDependencies();
  313. }
  314. private static ulong PackRange(int offset, int size)
  315. {
  316. return (uint)offset | ((ulong)size << 32);
  317. }
  318. private static (int offset, int size) UnpackRange(ulong range)
  319. {
  320. return ((int)range, (int)(range >> 32));
  321. }
  322. public void Dispose()
  323. {
  324. Clear();
  325. }
  326. }
  327. }