/ src / Ryujinx.Graphics.Nvdec.Vp9 / ReconInter.cs
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  }