Vulkan: Buffer Mirrors for MacOS performance (#4899)

* Initial implementation of buffer mirrors

Generally slower right now, goal is to reduce render passes in games that do inline updates

Fix support buffer mirrors

Reintroduce vertex buffer mirror

Add storage buffer support

Optimisation part 1

More optimisation

Avoid useless data copies.

Remove unused cbIndex stuff

Properly set write flag for storage buffers.

Fix minor issues

Not sure why this was here.

Fix BufferRangeList

Fix some big issues

Align storage buffers rather than getting full buffer as a range

Improves mirrorability of read-only storage buffers

Increase staging buffer size, as it now contains mirrors

Fix some issues with buffers not updating

Fix buffer SetDataUnchecked offset for one of the paths when using mirrors

Fix buffer mirrors interaction with buffer textures

Fix mirror rebinding

Move GetBuffer calls on indirect draws before BeginRenderPass to avoid draws without render pass

Fix mirrors rebase

Fix rebase 2023

* Fix crash when using stale vertex buffer

Similar to `Get` with a size that's too large, just treat it as a clamp.

* Explicitly set support buffer as mirrorable

* Address feedback

* Remove unused fragment of MVK workaround

* Replace logging for staging buffer OOM

* Address format issues

* Address more format issues

* Mini cleanup

* Address more things

* Rename BufferRangeList

* Support bounding range for ClearMirrors and UploadPendingData

* Add maximum size for vertex buffer mirrors

* Enable index buffer mirrors

Enabled on all platforms for the IbStreamer.

* Feedback

* Remove mystery BufferCache change

Probably macos related?

* Fix mirrors not creating when staging buffer is empty.

* Change log level to debug
This commit is contained in:
riperiperi 2023-08-14 18:18:47 +01:00 committed by GitHub
parent 550fd4a733
commit 492a046335
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 1285 additions and 136 deletions

View file

@ -140,18 +140,21 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
/// <summary>
/// Gets a sub-range from the buffer, from a start address till the end of the buffer.
/// Gets a sub-range from the buffer, from a start address til a page boundary after the given size.
/// </summary>
/// <remarks>
/// This can be used to bind and use sub-ranges of the buffer on the host API.
/// </remarks>
/// <param name="address">Start address of the sub-range, must be greater than or equal to the buffer address</param>
/// <param name="size">Size in bytes of the sub-range, must be less than or equal to the buffer size</param>
/// <param name="write">Whether the buffer will be written to by this use</param>
/// <returns>The buffer sub-range</returns>
public BufferRange GetRange(ulong address)
public BufferRange GetRangeAligned(ulong address, ulong size, bool write)
{
ulong end = ((address + size + MemoryManager.PageMask) & ~MemoryManager.PageMask) - Address;
ulong offset = address - Address;
return new BufferRange(Handle, (int)offset, (int)(Size - offset));
return new BufferRange(Handle, (int)offset, (int)(end - offset), write);
}
/// <summary>
@ -162,12 +165,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// </remarks>
/// <param name="address">Start address of the sub-range, must be greater than or equal to the buffer address</param>
/// <param name="size">Size in bytes of the sub-range, must be less than or equal to the buffer size</param>
/// <param name="write">Whether the buffer will be written to by this use</param>
/// <returns>The buffer sub-range</returns>
public BufferRange GetRange(ulong address, ulong size)
public BufferRange GetRange(ulong address, ulong size, bool write)
{
int offset = (int)(address - Address);
return new BufferRange(Handle, offset, (int)size);
return new BufferRange(Handle, offset, (int)size, write);
}
/// <summary>

View file

@ -372,15 +372,15 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
/// <summary>
/// Gets a buffer sub-range starting at a given memory address.
/// Gets a buffer sub-range from a start address til a page boundary after the given size.
/// </summary>
/// <param name="address">Start address 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 starting at the given memory address</returns>
public BufferRange GetBufferRangeTillEnd(ulong address, ulong size, bool write = false)
public BufferRange GetBufferRangeAligned(ulong address, ulong size, bool write = false)
{
return GetBuffer(address, size, write).GetRange(address);
return GetBuffer(address, size, write).GetRangeAligned(address, size, write);
}
/// <summary>
@ -392,7 +392,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <returns>The buffer sub-range for the given range</returns>
public BufferRange GetBufferRange(ulong address, ulong size, bool write = false)
{
return GetBuffer(address, size, write).GetRange(address, size);
return GetBuffer(address, size, write).GetRange(address, size, write);
}
/// <summary>

View file

@ -614,7 +614,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
if (_tfInfoBuffer == BufferHandle.Null)
{
_tfInfoBuffer = _context.Renderer.CreateBuffer(TfInfoBufferSize);
_tfInfoBuffer = _context.Renderer.CreateBuffer(TfInfoBufferSize, BufferAccess.Stream);
}
buffers[0] = new BufferAssignment(0, new BufferRange(_tfInfoBuffer, 0, TfInfoBufferSize));
@ -727,7 +727,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
{
var isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write);
var range = isStorage
? bufferCache.GetBufferRangeTillEnd(bounds.Address, bounds.Size, isWrite)
? bufferCache.GetBufferRangeAligned(bounds.Address, bounds.Size, isWrite)
: bufferCache.GetBufferRange(bounds.Address, bounds.Size);
ranges[rangesCount++] = new BufferAssignment(bindingInfo.Binding, range);
@ -764,7 +764,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
{
var isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write);
var range = isStorage
? bufferCache.GetBufferRangeTillEnd(bounds.Address, bounds.Size, isWrite)
? bufferCache.GetBufferRangeAligned(bounds.Address, bounds.Size, isWrite)
: bufferCache.GetBufferRange(bounds.Address, bounds.Size);
ranges[rangesCount++] = new BufferAssignment(bindingInfo.Binding, range);

View file

@ -228,7 +228,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
{
if (_handle == BufferHandle.Null)
{
_handle = _renderer.CreateBuffer(SupportBuffer.RequiredSize);
_handle = _renderer.CreateBuffer(SupportBuffer.RequiredSize, BufferAccess.Stream);
_renderer.Pipeline.ClearBuffer(_handle, 0, SupportBuffer.RequiredSize, 0);
var range = new BufferRange(_handle, 0, SupportBuffer.RequiredSize);