Pool.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. using Ryujinx.Cpu.Tracking;
  2. using Ryujinx.Graphics.Gpu.Memory;
  3. using System;
  4. namespace Ryujinx.Graphics.Gpu.Image
  5. {
  6. /// <summary>
  7. /// Represents a pool of GPU resources, such as samplers or textures.
  8. /// </summary>
  9. /// <typeparam name="T1">Type of the GPU resource</typeparam>
  10. /// <typeparam name="T2">Type of the descriptor</typeparam>
  11. abstract class Pool<T1, T2> : IDisposable where T2 : unmanaged
  12. {
  13. protected const int DescriptorSize = 0x20;
  14. protected GpuContext Context;
  15. protected PhysicalMemory PhysicalMemory;
  16. protected int SequenceNumber;
  17. protected T1[] Items;
  18. protected T2[] DescriptorCache;
  19. /// <summary>
  20. /// The maximum ID value of resources on the pool (inclusive).
  21. /// </summary>
  22. /// <remarks>
  23. /// The maximum amount of resources on the pool is equal to this value plus one.
  24. /// </remarks>
  25. public int MaximumId { get; }
  26. /// <summary>
  27. /// The address of the pool in guest memory.
  28. /// </summary>
  29. public ulong Address { get; }
  30. /// <summary>
  31. /// The size of the pool in bytes.
  32. /// </summary>
  33. public ulong Size { get; }
  34. private readonly CpuMultiRegionHandle _memoryTracking;
  35. private readonly Action<ulong, ulong> _modifiedDelegate;
  36. /// <summary>
  37. /// Creates a new instance of the GPU resource pool.
  38. /// </summary>
  39. /// <param name="context">GPU context that the pool belongs to</param>
  40. /// <param name="physicalMemory">Physical memory where the resource descriptors are mapped</param>
  41. /// <param name="address">Address of the pool in physical memory</param>
  42. /// <param name="maximumId">Maximum index of an item on the pool (inclusive)</param>
  43. public Pool(GpuContext context, PhysicalMemory physicalMemory, ulong address, int maximumId)
  44. {
  45. Context = context;
  46. PhysicalMemory = physicalMemory;
  47. MaximumId = maximumId;
  48. int count = maximumId + 1;
  49. ulong size = (ulong)(uint)count * DescriptorSize;
  50. Items = new T1[count];
  51. DescriptorCache = new T2[count];
  52. Address = address;
  53. Size = size;
  54. _memoryTracking = physicalMemory.BeginGranularTracking(address, size);
  55. _memoryTracking.RegisterPreciseAction(address, size, PreciseAction);
  56. _modifiedDelegate = RegionModified;
  57. }
  58. /// <summary>
  59. /// Gets the descriptor for a given ID.
  60. /// </summary>
  61. /// <param name="id">ID of the descriptor. This is effectively a zero-based index</param>
  62. /// <returns>The descriptor</returns>
  63. public T2 GetDescriptor(int id)
  64. {
  65. return PhysicalMemory.Read<T2>(Address + (ulong)id * DescriptorSize);
  66. }
  67. /// <summary>
  68. /// Gets the GPU resource with the given ID.
  69. /// </summary>
  70. /// <param name="id">ID of the resource. This is effectively a zero-based index</param>
  71. /// <returns>The GPU resource with the given ID</returns>
  72. public abstract T1 Get(int id);
  73. /// <summary>
  74. /// Synchronizes host memory with guest memory.
  75. /// This causes invalidation of pool entries,
  76. /// if a modification of entries by the CPU is detected.
  77. /// </summary>
  78. public void SynchronizeMemory()
  79. {
  80. _memoryTracking.QueryModified(_modifiedDelegate);
  81. }
  82. /// <summary>
  83. /// Indicate that a region of the pool was modified, and must be loaded from memory.
  84. /// </summary>
  85. /// <param name="mAddress">Start address of the modified region</param>
  86. /// <param name="mSize">Size of the modified region</param>
  87. private void RegionModified(ulong mAddress, ulong mSize)
  88. {
  89. if (mAddress < Address)
  90. {
  91. mAddress = Address;
  92. }
  93. ulong maxSize = Address + Size - mAddress;
  94. if (mSize > maxSize)
  95. {
  96. mSize = maxSize;
  97. }
  98. InvalidateRangeImpl(mAddress, mSize);
  99. }
  100. /// <summary>
  101. /// An action to be performed when a precise memory access occurs to this resource.
  102. /// Makes sure that the dirty flags are checked.
  103. /// </summary>
  104. /// <param name="address">Address of the memory action</param>
  105. /// <param name="size">Size in bytes</param>
  106. /// <param name="write">True if the access was a write, false otherwise</param>
  107. private bool PreciseAction(ulong address, ulong size, bool write)
  108. {
  109. if (write && Context.SequenceNumber == SequenceNumber)
  110. {
  111. SequenceNumber--;
  112. }
  113. return false;
  114. }
  115. protected abstract void InvalidateRangeImpl(ulong address, ulong size);
  116. protected abstract void Delete(T1 item);
  117. /// <summary>
  118. /// Performs the disposal of all resources stored on the pool.
  119. /// It's an error to try using the pool after disposal.
  120. /// </summary>
  121. public virtual void Dispose()
  122. {
  123. if (Items != null)
  124. {
  125. for (int index = 0; index < Items.Length; index++)
  126. {
  127. Delete(Items[index]);
  128. }
  129. Items = null;
  130. }
  131. _memoryTracking.Dispose();
  132. }
  133. }
  134. }