1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
using Ryujinx.Graphics.GAL;
using System;
namespace Ryujinx.Graphics.Gpu.Memory
{
class Buffer : IRange<Buffer>, IDisposable
{
private GpuContext _context;
private IBuffer _buffer;
public IBuffer HostBuffer => _buffer;
public ulong Address { get; }
public ulong Size { get; }
public ulong EndAddress => Address + Size;
private int[] _sequenceNumbers;
public Buffer(GpuContext context, ulong address, ulong size)
{
_context = context;
Address = address;
Size = size;
_buffer = context.Renderer.CreateBuffer((int)size);
_sequenceNumbers = new int[size / MemoryManager.PageSize];
Invalidate();
}
public BufferRange GetRange(ulong address, ulong size)
{
int offset = (int)(address - Address);
return new BufferRange(_buffer, offset, (int)size);
}
public bool OverlapsWith(ulong address, ulong size)
{
return Address < address + size && address < EndAddress;
}
public void SynchronizeMemory(ulong address, ulong size)
{
int currentSequenceNumber = _context.SequenceNumber;
bool needsSync = false;
ulong buffOffset = address - Address;
ulong buffEndOffset = (buffOffset + size + MemoryManager.PageMask) & ~MemoryManager.PageMask;
int startIndex = (int)(buffOffset / MemoryManager.PageSize);
int endIndex = (int)(buffEndOffset / MemoryManager.PageSize);
for (int index = startIndex; index < endIndex; index++)
{
if (_sequenceNumbers[index] != currentSequenceNumber)
{
_sequenceNumbers[index] = currentSequenceNumber;
needsSync = true;
}
}
if (!needsSync)
{
return;
}
(ulong, ulong)[] modifiedRanges = _context.PhysicalMemory.GetModifiedRanges(address, size, ResourceName.Buffer);
for (int index = 0; index < modifiedRanges.Length; index++)
{
(ulong mAddress, ulong mSize) = modifiedRanges[index];
int offset = (int)(mAddress - Address);
_buffer.SetData(offset, _context.PhysicalMemory.Read(mAddress, mSize));
}
}
public void CopyTo(Buffer destination, int dstOffset)
{
_buffer.CopyTo(destination._buffer, 0, dstOffset, (int)Size);
}
public void Flush(ulong address, ulong size)
{
int offset = (int)(address - Address);
byte[] data = _buffer.GetData(offset, (int)size);
_context.PhysicalMemory.Write(address, data);
}
public void Invalidate()
{
_buffer.SetData(0, _context.PhysicalMemory.Read(Address, Size));
}
public void Dispose()
{
_buffer.Dispose();
}
}
}
|