Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vulkan: Buffer Mirrors for MacOS performance #4899

Merged
merged 18 commits into from Aug 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Ryujinx.Graphics.GAL/BufferAccess.cs
Expand Up @@ -4,5 +4,6 @@ public enum BufferAccess
{
Default,
FlushPersistent,
Stream
}
}
4 changes: 3 additions & 1 deletion src/Ryujinx.Graphics.GAL/BufferRange.cs
Expand Up @@ -10,12 +10,14 @@ namespace Ryujinx.Graphics.GAL

public int Offset { get; }
public int Size { get; }
public bool Write { get; }

public BufferRange(BufferHandle handle, int offset, int size)
public BufferRange(BufferHandle handle, int offset, int size, bool write = false)
{
Handle = handle;
Offset = offset;
Size = size;
Write = write;
}
}
}
8 changes: 4 additions & 4 deletions src/Ryujinx.Graphics.GAL/Multithreading/BufferMap.cs
Expand Up @@ -113,7 +113,7 @@ internal BufferHandle MapBufferBlocking(BufferHandle handle)

internal BufferRange MapBufferRange(BufferRange range)
{
return new BufferRange(MapBuffer(range.Handle), range.Offset, range.Size);
return new BufferRange(MapBuffer(range.Handle), range.Offset, range.Size, range.Write);
}

internal Span<BufferRange> MapBufferRanges(Span<BufferRange> ranges)
Expand All @@ -131,7 +131,7 @@ internal Span<BufferRange> MapBufferRanges(Span<BufferRange> ranges)
result = BufferHandle.Null;
}

range = new BufferRange(result, range.Offset, range.Size);
range = new BufferRange(result, range.Offset, range.Size, range.Write);
}
}

Expand All @@ -154,7 +154,7 @@ internal Span<BufferAssignment> MapBufferRanges(Span<BufferAssignment> ranges)
result = BufferHandle.Null;
}

assignment = new BufferAssignment(ranges[i].Binding, new BufferRange(result, range.Offset, range.Size));
assignment = new BufferAssignment(ranges[i].Binding, new BufferRange(result, range.Offset, range.Size, range.Write));
}
}

Expand All @@ -176,7 +176,7 @@ internal Span<VertexBufferDescriptor> MapBufferRanges(Span<VertexBufferDescripto
result = BufferHandle.Null;
}

range = new BufferRange(result, range.Offset, range.Size);
range = new BufferRange(result, range.Offset, range.Size, range.Write);

ranges[i] = new VertexBufferDescriptor(range, ranges[i].Stride, ranges[i].Divisor);
}
Expand Down
4 changes: 2 additions & 2 deletions src/Ryujinx.Graphics.Gpu/Engine/Threed/IbStreamer.cs
Expand Up @@ -171,15 +171,15 @@ private BufferHandle GetInlineIndexBuffer(IRenderer renderer, int offset, int le

if (_inlineIndexBuffer == BufferHandle.Null)
{
_inlineIndexBuffer = renderer.CreateBuffer(size);
_inlineIndexBuffer = renderer.CreateBuffer(size, BufferAccess.Stream);
_inlineIndexBufferSize = size;
}
else if (_inlineIndexBufferSize < size)
{
BufferHandle oldBuffer = _inlineIndexBuffer;
int oldSize = _inlineIndexBufferSize;

_inlineIndexBuffer = renderer.CreateBuffer(size);
_inlineIndexBuffer = renderer.CreateBuffer(size, BufferAccess.Stream);
_inlineIndexBufferSize = size;

renderer.Pipeline.CopyBuffer(oldBuffer, _inlineIndexBuffer, 0, 0, oldSize);
Expand Down
14 changes: 9 additions & 5 deletions src/Ryujinx.Graphics.Gpu/Memory/Buffer.cs
Expand Up @@ -140,18 +140,21 @@ public Buffer(GpuContext context, PhysicalMemory physicalMemory, ulong address,
}

/// <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)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: This change is done to allow mirroring on storage buffer bindings. It's not clear to what extent games like Yokai Watch are intentionally accessing storage buffer data out of bounds, though the original assumption was that it's within the same page of the end address at least.

If a binding legitimately doesn't have a size in the future, the method should be reintroduced.

{
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>
Expand All @@ -162,12 +165,13 @@ public BufferRange GetRange(ulong address)
/// </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>
Expand Down
8 changes: 4 additions & 4 deletions src/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs
Expand Up @@ -372,15 +372,15 @@ public void ClearBuffer(MemoryManager memoryManager, ulong gpuVa, ulong size, ui
}

/// <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>
Expand All @@ -392,7 +392,7 @@ public BufferRange GetBufferRangeTillEnd(ulong address, ulong size, bool write =
/// <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>
Expand Down
6 changes: 3 additions & 3 deletions src/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
Expand Up @@ -614,7 +614,7 @@ public void CommitGraphicsBindings(bool indexed)

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));
Expand Down Expand Up @@ -727,7 +727,7 @@ private void BindBuffers(BufferCache bufferCache, BuffersPerStage[] bindings, bo
{
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);
Expand Down Expand Up @@ -764,7 +764,7 @@ private void BindBuffers(BufferCache bufferCache, BuffersPerStage buffers, bool
{
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);
Expand Down
2 changes: 1 addition & 1 deletion src/Ryujinx.Graphics.Gpu/Memory/SupportBufferUpdater.cs
Expand Up @@ -231,7 +231,7 @@ public void Commit()
{
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);
Expand Down
24 changes: 22 additions & 2 deletions src/Ryujinx.Graphics.Vulkan/Auto.cs
Expand Up @@ -18,6 +18,12 @@ interface IAutoPrivate : IAuto
void AddCommandBufferDependencies(CommandBufferScoped cbs);
}

interface IMirrorable<T> where T : IDisposable
{
Auto<T> GetMirrorable(CommandBufferScoped cbs, ref int offset, int size, out bool mirrored);
void ClearMirrors(CommandBufferScoped cbs, int offset, int size);
}

class Auto<T> : IAutoPrivate, IDisposable where T : IDisposable
{
private int _referenceCount;
Expand All @@ -26,6 +32,7 @@ class Auto<T> : IAutoPrivate, IDisposable where T : IDisposable
private readonly BitMap _cbOwnership;
private readonly MultiFenceHolder _waitable;
private readonly IAutoPrivate[] _referencedObjs;
private readonly IMirrorable<T> _mirrorable;

private bool _disposed;
private bool _destroyed;
Expand All @@ -37,6 +44,11 @@ public Auto(T value)
_cbOwnership = new BitMap(CommandBufferPool.MaxCommandBuffers);
}

public Auto(T value, IMirrorable<T> mirrorable, MultiFenceHolder waitable, params IAutoPrivate[] referencedObjs) : this(value, waitable, referencedObjs)
{
_mirrorable = mirrorable;
}

public Auto(T value, MultiFenceHolder waitable, params IAutoPrivate[] referencedObjs) : this(value)
{
_waitable = waitable;
Expand All @@ -48,9 +60,17 @@ public Auto(T value, MultiFenceHolder waitable, params IAutoPrivate[] referenced
}
}

public T Get(CommandBufferScoped cbs, int offset, int size)
public T GetMirrorable(CommandBufferScoped cbs, ref int offset, int size, out bool mirrored)
{
var mirror = _mirrorable.GetMirrorable(cbs, ref offset, size, out mirrored);
mirror._waitable?.AddBufferUse(cbs.CommandBufferIndex, offset, size, false);
riperiperi marked this conversation as resolved.
Show resolved Hide resolved
return mirror.Get(cbs);
}

public T Get(CommandBufferScoped cbs, int offset, int size, bool write = false)
{
_waitable?.AddBufferUse(cbs.CommandBufferIndex, offset, size);
_mirrorable?.ClearMirrors(cbs, offset, size);
_waitable?.AddBufferUse(cbs.CommandBufferIndex, offset, size, write);
return Get(cbs);
}

Expand Down