diff options
Diffstat (limited to 'Ryujinx.Graphics.Nvdec.Vp9/ReconIntra.cs')
-rw-r--r-- | Ryujinx.Graphics.Nvdec.Vp9/ReconIntra.cs | 761 |
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); + } + } +} |