| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- using System;
- namespace Ryujinx.Memory.Tracking
- {
- /// <summary>
- /// A region handle that tracks a large region using many smaller handles, to provide
- /// granular tracking that can be used to track partial updates.
- /// </summary>
- public class MultiRegionHandle : IMultiRegionHandle
- {
- /// <summary>
- /// A list of region handles for each granularity sized chunk of the whole region.
- /// </summary>
- private readonly RegionHandle[] _handles;
- private readonly ulong Address;
- private readonly ulong Granularity;
- private readonly ulong Size;
- public bool Dirty { get; private set; } = true;
- internal MultiRegionHandle(MemoryTracking tracking, ulong address, ulong size, ulong granularity)
- {
- _handles = new RegionHandle[size / granularity];
- Granularity = granularity;
- for (int i = 0; i < _handles.Length; i++)
- {
- RegionHandle handle = tracking.BeginTracking(address + (ulong)i * granularity, granularity);
- handle.Parent = this;
- _handles[i] = handle;
- }
- Address = address;
- Size = size;
- }
- public void SignalWrite()
- {
- Dirty = true;
- }
- public void QueryModified(Action<ulong, ulong> modifiedAction)
- {
- if (!Dirty)
- {
- return;
- }
- Dirty = false;
- QueryModified(Address, Size, modifiedAction);
- }
- public void QueryModified(ulong address, ulong size, Action<ulong, ulong> modifiedAction)
- {
- int startHandle = (int)((address - Address) / Granularity);
- int lastHandle = (int)((address + (size - 1) - Address) / Granularity);
- ulong rgStart = _handles[startHandle].Address;
- ulong rgSize = 0;
- for (int i = startHandle; i <= lastHandle; i++)
- {
- RegionHandle handle = _handles[i];
- if (handle.Dirty)
- {
- rgSize += handle.Size;
- handle.Reprotect();
- }
- else
- {
- // Submit the region scanned so far as dirty
- if (rgSize != 0)
- {
- modifiedAction(rgStart, rgSize);
- rgSize = 0;
- }
- rgStart = handle.EndAddress;
- }
- }
- if (rgSize != 0)
- {
- modifiedAction(rgStart, rgSize);
- }
- }
- public void QueryModified(ulong address, ulong size, Action<ulong, ulong> modifiedAction, int sequenceNumber)
- {
- int startHandle = (int)((address - Address) / Granularity);
- int lastHandle = (int)((address + (size - 1) - Address) / Granularity);
- ulong rgStart = _handles[startHandle].Address;
- ulong rgSize = 0;
- for (int i = startHandle; i <= lastHandle; i++)
- {
- RegionHandle handle = _handles[i];
- if (handle.Dirty && sequenceNumber != handle.SequenceNumber)
- {
- rgSize += handle.Size;
- handle.Reprotect();
- }
- else
- {
- // Submit the region scanned so far as dirty
- if (rgSize != 0)
- {
- modifiedAction(rgStart, rgSize);
- rgSize = 0;
- }
- rgStart = handle.EndAddress;
- }
- handle.SequenceNumber = sequenceNumber;
- }
- if (rgSize != 0)
- {
- modifiedAction(rgStart, rgSize);
- }
- }
- public void Dispose()
- {
- foreach (var handle in _handles)
- {
- handle.Dispose();
- }
- }
- }
- }
|