From d987cacfb720f2f4bc18958fc26ac0893903c090 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Fri, 17 Jun 2022 12:01:52 -0300 Subject: [PATCH] Fix VIC out of bounds copy (#3386) * Fix VIC out of bounds copy * Update the assert --- Ryujinx.Graphics.Vic/Blender.cs | 23 ++++++++++++++--------- Ryujinx.Graphics.Vic/Rectangle.cs | 18 ++++++++++++++++++ Ryujinx.Graphics.Vic/VicDevice.cs | 15 ++++++++++++++- 3 files changed, 46 insertions(+), 10 deletions(-) create mode 100644 Ryujinx.Graphics.Vic/Rectangle.cs diff --git a/Ryujinx.Graphics.Vic/Blender.cs b/Ryujinx.Graphics.Vic/Blender.cs index 92b641d6..b6ca35ae 100644 --- a/Ryujinx.Graphics.Vic/Blender.cs +++ b/Ryujinx.Graphics.Vic/Blender.cs @@ -10,17 +10,22 @@ namespace Ryujinx.Graphics.Vic { static class Blender { - public static void BlendOne(Surface dst, Surface src, ref SlotStruct slot) + public static void BlendOne(Surface dst, Surface src, ref SlotStruct slot, Rectangle targetRect) { - if (Sse41.IsSupported && (dst.Width & 3) == 0) + int x1 = targetRect.X; + int y1 = targetRect.Y; + int x2 = Math.Min(src.Width, x1 + targetRect.Width); + int y2 = Math.Min(src.Height, y1 + targetRect.Height); + + if (Sse41.IsSupported && ((x1 | x2) & 3) == 0) { - BlendOneSse41(dst, src, ref slot); + BlendOneSse41(dst, src, ref slot, x1, y1, x2, y2); return; } - for (int y = 0; y < dst.Height; y++) + for (int y = y1; y < y2; y++) { - for (int x = 0; x < dst.Width; x++) + for (int x = x1; x < x2; x++) { int inR = src.GetR(x, y); int inG = src.GetG(x, y); @@ -40,9 +45,9 @@ namespace Ryujinx.Graphics.Vic } } - private unsafe static void BlendOneSse41(Surface dst, Surface src, ref SlotStruct slot) + private unsafe static void BlendOneSse41(Surface dst, Surface src, ref SlotStruct slot, int x1, int y1, int x2, int y2) { - Debug.Assert((dst.Width & 3) == 0); + Debug.Assert(((x1 | x2) & 3) == 0); ref MatrixStruct mtx = ref slot.ColorMatrixStruct; @@ -62,9 +67,9 @@ namespace Ryujinx.Graphics.Vic Pixel* ip = srcPtr; Pixel* op = dstPtr; - for (int y = 0; y < dst.Height; y++, ip += src.Width, op += dst.Width) + for (int y = y1; y < y2; y++, ip += src.Width, op += dst.Width) { - for (int x = 0; x < dst.Width; x += 4) + for (int x = x1; x < x2; x += 4) { Vector128 pixel1 = Sse41.ConvertToVector128Int32((ushort*)(ip + (uint)x)); Vector128 pixel2 = Sse41.ConvertToVector128Int32((ushort*)(ip + (uint)x + 1)); diff --git a/Ryujinx.Graphics.Vic/Rectangle.cs b/Ryujinx.Graphics.Vic/Rectangle.cs new file mode 100644 index 00000000..2a13b95c --- /dev/null +++ b/Ryujinx.Graphics.Vic/Rectangle.cs @@ -0,0 +1,18 @@ +namespace Ryujinx.Graphics.Vic +{ + struct Rectangle + { + public readonly int X; + public readonly int Y; + public readonly int Width; + public readonly int Height; + + public Rectangle(int x, int y, int width, int height) + { + X = x; + Y = y; + Width = width; + Height = height; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics.Vic/VicDevice.cs b/Ryujinx.Graphics.Vic/VicDevice.cs index 537b8ba4..8b66727d 100644 --- a/Ryujinx.Graphics.Vic/VicDevice.cs +++ b/Ryujinx.Graphics.Vic/VicDevice.cs @@ -2,6 +2,7 @@ using Ryujinx.Graphics.Gpu.Memory; using Ryujinx.Graphics.Vic.Image; using Ryujinx.Graphics.Vic.Types; +using System; using System.Collections.Generic; namespace Ryujinx.Graphics.Vic @@ -47,7 +48,19 @@ namespace Ryujinx.Graphics.Vic using Surface src = SurfaceReader.Read(_rm, ref slot.SlotConfig, ref slot.SlotSurfaceConfig, ref offsets); - Blender.BlendOne(output, src, ref slot); + int x1 = config.OutputConfig.TargetRectLeft; + int y1 = config.OutputConfig.TargetRectTop; + int x2 = config.OutputConfig.TargetRectRight + 1; + int y2 = config.OutputConfig.TargetRectBottom + 1; + + int targetX = Math.Min(x1, x2); + int targetY = Math.Min(y1, y2); + int targetW = Math.Min(output.Width - targetX, Math.Abs(x2 - x1)); + int targetH = Math.Min(output.Height - targetY, Math.Abs(y2 - y1)); + + Rectangle targetRect = new Rectangle(targetX, targetY, targetW, targetH); + + Blender.BlendOne(output, src, ref slot, targetRect); } SurfaceWriter.Write(_rm, output, ref config.OutputSurfaceConfig, ref _state.State.SetOutputSurface);