PreloadCbs + FlushCommandsIfWeightExceeding
This commit is contained in:
parent
b1928461bb
commit
03161d8048
2 changed files with 53 additions and 0 deletions
|
@ -190,6 +190,18 @@ namespace Ryujinx.Graphics.Metal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cbs != null &&
|
||||||
|
_pipeline.RenderPassActive &&
|
||||||
|
!(_buffer.HasCommandBufferDependency(cbs.Value) &&
|
||||||
|
_waitable.IsBufferRangeInUse(cbs.Value.CommandBufferIndex, offset, dataSize)))
|
||||||
|
{
|
||||||
|
// If the buffer hasn't been used on the command buffer yet, try to preload the data.
|
||||||
|
// This avoids ending and beginning render passes on each buffer data upload.
|
||||||
|
|
||||||
|
cbs = _pipeline.PreloadCbs;
|
||||||
|
endRenderPass = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (allowCbsWait)
|
if (allowCbsWait)
|
||||||
{
|
{
|
||||||
_renderer.BufferManager.StagingBuffer.PushData(_renderer.CommandBufferPool, cbs, endRenderPass, this, offset, data);
|
_renderer.BufferManager.StagingBuffer.PushData(_renderer.CommandBufferPool, cbs, endRenderPass, this, offset, data);
|
||||||
|
@ -331,6 +343,8 @@ namespace Ryujinx.Graphics.Metal
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
_pipeline.FlushCommandsIfWeightExceeding(_buffer, (ulong)Size);
|
||||||
|
|
||||||
_buffer.Dispose();
|
_buffer.Dispose();
|
||||||
_cachedConvertedBuffers.Dispose();
|
_cachedConvertedBuffers.Dispose();
|
||||||
|
|
||||||
|
|
|
@ -20,16 +20,21 @@ namespace Ryujinx.Graphics.Metal
|
||||||
[SupportedOSPlatform("macos")]
|
[SupportedOSPlatform("macos")]
|
||||||
class Pipeline : IPipeline, IDisposable
|
class Pipeline : IPipeline, IDisposable
|
||||||
{
|
{
|
||||||
|
private const ulong MinByteWeightForFlush = 256 * 1024 * 1024; // MiB
|
||||||
|
|
||||||
private readonly MTLDevice _device;
|
private readonly MTLDevice _device;
|
||||||
private readonly MetalRenderer _renderer;
|
private readonly MetalRenderer _renderer;
|
||||||
private EncoderStateManager _encoderStateManager;
|
private EncoderStateManager _encoderStateManager;
|
||||||
|
private ulong _byteWeight;
|
||||||
|
|
||||||
public readonly Action EndRenderPassDelegate;
|
public readonly Action EndRenderPassDelegate;
|
||||||
public MTLCommandBuffer CommandBuffer;
|
public MTLCommandBuffer CommandBuffer;
|
||||||
|
|
||||||
|
internal CommandBufferScoped? PreloadCbs { get; private set; }
|
||||||
internal CommandBufferScoped Cbs { get; private set; }
|
internal CommandBufferScoped Cbs { get; private set; }
|
||||||
internal MTLCommandEncoder? CurrentEncoder { get; private set; }
|
internal MTLCommandEncoder? CurrentEncoder { get; private set; }
|
||||||
internal EncoderType CurrentEncoderType { get; private set; } = EncoderType.None;
|
internal EncoderType CurrentEncoderType { get; private set; } = EncoderType.None;
|
||||||
|
internal bool RenderPassActive { get; private set; }
|
||||||
|
|
||||||
public Pipeline(MTLDevice device, MetalRenderer renderer)
|
public Pipeline(MTLDevice device, MetalRenderer renderer)
|
||||||
{
|
{
|
||||||
|
@ -133,6 +138,7 @@ namespace Ryujinx.Graphics.Metal
|
||||||
case EncoderType.Render:
|
case EncoderType.Render:
|
||||||
new MTLRenderCommandEncoder(CurrentEncoder.Value).EndEncoding();
|
new MTLRenderCommandEncoder(CurrentEncoder.Value).EndEncoding();
|
||||||
CurrentEncoder = null;
|
CurrentEncoder = null;
|
||||||
|
RenderPassActive = false;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
|
@ -150,6 +156,7 @@ namespace Ryujinx.Graphics.Metal
|
||||||
|
|
||||||
CurrentEncoder = renderCommandEncoder;
|
CurrentEncoder = renderCommandEncoder;
|
||||||
CurrentEncoderType = EncoderType.Render;
|
CurrentEncoderType = EncoderType.Render;
|
||||||
|
RenderPassActive = true;
|
||||||
|
|
||||||
return renderCommandEncoder;
|
return renderCommandEncoder;
|
||||||
}
|
}
|
||||||
|
@ -198,12 +205,44 @@ namespace Ryujinx.Graphics.Metal
|
||||||
dst.Dispose();
|
dst.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void FlushCommandsIfWeightExceeding(IAuto disposedResource, ulong byteWeight)
|
||||||
|
{
|
||||||
|
bool usedByCurrentCb = disposedResource.HasCommandBufferDependency(Cbs);
|
||||||
|
|
||||||
|
if (PreloadCbs != null && !usedByCurrentCb)
|
||||||
|
{
|
||||||
|
usedByCurrentCb = disposedResource.HasCommandBufferDependency(PreloadCbs.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (usedByCurrentCb)
|
||||||
|
{
|
||||||
|
// Since we can only free memory after the command buffer that uses a given resource was executed,
|
||||||
|
// keeping the command buffer might cause a high amount of memory to be in use.
|
||||||
|
// To prevent that, we force submit command buffers if the memory usage by resources
|
||||||
|
// in use by the current command buffer is above a given limit, and those resources were disposed.
|
||||||
|
_byteWeight += byteWeight;
|
||||||
|
|
||||||
|
if (_byteWeight >= MinByteWeightForFlush)
|
||||||
|
{
|
||||||
|
FlushCommandsImpl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void FlushCommandsImpl()
|
public void FlushCommandsImpl()
|
||||||
{
|
{
|
||||||
SaveState();
|
SaveState();
|
||||||
|
|
||||||
EndCurrentPass();
|
EndCurrentPass();
|
||||||
|
|
||||||
|
_byteWeight = 0;
|
||||||
|
|
||||||
|
if (PreloadCbs != null)
|
||||||
|
{
|
||||||
|
PreloadCbs.Value.Dispose();
|
||||||
|
PreloadCbs = null;
|
||||||
|
}
|
||||||
|
|
||||||
CommandBuffer = (Cbs = _renderer.CommandBufferPool.ReturnAndRent(Cbs)).CommandBuffer;
|
CommandBuffer = (Cbs = _renderer.CommandBufferPool.ReturnAndRent(Cbs)).CommandBuffer;
|
||||||
_renderer.RegisterFlush();
|
_renderer.RegisterFlush();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue