- WritableRegion: enable wrapping IMemoryOwner<byte>
- IVirtualMemoryManager impls of GetWritableRegion() use pooled memory when region is non-contiguous. - IVirtualMemoryManager: add GetReadOnlySequence() and impls - ByteMemoryPool: add new method RentCopy() - ByteMemoryPool: make class static, remove ctor and singleton field from earlier impl
This commit is contained in:
parent
6208c3e6f0
commit
f05b70ce36
10 changed files with 296 additions and 28 deletions
|
@ -4,7 +4,7 @@ using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.Common.Memory
|
namespace Ryujinx.Common.Memory
|
||||||
{
|
{
|
||||||
public sealed partial class ByteMemoryPool
|
public partial class ByteMemoryPool
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a <see cref="IMemoryOwner{Byte}"/> that wraps an array rented from
|
/// Represents a <see cref="IMemoryOwner{Byte}"/> that wraps an array rented from
|
||||||
|
|
|
@ -6,24 +6,8 @@ namespace Ryujinx.Common.Memory
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides a pool of re-usable byte array instances.
|
/// Provides a pool of re-usable byte array instances.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class ByteMemoryPool
|
public static partial class ByteMemoryPool
|
||||||
{
|
{
|
||||||
private static readonly ByteMemoryPool _shared = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Constructs a <see cref="ByteMemoryPool"/> instance. Private to force access through
|
|
||||||
/// the <see cref="ByteMemoryPool.Shared"/> instance.
|
|
||||||
/// </summary>
|
|
||||||
private ByteMemoryPool()
|
|
||||||
{
|
|
||||||
// No implementation
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieves a shared <see cref="ByteMemoryPool"/> instance.
|
|
||||||
/// </summary>
|
|
||||||
public static ByteMemoryPool Shared => _shared;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the maximum buffer size supported by this pool.
|
/// Returns the maximum buffer size supported by this pool.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -95,6 +79,20 @@ namespace Ryujinx.Common.Memory
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copies <paramref name="buffer"/> into a newly rented byte memory buffer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buffer">The byte buffer to copy</param>
|
||||||
|
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory with <paramref name="buffer"/> copied to it</returns>
|
||||||
|
public static IMemoryOwner<byte> RentCopy(ReadOnlySpan<byte> buffer)
|
||||||
|
{
|
||||||
|
var copy = RentImpl(buffer.Length);
|
||||||
|
|
||||||
|
buffer.CopyTo(copy.Memory.Span);
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
private static ByteMemoryPoolBuffer RentImpl(int length)
|
private static ByteMemoryPoolBuffer RentImpl(int length)
|
||||||
{
|
{
|
||||||
if ((uint)length > Array.MaxLength)
|
if ((uint)length > Array.MaxLength)
|
||||||
|
|
26
src/Ryujinx.Common/Memory/BytesReadOnlySequenceSegment.cs
Normal file
26
src/Ryujinx.Common/Memory/BytesReadOnlySequenceSegment.cs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
|
|
||||||
|
namespace Ryujinx.Common.Memory
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A concrete implementation of <seealso cref="ReadOnlySequence{T}"/>,
|
||||||
|
/// with methods to help build a full sequence.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class BytesReadOnlySequenceSegment : ReadOnlySequenceSegment<byte>
|
||||||
|
{
|
||||||
|
public BytesReadOnlySequenceSegment(Memory<byte> memory) => Memory = memory;
|
||||||
|
|
||||||
|
public BytesReadOnlySequenceSegment Append(Memory<byte> memory)
|
||||||
|
{
|
||||||
|
var nextSegment = new BytesReadOnlySequenceSegment(memory)
|
||||||
|
{
|
||||||
|
RunningIndex = RunningIndex + Memory.Length
|
||||||
|
};
|
||||||
|
|
||||||
|
Next = nextSegment;
|
||||||
|
|
||||||
|
return nextSegment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,10 @@
|
||||||
using ARMeilleure.Memory;
|
using ARMeilleure.Memory;
|
||||||
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using Ryujinx.Memory.Range;
|
using Ryujinx.Memory.Range;
|
||||||
using Ryujinx.Memory.Tracking;
|
using Ryujinx.Memory.Tracking;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
@ -273,6 +275,76 @@ namespace Ryujinx.Cpu.AppleHv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ReadOnlySequence<byte> GetReadOnlySequence(ulong va, int size, bool tracked = false)
|
||||||
|
{
|
||||||
|
if (size == 0)
|
||||||
|
{
|
||||||
|
return ReadOnlySequence<byte>.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tracked)
|
||||||
|
{
|
||||||
|
SignalMemoryTracking(va, (ulong)size, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsContiguousAndMapped(va, size))
|
||||||
|
{
|
||||||
|
return new ReadOnlySequence<byte>(_backingMemory.GetMemory(GetPhysicalAddressInternal(va), size));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BytesReadOnlySequenceSegment first = null, last = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
AssertValidAddressAndSize(va, (ulong)size);
|
||||||
|
|
||||||
|
int offset = 0, segmentSize;
|
||||||
|
|
||||||
|
if ((va & PageMask) != 0)
|
||||||
|
{
|
||||||
|
ulong pa = GetPhysicalAddressChecked(va);
|
||||||
|
|
||||||
|
segmentSize = Math.Min(size, PageSize - (int)(va & PageMask));
|
||||||
|
|
||||||
|
var memory = _backingMemory.GetMemory(pa, segmentSize);
|
||||||
|
|
||||||
|
first = last = new BytesReadOnlySequenceSegment(memory);
|
||||||
|
|
||||||
|
offset += segmentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; offset < size; offset += segmentSize)
|
||||||
|
{
|
||||||
|
ulong pa = GetPhysicalAddressChecked(va + (ulong)offset);
|
||||||
|
|
||||||
|
segmentSize = Math.Min(size - offset, PageSize);
|
||||||
|
|
||||||
|
var memory = _backingMemory.GetMemory(pa, segmentSize);
|
||||||
|
|
||||||
|
if (first == null)
|
||||||
|
{
|
||||||
|
first = last = new BytesReadOnlySequenceSegment(memory);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
last = last.Append(memory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (InvalidMemoryRegionException)
|
||||||
|
{
|
||||||
|
if (_invalidAccessHandler == null || !_invalidAccessHandler(va))
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ReadOnlySequence<byte>(first, 0, last, (int)(size - last.RunningIndex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
|
public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
|
||||||
{
|
{
|
||||||
|
@ -319,11 +391,11 @@ namespace Ryujinx.Cpu.AppleHv
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Memory<byte> memory = new byte[size];
|
IMemoryOwner<byte> memoryOwner = ByteMemoryPool.Rent(size);
|
||||||
|
|
||||||
base.Read(va, memory.Span);
|
base.Read(va, memoryOwner.Memory.Span);
|
||||||
|
|
||||||
return new WritableRegion(this, va, memory);
|
return new WritableRegion(this, va, memoryOwner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
using ARMeilleure.Memory;
|
using ARMeilleure.Memory;
|
||||||
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using Ryujinx.Memory.Range;
|
using Ryujinx.Memory.Range;
|
||||||
using Ryujinx.Memory.Tracking;
|
using Ryujinx.Memory.Tracking;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
@ -311,6 +313,76 @@ namespace Ryujinx.Cpu.Jit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ReadOnlySequence<byte> GetReadOnlySequence(ulong va, int size, bool tracked = false)
|
||||||
|
{
|
||||||
|
if (size == 0)
|
||||||
|
{
|
||||||
|
return ReadOnlySequence<byte>.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tracked)
|
||||||
|
{
|
||||||
|
SignalMemoryTracking(va, (ulong)size, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsContiguousAndMapped(va, size))
|
||||||
|
{
|
||||||
|
return new ReadOnlySequence<byte>(_backingMemory.GetMemory(GetPhysicalAddressInternal(va), size));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BytesReadOnlySequenceSegment first = null, last = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
AssertValidAddressAndSize(va, (ulong)size);
|
||||||
|
|
||||||
|
int offset = 0, segmentSize;
|
||||||
|
|
||||||
|
if ((va & PageMask) != 0)
|
||||||
|
{
|
||||||
|
ulong pa = GetPhysicalAddressInternal(va);
|
||||||
|
|
||||||
|
segmentSize = Math.Min(size, PageSize - (int)(va & PageMask));
|
||||||
|
|
||||||
|
var memory = _backingMemory.GetMemory(pa, segmentSize);
|
||||||
|
|
||||||
|
first = last = new BytesReadOnlySequenceSegment(memory);
|
||||||
|
|
||||||
|
offset += segmentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; offset < size; offset += segmentSize)
|
||||||
|
{
|
||||||
|
ulong pa = GetPhysicalAddressInternal(va + (ulong)offset);
|
||||||
|
|
||||||
|
segmentSize = Math.Min(size - offset, PageSize);
|
||||||
|
|
||||||
|
var memory = _backingMemory.GetMemory(pa, segmentSize);
|
||||||
|
|
||||||
|
if (first == null)
|
||||||
|
{
|
||||||
|
first = last = new BytesReadOnlySequenceSegment(memory);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
last = last.Append(memory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (InvalidMemoryRegionException)
|
||||||
|
{
|
||||||
|
if (_invalidAccessHandler == null || !_invalidAccessHandler(va))
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ReadOnlySequence<byte>(first, 0, last, (int)(size - last.RunningIndex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
|
public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
|
||||||
{
|
{
|
||||||
|
@ -357,11 +429,11 @@ namespace Ryujinx.Cpu.Jit
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Memory<byte> memory = new byte[size];
|
IMemoryOwner<byte> memoryOwner = ByteMemoryPool.Rent(size);
|
||||||
|
|
||||||
GetSpan(va, size).CopyTo(memory.Span);
|
GetSpan(va, size).CopyTo(memoryOwner.Memory.Span);
|
||||||
|
|
||||||
return new WritableRegion(this, va, memory, tracked);
|
return new WritableRegion(this, va, memoryOwner, tracked);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ using Ryujinx.Memory;
|
||||||
using Ryujinx.Memory.Range;
|
using Ryujinx.Memory.Range;
|
||||||
using Ryujinx.Memory.Tracking;
|
using Ryujinx.Memory.Tracking;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
@ -279,6 +280,21 @@ namespace Ryujinx.Cpu.Jit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ReadOnlySequence<byte> GetReadOnlySequence(ulong va, int size, bool tracked = false)
|
||||||
|
{
|
||||||
|
if (tracked)
|
||||||
|
{
|
||||||
|
SignalMemoryTracking(va, (ulong)size, write: false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AssertMapped(va, (ulong)size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ReadOnlySequence<byte>(_addressSpace.Mirror.GetMemory(va, size));
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
|
public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.Memory.Range;
|
using Ryujinx.Memory.Range;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
@ -148,6 +150,57 @@ namespace Ryujinx.Memory
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ReadOnlySequence<byte> GetReadOnlySequence(ulong va, int size, bool tracked = false)
|
||||||
|
{
|
||||||
|
if (size == 0)
|
||||||
|
{
|
||||||
|
return ReadOnlySequence<byte>.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsContiguousAndMapped(va, size))
|
||||||
|
{
|
||||||
|
return new ReadOnlySequence<byte>(GetHostMemoryContiguous(va, size));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AssertValidAddressAndSize(va, (ulong)size);
|
||||||
|
|
||||||
|
int offset = 0, segmentSize;
|
||||||
|
|
||||||
|
BytesReadOnlySequenceSegment first = null, last = null;
|
||||||
|
|
||||||
|
if ((va & PageMask) != 0)
|
||||||
|
{
|
||||||
|
segmentSize = Math.Min(size, PageSize - (int)(va & PageMask));
|
||||||
|
|
||||||
|
var memory = GetHostMemoryContiguous(va, segmentSize);
|
||||||
|
|
||||||
|
first = last = new BytesReadOnlySequenceSegment(memory);
|
||||||
|
|
||||||
|
offset += segmentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; offset < size; offset += segmentSize)
|
||||||
|
{
|
||||||
|
segmentSize = Math.Min(size - offset, PageSize);
|
||||||
|
|
||||||
|
var memory = GetHostMemoryContiguous(va + (ulong)offset, segmentSize);
|
||||||
|
|
||||||
|
if (first == null)
|
||||||
|
{
|
||||||
|
first = last = new BytesReadOnlySequenceSegment(memory);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
last = last.Append(memory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ReadOnlySequence<byte>(first, 0, last, (int)(size - last.RunningIndex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
|
public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
|
||||||
{
|
{
|
||||||
|
@ -180,15 +233,15 @@ namespace Ryujinx.Memory
|
||||||
|
|
||||||
if (IsContiguousAndMapped(va, size))
|
if (IsContiguousAndMapped(va, size))
|
||||||
{
|
{
|
||||||
return new WritableRegion(null, va, new NativeMemoryManager<byte>((byte*)GetHostAddress(va), size).Memory);
|
return new WritableRegion(null, va, GetHostMemoryContiguous(va, size));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Memory<byte> memory = new byte[size];
|
IMemoryOwner<byte> memoryOwner = ByteMemoryPool.Rent(size);
|
||||||
|
|
||||||
GetSpan(va, size).CopyTo(memory.Span);
|
GetSpan(va, size).CopyTo(memoryOwner.Memory.Span);
|
||||||
|
|
||||||
return new WritableRegion(this, va, memory);
|
return new WritableRegion(this, va, memoryOwner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,6 +429,11 @@ namespace Ryujinx.Memory
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private unsafe Memory<byte> GetHostMemoryContiguous(ulong va, int size)
|
||||||
|
{
|
||||||
|
return new NativeMemoryManager<byte>((byte*)GetHostAddress(va), size).Memory;
|
||||||
|
}
|
||||||
|
|
||||||
private unsafe Span<byte> GetHostSpanContiguous(ulong va, int size)
|
private unsafe Span<byte> GetHostSpanContiguous(ulong va, int size)
|
||||||
{
|
{
|
||||||
return new Span<byte>((void*)GetHostAddress(va), size);
|
return new Span<byte>((void*)GetHostAddress(va), size);
|
||||||
|
|
|
@ -124,6 +124,16 @@ namespace Ryujinx.Memory
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a read-only sequence of read-only memory blocks from CPU mapped memory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="va">Virtual address of the data</param>
|
||||||
|
/// <param name="size">Size of the data</param>
|
||||||
|
/// <param name="tracked">True if read tracking is triggered on the memory</param>
|
||||||
|
/// <returns>A read-only sequence of read-only memory of the data</returns>
|
||||||
|
/// <exception cref="InvalidMemoryRegionException">Throw for unhandled invalid or unmapped memory accesses</exception>
|
||||||
|
ReadOnlySequence<byte> GetReadOnlySequence(ulong va, int size, bool tracked = false);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a read-only span of data from CPU mapped memory.
|
/// Gets a read-only span of data from CPU mapped memory.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
|
|
||||||
namespace Ryujinx.Memory
|
namespace Ryujinx.Memory
|
||||||
{
|
{
|
||||||
|
@ -6,6 +7,7 @@ namespace Ryujinx.Memory
|
||||||
{
|
{
|
||||||
private readonly IWritableBlock _block;
|
private readonly IWritableBlock _block;
|
||||||
private readonly ulong _va;
|
private readonly ulong _va;
|
||||||
|
private readonly IMemoryOwner<byte> _memoryOwner;
|
||||||
private readonly bool _tracked;
|
private readonly bool _tracked;
|
||||||
|
|
||||||
private bool NeedsWriteback => _block != null;
|
private bool NeedsWriteback => _block != null;
|
||||||
|
@ -20,6 +22,12 @@ namespace Ryujinx.Memory
|
||||||
Memory = memory;
|
Memory = memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public WritableRegion(IWritableBlock block, ulong va, IMemoryOwner<byte> memoryOwner, bool tracked = false)
|
||||||
|
: this(block, va, memoryOwner.Memory, tracked)
|
||||||
|
{
|
||||||
|
_memoryOwner = memoryOwner;
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (NeedsWriteback)
|
if (NeedsWriteback)
|
||||||
|
@ -33,6 +41,8 @@ namespace Ryujinx.Memory
|
||||||
_block.WriteUntracked(_va, Memory.Span);
|
_block.WriteUntracked(_va, Memory.Span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_memoryOwner?.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using Ryujinx.Memory.Range;
|
using Ryujinx.Memory.Range;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.Tests.Memory
|
namespace Ryujinx.Tests.Memory
|
||||||
|
@ -57,6 +58,11 @@ namespace Ryujinx.Tests.Memory
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ReadOnlySequence<byte> GetReadOnlySequence(ulong va, int size, bool tracked = false)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
|
public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue