452 lines
13 KiB
C#
452 lines
13 KiB
C#
|
using Ryujinx.Common.Memory;
|
|||
|
using System.Runtime.CompilerServices;
|
|||
|
using static Ryujinx.Graphics.Nvdec.Vp9.Dsp.Convolve;
|
|||
|
using static Ryujinx.Graphics.Nvdec.Vp9.Dsp.Filter;
|
|||
|
|
|||
|
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
|
{
|
|||
|
internal struct ScaleFactors
|
|||
|
{
|
|||
|
private const int RefScaleShift = 14;
|
|||
|
private const int RefNoScale = (1 << RefScaleShift);
|
|||
|
private const int RefInvalidScale = -1;
|
|||
|
|
|||
|
private unsafe delegate void ConvolveFn(
|
|||
|
byte* src,
|
|||
|
int srcStride,
|
|||
|
byte* dst,
|
|||
|
int dstStride,
|
|||
|
Array8<short>[] filter,
|
|||
|
int x0Q4,
|
|||
|
int xStepQ4,
|
|||
|
int y0Q4,
|
|||
|
int yStepQ4,
|
|||
|
int w,
|
|||
|
int h);
|
|||
|
|
|||
|
private unsafe delegate void HighbdConvolveFn(
|
|||
|
ushort* src,
|
|||
|
int srcStride,
|
|||
|
ushort* dst,
|
|||
|
int dstStride,
|
|||
|
Array8<short>[] filter,
|
|||
|
int x0Q4,
|
|||
|
int xStepQ4,
|
|||
|
int y0Q4,
|
|||
|
int yStepQ4,
|
|||
|
int w,
|
|||
|
int h,
|
|||
|
int bd);
|
|||
|
|
|||
|
private static readonly unsafe ConvolveFn[][][] PredictX16Y16 = new ConvolveFn[][][]
|
|||
|
{
|
|||
|
new ConvolveFn[][]
|
|||
|
{
|
|||
|
new ConvolveFn[]
|
|||
|
{
|
|||
|
ConvolveCopy,
|
|||
|
ConvolveAvg
|
|||
|
},
|
|||
|
new ConvolveFn[]
|
|||
|
{
|
|||
|
Convolve8Vert,
|
|||
|
Convolve8AvgVert
|
|||
|
}
|
|||
|
},
|
|||
|
new ConvolveFn[][]
|
|||
|
{
|
|||
|
new ConvolveFn[]
|
|||
|
{
|
|||
|
Convolve8Horiz,
|
|||
|
Convolve8AvgHoriz
|
|||
|
},
|
|||
|
new ConvolveFn[]
|
|||
|
{
|
|||
|
Convolve8,
|
|||
|
Convolve8Avg
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
private static readonly unsafe ConvolveFn[][][] PredictX16 = new ConvolveFn[][][]
|
|||
|
{
|
|||
|
new ConvolveFn[][]
|
|||
|
{
|
|||
|
new ConvolveFn[]
|
|||
|
{
|
|||
|
ScaledVert,
|
|||
|
ScaledAvgVert
|
|||
|
},
|
|||
|
new ConvolveFn[]
|
|||
|
{
|
|||
|
ScaledVert,
|
|||
|
ScaledAvgVert
|
|||
|
}
|
|||
|
},
|
|||
|
new ConvolveFn[][]
|
|||
|
{
|
|||
|
new ConvolveFn[]
|
|||
|
{
|
|||
|
Scaled2D,
|
|||
|
ScaledAvg2D
|
|||
|
},
|
|||
|
new ConvolveFn[]
|
|||
|
{
|
|||
|
Scaled2D,
|
|||
|
ScaledAvg2D
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
private static readonly unsafe ConvolveFn[][][] PredictY16 = new ConvolveFn[][][]
|
|||
|
{
|
|||
|
new ConvolveFn[][]
|
|||
|
{
|
|||
|
new ConvolveFn[]
|
|||
|
{
|
|||
|
ScaledHoriz,
|
|||
|
ScaledAvgHoriz
|
|||
|
},
|
|||
|
new ConvolveFn[]
|
|||
|
{
|
|||
|
Scaled2D,
|
|||
|
ScaledAvg2D
|
|||
|
}
|
|||
|
},
|
|||
|
new ConvolveFn[][]
|
|||
|
{
|
|||
|
new ConvolveFn[]
|
|||
|
{
|
|||
|
ScaledHoriz,
|
|||
|
ScaledAvgHoriz
|
|||
|
},
|
|||
|
new ConvolveFn[]
|
|||
|
{
|
|||
|
Scaled2D,
|
|||
|
ScaledAvg2D
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
private static readonly unsafe ConvolveFn[][][] Predict = new ConvolveFn[][][]
|
|||
|
{
|
|||
|
new ConvolveFn[][]
|
|||
|
{
|
|||
|
new ConvolveFn[]
|
|||
|
{
|
|||
|
Scaled2D,
|
|||
|
ScaledAvg2D
|
|||
|
},
|
|||
|
new ConvolveFn[]
|
|||
|
{
|
|||
|
Scaled2D,
|
|||
|
ScaledAvg2D
|
|||
|
}
|
|||
|
},
|
|||
|
new ConvolveFn[][]
|
|||
|
{
|
|||
|
new ConvolveFn[]
|
|||
|
{
|
|||
|
Scaled2D,
|
|||
|
ScaledAvg2D
|
|||
|
},
|
|||
|
new ConvolveFn[]
|
|||
|
{
|
|||
|
Scaled2D,
|
|||
|
ScaledAvg2D
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
private static readonly unsafe HighbdConvolveFn[][][] HighbdPredictX16Y16 = new HighbdConvolveFn[][][]
|
|||
|
{
|
|||
|
new HighbdConvolveFn[][]
|
|||
|
{
|
|||
|
new HighbdConvolveFn[]
|
|||
|
{
|
|||
|
HighbdConvolveCopy,
|
|||
|
HighbdConvolveAvg
|
|||
|
},
|
|||
|
new HighbdConvolveFn[]
|
|||
|
{
|
|||
|
HighbdConvolve8Vert,
|
|||
|
HighbdConvolve8AvgVert
|
|||
|
}
|
|||
|
},
|
|||
|
new HighbdConvolveFn[][]
|
|||
|
{
|
|||
|
new HighbdConvolveFn[]
|
|||
|
{
|
|||
|
HighbdConvolve8Horiz,
|
|||
|
HighbdConvolve8AvgHoriz
|
|||
|
},
|
|||
|
new HighbdConvolveFn[]
|
|||
|
{
|
|||
|
HighbdConvolve8,
|
|||
|
HighbdConvolve8Avg
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
private static readonly unsafe HighbdConvolveFn[][][] HighbdPredictX16 = new HighbdConvolveFn[][][]
|
|||
|
{
|
|||
|
new HighbdConvolveFn[][]
|
|||
|
{
|
|||
|
new HighbdConvolveFn[]
|
|||
|
{
|
|||
|
HighbdConvolve8Vert,
|
|||
|
HighbdConvolve8AvgVert
|
|||
|
},
|
|||
|
new HighbdConvolveFn[]
|
|||
|
{
|
|||
|
HighbdConvolve8Vert,
|
|||
|
HighbdConvolve8AvgVert
|
|||
|
}
|
|||
|
},
|
|||
|
new HighbdConvolveFn[][]
|
|||
|
{
|
|||
|
new HighbdConvolveFn[]
|
|||
|
{
|
|||
|
HighbdConvolve8,
|
|||
|
HighbdConvolve8Avg
|
|||
|
},
|
|||
|
new HighbdConvolveFn[]
|
|||
|
{
|
|||
|
HighbdConvolve8,
|
|||
|
HighbdConvolve8Avg
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
private static readonly unsafe HighbdConvolveFn[][][] HighbdPredictY16 = new HighbdConvolveFn[][][]
|
|||
|
{
|
|||
|
new HighbdConvolveFn[][]
|
|||
|
{
|
|||
|
new HighbdConvolveFn[]
|
|||
|
{
|
|||
|
HighbdConvolve8Horiz,
|
|||
|
HighbdConvolve8AvgHoriz
|
|||
|
},
|
|||
|
new HighbdConvolveFn[]
|
|||
|
{
|
|||
|
HighbdConvolve8,
|
|||
|
HighbdConvolve8Avg
|
|||
|
}
|
|||
|
},
|
|||
|
new HighbdConvolveFn[][]
|
|||
|
{
|
|||
|
new HighbdConvolveFn[]
|
|||
|
{
|
|||
|
HighbdConvolve8Horiz,
|
|||
|
HighbdConvolve8AvgHoriz
|
|||
|
},
|
|||
|
new HighbdConvolveFn[]
|
|||
|
{
|
|||
|
HighbdConvolve8,
|
|||
|
HighbdConvolve8Avg
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
private static readonly unsafe HighbdConvolveFn[][][] HighbdPredict = new HighbdConvolveFn[][][]
|
|||
|
{
|
|||
|
new HighbdConvolveFn[][]
|
|||
|
{
|
|||
|
new HighbdConvolveFn[]
|
|||
|
{
|
|||
|
HighbdConvolve8,
|
|||
|
HighbdConvolve8Avg
|
|||
|
},
|
|||
|
new HighbdConvolveFn[]
|
|||
|
{
|
|||
|
HighbdConvolve8,
|
|||
|
HighbdConvolve8Avg
|
|||
|
}
|
|||
|
},
|
|||
|
new HighbdConvolveFn[][]
|
|||
|
{
|
|||
|
new HighbdConvolveFn[]
|
|||
|
{
|
|||
|
HighbdConvolve8,
|
|||
|
HighbdConvolve8Avg
|
|||
|
},
|
|||
|
new HighbdConvolveFn[]
|
|||
|
{
|
|||
|
HighbdConvolve8,
|
|||
|
HighbdConvolve8Avg
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
public int XScaleFP; // Horizontal fixed point scale factor
|
|||
|
public int YScaleFP; // Vertical fixed point scale factor
|
|||
|
public int XStepQ4;
|
|||
|
public int YStepQ4;
|
|||
|
|
|||
|
public int ScaleValueX(int val)
|
|||
|
{
|
|||
|
return IsScaled() ? ScaledX(val) : val;
|
|||
|
}
|
|||
|
|
|||
|
public int ScaleValueY(int val)
|
|||
|
{
|
|||
|
return IsScaled() ? ScaledY(val) : val;
|
|||
|
}
|
|||
|
|
|||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|||
|
public unsafe void InterPredict(
|
|||
|
int horiz,
|
|||
|
int vert,
|
|||
|
int avg,
|
|||
|
byte* src,
|
|||
|
int srcStride,
|
|||
|
byte* dst,
|
|||
|
int dstStride,
|
|||
|
int subpelX,
|
|||
|
int subpelY,
|
|||
|
int w,
|
|||
|
int h,
|
|||
|
Array8<short>[] kernel,
|
|||
|
int xs,
|
|||
|
int ys)
|
|||
|
{
|
|||
|
if (XStepQ4 == 16)
|
|||
|
{
|
|||
|
if (YStepQ4 == 16)
|
|||
|
{
|
|||
|
// No scaling in either direction.
|
|||
|
PredictX16Y16[horiz][vert][avg](src, srcStride, dst, dstStride, kernel, subpelX, xs, subpelY, ys, w, h);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// No scaling in x direction. Must always scale in the y direction.
|
|||
|
PredictX16[horiz][vert][avg](src, srcStride, dst, dstStride, kernel, subpelX, xs, subpelY, ys, w, h);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (YStepQ4 == 16)
|
|||
|
{
|
|||
|
// No scaling in the y direction. Must always scale in the x direction.
|
|||
|
PredictY16[horiz][vert][avg](src, srcStride, dst, dstStride, kernel, subpelX, xs, subpelY, ys, w, h);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// Must always scale in both directions.
|
|||
|
Predict[horiz][vert][avg](src, srcStride, dst, dstStride, kernel, subpelX, xs, subpelY, ys, w, h);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|||
|
public unsafe void HighbdInterPredict(
|
|||
|
int horiz,
|
|||
|
int vert,
|
|||
|
int avg,
|
|||
|
ushort* src,
|
|||
|
int srcStride,
|
|||
|
ushort* dst,
|
|||
|
int dstStride,
|
|||
|
int subpelX,
|
|||
|
int subpelY,
|
|||
|
int w,
|
|||
|
int h,
|
|||
|
Array8<short>[] kernel,
|
|||
|
int xs,
|
|||
|
int ys,
|
|||
|
int bd)
|
|||
|
{
|
|||
|
if (XStepQ4 == 16)
|
|||
|
{
|
|||
|
if (YStepQ4 == 16)
|
|||
|
{
|
|||
|
// No scaling in either direction.
|
|||
|
HighbdPredictX16Y16[horiz][vert][avg](src, srcStride, dst, dstStride, kernel, subpelX, xs, subpelY, ys, w, h, bd);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// No scaling in x direction. Must always scale in the y direction.
|
|||
|
HighbdPredictX16[horiz][vert][avg](src, srcStride, dst, dstStride, kernel, subpelX, xs, subpelY, ys, w, h, bd);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (YStepQ4 == 16)
|
|||
|
{
|
|||
|
// No scaling in the y direction. Must always scale in the x direction.
|
|||
|
HighbdPredictY16[horiz][vert][avg](src, srcStride, dst, dstStride, kernel, subpelX, xs, subpelY, ys, w, h, bd);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// Must always scale in both directions.
|
|||
|
HighbdPredict[horiz][vert][avg](src, srcStride, dst, dstStride, kernel, subpelX, xs, subpelY, ys, w, h, bd);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private int ScaledX(int val)
|
|||
|
{
|
|||
|
return (int)((long)val * XScaleFP >> RefScaleShift);
|
|||
|
}
|
|||
|
|
|||
|
private int ScaledY(int val)
|
|||
|
{
|
|||
|
return (int)((long)val * YScaleFP >> RefScaleShift);
|
|||
|
}
|
|||
|
|
|||
|
private static int GetFixedPointScaleFactor(int otherSize, int thisSize)
|
|||
|
{
|
|||
|
// Calculate scaling factor once for each reference frame
|
|||
|
// and use fixed point scaling factors in decoding and encoding routines.
|
|||
|
// Hardware implementations can calculate scale factor in device driver
|
|||
|
// and use multiplication and shifting on hardware instead of division.
|
|||
|
return (otherSize << RefScaleShift) / thisSize;
|
|||
|
}
|
|||
|
|
|||
|
public Mv32 ScaleMv(ref Mv mv, int x, int y)
|
|||
|
{
|
|||
|
int xOffQ4 = ScaledX(x << SubpelBits) & SubpelMask;
|
|||
|
int yOffQ4 = ScaledY(y << SubpelBits) & SubpelMask;
|
|||
|
Mv32 res = new Mv32()
|
|||
|
{
|
|||
|
Row = ScaledY(mv.Row) + yOffQ4,
|
|||
|
Col = ScaledX(mv.Col) + xOffQ4
|
|||
|
};
|
|||
|
return res;
|
|||
|
}
|
|||
|
|
|||
|
public bool IsValidScale()
|
|||
|
{
|
|||
|
return XScaleFP != RefInvalidScale && YScaleFP != RefInvalidScale;
|
|||
|
}
|
|||
|
|
|||
|
public bool IsScaled()
|
|||
|
{
|
|||
|
return IsValidScale() && (XScaleFP != RefNoScale || YScaleFP != RefNoScale);
|
|||
|
}
|
|||
|
|
|||
|
public static bool ValidRefFrameSize(int refWidth, int refHeight, int thisWidth, int thisHeight)
|
|||
|
{
|
|||
|
return 2 * thisWidth >= refWidth &&
|
|||
|
2 * thisHeight >= refHeight &&
|
|||
|
thisWidth <= 16 * refWidth &&
|
|||
|
thisHeight <= 16 * refHeight;
|
|||
|
}
|
|||
|
|
|||
|
public void SetupScaleFactorsForFrame(int otherW, int otherH, int thisW, int thisH)
|
|||
|
{
|
|||
|
if (!ValidRefFrameSize(otherW, otherH, thisW, thisH))
|
|||
|
{
|
|||
|
XScaleFP = RefInvalidScale;
|
|||
|
YScaleFP = RefInvalidScale;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
XScaleFP = GetFixedPointScaleFactor(otherW, thisW);
|
|||
|
YScaleFP = GetFixedPointScaleFactor(otherH, thisH);
|
|||
|
XStepQ4 = ScaledX(16);
|
|||
|
YStepQ4 = ScaledY(16);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|