Account for negative strides on DMA copy (#2623)

* Account for negative strides on DMA copy

* Should account for non-zero Y
This commit is contained in:
gdkchan 2021-09-11 17:54:18 -03:00 committed by GitHub
parent 016fc64b3d
commit ac4ec1a015
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 27 additions and 11 deletions

View file

@ -76,6 +76,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
{ {
if (linear) if (linear)
{ {
// If the stride is negative, the texture has to be flipped, so
// the fast copy is not trivial, use the slow path.
if (stride <= 0)
{
return false;
}
int alignWidth = Constants.StrideAlignment / bpp; int alignWidth = Constants.StrideAlignment / bpp;
return tex.RegionX == 0 && return tex.RegionX == 0 &&
tex.RegionY == 0 && tex.RegionY == 0 &&
@ -155,8 +162,18 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
(int srcBaseOffset, int srcSize) = srcCalculator.GetRectangleRange(src.RegionX, src.RegionY, xCount, yCount); (int srcBaseOffset, int srcSize) = srcCalculator.GetRectangleRange(src.RegionX, src.RegionY, xCount, yCount);
(int dstBaseOffset, int dstSize) = dstCalculator.GetRectangleRange(dst.RegionX, dst.RegionY, xCount, yCount); (int dstBaseOffset, int dstSize) = dstCalculator.GetRectangleRange(dst.RegionX, dst.RegionY, xCount, yCount);
ReadOnlySpan<byte> srcSpan = memoryManager.GetSpan(srcGpuVa + (uint)srcBaseOffset, srcSize, true); if (srcLinear && srcStride < 0)
Span<byte> dstSpan = memoryManager.GetSpan(dstGpuVa + (uint)dstBaseOffset, dstSize).ToArray(); {
srcBaseOffset += srcStride * (yCount - 1);
}
if (dstLinear && dstStride < 0)
{
dstBaseOffset += dstStride * (yCount - 1);
}
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);
@ -214,7 +231,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
{ {
srcSpan.CopyTo(dstSpan); // No layout conversion has to be performed, just copy the data entirely. srcSpan.CopyTo(dstSpan); // No layout conversion has to be performed, just copy the data entirely.
memoryManager.Write(dstGpuVa + (uint)dstBaseOffset, dstSpan); memoryManager.Write(dstGpuVa + (ulong)dstBaseOffset, dstSpan);
return; return;
} }
@ -255,7 +272,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
_ => throw new NotSupportedException($"Unable to copy ${srcBpp} bpp pixel format.") _ => throw new NotSupportedException($"Unable to copy ${srcBpp} bpp pixel format.")
}; };
memoryManager.Write(dstGpuVa + (uint)dstBaseOffset, dstSpan); memoryManager.Write(dstGpuVa + (ulong)dstBaseOffset, dstSpan);
} }
else else
{ {

View file

@ -110,10 +110,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.InlineToMemory
ulong dstGpuVa = ((ulong)state.OffsetOutUpperValue << 32) | state.OffsetOut; ulong dstGpuVa = ((ulong)state.OffsetOutUpperValue << 32) | state.OffsetOut;
ulong dstBaseAddress = _channel.MemoryManager.Translate(dstGpuVa);
// Trigger read tracking, to flush any managed resources in the destination region. // Trigger read tracking, to flush any managed resources in the destination region.
_channel.MemoryManager.Physical.GetSpan(dstBaseAddress, _size, true); _channel.MemoryManager.GetSpan(dstGpuVa, _size, true);
_dstGpuVa = dstGpuVa; _dstGpuVa = dstGpuVa;
_dstX = state.SetDstOriginBytesXV; _dstX = state.SetDstOriginBytesXV;

View file

@ -892,7 +892,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
_physicalMemory.Write(Range, GetTextureDataFromGpu(Span<byte>.Empty, true, texture)); _physicalMemory.Write(Range, GetTextureDataFromGpu(Span<byte>.Empty, true, texture));
} }
else else
{ {
_physicalMemory.WriteUntracked(Range, GetTextureDataFromGpu(Span<byte>.Empty, false, texture)); _physicalMemory.WriteUntracked(Range, GetTextureDataFromGpu(Span<byte>.Empty, false, texture));
} }

View file

@ -1,4 +1,5 @@
using Ryujinx.Common; using Ryujinx.Common;
using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using static Ryujinx.Graphics.Texture.BlockLinearConstants; using static Ryujinx.Graphics.Texture.BlockLinearConstants;
@ -111,9 +112,9 @@ namespace Ryujinx.Graphics.Texture
{ {
if (_isLinear) if (_isLinear)
{ {
int start = y * _stride + x * _bytesPerPixel; int start = y * Math.Abs(_stride) + x * _bytesPerPixel;
int end = (y + height - 1) * _stride + (x + width) * _bytesPerPixel; int end = (y + height - 1) * Math.Abs(_stride) + (x + width) * _bytesPerPixel;
return (start, end - start); return (y * _stride + x * _bytesPerPixel, end - start);
} }
else else
{ {