forked from Mirror/Ryujinx
Reduce some unnecessary allocations in DMA handler (#2886)
* experimental changes to try and reduce allocations in kernel threading and DMA handler * Simplify the changes in this branch to just 1. Don't make unnecessary copies of data just for texture-texture transfers and 2. Add a fast path for 1bpp linear byte copies * forgot to check src + dst linearity in 1bpp DMA fast path. Fixes the UE4 regression. * removing dev log I left in * Generalizing the DMA linear fast path to cases other than 1bpp copies * revert kernel changes * revert whitespace * remove unneeded references * PR feedback Co-authored-by: Logan Stromberg <lostromb@microsoft.com> Co-authored-by: gdk <gab.dark.100@gmail.com>
This commit is contained in:
parent
c5bddfeab8
commit
6eb85e846f
1 changed files with 33 additions and 14 deletions
|
@ -208,7 +208,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadOnlySpan<byte> srcSpan = memoryManager.GetSpan(srcGpuVa + (ulong)srcBaseOffset, srcSize, true);
|
ReadOnlySpan<byte> srcSpan = memoryManager.GetSpan(srcGpuVa + (ulong)srcBaseOffset, srcSize, true);
|
||||||
Span<byte> dstSpan = memoryManager.GetSpan(dstGpuVa + (ulong)dstBaseOffset, dstSize).ToArray();
|
|
||||||
|
|
||||||
bool completeSource = IsTextureCopyComplete(src, srcLinear, srcBpp, srcStride, xCount, yCount);
|
bool completeSource = IsTextureCopyComplete(src, srcLinear, srcBpp, srcStride, xCount, yCount);
|
||||||
bool completeDest = IsTextureCopyComplete(dst, dstLinear, dstBpp, dstStride, xCount, yCount);
|
bool completeDest = IsTextureCopyComplete(dst, dstLinear, dstBpp, dstStride, xCount, yCount);
|
||||||
|
@ -262,43 +261,63 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
||||||
target.SynchronizeMemory();
|
target.SynchronizeMemory();
|
||||||
target.SetData(data);
|
target.SetData(data);
|
||||||
target.SignalModified();
|
target.SignalModified();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (srcCalculator.LayoutMatches(dstCalculator))
|
else if (srcCalculator.LayoutMatches(dstCalculator))
|
||||||
{
|
{
|
||||||
srcSpan.CopyTo(dstSpan); // No layout conversion has to be performed, just copy the data entirely.
|
// No layout conversion has to be performed, just copy the data entirely.
|
||||||
|
memoryManager.Write(dstGpuVa + (ulong)dstBaseOffset, srcSpan);
|
||||||
memoryManager.Write(dstGpuVa + (ulong)dstBaseOffset, dstSpan);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe bool Convert<T>(Span<byte> dstSpan, ReadOnlySpan<byte> srcSpan) where T : unmanaged
|
unsafe bool Convert<T>(Span<byte> dstSpan, ReadOnlySpan<byte> srcSpan) where T : unmanaged
|
||||||
{
|
{
|
||||||
fixed (byte* dstPtr = dstSpan, srcPtr = srcSpan)
|
if (srcLinear && dstLinear && srcBpp == dstBpp)
|
||||||
{
|
{
|
||||||
byte* dstBase = dstPtr - dstBaseOffset; // Layout offset is relative to the base, so we need to subtract the span's offset.
|
// Optimized path for purely linear copies - we don't need to calculate every single byte offset,
|
||||||
byte* srcBase = srcPtr - srcBaseOffset;
|
// and we can make use of Span.CopyTo which is very very fast (even compared to pointers)
|
||||||
|
|
||||||
for (int y = 0; y < yCount; y++)
|
for (int y = 0; y < yCount; y++)
|
||||||
{
|
{
|
||||||
srcCalculator.SetY(srcRegionY + y);
|
srcCalculator.SetY(srcRegionY + y);
|
||||||
dstCalculator.SetY(dstRegionY + y);
|
dstCalculator.SetY(dstRegionY + y);
|
||||||
|
int srcOffset = srcCalculator.GetOffset(srcRegionX);
|
||||||
|
int dstOffset = dstCalculator.GetOffset(dstRegionX);
|
||||||
|
srcSpan.Slice(srcOffset - srcBaseOffset, xCount * srcBpp)
|
||||||
|
.CopyTo(dstSpan.Slice(dstOffset - dstBaseOffset, xCount * dstBpp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fixed (byte* dstPtr = dstSpan, srcPtr = srcSpan)
|
||||||
|
{
|
||||||
|
byte* dstBase = dstPtr - dstBaseOffset; // Layout offset is relative to the base, so we need to subtract the span's offset.
|
||||||
|
byte* srcBase = srcPtr - srcBaseOffset;
|
||||||
|
|
||||||
for (int x = 0; x < xCount; x++)
|
for (int y = 0; y < yCount; y++)
|
||||||
{
|
{
|
||||||
int srcOffset = srcCalculator.GetOffset(srcRegionX + x);
|
srcCalculator.SetY(srcRegionY + y);
|
||||||
int dstOffset = dstCalculator.GetOffset(dstRegionX + x);
|
dstCalculator.SetY(dstRegionY + y);
|
||||||
|
|
||||||
*(T*)(dstBase + dstOffset) = *(T*)(srcBase + srcOffset);
|
for (int x = 0; x < xCount; x++)
|
||||||
|
{
|
||||||
|
int srcOffset = srcCalculator.GetOffset(srcRegionX + x);
|
||||||
|
int dstOffset = dstCalculator.GetOffset(dstRegionX + x);
|
||||||
|
|
||||||
|
*(T*)(dstBase + dstOffset) = *(T*)(srcBase + srcOffset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OPT: This allocates a (potentially) huge temporary array and then copies an existing
|
||||||
|
// region of memory into it, data that might get overwritten entirely anyways. Ideally this should
|
||||||
|
// all be rewritten to use pooled arrays, but that gets complicated with packed data and strides
|
||||||
|
Span<byte> dstSpan = memoryManager.GetSpan(dstGpuVa + (ulong)dstBaseOffset, dstSize).ToArray();
|
||||||
|
|
||||||
bool _ = srcBpp switch
|
bool _ = srcBpp switch
|
||||||
{
|
{
|
||||||
1 => Convert<byte>(dstSpan, srcSpan),
|
1 => Convert<byte>(dstSpan, srcSpan),
|
||||||
|
|
Loading…
Reference in a new issue