aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Gpu/Engine/MethodCopyBuffer.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Engine/MethodCopyBuffer.cs')
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/MethodCopyBuffer.cs139
1 files changed, 107 insertions, 32 deletions
diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodCopyBuffer.cs b/Ryujinx.Graphics.Gpu/Engine/MethodCopyBuffer.cs
index 277054ce..67047a27 100644
--- a/Ryujinx.Graphics.Gpu/Engine/MethodCopyBuffer.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/MethodCopyBuffer.cs
@@ -1,3 +1,4 @@
+using Ryujinx.Common;
using Ryujinx.Graphics.Gpu.State;
using Ryujinx.Graphics.Texture;
using System;
@@ -7,6 +8,37 @@ namespace Ryujinx.Graphics.Gpu.Engine
{
partial class Methods
{
+ private const int StrideAlignment = 32;
+ private const int GobAlignment = 64;
+
+ /// <summary>
+ /// Determine if a buffer-to-texture region covers the entirety of a texture.
+ /// </summary>
+ /// <param name="cbp">Copy command parameters</param>
+ /// <param name="tex">Texture to compare</param>
+ /// <param name="linear">True if the texture is linear, false if block linear</param>
+ /// <param name="bpp">Texture bytes per pixel</param>
+ /// <param name="stride">Texture stride</param>
+ /// <returns></returns>
+ private bool IsTextureCopyComplete(CopyBufferParams cbp, CopyBufferTexture tex, bool linear, int bpp, int stride)
+ {
+ if (linear)
+ {
+ int alignWidth = StrideAlignment / bpp;
+ return tex.RegionX == 0 &&
+ tex.RegionY == 0 &&
+ stride / bpp == BitUtils.AlignUp(cbp.XCount, alignWidth);
+ }
+ else
+ {
+ int alignWidth = GobAlignment / bpp;
+ return tex.RegionX == 0 &&
+ tex.RegionY == 0 &&
+ tex.Width == BitUtils.AlignUp(cbp.XCount, alignWidth) &&
+ tex.Height == cbp.YCount;
+ }
+ }
+
/// <summary>
/// Performs a buffer to buffer, or buffer to texture copy.
/// </summary>
@@ -62,54 +94,97 @@ namespace Ryujinx.Graphics.Gpu.Engine
(int srcBaseOffset, int srcSize) = srcCalculator.GetRectangleRange(src.RegionX, src.RegionY, cbp.XCount, cbp.YCount);
(int dstBaseOffset, int dstSize) = dstCalculator.GetRectangleRange(dst.RegionX, dst.RegionY, cbp.XCount, cbp.YCount);
- ReadOnlySpan<byte> srcSpan = _context.PhysicalMemory.GetSpan(srcBaseAddress + (ulong)srcBaseOffset, srcSize);
+ ReadOnlySpan<byte> srcSpan = _context.PhysicalMemory.GetSpan(srcBaseAddress + (ulong)srcBaseOffset, srcSize, true);
Span<byte> dstSpan = _context.PhysicalMemory.GetSpan(dstBaseAddress + (ulong)dstBaseOffset, dstSize).ToArray();
- bool completeSource = src.RegionX == 0 && src.RegionY == 0 && src.Width == cbp.XCount && src.Height == cbp.YCount;
- bool completeDest = dst.RegionX == 0 && dst.RegionY == 0 && dst.Width == cbp.XCount && dst.Height == cbp.YCount;
+ bool completeSource = IsTextureCopyComplete(cbp, src, srcLinear, srcBpp, cbp.SrcStride);
+ bool completeDest = IsTextureCopyComplete(cbp, dst, dstLinear, dstBpp, cbp.DstStride);
- if (completeSource && completeDest && srcCalculator.LayoutMatches(dstCalculator))
+ if (completeSource && completeDest)
{
- srcSpan.CopyTo(dstSpan); // No layout conversion has to be performed, just copy the data entirely.
+ Image.Texture target = TextureManager.FindTexture(dst, cbp, swizzle, dstLinear);
+ if (target != null)
+ {
+ ReadOnlySpan<byte> data;
+ if (srcLinear)
+ {
+ data = LayoutConverter.ConvertLinearStridedToLinear(
+ target.Info.Width,
+ target.Info.Height,
+ 1,
+ 1,
+ cbp.SrcStride,
+ target.Info.FormatInfo.BytesPerPixel,
+ srcSpan);
+ }
+ else
+ {
+ data = LayoutConverter.ConvertBlockLinearToLinear(
+ src.Width,
+ src.Height,
+ 1,
+ target.Info.Levels,
+ 1,
+ 1,
+ 1,
+ srcBpp,
+ src.MemoryLayout.UnpackGobBlocksInY(),
+ src.MemoryLayout.UnpackGobBlocksInZ(),
+ src.MemoryLayout.UnpackGobBlocksInX(),
+ new SizeInfo((int)target.Size),
+ srcSpan);
+ }
+
+ target.SetData(data);
+ target.SignalModified();
+
+ return;
+ }
+ else if (srcCalculator.LayoutMatches(dstCalculator))
+ {
+ srcSpan.CopyTo(dstSpan); // No layout conversion has to be performed, just copy the data entirely.
+
+ _context.PhysicalMemory.Write(dstBaseAddress + (ulong)dstBaseOffset, dstSpan);
+
+ return;
+ }
}
- else
+
+ 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)
{
- 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 y = 0; y < cbp.YCount; y++)
{
- byte* dstBase = dstPtr - dstBaseOffset; // Layout offset is relative to the base, so we need to subtract the span's offset.
- byte* srcBase = srcPtr - srcBaseOffset;
+ srcCalculator.SetY(src.RegionY + y);
+ dstCalculator.SetY(dst.RegionY + y);
- for (int y = 0; y < cbp.YCount; y++)
+ for (int x = 0; x < cbp.XCount; x++)
{
- srcCalculator.SetY(src.RegionY + y);
- dstCalculator.SetY(dst.RegionY + y);
+ int srcOffset = srcCalculator.GetOffset(src.RegionX + x);
+ int dstOffset = dstCalculator.GetOffset(dst.RegionX + x);
- for (int x = 0; x < cbp.XCount; x++)
- {
- int srcOffset = srcCalculator.GetOffset(src.RegionX + x);
- int dstOffset = dstCalculator.GetOffset(dst.RegionX + x);
-
- *(T*)(dstBase + dstOffset) = *(T*)(srcBase + srcOffset);
- }
+ *(T*)(dstBase + dstOffset) = *(T*)(srcBase + srcOffset);
}
}
- return true;
}
-
- bool _ = srcBpp switch
- {
- 1 => Convert<byte>(dstSpan, srcSpan),
- 2 => Convert<ushort>(dstSpan, srcSpan),
- 4 => Convert<uint>(dstSpan, srcSpan),
- 8 => Convert<ulong>(dstSpan, srcSpan),
- 12 => Convert<Bpp12Pixel>(dstSpan, srcSpan),
- 16 => Convert<Vector128<byte>>(dstSpan, srcSpan),
- _ => throw new NotSupportedException($"Unable to copy ${srcBpp} bpp pixel format.")
- };
+ return true;
}
+ bool _ = srcBpp switch
+ {
+ 1 => Convert<byte>(dstSpan, srcSpan),
+ 2 => Convert<ushort>(dstSpan, srcSpan),
+ 4 => Convert<uint>(dstSpan, srcSpan),
+ 8 => Convert<ulong>(dstSpan, srcSpan),
+ 12 => Convert<Bpp12Pixel>(dstSpan, srcSpan),
+ 16 => Convert<Vector128<byte>>(dstSpan, srcSpan),
+ _ => throw new NotSupportedException($"Unable to copy ${srcBpp} bpp pixel format.")
+ };
+
_context.PhysicalMemory.Write(dstBaseAddress + (ulong)dstBaseOffset, dstSpan);
}
else