ReconInter.cs
1 using Ryujinx.Common.Memory; 2 using Ryujinx.Graphics.Nvdec.Vp9.Types; 3 using System; 4 using System.Diagnostics; 5 using System.Runtime.CompilerServices; 6 using static Ryujinx.Graphics.Nvdec.Vp9.Dsp.Filter; 7 8 namespace Ryujinx.Graphics.Nvdec.Vp9 9 { 10 internal static class ReconInter 11 { 12 [MethodImpl(MethodImplOptions.AggressiveInlining)] 13 public static unsafe void InterPredictor( 14 byte* src, 15 int srcStride, 16 byte* dst, 17 int dstStride, 18 int subpelX, 19 int subpelY, 20 ref ScaleFactors sf, 21 int w, 22 int h, 23 int refr, 24 Array8<short>[] kernel, 25 int xs, 26 int ys) 27 { 28 sf.InterPredict( 29 subpelX != 0 ? 1 : 0, 30 subpelY != 0 ? 1 : 0, 31 refr, 32 src, 33 srcStride, 34 dst, 35 dstStride, 36 subpelX, 37 subpelY, 38 w, 39 h, 40 kernel, 41 xs, 42 ys); 43 } 44 45 [MethodImpl(MethodImplOptions.AggressiveInlining)] 46 public static unsafe void HighbdInterPredictor( 47 ushort* src, 48 int srcStride, 49 ushort* dst, 50 int dstStride, 51 int subpelX, 52 int subpelY, 53 ref ScaleFactors sf, 54 int w, 55 int h, 56 int refr, 57 Array8<short>[] kernel, 58 int xs, 59 int ys, 60 int bd) 61 { 62 sf.HighbdInterPredict( 63 subpelX != 0 ? 1 : 0, 64 subpelY != 0 ? 1 : 0, 65 refr, 66 src, 67 srcStride, 68 dst, 69 dstStride, 70 subpelX, 71 subpelY, 72 w, 73 h, 74 kernel, 75 xs, 76 ys, 77 bd); 78 } 79 80 private static int RoundMvCompQ4(int value) 81 { 82 return (value < 0 ? value - 2 : value + 2) / 4; 83 } 84 85 private static Mv MiMvPredQ4(ref ModeInfo mi, int idx) 86 { 87 return new Mv 88 { 89 Row = (short)RoundMvCompQ4( 90 mi.Bmi[0].Mv[idx].Row + mi.Bmi[1].Mv[idx].Row + 91 mi.Bmi[2].Mv[idx].Row + mi.Bmi[3].Mv[idx].Row), 92 Col = (short)RoundMvCompQ4( 93 mi.Bmi[0].Mv[idx].Col + mi.Bmi[1].Mv[idx].Col + 94 mi.Bmi[2].Mv[idx].Col + mi.Bmi[3].Mv[idx].Col), 95 }; 96 } 97 98 private static int RoundMvCompQ2(int value) 99 { 100 return (value < 0 ? value - 1 : value + 1) / 2; 101 } 102 103 private static Mv MiMvPredQ2(ref ModeInfo mi, int idx, int block0, int block1) 104 { 105 return new Mv 106 { 107 Row = (short)RoundMvCompQ2( 108 mi.Bmi[block0].Mv[idx].Row + 109 mi.Bmi[block1].Mv[idx].Row), 110 Col = (short)RoundMvCompQ2( 111 mi.Bmi[block0].Mv[idx].Col + 112 mi.Bmi[block1].Mv[idx].Col), 113 }; 114 } 115 116 public static Mv ClampMvToUmvBorderSb(ref MacroBlockD xd, ref Mv srcMv, int bw, int bh, int ssX, int ssY) 117 { 118 // If the MV points so far into the UMV border that no visible pixels 119 // are used for reconstruction, the subpel part of the MV can be 120 // discarded and the MV limited to 16 pixels with equivalent results. 121 int spelLeft = (Constants.Vp9InterpExtend + bw) << SubpelBits; 122 int spelRight = spelLeft - SubpelShifts; 123 int spelTop = (Constants.Vp9InterpExtend + bh) << SubpelBits; 124 int spelBottom = spelTop - SubpelShifts; 125 Mv clampedMv = new() 126 { 127 Row = (short)(srcMv.Row * (1 << (1 - ssY))), 128 Col = (short)(srcMv.Col * (1 << (1 - ssX))), 129 }; 130 131 Debug.Assert(ssX <= 1); 132 Debug.Assert(ssY <= 1); 133 134 clampedMv.ClampMv( 135 xd.MbToLeftEdge * (1 << (1 - ssX)) - spelLeft, 136 xd.MbToRightEdge * (1 << (1 - ssX)) + spelRight, 137 xd.MbToTopEdge * (1 << (1 - ssY)) - spelTop, 138 xd.MbToBottomEdge * (1 << (1 - ssY)) + spelBottom); 139 140 return clampedMv; 141 } 142 143 public static Mv AverageSplitMvs(ref MacroBlockDPlane pd, ref ModeInfo mi, int refr, int block) 144 { 145 int ssIdx = ((pd.SubsamplingX > 0 ? 1 : 0) << 1) | (pd.SubsamplingY > 0 ? 1 : 0); 146 Mv res = new(); 147 switch (ssIdx) 148 { 149 case 0: 150 res = mi.Bmi[block].Mv[refr]; 151 break; 152 case 1: 153 res = MiMvPredQ2(ref mi, refr, block, block + 2); 154 break; 155 case 2: 156 res = MiMvPredQ2(ref mi, refr, block, block + 1); 157 break; 158 case 3: 159 res = MiMvPredQ4(ref mi, refr); 160 break; 161 default: 162 Debug.Assert(ssIdx <= 3 && ssIdx >= 0); 163 break; 164 } 165 return res; 166 } 167 168 private static int ScaledBufferOffset(int xOffset, int yOffset, int stride, Ptr<ScaleFactors> sf) 169 { 170 int x = !sf.IsNull ? sf.Value.ScaleValueX(xOffset) : xOffset; 171 int y = !sf.IsNull ? sf.Value.ScaleValueY(yOffset) : yOffset; 172 173 return y * stride + x; 174 } 175 176 private static void SetupPredPlanes( 177 ref Buf2D dst, 178 ArrayPtr<byte> src, 179 int stride, 180 int miRow, 181 int miCol, 182 Ptr<ScaleFactors> scale, 183 int subsamplingX, 184 int subsamplingY) 185 { 186 int x = (Constants.MiSize * miCol) >> subsamplingX; 187 int y = (Constants.MiSize * miRow) >> subsamplingY; 188 dst.Buf = src.Slice(ScaledBufferOffset(x, y, stride, scale)); 189 dst.Stride = stride; 190 } 191 192 public static void SetupDstPlanes( 193 ref Array3<MacroBlockDPlane> planes, 194 ref Surface src, 195 int miRow, 196 int miCol) 197 { 198 Span<ArrayPtr<byte>> buffers = stackalloc ArrayPtr<byte>[Constants.MaxMbPlane]; 199 buffers[0] = src.YBuffer; 200 buffers[1] = src.UBuffer; 201 buffers[2] = src.VBuffer; 202 Span<int> strides = stackalloc int[Constants.MaxMbPlane]; 203 strides[0] = src.Stride; 204 strides[1] = src.UvStride; 205 strides[2] = src.UvStride; 206 int i; 207 208 for (i = 0; i < Constants.MaxMbPlane; ++i) 209 { 210 ref MacroBlockDPlane pd = ref planes[i]; 211 SetupPredPlanes(ref pd.Dst, buffers[i], strides[i], miRow, miCol, Ptr<ScaleFactors>.Null, pd.SubsamplingX, pd.SubsamplingY); 212 } 213 } 214 215 public static void SetupPrePlanes( 216 ref MacroBlockD xd, 217 int idx, 218 ref Surface src, 219 int miRow, 220 int miCol, 221 Ptr<ScaleFactors> sf) 222 { 223 if (!src.YBuffer.IsNull && !src.UBuffer.IsNull && !src.VBuffer.IsNull) 224 { 225 Span<ArrayPtr<byte>> buffers = stackalloc ArrayPtr<byte>[Constants.MaxMbPlane]; 226 buffers[0] = src.YBuffer; 227 buffers[1] = src.UBuffer; 228 buffers[2] = src.VBuffer; 229 Span<int> strides = stackalloc int[Constants.MaxMbPlane]; 230 strides[0] = src.Stride; 231 strides[1] = src.UvStride; 232 strides[2] = src.UvStride; 233 int i; 234 235 for (i = 0; i < Constants.MaxMbPlane; ++i) 236 { 237 ref MacroBlockDPlane pd = ref xd.Plane[i]; 238 SetupPredPlanes(ref pd.Pre[idx], buffers[i], strides[i], miRow, miCol, sf, pd.SubsamplingX, pd.SubsamplingY); 239 } 240 } 241 } 242 } 243 }