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:
Logan Stromberg 2022-07-14 11:45:56 -07:00 committed by GitHub
parent c5bddfeab8
commit 6eb85e846f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -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),