aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Nvdec.Vp9/ReconIntra.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics.Nvdec.Vp9/ReconIntra.cs')
-rw-r--r--Ryujinx.Graphics.Nvdec.Vp9/ReconIntra.cs761
1 files changed, 761 insertions, 0 deletions
diff --git a/Ryujinx.Graphics.Nvdec.Vp9/ReconIntra.cs b/Ryujinx.Graphics.Nvdec.Vp9/ReconIntra.cs
new file mode 100644
index 00000000..0e1ddfb3
--- /dev/null
+++ b/Ryujinx.Graphics.Nvdec.Vp9/ReconIntra.cs
@@ -0,0 +1,761 @@
+using Ryujinx.Graphics.Nvdec.Vp9.Common;
+using Ryujinx.Graphics.Nvdec.Vp9.Types;
+using static Ryujinx.Graphics.Nvdec.Vp9.Dsp.IntraPred;
+
+namespace Ryujinx.Graphics.Nvdec.Vp9
+{
+ internal static class ReconIntra
+ {
+ public static readonly TxType[] IntraModeToTxTypeLookup = new TxType[]
+ {
+ TxType.DctDct, // DC
+ TxType.AdstDct, // V
+ TxType.DctAdst, // H
+ TxType.DctDct, // D45
+ TxType.AdstAdst, // D135
+ TxType.AdstDct, // D117
+ TxType.DctAdst, // D153
+ TxType.DctAdst, // D207
+ TxType.AdstDct, // D63
+ TxType.AdstAdst // TM
+ };
+
+ private const int NeedLeft = 1 << 1;
+ private const int NeedAbove = 1 << 2;
+ private const int NeedAboveRight = 1 << 3;
+
+ private static readonly byte[] ExtendModes = new byte[]
+ {
+ NeedAbove | NeedLeft, // DC
+ NeedAbove, // V
+ NeedLeft, // H
+ NeedAboveRight, // D45
+ NeedLeft | NeedAbove, // D135
+ NeedLeft | NeedAbove, // D117
+ NeedLeft | NeedAbove, // D153
+ NeedLeft, // D207
+ NeedAboveRight, // D63
+ NeedLeft | NeedAbove, // TM
+ };
+
+ private unsafe delegate void IntraPredFn(byte* dst, int stride, byte* above, byte* left);
+
+ private static unsafe IntraPredFn[][] _pred = new IntraPredFn[][]
+ {
+ new IntraPredFn[]
+ {
+ null,
+ null,
+ null,
+ null
+ },
+ new IntraPredFn[]
+ {
+ VPredictor4x4,
+ VPredictor8x8,
+ VPredictor16x16,
+ VPredictor32x32
+ },
+ new IntraPredFn[]
+ {
+ HPredictor4x4,
+ HPredictor8x8,
+ HPredictor16x16,
+ HPredictor32x32
+ },
+ new IntraPredFn[]
+ {
+ D45Predictor4x4,
+ D45Predictor8x8,
+ D45Predictor16x16,
+ D45Predictor32x32
+ },
+ new IntraPredFn[]
+ {
+ D135Predictor4x4,
+ D135Predictor8x8,
+ D135Predictor16x16,
+ D135Predictor32x32
+ },
+ new IntraPredFn[]
+ {
+ D117Predictor4x4,
+ D117Predictor8x8,
+ D117Predictor16x16,
+ D117Predictor32x32
+ },
+ new IntraPredFn[]
+ {
+ D153Predictor4x4,
+ D153Predictor8x8,
+ D153Predictor16x16,
+ D153Predictor32x32
+ },
+ new IntraPredFn[]
+ {
+ D207Predictor4x4,
+ D207Predictor8x8,
+ D207Predictor16x16,
+ D207Predictor32x32
+ },
+ new IntraPredFn[]
+ {
+ D63Predictor4x4,
+ D63Predictor8x8,
+ D63Predictor16x16,
+ D63Predictor32x32
+ },
+ new IntraPredFn[]
+ {
+ TMPredictor4x4,
+ TMPredictor8x8,
+ TMPredictor16x16,
+ TMPredictor32x32
+ }
+ };
+
+ private static unsafe IntraPredFn[][][] _dcPred = new IntraPredFn[][][]
+ {
+ new IntraPredFn[][]
+ {
+ new IntraPredFn[]
+ {
+ Dc128Predictor4x4,
+ Dc128Predictor8x8,
+ Dc128Predictor16x16,
+ Dc128Predictor32x32
+ },
+ new IntraPredFn[]
+ {
+ DcTopPredictor4x4,
+ DcTopPredictor8x8,
+ DcTopPredictor16x16,
+ DcTopPredictor32x32
+ }
+ },
+ new IntraPredFn[][]
+ {
+ new IntraPredFn[]
+ {
+ DcLeftPredictor4x4,
+ DcLeftPredictor8x8,
+ DcLeftPredictor16x16,
+ DcLeftPredictor32x32
+ },
+ new IntraPredFn[]
+ {
+ DcPredictor4x4,
+ DcPredictor8x8,
+ DcPredictor16x16,
+ DcPredictor32x32
+ }
+ }
+ };
+
+ private unsafe delegate void IntraHighPredFn(ushort* dst, int stride, ushort* above, ushort* left, int bd);
+
+ private static unsafe IntraHighPredFn[][] _predHigh = new IntraHighPredFn[][]
+ {
+ new IntraHighPredFn[]
+ {
+ null,
+ null,
+ null,
+ null
+ },
+ new IntraHighPredFn[]
+ {
+ HighbdVPredictor4x4,
+ HighbdVPredictor8x8,
+ HighbdVPredictor16x16,
+ HighbdVPredictor32x32
+ },
+ new IntraHighPredFn[]
+ {
+ HighbdHPredictor4x4,
+ HighbdHPredictor8x8,
+ HighbdHPredictor16x16,
+ HighbdHPredictor32x32
+ },
+ new IntraHighPredFn[]
+ {
+ HighbdD45Predictor4x4,
+ HighbdD45Predictor8x8,
+ HighbdD45Predictor16x16,
+ HighbdD45Predictor32x32
+ },
+ new IntraHighPredFn[]
+ {
+ HighbdD135Predictor4x4,
+ HighbdD135Predictor8x8,
+ HighbdD135Predictor16x16,
+ HighbdD135Predictor32x32
+ },
+ new IntraHighPredFn[]
+ {
+ HighbdD117Predictor4x4,
+ HighbdD117Predictor8x8,
+ HighbdD117Predictor16x16,
+ HighbdD117Predictor32x32
+ },
+ new IntraHighPredFn[]
+ {
+ HighbdD153Predictor4x4,
+ HighbdD153Predictor8x8,
+ HighbdD153Predictor16x16,
+ HighbdD153Predictor32x32
+ },
+ new IntraHighPredFn[]
+ {
+ HighbdD207Predictor4x4,
+ HighbdD207Predictor8x8,
+ HighbdD207Predictor16x16,
+ HighbdD207Predictor32x32
+ },
+ new IntraHighPredFn[]
+ {
+ HighbdD63Predictor4x4,
+ HighbdD63Predictor8x8,
+ HighbdD63Predictor16x16,
+ HighbdD63Predictor32x32
+ },
+ new IntraHighPredFn[]
+ {
+ HighbdTMPredictor4x4,
+ HighbdTMPredictor8x8,
+ HighbdTMPredictor16x16,
+ HighbdTMPredictor32x32
+ }
+ };
+
+ private static unsafe IntraHighPredFn[][][] _dcPredHigh = new IntraHighPredFn[][][]
+ {
+ new IntraHighPredFn[][]
+ {
+ new IntraHighPredFn[]
+ {
+ HighbdDc128Predictor4x4,
+ HighbdDc128Predictor8x8,
+ HighbdDc128Predictor16x16,
+ HighbdDc128Predictor32x32
+ },
+ new IntraHighPredFn[]
+ {
+ HighbdDcTopPredictor4x4,
+ HighbdDcTopPredictor8x8,
+ HighbdDcTopPredictor16x16,
+ HighbdDcTopPredictor32x32
+ }
+ },
+ new IntraHighPredFn[][]
+ {
+ new IntraHighPredFn[]
+ {
+ HighbdDcLeftPredictor4x4,
+ HighbdDcLeftPredictor8x8,
+ HighbdDcLeftPredictor16x16,
+ HighbdDcLeftPredictor32x32
+ },
+ new IntraHighPredFn[]
+ {
+ HighbdDcPredictor4x4,
+ HighbdDcPredictor8x8,
+ HighbdDcPredictor16x16,
+ HighbdDcPredictor32x32
+ }
+ }
+ };
+
+ private static unsafe void BuildIntraPredictorsHigh(
+ ref MacroBlockD xd,
+ byte* ref8,
+ int refStride,
+ byte* dst8,
+ int dstStride,
+ PredictionMode mode,
+ TxSize txSize,
+ int upAvailable,
+ int leftAvailable,
+ int rightAvailable,
+ int x,
+ int y,
+ int plane)
+ {
+ int i;
+ ushort* dst = (ushort*)dst8;
+ ushort* refr = (ushort*)ref8;
+ ushort* leftCol = stackalloc ushort[32];
+ ushort* aboveData = stackalloc ushort[64 + 16];
+ ushort* aboveRow = aboveData + 16;
+ ushort* constAboveRow = aboveRow;
+ int bs = 4 << (int)txSize;
+ int frameWidth, frameHeight;
+ int x0, y0;
+ ref MacroBlockDPlane pd = ref xd.Plane[plane];
+ int needLeft = ExtendModes[(int)mode] & NeedLeft;
+ int needAbove = ExtendModes[(int)mode] & NeedAbove;
+ int needAboveRight = ExtendModes[(int)mode] & NeedAboveRight;
+ int baseVal = 128 << (xd.Bd - 8);
+ // 127 127 127 .. 127 127 127 127 127 127
+ // 129 A B .. Y Z
+ // 129 C D .. W X
+ // 129 E F .. U V
+ // 129 G H .. S T T T T T
+ // For 10 bit and 12 bit, 127 and 129 are replaced by base -1 and base + 1.
+
+ // Get current frame pointer, width and height.
+ if (plane == 0)
+ {
+ frameWidth = xd.CurBuf.Width;
+ frameHeight = xd.CurBuf.Height;
+ }
+ else
+ {
+ frameWidth = xd.CurBuf.UvWidth;
+ frameHeight = xd.CurBuf.UvHeight;
+ }
+
+ // Get block position in current frame.
+ x0 = (-xd.MbToLeftEdge >> (3 + pd.SubsamplingX)) + x;
+ y0 = (-xd.MbToTopEdge >> (3 + pd.SubsamplingY)) + y;
+
+ // NEED_LEFT
+ if (needLeft != 0)
+ {
+ if (leftAvailable != 0)
+ {
+ if (xd.MbToBottomEdge < 0)
+ {
+ /* slower path if the block needs border extension */
+ if (y0 + bs <= frameHeight)
+ {
+ for (i = 0; i < bs; ++i)
+ {
+ leftCol[i] = refr[i * refStride - 1];
+ }
+ }
+ else
+ {
+ int extendBottom = frameHeight - y0;
+ for (i = 0; i < extendBottom; ++i)
+ {
+ leftCol[i] = refr[i * refStride - 1];
+ }
+
+ for (; i < bs; ++i)
+ {
+ leftCol[i] = refr[(extendBottom - 1) * refStride - 1];
+ }
+ }
+ }
+ else
+ {
+ /* faster path if the block does not need extension */
+ for (i = 0; i < bs; ++i)
+ {
+ leftCol[i] = refr[i * refStride - 1];
+ }
+ }
+ }
+ else
+ {
+ MemoryUtil.Fill(leftCol, (ushort)(baseVal + 1), bs);
+ }
+ }
+
+ // NEED_ABOVE
+ if (needAbove != 0)
+ {
+ if (upAvailable != 0)
+ {
+ ushort* aboveRef = refr - refStride;
+ if (xd.MbToRightEdge < 0)
+ {
+ /* slower path if the block needs border extension */
+ if (x0 + bs <= frameWidth)
+ {
+ MemoryUtil.Copy(aboveRow, aboveRef, bs);
+ }
+ else if (x0 <= frameWidth)
+ {
+ int r = frameWidth - x0;
+ MemoryUtil.Copy(aboveRow, aboveRef, r);
+ MemoryUtil.Fill(aboveRow + r, aboveRow[r - 1], x0 + bs - frameWidth);
+ }
+ }
+ else
+ {
+ /* faster path if the block does not need extension */
+ if (bs == 4 && rightAvailable != 0 && leftAvailable != 0)
+ {
+ constAboveRow = aboveRef;
+ }
+ else
+ {
+ MemoryUtil.Copy(aboveRow, aboveRef, bs);
+ }
+ }
+ aboveRow[-1] = leftAvailable != 0 ? aboveRef[-1] : (ushort)(baseVal + 1);
+ }
+ else
+ {
+ MemoryUtil.Fill(aboveRow, (ushort)(baseVal - 1), bs);
+ aboveRow[-1] = (ushort)(baseVal - 1);
+ }
+ }
+
+ // NEED_ABOVERIGHT
+ if (needAboveRight != 0)
+ {
+ if (upAvailable != 0)
+ {
+ ushort* aboveRef = refr - refStride;
+ if (xd.MbToRightEdge < 0)
+ {
+ /* slower path if the block needs border extension */
+ if (x0 + 2 * bs <= frameWidth)
+ {
+ if (rightAvailable != 0 && bs == 4)
+ {
+ MemoryUtil.Copy(aboveRow, aboveRef, 2 * bs);
+ }
+ else
+ {
+ MemoryUtil.Copy(aboveRow, aboveRef, bs);
+ MemoryUtil.Fill(aboveRow + bs, aboveRow[bs - 1], bs);
+ }
+ }
+ else if (x0 + bs <= frameWidth)
+ {
+ int r = frameWidth - x0;
+ if (rightAvailable != 0 && bs == 4)
+ {
+ MemoryUtil.Copy(aboveRow, aboveRef, r);
+ MemoryUtil.Fill(aboveRow + r, aboveRow[r - 1], x0 + 2 * bs - frameWidth);
+ }
+ else
+ {
+ MemoryUtil.Copy(aboveRow, aboveRef, bs);
+ MemoryUtil.Fill(aboveRow + bs, aboveRow[bs - 1], bs);
+ }
+ }
+ else if (x0 <= frameWidth)
+ {
+ int r = frameWidth - x0;
+ MemoryUtil.Copy(aboveRow, aboveRef, r);
+ MemoryUtil.Fill(aboveRow + r, aboveRow[r - 1], x0 + 2 * bs - frameWidth);
+ }
+ aboveRow[-1] = leftAvailable != 0 ? aboveRef[-1] : (ushort)(baseVal + 1);
+ }
+ else
+ {
+ /* faster path if the block does not need extension */
+ if (bs == 4 && rightAvailable != 0 && leftAvailable != 0)
+ {
+ constAboveRow = aboveRef;
+ }
+ else
+ {
+ MemoryUtil.Copy(aboveRow, aboveRef, bs);
+ if (bs == 4 && rightAvailable != 0)
+ {
+ MemoryUtil.Copy(aboveRow + bs, aboveRef + bs, bs);
+ }
+ else
+ {
+ MemoryUtil.Fill(aboveRow + bs, aboveRow[bs - 1], bs);
+ }
+
+ aboveRow[-1] = leftAvailable != 0 ? aboveRef[-1] : (ushort)(baseVal + 1);
+ }
+ }
+ }
+ else
+ {
+ MemoryUtil.Fill(aboveRow, (ushort)(baseVal - 1), bs * 2);
+ aboveRow[-1] = (ushort)(baseVal - 1);
+ }
+ }
+
+ // Predict
+ if (mode == PredictionMode.DcPred)
+ {
+ _dcPredHigh[leftAvailable][upAvailable][(int)txSize](dst, dstStride, constAboveRow, leftCol, xd.Bd);
+ }
+ else
+ {
+ _predHigh[(int)mode][(int)txSize](dst, dstStride, constAboveRow, leftCol, xd.Bd);
+ }
+ }
+
+ public static unsafe void BuildIntraPredictors(
+ ref MacroBlockD xd,
+ byte* refr,
+ int refStride,
+ byte* dst,
+ int dstStride,
+ PredictionMode mode,
+ TxSize txSize,
+ int upAvailable,
+ int leftAvailable,
+ int rightAvailable,
+ int x,
+ int y,
+ int plane)
+ {
+ int i;
+ byte* leftCol = stackalloc byte[32];
+ byte* aboveData = stackalloc byte[64 + 16];
+ byte* aboveRow = aboveData + 16;
+ byte* constAboveRow = aboveRow;
+ int bs = 4 << (int)txSize;
+ int frameWidth, frameHeight;
+ int x0, y0;
+ ref MacroBlockDPlane pd = ref xd.Plane[plane];
+
+ // 127 127 127 .. 127 127 127 127 127 127
+ // 129 A B .. Y Z
+ // 129 C D .. W X
+ // 129 E F .. U V
+ // 129 G H .. S T T T T T
+ // ..
+
+ // Get current frame pointer, width and height.
+ if (plane == 0)
+ {
+ frameWidth = xd.CurBuf.Width;
+ frameHeight = xd.CurBuf.Height;
+ }
+ else
+ {
+ frameWidth = xd.CurBuf.UvWidth;
+ frameHeight = xd.CurBuf.UvHeight;
+ }
+
+ // Get block position in current frame.
+ x0 = (-xd.MbToLeftEdge >> (3 + pd.SubsamplingX)) + x;
+ y0 = (-xd.MbToTopEdge >> (3 + pd.SubsamplingY)) + y;
+
+ // NEED_LEFT
+ if ((ExtendModes[(int)mode] & NeedLeft) != 0)
+ {
+ if (leftAvailable != 0)
+ {
+ if (xd.MbToBottomEdge < 0)
+ {
+ /* Slower path if the block needs border extension */
+ if (y0 + bs <= frameHeight)
+ {
+ for (i = 0; i < bs; ++i)
+ {
+ leftCol[i] = refr[i * refStride - 1];
+ }
+ }
+ else
+ {
+ int extendBottom = frameHeight - y0;
+ for (i = 0; i < extendBottom; ++i)
+ {
+ leftCol[i] = refr[i * refStride - 1];
+ }
+
+ for (; i < bs; ++i)
+ {
+ leftCol[i] = refr[(extendBottom - 1) * refStride - 1];
+ }
+ }
+ }
+ else
+ {
+ /* Faster path if the block does not need extension */
+ for (i = 0; i < bs; ++i)
+ {
+ leftCol[i] = refr[i * refStride - 1];
+ }
+ }
+ }
+ else
+ {
+ MemoryUtil.Fill(leftCol, (byte)129, bs);
+ }
+ }
+
+ // NEED_ABOVE
+ if ((ExtendModes[(int)mode] & NeedAbove) != 0)
+ {
+ if (upAvailable != 0)
+ {
+ byte* aboveRef = refr - refStride;
+ if (xd.MbToRightEdge < 0)
+ {
+ /* Slower path if the block needs border extension */
+ if (x0 + bs <= frameWidth)
+ {
+ MemoryUtil.Copy(aboveRow, aboveRef, bs);
+ }
+ else if (x0 <= frameWidth)
+ {
+ int r = frameWidth - x0;
+ MemoryUtil.Copy(aboveRow, aboveRef, r);
+ MemoryUtil.Fill(aboveRow + r, aboveRow[r - 1], x0 + bs - frameWidth);
+ }
+ }
+ else
+ {
+ /* Faster path if the block does not need extension */
+ if (bs == 4 && rightAvailable != 0 && leftAvailable != 0)
+ {
+ constAboveRow = aboveRef;
+ }
+ else
+ {
+ MemoryUtil.Copy(aboveRow, aboveRef, bs);
+ }
+ }
+ aboveRow[-1] = leftAvailable != 0 ? aboveRef[-1] : (byte)129;
+ }
+ else
+ {
+ MemoryUtil.Fill(aboveRow, (byte)127, bs);
+ aboveRow[-1] = 127;
+ }
+ }
+
+ // NEED_ABOVERIGHT
+ if ((ExtendModes[(int)mode] & NeedAboveRight) != 0)
+ {
+ if (upAvailable != 0)
+ {
+ byte* aboveRef = refr - refStride;
+ if (xd.MbToRightEdge < 0)
+ {
+ /* Slower path if the block needs border extension */
+ if (x0 + 2 * bs <= frameWidth)
+ {
+ if (rightAvailable != 0 && bs == 4)
+ {
+ MemoryUtil.Copy(aboveRow, aboveRef, 2 * bs);
+ }
+ else
+ {
+ MemoryUtil.Copy(aboveRow, aboveRef, bs);
+ MemoryUtil.Fill(aboveRow + bs, aboveRow[bs - 1], bs);
+ }
+ }
+ else if (x0 + bs <= frameWidth)
+ {
+ int r = frameWidth - x0;
+ if (rightAvailable != 0 && bs == 4)
+ {
+ MemoryUtil.Copy(aboveRow, aboveRef, r);
+ MemoryUtil.Fill(aboveRow + r, aboveRow[r - 1], x0 + 2 * bs - frameWidth);
+ }
+ else
+ {
+ MemoryUtil.Copy(aboveRow, aboveRef, bs);
+ MemoryUtil.Fill(aboveRow + bs, aboveRow[bs - 1], bs);
+ }
+ }
+ else if (x0 <= frameWidth)
+ {
+ int r = frameWidth - x0;
+ MemoryUtil.Copy(aboveRow, aboveRef, r);
+ MemoryUtil.Fill(aboveRow + r, aboveRow[r - 1], x0 + 2 * bs - frameWidth);
+ }
+ }
+ else
+ {
+ /* Faster path if the block does not need extension */
+ if (bs == 4 && rightAvailable != 0 && leftAvailable != 0)
+ {
+ constAboveRow = aboveRef;
+ }
+ else
+ {
+ MemoryUtil.Copy(aboveRow, aboveRef, bs);
+ if (bs == 4 && rightAvailable != 0)
+ {
+ MemoryUtil.Copy(aboveRow + bs, aboveRef + bs, bs);
+ }
+ else
+ {
+ MemoryUtil.Fill(aboveRow + bs, aboveRow[bs - 1], bs);
+ }
+ }
+ }
+ aboveRow[-1] = leftAvailable != 0 ? aboveRef[-1] : (byte)129;
+ }
+ else
+ {
+ MemoryUtil.Fill(aboveRow, (byte)127, bs * 2);
+ aboveRow[-1] = 127;
+ }
+ }
+
+ // Predict
+ if (mode == PredictionMode.DcPred)
+ {
+ _dcPred[leftAvailable][upAvailable][(int)txSize](dst, dstStride, constAboveRow, leftCol);
+ }
+ else
+ {
+ _pred[(int)mode][(int)txSize](dst, dstStride, constAboveRow, leftCol);
+ }
+ }
+
+ public static unsafe void PredictIntraBlock(
+ ref MacroBlockD xd,
+ int bwlIn,
+ TxSize txSize,
+ PredictionMode mode,
+ byte* refr,
+ int refStride,
+ byte* dst,
+ int dstStride,
+ int aoff,
+ int loff,
+ int plane)
+ {
+ int bw = 1 << bwlIn;
+ int txw = 1 << (int)txSize;
+ int haveTop = loff != 0 || !xd.AboveMi.IsNull ? 1 : 0;
+ int haveLeft = aoff != 0 || !xd.LeftMi.IsNull ? 1 : 0;
+ int haveRight = (aoff + txw) < bw ? 1 : 0;
+ int x = aoff * 4;
+ int y = loff * 4;
+
+ if (xd.CurBuf.HighBd)
+ {
+ BuildIntraPredictorsHigh(
+ ref xd,
+ refr,
+ refStride,
+ dst,
+ dstStride,
+ mode,
+ txSize,
+ haveTop,
+ haveLeft,
+ haveRight,
+ x,
+ y,
+ plane);
+ return;
+ }
+ BuildIntraPredictors(
+ ref xd,
+ refr,
+ refStride,
+ dst,
+ dstStride,
+ mode,
+ txSize,
+ haveTop,
+ haveLeft,
+ haveRight,
+ x,
+ y,
+ plane);
+ }
+ }
+}