using ChocolArm64.Memory; using System; namespace Ryujinx.Graphics.Memory { class NvGpuVmmCache { private ValueRangeSet CachedRanges; public NvGpuVmmCache() { CachedRanges = new ValueRangeSet(); } public bool IsRegionModified(AMemory Memory, NvGpuBufferType BufferType, long PA, long Size) { (bool[] Modified, long ModifiedCount) = Memory.IsRegionModified(PA, Size); //Remove all modified ranges. int Index = 0; long Position = PA & ~NvGpuVmm.PageMask; while (ModifiedCount > 0) { if (Modified[Index++]) { CachedRanges.Remove(new ValueRange(Position, Position + NvGpuVmm.PageSize)); ModifiedCount--; } Position += NvGpuVmm.PageSize; } //Mask has the bit set for the current resource type. //If the region is not yet present on the list, then a new ValueRange //is directly added with the current resource type as the only bit set. //Otherwise, it just sets the bit for this new resource type on the current mask. int Mask = 1 << (int)BufferType; ValueRange NewCached = new ValueRange(PA, PA + Size); ValueRange[] Ranges = CachedRanges.GetAllIntersections(NewCached); long LastEnd = NewCached.Start; long Coverage = 0; for (Index = 0; Index < Ranges.Length; Index++) { ValueRange Current = Ranges[Index]; long RgStart = Math.Max(Current.Start, NewCached.Start); long RgEnd = Math.Min(Current.End, NewCached.End); if ((Current.Value & Mask) == 0) { CachedRanges.Add(new ValueRange(RgStart, RgEnd, Current.Value | Mask)); } else { Coverage += RgEnd - RgStart; } if (RgStart > LastEnd) { CachedRanges.Add(new ValueRange(LastEnd, RgStart, Mask)); } LastEnd = RgEnd; } if (LastEnd < NewCached.End) { CachedRanges.Add(new ValueRange(LastEnd, NewCached.End, Mask)); } return Coverage != Size; } } }