aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2021-07-12 16:48:57 -0300
committerGitHub <noreply@github.com>2021-07-12 16:48:57 -0300
commit04dce402ac94679c5439038be1c8ce090e7ad4cb (patch)
treec7478e7eb87061400bab37daf4f2f69cf387d9f2
parent9b08abc644c4afcb1b4eb59bfbe8057727ad9d70 (diff)
Implement a fast path for I2M transfers (#2467)
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs9
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoProcessor.cs53
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs20
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs9
4 files changed, 88 insertions, 3 deletions
diff --git a/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs b/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs
index ac8b1186..a0304308 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs
@@ -69,6 +69,15 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
}
/// <summary>
+ /// Pushes a block of data to the Inline-to-Memory engine.
+ /// </summary>
+ /// <param name="data">Data to push</param>
+ public void LoadInlineData(ReadOnlySpan<int> data)
+ {
+ _i2mClass.LoadInlineData(data);
+ }
+
+ /// <summary>
/// Pushes a word of data to the Inline-to-Memory engine.
/// </summary>
/// <param name="argument">Method call argument</param>
diff --git a/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoProcessor.cs b/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoProcessor.cs
index dd5e6fe5..ea34d6cd 100644
--- a/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoProcessor.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoProcessor.cs
@@ -18,6 +18,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
private const int MacrosCount = 0x80;
private const int MacroIndexMask = MacrosCount - 1;
+ private const int LoadInlineDataMethodOffset = 0x6d;
private const int UniformBufferUpdateDataMethodOffset = 0x8e4;
private readonly GpuChannel _channel;
@@ -78,6 +79,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
if (_state.MethodCount != 0)
{
+ if (TryFastI2mBufferUpdate(commandBuffer, ref index))
+ {
+ continue;
+ }
+
Send(_state.Method, command, _state.SubChannel, _state.MethodCount <= 1);
if (!_state.NonIncrementing)
@@ -124,6 +130,46 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
}
/// <summary>
+ /// Tries to perform a fast Inline-to-Memory data update.
+ /// If successful, all data will be copied at once, and <see cref="DmaState.MethodCount"/>
+ /// command buffer entries will be consumed.
+ /// </summary>
+ /// <param name="commandBuffer">Command buffer where the data is contained</param>
+ /// <param name="offset">Offset at <paramref name="commandBuffer"/> where the data is located, auto-incremented on success</param>
+ /// <returns>True if the fast copy was successful, false otherwise</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private bool TryFastI2mBufferUpdate(ReadOnlySpan<int> commandBuffer, ref int offset)
+ {
+ if (_state.Method == LoadInlineDataMethodOffset && _state.NonIncrementing && _state.SubChannel <= 2)
+ {
+ int availableCount = commandBuffer.Length - offset;
+ int consumeCount = Math.Min(_state.MethodCount, availableCount);
+
+ var data = commandBuffer.Slice(offset, consumeCount);
+
+ if (_state.SubChannel == 0)
+ {
+ _3dClass.LoadInlineData(data);
+ }
+ else if (_state.SubChannel == 1)
+ {
+ _computeClass.LoadInlineData(data);
+ }
+ else /* if (_state.SubChannel == 2) */
+ {
+ _i2mClass.LoadInlineData(data);
+ }
+
+ offset += consumeCount - 1;
+ _state.MethodCount -= consumeCount;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /// <summary>
/// Tries to perform a fast constant buffer data update.
/// If successful, all data will be copied at once, and <see cref="CompressedMethod.MethodCount"/> + 1
/// command buffer entries will be consumed.
@@ -132,13 +178,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
/// <param name="commandBuffer">Command buffer where <paramref name="meth"/> is contained</param>
/// <param name="offset">Offset at <paramref name="commandBuffer"/> where <paramref name="meth"/> is located</param>
/// <returns>True if the fast copy was successful, false otherwise</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
private bool TryFastUniformBufferUpdate(CompressedMethod meth, ReadOnlySpan<int> commandBuffer, int offset)
{
int availableCount = commandBuffer.Length - offset;
- if (meth.MethodCount < availableCount &&
- meth.SecOp == SecOp.NonIncMethod &&
- meth.MethodAddress == UniformBufferUpdateDataMethodOffset)
+ if (meth.MethodAddress == UniformBufferUpdateDataMethodOffset &&
+ meth.MethodCount < availableCount &&
+ meth.SecOp == SecOp.NonIncMethod)
{
_3dClass.ConstantBufferUpdate(commandBuffer.Slice(offset + 1, meth.MethodCount));
diff --git a/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs b/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs
index cb4133ec..186a4648 100644
--- a/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs
@@ -128,6 +128,26 @@ namespace Ryujinx.Graphics.Gpu.Engine.InlineToMemory
}
/// <summary>
+ /// Pushes a block of data to the Inline-to-Memory engine.
+ /// </summary>
+ /// <param name="data">Data to push</param>
+ public void LoadInlineData(ReadOnlySpan<int> data)
+ {
+ if (!_finished)
+ {
+ int copySize = Math.Min(data.Length, _buffer.Length - _offset);
+ data.Slice(0, copySize).CopyTo(new Span<int>(_buffer).Slice(_offset, copySize));
+
+ _offset += copySize;
+
+ if (_offset * 4 >= _size)
+ {
+ FinishTransfer();
+ }
+ }
+ }
+
+ /// <summary>
/// Pushes a word of data to the Inline-to-Memory engine.
/// </summary>
/// <param name="argument">Method call argument</param>
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs
index ad6a1d0e..37c8fec2 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs
@@ -184,6 +184,15 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
}
/// <summary>
+ /// Pushes a block of data to the Inline-to-Memory engine.
+ /// </summary>
+ /// <param name="data">Data to push</param>
+ public void LoadInlineData(ReadOnlySpan<int> data)
+ {
+ _i2mClass.LoadInlineData(data);
+ }
+
+ /// <summary>
/// Pushes a word of data to the Inline-to-Memory engine.
/// </summary>
/// <param name="argument">Method call argument</param>