diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodCopyTexture.cs b/Ryujinx.Graphics.Gpu/Engine/MethodCopyTexture.cs index 1a22bdbf3..da08f31a1 100644 --- a/Ryujinx.Graphics.Gpu/Engine/MethodCopyTexture.cs +++ b/Ryujinx.Graphics.Gpu/Engine/MethodCopyTexture.cs @@ -24,11 +24,29 @@ namespace Ryujinx.Graphics.Gpu.Engine var control = state.Get(MethodOffset.CopyTextureControl); - int srcX1 = (int)(region.SrcXF >> 32); - int srcY1 = (int)(region.SrcYF >> 32); + bool originCorner = control.UnpackOriginCorner(); - int srcX2 = (int)((region.SrcXF + region.SrcWidthRF * region.DstWidth) >> 32); - int srcY2 = (int)((region.SrcYF + region.SrcHeightRF * region.DstHeight) >> 32); + long srcX = region.SrcXF; + long srcY = region.SrcYF; + + if (originCorner) + { + // If the origin is corner, it is assumed that the guest API + // is manually centering the origin by adding a offset to the + // source region X/Y coordinates. + // Here we attempt to remove such offset to ensure we have the correct region. + // The offset is calculated as FactorXY / 2.0, where FactorXY = SrcXY / DstXY, + // so we do the same here by dividing the fixed point value by 2, while + // throwing away the fractional part to avoid rounding errors. + srcX -= (region.SrcWidthRF >> 33) << 32; + srcY -= (region.SrcHeightRF >> 33) << 32; + } + + int srcX1 = (int)(srcX >> 32); + int srcY1 = (int)(srcY >> 32); + + int srcX2 = srcX1 + (int)((region.SrcWidthRF * region.DstWidth + uint.MaxValue) >> 32); + int srcY2 = srcY1 + (int)((region.SrcHeightRF * region.DstHeight + uint.MaxValue) >> 32); int dstX1 = region.DstX; int dstY1 = region.DstY; diff --git a/Ryujinx.Graphics.Gpu/State/CopyTextureControl.cs b/Ryujinx.Graphics.Gpu/State/CopyTextureControl.cs index 50fb90103..d6256f685 100644 --- a/Ryujinx.Graphics.Gpu/State/CopyTextureControl.cs +++ b/Ryujinx.Graphics.Gpu/State/CopyTextureControl.cs @@ -9,6 +9,11 @@ namespace Ryujinx.Graphics.Gpu.State public uint Packed; #pragma warning restore CS0649 + public bool UnpackOriginCorner() + { + return (Packed & 1u) != 0; + } + public bool UnpackLinearFilter() { return (Packed & (1u << 4)) != 0;