|
@@ -68,9 +68,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|
|
/// <param name="index">Buffer slot</param>
|
|
/// <param name="index">Buffer slot</param>
|
|
|
/// <param name="address">Region virtual address</param>
|
|
/// <param name="address">Region virtual address</param>
|
|
|
/// <param name="size">Region size in bytes</param>
|
|
/// <param name="size">Region size in bytes</param>
|
|
|
- public void SetBounds(int index, ulong address, ulong size)
|
|
|
|
|
|
|
+ /// <param name="flags">Buffer usage flags</param>
|
|
|
|
|
+ public void SetBounds(int index, ulong address, ulong size, BufferUsageFlags flags = BufferUsageFlags.None)
|
|
|
{
|
|
{
|
|
|
- Buffers[index] = new BufferBounds(address, size);
|
|
|
|
|
|
|
+ Buffers[index] = new BufferBounds(address, size, flags);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
@@ -219,7 +220,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|
|
/// <param name="index">Index of the storage buffer</param>
|
|
/// <param name="index">Index of the storage buffer</param>
|
|
|
/// <param name="gpuVa">Start GPU virtual address of the buffer</param>
|
|
/// <param name="gpuVa">Start GPU virtual address of the buffer</param>
|
|
|
/// <param name="size">Size in bytes of the storage buffer</param>
|
|
/// <param name="size">Size in bytes of the storage buffer</param>
|
|
|
- public void SetComputeStorageBuffer(int index, ulong gpuVa, ulong size)
|
|
|
|
|
|
|
+ /// <param name="flags">Buffer usage flags</param>
|
|
|
|
|
+ public void SetComputeStorageBuffer(int index, ulong gpuVa, ulong size, BufferUsageFlags flags)
|
|
|
{
|
|
{
|
|
|
size += gpuVa & ((ulong)_context.Capabilities.StorageBufferOffsetAlignment - 1);
|
|
size += gpuVa & ((ulong)_context.Capabilities.StorageBufferOffsetAlignment - 1);
|
|
|
|
|
|
|
@@ -227,7 +229,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|
|
|
|
|
|
|
ulong address = TranslateAndCreateBuffer(gpuVa, size);
|
|
ulong address = TranslateAndCreateBuffer(gpuVa, size);
|
|
|
|
|
|
|
|
- _cpStorageBuffers.SetBounds(index, address, size);
|
|
|
|
|
|
|
+ _cpStorageBuffers.SetBounds(index, address, size, flags);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
@@ -238,7 +240,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|
|
/// <param name="index">Index of the storage buffer</param>
|
|
/// <param name="index">Index of the storage buffer</param>
|
|
|
/// <param name="gpuVa">Start GPU virtual address of the buffer</param>
|
|
/// <param name="gpuVa">Start GPU virtual address of the buffer</param>
|
|
|
/// <param name="size">Size in bytes of the storage buffer</param>
|
|
/// <param name="size">Size in bytes of the storage buffer</param>
|
|
|
- public void SetGraphicsStorageBuffer(int stage, int index, ulong gpuVa, ulong size)
|
|
|
|
|
|
|
+ /// <param name="flags">Buffer usage flags</param>
|
|
|
|
|
+ public void SetGraphicsStorageBuffer(int stage, int index, ulong gpuVa, ulong size, BufferUsageFlags flags)
|
|
|
{
|
|
{
|
|
|
size += gpuVa & ((ulong)_context.Capabilities.StorageBufferOffsetAlignment - 1);
|
|
size += gpuVa & ((ulong)_context.Capabilities.StorageBufferOffsetAlignment - 1);
|
|
|
|
|
|
|
@@ -252,7 +255,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|
|
_gpStorageBuffersDirty = true;
|
|
_gpStorageBuffersDirty = true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- _gpStorageBuffers[stage].SetBounds(index, address, size);
|
|
|
|
|
|
|
+ _gpStorageBuffers[stage].SetBounds(index, address, size, flags);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
@@ -385,6 +388,30 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|
|
return mask;
|
|
return mask;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// Handles removal of buffers written to a memory region being unmapped.
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ /// <param name="sender">Sender object</param>
|
|
|
|
|
+ /// <param name="e">Event arguments</param>
|
|
|
|
|
+ public void MemoryUnmappedHandler(object sender, UnmapEventArgs e)
|
|
|
|
|
+ {
|
|
|
|
|
+ Buffer[] overlaps = new Buffer[10];
|
|
|
|
|
+ int overlapCount;
|
|
|
|
|
+
|
|
|
|
|
+ ulong address = _context.MemoryManager.Translate(e.Address);
|
|
|
|
|
+ ulong size = e.Size;
|
|
|
|
|
+
|
|
|
|
|
+ lock (_buffers)
|
|
|
|
|
+ {
|
|
|
|
|
+ overlapCount = _buffers.FindOverlaps(address, size, ref overlaps);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for (int i = 0; i < overlapCount; i++)
|
|
|
|
|
+ {
|
|
|
|
|
+ overlaps[i].Unmapped(address, size);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/// <summary>
|
|
/// <summary>
|
|
|
/// Performs address translation of the GPU virtual address, and creates a
|
|
/// Performs address translation of the GPU virtual address, and creates a
|
|
|
/// new buffer, if needed, for the specified range.
|
|
/// new buffer, if needed, for the specified range.
|
|
@@ -443,7 +470,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|
|
/// <param name="size">Size in bytes of the buffer</param>
|
|
/// <param name="size">Size in bytes of the buffer</param>
|
|
|
private void CreateBufferAligned(ulong address, ulong size)
|
|
private void CreateBufferAligned(ulong address, ulong size)
|
|
|
{
|
|
{
|
|
|
- int overlapsCount = _buffers.FindOverlapsNonOverlapping(address, size, ref _bufferOverlaps);
|
|
|
|
|
|
|
+ int overlapsCount;
|
|
|
|
|
+
|
|
|
|
|
+ lock (_buffers)
|
|
|
|
|
+ {
|
|
|
|
|
+ overlapsCount = _buffers.FindOverlapsNonOverlapping(address, size, ref _bufferOverlaps);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
if (overlapsCount != 0)
|
|
if (overlapsCount != 0)
|
|
|
{
|
|
{
|
|
@@ -463,15 +495,19 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|
|
address = Math.Min(address, buffer.Address);
|
|
address = Math.Min(address, buffer.Address);
|
|
|
endAddress = Math.Max(endAddress, buffer.EndAddress);
|
|
endAddress = Math.Max(endAddress, buffer.EndAddress);
|
|
|
|
|
|
|
|
- buffer.SynchronizeMemory(buffer.Address, buffer.Size);
|
|
|
|
|
-
|
|
|
|
|
- _buffers.Remove(buffer);
|
|
|
|
|
|
|
+ lock (_buffers)
|
|
|
|
|
+ {
|
|
|
|
|
+ _buffers.Remove(buffer);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Buffer newBuffer = new Buffer(_context, address, endAddress - address);
|
|
Buffer newBuffer = new Buffer(_context, address, endAddress - address);
|
|
|
newBuffer.SynchronizeMemory(address, endAddress - address);
|
|
newBuffer.SynchronizeMemory(address, endAddress - address);
|
|
|
|
|
|
|
|
- _buffers.Add(newBuffer);
|
|
|
|
|
|
|
+ lock (_buffers)
|
|
|
|
|
+ {
|
|
|
|
|
+ _buffers.Add(newBuffer);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
for (int index = 0; index < overlapsCount; index++)
|
|
for (int index = 0; index < overlapsCount; index++)
|
|
|
{
|
|
{
|
|
@@ -479,7 +515,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|
|
|
|
|
|
|
int dstOffset = (int)(buffer.Address - newBuffer.Address);
|
|
int dstOffset = (int)(buffer.Address - newBuffer.Address);
|
|
|
|
|
|
|
|
|
|
+ buffer.SynchronizeMemory(buffer.Address, buffer.Size);
|
|
|
|
|
+
|
|
|
buffer.CopyTo(newBuffer, dstOffset);
|
|
buffer.CopyTo(newBuffer, dstOffset);
|
|
|
|
|
+ newBuffer.InheritModifiedRanges(buffer);
|
|
|
|
|
|
|
|
buffer.Dispose();
|
|
buffer.Dispose();
|
|
|
}
|
|
}
|
|
@@ -493,7 +532,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|
|
// No overlap, just create a new buffer.
|
|
// No overlap, just create a new buffer.
|
|
|
Buffer buffer = new Buffer(_context, address, size);
|
|
Buffer buffer = new Buffer(_context, address, size);
|
|
|
|
|
|
|
|
- _buffers.Add(buffer);
|
|
|
|
|
|
|
+ lock (_buffers)
|
|
|
|
|
+ {
|
|
|
|
|
+ _buffers.Add(buffer);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
ShrinkOverlapsBufferIfNeeded();
|
|
ShrinkOverlapsBufferIfNeeded();
|
|
@@ -549,7 +591,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|
|
|
|
|
|
|
if (bounds.Address != 0)
|
|
if (bounds.Address != 0)
|
|
|
{
|
|
{
|
|
|
- sRanges[bindingInfo.Binding] = GetBufferRange(bounds.Address, bounds.Size);
|
|
|
|
|
|
|
+ sRanges[bindingInfo.Binding] = GetBufferRange(bounds.Address, bounds.Size, bounds.Flags.HasFlag(BufferUsageFlags.Write));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -722,7 +764,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|
|
|
|
|
|
|
if (bounds.Address != 0)
|
|
if (bounds.Address != 0)
|
|
|
{
|
|
{
|
|
|
- ranges[bindingInfo.Binding] = GetBufferRange(bounds.Address, bounds.Size);
|
|
|
|
|
|
|
+ ranges[bindingInfo.Binding] = GetBufferRange(bounds.Address, bounds.Size, bounds.Flags.HasFlag(BufferUsageFlags.Write));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -818,7 +860,17 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|
|
dstOffset,
|
|
dstOffset,
|
|
|
(int)size);
|
|
(int)size);
|
|
|
|
|
|
|
|
- dstBuffer.Flush(dstAddress, size);
|
|
|
|
|
|
|
+ if (srcBuffer.IsModified(srcAddress, size))
|
|
|
|
|
+ {
|
|
|
|
|
+ dstBuffer.SignalModified(dstAddress, size);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ // Optimization: If the data being copied is already in memory, then copy it directly instead of flushing from GPU.
|
|
|
|
|
+
|
|
|
|
|
+ dstBuffer.ClearModified(dstAddress, size);
|
|
|
|
|
+ _context.PhysicalMemory.WriteUntracked(dstAddress, _context.PhysicalMemory.GetSpan(srcAddress, (int)size));
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
@@ -840,7 +892,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|
|
|
|
|
|
|
_context.Renderer.Pipeline.ClearBuffer(buffer.Handle, offset, (int)size, value);
|
|
_context.Renderer.Pipeline.ClearBuffer(buffer.Handle, offset, (int)size, value);
|
|
|
|
|
|
|
|
- buffer.Flush(address, size);
|
|
|
|
|
|
|
+ buffer.SignalModified(address, size);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
@@ -848,10 +900,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|
|
/// </summary>
|
|
/// </summary>
|
|
|
/// <param name="address">Start address of the memory range</param>
|
|
/// <param name="address">Start address of the memory range</param>
|
|
|
/// <param name="size">Size in bytes of the memory range</param>
|
|
/// <param name="size">Size in bytes of the memory range</param>
|
|
|
|
|
+ /// <param name="write">Whether the buffer will be written to by this use</param>
|
|
|
/// <returns>The buffer sub-range for the given range</returns>
|
|
/// <returns>The buffer sub-range for the given range</returns>
|
|
|
- private BufferRange GetBufferRange(ulong address, ulong size)
|
|
|
|
|
|
|
+ private BufferRange GetBufferRange(ulong address, ulong size, bool write = false)
|
|
|
{
|
|
{
|
|
|
- return GetBuffer(address, size).GetRange(address, size);
|
|
|
|
|
|
|
+ return GetBuffer(address, size, write).GetRange(address, size);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
@@ -860,20 +913,32 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|
|
/// </summary>
|
|
/// </summary>
|
|
|
/// <param name="address">Start address of the memory range</param>
|
|
/// <param name="address">Start address of the memory range</param>
|
|
|
/// <param name="size">Size in bytes of the memory range</param>
|
|
/// <param name="size">Size in bytes of the memory range</param>
|
|
|
|
|
+ /// <param name="write">Whether the buffer will be written to by this use</param>
|
|
|
/// <returns>The buffer where the range is fully contained</returns>
|
|
/// <returns>The buffer where the range is fully contained</returns>
|
|
|
- private Buffer GetBuffer(ulong address, ulong size)
|
|
|
|
|
|
|
+ private Buffer GetBuffer(ulong address, ulong size, bool write = false)
|
|
|
{
|
|
{
|
|
|
Buffer buffer;
|
|
Buffer buffer;
|
|
|
|
|
|
|
|
if (size != 0)
|
|
if (size != 0)
|
|
|
{
|
|
{
|
|
|
- buffer = _buffers.FindFirstOverlap(address, size);
|
|
|
|
|
|
|
+ lock (_buffers)
|
|
|
|
|
+ {
|
|
|
|
|
+ buffer = _buffers.FindFirstOverlap(address, size);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
buffer.SynchronizeMemory(address, size);
|
|
buffer.SynchronizeMemory(address, size);
|
|
|
|
|
+
|
|
|
|
|
+ if (write)
|
|
|
|
|
+ {
|
|
|
|
|
+ buffer.SignalModified(address, size);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
- buffer = _buffers.FindFirstOverlap(address, 1);
|
|
|
|
|
|
|
+ lock (_buffers)
|
|
|
|
|
+ {
|
|
|
|
|
+ buffer = _buffers.FindFirstOverlap(address, 1);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return buffer;
|
|
return buffer;
|
|
@@ -888,7 +953,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|
|
{
|
|
{
|
|
|
if (size != 0)
|
|
if (size != 0)
|
|
|
{
|
|
{
|
|
|
- Buffer buffer = _buffers.FindFirstOverlap(address, size);
|
|
|
|
|
|
|
+ Buffer buffer;
|
|
|
|
|
+
|
|
|
|
|
+ lock (_buffers)
|
|
|
|
|
+ {
|
|
|
|
|
+ buffer = _buffers.FindFirstOverlap(address, size);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
buffer.SynchronizeMemory(address, size);
|
|
buffer.SynchronizeMemory(address, size);
|
|
|
}
|
|
}
|
|
@@ -900,9 +970,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|
|
/// </summary>
|
|
/// </summary>
|
|
|
public void Dispose()
|
|
public void Dispose()
|
|
|
{
|
|
{
|
|
|
- foreach (Buffer buffer in _buffers)
|
|
|
|
|
|
|
+ lock (_buffers)
|
|
|
{
|
|
{
|
|
|
- buffer.Dispose();
|
|
|
|
|
|
|
+ foreach (Buffer buffer in _buffers)
|
|
|
|
|
+ {
|
|
|
|
|
+ buffer.Dispose();
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|