using System;
namespace Ryujinx.Graphics.Gpu.Memory
{
///
/// A record of when buffer data was copied from one buffer to another, along with the SyncNumber when the migration will be complete.
/// Keeps the source buffer alive for data flushes until the migration is complete.
///
internal class BufferMigration : IDisposable
{
///
/// The offset for the migrated region.
///
private readonly ulong _offset;
///
/// The size for the migrated region.
///
private readonly ulong _size;
///
/// The buffer that was migrated from.
///
private readonly Buffer _buffer;
///
/// The source range action, to be called on overlap with an unreached sync number.
///
private readonly Action _sourceRangeAction;
///
/// The source range list.
///
private readonly BufferModifiedRangeList _source;
///
/// The destination range list. This range list must be updated when flushing the source.
///
public readonly BufferModifiedRangeList Destination;
///
/// The sync number that needs to be reached for this migration to be removed. This is set to the pending sync number on creation.
///
public readonly ulong SyncNumber;
///
/// Creates a record for a buffer migration.
///
/// The source buffer for this migration
/// The flush action for the source buffer
/// The modified range list for the source buffer
/// The modified range list for the destination buffer
/// The sync number for when the migration is complete
public BufferMigration(
Buffer buffer,
Action sourceRangeAction,
BufferModifiedRangeList source,
BufferModifiedRangeList dest,
ulong syncNumber)
{
_offset = buffer.Address;
_size = buffer.Size;
_buffer = buffer;
_sourceRangeAction = sourceRangeAction;
_source = source;
Destination = dest;
SyncNumber = syncNumber;
}
///
/// Determine if the given range overlaps this migration, and has not been completed yet.
///
/// Start offset
/// Range size
/// The sync number that was waited on
/// True if overlapping and in progress, false otherwise
public bool Overlaps(ulong offset, ulong size, ulong syncNumber)
{
ulong end = offset + size;
ulong destEnd = _offset + _size;
long syncDiff = (long)(syncNumber - SyncNumber); // syncNumber is less if the copy has not completed.
return !(end <= _offset || offset >= destEnd) && syncDiff < 0;
}
///
/// Determine if the given range matches this migration.
///
/// Start offset
/// Range size
/// True if the range exactly matches, false otherwise
public bool FullyMatches(ulong offset, ulong size)
{
return _offset == offset && _size == size;
}
///
/// Perform the migration source's range action on the range provided, clamped to the bounds of the source buffer.
///
/// Start offset
/// Range size
/// Current sync number
/// The modified range list that originally owned this range
public void RangeActionWithMigration(ulong offset, ulong size, ulong syncNumber, BufferModifiedRangeList parent)
{
ulong end = offset + size;
end = Math.Min(_offset + _size, end);
offset = Math.Max(_offset, offset);
size = end - offset;
_source.RangeActionWithMigration(offset, size, syncNumber, parent, _sourceRangeAction);
}
///
/// Removes this reference to the range list, potentially allowing for the source buffer to be disposed.
///
public void Dispose()
{
Destination.RemoveMigration(this);
_buffer.DecrementReferenceCount();
}
}
}