Ryujinx/Ryujinx.Graphics.Nvdec.Vp9/Types/ScaleFactors.cs
gdkchan 4d02a2d2c0
New NVDEC and VIC implementation (#1384)
* Initial NVDEC and VIC implementation

* Update FFmpeg.AutoGen to 4.3.0

* Add nvdec dependencies for Windows

* Unify some VP9 structures

* Rename VP9 structure fields

* Improvements to Video API

* XML docs for Common.Memory

* Remove now unused or redundant overloads from MemoryAccessor

* NVDEC UV surface read/write scalar paths

* Add FIXME comments about hacky things/stuff that will need to be fixed in the future

* Cleaned up VP9 memory allocation

* Remove some debug logs

* Rename some VP9 structs

* Remove unused struct

* No need to compile Ryujinx.Graphics.Host1x with unsafe anymore

* Name AsyncWorkQueue threads to make debugging easier

* Make Vp9PictureInfo a ref struct

* LayoutConverter no longer needs the depth argument (broken by rebase)

* Pooling of VP9 buffers, plus fix a memory leak on VP9

* Really wish VS could rename projects properly...

* Address feedback

* Remove using

* Catch OperationCanceledException

* Add licensing informations

* Add THIRDPARTY.md to release too

Co-authored-by: Thog <me@thog.eu>
2020-07-12 05:07:01 +02:00

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);
}
}
}