Przeglądaj źródła

Fix VIC out of bounds copy (#3386)

* Fix VIC out of bounds copy

* Update the assert
gdkchan 3 lat temu
rodzic
commit
d987cacfb7

+ 14 - 9
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<int> pixel1 = Sse41.ConvertToVector128Int32((ushort*)(ip + (uint)x));
                         Vector128<int> pixel2 = Sse41.ConvertToVector128Int32((ushort*)(ip + (uint)x + 1));

+ 18 - 0
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;
+        }
+    }
+}

+ 14 - 1
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);