using Ryujinx.Common; using Ryujinx.Cpu.Tracking; using Ryujinx.Graphics.Gpu.Memory; using System; namespace Ryujinx.Graphics.Gpu.Image { /// /// Represents a pool of GPU resources, such as samplers or textures. /// /// Type of the GPU resource abstract class Pool : IDisposable { protected const int DescriptorSize = 0x20; protected GpuContext Context; protected T[] Items; /// /// The maximum ID value of resources on the pool (inclusive). /// /// /// The maximum amount of resources on the pool is equal to this value plus one. /// public int MaximumId { get; } /// /// The address of the pool in guest memory. /// public ulong Address { get; } /// /// The size of the pool in bytes. /// public ulong Size { get; } private readonly CpuMultiRegionHandle _memoryTracking; public Pool(GpuContext context, ulong address, int maximumId) { Context = context; MaximumId = maximumId; int count = maximumId + 1; ulong size = (ulong)(uint)count * DescriptorSize;; Items = new T[count]; Address = address; Size = size; _memoryTracking = context.PhysicalMemory.BeginGranularTracking(address, size); } /// /// Gets the GPU resource with the given ID. /// /// ID of the resource. This is effectively a zero-based index /// The GPU resource with the given ID public abstract T Get(int id); /// /// Synchronizes host memory with guest memory. /// This causes invalidation of pool entries, /// if a modification of entries by the CPU is detected. /// public void SynchronizeMemory() { _memoryTracking.QueryModified((ulong mAddress, ulong mSize) => { if (mAddress < Address) { mAddress = Address; } ulong maxSize = Address + Size - mAddress; if (mSize > maxSize) { mSize = maxSize; } InvalidateRangeImpl(mAddress, mSize); }); } protected abstract void InvalidateRangeImpl(ulong address, ulong size); protected abstract void Delete(T item); /// /// Performs the disposal of all resources stored on the pool. /// It's an error to try using the pool after disposal. /// public void Dispose() { if (Items != null) { for (int index = 0; index < Items.Length; index++) { Delete(Items[index]); } Items = null; } _memoryTracking.Dispose(); } } }