Pool.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. using Ryujinx.Common;
  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="T">Type of the GPU resource</typeparam>
  10. abstract class Pool<T> : IDisposable
  11. {
  12. protected const int DescriptorSize = 0x20;
  13. protected GpuContext Context;
  14. protected T[] Items;
  15. /// <summary>
  16. /// The maximum ID value of resources on the pool (inclusive).
  17. /// </summary>
  18. /// <remarks>
  19. /// The maximum amount of resources on the pool is equal to this value plus one.
  20. /// </remarks>
  21. public int MaximumId { get; }
  22. /// <summary>
  23. /// The address of the pool in guest memory.
  24. /// </summary>
  25. public ulong Address { get; }
  26. /// <summary>
  27. /// The size of the pool in bytes.
  28. /// </summary>
  29. public ulong Size { get; }
  30. private readonly (ulong, ulong)[] _modifiedRanges;
  31. public Pool(GpuContext context, ulong address, int maximumId)
  32. {
  33. Context = context;
  34. MaximumId = maximumId;
  35. int count = maximumId + 1;
  36. ulong size = (ulong)(uint)count * DescriptorSize;;
  37. Items = new T[count];
  38. Address = address;
  39. Size = size;
  40. ulong endAddress = BitUtils.AlignUp(Address + Size, PhysicalMemory.PageSize);
  41. ulong pagesCount = (endAddress - BitUtils.AlignDown(Address, PhysicalMemory.PageSize)) / PhysicalMemory.PageSize;
  42. _modifiedRanges = new (ulong, ulong)[pagesCount];
  43. }
  44. /// <summary>
  45. /// Gets the GPU resource with the given ID.
  46. /// </summary>
  47. /// <param name="id">ID of the resource. This is effectively a zero-based index</param>
  48. /// <returns>The GPU resource with the given ID</returns>
  49. public abstract T Get(int id);
  50. /// <summary>
  51. /// Synchronizes host memory with guest memory.
  52. /// This causes invalidation of pool entries,
  53. /// if a modification of entries by the CPU is detected.
  54. /// </summary>
  55. public void SynchronizeMemory()
  56. {
  57. int count = Context.PhysicalMemory.QueryModified(Address, Size, ResourceName.TexturePool, _modifiedRanges);
  58. for (int index = 0; index < count; index++)
  59. {
  60. (ulong mAddress, ulong mSize) = _modifiedRanges[index];
  61. if (mAddress < Address)
  62. {
  63. mAddress = Address;
  64. }
  65. ulong maxSize = Address + Size - mAddress;
  66. if (mSize > maxSize)
  67. {
  68. mSize = maxSize;
  69. }
  70. InvalidateRangeImpl(mAddress, mSize);
  71. }
  72. }
  73. private void InvalidateRangeInternal(ulong offset, int size)
  74. {
  75. InvalidateRangeImpl(Address + offset, (ulong)size);
  76. }
  77. /// <summary>
  78. /// Invalidates a range of memory of the GPU resource pool.
  79. /// Entries that falls inside the speicified range will be invalidated,
  80. /// causing all the data to be reloaded from guest memory.
  81. /// </summary>
  82. /// <param name="address">The start address of the range to invalidate</param>
  83. /// <param name="size">The size of the range to invalidate</param>
  84. public void InvalidateRange(ulong address, ulong size)
  85. {
  86. ulong endAddress = address + size;
  87. ulong texturePoolEndAddress = Address + Size;
  88. // If the range being invalidated is not overlapping the texture pool range,
  89. // then we don't have anything to do, exit early.
  90. if (address >= texturePoolEndAddress || endAddress <= Address)
  91. {
  92. return;
  93. }
  94. if (address < Address)
  95. {
  96. address = Address;
  97. }
  98. if (endAddress > texturePoolEndAddress)
  99. {
  100. endAddress = texturePoolEndAddress;
  101. }
  102. size = endAddress - address;
  103. InvalidateRangeImpl(address, size);
  104. }
  105. protected abstract void InvalidateRangeImpl(ulong address, ulong size);
  106. protected abstract void Delete(T item);
  107. /// <summary>
  108. /// Performs the disposal of all resources stored on the pool.
  109. /// It's an error to try using the pool after disposal.
  110. /// </summary>
  111. public void Dispose()
  112. {
  113. if (Items != null)
  114. {
  115. for (int index = 0; index < Items.Length; index++)
  116. {
  117. Delete(Items[index]);
  118. }
  119. Items = null;
  120. }
  121. }
  122. }
  123. }