diff --git a/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs b/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs index 3078cc8a..8e4ac5e2 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs @@ -76,6 +76,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma { 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; return tex.RegionX == 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 dstBaseOffset, int dstSize) = dstCalculator.GetRectangleRange(dst.RegionX, dst.RegionY, xCount, yCount); - ReadOnlySpan srcSpan = memoryManager.GetSpan(srcGpuVa + (uint)srcBaseOffset, srcSize, true); - Span dstSpan = memoryManager.GetSpan(dstGpuVa + (uint)dstBaseOffset, dstSize).ToArray(); + if (srcLinear && srcStride < 0) + { + srcBaseOffset += srcStride * (yCount - 1); + } + + if (dstLinear && dstStride < 0) + { + dstBaseOffset += dstStride * (yCount - 1); + } + + ReadOnlySpan srcSpan = memoryManager.GetSpan(srcGpuVa + (ulong)srcBaseOffset, srcSize, true); + Span dstSpan = memoryManager.GetSpan(dstGpuVa + (ulong)dstBaseOffset, dstSize).ToArray(); bool completeSource = IsTextureCopyComplete(src, srcLinear, srcBpp, srcStride, 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. - memoryManager.Write(dstGpuVa + (uint)dstBaseOffset, dstSpan); + memoryManager.Write(dstGpuVa + (ulong)dstBaseOffset, dstSpan); return; } @@ -255,7 +272,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma _ => throw new NotSupportedException($"Unable to copy ${srcBpp} bpp pixel format.") }; - memoryManager.Write(dstGpuVa + (uint)dstBaseOffset, dstSpan); + memoryManager.Write(dstGpuVa + (ulong)dstBaseOffset, dstSpan); } else { diff --git a/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs b/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs index 81c5ad77..75b8e220 100644 --- a/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs +++ b/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs @@ -110,10 +110,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.InlineToMemory 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. - _channel.MemoryManager.Physical.GetSpan(dstBaseAddress, _size, true); + _channel.MemoryManager.GetSpan(dstGpuVa, _size, true); _dstGpuVa = dstGpuVa; _dstX = state.SetDstOriginBytesXV; diff --git a/Ryujinx.Graphics.Gpu/Image/Texture.cs b/Ryujinx.Graphics.Gpu/Image/Texture.cs index 3a66960d..7cc8faf6 100644 --- a/Ryujinx.Graphics.Gpu/Image/Texture.cs +++ b/Ryujinx.Graphics.Gpu/Image/Texture.cs @@ -892,7 +892,7 @@ namespace Ryujinx.Graphics.Gpu.Image { _physicalMemory.Write(Range, GetTextureDataFromGpu(Span.Empty, true, texture)); } - else + else { _physicalMemory.WriteUntracked(Range, GetTextureDataFromGpu(Span.Empty, false, texture)); } diff --git a/Ryujinx.Graphics.Texture/OffsetCalculator.cs b/Ryujinx.Graphics.Texture/OffsetCalculator.cs index dd4b6e7f..d7472e2f 100644 --- a/Ryujinx.Graphics.Texture/OffsetCalculator.cs +++ b/Ryujinx.Graphics.Texture/OffsetCalculator.cs @@ -1,4 +1,5 @@ using Ryujinx.Common; +using System; using System.Runtime.CompilerServices; using static Ryujinx.Graphics.Texture.BlockLinearConstants; @@ -111,9 +112,9 @@ namespace Ryujinx.Graphics.Texture { if (_isLinear) { - int start = y * _stride + x * _bytesPerPixel; - int end = (y + height - 1) * _stride + (x + width) * _bytesPerPixel; - return (start, end - start); + int start = y * Math.Abs(_stride) + x * _bytesPerPixel; + int end = (y + height - 1) * Math.Abs(_stride) + (x + width) * _bytesPerPixel; + return (y * _stride + x * _bytesPerPixel, end - start); } else {