Implement VP9 loop filtering

This commit is contained in:
gdk 2023-02-04 19:44:30 -03:00 committed by TSR Berry
parent a73a5d7e85
commit 34a583e045
No known key found for this signature in database
GPG key ID: 52353C0A4CCA15E2
79 changed files with 10926 additions and 2595 deletions

View file

@ -2,8 +2,13 @@
{ {
internal enum BitDepth internal enum BitDepth
{ {
Bits8 = 8, /**< 8 bits */ // 8 bits
Bits10 = 10, /**< 10 bits */ Bits8 = 8,
Bits12 = 12, /**< 12 bits */
// 10 bits
Bits10 = 10,
// 12 bits
Bits12 = 12
} }
} }

View file

@ -3,26 +3,26 @@
internal enum CodecErr internal enum CodecErr
{ {
/*!\brief Operation completed without error */ /*!\brief Operation completed without error */
CodecOk, Ok,
/*!\brief Unspecified error */ /*!\brief Unspecified error */
CodecError, Error,
/*!\brief Memory operation failed */ /*!\brief Memory operation failed */
CodecMemError, MemError,
/*!\brief ABI version mismatch */ /*!\brief ABI version mismatch */
CodecAbiMismatch, AbiMismatch,
/*!\brief Algorithm does not have required capability */ /*!\brief Algorithm does not have required capability */
CodecIncapable, Incapable,
/*!\brief The given bitstream is not supported. /*!\brief The given bitstream is not supported.
* *
* The bitstream was unable to be parsed at the highest level. The decoder * The bitstream was unable to be parsed at the highest level. The decoder
* is unable to proceed. This error \ref SHOULD be treated as fatal to the * is unable to proceed. This error \ref SHOULD be treated as fatal to the
* stream. */ * stream. */
CodecUnsupBitstream, UnsupBitstream,
/*!\brief Encoded bitstream uses an unsupported feature /*!\brief Encoded bitstream uses an unsupported feature
* *
@ -31,7 +31,7 @@
* pictures from being properly decoded. This error \ref MAY be treated as * pictures from being properly decoded. This error \ref MAY be treated as
* fatal to the stream or \ref MAY be treated as fatal to the current GOP. * fatal to the stream or \ref MAY be treated as fatal to the current GOP.
*/ */
CodecUnsupFeature, UnsupFeature,
/*!\brief The coded data for this stream is corrupt or incomplete /*!\brief The coded data for this stream is corrupt or incomplete
* *
@ -41,16 +41,16 @@
* stream or \ref MAY be treated as fatal to the current GOP. If decoding * stream or \ref MAY be treated as fatal to the current GOP. If decoding
* is continued for the current GOP, artifacts may be present. * is continued for the current GOP, artifacts may be present.
*/ */
CodecCorruptFrame, CorruptFrame,
/*!\brief An application-supplied parameter is not valid. /*!\brief An application-supplied parameter is not valid.
* *
*/ */
CodecInvalidParam, InvalidParam,
/*!\brief An iterator reached the end of list. /*!\brief An iterator reached the end of list.
* *
*/ */
CodecListEnd ListEnd
} }
} }

View file

@ -10,7 +10,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Common
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static byte ClipPixel(int val) public static byte ClipPixel(int val)
{ {
return (byte)((val > 255) ? 255 : (val < 0) ? 0 : val); return (byte)(val > 255 ? 255 : val < 0 ? 0 : val);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]

View file

@ -16,7 +16,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Common
public bool InUse; public bool InUse;
} }
private PoolItem[] _pool = new PoolItem[PoolEntries]; private readonly PoolItem[] _pool = new PoolItem[PoolEntries];
public ArrayPtr<T> Allocate<T>(int length) where T : unmanaged public ArrayPtr<T> Allocate<T>(int length) where T : unmanaged
{ {
@ -51,6 +51,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Common
{ {
Marshal.FreeHGlobal(item.Pointer); Marshal.FreeHGlobal(item.Pointer);
} }
item.Pointer = ptr; item.Pointer = ptr;
item.Length = lengthInBytes; item.Length = lengthInBytes;
break; break;
@ -58,7 +59,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Common
} }
} }
return new ArrayPtr<T>(ptr, length); ArrayPtr<T> allocation = new ArrayPtr<T>(ptr, length);
allocation.AsSpan().Fill(default);
return allocation;
} }
public unsafe void Free<T>(ArrayPtr<T> arr) where T : unmanaged public unsafe void Free<T>(ArrayPtr<T> arr) where T : unmanaged

View file

@ -1,8 +1,10 @@
namespace Ryujinx.Graphics.Nvdec.Vp9 using Ryujinx.Graphics.Nvdec.Vp9.Types;
namespace Ryujinx.Graphics.Nvdec.Vp9
{ {
internal static class Constants internal static class Constants
{ {
public const int Vp9InterpExtend = 4; public const int InterpExtend = 4;
public const int MaxMbPlane = 3; public const int MaxMbPlane = 3;
@ -25,6 +27,7 @@
/* Segment Feature Masks */ /* Segment Feature Masks */
public const int MaxMvRefCandidates = 2; public const int MaxMvRefCandidates = 2;
public const int IntraInterContexts = 4;
public const int CompInterContexts = 5; public const int CompInterContexts = 5;
public const int RefContexts = 5; public const int RefContexts = 5;
@ -32,12 +35,26 @@
public const int EightTapSmooth = 1; public const int EightTapSmooth = 1;
public const int EightTapSharp = 2; public const int EightTapSharp = 2;
public const int SwitchableFilters = 3; /* Number of switchable filters */ public const int SwitchableFilters = 3; /* Number of switchable filters */
public const int Bilinear = 3; public const int Bilinear = 3;
public const int Switchable = 4; /* should be the last one */
// The codec can operate in four possible inter prediction filter mode:
// 8-tap, 8-tap-smooth, 8-tap-sharp, and switching between the three.
public const int SwitchableFilterContexts = SwitchableFilters + 1;
public const int Switchable = 4; /* Should be the last one */
// Frame // Frame
public const int RefsPerFrame = 3; public const int RefsPerFrame = 3;
public const int RefFramesLog2 = 3;
public const int RefFrames = 1 << RefFramesLog2;
// 1 scratch frame for the new frame, 3 for scaled references on the encoder.
public const int FrameBuffers = RefFrames + 4;
public const int FrameContextsLog2 = 2;
public const int FrameContexts = 1 << FrameContextsLog2;
public const int NumPingPongBuffers = 2; public const int NumPingPongBuffers = 2;
public const int Class0Bits = 1; /* bits at integer precision for class 0 */ public const int Class0Bits = 1; /* bits at integer precision for class 0 */
@ -65,5 +82,19 @@
public const int SegmentAbsData = 1; public const int SegmentAbsData = 1;
public const int MaxSegments = 8; public const int MaxSegments = 8;
public const int PartitionTypes = (int)PartitionType.PartitionTypes;
public const int PartitionPlOffset = 4; // Number of probability models per block size
public const int PartitionContexts = 4 * PartitionPlOffset;
public const int PlaneTypes = (int)PlaneType.PlaneTypes;
public const int IntraModes = (int)PredictionMode.TmPred + 1;
public const int InterModes = 1 + (int)PredictionMode.NewMv - (int)PredictionMode.NearestMv;
public const int SkipContexts = 3;
public const int InterModeContexts = 7;
} }
} }

View file

@ -0,0 +1,47 @@
using System.Diagnostics;
namespace Ryujinx.Graphics.Nvdec.Vp9
{
internal static class DSubExp
{
public static int InvRecenterNonneg(int v, int m)
{
if (v > 2 * m)
{
return v;
}
return (v & 1) != 0 ? m - ((v + 1) >> 1) : m + (v >> 1);
}
private static readonly byte[] InvMapTable =
{
7, 20, 33, 46, 59, 72, 85, 98, 111, 124, 137, 150, 163, 176, 189, 202, 215, 228, 241, 254, 1, 2, 3, 4,
5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34,
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 60, 61, 62,
63, 64, 65, 66, 67, 68, 69, 70, 71, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 86, 87, 88, 89, 90,
91, 92, 93, 94, 95, 96, 97, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 112, 113, 114,
115, 116, 117, 118, 119, 120, 121, 122, 123, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136,
138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 151, 152, 153, 154, 155, 156, 157, 158, 159,
160, 161, 162, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
183, 184, 185, 186, 187, 188, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 203, 204, 205,
206, 207, 208, 209, 210, 211, 212, 213, 214, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227,
229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 242, 243, 244, 245, 246, 247, 248, 249, 250,
251, 252, 253, 253
};
public static int InvRemapProb(int v, int m)
{
Debug.Assert(v < InvMapTable.Length / sizeof(byte));
v = InvMapTable[v];
m--;
if (m << 1 <= Prob.MaxProb)
{
return 1 + InvRecenterNonneg(v, m);
}
return Prob.MaxProb - InvRecenterNonneg(v, Prob.MaxProb - 1 - m);
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -5,18 +5,16 @@ using Ryujinx.Graphics.Video;
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using Mv = Ryujinx.Graphics.Nvdec.Vp9.Types.Mv;
using MvRef = Ryujinx.Graphics.Nvdec.Vp9.Types.MvRef;
namespace Ryujinx.Graphics.Nvdec.Vp9 namespace Ryujinx.Graphics.Nvdec.Vp9
{ {
internal static class DecodeMv internal static class DecodeMv
{ {
private const int MvrefNeighbours = 8; private const int RefNeighbours = 8;
private static PredictionMode ReadIntraMode(ref Reader r, ReadOnlySpan<byte> p) private static PredictionMode ReadIntraMode(ref Reader r, ReadOnlySpan<byte> p)
{ {
return (PredictionMode)r.ReadTree(Luts.Vp9IntraModeTree, p); return (PredictionMode)r.ReadTree(Luts.IntraModeTree, p);
} }
private static PredictionMode ReadIntraModeY(ref Vp9Common cm, ref MacroBlockD xd, ref Reader r, int sizeGroup) private static PredictionMode ReadIntraModeY(ref Vp9Common cm, ref MacroBlockD xd, ref Reader r, int sizeGroup)
@ -43,7 +41,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
private static PredictionMode ReadInterMode(ref Vp9Common cm, ref MacroBlockD xd, ref Reader r, int ctx) private static PredictionMode ReadInterMode(ref Vp9Common cm, ref MacroBlockD xd, ref Reader r, int ctx)
{ {
int mode = r.ReadTree(Luts.Vp9InterModeTree, cm.Fc.Value.InterModeProb[ctx].AsSpan()); int mode = r.ReadTree(Luts.InterModeTree, cm.Fc.Value.InterModeProb[ctx].AsSpan());
if (!xd.Counts.IsNull) if (!xd.Counts.IsNull)
{ {
++xd.Counts.Value.InterMode[ctx][mode]; ++xd.Counts.Value.InterMode[ctx][mode];
@ -54,7 +52,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
private static int ReadSegmentId(ref Reader r, ref Array7<byte> segTreeProbs) private static int ReadSegmentId(ref Reader r, ref Array7<byte> segTreeProbs)
{ {
return r.ReadTree(Luts.Vp9SegmentTree, segTreeProbs.AsSpan()); return r.ReadTree(Luts.SegmentTree, segTreeProbs.AsSpan());
} }
private static ReadOnlySpan<byte> GetTxProbs(ref Vp9EntropyProbs fc, TxSize maxTxSize, int ctx) private static ReadOnlySpan<byte> GetTxProbs(ref Vp9EntropyProbs fc, TxSize maxTxSize, int ctx)
@ -64,7 +62,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
case TxSize.Tx8x8: return fc.Tx8x8Prob[ctx].AsSpan(); case TxSize.Tx8x8: return fc.Tx8x8Prob[ctx].AsSpan();
case TxSize.Tx16x16: return fc.Tx16x16Prob[ctx].AsSpan(); case TxSize.Tx16x16: return fc.Tx16x16Prob[ctx].AsSpan();
case TxSize.Tx32x32: return fc.Tx32x32Prob[ctx].AsSpan(); case TxSize.Tx32x32: return fc.Tx32x32Prob[ctx].AsSpan();
default: Debug.Assert(false, "Invalid maxTxSize."); return ReadOnlySpan<byte>.Empty; default:
Debug.Assert(false, "Invalid maxTxSize.");
return ReadOnlySpan<byte>.Empty;
} }
} }
@ -75,7 +75,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
case TxSize.Tx8x8: return counts.Tx8x8[ctx].AsSpan(); case TxSize.Tx8x8: return counts.Tx8x8[ctx].AsSpan();
case TxSize.Tx16x16: return counts.Tx16x16[ctx].AsSpan(); case TxSize.Tx16x16: return counts.Tx16x16[ctx].AsSpan();
case TxSize.Tx32x32: return counts.Tx32x32[ctx].AsSpan(); case TxSize.Tx32x32: return counts.Tx32x32[ctx].AsSpan();
default: Debug.Assert(false, "Invalid maxTxSize."); return Span<uint>.Empty; default:
Debug.Assert(false, "Invalid maxTxSize.");
return Span<uint>.Empty;
} }
} }
@ -110,21 +112,20 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
{ {
return ReadSelectedTxSize(ref cm, ref xd, maxTxSize, ref r); return ReadSelectedTxSize(ref cm, ref xd, maxTxSize, ref r);
} }
else
{
return (TxSize)Math.Min((int)maxTxSize, (int)Luts.TxModeToBiggestTxSize[(int)txMode]); return (TxSize)Math.Min((int)maxTxSize, (int)Luts.TxModeToBiggestTxSize[(int)txMode]);
} }
}
private static int DecGetSegmentId(ref Vp9Common cm, ArrayPtr<byte> segmentIds, int miOffset, int xMis, int yMis) private static int DecGetSegmentId(ref Vp9Common cm, ArrayPtr<byte> segmentIds, int miOffset, int xMis,
int yMis)
{ {
int x, y, segmentId = int.MaxValue; int segmentId = int.MaxValue;
for (y = 0; y < yMis; y++) for (int y = 0; y < yMis; y++)
{ {
for (x = 0; x < xMis; x++) for (int x = 0; x < xMis; x++)
{ {
segmentId = Math.Min(segmentId, segmentIds[miOffset + y * cm.MiCols + x]); segmentId = Math.Min(segmentId, segmentIds[miOffset + (y * cm.MiCols) + x]);
} }
} }
@ -134,15 +135,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
private static void SetSegmentId(ref Vp9Common cm, int miOffset, int xMis, int yMis, int segmentId) private static void SetSegmentId(ref Vp9Common cm, int miOffset, int xMis, int yMis, int segmentId)
{ {
int x, y;
Debug.Assert(segmentId >= 0 && segmentId < Constants.MaxSegments); Debug.Assert(segmentId >= 0 && segmentId < Constants.MaxSegments);
for (y = 0; y < yMis; y++) for (int y = 0; y < yMis; y++)
{ {
for (x = 0; x < xMis; x++) for (int x = 0; x < xMis; x++)
{ {
cm.CurrentFrameSegMap[miOffset + y * cm.MiCols + x] = (byte)segmentId; cm.CurrentFrameSegMap[miOffset + (y * cm.MiCols) + x] = (byte)segmentId;
} }
} }
} }
@ -155,13 +154,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
int xMis, int xMis,
int yMis) int yMis)
{ {
int x, y; for (int y = 0; y < yMis; y++)
for (y = 0; y < yMis; y++)
{ {
for (x = 0; x < xMis; x++) for (int x = 0; x < xMis; x++)
{ {
currentSegmentIds[miOffset + y * cm.MiCols + x] = (byte)(!lastSegmentIds.IsNull ? lastSegmentIds[miOffset + y * cm.MiCols + x] : 0); currentSegmentIds[miOffset + (y * cm.MiCols) + x] = (byte)(!lastSegmentIds.IsNull
? lastSegmentIds[miOffset + (y * cm.MiCols) + x]
: 0);
} }
} }
} }
@ -199,7 +198,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
ref Segmentation seg = ref cm.Seg; ref Segmentation seg = ref cm.Seg;
ref ModeInfo mi = ref xd.Mi[0].Value; ref ModeInfo mi = ref xd.Mi[0].Value;
int predictedSegmentId, segmentId; int predictedSegmentId, segmentId;
int miOffset = miRow * cm.MiCols + miCol; int miOffset = (miRow * cm.MiCols) + miCol;
if (!seg.Enabled) if (!seg.Enabled)
{ {
@ -220,24 +219,26 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
{ {
byte predProb = Segmentation.GetPredProbSegId(ref cm.Fc.Value.SegPredProb, ref xd); byte predProb = Segmentation.GetPredProbSegId(ref cm.Fc.Value.SegPredProb, ref xd);
mi.SegIdPredicted = (sbyte)r.Read(predProb); mi.SegIdPredicted = (sbyte)r.Read(predProb);
segmentId = mi.SegIdPredicted != 0 ? predictedSegmentId : ReadSegmentId(ref r, ref cm.Fc.Value.SegTreeProb); segmentId = mi.SegIdPredicted != 0
? predictedSegmentId
: ReadSegmentId(ref r, ref cm.Fc.Value.SegTreeProb);
} }
else else
{ {
segmentId = ReadSegmentId(ref r, ref cm.Fc.Value.SegTreeProb); segmentId = ReadSegmentId(ref r, ref cm.Fc.Value.SegTreeProb);
} }
SetSegmentId(ref cm, miOffset, xMis, yMis, segmentId); SetSegmentId(ref cm, miOffset, xMis, yMis, segmentId);
return segmentId; return segmentId;
} }
private static int ReadSkip(ref Vp9Common cm, ref MacroBlockD xd, int segmentId, ref Reader r) private static int ReadSkip(ref Vp9Common cm, ref MacroBlockD xd, int segmentId, ref Reader r)
{ {
if (cm.Seg.IsSegFeatureActive(segmentId, SegLvlFeatures.SegLvlSkip) != 0) if (cm.Seg.IsSegFeatureActive(segmentId, SegLvlFeatures.Skip) != 0)
{ {
return 1; return 1;
} }
else
{
int ctx = xd.GetSkipContext(); int ctx = xd.GetSkipContext();
int skip = r.Read(cm.Fc.Value.SkipProb[ctx]); int skip = r.Read(cm.Fc.Value.SkipProb[ctx]);
if (!xd.Counts.IsNull) if (!xd.Counts.IsNull)
@ -247,14 +248,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
return skip; return skip;
} }
}
private static int ReadMvComponent(ref Reader r, ref Vp9EntropyProbs fc, int mvcomp, bool usehp) private static int ReadComponent(ref Reader r, ref Vp9EntropyProbs fc, int mvcomp, bool usehp)
{ {
int mag, d, fr, hp; int mag, d, fr, hp;
bool sign = r.Read(fc.Sign[mvcomp]) != 0; bool sign = r.Read(fc.Sign[mvcomp]) != 0;
MvClassType mvClass = (MvClassType)r.ReadTree(Luts.Vp9MvClassTree, fc.Classes[mvcomp].AsSpan()); MvClassType mvClass = (MvClassType)r.ReadTree(Luts.MvClassTree, fc.Classes[mvcomp].AsSpan());
bool class0 = mvClass == MvClassType.MvClass0; bool class0 = mvClass == MvClassType.Class0;
// Integer part // Integer part
if (class0) if (class0)
@ -264,11 +264,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
} }
else else
{ {
int i;
int n = (int)mvClass + Constants.Class0Bits - 1; // Number of bits int n = (int)mvClass + Constants.Class0Bits - 1; // Number of bits
d = 0; d = 0;
for (i = 0; i < n; ++i) for (int i = 0; i < n; ++i)
{ {
d |= r.Read(fc.Bits[mvcomp][i]) << i; d |= r.Read(fc.Bits[mvcomp][i]) << i;
} }
@ -277,7 +276,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
} }
// Fractional part // Fractional part
fr = r.ReadTree(Luts.Vp9MvFPTree, class0 ? fc.Class0Fp[mvcomp][d].AsSpan() : fc.Fp[mvcomp].AsSpan()); fr = r.ReadTree(Luts.MvFPTree, class0 ? fc.Class0Fp[mvcomp][d].AsSpan() : fc.Fp[mvcomp].AsSpan());
// High precision part (if hp is not used, the default value of the hp is 1) // High precision part (if hp is not used, the default value of the hp is 1)
hp = usehp ? r.Read(class0 ? fc.Class0Hp[mvcomp] : fc.Hp[mvcomp]) : 1; hp = usehp ? r.Read(class0 ? fc.Class0Hp[mvcomp] : fc.Hp[mvcomp]) : 1;
@ -287,29 +286,29 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
return sign ? -mag : mag; return sign ? -mag : mag;
} }
private static void ReadMv( private static void Read(
ref Reader r, ref Reader r,
ref Mv mv, ref Mv mv,
ref Mv refr, ref Mv refr,
ref Vp9EntropyProbs fc, ref Vp9EntropyProbs fc,
Ptr<Vp9BackwardUpdates> counts, Ptr<Vp9BackwardUpdates> counts,
bool allowHP) bool allowHp)
{ {
MvJointType jointType = (MvJointType)r.ReadTree(Luts.Vp9MvJointTree, fc.Joints.AsSpan()); MvJointType jointType = (MvJointType)r.ReadTree(Luts.MvJointTree, fc.Joints.AsSpan());
bool useHP = allowHP && refr.UseMvHp(); bool useHp = allowHp && refr.UseHp();
Mv diff = new Mv(); Mv diff = new();
if (Mv.MvJointVertical(jointType)) if (Mv.JointVertical(jointType))
{ {
diff.Row = (short)ReadMvComponent(ref r, ref fc, 0, useHP); diff.Row = (short)ReadComponent(ref r, ref fc, 0, useHp);
} }
if (Mv.MvJointHorizontal(jointType)) if (Mv.JointHorizontal(jointType))
{ {
diff.Col = (short)ReadMvComponent(ref r, ref fc, 1, useHP); diff.Col = (short)ReadComponent(ref r, ref fc, 1, useHp);
} }
diff.IncMv(counts); diff.Inc(counts);
mv.Row = (short)(refr.Row + diff.Row); mv.Row = (short)(refr.Row + diff.Row);
mv.Col = (short)(refr.Col + diff.Col); mv.Col = (short)(refr.Col + diff.Col);
@ -317,7 +316,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
private static ReferenceMode ReadBlockReferenceMode(ref Vp9Common cm, ref MacroBlockD xd, ref Reader r) private static ReferenceMode ReadBlockReferenceMode(ref Vp9Common cm, ref MacroBlockD xd, ref Reader r)
{ {
if (cm.ReferenceMode == ReferenceMode.ReferenceModeSelect) if (cm.ReferenceMode == ReferenceMode.Select)
{ {
int ctx = PredCommon.GetReferenceModeContext(ref cm, ref xd); int ctx = PredCommon.GetReferenceModeContext(ref cm, ref xd);
ReferenceMode mode = (ReferenceMode)r.Read(cm.Fc.Value.CompInterProb[ctx]); ReferenceMode mode = (ReferenceMode)r.Read(cm.Fc.Value.CompInterProb[ctx]);
@ -328,11 +327,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
return mode; // SingleReference or CompoundReference return mode; // SingleReference or CompoundReference
} }
else
{
return cm.ReferenceMode; return cm.ReferenceMode;
} }
}
// Read the referncence frame // Read the referncence frame
private static void ReadRefFrames( private static void ReadRefFrames(
@ -344,15 +341,15 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
{ {
ref Vp9EntropyProbs fc = ref cm.Fc.Value; ref Vp9EntropyProbs fc = ref cm.Fc.Value;
if (cm.Seg.IsSegFeatureActive(segmentId, SegLvlFeatures.SegLvlRefFrame) != 0) if (cm.Seg.IsSegFeatureActive(segmentId, SegLvlFeatures.RefFrame) != 0)
{ {
refFrame[0] = (sbyte)cm.Seg.GetSegData(segmentId, SegLvlFeatures.SegLvlRefFrame); refFrame[0] = (sbyte)cm.Seg.GetSegData(segmentId, SegLvlFeatures.RefFrame);
refFrame[1] = Constants.None; refFrame[1] = Constants.None;
} }
else else
{ {
ReferenceMode mode = ReadBlockReferenceMode(ref cm, ref xd, ref r); ReferenceMode mode = ReadBlockReferenceMode(ref cm, ref xd, ref r);
if (mode == ReferenceMode.CompoundReference) if (mode == ReferenceMode.Compound)
{ {
int idx = cm.RefFrameSignBias[cm.CompFixedRef]; int idx = cm.RefFrameSignBias[cm.CompFixedRef];
int ctx = PredCommon.GetPredContextCompRefP(ref cm, ref xd); int ctx = PredCommon.GetPredContextCompRefP(ref cm, ref xd);
@ -365,7 +362,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
refFrame[idx] = cm.CompFixedRef; refFrame[idx] = cm.CompFixedRef;
refFrame[idx == 0 ? 1 : 0] = cm.CompVarRef[bit]; refFrame[idx == 0 ? 1 : 0] = cm.CompVarRef[bit];
} }
else if (mode == ReferenceMode.SingleReference) else if (mode == ReferenceMode.Single)
{ {
int ctx0 = PredCommon.GetPredContextSingleRefP1(ref xd); int ctx0 = PredCommon.GetPredContextSingleRefP1(ref xd);
int bit0 = r.Read(fc.SingleRefProb[ctx0][0]); int bit0 = r.Read(fc.SingleRefProb[ctx0][0]);
@ -402,7 +399,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
private static byte ReadSwitchableInterpFilter(ref Vp9Common cm, ref MacroBlockD xd, ref Reader r) private static byte ReadSwitchableInterpFilter(ref Vp9Common cm, ref MacroBlockD xd, ref Reader r)
{ {
int ctx = xd.GetPredContextSwitchableInterp(); int ctx = xd.GetPredContextSwitchableInterp();
byte type = (byte)r.ReadTree(Luts.Vp9SwitchableInterpTree, cm.Fc.Value.SwitchableInterpProb[ctx].AsSpan()); byte type = (byte)r.ReadTree(Luts.SwitchableInterpTree, cm.Fc.Value.SwitchableInterpProb[ctx].AsSpan());
if (!xd.Counts.IsNull) if (!xd.Counts.IsNull)
{ {
++xd.Counts.Value.SwitchableInterp[ctx][type]; ++xd.Counts.Value.SwitchableInterp[ctx][type];
@ -414,12 +411,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
private static void ReadIntraBlockModeInfo(ref Vp9Common cm, ref MacroBlockD xd, ref ModeInfo mi, ref Reader r) private static void ReadIntraBlockModeInfo(ref Vp9Common cm, ref MacroBlockD xd, ref ModeInfo mi, ref Reader r)
{ {
BlockSize bsize = mi.SbType; BlockSize bsize = mi.SbType;
int i;
switch (bsize) switch (bsize)
{ {
case BlockSize.Block4x4: case BlockSize.Block4x4:
for (i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i)
{ {
mi.Bmi[i].Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0); mi.Bmi[i].Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
} }
@ -434,7 +431,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
mi.Bmi[0].Mode = mi.Bmi[1].Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0); mi.Bmi[0].Mode = mi.Bmi[1].Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
mi.Bmi[2].Mode = mi.Bmi[3].Mode = mi.Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0); mi.Bmi[2].Mode = mi.Bmi[3].Mode = mi.Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
break; break;
default: mi.Mode = ReadIntraModeY(ref cm, ref xd, ref r, Luts.SizeGroupLookup[(int)bsize]); break; default:
mi.Mode = ReadIntraModeY(ref cm, ref xd, ref r, Luts.SizeGroupLookup[(int)bsize]);
break;
} }
mi.UvMode = ReadIntraModeUv(ref cm, ref xd, ref r, (byte)mi.Mode); mi.UvMode = ReadIntraModeUv(ref cm, ref xd, ref r, (byte)mi.Mode);
@ -447,27 +446,19 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
mi.RefFrame[1] = Constants.None; mi.RefFrame[1] = Constants.None;
} }
private static bool IsMvValid(ref Mv mv) private static void CopyPair(ref Array2<Mv> dst, ref Array2<Mv> src)
{
return mv.Row > Constants.MvLow &&
mv.Row < Constants.MvUpp &&
mv.Col > Constants.MvLow &&
mv.Col < Constants.MvUpp;
}
private static void CopyMvPair(ref Array2<Mv> dst, ref Array2<Mv> src)
{ {
dst[0] = src[0]; dst[0] = src[0];
dst[1] = src[1]; dst[1] = src[1];
} }
private static void ZeroMvPair(ref Array2<Mv> dst) private static void ZeroPair(ref Array2<Mv> dst)
{ {
dst[0] = new Mv(); dst[0] = new Mv();
dst[1] = new Mv(); dst[1] = new Mv();
} }
private static bool AssignMv( private static bool Assign(
ref Vp9Common cm, ref Vp9Common cm,
ref MacroBlockD xd, ref MacroBlockD xd,
PredictionMode mode, PredictionMode mode,
@ -475,47 +466,47 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
ref Array2<Mv> refMv, ref Array2<Mv> refMv,
ref Array2<Mv> nearNearestMv, ref Array2<Mv> nearNearestMv,
int isCompound, int isCompound,
bool allowHP, bool allowHp,
ref Reader r) ref Reader r)
{ {
int i;
bool ret = true; bool ret = true;
switch (mode) switch (mode)
{ {
case PredictionMode.NewMv: case PredictionMode.NewMv:
{ {
for (i = 0; i < 1 + isCompound; ++i) for (int i = 0; i < 1 + isCompound; ++i)
{ {
ReadMv(ref r, ref mv[i], ref refMv[i], ref cm.Fc.Value, xd.Counts, allowHP); Read(ref r, ref mv[i], ref refMv[i], ref cm.Fc.Value, xd.Counts, allowHp);
ret = ret && IsMvValid(ref mv[i]); ret = ret && mv[i].IsValid();
} }
break; break;
} }
case PredictionMode.NearMv: case PredictionMode.NearMv:
case PredictionMode.NearestMv: case PredictionMode.NearestMv:
{ {
CopyMvPair(ref mv, ref nearNearestMv); CopyPair(ref mv, ref nearNearestMv);
break; break;
} }
case PredictionMode.ZeroMv: case PredictionMode.ZeroMv:
{ {
ZeroMvPair(ref mv); ZeroPair(ref mv);
break; break;
} }
default: return false; default: return false;
} }
return ret; return ret;
} }
private static bool ReadIsInterBlock(ref Vp9Common cm, ref MacroBlockD xd, int segmentId, ref Reader r) private static bool ReadIsInterBlock(ref Vp9Common cm, ref MacroBlockD xd, int segmentId, ref Reader r)
{ {
if (cm.Seg.IsSegFeatureActive(segmentId, SegLvlFeatures.SegLvlRefFrame) != 0) if (cm.Seg.IsSegFeatureActive(segmentId, SegLvlFeatures.RefFrame) != 0)
{ {
return cm.Seg.GetSegData(segmentId, SegLvlFeatures.SegLvlRefFrame) != Constants.IntraFrame; return cm.Seg.GetSegData(segmentId, SegLvlFeatures.RefFrame) != Constants.IntraFrame;
} }
else
{
int ctx = xd.GetIntraInterContext(); int ctx = xd.GetIntraInterContext();
bool isInter = r.Read(cm.Fc.Value.IntraInterProb[ctx]) != 0; bool isInter = r.Read(cm.Fc.Value.IntraInterProb[ctx]) != 0;
if (!xd.Counts.IsNull) if (!xd.Counts.IsNull)
@ -525,34 +516,31 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
return isInter; return isInter;
} }
}
private static void DecFindBestRefMvs(bool allowHP, Span<Mv> mvlist, ref Mv bestMv, int refmvCount) private static void DecFindBestRefs(bool allowHp, Span<Mv> mvlist, ref Mv bestMv, int refmvCount)
{ {
int i;
// Make sure all the candidates are properly clamped etc // Make sure all the candidates are properly clamped etc
for (i = 0; i < refmvCount; ++i) for (int i = 0; i < refmvCount; ++i)
{ {
mvlist[i].LowerMvPrecision(allowHP); mvlist[i].LowerPrecision(allowHp);
bestMv = mvlist[i]; bestMv = mvlist[i];
} }
} }
private static bool AddMvRefListEb(Mv mv, ref int refMvCount, Span<Mv> mvRefList, bool earlyBreak) private static bool AddRefListEb(Mv mv, ref int refCount, Span<Mv> mvRefList, bool earlyBreak)
{ {
if (refMvCount != 0) if (refCount != 0)
{ {
if (Unsafe.As<Mv, int>(ref mv) != Unsafe.As<Mv, int>(ref mvRefList[0])) if (Unsafe.As<Mv, int>(ref mv) != Unsafe.As<Mv, int>(ref mvRefList[0]))
{ {
mvRefList[refMvCount] = mv; mvRefList[refCount] = mv;
refMvCount++; refCount++;
return true; return true;
} }
} }
else else
{ {
mvRefList[refMvCount++] = mv; mvRefList[refCount++] = mv;
if (earlyBreak) if (earlyBreak)
{ {
return true; return true;
@ -562,19 +550,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
return false; return false;
} }
// Performs mv sign inversion if indicated by the reference frame combination. private static bool IsDiffRefFrameAddEb(
private static Mv ScaleMv(ref ModeInfo mi, int refr, sbyte thisRefFrame, ref Array4<sbyte> refSignBias)
{
Mv mv = mi.Mv[refr];
if (refSignBias[mi.RefFrame[refr]] != refSignBias[thisRefFrame])
{
mv.Row *= -1;
mv.Col *= -1;
}
return mv;
}
private static bool IsDiffRefFrameAddMvEb(
ref ModeInfo mbmi, ref ModeInfo mbmi,
sbyte refFrame, sbyte refFrame,
ref Array4<sbyte> refSignBias, ref Array4<sbyte> refSignBias,
@ -586,26 +562,30 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
{ {
if (mbmi.RefFrame[0] != refFrame) if (mbmi.RefFrame[0] != refFrame)
{ {
if (AddMvRefListEb(ScaleMv(ref mbmi, 0, refFrame, ref refSignBias), ref refmvCount, mvRefList, earlyBreak)) if (AddRefListEb(mbmi.ScaleMv(0, refFrame, ref refSignBias), ref refmvCount, mvRefList,
{ earlyBreak))
return true;
}
}
if (mbmi.HasSecondRef() && mbmi.RefFrame[1] != refFrame && Unsafe.As<Mv, int>(ref mbmi.Mv[1]) != Unsafe.As<Mv, int>(ref mbmi.Mv[0]))
{
if (AddMvRefListEb(ScaleMv(ref mbmi, 1, refFrame, ref refSignBias), ref refmvCount, mvRefList, earlyBreak))
{ {
return true; return true;
} }
} }
if (mbmi.HasSecondRef() && mbmi.RefFrame[1] != refFrame &&
Unsafe.As<Mv, int>(ref mbmi.Mv[1]) != Unsafe.As<Mv, int>(ref mbmi.Mv[0]))
{
if (AddRefListEb(mbmi.ScaleMv(1, refFrame, ref refSignBias), ref refmvCount, mvRefList,
earlyBreak))
{
return true;
} }
}
}
return false; return false;
} }
// This function searches the neighborhood of a given MB/SB // This function searches the neighborhood of a given MB/SB
// to try and find candidate reference vectors. // to try and find candidate reference vectors.
private static unsafe int DecFindMvRefs( private static int DecFindRefs(
ref Vp9Common cm, ref Vp9Common cm,
ref MacroBlockD xd, ref MacroBlockD xd,
PredictionMode mode, PredictionMode mode,
@ -615,12 +595,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
int miRow, int miRow,
int miCol, int miCol,
int block, int block,
int isSub8X8) int isSub8x8)
{ {
ref Array4<sbyte> refSignBias = ref cm.RefFrameSignBias; ref Array4<sbyte> refSignBias = ref cm.RefFrameSignBias;
int i, refmvCount = 0; int i, refmvCount = 0;
bool differentRefFound = false; bool differentRefFound = false;
Ptr<MvRef> prevFrameMvs = cm.UsePrevFrameMvs ? new Ptr<MvRef>(ref cm.PrevFrameMvs[miRow * cm.MiCols + miCol]) : Ptr<MvRef>.Null; Ptr<MvRef> prevFrameMvs = cm.UsePrevFrameMvs
? new Ptr<MvRef>(ref cm.PrevFrameMvs[(miRow * cm.MiCols) + miCol])
: Ptr<MvRef>.Null;
ref TileInfo tile = ref xd.Tile; ref TileInfo tile = ref xd.Tile;
// If mode is nearestmv or newmv (uses nearestmv as a reference) then stop // If mode is nearestmv or newmv (uses nearestmv as a reference) then stop
// searching after the first mv is found. // searching after the first mv is found.
@ -630,7 +612,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
mvRefList.Slice(0, Constants.MaxMvRefCandidates).Fill(new Mv()); mvRefList.Slice(0, Constants.MaxMvRefCandidates).Fill(new Mv());
i = 0; i = 0;
if (isSub8X8 != 0) if (isSub8x8 != 0)
{ {
// If the size < 8x8 we get the mv from the bmi substructure for the // If the size < 8x8 we get the mv from the bmi substructure for the
// nearest two blocks. // nearest two blocks.
@ -639,19 +621,21 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
ref Position mvRef = ref mvRefSearch[i]; ref Position mvRef = ref mvRefSearch[i];
if (tile.IsInside(miCol, miRow, cm.MiRows, ref mvRef)) if (tile.IsInside(miCol, miRow, cm.MiRows, ref mvRef))
{ {
ref ModeInfo candidateMi = ref xd.Mi[mvRef.Col + mvRef.Row * xd.MiStride].Value; ref ModeInfo candidateMi = ref xd.Mi[mvRef.Col + (mvRef.Row * xd.MiStride)].Value;
differentRefFound = true; differentRefFound = true;
if (candidateMi.RefFrame[0] == refFrame) if (candidateMi.RefFrame[0] == refFrame)
{ {
if (AddMvRefListEb(candidateMi.GetSubBlockMv(0, mvRef.Col, block), ref refmvCount, mvRefList, earlyBreak)) if (AddRefListEb(candidateMi.GetSubBlockMv(0, mvRef.Col, block), ref refmvCount,
mvRefList, earlyBreak))
{ {
goto Done; goto Done;
} }
} }
else if (candidateMi.RefFrame[1] == refFrame) else if (candidateMi.RefFrame[1] == refFrame)
{ {
if (AddMvRefListEb(candidateMi.GetSubBlockMv(1, mvRef.Col, block), ref refmvCount, mvRefList, earlyBreak)) if (AddRefListEb(candidateMi.GetSubBlockMv(1, mvRef.Col, block), ref refmvCount,
mvRefList, earlyBreak))
{ {
goto Done; goto Done;
} }
@ -663,24 +647,24 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
// Check the rest of the neighbors in much the same way // Check the rest of the neighbors in much the same way
// as before except we don't need to keep track of sub blocks or // as before except we don't need to keep track of sub blocks or
// mode counts. // mode counts.
for (; i < MvrefNeighbours; ++i) for (; i < RefNeighbours; ++i)
{ {
ref Position mvRef = ref mvRefSearch[i]; ref Position mvRef = ref mvRefSearch[i];
if (tile.IsInside(miCol, miRow, cm.MiRows, ref mvRef)) if (tile.IsInside(miCol, miRow, cm.MiRows, ref mvRef))
{ {
ref ModeInfo candidate = ref xd.Mi[mvRef.Col + mvRef.Row * xd.MiStride].Value; ref ModeInfo candidate = ref xd.Mi[mvRef.Col + (mvRef.Row * xd.MiStride)].Value;
differentRefFound = true; differentRefFound = true;
if (candidate.RefFrame[0] == refFrame) if (candidate.RefFrame[0] == refFrame)
{ {
if (AddMvRefListEb(candidate.Mv[0], ref refmvCount, mvRefList, earlyBreak)) if (AddRefListEb(candidate.Mv[0], ref refmvCount, mvRefList, earlyBreak))
{ {
goto Done; goto Done;
} }
} }
else if (candidate.RefFrame[1] == refFrame) else if (candidate.RefFrame[1] == refFrame)
{ {
if (AddMvRefListEb(candidate.Mv[1], ref refmvCount, mvRefList, earlyBreak)) if (AddRefListEb(candidate.Mv[1], ref refmvCount, mvRefList, earlyBreak))
{ {
goto Done; goto Done;
} }
@ -693,14 +677,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
{ {
if (prevFrameMvs.Value.RefFrame[0] == refFrame) if (prevFrameMvs.Value.RefFrame[0] == refFrame)
{ {
if (AddMvRefListEb(prevFrameMvs.Value.Mv[0], ref refmvCount, mvRefList, earlyBreak)) if (AddRefListEb(prevFrameMvs.Value.Mv[0], ref refmvCount, mvRefList, earlyBreak))
{ {
goto Done; goto Done;
} }
} }
else if (prevFrameMvs.Value.RefFrame[1] == refFrame) else if (prevFrameMvs.Value.RefFrame[1] == refFrame)
{ {
if (AddMvRefListEb(prevFrameMvs.Value.Mv[1], ref refmvCount, mvRefList, earlyBreak)) if (AddRefListEb(prevFrameMvs.Value.Mv[1], ref refmvCount, mvRefList, earlyBreak))
{ {
goto Done; goto Done;
} }
@ -712,15 +696,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
// different reference frames. // different reference frames.
if (differentRefFound) if (differentRefFound)
{ {
for (i = 0; i < MvrefNeighbours; ++i) for (i = 0; i < RefNeighbours; ++i)
{ {
ref Position mvRef = ref mvRefSearch[i]; ref Position mvRef = ref mvRefSearch[i];
if (tile.IsInside(miCol, miRow, cm.MiRows, ref mvRef)) if (tile.IsInside(miCol, miRow, cm.MiRows, ref mvRef))
{ {
ref ModeInfo candidate = ref xd.Mi[mvRef.Col + mvRef.Row * xd.MiStride].Value; ref ModeInfo candidate = ref xd.Mi[mvRef.Col + (mvRef.Row * xd.MiStride)].Value;
// If the candidate is Intra we don't want to consider its mv. // If the candidate is Intra we don't want to consider its mv.
if (IsDiffRefFrameAddMvEb(ref candidate, refFrame, ref refSignBias, ref refmvCount, mvRefList, earlyBreak)) if (IsDiffRefFrameAddEb(ref candidate, refFrame, ref refSignBias, ref refmvCount, mvRefList,
earlyBreak))
{ {
goto Done; goto Done;
} }
@ -739,7 +724,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
mv.Row *= -1; mv.Row *= -1;
mv.Col *= -1; mv.Col *= -1;
} }
if (AddMvRefListEb(mv, ref refmvCount, mvRefList, earlyBreak))
if (AddRefListEb(mv, ref refmvCount, mvRefList, earlyBreak))
{ {
goto Done; goto Done;
} }
@ -747,7 +733,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
if (prevFrameMvs.Value.RefFrame[1] > Constants.IntraFrame && if (prevFrameMvs.Value.RefFrame[1] > Constants.IntraFrame &&
prevFrameMvs.Value.RefFrame[1] != refFrame && prevFrameMvs.Value.RefFrame[1] != refFrame &&
Unsafe.As<Mv, int>(ref prevFrameMvs.Value.Mv[1]) != Unsafe.As<Mv, int>(ref prevFrameMvs.Value.Mv[0])) Unsafe.As<Mv, int>(ref prevFrameMvs.Value.Mv[1]) !=
Unsafe.As<Mv, int>(ref prevFrameMvs.Value.Mv[0]))
{ {
Mv mv = prevFrameMvs.Value.Mv[1]; Mv mv = prevFrameMvs.Value.Mv[1];
if (refSignBias[prevFrameMvs.Value.RefFrame[1]] != refSignBias[refFrame]) if (refSignBias[prevFrameMvs.Value.RefFrame[1]] != refSignBias[refFrame])
@ -755,7 +742,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
mv.Row *= -1; mv.Row *= -1;
mv.Col *= -1; mv.Col *= -1;
} }
if (AddMvRefListEb(mv, ref refmvCount, mvRefList, earlyBreak))
if (AddRefListEb(mv, ref refmvCount, mvRefList, earlyBreak))
{ {
goto Done; goto Done;
} }
@ -776,13 +764,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
// Clamp vectors // Clamp vectors
for (i = 0; i < refmvCount; ++i) for (i = 0; i < refmvCount; ++i)
{ {
mvRefList[i].ClampMvRef(ref xd); mvRefList[i].ClampRef(ref xd);
} }
return refmvCount; return refmvCount;
} }
private static void AppendSub8x8MvsForIdx( private static void AppendSub8x8ForIdx(
ref Vp9Common cm, ref Vp9Common cm,
ref MacroBlockD xd, ref MacroBlockD xd,
Span<Position> mvRefSearch, Span<Position> mvRefSearch,
@ -796,16 +784,18 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
Span<Mv> mvList = stackalloc Mv[Constants.MaxMvRefCandidates]; Span<Mv> mvList = stackalloc Mv[Constants.MaxMvRefCandidates];
ref ModeInfo mi = ref xd.Mi[0].Value; ref ModeInfo mi = ref xd.Mi[0].Value;
ref Array4<BModeInfo> bmi = ref mi.Bmi; ref Array4<BModeInfo> bmi = ref mi.Bmi;
int n;
int refmvCount; int refmvCount;
Debug.Assert(Constants.MaxMvRefCandidates == 2); Debug.Assert(Constants.MaxMvRefCandidates == 2);
refmvCount = DecFindMvRefs(ref cm, ref xd, bMode, mi.RefFrame[refr], mvRefSearch, mvList, miRow, miCol, block, 1); refmvCount = DecFindRefs(ref cm, ref xd, bMode, mi.RefFrame[refr], mvRefSearch, mvList, miRow, miCol,
block, 1);
switch (block) switch (block)
{ {
case 0: bestSub8x8 = mvList[refmvCount - 1]; break; case 0:
bestSub8x8 = mvList[refmvCount - 1];
break;
case 1: case 1:
case 2: case 2:
if (bMode == PredictionMode.NearestMv) if (bMode == PredictionMode.NearestMv)
@ -815,7 +805,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
else else
{ {
bestSub8x8 = new Mv(); bestSub8x8 = new Mv();
for (n = 0; n < refmvCount; ++n) for (int n = 0; n < refmvCount; ++n)
{ {
if (Unsafe.As<Mv, int>(ref bmi[0].Mv[refr]) != Unsafe.As<Mv, int>(ref mvList[n])) if (Unsafe.As<Mv, int>(ref bmi[0].Mv[refr]) != Unsafe.As<Mv, int>(ref mvList[n]))
{ {
@ -824,6 +814,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
} }
} }
} }
break; break;
case 3: case 3:
if (bMode == PredictionMode.NearestMv) if (bMode == PredictionMode.NearestMv)
@ -838,7 +829,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
candidates[2] = mvList[0]; candidates[2] = mvList[0];
candidates[3] = mvList[1]; candidates[3] = mvList[1];
bestSub8x8 = new Mv(); bestSub8x8 = new Mv();
for (n = 0; n < 2 + Constants.MaxMvRefCandidates; ++n) for (int n = 0; n < 2 + Constants.MaxMvRefCandidates; ++n)
{ {
if (Unsafe.As<Mv, int>(ref bmi[2].Mv[refr]) != Unsafe.As<Mv, int>(ref candidates[n])) if (Unsafe.As<Mv, int>(ref bmi[2].Mv[refr]) != Unsafe.As<Mv, int>(ref candidates[n]))
{ {
@ -847,24 +838,27 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
} }
} }
} }
break;
default:
Debug.Assert(false, "Invalid block index.");
break; break;
default: Debug.Assert(false, "Invalid block index."); break;
} }
} }
private static byte GetModeContext(ref Vp9Common cm, ref MacroBlockD xd, Span<Position> mvRefSearch, int miRow, int miCol) private static byte GetModeContext(ref Vp9Common cm, ref MacroBlockD xd, Span<Position> mvRefSearch, int miRow,
int miCol)
{ {
int i;
int contextCounter = 0; int contextCounter = 0;
ref TileInfo tile = ref xd.Tile; ref TileInfo tile = ref xd.Tile;
// Get mode count from nearest 2 blocks // Get mode count from nearest 2 blocks
for (i = 0; i < 2; ++i) for (int i = 0; i < 2; ++i)
{ {
ref Position mvRef = ref mvRefSearch[i]; ref Position mvRef = ref mvRefSearch[i];
if (tile.IsInside(miCol, miRow, cm.MiRows, ref mvRef)) if (tile.IsInside(miCol, miRow, cm.MiRows, ref mvRef))
{ {
ref ModeInfo candidate = ref xd.Mi[mvRef.Col + mvRef.Row * xd.MiStride].Value; ref ModeInfo candidate = ref xd.Mi[mvRef.Col + (mvRef.Row * xd.MiStride)].Value;
// Keep counts for entropy encoding. // Keep counts for entropy encoding.
contextCounter += Luts.Mode2Counter[(int)candidate.Mode]; contextCounter += Luts.Mode2Counter[(int)candidate.Mode];
} }
@ -882,8 +876,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
ref Reader r) ref Reader r)
{ {
BlockSize bsize = mi.SbType; BlockSize bsize = mi.SbType;
bool allowHP = cm.AllowHighPrecisionMv; bool allowHp = cm.AllowHighPrecisionMv;
Array2<Mv> bestRefMvs = new Array2<Mv>(); Array2<Mv> bestRefMvs = new();
int refr, isCompound; int refr, isCompound;
byte interModeCtx; byte interModeCtx;
Span<Position> mvRefSearch = Luts.MvRefBlocks[(int)bsize]; Span<Position> mvRefSearch = Luts.MvRefBlocks[(int)bsize];
@ -892,12 +886,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
isCompound = mi.HasSecondRef() ? 1 : 0; isCompound = mi.HasSecondRef() ? 1 : 0;
interModeCtx = GetModeContext(ref cm, ref xd, mvRefSearch, miRow, miCol); interModeCtx = GetModeContext(ref cm, ref xd, mvRefSearch, miRow, miCol);
if (cm.Seg.IsSegFeatureActive(mi.SegmentId, SegLvlFeatures.SegLvlSkip) != 0) if (cm.Seg.IsSegFeatureActive(mi.SegmentId, SegLvlFeatures.Skip) != 0)
{ {
mi.Mode = PredictionMode.ZeroMv; mi.Mode = PredictionMode.ZeroMv;
if (bsize < BlockSize.Block8x8) if (bsize < BlockSize.Block8x8)
{ {
xd.ErrorInfo.Value.InternalError(CodecErr.CodecUnsupBitstream, "Invalid usage of segement feature on small blocks"); xd.ErrorInfo.Value.InternalError(CodecErr.UnsupBitstream,
"Invalid usage of segement feature on small blocks");
return; return;
} }
} }
@ -925,53 +920,58 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
sbyte frame = mi.RefFrame[refr]; sbyte frame = mi.RefFrame[refr];
int refmvCount; int refmvCount;
refmvCount = DecFindMvRefs(ref cm, ref xd, mi.Mode, frame, mvRefSearch, tmpMvs, miRow, miCol, -1, 0); refmvCount = DecFindRefs(ref cm, ref xd, mi.Mode, frame, mvRefSearch, tmpMvs, miRow, miCol,
-1, 0);
DecFindBestRefMvs(allowHP, tmpMvs, ref bestRefMvs[refr], refmvCount); DecFindBestRefs(allowHp, tmpMvs, ref bestRefMvs[refr], refmvCount);
} }
} }
} }
mi.InterpFilter = (cm.InterpFilter == Constants.Switchable) ? ReadSwitchableInterpFilter(ref cm, ref xd, ref r) : cm.InterpFilter; mi.InterpFilter = cm.InterpFilter == Constants.Switchable
? ReadSwitchableInterpFilter(ref cm, ref xd, ref r)
: cm.InterpFilter;
if (bsize < BlockSize.Block8x8) if (bsize < BlockSize.Block8x8)
{ {
int num4X4W = 1 << xd.BmodeBlocksWl; int num4x4W = 1 << xd.BmodeBlocksWl;
int num4X4H = 1 << xd.BmodeBlocksHl; int num4x4H = 1 << xd.BmodeBlocksHl;
int idx, idy; int idx, idy;
PredictionMode bMode = 0; PredictionMode bMode = 0;
Array2<Mv> bestSub8x8 = new Array2<Mv>(); Array2<Mv> bestSub8x8 = new();
const uint invalidMv = 0x80008000; const uint invalidMv = 0x80008000;
// Initialize the 2nd element as even though it won't be used meaningfully // Initialize the 2nd element as even though it won't be used meaningfully
// if isCompound is false. // if isCompound is false.
Unsafe.As<Mv, uint>(ref bestSub8x8[1]) = invalidMv; Unsafe.As<Mv, uint>(ref bestSub8x8[1]) = invalidMv;
for (idy = 0; idy < 2; idy += num4X4H) for (idy = 0; idy < 2; idy += num4x4H)
{ {
for (idx = 0; idx < 2; idx += num4X4W) for (idx = 0; idx < 2; idx += num4x4W)
{ {
int j = idy * 2 + idx; int j = (idy * 2) + idx;
bMode = ReadInterMode(ref cm, ref xd, ref r, interModeCtx); bMode = ReadInterMode(ref cm, ref xd, ref r, interModeCtx);
if (bMode == PredictionMode.NearestMv || bMode == PredictionMode.NearMv) if (bMode == PredictionMode.NearestMv || bMode == PredictionMode.NearMv)
{ {
for (refr = 0; refr < 1 + isCompound; ++refr) for (refr = 0; refr < 1 + isCompound; ++refr)
{ {
AppendSub8x8MvsForIdx(ref cm, ref xd, mvRefSearch, bMode, j, refr, miRow, miCol, ref bestSub8x8[refr]); AppendSub8x8ForIdx(ref cm, ref xd, mvRefSearch, bMode, j, refr, miRow, miCol,
ref bestSub8x8[refr]);
} }
} }
if (!AssignMv(ref cm, ref xd, bMode, ref mi.Bmi[j].Mv, ref bestRefMvs, ref bestSub8x8, isCompound, allowHP, ref r)) if (!Assign(ref cm, ref xd, bMode, ref mi.Bmi[j].Mv, ref bestRefMvs, ref bestSub8x8,
isCompound, allowHp, ref r))
{ {
xd.Corrupted |= true; xd.Corrupted |= true;
break; break;
} }
if (num4X4H == 2) if (num4x4H == 2)
{ {
mi.Bmi[j + 2] = mi.Bmi[j]; mi.Bmi[j + 2] = mi.Bmi[j];
} }
if (num4X4W == 2) if (num4x4W == 2)
{ {
mi.Bmi[j + 1] = mi.Bmi[j]; mi.Bmi[j + 1] = mi.Bmi[j];
} }
@ -980,11 +980,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
mi.Mode = bMode; mi.Mode = bMode;
CopyMvPair(ref mi.Mv, ref mi.Bmi[3].Mv); CopyPair(ref mi.Mv, ref mi.Bmi[3].Mv);
} }
else else
{ {
xd.Corrupted |= !AssignMv(ref cm, ref xd, mi.Mode, ref mi.Mv, ref bestRefMvs, ref bestRefMvs, isCompound, allowHP, ref r); xd.Corrupted |= !Assign(ref cm, ref xd, mi.Mode, ref mi.Mv, ref bestRefMvs, ref bestRefMvs,
isCompound, allowHp, ref r);
} }
} }
@ -1026,12 +1027,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
return leftMi.Value.GetYMode(b + 1); return leftMi.Value.GetYMode(b + 1);
} }
else
{
Debug.Assert(b == 1 || b == 3); Debug.Assert(b == 1 || b == 3);
return curMi.Value.Bmi[b - 1].Mode; return curMi.Value.Bmi[b - 1].Mode;
} }
}
private static PredictionMode AboveBlockMode(Ptr<ModeInfo> curMi, Ptr<ModeInfo> aboveMi, int b) private static PredictionMode AboveBlockMode(Ptr<ModeInfo> curMi, Ptr<ModeInfo> aboveMi, int b)
{ {
@ -1044,12 +1043,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
return aboveMi.Value.GetYMode(b + 2); return aboveMi.Value.GetYMode(b + 2);
} }
else
{
Debug.Assert(b == 2 || b == 3); Debug.Assert(b == 2 || b == 3);
return curMi.Value.Bmi[b - 2].Mode; return curMi.Value.Bmi[b - 2].Mode;
} }
}
private static ReadOnlySpan<byte> GetYModeProbs( private static ReadOnlySpan<byte> GetYModeProbs(
ref Vp9EntropyProbs fc, ref Vp9EntropyProbs fc,
@ -1076,8 +1073,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
Ptr<ModeInfo> aboveMi = xd.AboveMi; Ptr<ModeInfo> aboveMi = xd.AboveMi;
Ptr<ModeInfo> leftMi = xd.LeftMi; Ptr<ModeInfo> leftMi = xd.LeftMi;
BlockSize bsize = mi.Value.SbType; BlockSize bsize = mi.Value.SbType;
int i;
int miOffset = miRow * cm.MiCols + miCol; int miOffset = (miRow * cm.MiCols) + miCol;
mi.Value.SegmentId = (sbyte)ReadIntraSegmentId(ref cm, miOffset, xMis, yMis, ref r); mi.Value.SegmentId = (sbyte)ReadIntraSegmentId(ref cm, miOffset, xMis, yMis, ref r);
mi.Value.Skip = (sbyte)ReadSkip(ref cm, ref xd, mi.Value.SegmentId, ref r); mi.Value.Skip = (sbyte)ReadSkip(ref cm, ref xd, mi.Value.SegmentId, ref r);
@ -1088,7 +1085,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
switch (bsize) switch (bsize)
{ {
case BlockSize.Block4x4: case BlockSize.Block4x4:
for (i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i)
{ {
mi.Value.Bmi[i].Mode = mi.Value.Bmi[i].Mode =
ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, i)); ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, i));
@ -1133,8 +1130,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
ref Reader r = ref twd.BitReader; ref Reader r = ref twd.BitReader;
ref MacroBlockD xd = ref twd.Xd; ref MacroBlockD xd = ref twd.Xd;
ref ModeInfo mi = ref xd.Mi[0].Value; ref ModeInfo mi = ref xd.Mi[0].Value;
ArrayPtr<MvRef> frameMvs = cm.CurFrameMvs.Slice(miRow * cm.MiCols + miCol); ArrayPtr<MvRef> frameMvs = cm.CurFrameMvs.Slice((miRow * cm.MiCols) + miCol);
int w, h;
if (cm.FrameIsIntraOnly()) if (cm.FrameIsIntraOnly())
{ {
@ -1144,14 +1140,15 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
{ {
ReadInterFrameModeInfo(ref cm, ref xd, miRow, miCol, ref r, xMis, yMis); ReadInterFrameModeInfo(ref cm, ref xd, miRow, miCol, ref r, xMis, yMis);
for (h = 0; h < yMis; ++h) for (int h = 0; h < yMis; ++h)
{ {
for (w = 0; w < xMis; ++w) for (int w = 0; w < xMis; ++w)
{ {
ref MvRef mv = ref frameMvs[w]; ref MvRef mv = ref frameMvs[w];
CopyRefFramePair(ref mv.RefFrame, ref mi.RefFrame); CopyRefFramePair(ref mv.RefFrame, ref mi.RefFrame);
CopyMvPair(ref mv.Mv, ref mi.Mv); CopyPair(ref mv.Mv, ref mi.Mv);
} }
frameMvs = frameMvs.Slice(cm.MiCols); frameMvs = frameMvs.Slice(cm.MiCols);
} }
} }

View file

@ -3,7 +3,6 @@ using Ryujinx.Graphics.Nvdec.Vp9.Common;
using Ryujinx.Graphics.Nvdec.Vp9.Types; using Ryujinx.Graphics.Nvdec.Vp9.Types;
using Ryujinx.Graphics.Video; using Ryujinx.Graphics.Video;
using System; using System;
using Vp9MvRef = Ryujinx.Graphics.Video.Vp9MvRef;
namespace Ryujinx.Graphics.Nvdec.Vp9 namespace Ryujinx.Graphics.Nvdec.Vp9
{ {
@ -11,16 +10,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
{ {
public bool IsHardwareAccelerated => false; public bool IsHardwareAccelerated => false;
private readonly MemoryAllocator _allocator = new MemoryAllocator(); private readonly MemoryAllocator _allocator = new();
public ISurface CreateSurface(int width, int height) => new Surface(width, height); public ISurface CreateSurface(int width, int height)
{
return new Surface(width, height);
}
private static ReadOnlySpan<byte> LiteralToFilter => new byte[] private static ReadOnlySpan<byte> LiteralToFilter => new byte[]
{ {
Constants.EightTapSmooth, Constants.EightTapSmooth, Constants.EightTap, Constants.EightTapSharp, Constants.Bilinear
Constants.EightTap,
Constants.EightTapSharp,
Constants.Bilinear
}; };
public unsafe bool Decode( public unsafe bool Decode(
@ -30,7 +29,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
ReadOnlySpan<Vp9MvRef> mvsIn, ReadOnlySpan<Vp9MvRef> mvsIn,
Span<Vp9MvRef> mvsOut) Span<Vp9MvRef> mvsOut)
{ {
Vp9Common cm = new Vp9Common(); Vp9Common cm = new();
cm.FrameType = pictureInfo.IsKeyFrame ? FrameType.KeyFrame : FrameType.InterFrame; cm.FrameType = pictureInfo.IsKeyFrame ? FrameType.KeyFrame : FrameType.InterFrame;
cm.IntraOnly = pictureInfo.IntraOnly; cm.IntraOnly = pictureInfo.IntraOnly;
@ -68,6 +67,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
cm.CompFixedRef = pictureInfo.CompFixedRef; cm.CompFixedRef = pictureInfo.CompFixedRef;
cm.CompVarRef = pictureInfo.CompVarRef; cm.CompVarRef = pictureInfo.CompVarRef;
cm.BitDepth = BitDepth.Bits8;
cm.Log2TileCols = pictureInfo.Log2TileCols; cm.Log2TileCols = pictureInfo.Log2TileCols;
cm.Log2TileRows = pictureInfo.Log2TileRows; cm.Log2TileRows = pictureInfo.Log2TileRows;
@ -78,6 +79,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
cm.Seg.FeatureMask = pictureInfo.SegmentFeatureEnable; cm.Seg.FeatureMask = pictureInfo.SegmentFeatureEnable;
cm.Seg.FeatureData = pictureInfo.SegmentFeatureData; cm.Seg.FeatureData = pictureInfo.SegmentFeatureData;
cm.Lf.FilterLevel = pictureInfo.LoopFilterLevel;
cm.Lf.SharpnessLevel = pictureInfo.LoopFilterSharpnessLevel;
cm.Lf.ModeRefDeltaEnabled = pictureInfo.ModeRefDeltaEnabled; cm.Lf.ModeRefDeltaEnabled = pictureInfo.ModeRefDeltaEnabled;
cm.Lf.RefDeltas = pictureInfo.RefDeltas; cm.Lf.RefDeltas = pictureInfo.RefDeltas;
cm.Lf.ModeDeltas = pictureInfo.ModeDeltas; cm.Lf.ModeDeltas = pictureInfo.ModeDeltas;
@ -105,7 +108,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
cm.SetupSegmentationDequant(); cm.SetupSegmentationDequant();
cm.SetupScaleFactors(); cm.SetupScaleFactors();
SetMvs(ref cm, mvsIn); cm.SetMvs(mvsIn);
fixed (byte* dataPtr = bitstream) fixed (byte* dataPtr = bitstream)
{ {
@ -114,10 +117,27 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
if (maxThreads > 1 && tileRows == 1 && tileCols > 1) if (maxThreads > 1 && tileRows == 1 && tileCols > 1)
{ {
DecodeFrame.DecodeTilesMt(ref cm, new ArrayPtr<byte>(dataPtr, bitstream.Length), maxThreads); DecodeFrame.DecodeTilesMt(ref cm, new ArrayPtr<byte>(dataPtr, bitstream.Length), maxThreads);
LoopFilter.LoopFilterFrameMt(
ref cm.Mb.CurBuf,
ref cm,
ref cm.Mb,
cm.Lf.FilterLevel,
false,
false,
maxThreads);
} }
else else
{ {
DecodeFrame.DecodeTiles(ref cm, new ArrayPtr<byte>(dataPtr, bitstream.Length)); DecodeFrame.DecodeTiles(ref cm, new ArrayPtr<byte>(dataPtr, bitstream.Length));
LoopFilter.LoopFilterFrame(
ref cm.Mb.CurBuf,
ref cm,
ref cm.Mb,
cm.Lf.FilterLevel,
false,
false);
} }
} }
catch (InternalErrorException) catch (InternalErrorException)
@ -126,7 +146,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
} }
} }
GetMvs(ref cm, mvsOut); cm.GetMvs(mvsOut);
cm.FreeTileWorkerData(_allocator); cm.FreeTileWorkerData(_allocator);
cm.FreeContextBuffers(_allocator); cm.FreeContextBuffers(_allocator);
@ -134,48 +154,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
return true; return true;
} }
private static void SetMvs(ref Vp9Common cm, ReadOnlySpan<Vp9MvRef> mvs) public void Dispose()
{ {
if (mvs.Length > cm.PrevFrameMvs.Length) _allocator.Dispose();
{
throw new ArgumentException($"Size mismatch, expected: {cm.PrevFrameMvs.Length}, but got: {mvs.Length}.");
} }
for (int i = 0; i < mvs.Length; i++)
{
ref var mv = ref cm.PrevFrameMvs[i];
mv.Mv[0].Row = mvs[i].Mvs[0].Row;
mv.Mv[0].Col = mvs[i].Mvs[0].Col;
mv.Mv[1].Row = mvs[i].Mvs[1].Row;
mv.Mv[1].Col = mvs[i].Mvs[1].Col;
mv.RefFrame[0] = (sbyte)mvs[i].RefFrames[0];
mv.RefFrame[1] = (sbyte)mvs[i].RefFrames[1];
}
}
private static void GetMvs(ref Vp9Common cm, Span<Vp9MvRef> mvs)
{
if (mvs.Length > cm.CurFrameMvs.Length)
{
throw new ArgumentException($"Size mismatch, expected: {cm.CurFrameMvs.Length}, but got: {mvs.Length}.");
}
for (int i = 0; i < mvs.Length; i++)
{
ref var mv = ref cm.CurFrameMvs[i];
mvs[i].Mvs[0].Row = mv.Mv[0].Row;
mvs[i].Mvs[0].Col = mv.Mv[0].Col;
mvs[i].Mvs[1].Row = mv.Mv[1].Row;
mvs[i].Mvs[1].Col = mv.Mv[1].Col;
mvs[i].RefFrames[0] = mv.RefFrame[0];
mvs[i].RefFrames[1] = mv.RefFrame[1];
}
}
public void Dispose() => _allocator.Dispose();
} }
} }

View file

@ -19,24 +19,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
{ {
const int maxNeighbors = 2; const int maxNeighbors = 2;
return (1 + tokenCache[neighbors[maxNeighbors * c + 0]] + tokenCache[neighbors[maxNeighbors * c + 1]]) >> 1; return (1 + tokenCache[neighbors[(maxNeighbors * c) + 0]] +
} tokenCache[neighbors[(maxNeighbors * c) + 1]]) >> 1;
private static int ReadCoeff(
ref Reader r,
ReadOnlySpan<byte> probs,
int n,
ref ulong value,
ref int count,
ref uint range)
{
int i, val = 0;
for (i = 0; i < n; ++i)
{
val = (val << 1) | r.ReadBool(probs[i], ref value, ref count, ref range);
}
return val;
} }
private static int DecodeCoefs( private static int DecodeCoefs(
@ -57,14 +41,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
int band, c = 0; int band, c = 0;
ref Array6<Array6<Array3<byte>>> coefProbs = ref fc.CoefProbs[(int)txSize][(int)type][refr]; ref Array6<Array6<Array3<byte>>> coefProbs = ref fc.CoefProbs[(int)txSize][(int)type][refr];
Span<byte> tokenCache = stackalloc byte[32 * 32]; Span<byte> tokenCache = stackalloc byte[32 * 32];
ReadOnlySpan<byte> bandTranslate = Luts.get_band_translate(txSize); ReadOnlySpan<byte> bandTranslate = Luts.GetBandTranslate(txSize);
int dqShift = (txSize == TxSize.Tx32x32) ? 1 : 0; int dqShift = txSize == TxSize.Tx32x32 ? 1 : 0;
int v; int v;
short dqv = dq[0]; short dqv = dq[0];
ReadOnlySpan<byte> cat6Prob = (xd.Bd == 12) ReadOnlySpan<byte> cat6Prob = xd.Bd == 12
? Luts.Vp9Cat6ProbHigh12 ? Luts.Cat6ProbHigh12
: (xd.Bd == 10) ? Luts.Vp9Cat6ProbHigh12.Slice(2) : Luts.Vp9Cat6Prob; : xd.Bd == 10
int cat6Bits = (xd.Bd == 12) ? 18 : (xd.Bd == 10) ? 16 : 14; ? Luts.Cat6ProbHigh12.Slice(2)
: Luts.Cat6Prob;
int cat6Bits = xd.Bd == 12 ? 18 : xd.Bd == 10 ? 16 : 14;
// Keep value, range, and count as locals. The compiler produces better // Keep value, range, and count as locals. The compiler produces better
// results with the locals than using r directly. // results with the locals than using r directly.
ulong value = r.Value; ulong value = r.Value;
@ -109,6 +95,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
r.Count = count; r.Count = count;
return c; // Zero tokens at the end (no eob token) return c; // Zero tokens at the end (no eob token)
} }
ctx = GetCoefContext(nb, tokenCache, c); ctx = GetCoefContext(nb, tokenCache, c);
band = bandTranslate[0]; band = bandTranslate[0];
bandTranslate = bandTranslate.Slice(1); bandTranslate = bandTranslate.Slice(1);
@ -117,7 +104,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
if (r.ReadBool(prob[OneContextNode], ref value, ref count, ref range) != 0) if (r.ReadBool(prob[OneContextNode], ref value, ref count, ref range) != 0)
{ {
ReadOnlySpan<byte> p = Luts.Vp9Pareto8Full[prob[Constants.PivotNode] - 1]; ReadOnlySpan<byte> p = Luts.Pareto8Full[prob[Constants.PivotNode] - 1];
if (!xd.Counts.IsNull) if (!xd.Counts.IsNull)
{ {
++counts.Coef[(int)txSize][(int)type][refr][band][ctx][Constants.TwoToken]; ++counts.Coef[(int)txSize][(int)type][refr][band][ctx][Constants.TwoToken];
@ -132,20 +119,24 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
{ {
if (r.ReadBool(p[7], ref value, ref count, ref range) != 0) if (r.ReadBool(p[7], ref value, ref count, ref range) != 0)
{ {
val = Constants.Cat6MinVal + ReadCoeff(ref r, cat6Prob, cat6Bits, ref value, ref count, ref range); val = Constants.Cat6MinVal + r.ReadCoeff(cat6Prob, cat6Bits, ref value,
ref count, ref range);
} }
else else
{ {
val = Constants.Cat5MinVal + ReadCoeff(ref r, Luts.Vp9Cat5Prob, 5, ref value, ref count, ref range); val = Constants.Cat5MinVal + r.ReadCoeff(Luts.Cat5Prob, 5, ref value,
ref count, ref range);
} }
} }
else if (r.ReadBool(p[6], ref value, ref count, ref range) != 0) else if (r.ReadBool(p[6], ref value, ref count, ref range) != 0)
{ {
val = Constants.Cat4MinVal + ReadCoeff(ref r, Luts.Vp9Cat4Prob, 4, ref value, ref count, ref range); val = Constants.Cat4MinVal + r.ReadCoeff(Luts.Cat4Prob, 4, ref value, ref count,
ref range);
} }
else else
{ {
val = Constants.Cat3MinVal + ReadCoeff(ref r, Luts.Vp9Cat3Prob, 3, ref value, ref count, ref range); val = Constants.Cat3MinVal + r.ReadCoeff(Luts.Cat3Prob, 3, ref value, ref count,
ref range);
} }
} }
else else
@ -153,13 +144,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
tokenCache[scan[c]] = 4; tokenCache[scan[c]] = 4;
if (r.ReadBool(p[4], ref value, ref count, ref range) != 0) if (r.ReadBool(p[4], ref value, ref count, ref range) != 0)
{ {
val = Constants.Cat2MinVal + ReadCoeff(ref r, Luts.Vp9Cat2Prob, 2, ref value, ref count, ref range); val = Constants.Cat2MinVal + r.ReadCoeff(Luts.Cat2Prob, 2, ref value, ref count,
ref range);
} }
else else
{ {
val = Constants.Cat1MinVal + ReadCoeff(ref r, Luts.Vp9Cat1Prob, 1, ref value, ref count, ref range); val = Constants.Cat1MinVal + r.ReadCoeff(Luts.Cat1Prob, 1, ref value, ref count,
ref range);
} }
} }
// Val may use 18-bits // Val may use 18-bits
v = (int)(((long)val * dqv) >> dqShift); v = (int)(((long)val * dqv) >> dqShift);
} }
@ -187,7 +181,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
tokenCache[scan[c]] = 1; tokenCache[scan[c]] = 1;
v = dqv >> dqShift; v = dqv >> dqShift;
} }
dqcoeff[scan[c]] = (int)HighbdCheckRange(r.ReadBool(128, ref value, ref count, ref range) != 0 ? -v : v, xd.Bd);
dqcoeff[scan[c]] = (int)HighbdCheckRange(r.ReadBool(128, ref value, ref count, ref range) != 0 ? -v : v,
xd.Bd);
++c; ++c;
ctx = GetCoefContext(nb, tokenCache, c); ctx = GetCoefContext(nb, tokenCache, c);
dqv = dq[1]; dqv = dq[1];
@ -199,7 +195,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
return c; return c;
} }
private static void GetCtxShift(ref MacroBlockD xd, ref int ctxShiftA, ref int ctxShiftL, int x, int y, uint txSizeInBlocks) private static void GetCtxShift(ref MacroBlockD xd, ref int ctxShiftA, ref int ctxShiftL, int x, int y,
uint txSizeInBlocks)
{ {
if (xd.MaxBlocksWide != 0) if (xd.MaxBlocksWide != 0)
{ {
@ -208,6 +205,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
ctxShiftA = (int)(txSizeInBlocks - (xd.MaxBlocksWide - x)) * 8; ctxShiftA = (int)(txSizeInBlocks - (xd.MaxBlocksWide - x)) * 8;
} }
} }
if (xd.MaxBlocksHigh != 0) if (xd.MaxBlocksHigh != 0)
{ {
if (txSizeInBlocks + y > xd.MaxBlocksHigh) if (txSizeInBlocks + y > xd.MaxBlocksHigh)

View file

@ -75,17 +75,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
Vector128<int> zero = Vector128<int>.Zero; Vector128<int> zero = Vector128<int>.Zero;
Vector128<int> const64 = Vector128.Create(64); Vector128<int> const64 = Vector128.Create(64);
ulong x, y; src -= (SubpelTaps / 2) - 1;
src -= SubpelTaps / 2 - 1;
fixed (Array8<short>* xFilter = xFilters) fixed (Array8<short>* xFilter = xFilters)
{ {
Vector128<short> vfilter = Sse2.LoadVector128((short*)xFilter + (uint)(x0Q4 & SubpelMask) * 8); Vector128<short> vfilter = Sse2.LoadVector128((short*)xFilter + ((uint)(x0Q4 & SubpelMask) * 8));
for (y = 0; y < (uint)h; ++y) for (ulong y = 0; y < (uint)h; ++y)
{ {
ulong srcOffset = (uint)x0Q4 >> SubpelBits; ulong srcOffset = (uint)x0Q4 >> SubpelBits;
for (x = 0; x < (uint)w; x += 4) for (ulong x = 0; x < (uint)w; x += 4)
{ {
Vector128<short> vsrc0 = Sse41.ConvertToVector128Int16(&src[srcOffset + x]); Vector128<short> vsrc0 = Sse41.ConvertToVector128Int16(&src[srcOffset + x]);
Vector128<short> vsrc1 = Sse41.ConvertToVector128Int16(&src[srcOffset + x + 1]); Vector128<short> vsrc1 = Sse41.ConvertToVector128Int16(&src[srcOffset + x + 1]);
@ -94,8 +93,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
Vector128<int> sum0123 = MultiplyAddAdjacent(vsrc0, vsrc1, vsrc2, vsrc3, vfilter, zero); Vector128<int> sum0123 = MultiplyAddAdjacent(vsrc0, vsrc1, vsrc2, vsrc3, vfilter, zero);
Sse.StoreScalar((float*)&dst[x], PackUnsignedSaturate(RoundShift(sum0123, const64), zero).AsSingle()); Sse.StoreScalar((float*)&dst[x],
PackUnsignedSaturate(RoundShift(sum0123, const64), zero).AsSingle());
} }
src += srcStride; src += srcStride;
dst += dstStride; dst += dstStride;
} }
@ -120,18 +121,17 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
return; return;
} }
int x, y; src -= (SubpelTaps / 2) - 1;
src -= SubpelTaps / 2 - 1;
for (y = 0; y < h; ++y) for (int y = 0; y < h; ++y)
{ {
int xQ4 = x0Q4; int xQ4 = x0Q4;
for (x = 0; x < w; ++x) for (int x = 0; x < w; ++x)
{ {
byte* srcX = &src[xQ4 >> SubpelBits]; byte* srcX = &src[xQ4 >> SubpelBits];
ref Array8<short> xFilter = ref xFilters[xQ4 & SubpelMask]; ref Array8<short> xFilter = ref xFilters[xQ4 & SubpelMask];
int k, sum = 0; int sum = 0;
for (k = 0; k < SubpelTaps; ++k) for (int k = 0; k < SubpelTaps; ++k)
{ {
sum += srcX[k] * xFilter[k]; sum += srcX[k] * xFilter[k];
} }
@ -139,6 +139,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
dst[x] = BitUtils.ClipPixel(BitUtils.RoundPowerOfTwo(sum, FilterBits)); dst[x] = BitUtils.ClipPixel(BitUtils.RoundPowerOfTwo(sum, FilterBits));
xQ4 += xStepQ4; xQ4 += xStepQ4;
} }
src += srcStride; src += srcStride;
dst += dstStride; dst += dstStride;
} }
@ -155,25 +156,26 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
int w, int w,
int h) int h)
{ {
int x, y; src -= (SubpelTaps / 2) - 1;
src -= SubpelTaps / 2 - 1;
for (y = 0; y < h; ++y) for (int y = 0; y < h; ++y)
{ {
int xQ4 = x0Q4; int xQ4 = x0Q4;
for (x = 0; x < w; ++x) for (int x = 0; x < w; ++x)
{ {
byte* srcX = &src[xQ4 >> SubpelBits]; byte* srcX = &src[xQ4 >> SubpelBits];
ref Array8<short> xFilter = ref xFilters[xQ4 & SubpelMask]; ref Array8<short> xFilter = ref xFilters[xQ4 & SubpelMask];
int k, sum = 0; int sum = 0;
for (k = 0; k < SubpelTaps; ++k) for (int k = 0; k < SubpelTaps; ++k)
{ {
sum += srcX[k] * xFilter[k]; sum += srcX[k] * xFilter[k];
} }
dst[x] = (byte)BitUtils.RoundPowerOfTwo(dst[x] + BitUtils.ClipPixel(BitUtils.RoundPowerOfTwo(sum, FilterBits)), 1); dst[x] = (byte)BitUtils.RoundPowerOfTwo(
dst[x] + BitUtils.ClipPixel(BitUtils.RoundPowerOfTwo(sum, FilterBits)), 1);
xQ4 += xStepQ4; xQ4 += xStepQ4;
} }
src += srcStride; src += srcStride;
dst += dstStride; dst += dstStride;
} }
@ -202,18 +204,17 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
srcStride * 6, srcStride * 6,
srcStride * 7); srcStride * 7);
ulong x, y; src -= srcStride * ((SubpelTaps / 2) - 1);
src -= srcStride * (SubpelTaps / 2 - 1);
fixed (Array8<short>* yFilter = yFilters) fixed (Array8<short>* yFilter = yFilters)
{ {
Vector128<short> vfilter = Sse2.LoadVector128((short*)yFilter + (uint)(y0Q4 & SubpelMask) * 8); Vector128<short> vfilter = Sse2.LoadVector128((short*)yFilter + ((uint)(y0Q4 & SubpelMask) * 8));
ulong srcBaseY = (uint)y0Q4 >> SubpelBits; ulong srcBaseY = (uint)y0Q4 >> SubpelBits;
for (y = 0; y < (uint)h; ++y) for (ulong y = 0; y < (uint)h; ++y)
{ {
ulong srcOffset = (srcBaseY + y) * (uint)srcStride; ulong srcOffset = (srcBaseY + y) * (uint)srcStride;
for (x = 0; x < (uint)w; x += 4) for (ulong x = 0; x < (uint)w; x += 4)
{ {
Vector256<int> vsrc = Avx2.GatherVector256((uint*)&src[srcOffset + x], indices, 1).AsInt32(); Vector256<int> vsrc = Avx2.GatherVector256((uint*)&src[srcOffset + x], indices, 1).AsInt32();
@ -239,8 +240,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
Vector128<int> sum0123 = MultiplyAddAdjacent(vsrc0, vsrc1, vsrc2, vsrc3, vfilter, zero); Vector128<int> sum0123 = MultiplyAddAdjacent(vsrc0, vsrc1, vsrc2, vsrc3, vfilter, zero);
Sse.StoreScalar((float*)&dst[x], PackUnsignedSaturate(RoundShift(sum0123, const64), zero).AsSingle()); Sse.StoreScalar((float*)&dst[x],
PackUnsignedSaturate(RoundShift(sum0123, const64), zero).AsSingle());
} }
dst += dstStride; dst += dstStride;
} }
} }
@ -264,18 +267,17 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
return; return;
} }
int x, y; src -= srcStride * ((SubpelTaps / 2) - 1);
src -= srcStride * (SubpelTaps / 2 - 1);
for (x = 0; x < w; ++x) for (int x = 0; x < w; ++x)
{ {
int yQ4 = y0Q4; int yQ4 = y0Q4;
for (y = 0; y < h; ++y) for (int y = 0; y < h; ++y)
{ {
byte* srcY = &src[(yQ4 >> SubpelBits) * srcStride]; byte* srcY = &src[(yQ4 >> SubpelBits) * srcStride];
ref Array8<short> yFilter = ref yFilters[yQ4 & SubpelMask]; ref Array8<short> yFilter = ref yFilters[yQ4 & SubpelMask];
int k, sum = 0; int sum = 0;
for (k = 0; k < SubpelTaps; ++k) for (int k = 0; k < SubpelTaps; ++k)
{ {
sum += srcY[k * srcStride] * yFilter[k]; sum += srcY[k * srcStride] * yFilter[k];
} }
@ -283,6 +285,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
dst[y * dstStride] = BitUtils.ClipPixel(BitUtils.RoundPowerOfTwo(sum, FilterBits)); dst[y * dstStride] = BitUtils.ClipPixel(BitUtils.RoundPowerOfTwo(sum, FilterBits));
yQ4 += yStepQ4; yQ4 += yStepQ4;
} }
++src; ++src;
++dst; ++dst;
} }
@ -299,18 +302,17 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
int w, int w,
int h) int h)
{ {
int x, y; src -= srcStride * ((SubpelTaps / 2) - 1);
src -= srcStride * (SubpelTaps / 2 - 1);
for (x = 0; x < w; ++x) for (int x = 0; x < w; ++x)
{ {
int yQ4 = y0Q4; int yQ4 = y0Q4;
for (y = 0; y < h; ++y) for (int y = 0; y < h; ++y)
{ {
byte* srcY = &src[(yQ4 >> SubpelBits) * srcStride]; byte* srcY = &src[(yQ4 >> SubpelBits) * srcStride];
ref Array8<short> yFilter = ref yFilters[yQ4 & SubpelMask]; ref Array8<short> yFilter = ref yFilters[yQ4 & SubpelMask];
int k, sum = 0; int sum = 0;
for (k = 0; k < SubpelTaps; ++k) for (int k = 0; k < SubpelTaps; ++k)
{ {
sum += srcY[k * srcStride] * yFilter[k]; sum += srcY[k * srcStride] * yFilter[k];
} }
@ -319,6 +321,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
dst[y * dstStride] + BitUtils.ClipPixel(BitUtils.RoundPowerOfTwo(sum, FilterBits)), 1); dst[y * dstStride] + BitUtils.ClipPixel(BitUtils.RoundPowerOfTwo(sum, FilterBits)), 1);
yQ4 += yStepQ4; yQ4 += yStepQ4;
} }
++src; ++src;
++dst; ++dst;
} }
@ -418,15 +421,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
// ==> yStepQ4 = 64. Since w and h are at most 16, the temp buffer is still // ==> yStepQ4 = 64. Since w and h are at most 16, the temp buffer is still
// big enough. // big enough.
byte* temp = stackalloc byte[64 * 135]; byte* temp = stackalloc byte[64 * 135];
int intermediateHeight = (((h - 1) * yStepQ4 + y0Q4) >> SubpelBits) + SubpelTaps; int intermediateHeight = ((((h - 1) * yStepQ4) + y0Q4) >> SubpelBits) + SubpelTaps;
Debug.Assert(w <= 64); Debug.Assert(w <= 64);
Debug.Assert(h <= 64); Debug.Assert(h <= 64);
Debug.Assert(yStepQ4 <= 32 || (yStepQ4 <= 64 && h <= 32)); Debug.Assert(yStepQ4 <= 32 || (yStepQ4 <= 64 && h <= 32));
Debug.Assert(xStepQ4 <= 64); Debug.Assert(xStepQ4 <= 64);
ConvolveHoriz(src - srcStride * (SubpelTaps / 2 - 1), srcStride, temp, 64, filter, x0Q4, xStepQ4, w, intermediateHeight); ConvolveHoriz(src - (srcStride * ((SubpelTaps / 2) - 1)), srcStride, temp, 64, filter, x0Q4, xStepQ4, w,
ConvolveVert(temp + 64 * (SubpelTaps / 2 - 1), 64, dst, dstStride, filter, y0Q4, yStepQ4, w, h); intermediateHeight);
ConvolveVert(temp + (64 * ((SubpelTaps / 2) - 1)), 64, dst, dstStride, filter, y0Q4, yStepQ4, w, h);
} }
public static unsafe void Convolve8Avg( public static unsafe void Convolve8Avg(
@ -487,11 +491,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
int w, int w,
int h) int h)
{ {
int x, y; for (int y = 0; y < h; ++y)
for (y = 0; y < h; ++y)
{ {
for (x = 0; x < w; ++x) for (int x = 0; x < w; ++x)
{ {
dst[x] = (byte)BitUtils.RoundPowerOfTwo(dst[x] + src[x], 1); dst[x] = (byte)BitUtils.RoundPowerOfTwo(dst[x] + src[x], 1);
} }
@ -609,18 +611,17 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
int h, int h,
int bd) int bd)
{ {
int x, y; src -= (SubpelTaps / 2) - 1;
src -= SubpelTaps / 2 - 1;
for (y = 0; y < h; ++y) for (int y = 0; y < h; ++y)
{ {
int xQ4 = x0Q4; int xQ4 = x0Q4;
for (x = 0; x < w; ++x) for (int x = 0; x < w; ++x)
{ {
ushort* srcX = &src[xQ4 >> SubpelBits]; ushort* srcX = &src[xQ4 >> SubpelBits];
ref Array8<short> xFilter = ref xFilters[xQ4 & SubpelMask]; ref Array8<short> xFilter = ref xFilters[xQ4 & SubpelMask];
int k, sum = 0; int sum = 0;
for (k = 0; k < SubpelTaps; ++k) for (int k = 0; k < SubpelTaps; ++k)
{ {
sum += srcX[k] * xFilter[k]; sum += srcX[k] * xFilter[k];
} }
@ -628,6 +629,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
dst[x] = BitUtils.ClipPixelHighbd(BitUtils.RoundPowerOfTwo(sum, FilterBits), bd); dst[x] = BitUtils.ClipPixelHighbd(BitUtils.RoundPowerOfTwo(sum, FilterBits), bd);
xQ4 += xStepQ4; xQ4 += xStepQ4;
} }
src += srcStride; src += srcStride;
dst += dstStride; dst += dstStride;
} }
@ -645,25 +647,26 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
int h, int h,
int bd) int bd)
{ {
int x, y; src -= (SubpelTaps / 2) - 1;
src -= SubpelTaps / 2 - 1;
for (y = 0; y < h; ++y) for (int y = 0; y < h; ++y)
{ {
int xQ4 = x0Q4; int xQ4 = x0Q4;
for (x = 0; x < w; ++x) for (int x = 0; x < w; ++x)
{ {
ushort* srcX = &src[xQ4 >> SubpelBits]; ushort* srcX = &src[xQ4 >> SubpelBits];
ref Array8<short> xFilter = ref xFilters[xQ4 & SubpelMask]; ref Array8<short> xFilter = ref xFilters[xQ4 & SubpelMask];
int k, sum = 0; int sum = 0;
for (k = 0; k < SubpelTaps; ++k) for (int k = 0; k < SubpelTaps; ++k)
{ {
sum += srcX[k] * xFilter[k]; sum += srcX[k] * xFilter[k];
} }
dst[x] = (ushort)BitUtils.RoundPowerOfTwo(dst[x] + BitUtils.ClipPixelHighbd(BitUtils.RoundPowerOfTwo(sum, FilterBits), bd), 1); dst[x] = (ushort)BitUtils.RoundPowerOfTwo(
dst[x] + BitUtils.ClipPixelHighbd(BitUtils.RoundPowerOfTwo(sum, FilterBits), bd), 1);
xQ4 += xStepQ4; xQ4 += xStepQ4;
} }
src += srcStride; src += srcStride;
dst += dstStride; dst += dstStride;
} }
@ -681,18 +684,17 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
int h, int h,
int bd) int bd)
{ {
int x, y; src -= srcStride * ((SubpelTaps / 2) - 1);
src -= srcStride * (SubpelTaps / 2 - 1);
for (x = 0; x < w; ++x) for (int x = 0; x < w; ++x)
{ {
int yQ4 = y0Q4; int yQ4 = y0Q4;
for (y = 0; y < h; ++y) for (int y = 0; y < h; ++y)
{ {
ushort* srcY = &src[(yQ4 >> SubpelBits) * srcStride]; ushort* srcY = &src[(yQ4 >> SubpelBits) * srcStride];
ref Array8<short> yFilter = ref yFilters[yQ4 & SubpelMask]; ref Array8<short> yFilter = ref yFilters[yQ4 & SubpelMask];
int k, sum = 0; int sum = 0;
for (k = 0; k < SubpelTaps; ++k) for (int k = 0; k < SubpelTaps; ++k)
{ {
sum += srcY[k * srcStride] * yFilter[k]; sum += srcY[k * srcStride] * yFilter[k];
} }
@ -700,6 +702,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
dst[y * dstStride] = BitUtils.ClipPixelHighbd(BitUtils.RoundPowerOfTwo(sum, FilterBits), bd); dst[y * dstStride] = BitUtils.ClipPixelHighbd(BitUtils.RoundPowerOfTwo(sum, FilterBits), bd);
yQ4 += yStepQ4; yQ4 += yStepQ4;
} }
++src; ++src;
++dst; ++dst;
} }
@ -717,26 +720,27 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
int h, int h,
int bd) int bd)
{ {
int x, y; src -= srcStride * ((SubpelTaps / 2) - 1);
src -= srcStride * (SubpelTaps / 2 - 1);
for (x = 0; x < w; ++x) for (int x = 0; x < w; ++x)
{ {
int yQ4 = y0Q4; int yQ4 = y0Q4;
for (y = 0; y < h; ++y) for (int y = 0; y < h; ++y)
{ {
ushort* srcY = &src[(yQ4 >> SubpelBits) * srcStride]; ushort* srcY = &src[(yQ4 >> SubpelBits) * srcStride];
ref Array8<short> yFilter = ref yFilters[yQ4 & SubpelMask]; ref Array8<short> yFilter = ref yFilters[yQ4 & SubpelMask];
int k, sum = 0; int sum = 0;
for (k = 0; k < SubpelTaps; ++k) for (int k = 0; k < SubpelTaps; ++k)
{ {
sum += srcY[k * srcStride] * yFilter[k]; sum += srcY[k * srcStride] * yFilter[k];
} }
dst[y * dstStride] = (ushort)BitUtils.RoundPowerOfTwo( dst[y * dstStride] = (ushort)BitUtils.RoundPowerOfTwo(
dst[y * dstStride] + BitUtils.ClipPixelHighbd(BitUtils.RoundPowerOfTwo(sum, FilterBits), bd), 1); dst[y * dstStride] + BitUtils.ClipPixelHighbd(BitUtils.RoundPowerOfTwo(sum, FilterBits), bd),
1);
yQ4 += yStepQ4; yQ4 += yStepQ4;
} }
++src; ++src;
++dst; ++dst;
} }
@ -769,15 +773,17 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
// --Require an additional SubpelTaps rows for the 8-tap filter tails. // --Require an additional SubpelTaps rows for the 8-tap filter tails.
// --((64 - 1) * 32 + 15) >> 4 + 8 = 135. // --((64 - 1) * 32 + 15) >> 4 + 8 = 135.
ushort* temp = stackalloc ushort[64 * 135]; ushort* temp = stackalloc ushort[64 * 135];
int intermediateHeight = (((h - 1) * yStepQ4 + y0Q4) >> SubpelBits) + SubpelTaps; int intermediateHeight = ((((h - 1) * yStepQ4) + y0Q4) >> SubpelBits) + SubpelTaps;
Debug.Assert(w <= 64); Debug.Assert(w <= 64);
Debug.Assert(h <= 64); Debug.Assert(h <= 64);
Debug.Assert(yStepQ4 <= 32); Debug.Assert(yStepQ4 <= 32);
Debug.Assert(xStepQ4 <= 32); Debug.Assert(xStepQ4 <= 32);
HighbdConvolveHoriz(src - srcStride * (SubpelTaps / 2 - 1), srcStride, temp, 64, filter, x0Q4, xStepQ4, w, intermediateHeight, bd); HighbdConvolveHoriz(src - (srcStride * ((SubpelTaps / 2) - 1)), srcStride, temp, 64, filter, x0Q4, xStepQ4,
HighbdConvolveVert(temp + 64 * (SubpelTaps / 2 - 1), 64, dst, dstStride, filter, y0Q4, yStepQ4, w, h, bd); w, intermediateHeight, bd);
HighbdConvolveVert(temp + (64 * ((SubpelTaps / 2) - 1)), 64, dst, dstStride, filter, y0Q4, yStepQ4, w, h,
bd);
} }
public static unsafe void HighbdConvolve8Horiz( public static unsafe void HighbdConvolve8Horiz(
@ -926,11 +932,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
int h, int h,
int bd) int bd)
{ {
int x, y; for (int y = 0; y < h; ++y)
for (y = 0; y < h; ++y)
{ {
for (x = 0; x < w; ++x) for (int x = 0; x < w; ++x)
{ {
dst[x] = (ushort)BitUtils.RoundPowerOfTwo(dst[x] + src[x], 1); dst[x] = (ushort)BitUtils.RoundPowerOfTwo(dst[x] + src[x], 1);
} }

View file

@ -6,22 +6,22 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
{ {
private static unsafe ref byte Dst(byte* dst, int stride, int x, int y) private static unsafe ref byte Dst(byte* dst, int stride, int x, int y)
{ {
return ref dst[x + y * stride]; return ref dst[x + (y * stride)];
} }
private static unsafe ref ushort Dst(ushort* dst, int stride, int x, int y) private static unsafe ref ushort Dst(ushort* dst, int stride, int x, int y)
{ {
return ref dst[x + y * stride]; return ref dst[x + (y * stride)];
} }
private static byte Avg3(byte a, byte b, byte c) private static byte Avg3(byte a, byte b, byte c)
{ {
return (byte)((a + 2 * b + c + 2) >> 2); return (byte)((a + (2 * b) + c + 2) >> 2);
} }
private static ushort Avg3(ushort a, ushort b, ushort c) private static ushort Avg3(ushort a, ushort b, ushort c)
{ {
return (ushort)((a + 2 * b + c + 2) >> 2); return (ushort)((a + (2 * b) + c + 2) >> 2);
} }
private static byte Avg2(byte a, byte b) private static byte Avg2(byte a, byte b)
@ -51,9 +51,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
private static unsafe void D207Predictor(byte* dst, int stride, int bs, byte* above, byte* left) private static unsafe void D207Predictor(byte* dst, int stride, int bs, byte* above, byte* left)
{ {
int r, c;
// First column // First column
for (r = 0; r < bs - 1; ++r) for (int r = 0; r < bs - 1; ++r)
{ {
dst[r * stride] = Avg2(left[r], left[r + 1]); dst[r * stride] = Avg2(left[r], left[r + 1]);
} }
@ -62,7 +61,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
dst++; dst++;
// Second column // Second column
for (r = 0; r < bs - 2; ++r) for (int r = 0; r < bs - 2; ++r)
{ {
dst[r * stride] = Avg3(left[r], left[r + 1], left[r + 2]); dst[r * stride] = Avg3(left[r], left[r + 1], left[r + 2]);
} }
@ -72,16 +71,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
dst++; dst++;
// Rest of last row // Rest of last row
for (c = 0; c < bs - 2; ++c) for (int c = 0; c < bs - 2; ++c)
{ {
dst[(bs - 1) * stride + c] = left[bs - 1]; dst[((bs - 1) * stride) + c] = left[bs - 1];
} }
for (r = bs - 2; r >= 0; --r) for (int r = bs - 2; r >= 0; --r)
{ {
for (c = 0; c < bs - 2; ++c) for (int c = 0; c < bs - 2; ++c)
{ {
dst[r * stride + c] = dst[(r + 1) * stride + c - 2]; dst[(r * stride) + c] = dst[((r + 1) * stride) + c - 2];
} }
} }
} }
@ -103,19 +102,18 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
private static unsafe void D63Predictor(byte* dst, int stride, int bs, byte* above, byte* left) private static unsafe void D63Predictor(byte* dst, int stride, int bs, byte* above, byte* left)
{ {
int r, c; for (int c = 0; c < bs; ++c)
int size;
for (c = 0; c < bs; ++c)
{ {
dst[c] = Avg2(above[c], above[c + 1]); dst[c] = Avg2(above[c], above[c + 1]);
dst[stride + c] = Avg3(above[c], above[c + 1], above[c + 2]); dst[stride + c] = Avg3(above[c], above[c + 1], above[c + 2]);
} }
for (r = 2, size = bs - 2; r < bs; r += 2, --size)
for (int r = 2, size = bs - 2; r < bs; r += 2, --size)
{ {
MemoryUtil.Copy(dst + (r + 0) * stride, dst + (r >> 1), size); MemoryUtil.Copy(dst + ((r + 0) * stride), dst + (r >> 1), size);
MemoryUtil.Fill(dst + (r + 0) * stride + size, above[bs - 1], bs - size); MemoryUtil.Fill(dst + ((r + 0) * stride) + size, above[bs - 1], bs - size);
MemoryUtil.Copy(dst + (r + 1) * stride, dst + stride + (r >> 1), size); MemoryUtil.Copy(dst + ((r + 1) * stride), dst + stride + (r >> 1), size);
MemoryUtil.Fill(dst + (r + 1) * stride + size, above[bs - 1], bs - size); MemoryUtil.Fill(dst + ((r + 1) * stride) + size, above[bs - 1], bs - size);
} }
} }
@ -138,15 +136,15 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
{ {
byte aboveRight = above[bs - 1]; byte aboveRight = above[bs - 1];
byte* dstRow0 = dst; byte* dstRow0 = dst;
int x, size;
for (x = 0; x < bs - 1; ++x) for (int x = 0; x < bs - 1; ++x)
{ {
dst[x] = Avg3(above[x], above[x + 1], above[x + 2]); dst[x] = Avg3(above[x], above[x + 1], above[x + 2]);
} }
dst[bs - 1] = aboveRight; dst[bs - 1] = aboveRight;
dst += stride; dst += stride;
for (x = 1, size = bs - 2; x < bs; ++x, --size) for (int x = 1, size = bs - 2; x < bs; ++x, --size)
{ {
MemoryUtil.Copy(dst, dstRow0 + x, size); MemoryUtil.Copy(dst, dstRow0 + x, size);
MemoryUtil.Fill(dst + size, aboveRight, x + 1); MemoryUtil.Fill(dst + size, aboveRight, x + 1);
@ -171,10 +169,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
private static unsafe void D117Predictor(byte* dst, int stride, int bs, byte* above, byte* left) private static unsafe void D117Predictor(byte* dst, int stride, int bs, byte* above, byte* left)
{ {
int r, c;
// First row // First row
for (c = 0; c < bs; c++) for (int c = 0; c < bs; c++)
{ {
dst[c] = Avg2(above[c - 1], above[c]); dst[c] = Avg2(above[c - 1], above[c]);
} }
@ -183,7 +179,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
// Second row // Second row
dst[0] = Avg3(left[0], above[-1], above[0]); dst[0] = Avg3(left[0], above[-1], above[0]);
for (c = 1; c < bs; c++) for (int c = 1; c < bs; c++)
{ {
dst[c] = Avg3(above[c - 2], above[c - 1], above[c]); dst[c] = Avg3(above[c - 2], above[c - 1], above[c]);
} }
@ -192,17 +188,17 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
// The rest of first col // The rest of first col
dst[0] = Avg3(above[-1], left[0], left[1]); dst[0] = Avg3(above[-1], left[0], left[1]);
for (r = 3; r < bs; ++r) for (int r = 3; r < bs; ++r)
{ {
dst[(r - 2) * stride] = Avg3(left[r - 3], left[r - 2], left[r - 1]); dst[(r - 2) * stride] = Avg3(left[r - 3], left[r - 2], left[r - 1]);
} }
// The rest of the block // The rest of the block
for (r = 2; r < bs; ++r) for (int r = 2; r < bs; ++r)
{ {
for (c = 1; c < bs; c++) for (int c = 1; c < bs; c++)
{ {
dst[c] = dst[-2 * stride + c - 1]; dst[c] = dst[(-2 * stride) + c - 1];
} }
dst += stride; dst += stride;
@ -226,26 +222,26 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
private static unsafe void D135Predictor(byte* dst, int stride, int bs, byte* above, byte* left) private static unsafe void D135Predictor(byte* dst, int stride, int bs, byte* above, byte* left)
{ {
int i;
byte* border = stackalloc byte[32 + 32 - 1]; // outer border from bottom-left to top-right byte* border = stackalloc byte[32 + 32 - 1]; // outer border from bottom-left to top-right
// Dst(dst, stride, bs, bs - 2)[0], i.e., border starting at bottom-left // Dst(dst, stride, bs, bs - 2)[0], i.e., border starting at bottom-left
for (i = 0; i < bs - 2; ++i) for (int i = 0; i < bs - 2; ++i)
{ {
border[i] = Avg3(left[bs - 3 - i], left[bs - 2 - i], left[bs - 1 - i]); border[i] = Avg3(left[bs - 3 - i], left[bs - 2 - i], left[bs - 1 - i]);
} }
border[bs - 2] = Avg3(above[-1], left[0], left[1]); border[bs - 2] = Avg3(above[-1], left[0], left[1]);
border[bs - 1] = Avg3(left[0], above[-1], above[0]); border[bs - 1] = Avg3(left[0], above[-1], above[0]);
border[bs - 0] = Avg3(above[-1], above[0], above[1]); border[bs - 0] = Avg3(above[-1], above[0], above[1]);
// dst[0][2, size), i.e., remaining top border ascending // dst[0][2, size), i.e., remaining top border ascending
for (i = 0; i < bs - 2; ++i) for (int i = 0; i < bs - 2; ++i)
{ {
border[bs + 1 + i] = Avg3(above[i], above[i + 1], above[i + 2]); border[bs + 1 + i] = Avg3(above[i], above[i + 1], above[i + 2]);
} }
for (i = 0; i < bs; ++i) for (int i = 0; i < bs; ++i)
{ {
MemoryUtil.Copy(dst + i * stride, border + bs - 1 - i, bs); MemoryUtil.Copy(dst + (i * stride), border + bs - 1 - i, bs);
} }
} }
@ -266,9 +262,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
private static unsafe void D153Predictor(byte* dst, int stride, int bs, byte* above, byte* left) private static unsafe void D153Predictor(byte* dst, int stride, int bs, byte* above, byte* left)
{ {
int r, c;
dst[0] = Avg2(above[-1], left[0]); dst[0] = Avg2(above[-1], left[0]);
for (r = 1; r < bs; r++) for (int r = 1; r < bs; r++)
{ {
dst[r * stride] = Avg2(left[r - 1], left[r]); dst[r * stride] = Avg2(left[r - 1], left[r]);
} }
@ -277,23 +272,23 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
dst[0] = Avg3(left[0], above[-1], above[0]); dst[0] = Avg3(left[0], above[-1], above[0]);
dst[stride] = Avg3(above[-1], left[0], left[1]); dst[stride] = Avg3(above[-1], left[0], left[1]);
for (r = 2; r < bs; r++) for (int r = 2; r < bs; r++)
{ {
dst[r * stride] = Avg3(left[r - 2], left[r - 1], left[r]); dst[r * stride] = Avg3(left[r - 2], left[r - 1], left[r]);
} }
dst++; dst++;
for (c = 0; c < bs - 2; c++) for (int c = 0; c < bs - 2; c++)
{ {
dst[c] = Avg3(above[c - 1], above[c], above[c + 1]); dst[c] = Avg3(above[c - 1], above[c], above[c + 1]);
} }
dst += stride; dst += stride;
for (r = 1; r < bs; ++r) for (int r = 1; r < bs; ++r)
{ {
for (c = 0; c < bs - 2; c++) for (int c = 0; c < bs - 2; c++)
{ {
dst[c] = dst[-stride + c - 2]; dst[c] = dst[-stride + c - 2];
} }
@ -324,9 +319,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
private static unsafe void VPredictor(byte* dst, int stride, int bs, byte* above, byte* left) private static unsafe void VPredictor(byte* dst, int stride, int bs, byte* above, byte* left)
{ {
int r; for (int r = 0; r < bs; r++)
for (r = 0; r < bs; r++)
{ {
MemoryUtil.Copy(dst, above, bs); MemoryUtil.Copy(dst, above, bs);
dst += stride; dst += stride;
@ -355,43 +348,40 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
private static unsafe void HPredictor(byte* dst, int stride, int bs, byte* above, byte* left) private static unsafe void HPredictor(byte* dst, int stride, int bs, byte* above, byte* left)
{ {
int r; for (int r = 0; r < bs; r++)
for (r = 0; r < bs; r++)
{ {
MemoryUtil.Fill(dst, left[r], bs); MemoryUtil.Fill(dst, left[r], bs);
dst += stride; dst += stride;
} }
} }
public static unsafe void TMPredictor4x4(byte* dst, int stride, byte* above, byte* left) public static unsafe void TmPredictor4x4(byte* dst, int stride, byte* above, byte* left)
{ {
TMPredictor(dst, stride, 4, above, left); TmPredictor(dst, stride, 4, above, left);
} }
public static unsafe void TMPredictor8x8(byte* dst, int stride, byte* above, byte* left) public static unsafe void TmPredictor8x8(byte* dst, int stride, byte* above, byte* left)
{ {
TMPredictor(dst, stride, 8, above, left); TmPredictor(dst, stride, 8, above, left);
} }
public static unsafe void TMPredictor16x16(byte* dst, int stride, byte* above, byte* left) public static unsafe void TmPredictor16x16(byte* dst, int stride, byte* above, byte* left)
{ {
TMPredictor(dst, stride, 16, above, left); TmPredictor(dst, stride, 16, above, left);
} }
public static unsafe void TMPredictor32x32(byte* dst, int stride, byte* above, byte* left) public static unsafe void TmPredictor32x32(byte* dst, int stride, byte* above, byte* left)
{ {
TMPredictor(dst, stride, 32, above, left); TmPredictor(dst, stride, 32, above, left);
} }
private static unsafe void TMPredictor(byte* dst, int stride, int bs, byte* above, byte* left) private static unsafe void TmPredictor(byte* dst, int stride, int bs, byte* above, byte* left)
{ {
int r, c;
int yTopLeft = above[-1]; int yTopLeft = above[-1];
for (r = 0; r < bs; r++) for (int r = 0; r < bs; r++)
{ {
for (c = 0; c < bs; c++) for (int c = 0; c < bs; c++)
{ {
dst[c] = BitUtils.ClipPixel(left[r] + above[c] - yTopLeft); dst[c] = BitUtils.ClipPixel(left[r] + above[c] - yTopLeft);
} }
@ -422,9 +412,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
private static unsafe void Dc128Predictor(byte* dst, int stride, int bs, byte* above, byte* left) private static unsafe void Dc128Predictor(byte* dst, int stride, int bs, byte* above, byte* left)
{ {
int r; for (int r = 0; r < bs; r++)
for (r = 0; r < bs; r++)
{ {
MemoryUtil.Fill(dst, (byte)128, bs); MemoryUtil.Fill(dst, (byte)128, bs);
dst += stride; dst += stride;
@ -453,16 +441,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
private static unsafe void DcLeftPredictor(byte* dst, int stride, int bs, byte* above, byte* left) private static unsafe void DcLeftPredictor(byte* dst, int stride, int bs, byte* above, byte* left)
{ {
int i, r, expectedDc, sum = 0; int expectedDc, sum = 0;
for (i = 0; i < bs; i++) for (int i = 0; i < bs; i++)
{ {
sum += left[i]; sum += left[i];
} }
expectedDc = (sum + (bs >> 1)) / bs; expectedDc = (sum + (bs >> 1)) / bs;
for (r = 0; r < bs; r++) for (int r = 0; r < bs; r++)
{ {
MemoryUtil.Fill(dst, (byte)expectedDc, bs); MemoryUtil.Fill(dst, (byte)expectedDc, bs);
dst += stride; dst += stride;
@ -491,16 +479,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
private static unsafe void DcTopPredictor(byte* dst, int stride, int bs, byte* above, byte* left) private static unsafe void DcTopPredictor(byte* dst, int stride, int bs, byte* above, byte* left)
{ {
int i, r, expectedDc, sum = 0; int expectedDc, sum = 0;
for (i = 0; i < bs; i++) for (int i = 0; i < bs; i++)
{ {
sum += above[i]; sum += above[i];
} }
expectedDc = (sum + (bs >> 1)) / bs; expectedDc = (sum + (bs >> 1)) / bs;
for (r = 0; r < bs; r++) for (int r = 0; r < bs; r++)
{ {
MemoryUtil.Fill(dst, (byte)expectedDc, bs); MemoryUtil.Fill(dst, (byte)expectedDc, bs);
dst += stride; dst += stride;
@ -529,10 +517,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
private static unsafe void DcPredictor(byte* dst, int stride, int bs, byte* above, byte* left) private static unsafe void DcPredictor(byte* dst, int stride, int bs, byte* above, byte* left)
{ {
int i, r, expectedDc, sum = 0; int expectedDc, sum = 0;
int count = 2 * bs; int count = 2 * bs;
for (i = 0; i < bs; i++) for (int i = 0; i < bs; i++)
{ {
sum += above[i]; sum += above[i];
sum += left[i]; sum += left[i];
@ -540,7 +528,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
expectedDc = (sum + (count >> 1)) / count; expectedDc = (sum + (count >> 1)) / count;
for (r = 0; r < bs; r++) for (int r = 0; r < bs; r++)
{ {
MemoryUtil.Fill(dst, (byte)expectedDc, bs); MemoryUtil.Fill(dst, (byte)expectedDc, bs);
dst += stride; dst += stride;
@ -555,10 +543,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
byte k = left[2]; byte k = left[2];
byte l = left[3]; byte l = left[3];
MemoryUtil.Fill(dst + stride * 0, Avg3(h, I, j), 4); MemoryUtil.Fill(dst + (stride * 0), Avg3(h, I, j), 4);
MemoryUtil.Fill(dst + stride * 1, Avg3(I, j, k), 4); MemoryUtil.Fill(dst + (stride * 1), Avg3(I, j, k), 4);
MemoryUtil.Fill(dst + stride * 2, Avg3(j, k, l), 4); MemoryUtil.Fill(dst + (stride * 2), Avg3(j, k, l), 4);
MemoryUtil.Fill(dst + stride * 3, Avg3(k, l, l), 4); MemoryUtil.Fill(dst + (stride * 3), Avg3(k, l, l), 4);
} }
public static unsafe void VePredictor4x4(byte* dst, int stride, byte* above, byte* left) public static unsafe void VePredictor4x4(byte* dst, int stride, byte* above, byte* left)
@ -574,9 +562,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
dst[1] = Avg3(I, j, k); dst[1] = Avg3(I, j, k);
dst[2] = Avg3(j, k, l); dst[2] = Avg3(j, k, l);
dst[3] = Avg3(k, l, m); dst[3] = Avg3(k, l, m);
MemoryUtil.Copy(dst + stride * 1, dst, 4); MemoryUtil.Copy(dst + (stride * 1), dst, 4);
MemoryUtil.Copy(dst + stride * 2, dst, 4); MemoryUtil.Copy(dst + (stride * 2), dst, 4);
MemoryUtil.Copy(dst + stride * 3, dst, 4); MemoryUtil.Copy(dst + (stride * 3), dst, 4);
} }
public static unsafe void D207Predictor4x4(byte* dst, int stride, byte* above, byte* left) public static unsafe void D207Predictor4x4(byte* dst, int stride, byte* above, byte* left)
@ -591,7 +579,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
Dst(dst, stride, 1, 0) = Avg3(I, j, k); Dst(dst, stride, 1, 0) = Avg3(I, j, k);
Dst(dst, stride, 3, 0) = Dst(dst, stride, 1, 1) = Avg3(j, k, l); Dst(dst, stride, 3, 0) = Dst(dst, stride, 1, 1) = Avg3(j, k, l);
Dst(dst, stride, 3, 1) = Dst(dst, stride, 1, 2) = Avg3(k, l, l); Dst(dst, stride, 3, 1) = Dst(dst, stride, 1, 2) = Avg3(k, l, l);
Dst(dst, stride, 3, 2) = Dst(dst, stride, 2, 2) = Dst(dst, stride, 0, 3) = Dst(dst, stride, 1, 3) = Dst(dst, stride, 2, 3) = Dst(dst, stride, 3, 3) = l; Dst(dst, stride, 3, 2) = Dst(dst, stride, 2, 2) = Dst(dst, stride, 0, 3) =
Dst(dst, stride, 1, 3) = Dst(dst, stride, 2, 3) = Dst(dst, stride, 3, 3) = l;
} }
public static unsafe void D63Predictor4x4(byte* dst, int stride, byte* above, byte* left) public static unsafe void D63Predictor4x4(byte* dst, int stride, byte* above, byte* left)
@ -616,7 +605,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
Dst(dst, stride, 3, 3) = Avg3(e, f, g); // Differs from vp8 Dst(dst, stride, 3, 3) = Avg3(e, f, g); // Differs from vp8
} }
public static unsafe void D63ePredictor4x4(byte* dst, int stride, byte* above, byte* left) public static unsafe void D63EPredictor4x4(byte* dst, int stride, byte* above, byte* left)
{ {
byte a = above[0]; byte a = above[0];
byte b = above[1]; byte b = above[1];
@ -652,13 +641,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
Dst(dst, stride, 0, 0) = Avg3(a, b, c); Dst(dst, stride, 0, 0) = Avg3(a, b, c);
Dst(dst, stride, 1, 0) = Dst(dst, stride, 0, 1) = Avg3(b, c, d); Dst(dst, stride, 1, 0) = Dst(dst, stride, 0, 1) = Avg3(b, c, d);
Dst(dst, stride, 2, 0) = Dst(dst, stride, 1, 1) = Dst(dst, stride, 0, 2) = Avg3(c, d, e); Dst(dst, stride, 2, 0) = Dst(dst, stride, 1, 1) = Dst(dst, stride, 0, 2) = Avg3(c, d, e);
Dst(dst, stride, 3, 0) = Dst(dst, stride, 2, 1) = Dst(dst, stride, 1, 2) = Dst(dst, stride, 0, 3) = Avg3(d, e, f); Dst(dst, stride, 3, 0) =
Dst(dst, stride, 2, 1) = Dst(dst, stride, 1, 2) = Dst(dst, stride, 0, 3) = Avg3(d, e, f);
Dst(dst, stride, 3, 1) = Dst(dst, stride, 2, 2) = Dst(dst, stride, 1, 3) = Avg3(e, f, g); Dst(dst, stride, 3, 1) = Dst(dst, stride, 2, 2) = Dst(dst, stride, 1, 3) = Avg3(e, f, g);
Dst(dst, stride, 3, 2) = Dst(dst, stride, 2, 3) = Avg3(f, g, h); Dst(dst, stride, 3, 2) = Dst(dst, stride, 2, 3) = Avg3(f, g, h);
Dst(dst, stride, 3, 3) = h; // differs from vp8 Dst(dst, stride, 3, 3) = h; // differs from vp8
} }
public static unsafe void D45ePredictor4x4(byte* dst, int stride, byte* above, byte* left) public static unsafe void D45EPredictor4x4(byte* dst, int stride, byte* above, byte* left)
{ {
byte a = above[0]; byte a = above[0];
byte b = above[1]; byte b = above[1];
@ -671,7 +661,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
Dst(dst, stride, 0, 0) = Avg3(a, b, c); Dst(dst, stride, 0, 0) = Avg3(a, b, c);
Dst(dst, stride, 1, 0) = Dst(dst, stride, 0, 1) = Avg3(b, c, d); Dst(dst, stride, 1, 0) = Dst(dst, stride, 0, 1) = Avg3(b, c, d);
Dst(dst, stride, 2, 0) = Dst(dst, stride, 1, 1) = Dst(dst, stride, 0, 2) = Avg3(c, d, e); Dst(dst, stride, 2, 0) = Dst(dst, stride, 1, 1) = Dst(dst, stride, 0, 2) = Avg3(c, d, e);
Dst(dst, stride, 3, 0) = Dst(dst, stride, 2, 1) = Dst(dst, stride, 1, 2) = Dst(dst, stride, 0, 3) = Avg3(d, e, f); Dst(dst, stride, 3, 0) =
Dst(dst, stride, 2, 1) = Dst(dst, stride, 1, 2) = Dst(dst, stride, 0, 3) = Avg3(d, e, f);
Dst(dst, stride, 3, 1) = Dst(dst, stride, 2, 2) = Dst(dst, stride, 1, 3) = Avg3(e, f, g); Dst(dst, stride, 3, 1) = Dst(dst, stride, 2, 2) = Dst(dst, stride, 1, 3) = Avg3(e, f, g);
Dst(dst, stride, 3, 2) = Dst(dst, stride, 2, 3) = Avg3(f, g, h); Dst(dst, stride, 3, 2) = Dst(dst, stride, 2, 3) = Avg3(f, g, h);
Dst(dst, stride, 3, 3) = Avg3(g, h, h); Dst(dst, stride, 3, 3) = Avg3(g, h, h);
@ -714,7 +705,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
Dst(dst, stride, 0, 3) = Avg3(j, k, l); Dst(dst, stride, 0, 3) = Avg3(j, k, l);
Dst(dst, stride, 1, 3) = Dst(dst, stride, 0, 2) = Avg3(I, j, k); Dst(dst, stride, 1, 3) = Dst(dst, stride, 0, 2) = Avg3(I, j, k);
Dst(dst, stride, 2, 3) = Dst(dst, stride, 1, 2) = Dst(dst, stride, 0, 1) = Avg3(x, I, j); Dst(dst, stride, 2, 3) = Dst(dst, stride, 1, 2) = Dst(dst, stride, 0, 1) = Avg3(x, I, j);
Dst(dst, stride, 3, 3) = Dst(dst, stride, 2, 2) = Dst(dst, stride, 1, 1) = Dst(dst, stride, 0, 0) = Avg3(a, x, I); Dst(dst, stride, 3, 3) =
Dst(dst, stride, 2, 2) = Dst(dst, stride, 1, 1) = Dst(dst, stride, 0, 0) = Avg3(a, x, I);
Dst(dst, stride, 3, 2) = Dst(dst, stride, 2, 1) = Dst(dst, stride, 1, 0) = Avg3(b, a, x); Dst(dst, stride, 3, 2) = Dst(dst, stride, 2, 1) = Dst(dst, stride, 1, 0) = Avg3(b, a, x);
Dst(dst, stride, 3, 1) = Dst(dst, stride, 2, 0) = Avg3(c, b, a); Dst(dst, stride, 3, 1) = Dst(dst, stride, 2, 0) = Avg3(c, b, a);
Dst(dst, stride, 3, 0) = Avg3(d, c, b); Dst(dst, stride, 3, 0) = Avg3(d, c, b);
@ -758,38 +750,39 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
HighbdD207Predictor(dst, stride, 32, above, left, bd); HighbdD207Predictor(dst, stride, 32, above, left, bd);
} }
private static unsafe void HighbdD207Predictor(ushort* dst, int stride, int bs, ushort* above, ushort* left, int bd) private static unsafe void HighbdD207Predictor(ushort* dst, int stride, int bs, ushort* above, ushort* left,
int bd)
{ {
int r, c;
// First column. // First column.
for (r = 0; r < bs - 1; ++r) for (int r = 0; r < bs - 1; ++r)
{ {
dst[r * stride] = Avg2(left[r], left[r + 1]); dst[r * stride] = Avg2(left[r], left[r + 1]);
} }
dst[(bs - 1) * stride] = left[bs - 1]; dst[(bs - 1) * stride] = left[bs - 1];
dst++; dst++;
// Second column. // Second column.
for (r = 0; r < bs - 2; ++r) for (int r = 0; r < bs - 2; ++r)
{ {
dst[r * stride] = Avg3(left[r], left[r + 1], left[r + 2]); dst[r * stride] = Avg3(left[r], left[r + 1], left[r + 2]);
} }
dst[(bs - 2) * stride] = Avg3(left[bs - 2], left[bs - 1], left[bs - 1]); dst[(bs - 2) * stride] = Avg3(left[bs - 2], left[bs - 1], left[bs - 1]);
dst[(bs - 1) * stride] = left[bs - 1]; dst[(bs - 1) * stride] = left[bs - 1];
dst++; dst++;
// Rest of last row. // Rest of last row.
for (c = 0; c < bs - 2; ++c) for (int c = 0; c < bs - 2; ++c)
{ {
dst[(bs - 1) * stride + c] = left[bs - 1]; dst[((bs - 1) * stride) + c] = left[bs - 1];
} }
for (r = bs - 2; r >= 0; --r) for (int r = bs - 2; r >= 0; --r)
{ {
for (c = 0; c < bs - 2; ++c) for (int c = 0; c < bs - 2; ++c)
{ {
dst[r * stride + c] = dst[(r + 1) * stride + c - 2]; dst[(r * stride) + c] = dst[((r + 1) * stride) + c - 2];
} }
} }
} }
@ -809,21 +802,21 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
HighbdD63Predictor(dst, stride, 32, above, left, bd); HighbdD63Predictor(dst, stride, 32, above, left, bd);
} }
private static unsafe void HighbdD63Predictor(ushort* dst, int stride, int bs, ushort* above, ushort* left, int bd) private static unsafe void HighbdD63Predictor(ushort* dst, int stride, int bs, ushort* above, ushort* left,
int bd)
{ {
int r, c; for (int c = 0; c < bs; ++c)
int size;
for (c = 0; c < bs; ++c)
{ {
dst[c] = Avg2(above[c], above[c + 1]); dst[c] = Avg2(above[c], above[c + 1]);
dst[stride + c] = Avg3(above[c], above[c + 1], above[c + 2]); dst[stride + c] = Avg3(above[c], above[c + 1], above[c + 2]);
} }
for (r = 2, size = bs - 2; r < bs; r += 2, --size)
for (int r = 2, size = bs - 2; r < bs; r += 2, --size)
{ {
MemoryUtil.Copy(dst + (r + 0) * stride, dst + (r >> 1), size); MemoryUtil.Copy(dst + ((r + 0) * stride), dst + (r >> 1), size);
MemoryUtil.Fill(dst + (r + 0) * stride + size, above[bs - 1], bs - size); MemoryUtil.Fill(dst + ((r + 0) * stride) + size, above[bs - 1], bs - size);
MemoryUtil.Copy(dst + (r + 1) * stride, dst + stride + (r >> 1), size); MemoryUtil.Copy(dst + ((r + 1) * stride), dst + stride + (r >> 1), size);
MemoryUtil.Fill(dst + (r + 1) * stride + size, above[bs - 1], bs - size); MemoryUtil.Fill(dst + ((r + 1) * stride) + size, above[bs - 1], bs - size);
} }
} }
@ -842,19 +835,20 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
HighbdD45Predictor(dst, stride, 32, above, left, bd); HighbdD45Predictor(dst, stride, 32, above, left, bd);
} }
private static unsafe void HighbdD45Predictor(ushort* dst, int stride, int bs, ushort* above, ushort* left, int bd) private static unsafe void HighbdD45Predictor(ushort* dst, int stride, int bs, ushort* above, ushort* left,
int bd)
{ {
ushort aboveRight = above[bs - 1]; ushort aboveRight = above[bs - 1];
ushort* dstRow0 = dst; ushort* dstRow0 = dst;
int x, size;
for (x = 0; x < bs - 1; ++x) for (int x = 0; x < bs - 1; ++x)
{ {
dst[x] = Avg3(above[x], above[x + 1], above[x + 2]); dst[x] = Avg3(above[x], above[x + 1], above[x + 2]);
} }
dst[bs - 1] = aboveRight; dst[bs - 1] = aboveRight;
dst += stride; dst += stride;
for (x = 1, size = bs - 2; x < bs; ++x, --size) for (int x = 1, size = bs - 2; x < bs; ++x, --size)
{ {
MemoryUtil.Copy(dst, dstRow0 + x, size); MemoryUtil.Copy(dst, dstRow0 + x, size);
MemoryUtil.Fill(dst + size, aboveRight, x + 1); MemoryUtil.Fill(dst + size, aboveRight, x + 1);
@ -877,12 +871,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
HighbdD117Predictor(dst, stride, 32, above, left, bd); HighbdD117Predictor(dst, stride, 32, above, left, bd);
} }
private static unsafe void HighbdD117Predictor(ushort* dst, int stride, int bs, ushort* above, ushort* left, int bd) private static unsafe void HighbdD117Predictor(ushort* dst, int stride, int bs, ushort* above, ushort* left,
int bd)
{ {
int r, c;
// First row // First row
for (c = 0; c < bs; c++) for (int c = 0; c < bs; c++)
{ {
dst[c] = Avg2(above[c - 1], above[c]); dst[c] = Avg2(above[c - 1], above[c]);
} }
@ -891,7 +884,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
// Second row // Second row
dst[0] = Avg3(left[0], above[-1], above[0]); dst[0] = Avg3(left[0], above[-1], above[0]);
for (c = 1; c < bs; c++) for (int c = 1; c < bs; c++)
{ {
dst[c] = Avg3(above[c - 2], above[c - 1], above[c]); dst[c] = Avg3(above[c - 2], above[c - 1], above[c]);
} }
@ -900,17 +893,17 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
// The rest of first col // The rest of first col
dst[0] = Avg3(above[-1], left[0], left[1]); dst[0] = Avg3(above[-1], left[0], left[1]);
for (r = 3; r < bs; ++r) for (int r = 3; r < bs; ++r)
{ {
dst[(r - 2) * stride] = Avg3(left[r - 3], left[r - 2], left[r - 1]); dst[(r - 2) * stride] = Avg3(left[r - 3], left[r - 2], left[r - 1]);
} }
// The rest of the block // The rest of the block
for (r = 2; r < bs; ++r) for (int r = 2; r < bs; ++r)
{ {
for (c = 1; c < bs; c++) for (int c = 1; c < bs; c++)
{ {
dst[c] = dst[-2 * stride + c - 1]; dst[c] = dst[(-2 * stride) + c - 1];
} }
dst += stride; dst += stride;
@ -932,28 +925,29 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
HighbdD135Predictor(dst, stride, 32, above, left, bd); HighbdD135Predictor(dst, stride, 32, above, left, bd);
} }
private static unsafe void HighbdD135Predictor(ushort* dst, int stride, int bs, ushort* above, ushort* left, int bd) private static unsafe void HighbdD135Predictor(ushort* dst, int stride, int bs, ushort* above, ushort* left,
int bd)
{ {
int i;
ushort* border = stackalloc ushort[32 + 32 - 1]; // Outer border from bottom-left to top-right ushort* border = stackalloc ushort[32 + 32 - 1]; // Outer border from bottom-left to top-right
// Dst(dst, stride, bs, bs - 2)[0], i.e., border starting at bottom-left // Dst(dst, stride, bs, bs - 2)[0], i.e., border starting at bottom-left
for (i = 0; i < bs - 2; ++i) for (int i = 0; i < bs - 2; ++i)
{ {
border[i] = Avg3(left[bs - 3 - i], left[bs - 2 - i], left[bs - 1 - i]); border[i] = Avg3(left[bs - 3 - i], left[bs - 2 - i], left[bs - 1 - i]);
} }
border[bs - 2] = Avg3(above[-1], left[0], left[1]); border[bs - 2] = Avg3(above[-1], left[0], left[1]);
border[bs - 1] = Avg3(left[0], above[-1], above[0]); border[bs - 1] = Avg3(left[0], above[-1], above[0]);
border[bs - 0] = Avg3(above[-1], above[0], above[1]); border[bs - 0] = Avg3(above[-1], above[0], above[1]);
// dst[0][2, size), i.e., remaining top border ascending // dst[0][2, size), i.e., remaining top border ascending
for (i = 0; i < bs - 2; ++i) for (int i = 0; i < bs - 2; ++i)
{ {
border[bs + 1 + i] = Avg3(above[i], above[i + 1], above[i + 2]); border[bs + 1 + i] = Avg3(above[i], above[i + 1], above[i + 2]);
} }
for (i = 0; i < bs; ++i) for (int i = 0; i < bs; ++i)
{ {
MemoryUtil.Copy(dst + i * stride, border + bs - 1 - i, bs); MemoryUtil.Copy(dst + (i * stride), border + bs - 1 - i, bs);
} }
} }
@ -972,11 +966,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
HighbdD153Predictor(dst, stride, 32, above, left, bd); HighbdD153Predictor(dst, stride, 32, above, left, bd);
} }
private static unsafe void HighbdD153Predictor(ushort* dst, int stride, int bs, ushort* above, ushort* left, int bd) private static unsafe void HighbdD153Predictor(ushort* dst, int stride, int bs, ushort* above, ushort* left,
int bd)
{ {
int r, c;
dst[0] = Avg2(above[-1], left[0]); dst[0] = Avg2(above[-1], left[0]);
for (r = 1; r < bs; r++) for (int r = 1; r < bs; r++)
{ {
dst[r * stride] = Avg2(left[r - 1], left[r]); dst[r * stride] = Avg2(left[r - 1], left[r]);
} }
@ -985,23 +979,23 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
dst[0] = Avg3(left[0], above[-1], above[0]); dst[0] = Avg3(left[0], above[-1], above[0]);
dst[stride] = Avg3(above[-1], left[0], left[1]); dst[stride] = Avg3(above[-1], left[0], left[1]);
for (r = 2; r < bs; r++) for (int r = 2; r < bs; r++)
{ {
dst[r * stride] = Avg3(left[r - 2], left[r - 1], left[r]); dst[r * stride] = Avg3(left[r - 2], left[r - 1], left[r]);
} }
dst++; dst++;
for (c = 0; c < bs - 2; c++) for (int c = 0; c < bs - 2; c++)
{ {
dst[c] = Avg3(above[c - 1], above[c], above[c + 1]); dst[c] = Avg3(above[c - 1], above[c], above[c + 1]);
} }
dst += stride; dst += stride;
for (r = 1; r < bs; ++r) for (int r = 1; r < bs; ++r)
{ {
for (c = 0; c < bs - 2; c++) for (int c = 0; c < bs - 2; c++)
{ {
dst[c] = dst[-stride + c - 2]; dst[c] = dst[-stride + c - 2];
} }
@ -1030,10 +1024,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
HighbdVPredictor(dst, stride, 32, above, left, bd); HighbdVPredictor(dst, stride, 32, above, left, bd);
} }
private static unsafe void HighbdVPredictor(ushort* dst, int stride, int bs, ushort* above, ushort* left, int bd) private static unsafe void HighbdVPredictor(ushort* dst, int stride, int bs, ushort* above, ushort* left,
int bd)
{ {
int r; for (int r = 0; r < bs; r++)
for (r = 0; r < bs; r++)
{ {
MemoryUtil.Copy(dst, above, bs); MemoryUtil.Copy(dst, above, bs);
dst += stride; dst += stride;
@ -1060,44 +1054,44 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
HighbdHPredictor(dst, stride, 32, above, left, bd); HighbdHPredictor(dst, stride, 32, above, left, bd);
} }
private static unsafe void HighbdHPredictor(ushort* dst, int stride, int bs, ushort* above, ushort* left, int bd) private static unsafe void HighbdHPredictor(ushort* dst, int stride, int bs, ushort* above, ushort* left,
int bd)
{ {
int r; for (int r = 0; r < bs; r++)
for (r = 0; r < bs; r++)
{ {
MemoryUtil.Fill(dst, left[r], bs); MemoryUtil.Fill(dst, left[r], bs);
dst += stride; dst += stride;
} }
} }
public static unsafe void HighbdTMPredictor4x4(ushort* dst, int stride, ushort* above, ushort* left, int bd) public static unsafe void HighbdTmPredictor4x4(ushort* dst, int stride, ushort* above, ushort* left, int bd)
{ {
HighbdTMPredictor(dst, stride, 4, above, left, bd); HighbdTmPredictor(dst, stride, 4, above, left, bd);
} }
public static unsafe void HighbdTMPredictor8x8(ushort* dst, int stride, ushort* above, ushort* left, int bd) public static unsafe void HighbdTmPredictor8x8(ushort* dst, int stride, ushort* above, ushort* left, int bd)
{ {
HighbdTMPredictor(dst, stride, 8, above, left, bd); HighbdTmPredictor(dst, stride, 8, above, left, bd);
} }
public static unsafe void HighbdTMPredictor16x16(ushort* dst, int stride, ushort* above, ushort* left, int bd) public static unsafe void HighbdTmPredictor16x16(ushort* dst, int stride, ushort* above, ushort* left, int bd)
{ {
HighbdTMPredictor(dst, stride, 16, above, left, bd); HighbdTmPredictor(dst, stride, 16, above, left, bd);
} }
public static unsafe void HighbdTMPredictor32x32(ushort* dst, int stride, ushort* above, ushort* left, int bd) public static unsafe void HighbdTmPredictor32x32(ushort* dst, int stride, ushort* above, ushort* left, int bd)
{ {
HighbdTMPredictor(dst, stride, 32, above, left, bd); HighbdTmPredictor(dst, stride, 32, above, left, bd);
} }
private static unsafe void HighbdTMPredictor(ushort* dst, int stride, int bs, ushort* above, ushort* left, int bd) private static unsafe void HighbdTmPredictor(ushort* dst, int stride, int bs, ushort* above, ushort* left,
int bd)
{ {
int r, c;
int yTopLeft = above[-1]; int yTopLeft = above[-1];
for (r = 0; r < bs; r++) for (int r = 0; r < bs; r++)
{ {
for (c = 0; c < bs; c++) for (int c = 0; c < bs; c++)
{ {
dst[c] = BitUtils.ClipPixelHighbd(left[r] + above[c] - yTopLeft, bd); dst[c] = BitUtils.ClipPixelHighbd(left[r] + above[c] - yTopLeft, bd);
} }
@ -1116,21 +1110,22 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
HighbdDc128Predictor(dst, stride, 8, above, left, bd); HighbdDc128Predictor(dst, stride, 8, above, left, bd);
} }
public static unsafe void HighbdDc128Predictor16x16(ushort* dst, int stride, ushort* above, ushort* left, int bd) public static unsafe void HighbdDc128Predictor16x16(ushort* dst, int stride, ushort* above, ushort* left,
int bd)
{ {
HighbdDc128Predictor(dst, stride, 16, above, left, bd); HighbdDc128Predictor(dst, stride, 16, above, left, bd);
} }
public static unsafe void HighbdDc128Predictor32x32(ushort* dst, int stride, ushort* above, ushort* left, int bd) public static unsafe void HighbdDc128Predictor32x32(ushort* dst, int stride, ushort* above, ushort* left,
int bd)
{ {
HighbdDc128Predictor(dst, stride, 32, above, left, bd); HighbdDc128Predictor(dst, stride, 32, above, left, bd);
} }
private static unsafe void HighbdDc128Predictor(ushort* dst, int stride, int bs, ushort* above, ushort* left, int bd) private static unsafe void HighbdDc128Predictor(ushort* dst, int stride, int bs, ushort* above, ushort* left,
int bd)
{ {
int r; for (int r = 0; r < bs; r++)
for (r = 0; r < bs; r++)
{ {
MemoryUtil.Fill(dst, (ushort)(128 << (bd - 8)), bs); MemoryUtil.Fill(dst, (ushort)(128 << (bd - 8)), bs);
dst += stride; dst += stride;
@ -1147,28 +1142,31 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
HighbdDcLeftPredictor(dst, stride, 8, above, left, bd); HighbdDcLeftPredictor(dst, stride, 8, above, left, bd);
} }
public static unsafe void HighbdDcLeftPredictor16x16(ushort* dst, int stride, ushort* above, ushort* left, int bd) public static unsafe void HighbdDcLeftPredictor16x16(ushort* dst, int stride, ushort* above, ushort* left,
int bd)
{ {
HighbdDcLeftPredictor(dst, stride, 16, above, left, bd); HighbdDcLeftPredictor(dst, stride, 16, above, left, bd);
} }
public static unsafe void HighbdDcLeftPredictor32x32(ushort* dst, int stride, ushort* above, ushort* left, int bd) public static unsafe void HighbdDcLeftPredictor32x32(ushort* dst, int stride, ushort* above, ushort* left,
int bd)
{ {
HighbdDcLeftPredictor(dst, stride, 32, above, left, bd); HighbdDcLeftPredictor(dst, stride, 32, above, left, bd);
} }
private static unsafe void HighbdDcLeftPredictor(ushort* dst, int stride, int bs, ushort* above, ushort* left, int bd) private static unsafe void HighbdDcLeftPredictor(ushort* dst, int stride, int bs, ushort* above, ushort* left,
int bd)
{ {
int i, r, expectedDc, sum = 0; int expectedDc, sum = 0;
for (i = 0; i < bs; i++) for (int i = 0; i < bs; i++)
{ {
sum += left[i]; sum += left[i];
} }
expectedDc = (sum + (bs >> 1)) / bs; expectedDc = (sum + (bs >> 1)) / bs;
for (r = 0; r < bs; r++) for (int r = 0; r < bs; r++)
{ {
MemoryUtil.Fill(dst, (ushort)expectedDc, bs); MemoryUtil.Fill(dst, (ushort)expectedDc, bs);
dst += stride; dst += stride;
@ -1185,28 +1183,31 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
HighbdDcTopPredictor(dst, stride, 8, above, left, bd); HighbdDcTopPredictor(dst, stride, 8, above, left, bd);
} }
public static unsafe void HighbdDcTopPredictor16x16(ushort* dst, int stride, ushort* above, ushort* left, int bd) public static unsafe void HighbdDcTopPredictor16x16(ushort* dst, int stride, ushort* above, ushort* left,
int bd)
{ {
HighbdDcTopPredictor(dst, stride, 16, above, left, bd); HighbdDcTopPredictor(dst, stride, 16, above, left, bd);
} }
public static unsafe void HighbdDcTopPredictor32x32(ushort* dst, int stride, ushort* above, ushort* left, int bd) public static unsafe void HighbdDcTopPredictor32x32(ushort* dst, int stride, ushort* above, ushort* left,
int bd)
{ {
HighbdDcTopPredictor(dst, stride, 32, above, left, bd); HighbdDcTopPredictor(dst, stride, 32, above, left, bd);
} }
private static unsafe void HighbdDcTopPredictor(ushort* dst, int stride, int bs, ushort* above, ushort* left, int bd) private static unsafe void HighbdDcTopPredictor(ushort* dst, int stride, int bs, ushort* above, ushort* left,
int bd)
{ {
int i, r, expectedDc, sum = 0; int expectedDc, sum = 0;
for (i = 0; i < bs; i++) for (int i = 0; i < bs; i++)
{ {
sum += above[i]; sum += above[i];
} }
expectedDc = (sum + (bs >> 1)) / bs; expectedDc = (sum + (bs >> 1)) / bs;
for (r = 0; r < bs; r++) for (int r = 0; r < bs; r++)
{ {
MemoryUtil.Fill(dst, (ushort)expectedDc, bs); MemoryUtil.Fill(dst, (ushort)expectedDc, bs);
dst += stride; dst += stride;
@ -1233,12 +1234,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
HighbdDcPredictor(dst, stride, 32, above, left, bd); HighbdDcPredictor(dst, stride, 32, above, left, bd);
} }
private static unsafe void HighbdDcPredictor(ushort* dst, int stride, int bs, ushort* above, ushort* left, int bd) private static unsafe void HighbdDcPredictor(ushort* dst, int stride, int bs, ushort* above, ushort* left,
int bd)
{ {
int i, r, expectedDc, sum = 0; int expectedDc, sum = 0;
int count = 2 * bs; int count = 2 * bs;
for (i = 0; i < bs; i++) for (int i = 0; i < bs; i++)
{ {
sum += above[i]; sum += above[i];
sum += left[i]; sum += left[i];
@ -1246,7 +1248,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
expectedDc = (sum + (count >> 1)) / count; expectedDc = (sum + (count >> 1)) / count;
for (r = 0; r < bs; r++) for (int r = 0; r < bs; r++)
{ {
MemoryUtil.Fill(dst, (ushort)expectedDc, bs); MemoryUtil.Fill(dst, (ushort)expectedDc, bs);
dst += stride; dst += stride;
@ -1265,7 +1267,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
Dst(dst, stride, 1, 0) = Avg3(I, j, k); Dst(dst, stride, 1, 0) = Avg3(I, j, k);
Dst(dst, stride, 3, 0) = Dst(dst, stride, 1, 1) = Avg3(j, k, l); Dst(dst, stride, 3, 0) = Dst(dst, stride, 1, 1) = Avg3(j, k, l);
Dst(dst, stride, 3, 1) = Dst(dst, stride, 1, 2) = Avg3(k, l, l); Dst(dst, stride, 3, 1) = Dst(dst, stride, 1, 2) = Avg3(k, l, l);
Dst(dst, stride, 3, 2) = Dst(dst, stride, 2, 2) = Dst(dst, stride, 0, 3) = Dst(dst, stride, 1, 3) = Dst(dst, stride, 2, 3) = Dst(dst, stride, 3, 3) = l; Dst(dst, stride, 3, 2) = Dst(dst, stride, 2, 2) = Dst(dst, stride, 0, 3) =
Dst(dst, stride, 1, 3) = Dst(dst, stride, 2, 3) = Dst(dst, stride, 3, 3) = l;
} }
public static unsafe void HighbdD63Predictor4x4(ushort* dst, int stride, ushort* above, ushort* left, int bd) public static unsafe void HighbdD63Predictor4x4(ushort* dst, int stride, ushort* above, ushort* left, int bd)
@ -1303,7 +1306,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
Dst(dst, stride, 0, 0) = Avg3(a, b, c); Dst(dst, stride, 0, 0) = Avg3(a, b, c);
Dst(dst, stride, 1, 0) = Dst(dst, stride, 0, 1) = Avg3(b, c, d); Dst(dst, stride, 1, 0) = Dst(dst, stride, 0, 1) = Avg3(b, c, d);
Dst(dst, stride, 2, 0) = Dst(dst, stride, 1, 1) = Dst(dst, stride, 0, 2) = Avg3(c, d, e); Dst(dst, stride, 2, 0) = Dst(dst, stride, 1, 1) = Dst(dst, stride, 0, 2) = Avg3(c, d, e);
Dst(dst, stride, 3, 0) = Dst(dst, stride, 2, 1) = Dst(dst, stride, 1, 2) = Dst(dst, stride, 0, 3) = Avg3(d, e, f); Dst(dst, stride, 3, 0) =
Dst(dst, stride, 2, 1) = Dst(dst, stride, 1, 2) = Dst(dst, stride, 0, 3) = Avg3(d, e, f);
Dst(dst, stride, 3, 1) = Dst(dst, stride, 2, 2) = Dst(dst, stride, 1, 3) = Avg3(e, f, g); Dst(dst, stride, 3, 1) = Dst(dst, stride, 2, 2) = Dst(dst, stride, 1, 3) = Avg3(e, f, g);
Dst(dst, stride, 3, 2) = Dst(dst, stride, 2, 3) = Avg3(f, g, h); Dst(dst, stride, 3, 2) = Dst(dst, stride, 2, 3) = Avg3(f, g, h);
Dst(dst, stride, 3, 3) = h; // Differs from vp8 Dst(dst, stride, 3, 3) = h; // Differs from vp8
@ -1346,7 +1350,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
Dst(dst, stride, 0, 3) = Avg3(j, k, l); Dst(dst, stride, 0, 3) = Avg3(j, k, l);
Dst(dst, stride, 1, 3) = Dst(dst, stride, 0, 2) = Avg3(I, j, k); Dst(dst, stride, 1, 3) = Dst(dst, stride, 0, 2) = Avg3(I, j, k);
Dst(dst, stride, 2, 3) = Dst(dst, stride, 1, 2) = Dst(dst, stride, 0, 1) = Avg3(x, I, j); Dst(dst, stride, 2, 3) = Dst(dst, stride, 1, 2) = Dst(dst, stride, 0, 1) = Avg3(x, I, j);
Dst(dst, stride, 3, 3) = Dst(dst, stride, 2, 2) = Dst(dst, stride, 1, 1) = Dst(dst, stride, 0, 0) = Avg3(a, x, I); Dst(dst, stride, 3, 3) =
Dst(dst, stride, 2, 2) = Dst(dst, stride, 1, 1) = Dst(dst, stride, 0, 0) = Avg3(a, x, I);
Dst(dst, stride, 3, 2) = Dst(dst, stride, 2, 1) = Dst(dst, stride, 1, 0) = Avg3(b, a, x); Dst(dst, stride, 3, 2) = Dst(dst, stride, 2, 1) = Dst(dst, stride, 1, 0) = Avg3(b, a, x);
Dst(dst, stride, 3, 1) = Dst(dst, stride, 2, 0) = Avg3(c, b, a); Dst(dst, stride, 3, 1) = Dst(dst, stride, 2, 0) = Avg3(c, b, a);
Dst(dst, stride, 3, 0) = Avg3(d, c, b); Dst(dst, stride, 3, 0) = Avg3(d, c, b);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,229 @@
using Ryujinx.Common.Memory;
using System;
using System.Runtime.Intrinsics.X86;
namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
{
internal class LoopFilterAuto
{
public static void LpfHorizontal4(
ArrayPtr<byte> s,
int pitch,
ReadOnlySpan<byte> blimit,
ReadOnlySpan<byte> limit,
ReadOnlySpan<byte> thresh)
{
if (Sse2.IsSupported)
{
LoopFilterSse2.LpfHorizontal4(s, pitch, blimit, limit, thresh);
}
else
{
LoopFilterScalar.LpfHorizontal4(s, pitch, blimit[0], limit[0], thresh[0]);
}
}
public static void LpfHorizontal4Dual(
ArrayPtr<byte> s,
int pitch,
ReadOnlySpan<byte> blimit0,
ReadOnlySpan<byte> limit0,
ReadOnlySpan<byte> thresh0,
ReadOnlySpan<byte> blimit1,
ReadOnlySpan<byte> limit1,
ReadOnlySpan<byte> thresh1)
{
if (Sse2.IsSupported)
{
LoopFilterSse2.LpfHorizontal4Dual(s, pitch, blimit0, limit0, thresh0, blimit1, limit1, thresh1);
}
else
{
LoopFilterScalar.LpfHorizontal4Dual(s, pitch, blimit0[0], limit0[0], thresh0[0], blimit1[0], limit1[0],
thresh1[0]);
}
}
public static void LpfHorizontal8(
ArrayPtr<byte> s,
int pitch,
ReadOnlySpan<byte> blimit,
ReadOnlySpan<byte> limit,
ReadOnlySpan<byte> thresh)
{
if (Sse2.IsSupported)
{
LoopFilterSse2.LpfHorizontal8(s, pitch, blimit, limit, thresh);
}
else
{
LoopFilterScalar.LpfHorizontal8(s, pitch, blimit[0], limit[0], thresh[0]);
}
}
public static void LpfHorizontal8Dual(
ArrayPtr<byte> s,
int pitch,
ReadOnlySpan<byte> blimit0,
ReadOnlySpan<byte> limit0,
ReadOnlySpan<byte> thresh0,
ReadOnlySpan<byte> blimit1,
ReadOnlySpan<byte> limit1,
ReadOnlySpan<byte> thresh1)
{
if (Sse2.IsSupported)
{
LoopFilterSse2.LpfHorizontal8Dual(s, pitch, blimit0, limit0, thresh0, blimit1, limit1, thresh1);
}
else
{
LoopFilterScalar.LpfHorizontal8Dual(s, pitch, blimit0[0], limit0[0], thresh0[0], blimit1[0], limit1[0],
thresh1[0]);
}
}
public static void LpfHorizontal16(
ArrayPtr<byte> s,
int pitch,
ReadOnlySpan<byte> blimit,
ReadOnlySpan<byte> limit,
ReadOnlySpan<byte> thresh)
{
if (Sse2.IsSupported)
{
LoopFilterSse2.LpfHorizontal16(s, pitch, blimit, limit, thresh);
}
else
{
LoopFilterScalar.LpfHorizontal16(s, pitch, blimit[0], limit[0], thresh[0]);
}
}
public static void LpfHorizontal16Dual(
ArrayPtr<byte> s,
int pitch,
ReadOnlySpan<byte> blimit,
ReadOnlySpan<byte> limit,
ReadOnlySpan<byte> thresh)
{
if (Sse2.IsSupported)
{
LoopFilterSse2.LpfHorizontal16Dual(s, pitch, blimit, limit, thresh);
}
else
{
LoopFilterScalar.LpfHorizontal16Dual(s, pitch, blimit[0], limit[0], thresh[0]);
}
}
public static void LpfVertical4(
ArrayPtr<byte> s,
int pitch,
ReadOnlySpan<byte> blimit,
ReadOnlySpan<byte> limit,
ReadOnlySpan<byte> thresh)
{
if (Sse2.IsSupported)
{
LoopFilterSse2.LpfVertical4(s, pitch, blimit, limit, thresh);
}
else
{
LoopFilterScalar.LpfVertical4(s, pitch, blimit[0], limit[0], thresh[0]);
}
}
public static void LpfVertical4Dual(
ArrayPtr<byte> s,
int pitch,
ReadOnlySpan<byte> blimit0,
ReadOnlySpan<byte> limit0,
ReadOnlySpan<byte> thresh0,
ReadOnlySpan<byte> blimit1,
ReadOnlySpan<byte> limit1,
ReadOnlySpan<byte> thresh1)
{
if (Sse2.IsSupported)
{
LoopFilterSse2.LpfVertical4Dual(s, pitch, blimit0, limit0, thresh0, blimit1, limit1, thresh1);
}
else
{
LoopFilterScalar.LpfVertical4Dual(s, pitch, blimit0[0], limit0[0], thresh0[0], blimit1[0], limit1[0],
thresh1[0]);
}
}
public static void LpfVertical8(
ArrayPtr<byte> s,
int pitch,
ReadOnlySpan<byte> blimit,
ReadOnlySpan<byte> limit,
ReadOnlySpan<byte> thresh)
{
if (Sse2.IsSupported)
{
LoopFilterSse2.LpfVertical8(s, pitch, blimit, limit, thresh);
}
else
{
LoopFilterScalar.LpfVertical8(s, pitch, blimit[0], limit[0], thresh[0]);
}
}
public static void LpfVertical8Dual(
ArrayPtr<byte> s,
int pitch,
ReadOnlySpan<byte> blimit0,
ReadOnlySpan<byte> limit0,
ReadOnlySpan<byte> thresh0,
ReadOnlySpan<byte> blimit1,
ReadOnlySpan<byte> limit1,
ReadOnlySpan<byte> thresh1)
{
if (Sse2.IsSupported)
{
LoopFilterSse2.LpfVertical8Dual(s, pitch, blimit0, limit0, thresh0, blimit1, limit1, thresh1);
}
else
{
LoopFilterScalar.LpfVertical8Dual(s, pitch, blimit0[0], limit0[0], thresh0[0], blimit1[0], limit1[0],
thresh1[0]);
}
}
public static void LpfVertical16(
ArrayPtr<byte> s,
int pitch,
ReadOnlySpan<byte> blimit,
ReadOnlySpan<byte> limit,
ReadOnlySpan<byte> thresh)
{
if (Sse2.IsSupported)
{
LoopFilterSse2.LpfVertical16(s, pitch, blimit, limit, thresh);
}
else
{
LoopFilterScalar.LpfVertical16(s, pitch, blimit[0], limit[0], thresh[0]);
}
}
public static void LpfVertical16Dual(
ArrayPtr<byte> s,
int pitch,
ReadOnlySpan<byte> blimit,
ReadOnlySpan<byte> limit,
ReadOnlySpan<byte> thresh)
{
if (Sse2.IsSupported)
{
LoopFilterSse2.LpfVertical16Dual(s, pitch, blimit, limit, thresh);
}
else
{
LoopFilterScalar.LpfVertical16Dual(s, pitch, blimit[0], limit[0], thresh[0]);
}
}
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -12,7 +12,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
{ {
Debug.Assert(den != 0); Debug.Assert(den != 0);
{ {
int p = (int)(((ulong)num * 256 + (den >> 1)) / den); int p = (int)((((ulong)num * 256) + (den >> 1)) / den);
// (p > 255) ? 255 : (p < 1) ? 1 : p; // (p > 255) ? 255 : (p < 1) ? 1 : p;
int clippedProb = p | ((255 - p) >> 23) | (p == 0 ? 1 : 0); int clippedProb = p | ((255 - p) >> 23) | (p == 0 ? 1 : 0);
return (byte)clippedProb; return (byte)clippedProb;
@ -22,14 +22,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
/* This function assumes prob1 and prob2 are already within [1,255] range. */ /* This function assumes prob1 and prob2 are already within [1,255] range. */
public static byte WeightedProb(int prob1, int prob2, int factor) public static byte WeightedProb(int prob1, int prob2, int factor)
{ {
return (byte)BitUtils.RoundPowerOfTwo(prob1 * (256 - factor) + prob2 * factor, 8); return (byte)BitUtils.RoundPowerOfTwo((prob1 * (256 - factor)) + (prob2 * factor), 8);
} }
// MODE_MV_MAX_UPDATE_FACTOR (128) * count / MODE_MV_COUNT_SAT; // MODE_MV_MAX_UPDATE_FACTOR (128) * count / MODE_MV_COUNT_SAT;
private static readonly uint[] CountToUpdateFactor = new uint[] private static readonly uint[] CountToUpdateFactor =
{ {
0, 6, 12, 19, 25, 32, 38, 44, 51, 57, 64, 0, 6, 12, 19, 25, 32, 38, 44, 51, 57, 64, 70, 76, 83, 89, 96, 102, 108, 115, 121, 128
70, 76, 83, 89, 96, 102, 108, 115, 121, 128
}; };
private const int ModeMvCountSat = 20; private const int ModeMvCountSat = 20;
@ -41,14 +40,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
{ {
return preProb; return preProb;
} }
else
{
uint count = Math.Min(den, ModeMvCountSat); uint count = Math.Min(den, ModeMvCountSat);
uint factor = CountToUpdateFactor[(int)count]; uint factor = CountToUpdateFactor[(int)count];
byte prob = GetProb(ct0, den); byte prob = GetProb(ct0, den);
return WeightedProb(preProb, prob, (int)factor); return WeightedProb(preProb, prob, (int)factor);
} }
}
private static uint TreeMergeProbsImpl( private static uint TreeMergeProbsImpl(
uint i, uint i,
@ -58,14 +55,15 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
Span<byte> probs) Span<byte> probs)
{ {
int l = tree[i]; int l = tree[i];
uint leftCount = (l <= 0) ? counts[-l] : TreeMergeProbsImpl((uint)l, tree, preProbs, counts, probs); uint leftCount = l <= 0 ? counts[-l] : TreeMergeProbsImpl((uint)l, tree, preProbs, counts, probs);
int r = tree[i + 1]; int r = tree[i + 1];
uint rightCount = (r <= 0) ? counts[-r] : TreeMergeProbsImpl((uint)r, tree, preProbs, counts, probs); uint rightCount = r <= 0 ? counts[-r] : TreeMergeProbsImpl((uint)r, tree, preProbs, counts, probs);
probs[(int)(i >> 1)] = ModeMvMergeProbs(preProbs[(int)(i >> 1)], leftCount, rightCount); probs[(int)(i >> 1)] = ModeMvMergeProbs(preProbs[(int)(i >> 1)], leftCount, rightCount);
return leftCount + rightCount; return leftCount + rightCount;
} }
public static void TreeMergeProbs(sbyte[] tree, ReadOnlySpan<byte> preProbs, ReadOnlySpan<uint> counts, Span<byte> probs) public static void TreeMergeProbs(sbyte[] tree, ReadOnlySpan<byte> preProbs, ReadOnlySpan<uint> counts,
Span<byte> probs)
{ {
TreeMergeProbsImpl(0, tree, preProbs, counts, probs); TreeMergeProbsImpl(0, tree, preProbs, counts, probs);
} }

View file

@ -1,4 +1,5 @@
using Ryujinx.Common.Memory; using Ryujinx.Common.Memory;
using Ryujinx.Graphics.Nvdec.Vp9.Types;
using System; using System;
using System.Buffers.Binary; using System.Buffers.Binary;
@ -6,19 +7,18 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
{ {
internal struct Reader internal struct Reader
{ {
private static readonly byte[] Norm = new byte[] private static readonly byte[] Norm =
{ {
0, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2,
3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}; };
private const int BdValueSize = sizeof(ulong) * 8; private const int BdValueSize = sizeof(ulong) * 8;
// This is meant to be a large, positive constant that can still be efficiently // This is meant to be a large, positive constant that can still be efficiently
@ -37,8 +37,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
{ {
return true; return true;
} }
else
{
_buffer = new ArrayPtr<byte>(ref buffer[0], size); _buffer = new ArrayPtr<byte>(ref buffer[0], size);
Value = 0; Value = 0;
Count = -8; Count = -8;
@ -46,7 +45,6 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
Fill(); Fill();
return ReadBit() != 0; // Marker bit return ReadBit() != 0; // Marker bit
} }
}
private void Fill() private void Fill()
{ {
@ -124,7 +122,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
ulong bigsplit; ulong bigsplit;
int count; int count;
uint range; uint range;
uint split = (Range * (uint)prob + (256 - (uint)prob)) >> 8; uint split = ((Range * (uint)prob) + (256 - (uint)prob)) >> 8;
if (Count < 0) if (Count < 0)
{ {
@ -181,7 +179,6 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
while ((i = tree[i + Read(probs[i >> 1])]) > 0) while ((i = tree[i + Read(probs[i >> 1])]) > 0)
{ {
continue;
} }
return -i; return -i;
@ -189,7 +186,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
public int ReadBool(int prob, ref ulong value, ref int count, ref uint range) public int ReadBool(int prob, ref ulong value, ref int count, ref uint range)
{ {
uint split = (range * (uint)prob + (256 - (uint)prob)) >> 8; uint split = ((range * (uint)prob) + (256 - (uint)prob)) >> 8;
ulong bigsplit = (ulong)split << (BdValueSize - 8); ulong bigsplit = (ulong)split << (BdValueSize - 8);
if (count < 0) if (count < 0)
@ -213,6 +210,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
} }
return 1; return 1;
} }
range = split; range = split;
{ {
int shift = Norm[range]; int shift = Norm[range];
@ -231,7 +229,82 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
Count -= 8; Count -= 8;
_buffer = _buffer.Slice(-1); _buffer = _buffer.Slice(-1);
} }
return _buffer; return _buffer;
} }
private int DecodeUniform()
{
const int l = 8;
const int m = (1 << l) - 191;
int v = ReadLiteral(l - 1);
return v < m ? v : (v << 1) - m + ReadBit();
}
public int DecodeTermSubexp()
{
if (ReadBit() == 0)
{
return ReadLiteral(4);
}
if (ReadBit() == 0)
{
return ReadLiteral(4) + 16;
}
if (ReadBit() == 0)
{
return ReadLiteral(5) + 32;
}
return DecodeUniform() + 64;
}
public TxMode ReadTxMode()
{
TxMode txMode = (TxMode)ReadLiteral(2);
if (txMode == TxMode.Allow32x32)
{
txMode += ReadBit();
}
return txMode;
}
public int ReadCoeff(
ReadOnlySpan<byte> probs,
int n,
ref ulong value,
ref int count,
ref uint range)
{
int val = 0;
for (int i = 0; i < n; ++i)
{
val = (val << 1) | ReadBool(probs[i], ref value, ref count, ref range);
}
return val;
}
public void DiffUpdateProb(ref byte p)
{
if (Read(Entropy.DiffUpdateProb) != 0)
{
p = (byte)DSubExp.InvRemapProb(DecodeTermSubexp(), p);
}
}
public void UpdateMvProbs(Span<byte> p, int n)
{
for (int i = 0; i < n; ++i)
{
if (Read(EntropyMv.UpdateProb) != 0)
{
p[i] = (byte)((ReadLiteral(7) << 1) | 1);
}
}
}
} }
} }

View file

@ -13,42 +13,42 @@
// for (int i = 1; i < 32; ++i) // for (int i = 1; i < 32; ++i)
// Console.WriteLine("public const short CosPi{0}_64 = {1};", i, MathF.Round(16384 * MathF.Cos(i * MathF.PI / 64))); // Console.WriteLine("public const short CosPi{0}_64 = {1};", i, MathF.Round(16384 * MathF.Cos(i * MathF.PI / 64)));
// Note: sin(k * Pi / 64) = cos((32 - k) * Pi / 64) // Note: sin(k * Pi / 64) = cos((32 - k) * Pi / 64)
public const short CosPi1_64 = 16364; public const short CosPi164 = 16364;
public const short CosPi2_64 = 16305; public const short CosPi264 = 16305;
public const short CosPi3_64 = 16207; public const short CosPi364 = 16207;
public const short CosPi4_64 = 16069; public const short CosPi464 = 16069;
public const short CosPi5_64 = 15893; public const short CosPi564 = 15893;
public const short CosPi6_64 = 15679; public const short CosPi664 = 15679;
public const short CosPi7_64 = 15426; public const short CosPi764 = 15426;
public const short CosPi8_64 = 15137; public const short CosPi864 = 15137;
public const short CosPi9_64 = 14811; public const short CosPi964 = 14811;
public const short CosPi10_64 = 14449; public const short CosPi1064 = 14449;
public const short CosPi11_64 = 14053; public const short CosPi1164 = 14053;
public const short CosPi12_64 = 13623; public const short CosPi1264 = 13623;
public const short CosPi13_64 = 13160; public const short CosPi1364 = 13160;
public const short CosPi14_64 = 12665; public const short CosPi1464 = 12665;
public const short CosPi15_64 = 12140; public const short CosPi1564 = 12140;
public const short CosPi16_64 = 11585; public const short CosPi1664 = 11585;
public const short CosPi17_64 = 11003; public const short CosPi1764 = 11003;
public const short CosPi18_64 = 10394; public const short CosPi1864 = 10394;
public const short CosPi19_64 = 9760; public const short CosPi1964 = 9760;
public const short CosPi20_64 = 9102; public const short CosPi2064 = 9102;
public const short CosPi21_64 = 8423; public const short CosPi2164 = 8423;
public const short CosPi22_64 = 7723; public const short CosPi2264 = 7723;
public const short CosPi23_64 = 7005; public const short CosPi2364 = 7005;
public const short CosPi24_64 = 6270; public const short CosPi2464 = 6270;
public const short CosPi25_64 = 5520; public const short CosPi2564 = 5520;
public const short CosPi26_64 = 4756; public const short CosPi2664 = 4756;
public const short CosPi27_64 = 3981; public const short CosPi2764 = 3981;
public const short CosPi28_64 = 3196; public const short CosPi2864 = 3196;
public const short CosPi29_64 = 2404; public const short CosPi2964 = 2404;
public const short CosPi30_64 = 1606; public const short CosPi3064 = 1606;
public const short CosPi31_64 = 804; public const short CosPi3164 = 804;
// 16384 * sqrt(2) * sin(kPi / 9) * 2 / 3 // 16384 * sqrt(2) * sin(kPi / 9) * 2 / 3
public const short SinPi1_9 = 5283; public const short SinPi19 = 5283;
public const short SinPi2_9 = 9929; public const short SinPi29 = 9929;
public const short SinPi3_9 = 13377; public const short SinPi39 = 13377;
public const short SinPi4_9 = 15212; public const short SinPi49 = 15212;
} }
} }

View file

@ -0,0 +1,623 @@
using Ryujinx.Graphics.Nvdec.Vp9.Types;
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Nvdec.Vp9
{
internal static class Entropy
{
public const int DiffUpdateProb = 252;
// Coefficient token alphabet
public const int ZeroToken = 0; // 0 Extra Bits 0+0
public const int OneToken = 1; // 1 Extra Bits 0+1
public const int TwoToken = 2; // 2 Extra Bits 0+1
public const int ThreeToken = 3; // 3 Extra Bits 0+1
public const int FourToken = 4; // 4 Extra Bits 0+1
public const int Category1Token = 5; // 5-6 Extra Bits 1+1
public const int Category2Token = 6; // 7-10 Extra Bits 2+1
public const int Category3Token = 7; // 11-18 Extra Bits 3+1
public const int Category4Token = 8; // 19-34 Extra Bits 4+1
public const int Category5Token = 9; // 35-66 Extra Bits 5+1
public const int Category6Token = 10; // 67+ Extra Bits 14+1
public const int EobToken = 11; // EOB Extra Bits 0+0
public const int EntropyTokens = 12;
public const int RefTypes = 2; // intra=0, inter=1
/* Middle dimension reflects the coefficient position within the transform. */
public const int CoefBands = 6;
/* Inside dimension is measure of nearby complexity, that reflects the energy
of nearby coefficients are nonzero. For the first coefficient (DC, unless
block type is 0), we look at the (already encoded) blocks above and to the
left of the current block. The context index is then the number (0,1,or 2)
of these blocks having nonzero coefficients.
After decoding a coefficient, the measure is determined by the size of the
most recently decoded coefficient.
Note that the intuitive meaning of this measure changes as coefficients
are decoded, e.g., prior to the first token, a zero means that my neighbors
are empty while, after the first token, because of the use of end-of-block,
a zero means we just decoded a zero and hence guarantees that a non-zero
coefficient will appear later in this block. However, this shift
in meaning is perfectly OK because our context depends also on the
coefficient band (and since zigzag positions 0, 1, and 2 are in
distinct bands). */
public const int CoeffContexts = 6;
public static int BAND_COEFF_CONTEXTS(int band)
{
return band == 0 ? 3 : CoeffContexts;
}
public const int UnconstrainedNodes = 3;
public const int PivotNode = 2;
public const int Cat1MinVal = 5;
public const int Cat2MinVal = 7;
public const int Cat3MinVal = 11;
public const int Cat4MinVal = 19;
public const int Cat5MinVal = 35;
public const int Cat6MinVal = 67;
public static readonly byte[] Cat1Prob = { 159 };
public static readonly byte[] Cat2Prob = { 165, 145 };
public static readonly byte[] Cat3Prob = { 173, 148, 140 };
public static readonly byte[] Cat4Prob = { 176, 155, 140, 135 };
public static readonly byte[] Cat5Prob = { 180, 157, 141, 134, 130 };
public static readonly byte[] Cat6Prob =
{
254, 254, 254, 252, 249, 243, 230, 196, 177, 153, 140, 133, 130, 129
};
public static readonly byte[] Cat6ProbHigh12 =
{
255, 255, 255, 255, 254, 254, 54, 252, 249, 243, 230, 196, 177, 153, 140, 133, 130, 129
};
public const int EobModelToken = 3;
private static readonly byte[] CoefbandTrans8x8Plus =
{
0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5,
// beyond MAXBAND_INDEX+1 all values are filled as 5
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
};
private static readonly byte[] CoefbandTrans4x4 = { 0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5 };
public static readonly byte[][] Pareto8Full =
{
new byte[] { 3, 86, 128, 6, 86, 23, 88, 29 }, new byte[] { 6, 86, 128, 11, 87, 42, 91, 52 },
new byte[] { 9, 86, 129, 17, 88, 61, 94, 76 }, new byte[] { 12, 86, 129, 22, 88, 77, 97, 93 },
new byte[] { 15, 87, 129, 28, 89, 93, 100, 110 }, new byte[] { 17, 87, 129, 33, 90, 105, 103, 123 },
new byte[] { 20, 88, 130, 38, 91, 118, 106, 136 }, new byte[] { 23, 88, 130, 43, 91, 128, 108, 146 },
new byte[] { 26, 89, 131, 48, 92, 139, 111, 156 }, new byte[] { 28, 89, 131, 53, 93, 147, 114, 163 },
new byte[] { 31, 90, 131, 58, 94, 156, 117, 171 }, new byte[] { 34, 90, 131, 62, 94, 163, 119, 177 },
new byte[] { 37, 90, 132, 66, 95, 171, 122, 184 }, new byte[] { 39, 90, 132, 70, 96, 177, 124, 189 },
new byte[] { 42, 91, 132, 75, 97, 183, 127, 194 }, new byte[] { 44, 91, 132, 79, 97, 188, 129, 198 },
new byte[] { 47, 92, 133, 83, 98, 193, 132, 202 }, new byte[] { 49, 92, 133, 86, 99, 197, 134, 205 },
new byte[] { 52, 93, 133, 90, 100, 201, 137, 208 }, new byte[] { 54, 93, 133, 94, 100, 204, 139, 211 },
new byte[] { 57, 94, 134, 98, 101, 208, 142, 214 }, new byte[] { 59, 94, 134, 101, 102, 211, 144, 216 },
new byte[] { 62, 94, 135, 105, 103, 214, 146, 218 },
new byte[] { 64, 94, 135, 108, 103, 216, 148, 220 },
new byte[] { 66, 95, 135, 111, 104, 219, 151, 222 },
new byte[] { 68, 95, 135, 114, 105, 221, 153, 223 },
new byte[] { 71, 96, 136, 117, 106, 224, 155, 225 },
new byte[] { 73, 96, 136, 120, 106, 225, 157, 226 },
new byte[] { 76, 97, 136, 123, 107, 227, 159, 228 },
new byte[] { 78, 97, 136, 126, 108, 229, 160, 229 },
new byte[] { 80, 98, 137, 129, 109, 231, 162, 231 },
new byte[] { 82, 98, 137, 131, 109, 232, 164, 232 },
new byte[] { 84, 98, 138, 134, 110, 234, 166, 233 },
new byte[] { 86, 98, 138, 137, 111, 235, 168, 234 },
new byte[] { 89, 99, 138, 140, 112, 236, 170, 235 },
new byte[] { 91, 99, 138, 142, 112, 237, 171, 235 },
new byte[] { 93, 100, 139, 145, 113, 238, 173, 236 },
new byte[] { 95, 100, 139, 147, 114, 239, 174, 237 },
new byte[] { 97, 101, 140, 149, 115, 240, 176, 238 },
new byte[] { 99, 101, 140, 151, 115, 241, 177, 238 },
new byte[] { 101, 102, 140, 154, 116, 242, 179, 239 },
new byte[] { 103, 102, 140, 156, 117, 242, 180, 239 },
new byte[] { 105, 103, 141, 158, 118, 243, 182, 240 },
new byte[] { 107, 103, 141, 160, 118, 243, 183, 240 },
new byte[] { 109, 104, 141, 162, 119, 244, 185, 241 },
new byte[] { 111, 104, 141, 164, 119, 244, 186, 241 },
new byte[] { 113, 104, 142, 166, 120, 245, 187, 242 },
new byte[] { 114, 104, 142, 168, 121, 245, 188, 242 },
new byte[] { 116, 105, 143, 170, 122, 246, 190, 243 },
new byte[] { 118, 105, 143, 171, 122, 246, 191, 243 },
new byte[] { 120, 106, 143, 173, 123, 247, 192, 244 },
new byte[] { 121, 106, 143, 175, 124, 247, 193, 244 },
new byte[] { 123, 107, 144, 177, 125, 248, 195, 244 },
new byte[] { 125, 107, 144, 178, 125, 248, 196, 244 },
new byte[] { 127, 108, 145, 180, 126, 249, 197, 245 },
new byte[] { 128, 108, 145, 181, 127, 249, 198, 245 },
new byte[] { 130, 109, 145, 183, 128, 249, 199, 245 },
new byte[] { 132, 109, 145, 184, 128, 249, 200, 245 },
new byte[] { 134, 110, 146, 186, 129, 250, 201, 246 },
new byte[] { 135, 110, 146, 187, 130, 250, 202, 246 },
new byte[] { 137, 111, 147, 189, 131, 251, 203, 246 },
new byte[] { 138, 111, 147, 190, 131, 251, 204, 246 },
new byte[] { 140, 112, 147, 192, 132, 251, 205, 247 },
new byte[] { 141, 112, 147, 193, 132, 251, 206, 247 },
new byte[] { 143, 113, 148, 194, 133, 251, 207, 247 },
new byte[] { 144, 113, 148, 195, 134, 251, 207, 247 },
new byte[] { 146, 114, 149, 197, 135, 252, 208, 248 },
new byte[] { 147, 114, 149, 198, 135, 252, 209, 248 },
new byte[] { 149, 115, 149, 199, 136, 252, 210, 248 },
new byte[] { 150, 115, 149, 200, 137, 252, 210, 248 },
new byte[] { 152, 115, 150, 201, 138, 252, 211, 248 },
new byte[] { 153, 115, 150, 202, 138, 252, 212, 248 },
new byte[] { 155, 116, 151, 204, 139, 253, 213, 249 },
new byte[] { 156, 116, 151, 205, 139, 253, 213, 249 },
new byte[] { 158, 117, 151, 206, 140, 253, 214, 249 },
new byte[] { 159, 117, 151, 207, 141, 253, 215, 249 },
new byte[] { 161, 118, 152, 208, 142, 253, 216, 249 },
new byte[] { 162, 118, 152, 209, 142, 253, 216, 249 },
new byte[] { 163, 119, 153, 210, 143, 253, 217, 249 },
new byte[] { 164, 119, 153, 211, 143, 253, 217, 249 },
new byte[] { 166, 120, 153, 212, 144, 254, 218, 250 },
new byte[] { 167, 120, 153, 212, 145, 254, 219, 250 },
new byte[] { 168, 121, 154, 213, 146, 254, 220, 250 },
new byte[] { 169, 121, 154, 214, 146, 254, 220, 250 },
new byte[] { 171, 122, 155, 215, 147, 254, 221, 250 },
new byte[] { 172, 122, 155, 216, 147, 254, 221, 250 },
new byte[] { 173, 123, 155, 217, 148, 254, 222, 250 },
new byte[] { 174, 123, 155, 217, 149, 254, 222, 250 },
new byte[] { 176, 124, 156, 218, 150, 254, 223, 250 },
new byte[] { 177, 124, 156, 219, 150, 254, 223, 250 },
new byte[] { 178, 125, 157, 220, 151, 254, 224, 251 },
new byte[] { 179, 125, 157, 220, 151, 254, 224, 251 },
new byte[] { 180, 126, 157, 221, 152, 254, 225, 251 },
new byte[] { 181, 126, 157, 221, 152, 254, 225, 251 },
new byte[] { 183, 127, 158, 222, 153, 254, 226, 251 },
new byte[] { 184, 127, 158, 223, 154, 254, 226, 251 },
new byte[] { 185, 128, 159, 224, 155, 255, 227, 251 },
new byte[] { 186, 128, 159, 224, 155, 255, 227, 251 },
new byte[] { 187, 129, 160, 225, 156, 255, 228, 251 },
new byte[] { 188, 130, 160, 225, 156, 255, 228, 251 },
new byte[] { 189, 131, 160, 226, 157, 255, 228, 251 },
new byte[] { 190, 131, 160, 226, 158, 255, 228, 251 },
new byte[] { 191, 132, 161, 227, 159, 255, 229, 251 },
new byte[] { 192, 132, 161, 227, 159, 255, 229, 251 },
new byte[] { 193, 133, 162, 228, 160, 255, 230, 252 },
new byte[] { 194, 133, 162, 229, 160, 255, 230, 252 },
new byte[] { 195, 134, 163, 230, 161, 255, 231, 252 },
new byte[] { 196, 134, 163, 230, 161, 255, 231, 252 },
new byte[] { 197, 135, 163, 231, 162, 255, 231, 252 },
new byte[] { 198, 135, 163, 231, 162, 255, 231, 252 },
new byte[] { 199, 136, 164, 232, 163, 255, 232, 252 },
new byte[] { 200, 136, 164, 232, 164, 255, 232, 252 },
new byte[] { 201, 137, 165, 233, 165, 255, 233, 252 },
new byte[] { 201, 137, 165, 233, 165, 255, 233, 252 },
new byte[] { 202, 138, 166, 233, 166, 255, 233, 252 },
new byte[] { 203, 138, 166, 233, 166, 255, 233, 252 },
new byte[] { 204, 139, 166, 234, 167, 255, 234, 252 },
new byte[] { 205, 139, 166, 234, 167, 255, 234, 252 },
new byte[] { 206, 140, 167, 235, 168, 255, 235, 252 },
new byte[] { 206, 140, 167, 235, 168, 255, 235, 252 },
new byte[] { 207, 141, 168, 236, 169, 255, 235, 252 },
new byte[] { 208, 141, 168, 236, 170, 255, 235, 252 },
new byte[] { 209, 142, 169, 237, 171, 255, 236, 252 },
new byte[] { 209, 143, 169, 237, 171, 255, 236, 252 },
new byte[] { 210, 144, 169, 237, 172, 255, 236, 252 },
new byte[] { 211, 144, 169, 237, 172, 255, 236, 252 },
new byte[] { 212, 145, 170, 238, 173, 255, 237, 252 },
new byte[] { 213, 145, 170, 238, 173, 255, 237, 252 },
new byte[] { 214, 146, 171, 239, 174, 255, 237, 253 },
new byte[] { 214, 146, 171, 239, 174, 255, 237, 253 },
new byte[] { 215, 147, 172, 240, 175, 255, 238, 253 },
new byte[] { 215, 147, 172, 240, 175, 255, 238, 253 },
new byte[] { 216, 148, 173, 240, 176, 255, 238, 253 },
new byte[] { 217, 148, 173, 240, 176, 255, 238, 253 },
new byte[] { 218, 149, 173, 241, 177, 255, 239, 253 },
new byte[] { 218, 149, 173, 241, 178, 255, 239, 253 },
new byte[] { 219, 150, 174, 241, 179, 255, 239, 253 },
new byte[] { 219, 151, 174, 241, 179, 255, 239, 253 },
new byte[] { 220, 152, 175, 242, 180, 255, 240, 253 },
new byte[] { 221, 152, 175, 242, 180, 255, 240, 253 },
new byte[] { 222, 153, 176, 242, 181, 255, 240, 253 },
new byte[] { 222, 153, 176, 242, 181, 255, 240, 253 },
new byte[] { 223, 154, 177, 243, 182, 255, 240, 253 },
new byte[] { 223, 154, 177, 243, 182, 255, 240, 253 },
new byte[] { 224, 155, 178, 244, 183, 255, 241, 253 },
new byte[] { 224, 155, 178, 244, 183, 255, 241, 253 },
new byte[] { 225, 156, 178, 244, 184, 255, 241, 253 },
new byte[] { 225, 157, 178, 244, 184, 255, 241, 253 },
new byte[] { 226, 158, 179, 244, 185, 255, 242, 253 },
new byte[] { 227, 158, 179, 244, 185, 255, 242, 253 },
new byte[] { 228, 159, 180, 245, 186, 255, 242, 253 },
new byte[] { 228, 159, 180, 245, 186, 255, 242, 253 },
new byte[] { 229, 160, 181, 245, 187, 255, 242, 253 },
new byte[] { 229, 160, 181, 245, 187, 255, 242, 253 },
new byte[] { 230, 161, 182, 246, 188, 255, 243, 253 },
new byte[] { 230, 162, 182, 246, 188, 255, 243, 253 },
new byte[] { 231, 163, 183, 246, 189, 255, 243, 253 },
new byte[] { 231, 163, 183, 246, 189, 255, 243, 253 },
new byte[] { 232, 164, 184, 247, 190, 255, 243, 253 },
new byte[] { 232, 164, 184, 247, 190, 255, 243, 253 },
new byte[] { 233, 165, 185, 247, 191, 255, 244, 253 },
new byte[] { 233, 165, 185, 247, 191, 255, 244, 253 },
new byte[] { 234, 166, 185, 247, 192, 255, 244, 253 },
new byte[] { 234, 167, 185, 247, 192, 255, 244, 253 },
new byte[] { 235, 168, 186, 248, 193, 255, 244, 253 },
new byte[] { 235, 168, 186, 248, 193, 255, 244, 253 },
new byte[] { 236, 169, 187, 248, 194, 255, 244, 253 },
new byte[] { 236, 169, 187, 248, 194, 255, 244, 253 },
new byte[] { 236, 170, 188, 248, 195, 255, 245, 253 },
new byte[] { 236, 170, 188, 248, 195, 255, 245, 253 },
new byte[] { 237, 171, 189, 249, 196, 255, 245, 254 },
new byte[] { 237, 172, 189, 249, 196, 255, 245, 254 },
new byte[] { 238, 173, 190, 249, 197, 255, 245, 254 },
new byte[] { 238, 173, 190, 249, 197, 255, 245, 254 },
new byte[] { 239, 174, 191, 249, 198, 255, 245, 254 },
new byte[] { 239, 174, 191, 249, 198, 255, 245, 254 },
new byte[] { 240, 175, 192, 249, 199, 255, 246, 254 },
new byte[] { 240, 176, 192, 249, 199, 255, 246, 254 },
new byte[] { 240, 177, 193, 250, 200, 255, 246, 254 },
new byte[] { 240, 177, 193, 250, 200, 255, 246, 254 },
new byte[] { 241, 178, 194, 250, 201, 255, 246, 254 },
new byte[] { 241, 178, 194, 250, 201, 255, 246, 254 },
new byte[] { 242, 179, 195, 250, 202, 255, 246, 254 },
new byte[] { 242, 180, 195, 250, 202, 255, 246, 254 },
new byte[] { 242, 181, 196, 250, 203, 255, 247, 254 },
new byte[] { 242, 181, 196, 250, 203, 255, 247, 254 },
new byte[] { 243, 182, 197, 251, 204, 255, 247, 254 },
new byte[] { 243, 183, 197, 251, 204, 255, 247, 254 },
new byte[] { 244, 184, 198, 251, 205, 255, 247, 254 },
new byte[] { 244, 184, 198, 251, 205, 255, 247, 254 },
new byte[] { 244, 185, 199, 251, 206, 255, 247, 254 },
new byte[] { 244, 185, 199, 251, 206, 255, 247, 254 },
new byte[] { 245, 186, 200, 251, 207, 255, 247, 254 },
new byte[] { 245, 187, 200, 251, 207, 255, 247, 254 },
new byte[] { 246, 188, 201, 252, 207, 255, 248, 254 },
new byte[] { 246, 188, 201, 252, 207, 255, 248, 254 },
new byte[] { 246, 189, 202, 252, 208, 255, 248, 254 },
new byte[] { 246, 190, 202, 252, 208, 255, 248, 254 },
new byte[] { 247, 191, 203, 252, 209, 255, 248, 254 },
new byte[] { 247, 191, 203, 252, 209, 255, 248, 254 },
new byte[] { 247, 192, 204, 252, 210, 255, 248, 254 },
new byte[] { 247, 193, 204, 252, 210, 255, 248, 254 },
new byte[] { 248, 194, 205, 252, 211, 255, 248, 254 },
new byte[] { 248, 194, 205, 252, 211, 255, 248, 254 },
new byte[] { 248, 195, 206, 252, 212, 255, 249, 254 },
new byte[] { 248, 196, 206, 252, 212, 255, 249, 254 },
new byte[] { 249, 197, 207, 253, 213, 255, 249, 254 },
new byte[] { 249, 197, 207, 253, 213, 255, 249, 254 },
new byte[] { 249, 198, 208, 253, 214, 255, 249, 254 },
new byte[] { 249, 199, 209, 253, 214, 255, 249, 254 },
new byte[] { 250, 200, 210, 253, 215, 255, 249, 254 },
new byte[] { 250, 200, 210, 253, 215, 255, 249, 254 },
new byte[] { 250, 201, 211, 253, 215, 255, 249, 254 },
new byte[] { 250, 202, 211, 253, 215, 255, 249, 254 },
new byte[] { 250, 203, 212, 253, 216, 255, 249, 254 },
new byte[] { 250, 203, 212, 253, 216, 255, 249, 254 },
new byte[] { 251, 204, 213, 253, 217, 255, 250, 254 },
new byte[] { 251, 205, 213, 253, 217, 255, 250, 254 },
new byte[] { 251, 206, 214, 254, 218, 255, 250, 254 },
new byte[] { 251, 206, 215, 254, 218, 255, 250, 254 },
new byte[] { 252, 207, 216, 254, 219, 255, 250, 254 },
new byte[] { 252, 208, 216, 254, 219, 255, 250, 254 },
new byte[] { 252, 209, 217, 254, 220, 255, 250, 254 },
new byte[] { 252, 210, 217, 254, 220, 255, 250, 254 },
new byte[] { 252, 211, 218, 254, 221, 255, 250, 254 },
new byte[] { 252, 212, 218, 254, 221, 255, 250, 254 },
new byte[] { 253, 213, 219, 254, 222, 255, 250, 254 },
new byte[] { 253, 213, 220, 254, 222, 255, 250, 254 },
new byte[] { 253, 214, 221, 254, 223, 255, 250, 254 },
new byte[] { 253, 215, 221, 254, 223, 255, 250, 254 },
new byte[] { 253, 216, 222, 254, 224, 255, 251, 254 },
new byte[] { 253, 217, 223, 254, 224, 255, 251, 254 },
new byte[] { 253, 218, 224, 254, 225, 255, 251, 254 },
new byte[] { 253, 219, 224, 254, 225, 255, 251, 254 },
new byte[] { 254, 220, 225, 254, 225, 255, 251, 254 },
new byte[] { 254, 221, 226, 254, 225, 255, 251, 254 },
new byte[] { 254, 222, 227, 255, 226, 255, 251, 254 },
new byte[] { 254, 223, 227, 255, 226, 255, 251, 254 },
new byte[] { 254, 224, 228, 255, 227, 255, 251, 254 },
new byte[] { 254, 225, 229, 255, 227, 255, 251, 254 },
new byte[] { 254, 226, 230, 255, 228, 255, 251, 254 },
new byte[] { 254, 227, 230, 255, 229, 255, 251, 254 },
new byte[] { 255, 228, 231, 255, 230, 255, 251, 254 },
new byte[] { 255, 229, 232, 255, 230, 255, 251, 254 },
new byte[] { 255, 230, 233, 255, 231, 255, 252, 254 },
new byte[] { 255, 231, 234, 255, 231, 255, 252, 254 },
new byte[] { 255, 232, 235, 255, 232, 255, 252, 254 },
new byte[] { 255, 233, 236, 255, 232, 255, 252, 254 },
new byte[] { 255, 235, 237, 255, 233, 255, 252, 254 },
new byte[] { 255, 236, 238, 255, 234, 255, 252, 254 },
new byte[] { 255, 238, 240, 255, 235, 255, 252, 255 },
new byte[] { 255, 239, 241, 255, 235, 255, 252, 254 },
new byte[] { 255, 241, 243, 255, 236, 255, 252, 254 },
new byte[] { 255, 243, 245, 255, 237, 255, 252, 254 },
new byte[] { 255, 246, 247, 255, 239, 255, 253, 255 }
};
internal static readonly byte[] DefaultCoefProbs4x4 =
{
// Y plane
// Intra
// Band 0
195, 29, 183, 84, 49, 136, 8, 42, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// Band 1
31, 107, 169, 35, 99, 159, 17, 82, 140, 8, 66, 114, 2, 44, 76, 1, 19, 32,
// Band 2
40, 132, 201, 29, 114, 187, 13, 91, 157, 7, 75, 127, 3, 58, 95, 1, 28, 47,
// Band 3
69, 142, 221, 42, 122, 201, 15, 91, 159, 6, 67, 121, 1, 42, 77, 1, 17, 31,
// Band 4
102, 148, 228, 67, 117, 204, 17, 82, 154, 6, 59, 114, 2, 39, 75, 1, 15, 29,
// Band 5
156, 57, 233, 119, 57, 212, 58, 48, 163, 29, 40, 124, 12, 30, 81, 3, 12, 31,
// Inter
// Band 0
191, 107, 226, 124, 117, 204, 25, 99, 155, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// Band 1
29, 148, 210, 37, 126, 194, 8, 93, 157, 2, 68, 118, 1, 39, 69, 1, 17, 33,
// Band 2
41, 151, 213, 27, 123, 193, 3, 82, 144, 1, 58, 105, 1, 32, 60, 1, 13, 26,
// Band 3
59, 159, 220, 23, 126, 198, 4, 88, 151, 1, 66, 114, 1, 38, 71, 1, 18, 34,
// Band 4
114, 136, 232, 51, 114, 207, 11, 83, 155, 3, 56, 105, 1, 33, 65, 1, 17, 34,
// Band 5
149, 65, 234, 121, 57, 215, 61, 49, 166, 28, 36, 114, 12, 25, 76, 3, 16, 42,
// UV plane
// Intra
// Band 0
214, 49, 220, 132, 63, 188, 42, 65, 137, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// Band 1
85, 137, 221, 104, 131, 216, 49, 111, 192, 21, 87, 155, 2, 49, 87, 1, 16, 28,
// Band 2
89, 163, 230, 90, 137, 220, 29, 100, 183, 10, 70, 135, 2, 42, 81, 1, 17, 33,
// Band 3
108, 167, 237, 55, 133, 222, 15, 97, 179, 4, 72, 135, 1, 45, 85, 1, 19, 38,
// Band 4
124, 146, 240, 66, 124, 224, 17, 88, 175, 4, 58, 122, 1, 36, 75, 1, 18, 37,
// Band 5
141, 79, 241, 126, 70, 227, 66, 58, 182, 30, 44, 136, 12, 34, 96, 2, 20, 47,
// Inter
// Band 0
229, 99, 249, 143, 111, 235, 46, 109, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// Band 1
82, 158, 236, 94, 146, 224, 25, 117, 191, 9, 87, 149, 3, 56, 99, 1, 33, 57,
// Band 2
83, 167, 237, 68, 145, 222, 10, 103, 177, 2, 72, 131, 1, 41, 79, 1, 20, 39,
// Band 3
99, 167, 239, 47, 141, 224, 10, 104, 178, 2, 73, 133, 1, 44, 85, 1, 22, 47,
// Band 4
127, 145, 243, 71, 129, 228, 17, 93, 177, 3, 61, 124, 1, 41, 84, 1, 21, 52,
// Band 5
157, 78, 244, 140, 72, 231, 69, 58, 184, 31, 44, 137, 14, 38, 105, 8, 23, 61
};
internal static readonly byte[] DefaultCoefProbs8x8 =
{
// Y plane
// Intra
// Band 0
125, 34, 187, 52, 41, 133, 6, 31, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// Band 1
37, 109, 153, 51, 102, 147, 23, 87, 128, 8, 67, 101, 1, 41, 63, 1, 19, 29,
// Band 2
31, 154, 185, 17, 127, 175, 6, 96, 145, 2, 73, 114, 1, 51, 82, 1, 28, 45,
// Band 3
23, 163, 200, 10, 131, 185, 2, 93, 148, 1, 67, 111, 1, 41, 69, 1, 14, 24,
// Band 4
29, 176, 217, 12, 145, 201, 3, 101, 156, 1, 69, 111, 1, 39, 63, 1, 14, 23,
// Band 5
57, 192, 233, 25, 154, 215, 6, 109, 167, 3, 78, 118, 1, 48, 69, 1, 21, 29,
// Inter
// Band 0
202, 105, 245, 108, 106, 216, 18, 90, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// Band 1
33, 172, 219, 64, 149, 206, 14, 117, 177, 5, 90, 141, 2, 61, 95, 1, 37, 57,
// Band 2
33, 179, 220, 11, 140, 198, 1, 89, 148, 1, 60, 104, 1, 33, 57, 1, 12, 21,
// Band 3
30, 181, 221, 8, 141, 198, 1, 87, 145, 1, 58, 100, 1, 31, 55, 1, 12, 20,
// Band 4
32, 186, 224, 7, 142, 198, 1, 86, 143, 1, 58, 100, 1, 31, 55, 1, 12, 22,
// Band 5
57, 192, 227, 20, 143, 204, 3, 96, 154, 1, 68, 112, 1, 42, 69, 1, 19, 32,
// UV plane
// Intra
// Band 0
212, 35, 215, 113, 47, 169, 29, 48, 105, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// Band 1
74, 129, 203, 106, 120, 203, 49, 107, 178, 19, 84, 144, 4, 50, 84, 1, 15, 25,
// Band 2
71, 172, 217, 44, 141, 209, 15, 102, 173, 6, 76, 133, 2, 51, 89, 1, 24, 42,
// Band 3
64, 185, 231, 31, 148, 216, 8, 103, 175, 3, 74, 131, 1, 46, 81, 1, 18, 30,
// Band 4
65, 196, 235, 25, 157, 221, 5, 105, 174, 1, 67, 120, 1, 38, 69, 1, 15, 30,
// Band 5
65, 204, 238, 30, 156, 224, 7, 107, 177, 2, 70, 124, 1, 42, 73, 1, 18, 34,
// Inter
// Band 0
225, 86, 251, 144, 104, 235, 42, 99, 181, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// Band 1
85, 175, 239, 112, 165, 229, 29, 136, 200, 12, 103, 162, 6, 77, 123, 2, 53, 84,
// Band 2
75, 183, 239, 30, 155, 221, 3, 106, 171, 1, 74, 128, 1, 44, 76, 1, 17, 28,
// Band 3
73, 185, 240, 27, 159, 222, 2, 107, 172, 1, 75, 127, 1, 42, 73, 1, 17, 29,
// Band 4
62, 190, 238, 21, 159, 222, 2, 107, 172, 1, 72, 122, 1, 40, 71, 1, 18, 32,
// Band 5
61, 199, 240, 27, 161, 226, 4, 113, 180, 1, 76, 129, 1, 46, 80, 1, 23, 41
};
internal static readonly byte[] DefaultCoefProbs16x16 =
{
// Y plane
// Intra
// Band 0
7, 27, 153, 5, 30, 95, 1, 16, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// Band 1
50, 75, 127, 57, 75, 124, 27, 67, 108, 10, 54, 86, 1, 33, 52, 1, 12, 18,
// Band 2
43, 125, 151, 26, 108, 148, 7, 83, 122, 2, 59, 89, 1, 38, 60, 1, 17, 27,
// Band 3
23, 144, 163, 13, 112, 154, 2, 75, 117, 1, 50, 81, 1, 31, 51, 1, 14, 23,
// Band 4
18, 162, 185, 6, 123, 171, 1, 78, 125, 1, 51, 86, 1, 31, 54, 1, 14, 23,
// Band 5
15, 199, 227, 3, 150, 204, 1, 91, 146, 1, 55, 95, 1, 30, 53, 1, 11, 20,
// Inter
// Band 0
19, 55, 240, 19, 59, 196, 3, 52, 105, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// Band 1
41, 166, 207, 104, 153, 199, 31, 123, 181, 14, 101, 152, 5, 72, 106, 1, 36, 52,
// Band 2
35, 176, 211, 12, 131, 190, 2, 88, 144, 1, 60, 101, 1, 36, 60, 1, 16, 28,
// Band 3
28, 183, 213, 8, 134, 191, 1, 86, 142, 1, 56, 96, 1, 30, 53, 1, 12, 20,
// Band 4
20, 190, 215, 4, 135, 192, 1, 84, 139, 1, 53, 91, 1, 28, 49, 1, 11, 20,
// Band 5
13, 196, 216, 2, 137, 192, 1, 86, 143, 1, 57, 99, 1, 32, 56, 1, 13, 24,
// UV plane
// Intra
// Band 0
211, 29, 217, 96, 47, 156, 22, 43, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// Band 1
78, 120, 193, 111, 116, 186, 46, 102, 164, 15, 80, 128, 2, 49, 76, 1, 18, 28,
// Band 2
71, 161, 203, 42, 132, 192, 10, 98, 150, 3, 69, 109, 1, 44, 70, 1, 18, 29,
// Band 3
57, 186, 211, 30, 140, 196, 4, 93, 146, 1, 62, 102, 1, 38, 65, 1, 16, 27,
// Band 4
47, 199, 217, 14, 145, 196, 1, 88, 142, 1, 57, 98, 1, 36, 62, 1, 15, 26,
// Band 5
26, 219, 229, 5, 155, 207, 1, 94, 151, 1, 60, 104, 1, 36, 62, 1, 16, 28,
// Inter
// Band 0
233, 29, 248, 146, 47, 220, 43, 52, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// Band 1
100, 163, 232, 179, 161, 222, 63, 142, 204, 37, 113, 174, 26, 89, 137, 18, 68, 97,
// Band 2
85, 181, 230, 32, 146, 209, 7, 100, 164, 3, 71, 121, 1, 45, 77, 1, 18, 30,
// Band 3
65, 187, 230, 20, 148, 207, 2, 97, 159, 1, 68, 116, 1, 40, 70, 1, 14, 29,
// Band 4
40, 194, 227, 8, 147, 204, 1, 94, 155, 1, 65, 112, 1, 39, 66, 1, 14, 26,
// Band 5
16, 208, 228, 3, 151, 207, 1, 98, 160, 1, 67, 117, 1, 41, 74, 1, 17, 31
};
internal static readonly byte[] DefaultCoefProbs32x32 =
{
// Y plane
// Intra
// Band 0
17, 38, 140, 7, 34, 80, 1, 17, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// Band 1
37, 75, 128, 41, 76, 128, 26, 66, 116, 12, 52, 94, 2, 32, 55, 1, 10, 16,
// Band 2
50, 127, 154, 37, 109, 152, 16, 82, 121, 5, 59, 85, 1, 35, 54, 1, 13, 20,
// Band 3
40, 142, 167, 17, 110, 157, 2, 71, 112, 1, 44, 72, 1, 27, 45, 1, 11, 17,
// Band 4
30, 175, 188, 9, 124, 169, 1, 74, 116, 1, 48, 78, 1, 30, 49, 1, 11, 18,
// Band 5
10, 222, 223, 2, 150, 194, 1, 83, 128, 1, 48, 79, 1, 27, 45, 1, 11, 17,
// Inter
// Band 0
36, 41, 235, 29, 36, 193, 10, 27, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// Band 1
85, 165, 222, 177, 162, 215, 110, 135, 195, 57, 113, 168, 23, 83, 120, 10, 49, 61,
// Band 2
85, 190, 223, 36, 139, 200, 5, 90, 146, 1, 60, 103, 1, 38, 65, 1, 18, 30,
// Band 3
72, 202, 223, 23, 141, 199, 2, 86, 140, 1, 56, 97, 1, 36, 61, 1, 16, 27,
// Band 4
55, 218, 225, 13, 145, 200, 1, 86, 141, 1, 57, 99, 1, 35, 61, 1, 13, 22,
// Band 5
15, 235, 212, 1, 132, 184, 1, 84, 139, 1, 57, 97, 1, 34, 56, 1, 14, 23,
// UV plane
// Intra
// Band 0
181, 21, 201, 61, 37, 123, 10, 38, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// Band 1
47, 106, 172, 95, 104, 173, 42, 93, 159, 18, 77, 131, 4, 50, 81, 1, 17, 23,
// Band 2
62, 147, 199, 44, 130, 189, 28, 102, 154, 18, 75, 115, 2, 44, 65, 1, 12, 19,
// Band 3
55, 153, 210, 24, 130, 194, 3, 93, 146, 1, 61, 97, 1, 31, 50, 1, 10, 16,
// Band 4
49, 186, 223, 17, 148, 204, 1, 96, 142, 1, 53, 83, 1, 26, 44, 1, 11, 17,
// Band 5
13, 217, 212, 2, 136, 180, 1, 78, 124, 1, 50, 83, 1, 29, 49, 1, 14, 23,
// Inter
// Band 0
197, 13, 247, 82, 17, 222, 25, 17, 162, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// Band 1
126, 186, 247, 234, 191, 243, 176, 177, 234, 104, 158, 220, 66, 128, 186, 55, 90, 137,
// Band 2
111, 197, 242, 46, 158, 219, 9, 104, 171, 2, 65, 125, 1, 44, 80, 1, 17, 91,
// Band 3
104, 208, 245, 39, 168, 224, 3, 109, 162, 1, 79, 124, 1, 50, 102, 1, 43, 102,
// Band 4
84, 220, 246, 31, 177, 231, 2, 115, 180, 1, 79, 134, 1, 55, 77, 1, 60, 79,
// Band 5
43, 243, 240, 8, 180, 217, 1, 115, 166, 1, 84, 121, 1, 51, 67, 1, 16, 6
};
public static byte[] GetBandTranslate(int txSize)
{
return txSize == (int)TxSize.Tx4x4 ? CoefbandTrans4x4 : CoefbandTrans8x8Plus;
}
public static void CopyProbs<T>(ref T dest, ReadOnlySpan<byte> probs) where T : unmanaged
{
if (Unsafe.SizeOf<T>() != probs.Length)
{
throw new Exception("size mismatch expected: " + probs.Length + " got: " + Unsafe.SizeOf<T>());
}
probs.CopyTo(MemoryMarshal.Cast<T, byte>(MemoryMarshal.CreateSpan(ref dest, 1)));
}
internal const int CoefCountSat = 24;
internal const int CoefMaxUpdateFactor = 112;
internal const int CoefCountSatKey = 24;
internal const int CoefMaxUpdateFactorKey = 112;
internal const int CoefCountSatAfterKey = 24;
internal const int CoefMaxUpdateFactorAfterKey = 128;
}
}

View file

@ -0,0 +1,400 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.Nvdec.Vp9.Common;
using Ryujinx.Graphics.Nvdec.Vp9.Types;
using Ryujinx.Graphics.Video;
using System;
namespace Ryujinx.Graphics.Nvdec.Vp9
{
internal class EntropyMode
{
public const int BlockSizeGroups = 4;
public const int TxSizeContexts = 2;
public static readonly byte[][][] KfYModeProb =
{
new[]
{
// above = dc
new byte[] { 137, 30, 42, 148, 151, 207, 70, 52, 91 }, // left = dc
new byte[] { 92, 45, 102, 136, 116, 180, 74, 90, 100 }, // left = v
new byte[] { 73, 32, 19, 187, 222, 215, 46, 34, 100 }, // left = h
new byte[] { 91, 30, 32, 116, 121, 186, 93, 86, 94 }, // left = d45
new byte[] { 72, 35, 36, 149, 68, 206, 68, 63, 105 }, // left = d135
new byte[] { 73, 31, 28, 138, 57, 124, 55, 122, 151 }, // left = d117
new byte[] { 67, 23, 21, 140, 126, 197, 40, 37, 171 }, // left = d153
new byte[] { 86, 27, 28, 128, 154, 212, 45, 43, 53 }, // left = d207
new byte[] { 74, 32, 27, 107, 86, 160, 63, 134, 102 }, // left = d63
new byte[] { 59, 67, 44, 140, 161, 202, 78, 67, 119 } // left = tm
},
new[]
{
// above = v
new byte[] { 63, 36, 126, 146, 123, 158, 60, 90, 96 }, // left = dc
new byte[] { 43, 46, 168, 134, 107, 128, 69, 142, 92 }, // left = v
new byte[] { 44, 29, 68, 159, 201, 177, 50, 57, 77 }, // left = h
new byte[] { 58, 38, 76, 114, 97, 172, 78, 133, 92 }, // left = d45
new byte[] { 46, 41, 76, 140, 63, 184, 69, 112, 57 }, // left = d135
new byte[] { 38, 32, 85, 140, 46, 112, 54, 151, 133 }, // left = d117
new byte[] { 39, 27, 61, 131, 110, 175, 44, 75, 136 }, // left = d153
new byte[] { 52, 30, 74, 113, 130, 175, 51, 64, 58 }, // left = d207
new byte[] { 47, 35, 80, 100, 74, 143, 64, 163, 74 }, // left = d63
new byte[] { 36, 61, 116, 114, 128, 162, 80, 125, 82 } // left = tm
},
new[]
{
// above = h
new byte[] { 82, 26, 26, 171, 208, 204, 44, 32, 105 }, // left = dc
new byte[] { 55, 44, 68, 166, 179, 192, 57, 57, 108 }, // left = v
new byte[] { 42, 26, 11, 199, 241, 228, 23, 15, 85 }, // left = h
new byte[] { 68, 42, 19, 131, 160, 199, 55, 52, 83 }, // left = d45
new byte[] { 58, 50, 25, 139, 115, 232, 39, 52, 118 }, // left = d135
new byte[] { 50, 35, 33, 153, 104, 162, 64, 59, 131 }, // left = d117
new byte[] { 44, 24, 16, 150, 177, 202, 33, 19, 156 }, // left = d153
new byte[] { 55, 27, 12, 153, 203, 218, 26, 27, 49 }, // left = d207
new byte[] { 53, 49, 21, 110, 116, 168, 59, 80, 76 }, // left = d63
new byte[] { 38, 72, 19, 168, 203, 212, 50, 50, 107 } // left = tm
},
new[]
{
// above = d45
new byte[] { 103, 26, 36, 129, 132, 201, 83, 80, 93 }, // left = dc
new byte[] { 59, 38, 83, 112, 103, 162, 98, 136, 90 }, // left = v
new byte[] { 62, 30, 23, 158, 200, 207, 59, 57, 50 }, // left = h
new byte[] { 67, 30, 29, 84, 86, 191, 102, 91, 59 }, // left = d45
new byte[] { 60, 32, 33, 112, 71, 220, 64, 89, 104 }, // left = d135
new byte[] { 53, 26, 34, 130, 56, 149, 84, 120, 103 }, // left = d117
new byte[] { 53, 21, 23, 133, 109, 210, 56, 77, 172 }, // left = d153
new byte[] { 77, 19, 29, 112, 142, 228, 55, 66, 36 }, // left = d207
new byte[] { 61, 29, 29, 93, 97, 165, 83, 175, 162 }, // left = d63
new byte[] { 47, 47, 43, 114, 137, 181, 100, 99, 95 } // left = tm
},
new[]
{
// above = d135
new byte[] { 69, 23, 29, 128, 83, 199, 46, 44, 101 }, // left = dc
new byte[] { 53, 40, 55, 139, 69, 183, 61, 80, 110 }, // left = v
new byte[] { 40, 29, 19, 161, 180, 207, 43, 24, 91 }, // left = h
new byte[] { 60, 34, 19, 105, 61, 198, 53, 64, 89 }, // left = d45
new byte[] { 52, 31, 22, 158, 40, 209, 58, 62, 89 }, // left = d135
new byte[] { 44, 31, 29, 147, 46, 158, 56, 102, 198 }, // left = d117
new byte[] { 35, 19, 12, 135, 87, 209, 41, 45, 167 }, // left = d153
new byte[] { 55, 25, 21, 118, 95, 215, 38, 39, 66 }, // left = d207
new byte[] { 51, 38, 25, 113, 58, 164, 70, 93, 97 }, // left = d63
new byte[] { 47, 54, 34, 146, 108, 203, 72, 103, 151 } // left = tm
},
new[]
{
// above = d117
new byte[] { 64, 19, 37, 156, 66, 138, 49, 95, 133 }, // left = dc
new byte[] { 46, 27, 80, 150, 55, 124, 55, 121, 135 }, // left = v
new byte[] { 36, 23, 27, 165, 149, 166, 54, 64, 118 }, // left = h
new byte[] { 53, 21, 36, 131, 63, 163, 60, 109, 81 }, // left = d45
new byte[] { 40, 26, 35, 154, 40, 185, 51, 97, 123 }, // left = d135
new byte[] { 35, 19, 34, 179, 19, 97, 48, 129, 124 }, // left = d117
new byte[] { 36, 20, 26, 136, 62, 164, 33, 77, 154 }, // left = d153
new byte[] { 45, 18, 32, 130, 90, 157, 40, 79, 91 }, // left = d207
new byte[] { 45, 26, 28, 129, 45, 129, 49, 147, 123 }, // left = d63
new byte[] { 38, 44, 51, 136, 74, 162, 57, 97, 121 } // left = tm
},
new[]
{
// above = d153
new byte[] { 75, 17, 22, 136, 138, 185, 32, 34, 166 }, // left = dc
new byte[] { 56, 39, 58, 133, 117, 173, 48, 53, 187 }, // left = v
new byte[] { 35, 21, 12, 161, 212, 207, 20, 23, 145 }, // left = h
new byte[] { 56, 29, 19, 117, 109, 181, 55, 68, 112 }, // left = d45
new byte[] { 47, 29, 17, 153, 64, 220, 59, 51, 114 }, // left = d135
new byte[] { 46, 16, 24, 136, 76, 147, 41, 64, 172 }, // left = d117
new byte[] { 34, 17, 11, 108, 152, 187, 13, 15, 209 }, // left = d153
new byte[] { 51, 24, 14, 115, 133, 209, 32, 26, 104 }, // left = d207
new byte[] { 55, 30, 18, 122, 79, 179, 44, 88, 116 }, // left = d63
new byte[] { 37, 49, 25, 129, 168, 164, 41, 54, 148 } // left = tm
},
new[]
{
// above = d207
new byte[] { 82, 22, 32, 127, 143, 213, 39, 41, 70 }, // left = dc
new byte[] { 62, 44, 61, 123, 105, 189, 48, 57, 64 }, // left = v
new byte[] { 47, 25, 17, 175, 222, 220, 24, 30, 86 }, // left = h
new byte[] { 68, 36, 17, 106, 102, 206, 59, 74, 74 }, // left = d45
new byte[] { 57, 39, 23, 151, 68, 216, 55, 63, 58 }, // left = d135
new byte[] { 49, 30, 35, 141, 70, 168, 82, 40, 115 }, // left = d117
new byte[] { 51, 25, 15, 136, 129, 202, 38, 35, 139 }, // left = d153
new byte[] { 68, 26, 16, 111, 141, 215, 29, 28, 28 }, // left = d207
new byte[] { 59, 39, 19, 114, 75, 180, 77, 104, 42 }, // left = d63
new byte[] { 40, 61, 26, 126, 152, 206, 61, 59, 93 } // left = tm
},
new[]
{
// above = d63
new byte[] { 78, 23, 39, 111, 117, 170, 74, 124, 94 }, // left = dc
new byte[] { 48, 34, 86, 101, 92, 146, 78, 179, 134 }, // left = v
new byte[] { 47, 22, 24, 138, 187, 178, 68, 69, 59 }, // left = h
new byte[] { 56, 25, 33, 105, 112, 187, 95, 177, 129 }, // left = d45
new byte[] { 48, 31, 27, 114, 63, 183, 82, 116, 56 }, // left = d135
new byte[] { 43, 28, 37, 121, 63, 123, 61, 192, 169 }, // left = d117
new byte[] { 42, 17, 24, 109, 97, 177, 56, 76, 122 }, // left = d153
new byte[] { 58, 18, 28, 105, 139, 182, 70, 92, 63 }, // left = d207
new byte[] { 46, 23, 32, 74, 86, 150, 67, 183, 88 }, // left = d63
new byte[] { 36, 38, 48, 92, 122, 165, 88, 137, 91 } // left = tm
},
new[]
{
// above = tm
new byte[] { 65, 70, 60, 155, 159, 199, 61, 60, 81 }, // left = dc
new byte[] { 44, 78, 115, 132, 119, 173, 71, 112, 93 }, // left = v
new byte[] { 39, 38, 21, 184, 227, 206, 42, 32, 64 }, // left = h
new byte[] { 58, 47, 36, 124, 137, 193, 80, 82, 78 }, // left = d45
new byte[] { 49, 50, 35, 144, 95, 205, 63, 78, 59 }, // left = d135
new byte[] { 41, 53, 52, 148, 71, 142, 65, 128, 51 }, // left = d117
new byte[] { 40, 36, 28, 143, 143, 202, 40, 55, 137 }, // left = d153
new byte[] { 52, 34, 29, 129, 183, 227, 42, 35, 43 }, // left = d207
new byte[] { 42, 44, 44, 104, 105, 164, 64, 130, 80 }, // left = d63
new byte[] { 43, 81, 53, 140, 169, 204, 68, 84, 72 } // left = tm
}
};
public static readonly byte[][] KfUvModeProb =
{
new byte[] { 144, 11, 54, 157, 195, 130, 46, 58, 108 }, // y = dc
new byte[] { 118, 15, 123, 148, 131, 101, 44, 93, 131 }, // y = v
new byte[] { 113, 12, 23, 188, 226, 142, 26, 32, 125 }, // y = h
new byte[] { 120, 11, 50, 123, 163, 135, 64, 77, 103 }, // y = d45
new byte[] { 113, 9, 36, 155, 111, 157, 32, 44, 161 }, // y = d135
new byte[] { 116, 9, 55, 176, 76, 96, 37, 61, 149 }, // y = d117
new byte[] { 115, 9, 28, 141, 161, 167, 21, 25, 193 }, // y = d153
new byte[] { 120, 12, 32, 145, 195, 142, 32, 38, 86 }, // y = d207
new byte[] { 116, 12, 64, 120, 140, 125, 49, 115, 121 }, // y = d63
new byte[] { 102, 19, 66, 162, 182, 122, 35, 59, 128 } // y = tm
};
private static readonly byte[] DefaultIfYProbs =
{
65, 32, 18, 144, 162, 194, 41, 51, 98, // block_size < 8x8
132, 68, 18, 165, 217, 196, 45, 40, 78, // block_size < 16x16
173, 80, 19, 176, 240, 193, 64, 35, 46, // block_size < 32x32
221, 135, 38, 194, 248, 121, 96, 85, 29 // block_size >= 32x32
};
private static readonly byte[] DefaultIfUvProbs =
{
120, 7, 76, 176, 208, 126, 28, 54, 103, // y = dc
48, 12, 154, 155, 139, 90, 34, 117, 119, // y = v
67, 6, 25, 204, 243, 158, 13, 21, 96, // y = h
97, 5, 44, 131, 176, 139, 48, 68, 97, // y = d45
83, 5, 42, 156, 111, 152, 26, 49, 152, // y = d135
80, 5, 58, 178, 74, 83, 33, 62, 145, // y = d117
86, 5, 32, 154, 192, 168, 14, 22, 163, // y = d153
85, 5, 32, 156, 216, 148, 19, 29, 73, // y = d207
77, 7, 64, 116, 132, 122, 37, 126, 120, // y = d63
101, 21, 107, 181, 192, 103, 19, 67, 125 // y = tm
};
private static readonly byte[] DefaultPartitionProbs =
{
// 8x8 . 4x4
199, 122, 141, // a/l both not split
147, 63, 159, // a split, l not split
148, 133, 118, // l split, a not split
121, 104, 114, // a/l both split
// 16x16 . 8x8
174, 73, 87, // a/l both not split
92, 41, 83, // a split, l not split
82, 99, 50, // l split, a not split
53, 39, 39, // a/l both split
// 32x32 . 16x16
177, 58, 59, // a/l both not split
68, 26, 63, // a split, l not split
52, 79, 25, // l split, a not split
17, 14, 12, // a/l both split
// 64x64 . 32x32
222, 34, 30, // a/l both not split
72, 16, 44, // a split, l not split
58, 32, 12, // l split, a not split
10, 7, 6 // a/l both split
};
private static readonly byte[] DefaultInterModeProbs =
{
2, 173, 34, // 0 = both zero mv
7, 145, 85, // 1 = one zero mv + one a predicted mv
7, 166, 63, // 2 = two predicted mvs
7, 94, 66, // 3 = one predicted/zero and one new mv
8, 64, 46, // 4 = two new mvs
17, 81, 31, // 5 = one intra neighbour + x
25, 29, 30 // 6 = two intra neighbours
};
/* Array indices are identical to previously-existing INTRAMODECONTEXTNODES. */
public static readonly sbyte[] IntraModeTree =
{
-(int)PredictionMode.DcPred, 2, /* 0 = DC_NODE */ -(int)PredictionMode.TmPred, 4, /* 1 = TM_NODE */
-(int)PredictionMode.VPred, 6, /* 2 = V_NODE */ 8, 12, /* 3 = COM_NODE */ -(int)PredictionMode.HPred,
10, /* 4 = H_NODE */ -(int)PredictionMode.D135Pred, -(int)PredictionMode.D117Pred, /* 5 = D135_NODE */
-(int)PredictionMode.D45Pred, 14, /* 6 = D45_NODE */ -(int)PredictionMode.D63Pred,
16, /* 7 = D63_NODE */ -(int)PredictionMode.D153Pred, -(int)PredictionMode.D207Pred /* 8 = D153_NODE */
};
public static readonly sbyte[] InterModeTree =
{
-((int)PredictionMode.ZeroMv - (int)PredictionMode.NearestMv), 2,
-((int)PredictionMode.NearestMv - (int)PredictionMode.NearestMv), 4,
-((int)PredictionMode.NearMv - (int)PredictionMode.NearestMv),
-((int)PredictionMode.NewMv - (int)PredictionMode.NearestMv)
};
public static readonly sbyte[] PartitionTree =
{
-(sbyte)PartitionType.PartitionNone, 2, -(sbyte)PartitionType.PartitionHorz, 4,
-(sbyte)PartitionType.PartitionVert, -(sbyte)PartitionType.PartitionSplit
};
public static readonly sbyte[] SwitchableInterpTree =
{
-Constants.EightTap, 2, -Constants.EightTapSmooth, -Constants.EightTapSharp
};
private static readonly byte[] DefaultIntraInterP = { 9, 102, 187, 225 };
private static readonly byte[] DefaultCompInterP = { 239, 183, 119, 96, 41 };
private static readonly byte[] DefaultCompRefP = { 50, 126, 123, 221, 226 };
private static readonly byte[] DefaultSingleRefP = { 33, 16, 77, 74, 142, 142, 172, 170, 238, 247 };
private static readonly byte[] DefaultTxProbs = { 3, 136, 37, 5, 52, 13, 20, 152, 15, 101, 100, 66 };
static EntropyMode()
{
byte[][] KfPartitionProbs =
{
// 8x8 . 4x4
new byte[] { 158, 97, 94 }, // a/l both not split
new byte[] { 93, 24, 99 }, // a split, l not split
new byte[] { 85, 119, 44 }, // l split, a not split
new byte[] { 62, 59, 67 }, // a/l both split
// 16x16 . 8x8
new byte[] { 149, 53, 53 }, // a/l both not split
new byte[] { 94, 20, 48 }, // a split, l not split
new byte[] { 83, 53, 24 }, // l split, a not split
new byte[] { 52, 18, 18 }, // a/l both split
// 32x32 . 16x16
new byte[] { 150, 40, 39 }, // a/l both not split
new byte[] { 78, 12, 26 }, // a split, l not split
new byte[] { 67, 33, 11 }, // l split, a not split
new byte[] { 24, 7, 5 }, // a/l both split
// 64x64 . 32x32
new byte[] { 174, 35, 49 }, // a/l both not split
new byte[] { 68, 11, 27 }, // a split, l not split
new byte[] { 57, 15, 9 }, // l split, a not split
new byte[] { 12, 3, 3 } // a/l both split
};
}
private static readonly byte[] DefaultSkipProbs = { 192, 128, 64 };
private static readonly byte[] DefaultSwitchableInterpProb = { 235, 162, 36, 255, 34, 3, 149, 144 };
private static void InitModeProbs(ref Vp9EntropyProbs fc)
{
Entropy.CopyProbs(ref fc.UvModeProb, DefaultIfUvProbs);
Entropy.CopyProbs(ref fc.YModeProb, DefaultIfYProbs);
Entropy.CopyProbs(ref fc.SwitchableInterpProb, DefaultSwitchableInterpProb);
Entropy.CopyProbs(ref fc.PartitionProb, DefaultPartitionProbs);
Entropy.CopyProbs(ref fc.IntraInterProb, DefaultIntraInterP);
Entropy.CopyProbs(ref fc.CompInterProb, DefaultCompInterP);
Entropy.CopyProbs(ref fc.CompRefProb, DefaultCompRefP);
Entropy.CopyProbs(ref fc.SingleRefProb, DefaultSingleRefP);
Entropy.CopyProbs(ref fc.Tx32x32Prob, DefaultTxProbs.AsSpan().Slice(0, 6));
Entropy.CopyProbs(ref fc.Tx16x16Prob, DefaultTxProbs.AsSpan().Slice(6, 4));
Entropy.CopyProbs(ref fc.Tx8x8Prob, DefaultTxProbs.AsSpan().Slice(10, 2));
Entropy.CopyProbs(ref fc.SkipProb, DefaultSkipProbs);
Entropy.CopyProbs(ref fc.InterModeProb, DefaultInterModeProbs);
}
internal static void TxCountsToBranchCounts32x32(ReadOnlySpan<uint> txCount32x32P,
ref Array3<Array2<uint>> ct32x32P)
{
ct32x32P[0][0] = txCount32x32P[(int)TxSize.Tx4x4];
ct32x32P[0][1] = txCount32x32P[(int)TxSize.Tx8x8] + txCount32x32P[(int)TxSize.Tx16x16] +
txCount32x32P[(int)TxSize.Tx32x32];
ct32x32P[1][0] = txCount32x32P[(int)TxSize.Tx8x8];
ct32x32P[1][1] = txCount32x32P[(int)TxSize.Tx16x16] + txCount32x32P[(int)TxSize.Tx32x32];
ct32x32P[2][0] = txCount32x32P[(int)TxSize.Tx16x16];
ct32x32P[2][1] = txCount32x32P[(int)TxSize.Tx32x32];
}
internal static void TxCountsToBranchCounts16x16(ReadOnlySpan<uint> txCount16x16P,
ref Array2<Array2<uint>> ct16x16P)
{
ct16x16P[0][0] = txCount16x16P[(int)TxSize.Tx4x4];
ct16x16P[0][1] = txCount16x16P[(int)TxSize.Tx8x8] + txCount16x16P[(int)TxSize.Tx16x16];
ct16x16P[1][0] = txCount16x16P[(int)TxSize.Tx8x8];
ct16x16P[1][1] = txCount16x16P[(int)TxSize.Tx16x16];
}
internal static void TxCountsToBranchCounts8x8(ReadOnlySpan<uint> txCount8x8P,
ref Array1<Array2<uint>> ct8x8P)
{
ct8x8P[0][0] = txCount8x8P[(int)TxSize.Tx4x4];
ct8x8P[0][1] = txCount8x8P[(int)TxSize.Tx8x8];
}
public static unsafe void SetupPastIndependence(ref Vp9Common cm)
{
// Reset the segment feature data to the default stats:
// Features disabled, 0, with delta coding (Default state).
ref Types.LoopFilter lf = ref cm.Lf;
cm.Seg.ClearAllSegFeatures();
cm.Seg.AbsDelta = Segmentation.SegmentDeltadata;
if (!cm.LastFrameSegMap.IsNull)
{
MemoryUtil.Fill(cm.LastFrameSegMap.ToPointer(), (byte)0, cm.MiRows * cm.MiCols);
}
if (!cm.CurrentFrameSegMap.IsNull)
{
MemoryUtil.Fill(cm.CurrentFrameSegMap.ToPointer(), (byte)0, cm.MiRows * cm.MiCols);
}
// Reset the mode ref deltas for loop filter
lf.LastRefDeltas = new Array4<sbyte>();
lf.LastModeDeltas = new Array2<sbyte>();
lf.SetDefaultLfDeltas();
// To force update of the sharpness
lf.LastSharpnessLevel = -1;
cm.DefaultCoefProbs();
InitModeProbs(ref cm.Fc.Value);
cm.InitMvProbs();
if (cm.FrameType == FrameType.KeyFrame || cm.ErrorResilientMode != 0 || cm.ResetFrameContext == 3)
{
// Reset all frame contexts.
for (int i = 0; i < Constants.FrameContexts; ++i)
{
cm.FrameContexts[i] = cm.Fc.Value;
}
}
else if (cm.ResetFrameContext == 2)
{
// Reset only the frame context specified in the frame header.
cm.FrameContexts[(int)cm.FrameContextIdx] = cm.Fc.Value;
}
// prev_mip will only be allocated in encoder.
if (cm.FrameIsIntraOnly() && !cm.PrevMip.IsNull)
{
cm.PrevMi.Value = new ModeInfo();
}
cm.RefFrameSignBias = new Array4<sbyte>();
cm.FrameContextIdx = 0;
}
}
}

View file

@ -0,0 +1,165 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.Nvdec.Vp9.Types;
using Ryujinx.Graphics.Video;
using System.Diagnostics;
namespace Ryujinx.Graphics.Nvdec.Vp9
{
internal static class EntropyMv
{
public const int UpdateProb = 252;
/* Symbols for coding which components are zero jointly */
public const int Joints = 4;
public static readonly sbyte[] JointTree =
{
-(sbyte)MvJointType.Zero, 2, -(sbyte)MvJointType.Hnzvz, 4,
-(sbyte)MvJointType.Hzvnz, -(sbyte)MvJointType.Hnzvnz
};
public static readonly sbyte[] ClassTree =
{
-(sbyte)MvClassType.Class0, 2, -(sbyte)MvClassType.Class1, 4, 6, 8, -(sbyte)MvClassType.Class2,
-(sbyte)MvClassType.Class3, 10, 12, -(sbyte)MvClassType.Class4, -(sbyte)MvClassType.Class5,
-(sbyte)MvClassType.Class6, 14, 16, 18, -(sbyte)MvClassType.Class7, -(sbyte)MvClassType.Class8,
-(sbyte)MvClassType.Class9, -(sbyte)MvClassType.Class10
};
public static readonly sbyte[] Class0Tree = { -0, -1 };
public static readonly sbyte[] FpTree = { -0, 2, -1, 4, -2, -3 };
private static bool JointVertical(MvJointType type)
{
return type == MvJointType.Hzvnz || type == MvJointType.Hnzvnz;
}
private static bool JointHorizontal(MvJointType type)
{
return type == MvJointType.Hnzvz || type == MvJointType.Hnzvnz;
}
private static readonly byte[] LogInBase2 =
{
0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 10
};
private static int ClassBase(MvClassType c)
{
return c != 0 ? Class0Size << ((int)c + 2) : 0;
}
private static MvClassType GetClass(int z, Ptr<int> offset)
{
MvClassType c = z >= Class0Size * 4096
? MvClassType.Class10
: (MvClassType)LogInBase2[z >> 3];
if (!offset.IsNull)
{
offset.Value = z - ClassBase(c);
}
return c;
}
private static void IncComponent(int v, ref Vp9BackwardUpdates compCounts, int compIndex, int incr, int usehp)
{
int s, z, c, o = 0, d, e, f;
Debug.Assert(v != 0); /* should not be zero */
s = v < 0 ? 1 : 0;
compCounts.Sign[compIndex][s] += (uint)incr;
z = (s != 0 ? -v : v) - 1; /* magnitude - 1 */
c = (int)GetClass(z, new Ptr<int>(ref o));
compCounts.Classes[compIndex][c] += (uint)incr;
d = o >> 3; /* int mv data */
f = (o >> 1) & 3; /* fractional pel mv data */
e = o & 1; /* high precision mv data */
if (c == (int)MvClassType.Class0)
{
compCounts.Class0[compIndex][d] += (uint)incr;
compCounts.Class0Fp[compIndex][d][f] += (uint)incr;
compCounts.Class0Hp[compIndex][e] += (uint)(usehp * incr);
}
else
{
int b = c + Class0Bits - 1; // number of bits
for (int i = 0; i < b; ++i)
{
compCounts.Bits[compIndex][i][(d >> i) & 1] += (uint)incr;
}
compCounts.Fp[compIndex][f] += (uint)incr;
compCounts.Hp[compIndex][e] += (uint)(usehp * incr);
}
}
public static void Inc(ref Mv mv, Ptr<Vp9BackwardUpdates> counts)
{
if (!counts.IsNull)
{
MvJointType j = mv.GetJoint();
++counts.Value.Joints[(int)j];
if (JointVertical(j))
{
IncComponent(mv.Row, ref counts.Value, 0, 1, 1);
}
if (JointHorizontal(j))
{
IncComponent(mv.Col, ref counts.Value, 1, 1, 1);
}
}
}
/* Symbols for coding magnitude class of nonzero components */
public const int Classes = 11;
public const int Class0Bits = 1; /* bits at integer precision for class 0 */
public const int Class0Size = 1 << Class0Bits;
public const int OffsetBits = Classes + Class0Bits - 2;
public const int FpSize = 4;
public const int MaxBits = Classes + Class0Bits + 2;
public const int Max = (1 << MaxBits) - 1;
public const int Vals = (Max << 1) + 1;
public const int InUseBits = 14;
public const int Upp = (1 << InUseBits) - 1;
public const int Low = -(1 << InUseBits);
}
}

View file

@ -0,0 +1,79 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.Nvdec.Vp9.Common;
using Ryujinx.Graphics.Nvdec.Vp9.Types;
namespace Ryujinx.Graphics.Nvdec.Vp9
{
internal struct InternalFrameBuffer
{
public ArrayPtr<byte> Data;
public bool InUse;
}
internal struct InternalFrameBufferList
{
public ArrayPtr<InternalFrameBuffer> IntFb;
}
internal static class FrameBuffers
{
public static int GetFrameBuffer(MemoryAllocator allocator, Ptr<InternalFrameBufferList> cbPriv, ulong minSize,
ref VpxCodecFrameBuffer fb)
{
int i;
Ptr<InternalFrameBufferList> intFbList = cbPriv;
if (intFbList.IsNull)
{
return -1;
}
// Find a free frame buffer.
for (i = 0; i < intFbList.Value.IntFb.Length; ++i)
{
if (!intFbList.Value.IntFb[i].InUse)
{
break;
}
}
if (i == intFbList.Value.IntFb.Length)
{
return -1;
}
if ((ulong)intFbList.Value.IntFb[i].Data.Length < minSize)
{
if (!intFbList.Value.IntFb[i].Data.IsNull)
{
allocator.Free(intFbList.Value.IntFb[i].Data);
}
// The data must be zeroed to fix a valgrind error from the C loop filter
// due to access uninitialized memory in frame border. It could be
// skipped if border were totally removed.
intFbList.Value.IntFb[i].Data = allocator.Allocate<byte>((int)minSize);
if (intFbList.Value.IntFb[i].Data.IsNull)
{
return -1;
}
}
fb.Data = intFbList.Value.IntFb[i].Data;
intFbList.Value.IntFb[i].InUse = true;
// Set the frame buffer's private data to point at the internal frame buffer.
fb.Priv = new Ptr<InternalFrameBuffer>(ref intFbList.Value.IntFb[i]);
return 0;
}
public static int ReleaseFrameBuffer(Ptr<InternalFrameBufferList> cbPriv, ref VpxCodecFrameBuffer fb)
{
if (!fb.Priv.IsNull)
{
fb.Priv.Value.InUse = false;
}
return 0;
}
}
}

View file

@ -8,11 +8,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
internal static class Idct internal static class Idct
{ {
private delegate void Transform1D(ReadOnlySpan<int> input, Span<int> output); private delegate void Transform1D(ReadOnlySpan<int> input, Span<int> output);
private delegate void HighbdTransform1D(ReadOnlySpan<int> input, Span<int> output, int bd); private delegate void HighbdTransform1D(ReadOnlySpan<int> input, Span<int> output, int bd);
private struct Transform2D private struct Transform2D
{ {
public Transform1D Cols, Rows; // Vertical and horizontal public readonly Transform1D Cols; // Vertical and horizontal
public readonly Transform1D Rows; // Vertical and horizontal
public Transform2D(Transform1D cols, Transform1D rows) public Transform2D(Transform1D cols, Transform1D rows)
{ {
@ -23,7 +25,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
private struct HighbdTransform2D private struct HighbdTransform2D
{ {
public HighbdTransform1D Cols, Rows; // Vertical and horizontal public readonly HighbdTransform1D Cols; // Vertical and horizontal
public readonly HighbdTransform1D Rows; // Vertical and horizontal
public HighbdTransform2D(HighbdTransform1D cols, HighbdTransform1D rows) public HighbdTransform2D(HighbdTransform1D cols, HighbdTransform1D rows)
{ {
@ -32,24 +35,23 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
} }
} }
private static readonly Transform2D[] Iht4 = new Transform2D[] private static readonly Transform2D[] Iht4 =
{ {
new Transform2D(Idct4, Idct4), // DCT_DCT = 0 new(Idct4, Idct4), // DCT_DCT = 0
new Transform2D(Iadst4, Idct4), // ADST_DCT = 1 new(Iadst4, Idct4), // ADST_DCT = 1
new Transform2D(Idct4, Iadst4), // DCT_ADST = 2 new(Idct4, Iadst4), // DCT_ADST = 2
new Transform2D(Iadst4, Iadst4) // ADST_ADST = 3 new(Iadst4, Iadst4) // ADST_ADST = 3
}; };
public static void Iht4x416Add(ReadOnlySpan<int> input, Span<byte> dest, int stride, int txType) public static void Iht4x416Add(ReadOnlySpan<int> input, Span<byte> dest, int stride, int txType)
{ {
int i, j;
Span<int> output = stackalloc int[4 * 4]; Span<int> output = stackalloc int[4 * 4];
Span<int> outptr = output; Span<int> outptr = output;
Span<int> tempIn = stackalloc int[4]; Span<int> tempIn = stackalloc int[4];
Span<int> tempOut = stackalloc int[4]; Span<int> tempOut = stackalloc int[4];
// Inverse transform row vectors // Inverse transform row vectors
for (i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i)
{ {
Iht4[txType].Rows(input, outptr); Iht4[txType].Rows(input, outptr);
input = input.Slice(4); input = input.Slice(4);
@ -57,32 +59,32 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
} }
// Inverse transform column vectors // Inverse transform column vectors
for (i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i)
{ {
for (j = 0; j < 4; ++j) for (int j = 0; j < 4; ++j)
{ {
tempIn[j] = output[j * 4 + i]; tempIn[j] = output[(j * 4) + i];
} }
Iht4[txType].Cols(tempIn, tempOut); Iht4[txType].Cols(tempIn, tempOut);
for (j = 0; j < 4; ++j) for (int j = 0; j < 4; ++j)
{ {
dest[j * stride + i] = ClipPixelAdd(dest[j * stride + i], BitUtils.RoundPowerOfTwo(tempOut[j], 4)); dest[(j * stride) + i] =
ClipPixelAdd(dest[(j * stride) + i], BitUtils.RoundPowerOfTwo(tempOut[j], 4));
} }
} }
} }
private static readonly Transform2D[] Iht8 = new Transform2D[] private static readonly Transform2D[] Iht8 =
{ {
new Transform2D(Idct8, Idct8), // DCT_DCT = 0 new(Idct8, Idct8), // DCT_DCT = 0
new Transform2D(Iadst8, Idct8), // ADST_DCT = 1 new(Iadst8, Idct8), // ADST_DCT = 1
new Transform2D(Idct8, Iadst8), // DCT_ADST = 2 new(Idct8, Iadst8), // DCT_ADST = 2
new Transform2D(Iadst8, Iadst8) // ADST_ADST = 3 new(Iadst8, Iadst8) // ADST_ADST = 3
}; };
public static void Iht8x864Add(ReadOnlySpan<int> input, Span<byte> dest, int stride, int txType) public static void Iht8x864Add(ReadOnlySpan<int> input, Span<byte> dest, int stride, int txType)
{ {
int i, j;
Span<int> output = stackalloc int[8 * 8]; Span<int> output = stackalloc int[8 * 8];
Span<int> outptr = output; Span<int> outptr = output;
Span<int> tempIn = stackalloc int[8]; Span<int> tempIn = stackalloc int[8];
@ -90,7 +92,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
Transform2D ht = Iht8[txType]; Transform2D ht = Iht8[txType];
// Inverse transform row vectors // Inverse transform row vectors
for (i = 0; i < 8; ++i) for (int i = 0; i < 8; ++i)
{ {
ht.Rows(input, outptr); ht.Rows(input, outptr);
input = input.Slice(8); input = input.Slice(8);
@ -98,32 +100,32 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
} }
// Inverse transform column vectors // Inverse transform column vectors
for (i = 0; i < 8; ++i) for (int i = 0; i < 8; ++i)
{ {
for (j = 0; j < 8; ++j) for (int j = 0; j < 8; ++j)
{ {
tempIn[j] = output[j * 8 + i]; tempIn[j] = output[(j * 8) + i];
} }
ht.Cols(tempIn, tempOut); ht.Cols(tempIn, tempOut);
for (j = 0; j < 8; ++j) for (int j = 0; j < 8; ++j)
{ {
dest[j * stride + i] = ClipPixelAdd(dest[j * stride + i], BitUtils.RoundPowerOfTwo(tempOut[j], 5)); dest[(j * stride) + i] =
ClipPixelAdd(dest[(j * stride) + i], BitUtils.RoundPowerOfTwo(tempOut[j], 5));
} }
} }
} }
private static readonly Transform2D[] Iht16 = new Transform2D[] private static readonly Transform2D[] Iht16 =
{ {
new Transform2D(Idct16, Idct16), // DCT_DCT = 0 new(Idct16, Idct16), // DCT_DCT = 0
new Transform2D(Iadst16, Idct16), // ADST_DCT = 1 new(Iadst16, Idct16), // ADST_DCT = 1
new Transform2D(Idct16, Iadst16), // DCT_ADST = 2 new(Idct16, Iadst16), // DCT_ADST = 2
new Transform2D(Iadst16, Iadst16) // ADST_ADST = 3 new(Iadst16, Iadst16) // ADST_ADST = 3
}; };
public static void Iht16x16256Add(ReadOnlySpan<int> input, Span<byte> dest, int stride, int txType) public static void Iht16x16256Add(ReadOnlySpan<int> input, Span<byte> dest, int stride, int txType)
{ {
int i, j;
Span<int> output = stackalloc int[16 * 16]; Span<int> output = stackalloc int[16 * 16];
Span<int> outptr = output; Span<int> outptr = output;
Span<int> tempIn = stackalloc int[16]; Span<int> tempIn = stackalloc int[16];
@ -131,7 +133,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
Transform2D ht = Iht16[txType]; Transform2D ht = Iht16[txType];
// Rows // Rows
for (i = 0; i < 16; ++i) for (int i = 0; i < 16; ++i)
{ {
ht.Rows(input, outptr); ht.Rows(input, outptr);
input = input.Slice(16); input = input.Slice(16);
@ -139,17 +141,18 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
} }
// Columns // Columns
for (i = 0; i < 16; ++i) for (int i = 0; i < 16; ++i)
{ {
for (j = 0; j < 16; ++j) for (int j = 0; j < 16; ++j)
{ {
tempIn[j] = output[j * 16 + i]; tempIn[j] = output[(j * 16) + i];
} }
ht.Cols(tempIn, tempOut); ht.Cols(tempIn, tempOut);
for (j = 0; j < 16; ++j) for (int j = 0; j < 16; ++j)
{ {
dest[j * stride + i] = ClipPixelAdd(dest[j * stride + i], BitUtils.RoundPowerOfTwo(tempOut[j], 6)); dest[(j * stride) + i] =
ClipPixelAdd(dest[(j * stride) + i], BitUtils.RoundPowerOfTwo(tempOut[j], 6));
} }
} }
} }
@ -283,24 +286,23 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
} }
} }
private static readonly HighbdTransform2D[] HighbdIht4 = new HighbdTransform2D[] private static readonly HighbdTransform2D[] HighbdIht4 =
{ {
new HighbdTransform2D(HighbdIdct4, HighbdIdct4), // DCT_DCT = 0 new(HighbdIdct4, HighbdIdct4), // DCT_DCT = 0
new HighbdTransform2D(HighbdIadst4, HighbdIdct4), // ADST_DCT = 1 new(HighbdIadst4, HighbdIdct4), // ADST_DCT = 1
new HighbdTransform2D(HighbdIdct4, HighbdIadst4), // DCT_ADST = 2 new(HighbdIdct4, HighbdIadst4), // DCT_ADST = 2
new HighbdTransform2D(HighbdIadst4, HighbdIadst4) // ADST_ADST = 3 new(HighbdIadst4, HighbdIadst4) // ADST_ADST = 3
}; };
public static void HighbdIht4x416Add(ReadOnlySpan<int> input, Span<ushort> dest, int stride, int txType, int bd) public static void HighbdIht4x416Add(ReadOnlySpan<int> input, Span<ushort> dest, int stride, int txType, int bd)
{ {
int i, j;
Span<int> output = stackalloc int[4 * 4]; Span<int> output = stackalloc int[4 * 4];
Span<int> outptr = output; Span<int> outptr = output;
Span<int> tempIn = stackalloc int[4]; Span<int> tempIn = stackalloc int[4];
Span<int> tempOut = stackalloc int[4]; Span<int> tempOut = stackalloc int[4];
// Inverse transform row vectors. // Inverse transform row vectors.
for (i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i)
{ {
HighbdIht4[txType].Rows(input, outptr, bd); HighbdIht4[txType].Rows(input, outptr, bd);
input = input.Slice(4); input = input.Slice(4);
@ -308,32 +310,32 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
} }
// Inverse transform column vectors. // Inverse transform column vectors.
for (i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i)
{ {
for (j = 0; j < 4; ++j) for (int j = 0; j < 4; ++j)
{ {
tempIn[j] = output[j * 4 + i]; tempIn[j] = output[(j * 4) + i];
} }
HighbdIht4[txType].Cols(tempIn, tempOut, bd); HighbdIht4[txType].Cols(tempIn, tempOut, bd);
for (j = 0; j < 4; ++j) for (int j = 0; j < 4; ++j)
{ {
dest[j * stride + i] = HighbdClipPixelAdd(dest[j * stride + i], BitUtils.RoundPowerOfTwo(tempOut[j], 4), bd); dest[(j * stride) + i] = HighbdClipPixelAdd(dest[(j * stride) + i],
BitUtils.RoundPowerOfTwo(tempOut[j], 4), bd);
} }
} }
} }
private static readonly HighbdTransform2D[] HighIht8 = new HighbdTransform2D[] private static readonly HighbdTransform2D[] HighIht8 =
{ {
new HighbdTransform2D(HighbdIdct8, HighbdIdct8), // DCT_DCT = 0 new(HighbdIdct8, HighbdIdct8), // DCT_DCT = 0
new HighbdTransform2D(HighbdIadst8, HighbdIdct8), // ADST_DCT = 1 new(HighbdIadst8, HighbdIdct8), // ADST_DCT = 1
new HighbdTransform2D(HighbdIdct8, HighbdIadst8), // DCT_ADST = 2 new(HighbdIdct8, HighbdIadst8), // DCT_ADST = 2
new HighbdTransform2D(HighbdIadst8, HighbdIadst8) // ADST_ADST = 3 new(HighbdIadst8, HighbdIadst8) // ADST_ADST = 3
}; };
public static void HighbdIht8x864Add(ReadOnlySpan<int> input, Span<ushort> dest, int stride, int txType, int bd) public static void HighbdIht8x864Add(ReadOnlySpan<int> input, Span<ushort> dest, int stride, int txType, int bd)
{ {
int i, j;
Span<int> output = stackalloc int[8 * 8]; Span<int> output = stackalloc int[8 * 8];
Span<int> outptr = output; Span<int> outptr = output;
Span<int> tempIn = stackalloc int[8]; Span<int> tempIn = stackalloc int[8];
@ -341,7 +343,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
HighbdTransform2D ht = HighIht8[txType]; HighbdTransform2D ht = HighIht8[txType];
// Inverse transform row vectors. // Inverse transform row vectors.
for (i = 0; i < 8; ++i) for (int i = 0; i < 8; ++i)
{ {
ht.Rows(input, outptr, bd); ht.Rows(input, outptr, bd);
input = input.Slice(8); input = input.Slice(8);
@ -349,32 +351,33 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
} }
// Inverse transform column vectors. // Inverse transform column vectors.
for (i = 0; i < 8; ++i) for (int i = 0; i < 8; ++i)
{ {
for (j = 0; j < 8; ++j) for (int j = 0; j < 8; ++j)
{ {
tempIn[j] = output[j * 8 + i]; tempIn[j] = output[(j * 8) + i];
} }
ht.Cols(tempIn, tempOut, bd); ht.Cols(tempIn, tempOut, bd);
for (j = 0; j < 8; ++j) for (int j = 0; j < 8; ++j)
{ {
dest[j * stride + i] = HighbdClipPixelAdd(dest[j * stride + i], BitUtils.RoundPowerOfTwo(tempOut[j], 5), bd); dest[(j * stride) + i] = HighbdClipPixelAdd(dest[(j * stride) + i],
BitUtils.RoundPowerOfTwo(tempOut[j], 5), bd);
} }
} }
} }
private static readonly HighbdTransform2D[] HighIht16 = new HighbdTransform2D[] private static readonly HighbdTransform2D[] HighIht16 =
{ {
new HighbdTransform2D(HighbdIdct16, HighbdIdct16), // DCT_DCT = 0 new(HighbdIdct16, HighbdIdct16), // DCT_DCT = 0
new HighbdTransform2D(HighbdIadst16, HighbdIdct16), // ADST_DCT = 1 new(HighbdIadst16, HighbdIdct16), // ADST_DCT = 1
new HighbdTransform2D(HighbdIdct16, HighbdIadst16), // DCT_ADST = 2 new(HighbdIdct16, HighbdIadst16), // DCT_ADST = 2
new HighbdTransform2D(HighbdIadst16, HighbdIadst16) // ADST_ADST = 3 new(HighbdIadst16, HighbdIadst16) // ADST_ADST = 3
}; };
public static void HighbdIht16x16256Add(ReadOnlySpan<int> input, Span<ushort> dest, int stride, int txType, int bd) public static void HighbdIht16x16256Add(ReadOnlySpan<int> input, Span<ushort> dest, int stride, int txType,
int bd)
{ {
int i, j;
Span<int> output = stackalloc int[16 * 16]; Span<int> output = stackalloc int[16 * 16];
Span<int> outptr = output; Span<int> outptr = output;
Span<int> tempIn = stackalloc int[16]; Span<int> tempIn = stackalloc int[16];
@ -382,7 +385,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
HighbdTransform2D ht = HighIht16[txType]; HighbdTransform2D ht = HighIht16[txType];
// Rows // Rows
for (i = 0; i < 16; ++i) for (int i = 0; i < 16; ++i)
{ {
ht.Rows(input, outptr, bd); ht.Rows(input, outptr, bd);
input = input.Slice(16); input = input.Slice(16);
@ -390,17 +393,18 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
} }
// Columns // Columns
for (i = 0; i < 16; ++i) for (int i = 0; i < 16; ++i)
{ {
for (j = 0; j < 16; ++j) for (int j = 0; j < 16; ++j)
{ {
tempIn[j] = output[j * 16 + i]; tempIn[j] = output[(j * 16) + i];
} }
ht.Cols(tempIn, tempOut, bd); ht.Cols(tempIn, tempOut, bd);
for (j = 0; j < 16; ++j) for (int j = 0; j < 16; ++j)
{ {
dest[j * stride + i] = HighbdClipPixelAdd(dest[j * stride + i], BitUtils.RoundPowerOfTwo(tempOut[j], 6), bd); dest[(j * stride) + i] = HighbdClipPixelAdd(dest[(j * stride) + i],
BitUtils.RoundPowerOfTwo(tempOut[j], 6), bd);
} }
} }
} }
@ -440,7 +444,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
// DC only DCT coefficient // DC only DCT coefficient
if (eob == 1) if (eob == 1)
{ {
vpx_Highbdidct8x8_1_add_c(input, dest, stride, bd); VpxHighbdidct8x81AddC(input, dest, stride, bd);
} }
else if (eob <= 12) else if (eob <= 12)
{ {
@ -497,7 +501,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
} }
// Iht // Iht
public static void HighbdIht4x4Add(TxType txType, ReadOnlySpan<int> input, Span<ushort> dest, int stride, int eob, int bd) public static void HighbdIht4x4Add(TxType txType, ReadOnlySpan<int> input, Span<ushort> dest, int stride,
int eob, int bd)
{ {
if (txType == TxType.DctDct) if (txType == TxType.DctDct)
{ {
@ -509,7 +514,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
} }
} }
public static void HighbdIht8x8Add(TxType txType, ReadOnlySpan<int> input, Span<ushort> dest, int stride, int eob, int bd) public static void HighbdIht8x8Add(TxType txType, ReadOnlySpan<int> input, Span<ushort> dest, int stride,
int eob, int bd)
{ {
if (txType == TxType.DctDct) if (txType == TxType.DctDct)
{ {
@ -521,7 +527,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
} }
} }
public static void HighbdIht16x16Add(TxType txType, ReadOnlySpan<int> input, Span<ushort> dest, int stride, int eob, int bd) public static void HighbdIht16x16Add(TxType txType, ReadOnlySpan<int> input, Span<ushort> dest, int stride,
int eob, int bd)
{ {
if (txType == TxType.DctDct) if (txType == TxType.DctDct)
{ {

View file

@ -2,7 +2,7 @@
namespace Ryujinx.Graphics.Nvdec.Vp9 namespace Ryujinx.Graphics.Nvdec.Vp9
{ {
class InternalErrorException : Exception internal class InternalErrorException : Exception
{ {
public InternalErrorException(string message) : base(message) public InternalErrorException(string message) : base(message)
{ {

File diff suppressed because it is too large Load diff

View file

@ -84,7 +84,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
}, },
new TxSize[][][] new TxSize[][][]
{ {
// BLOCK_4X8 // BLOCK_4x8
new TxSize[][] { new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } }, new TxSize[][] { new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } },
new TxSize[][] { new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } }, new TxSize[][] { new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } },
new TxSize[][] { new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } }, new TxSize[][] { new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } },
@ -92,7 +92,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
}, },
new TxSize[][][] new TxSize[][][]
{ {
// BLOCK_8X4 // BLOCK_8x4
new TxSize[][] { new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } }, new TxSize[][] { new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } },
new TxSize[][] { new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } }, new TxSize[][] { new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } },
new TxSize[][] { new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } }, new TxSize[][] { new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } },
@ -108,7 +108,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
}, },
new TxSize[][][] new TxSize[][][]
{ {
// BLOCK_8X16 // BLOCK_8x16
new TxSize[][] { new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } }, new TxSize[][] { new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } },
new TxSize[][] { new TxSize[] { TxSize.Tx8x8, TxSize.Tx8x8 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } }, new TxSize[][] { new TxSize[] { TxSize.Tx8x8, TxSize.Tx8x8 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } },
new TxSize[][] { new TxSize[] { TxSize.Tx8x8, TxSize.Tx8x8 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } }, new TxSize[][] { new TxSize[] { TxSize.Tx8x8, TxSize.Tx8x8 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } },
@ -116,7 +116,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
}, },
new TxSize[][][] new TxSize[][][]
{ {
// BLOCK_16X8 // BLOCK_16x8
new TxSize[][] { new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } }, new TxSize[][] { new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } },
new TxSize[][] { new TxSize[] { TxSize.Tx8x8, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx8x8, TxSize.Tx4x4 } }, new TxSize[][] { new TxSize[] { TxSize.Tx8x8, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx8x8, TxSize.Tx4x4 } },
new TxSize[][] { new TxSize[] { TxSize.Tx8x8, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx8x8, TxSize.Tx8x8 } }, new TxSize[][] { new TxSize[] { TxSize.Tx8x8, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx8x8, TxSize.Tx8x8 } },
@ -132,7 +132,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
}, },
new TxSize[][][] new TxSize[][][]
{ {
// BLOCK_16X32 // BLOCK_16x32
new TxSize[][] { new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } }, new TxSize[][] { new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } },
new TxSize[][] { new TxSize[] { TxSize.Tx8x8, TxSize.Tx8x8 }, new TxSize[] { TxSize.Tx8x8, TxSize.Tx8x8 } }, new TxSize[][] { new TxSize[] { TxSize.Tx8x8, TxSize.Tx8x8 }, new TxSize[] { TxSize.Tx8x8, TxSize.Tx8x8 } },
new TxSize[][] { new TxSize[] { TxSize.Tx16x16, TxSize.Tx16x16 }, new TxSize[] { TxSize.Tx8x8, TxSize.Tx8x8 } }, new TxSize[][] { new TxSize[] { TxSize.Tx16x16, TxSize.Tx16x16 }, new TxSize[] { TxSize.Tx8x8, TxSize.Tx8x8 } },
@ -140,7 +140,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
}, },
new TxSize[][][] new TxSize[][][]
{ {
// BLOCK_32X16 // BLOCK_32x16
new TxSize[][] { new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } }, new TxSize[][] { new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } },
new TxSize[][] { new TxSize[] { TxSize.Tx8x8, TxSize.Tx8x8 }, new TxSize[] { TxSize.Tx8x8, TxSize.Tx8x8 } }, new TxSize[][] { new TxSize[] { TxSize.Tx8x8, TxSize.Tx8x8 }, new TxSize[] { TxSize.Tx8x8, TxSize.Tx8x8 } },
new TxSize[][] { new TxSize[] { TxSize.Tx16x16, TxSize.Tx8x8 }, new TxSize[] { TxSize.Tx16x16, TxSize.Tx8x8 } }, new TxSize[][] { new TxSize[] { TxSize.Tx16x16, TxSize.Tx8x8 }, new TxSize[] { TxSize.Tx16x16, TxSize.Tx8x8 } },
@ -156,7 +156,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
}, },
new TxSize[][][] new TxSize[][][]
{ {
// BLOCK_32X64 // BLOCK_32x64
new TxSize[][] { new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } }, new TxSize[][] { new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } },
new TxSize[][] { new TxSize[] { TxSize.Tx8x8, TxSize.Tx8x8 }, new TxSize[] { TxSize.Tx8x8, TxSize.Tx8x8 } }, new TxSize[][] { new TxSize[] { TxSize.Tx8x8, TxSize.Tx8x8 }, new TxSize[] { TxSize.Tx8x8, TxSize.Tx8x8 } },
new TxSize[][] { new TxSize[] { TxSize.Tx16x16, TxSize.Tx16x16 }, new TxSize[] { TxSize.Tx16x16, TxSize.Tx16x16 } }, new TxSize[][] { new TxSize[] { TxSize.Tx16x16, TxSize.Tx16x16 }, new TxSize[] { TxSize.Tx16x16, TxSize.Tx16x16 } },
@ -164,7 +164,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
}, },
new TxSize[][][] new TxSize[][][]
{ {
// BLOCK_64X32 // BLOCK_64x32
new TxSize[][] { new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } }, new TxSize[][] { new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } },
new TxSize[][] { new TxSize[] { TxSize.Tx8x8, TxSize.Tx8x8 }, new TxSize[] { TxSize.Tx8x8, TxSize.Tx8x8 } }, new TxSize[][] { new TxSize[] { TxSize.Tx8x8, TxSize.Tx8x8 }, new TxSize[] { TxSize.Tx8x8, TxSize.Tx8x8 } },
new TxSize[][] { new TxSize[] { TxSize.Tx16x16, TxSize.Tx16x16 }, new TxSize[] { TxSize.Tx16x16, TxSize.Tx16x16 } }, new TxSize[][] { new TxSize[] { TxSize.Tx16x16, TxSize.Tx16x16 }, new TxSize[] { TxSize.Tx16x16, TxSize.Tx16x16 } },
@ -172,7 +172,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
}, },
new TxSize[][][] new TxSize[][][]
{ {
// BLOCK_64X64 // BLOCK_64x64
new TxSize[][] { new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } }, new TxSize[][] { new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 }, new TxSize[] { TxSize.Tx4x4, TxSize.Tx4x4 } },
new TxSize[][] { new TxSize[] { TxSize.Tx8x8, TxSize.Tx8x8 }, new TxSize[] { TxSize.Tx8x8, TxSize.Tx8x8 } }, new TxSize[][] { new TxSize[] { TxSize.Tx8x8, TxSize.Tx8x8 }, new TxSize[] { TxSize.Tx8x8, TxSize.Tx8x8 } },
new TxSize[][] { new TxSize[] { TxSize.Tx16x16, TxSize.Tx16x16 }, new TxSize[] { TxSize.Tx16x16, TxSize.Tx16x16 } }, new TxSize[][] { new TxSize[] { TxSize.Tx16x16, TxSize.Tx16x16 }, new TxSize[] { TxSize.Tx16x16, TxSize.Tx16x16 } },
@ -198,18 +198,18 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
public static readonly PartitionContextPair[] PartitionContextLookup = new PartitionContextPair[] public static readonly PartitionContextPair[] PartitionContextLookup = new PartitionContextPair[]
{ {
new PartitionContextPair(15, 15), // 4X4 - {0b1111, 0b1111} new PartitionContextPair(15, 15), // 4X4 - {0b1111, 0b1111}
new PartitionContextPair(15, 14), // 4X8 - {0b1111, 0b1110} new PartitionContextPair(15, 14), // 4x8 - {0b1111, 0b1110}
new PartitionContextPair(14, 15), // 8X4 - {0b1110, 0b1111} new PartitionContextPair(14, 15), // 8x4 - {0b1110, 0b1111}
new PartitionContextPair(14, 14), // 8X8 - {0b1110, 0b1110} new PartitionContextPair(14, 14), // 8X8 - {0b1110, 0b1110}
new PartitionContextPair(14, 12), // 8X16 - {0b1110, 0b1100} new PartitionContextPair(14, 12), // 8x16 - {0b1110, 0b1100}
new PartitionContextPair(12, 14), // 16X8 - {0b1100, 0b1110} new PartitionContextPair(12, 14), // 16x8 - {0b1100, 0b1110}
new PartitionContextPair(12, 12), // 16X16 - {0b1100, 0b1100} new PartitionContextPair(12, 12), // 16X16 - {0b1100, 0b1100}
new PartitionContextPair(12, 8), // 16X32 - {0b1100, 0b1000} new PartitionContextPair(12, 8), // 16x32 - {0b1100, 0b1000}
new PartitionContextPair(8, 12), // 32X16 - {0b1000, 0b1100} new PartitionContextPair(8, 12), // 32x16 - {0b1000, 0b1100}
new PartitionContextPair(8, 8), // 32X32 - {0b1000, 0b1000} new PartitionContextPair(8, 8), // 32X32 - {0b1000, 0b1000}
new PartitionContextPair(8, 0), // 32X64 - {0b1000, 0b0000} new PartitionContextPair(8, 0), // 32x64 - {0b1000, 0b0000}
new PartitionContextPair(0, 8), // 64X32 - {0b0000, 0b1000} new PartitionContextPair(0, 8), // 64x32 - {0b0000, 0b1000}
new PartitionContextPair(0, 0), // 64X64 - {0b0000, 0b0000} new PartitionContextPair(0, 0), // 64x64 - {0b0000, 0b0000}
}; };
// Filter // Filter
@ -281,7 +281,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
return output; return output;
} }
public static readonly Array8<short>[][] Vp9FilterKernels = new Array8<short>[][] public static readonly Array8<short>[][] FilterKernels = new Array8<short>[][]
{ {
SubPelFilters8, SubPelFilters8Lp, SubPelFilters8S, BilinearFilters SubPelFilters8, SubPelFilters8Lp, SubPelFilters8S, BilinearFilters
}; };
@ -797,22 +797,22 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
959, 990, 991, 1022, 0, 0, 959, 990, 991, 1022, 0, 0,
}; };
private static readonly short[] Vp9DefaultIscan4X4 = new short[] private static readonly short[] DefaultIscan4X4 = new short[]
{ {
0, 2, 5, 8, 1, 3, 9, 12, 4, 7, 11, 14, 6, 10, 13, 15, 0, 2, 5, 8, 1, 3, 9, 12, 4, 7, 11, 14, 6, 10, 13, 15,
}; };
private static readonly short[] Vp9ColIscan4X4 = new short[] private static readonly short[] ColIscan4X4 = new short[]
{ {
0, 3, 7, 11, 1, 5, 9, 12, 2, 6, 10, 14, 4, 8, 13, 15, 0, 3, 7, 11, 1, 5, 9, 12, 2, 6, 10, 14, 4, 8, 13, 15,
}; };
private static readonly short[] Vp9RowIscan4X4 = new short[] private static readonly short[] RowIscan4X4 = new short[]
{ {
0, 1, 3, 5, 2, 4, 6, 9, 7, 8, 11, 13, 10, 12, 14, 15, 0, 1, 3, 5, 2, 4, 6, 9, 7, 8, 11, 13, 10, 12, 14, 15,
}; };
private static readonly short[] Vp9ColIscan8X8 = new short[] private static readonly short[] ColIscan8X8 = new short[]
{ {
0, 3, 8, 15, 22, 32, 40, 47, 1, 5, 11, 18, 26, 34, 44, 51, 0, 3, 8, 15, 22, 32, 40, 47, 1, 5, 11, 18, 26, 34, 44, 51,
2, 7, 13, 20, 28, 38, 46, 54, 4, 10, 16, 24, 31, 41, 50, 56, 2, 7, 13, 20, 28, 38, 46, 54, 4, 10, 16, 24, 31, 41, 50, 56,
@ -820,7 +820,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
14, 23, 30, 37, 45, 53, 59, 62, 19, 29, 36, 42, 49, 57, 61, 63, 14, 23, 30, 37, 45, 53, 59, 62, 19, 29, 36, 42, 49, 57, 61, 63,
}; };
private static readonly short[] Vp9RowIscan8X8 = new short[] private static readonly short[] RowIscan8X8 = new short[]
{ {
0, 1, 2, 5, 8, 12, 19, 24, 3, 4, 7, 10, 15, 20, 30, 39, 0, 1, 2, 5, 8, 12, 19, 24, 3, 4, 7, 10, 15, 20, 30, 39,
6, 9, 13, 16, 21, 27, 37, 46, 11, 14, 17, 23, 28, 34, 44, 52, 6, 9, 13, 16, 21, 27, 37, 46, 11, 14, 17, 23, 28, 34, 44, 52,
@ -828,7 +828,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
32, 36, 42, 47, 51, 54, 60, 61, 40, 45, 48, 53, 56, 58, 62, 63, 32, 36, 42, 47, 51, 54, 60, 61, 40, 45, 48, 53, 56, 58, 62, 63,
}; };
private static readonly short[] Vp9DefaultIscan8X8 = new short[] private static readonly short[] DefaultIscan8X8 = new short[]
{ {
0, 2, 5, 9, 14, 22, 31, 37, 1, 4, 8, 13, 19, 26, 38, 44, 0, 2, 5, 9, 14, 22, 31, 37, 1, 4, 8, 13, 19, 26, 38, 44,
3, 6, 10, 17, 24, 30, 42, 49, 7, 11, 15, 21, 29, 36, 47, 53, 3, 6, 10, 17, 24, 30, 42, 49, 7, 11, 15, 21, 29, 36, 47, 53,
@ -836,7 +836,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
25, 32, 39, 45, 50, 55, 59, 62, 33, 40, 46, 51, 54, 58, 61, 63, 25, 32, 39, 45, 50, 55, 59, 62, 33, 40, 46, 51, 54, 58, 61, 63,
}; };
private static readonly short[] Vp9ColIscan16X16 = new short[] private static readonly short[] ColIscan16X16 = new short[]
{ {
0, 4, 11, 20, 31, 43, 59, 75, 85, 109, 130, 150, 165, 181, 195, 198, 0, 4, 11, 20, 31, 43, 59, 75, 85, 109, 130, 150, 165, 181, 195, 198,
1, 6, 14, 23, 34, 47, 64, 81, 95, 114, 135, 153, 171, 188, 201, 212, 1, 6, 14, 23, 34, 47, 64, 81, 95, 114, 135, 153, 171, 188, 201, 212,
@ -856,7 +856,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
65, 88, 107, 124, 139, 152, 163, 177, 185, 199, 221, 234, 243, 248, 252, 255, 65, 88, 107, 124, 139, 152, 163, 177, 185, 199, 221, 234, 243, 248, 252, 255,
}; };
private static readonly short[] Vp9RowIscan16X16 = new short[] private static readonly short[] RowIscan16X16 = new short[]
{ {
0, 1, 2, 4, 6, 9, 12, 17, 22, 29, 36, 43, 54, 64, 76, 0, 1, 2, 4, 6, 9, 12, 17, 22, 29, 36, 43, 54, 64, 76,
86, 3, 5, 7, 11, 15, 19, 25, 32, 38, 48, 59, 68, 84, 99, 86, 3, 5, 7, 11, 15, 19, 25, 32, 38, 48, 59, 68, 84, 99,
@ -878,7 +878,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
255, 255,
}; };
private static readonly short[] Vp9DefaultIscan16X16 = new short[] private static readonly short[] DefaultIscan16X16 = new short[]
{ {
0, 2, 5, 9, 17, 24, 36, 44, 55, 72, 88, 104, 128, 143, 166, 0, 2, 5, 9, 17, 24, 36, 44, 55, 72, 88, 104, 128, 143, 166,
179, 1, 4, 8, 13, 20, 30, 40, 54, 66, 79, 96, 113, 141, 154, 179, 1, 4, 8, 13, 20, 30, 40, 54, 66, 79, 96, 113, 141, 154,
@ -900,7 +900,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
255, 255,
}; };
private static readonly short[] Vp9DefaultIscan32X32 = new short[] private static readonly short[] DefaultIscan32X32 = new short[]
{ {
0, 2, 5, 10, 17, 25, 38, 47, 62, 83, 101, 121, 145, 0, 2, 5, 10, 17, 25, 38, 47, 62, 83, 101, 121, 145,
170, 193, 204, 210, 219, 229, 233, 245, 257, 275, 299, 342, 356, 170, 193, 204, 210, 219, 229, 233, 245, 257, 275, 299, 342, 356,
@ -997,94 +997,94 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
} }
} }
public static readonly ScanOrder[] Vp9DefaultScanOrders = new ScanOrder[] public static readonly ScanOrder[] DefaultScanOrders = new ScanOrder[]
{ {
new ScanOrder(DefaultScan4X4, Vp9DefaultIscan4X4, DefaultScan4X4Neighbors), new ScanOrder(DefaultScan4X4, DefaultIscan4X4, DefaultScan4X4Neighbors),
new ScanOrder(DefaultScan8X8, Vp9DefaultIscan8X8, DefaultScan8X8Neighbors), new ScanOrder(DefaultScan8X8, DefaultIscan8X8, DefaultScan8X8Neighbors),
new ScanOrder(DefaultScan16X16, Vp9DefaultIscan16X16, DefaultScan16X16Neighbors), new ScanOrder(DefaultScan16X16, DefaultIscan16X16, DefaultScan16X16Neighbors),
new ScanOrder(DefaultScan32X32, Vp9DefaultIscan32X32, DefaultScan32X32Neighbors) new ScanOrder(DefaultScan32X32, DefaultIscan32X32, DefaultScan32X32Neighbors)
}; };
public static readonly ScanOrder[][] Vp9ScanOrders = new ScanOrder[][] public static readonly ScanOrder[][] ScanOrders = new ScanOrder[][]
{ {
new ScanOrder[] new ScanOrder[]
{ // TX_4X4 { // TX_4X4
new ScanOrder(DefaultScan4X4, Vp9DefaultIscan4X4, DefaultScan4X4Neighbors), new ScanOrder(DefaultScan4X4, DefaultIscan4X4, DefaultScan4X4Neighbors),
new ScanOrder(RowScan4X4, Vp9RowIscan4X4, RowScan4X4Neighbors), new ScanOrder(RowScan4X4, RowIscan4X4, RowScan4X4Neighbors),
new ScanOrder(ColScan4X4, Vp9ColIscan4X4, ColScan4X4Neighbors), new ScanOrder(ColScan4X4, ColIscan4X4, ColScan4X4Neighbors),
new ScanOrder(DefaultScan4X4, Vp9DefaultIscan4X4, DefaultScan4X4Neighbors) new ScanOrder(DefaultScan4X4, DefaultIscan4X4, DefaultScan4X4Neighbors)
}, },
new ScanOrder[] new ScanOrder[]
{ // TX_8X8 { // TX_8X8
new ScanOrder(DefaultScan8X8, Vp9DefaultIscan8X8, DefaultScan8X8Neighbors), new ScanOrder(DefaultScan8X8, DefaultIscan8X8, DefaultScan8X8Neighbors),
new ScanOrder(RowScan8X8, Vp9RowIscan8X8, RowScan8X8Neighbors), new ScanOrder(RowScan8X8, RowIscan8X8, RowScan8X8Neighbors),
new ScanOrder(ColScan8X8, Vp9ColIscan8X8, ColScan8X8Neighbors), new ScanOrder(ColScan8X8, ColIscan8X8, ColScan8X8Neighbors),
new ScanOrder(DefaultScan8X8, Vp9DefaultIscan8X8, DefaultScan8X8Neighbors) new ScanOrder(DefaultScan8X8, DefaultIscan8X8, DefaultScan8X8Neighbors)
}, },
new ScanOrder[] new ScanOrder[]
{ // TX_16X16 { // TX_16X16
new ScanOrder(DefaultScan16X16, Vp9DefaultIscan16X16, DefaultScan16X16Neighbors), new ScanOrder(DefaultScan16X16, DefaultIscan16X16, DefaultScan16X16Neighbors),
new ScanOrder(RowScan16X16, Vp9RowIscan16X16, RowScan16X16Neighbors), new ScanOrder(RowScan16X16, RowIscan16X16, RowScan16X16Neighbors),
new ScanOrder(ColScan16X16, Vp9ColIscan16X16, ColScan16X16Neighbors), new ScanOrder(ColScan16X16, ColIscan16X16, ColScan16X16Neighbors),
new ScanOrder(DefaultScan16X16, Vp9DefaultIscan16X16, DefaultScan16X16Neighbors) new ScanOrder(DefaultScan16X16, DefaultIscan16X16, DefaultScan16X16Neighbors)
}, },
new ScanOrder[] new ScanOrder[]
{ // TX_32X32 { // TX_32X32
new ScanOrder(DefaultScan32X32, Vp9DefaultIscan32X32, DefaultScan32X32Neighbors), new ScanOrder(DefaultScan32X32, DefaultIscan32X32, DefaultScan32X32Neighbors),
new ScanOrder(DefaultScan32X32, Vp9DefaultIscan32X32, DefaultScan32X32Neighbors), new ScanOrder(DefaultScan32X32, DefaultIscan32X32, DefaultScan32X32Neighbors),
new ScanOrder(DefaultScan32X32, Vp9DefaultIscan32X32, DefaultScan32X32Neighbors), new ScanOrder(DefaultScan32X32, DefaultIscan32X32, DefaultScan32X32Neighbors),
new ScanOrder(DefaultScan32X32, Vp9DefaultIscan32X32, DefaultScan32X32Neighbors) new ScanOrder(DefaultScan32X32, DefaultIscan32X32, DefaultScan32X32Neighbors)
} }
}; };
// Entropy MV // Entropy MV
public static readonly sbyte[] Vp9MvJointTree = new sbyte[] public static readonly sbyte[] MvJointTree = new sbyte[]
{ {
-(sbyte)MvJointType.MvJointZero, 2, -(sbyte)MvJointType.MvJointHnzvz, 4, -(sbyte)MvJointType.MvJointHzvnz, -(sbyte)MvJointType.MvJointHnzvnz -(sbyte)MvJointType.Zero, 2, -(sbyte)MvJointType.Hnzvz, 4, -(sbyte)MvJointType.Hzvnz, -(sbyte)MvJointType.Hnzvnz
}; };
public static readonly sbyte[] Vp9MvClassTree = new sbyte[] public static readonly sbyte[] MvClassTree = new sbyte[]
{ {
-(sbyte)MvClassType.MvClass0, -(sbyte)MvClassType.Class0,
2, 2,
-(sbyte)MvClassType.MvClass1, -(sbyte)MvClassType.Class1,
4, 4,
6, 6,
8, 8,
-(sbyte)MvClassType.MvClass2, -(sbyte)MvClassType.Class2,
-(sbyte)MvClassType.MvClass3, -(sbyte)MvClassType.Class3,
10, 10,
12, 12,
-(sbyte)MvClassType.MvClass4, -(sbyte)MvClassType.Class4,
-(sbyte)MvClassType.MvClass5, -(sbyte)MvClassType.Class5,
-(sbyte)MvClassType.MvClass6, -(sbyte)MvClassType.Class6,
14, 14,
16, 16,
18, 18,
-(sbyte)MvClassType.MvClass7, -(sbyte)MvClassType.Class7,
-(sbyte)MvClassType.MvClass8, -(sbyte)MvClassType.Class8,
-(sbyte)MvClassType.MvClass9, -(sbyte)MvClassType.Class9,
-(sbyte)MvClassType.MvClass10, -(sbyte)MvClassType.Class10
}; };
public static ReadOnlySpan<sbyte> Vp9MvFPTree => new sbyte[] { -0, 2, -1, 4, -2, -3 }; public static ReadOnlySpan<sbyte> MvFPTree => new sbyte[] { -0, 2, -1, 4, -2, -3 };
// Entropy // Entropy
public static ReadOnlySpan<byte> Vp9Cat1Prob => new byte[] { 159 }; public static ReadOnlySpan<byte> Cat1Prob => new byte[] { 159 };
public static ReadOnlySpan<byte> Vp9Cat2Prob => new byte[] { 165, 145 }; public static ReadOnlySpan<byte> Cat2Prob => new byte[] { 165, 145 };
public static ReadOnlySpan<byte> Vp9Cat3Prob => new byte[] { 173, 148, 140 }; public static ReadOnlySpan<byte> Cat3Prob => new byte[] { 173, 148, 140 };
public static ReadOnlySpan<byte> Vp9Cat4Prob => new byte[] { 176, 155, 140, 135 }; public static ReadOnlySpan<byte> Cat4Prob => new byte[] { 176, 155, 140, 135 };
public static ReadOnlySpan<byte> Vp9Cat5Prob => new byte[] { 180, 157, 141, 134, 130 }; public static ReadOnlySpan<byte> Cat5Prob => new byte[] { 180, 157, 141, 134, 130 };
public static ReadOnlySpan<byte> Vp9Cat6Prob => new byte[] { 254, 254, 254, 252, 249, 243, 230, 196, 177, 153, 140, 133, 130, 129 }; public static ReadOnlySpan<byte> Cat6Prob => new byte[] { 254, 254, 254, 252, 249, 243, 230, 196, 177, 153, 140, 133, 130, 129 };
public static ReadOnlySpan<byte> Vp9Cat6ProbHigh12 => new byte[] public static ReadOnlySpan<byte> Cat6ProbHigh12 => new byte[]
{ {
255, 255, 255, 255, 254, 254, 54, 252, 249, 243, 230, 196, 177, 153, 140, 133, 130, 129 255, 255, 255, 255, 254, 254, 54, 252, 249, 243, 230, 196, 177, 153, 140, 133, 130, 129
}; };
private static readonly byte[] Vp9CoefbandTrans8X8Plus = new byte[] private static readonly byte[] CoefbandTrans8X8Plus = new byte[]
{ {
0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5,
// Beyond MAXBAND_INDEX+1 all values are filled as 5 // Beyond MAXBAND_INDEX+1 all values are filled as 5
@ -1129,17 +1129,17 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
}; };
private static ReadOnlySpan<byte> Vp9CoefbandTrans4X4 => new byte[] private static ReadOnlySpan<byte> CoefbandTrans4X4 => new byte[]
{ {
0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, 0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5,
}; };
public static ReadOnlySpan<byte> get_band_translate(TxSize txSize) public static ReadOnlySpan<byte> GetBandTranslate(TxSize txSize)
{ {
return txSize == TxSize.Tx4x4 ? Vp9CoefbandTrans4X4 : Vp9CoefbandTrans8X8Plus; return txSize == TxSize.Tx4x4 ? CoefbandTrans4X4 : CoefbandTrans8X8Plus;
} }
public static readonly byte[][] Vp9Pareto8Full = new byte[][] public static readonly byte[][] Pareto8Full = new byte[][]
{ {
new byte[] { 3, 86, 128, 6, 86, 23, 88, 29 }, new byte[] { 3, 86, 128, 6, 86, 23, 88, 29 },
new byte[] { 6, 86, 128, 11, 87, 42, 91, 52 }, new byte[] { 6, 86, 128, 11, 87, 42, 91, 52 },
@ -1399,7 +1399,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
}; };
/* Array indices are identical to previously-existing INTRAMODECONTEXTNODES. */ /* Array indices are identical to previously-existing INTRAMODECONTEXTNODES. */
public static readonly sbyte[] Vp9IntraModeTree = new sbyte[] public static readonly sbyte[] IntraModeTree = new sbyte[]
{ {
-(sbyte)PredictionMode.DcPred, 2, /* 0 = DC_NODE */ -(sbyte)PredictionMode.DcPred, 2, /* 0 = DC_NODE */
-(sbyte)PredictionMode.TmPred, 4, /* 1 = TM_NODE */ -(sbyte)PredictionMode.TmPred, 4, /* 1 = TM_NODE */
@ -1412,7 +1412,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
-(sbyte)PredictionMode.D153Pred, -(sbyte)PredictionMode.D207Pred /* 8 = D153_NODE */ -(sbyte)PredictionMode.D153Pred, -(sbyte)PredictionMode.D207Pred /* 8 = D153_NODE */
}; };
public static readonly sbyte[] Vp9InterModeTree = new sbyte[] public static readonly sbyte[] InterModeTree = new sbyte[]
{ {
-((sbyte)PredictionMode.ZeroMv - (sbyte)PredictionMode. NearestMv), 2, -((sbyte)PredictionMode.ZeroMv - (sbyte)PredictionMode. NearestMv), 2,
-((sbyte)PredictionMode.NearestMv - (sbyte)PredictionMode.NearestMv), 4, -((sbyte)PredictionMode.NearestMv - (sbyte)PredictionMode.NearestMv), 4,
@ -1420,17 +1420,17 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
-((sbyte)PredictionMode.NewMv - (sbyte)PredictionMode.NearestMv) -((sbyte)PredictionMode.NewMv - (sbyte)PredictionMode.NearestMv)
}; };
public static readonly sbyte[] Vp9PartitionTree = new sbyte[] public static readonly sbyte[] PartitionTree = new sbyte[]
{ {
-(sbyte)PartitionType.PartitionNone, 2, -(sbyte)PartitionType.PartitionHorz, 4, -(sbyte)PartitionType.PartitionVert, -(sbyte)PartitionType.PartitionSplit -(sbyte)PartitionType.PartitionNone, 2, -(sbyte)PartitionType.PartitionHorz, 4, -(sbyte)PartitionType.PartitionVert, -(sbyte)PartitionType.PartitionSplit
}; };
public static readonly sbyte[] Vp9SwitchableInterpTree = new sbyte[] public static readonly sbyte[] SwitchableInterpTree = new sbyte[]
{ {
-Constants.EightTap, 2, -Constants.EightTapSmooth, -Constants.EightTapSharp -Constants.EightTap, 2, -Constants.EightTapSmooth, -Constants.EightTapSharp
}; };
public static readonly sbyte[] Vp9SegmentTree = new sbyte[] public static readonly sbyte[] SegmentTree = new sbyte[]
{ {
2, 4, 6, 8, 10, 12, 0, -1, -2, -3, -4, -5, -6, -7 2, 4, 6, 8, 10, 12, 0, -1, -2, -3, -4, -5, -6, -7
}; };
@ -1497,7 +1497,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
new Position( -2, -1 ), new Position( -2, -1 ),
new Position( -1, -2 ), new Position( -1, -2 ),
new Position( -2, -2 ) }, new Position( -2, -2 ) },
// 4X8 // 4x8
new Position[] { new Position( -1, 0 ), new Position[] { new Position( -1, 0 ),
new Position( 0, -1 ), new Position( 0, -1 ),
new Position( -1, -1 ), new Position( -1, -1 ),
@ -1506,7 +1506,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
new Position( -2, -1 ), new Position( -2, -1 ),
new Position( -1, -2 ), new Position( -1, -2 ),
new Position( -2, -2 ) }, new Position( -2, -2 ) },
// 8X4 // 8x4
new Position[] { new Position( -1, 0 ), new Position[] { new Position( -1, 0 ),
new Position( 0, -1 ), new Position( 0, -1 ),
new Position( -1, -1 ), new Position( -1, -1 ),
@ -1524,7 +1524,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
new Position( -2, -1 ), new Position( -2, -1 ),
new Position( -1, -2 ), new Position( -1, -2 ),
new Position( -2, -2 ) }, new Position( -2, -2 ) },
// 8X16 // 8x16
new Position[] { new Position( 0, -1 ), new Position[] { new Position( 0, -1 ),
new Position( -1, 0 ), new Position( -1, 0 ),
new Position( 1, -1 ), new Position( 1, -1 ),
@ -1533,7 +1533,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
new Position( -2, 0 ), new Position( -2, 0 ),
new Position( -2, -1 ), new Position( -2, -1 ),
new Position( -1, -2 ) }, new Position( -1, -2 ) },
// 16X8 // 16x8
new Position[] { new Position( -1, 0 ), new Position[] { new Position( -1, 0 ),
new Position( 0, -1 ), new Position( 0, -1 ),
new Position( -1, 1 ), new Position( -1, 1 ),
@ -1551,7 +1551,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
new Position( -3, 0 ), new Position( -3, 0 ),
new Position( 0, -3 ), new Position( 0, -3 ),
new Position( -3, -3 ) }, new Position( -3, -3 ) },
// 16X32 // 16x32
new Position[] { new Position( 0, -1 ), new Position[] { new Position( 0, -1 ),
new Position( -1, 0 ), new Position( -1, 0 ),
new Position( 2, -1 ), new Position( 2, -1 ),
@ -1560,7 +1560,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
new Position( 0, -3 ), new Position( 0, -3 ),
new Position( -3, 0 ), new Position( -3, 0 ),
new Position( -3, -3 ) }, new Position( -3, -3 ) },
// 32X16 // 32x16
new Position[] { new Position( -1, 0 ), new Position[] { new Position( -1, 0 ),
new Position( 0, -1 ), new Position( 0, -1 ),
new Position( -1, 2 ), new Position( -1, 2 ),
@ -1578,7 +1578,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
new Position( -3, 0 ), new Position( -3, 0 ),
new Position( 0, -3 ), new Position( 0, -3 ),
new Position( -3, -3 ) }, new Position( -3, -3 ) },
// 32X64 // 32x64
new Position[] { new Position( 0, -1 ), new Position[] { new Position( 0, -1 ),
new Position( -1, 0 ), new Position( -1, 0 ),
new Position( 4, -1 ), new Position( 4, -1 ),
@ -1587,7 +1587,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
new Position( 0, -3 ), new Position( 0, -3 ),
new Position( -3, 0 ), new Position( -3, 0 ),
new Position( 2, -1 ) }, new Position( 2, -1 ) },
// 64X32 // 64x32
new Position[] { new Position( -1, 0 ), new Position[] { new Position( -1, 0 ),
new Position( 0, -1 ), new Position( 0, -1 ),
new Position( -1, 4 ), new Position( -1, 4 ),
@ -1596,7 +1596,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
new Position( -3, 0 ), new Position( -3, 0 ),
new Position( 0, -3 ), new Position( 0, -3 ),
new Position( -1, 2 ) }, new Position( -1, 2 ) },
// 64X64 // 64x64
new Position[] { new Position( -1, 3 ), new Position[] { new Position( -1, 3 ),
new Position( 3, -1 ), new Position( 3, -1 ),
new Position( -1, 4 ), new Position( -1, 4 ),

View file

@ -13,7 +13,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
// left of the entries corresponding to real macroblocks. // left of the entries corresponding to real macroblocks.
// The prediction flags in these dummy entries are initialized to 0. // The prediction flags in these dummy entries are initialized to 0.
if (!xd.AboveMi.IsNull && !xd.LeftMi.IsNull) if (!xd.AboveMi.IsNull && !xd.LeftMi.IsNull)
{ // both edges available {
// both edges available
if (!xd.AboveMi.Value.HasSecondRef() && !xd.LeftMi.Value.HasSecondRef()) if (!xd.AboveMi.Value.HasSecondRef() && !xd.LeftMi.Value.HasSecondRef())
{ {
// Neither edge uses comp pred (0/1) // Neither edge uses comp pred (0/1)
@ -23,12 +24,15 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
else if (!xd.AboveMi.Value.HasSecondRef()) else if (!xd.AboveMi.Value.HasSecondRef())
{ {
// One of two edges uses comp pred (2/3) // One of two edges uses comp pred (2/3)
ctx = 2 + (xd.AboveMi.Value.RefFrame[0] == cm.CompFixedRef || !xd.AboveMi.Value.IsInterBlock() ? 1 : 0); ctx = 2 + (xd.AboveMi.Value.RefFrame[0] == cm.CompFixedRef || !xd.AboveMi.Value.IsInterBlock()
? 1
: 0);
} }
else if (!xd.LeftMi.Value.HasSecondRef()) else if (!xd.LeftMi.Value.HasSecondRef())
{ {
// One of two edges uses comp pred (2/3) // One of two edges uses comp pred (2/3)
ctx = 2 + (xd.LeftMi.Value.RefFrame[0] == cm.CompFixedRef || !xd.LeftMi.Value.IsInterBlock() ? 1 : 0); ctx = 2 +
(xd.LeftMi.Value.RefFrame[0] == cm.CompFixedRef || !xd.LeftMi.Value.IsInterBlock() ? 1 : 0);
} }
else // Both edges use comp pred (4) else // Both edges use comp pred (4)
{ {
@ -36,7 +40,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
} }
} }
else if (!xd.AboveMi.IsNull || !xd.LeftMi.IsNull) else if (!xd.AboveMi.IsNull || !xd.LeftMi.IsNull)
{ // One edge available {
// One edge available
ref ModeInfo edgeMi = ref !xd.AboveMi.IsNull ? ref xd.AboveMi.Value : ref xd.LeftMi.Value; ref ModeInfo edgeMi = ref !xd.AboveMi.IsNull ? ref xd.AboveMi.Value : ref xd.LeftMi.Value;
if (!edgeMi.HasSecondRef()) if (!edgeMi.HasSecondRef())
@ -51,9 +56,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
} }
} }
else else
{ // No edges available (1) {
// No edges available (1)
ctx = 1; ctx = 1;
} }
Debug.Assert(ctx >= 0 && ctx < Constants.CompInterContexts); Debug.Assert(ctx >= 0 && ctx < Constants.CompInterContexts);
return ctx; return ctx;
} }
@ -70,29 +77,33 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
int varRefIdx = fixRefIdx == 0 ? 1 : 0; int varRefIdx = fixRefIdx == 0 ? 1 : 0;
if (!xd.AboveMi.IsNull && !xd.LeftMi.IsNull) if (!xd.AboveMi.IsNull && !xd.LeftMi.IsNull)
{ // Both edges available {
// Both edges available
bool aboveIntra = !xd.AboveMi.Value.IsInterBlock(); bool aboveIntra = !xd.AboveMi.Value.IsInterBlock();
bool leftIntra = !xd.LeftMi.Value.IsInterBlock(); bool leftIntra = !xd.LeftMi.Value.IsInterBlock();
if (aboveIntra && leftIntra) if (aboveIntra && leftIntra)
{ // Intra/Intra (2) {
// Intra/Intra (2)
predContext = 2; predContext = 2;
} }
else if (aboveIntra || leftIntra) else if (aboveIntra || leftIntra)
{ // Intra/Inter {
// Intra/Inter
ref ModeInfo edgeMi = ref aboveIntra ? ref xd.LeftMi.Value : ref xd.AboveMi.Value; ref ModeInfo edgeMi = ref aboveIntra ? ref xd.LeftMi.Value : ref xd.AboveMi.Value;
if (!edgeMi.HasSecondRef()) // single pred (1/3) if (!edgeMi.HasSecondRef()) // single pred (1/3)
{ {
predContext = 1 + 2 * (edgeMi.RefFrame[0] != cm.CompVarRef[1] ? 1 : 0); predContext = 1 + (2 * (edgeMi.RefFrame[0] != cm.CompVarRef[1] ? 1 : 0));
} }
else // Comp pred (1/3) else // Comp pred (1/3)
{ {
predContext = 1 + 2 * (edgeMi.RefFrame[varRefIdx] != cm.CompVarRef[1] ? 1 : 0); predContext = 1 + (2 * (edgeMi.RefFrame[varRefIdx] != cm.CompVarRef[1] ? 1 : 0));
} }
} }
else else
{ // Inter/Inter {
// Inter/Inter
bool lSg = !xd.LeftMi.Value.HasSecondRef(); bool lSg = !xd.LeftMi.Value.HasSecondRef();
bool aSg = !xd.AboveMi.Value.HasSecondRef(); bool aSg = !xd.AboveMi.Value.HasSecondRef();
sbyte vrfa = aSg ? xd.AboveMi.Value.RefFrame[0] : xd.AboveMi.Value.RefFrame[varRefIdx]; sbyte vrfa = aSg ? xd.AboveMi.Value.RefFrame[0] : xd.AboveMi.Value.RefFrame[varRefIdx];
@ -103,7 +114,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
predContext = 0; predContext = 0;
} }
else if (lSg && aSg) else if (lSg && aSg)
{ // Single/Single {
// Single/Single
if ((vrfa == cm.CompFixedRef && vrfl == cm.CompVarRef[0]) || if ((vrfa == cm.CompFixedRef && vrfl == cm.CompVarRef[0]) ||
(vrfl == cm.CompFixedRef && vrfa == cm.CompVarRef[0])) (vrfl == cm.CompFixedRef && vrfa == cm.CompVarRef[0]))
{ {
@ -119,7 +131,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
} }
} }
else if (lSg || aSg) else if (lSg || aSg)
{ // Single/Comp {
// Single/Comp
sbyte vrfc = lSg ? vrfa : vrfl; sbyte vrfc = lSg ? vrfa : vrfl;
sbyte rfs = aSg ? vrfa : vrfl; sbyte rfs = aSg ? vrfa : vrfl;
if (vrfc == cm.CompVarRef[1] && rfs != cm.CompVarRef[1]) if (vrfc == cm.CompVarRef[1] && rfs != cm.CompVarRef[1])
@ -136,7 +149,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
} }
} }
else if (vrfa == vrfl) else if (vrfa == vrfl)
{ // Comp/Comp {
// Comp/Comp
predContext = 4; predContext = 4;
} }
else else
@ -146,7 +160,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
} }
} }
else if (!xd.AboveMi.IsNull || !xd.LeftMi.IsNull) else if (!xd.AboveMi.IsNull || !xd.LeftMi.IsNull)
{ // One edge available {
// One edge available
ref ModeInfo edgeMi = ref !xd.AboveMi.IsNull ? ref xd.AboveMi.Value : ref xd.LeftMi.Value; ref ModeInfo edgeMi = ref !xd.AboveMi.IsNull ? ref xd.AboveMi.Value : ref xd.LeftMi.Value;
if (!edgeMi.IsInterBlock()) if (!edgeMi.IsInterBlock())
@ -166,9 +181,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
} }
} }
else else
{ // No edges available (2) {
// No edges available (2)
predContext = 2; predContext = 2;
} }
Debug.Assert(predContext >= 0 && predContext < Constants.RefContexts); Debug.Assert(predContext >= 0 && predContext < Constants.RefContexts);
return predContext; return predContext;
} }
@ -181,16 +198,19 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
// left of the entries corresponding to real macroblocks. // left of the entries corresponding to real macroblocks.
// The prediction flags in these dummy entries are initialized to 0. // The prediction flags in these dummy entries are initialized to 0.
if (!xd.AboveMi.IsNull && !xd.LeftMi.IsNull) if (!xd.AboveMi.IsNull && !xd.LeftMi.IsNull)
{ // Both edges available {
// Both edges available
bool aboveIntra = !xd.AboveMi.Value.IsInterBlock(); bool aboveIntra = !xd.AboveMi.Value.IsInterBlock();
bool leftIntra = !xd.LeftMi.Value.IsInterBlock(); bool leftIntra = !xd.LeftMi.Value.IsInterBlock();
if (aboveIntra && leftIntra) if (aboveIntra && leftIntra)
{ // Intra/Intra {
// Intra/Intra
predContext = 2; predContext = 2;
} }
else if (aboveIntra || leftIntra) else if (aboveIntra || leftIntra)
{ // Intra/Inter or Inter/Intra {
// Intra/Inter or Inter/Intra
ref ModeInfo edgeMi = ref aboveIntra ? ref xd.LeftMi.Value : ref xd.AboveMi.Value; ref ModeInfo edgeMi = ref aboveIntra ? ref xd.LeftMi.Value : ref xd.AboveMi.Value;
if (!edgeMi.HasSecondRef()) if (!edgeMi.HasSecondRef())
{ {
@ -199,11 +219,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
else else
{ {
predContext = 1 + (edgeMi.RefFrame[0] == Constants.LastFrame || predContext = 1 + (edgeMi.RefFrame[0] == Constants.LastFrame ||
edgeMi.RefFrame[1] == Constants.LastFrame ? 1 : 0); edgeMi.RefFrame[1] == Constants.LastFrame
? 1
: 0);
} }
} }
else else
{ // Inter/Inter {
// Inter/Inter
bool aboveHasSecond = xd.AboveMi.Value.HasSecondRef(); bool aboveHasSecond = xd.AboveMi.Value.HasSecondRef();
bool leftHasSecond = xd.LeftMi.Value.HasSecondRef(); bool leftHasSecond = xd.LeftMi.Value.HasSecondRef();
sbyte above0 = xd.AboveMi.Value.RefFrame[0]; sbyte above0 = xd.AboveMi.Value.RefFrame[0];
@ -214,7 +237,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
if (aboveHasSecond && leftHasSecond) if (aboveHasSecond && leftHasSecond)
{ {
predContext = 1 + (above0 == Constants.LastFrame || above1 == Constants.LastFrame || predContext = 1 + (above0 == Constants.LastFrame || above1 == Constants.LastFrame ||
left0 == Constants.LastFrame || left1 == Constants.LastFrame ? 1 : 0); left0 == Constants.LastFrame || left1 == Constants.LastFrame
? 1
: 0);
} }
else if (aboveHasSecond || leftHasSecond) else if (aboveHasSecond || leftHasSecond)
{ {
@ -228,24 +253,28 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
} }
else else
{ {
predContext = (crf1 == Constants.LastFrame || crf2 == Constants.LastFrame ? 1 : 0); predContext = crf1 == Constants.LastFrame || crf2 == Constants.LastFrame ? 1 : 0;
} }
} }
else else
{ {
predContext = 2 * (above0 == Constants.LastFrame ? 1 : 0) + 2 * (left0 == Constants.LastFrame ? 1 : 0); predContext = (2 * (above0 == Constants.LastFrame ? 1 : 0)) +
(2 * (left0 == Constants.LastFrame ? 1 : 0));
} }
} }
} }
else if (!xd.AboveMi.IsNull || !xd.LeftMi.IsNull) else if (!xd.AboveMi.IsNull || !xd.LeftMi.IsNull)
{ // One edge available {
// One edge available
ref ModeInfo edgeMi = ref !xd.AboveMi.IsNull ? ref xd.AboveMi.Value : ref xd.LeftMi.Value; ref ModeInfo edgeMi = ref !xd.AboveMi.IsNull ? ref xd.AboveMi.Value : ref xd.LeftMi.Value;
if (!edgeMi.IsInterBlock()) if (!edgeMi.IsInterBlock())
{ // Intra {
// Intra
predContext = 2; predContext = 2;
} }
else else
{ // Inter {
// Inter
if (!edgeMi.HasSecondRef()) if (!edgeMi.HasSecondRef())
{ {
predContext = 4 * (edgeMi.RefFrame[0] == Constants.LastFrame ? 1 : 0); predContext = 4 * (edgeMi.RefFrame[0] == Constants.LastFrame ? 1 : 0);
@ -253,14 +282,18 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
else else
{ {
predContext = 1 + (edgeMi.RefFrame[0] == Constants.LastFrame || predContext = 1 + (edgeMi.RefFrame[0] == Constants.LastFrame ||
edgeMi.RefFrame[1] == Constants.LastFrame ? 1 : 0); edgeMi.RefFrame[1] == Constants.LastFrame
? 1
: 0);
} }
} }
} }
else else
{ // No edges available {
// No edges available
predContext = 2; predContext = 2;
} }
Debug.Assert(predContext >= 0 && predContext < Constants.RefContexts); Debug.Assert(predContext >= 0 && predContext < Constants.RefContexts);
return predContext; return predContext;
} }
@ -274,16 +307,19 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
// left of the entries corresponding to real macroblocks. // left of the entries corresponding to real macroblocks.
// The prediction flags in these dummy entries are initialized to 0. // The prediction flags in these dummy entries are initialized to 0.
if (!xd.AboveMi.IsNull && !xd.LeftMi.IsNull) if (!xd.AboveMi.IsNull && !xd.LeftMi.IsNull)
{ // Both edges available {
// Both edges available
bool aboveIntra = !xd.AboveMi.Value.IsInterBlock(); bool aboveIntra = !xd.AboveMi.Value.IsInterBlock();
bool leftIntra = !xd.LeftMi.Value.IsInterBlock(); bool leftIntra = !xd.LeftMi.Value.IsInterBlock();
if (aboveIntra && leftIntra) if (aboveIntra && leftIntra)
{ // Intra/Intra {
// Intra/Intra
predContext = 2; predContext = 2;
} }
else if (aboveIntra || leftIntra) else if (aboveIntra || leftIntra)
{ // Intra/Inter or Inter/Intra {
// Intra/Inter or Inter/Intra
ref ModeInfo edgeMi = ref aboveIntra ? ref xd.LeftMi.Value : ref xd.AboveMi.Value; ref ModeInfo edgeMi = ref aboveIntra ? ref xd.LeftMi.Value : ref xd.AboveMi.Value;
if (!edgeMi.HasSecondRef()) if (!edgeMi.HasSecondRef())
{ {
@ -298,12 +334,15 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
} }
else else
{ {
predContext = 1 + 2 * (edgeMi.RefFrame[0] == Constants.GoldenFrame || predContext = 1 + (2 * (edgeMi.RefFrame[0] == Constants.GoldenFrame ||
edgeMi.RefFrame[1] == Constants.GoldenFrame ? 1 : 0); edgeMi.RefFrame[1] == Constants.GoldenFrame
? 1
: 0));
} }
} }
else else
{ // Inter/Inter {
// Inter/Inter
bool aboveHasSecond = xd.AboveMi.Value.HasSecondRef(); bool aboveHasSecond = xd.AboveMi.Value.HasSecondRef();
bool leftHasSecond = xd.LeftMi.Value.HasSecondRef(); bool leftHasSecond = xd.LeftMi.Value.HasSecondRef();
sbyte above0 = xd.AboveMi.Value.RefFrame[0]; sbyte above0 = xd.AboveMi.Value.RefFrame[0];
@ -316,7 +355,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
if (above0 == left0 && above1 == left1) if (above0 == left0 && above1 == left1)
{ {
predContext = 3 * (above0 == Constants.GoldenFrame || above1 == Constants.GoldenFrame || predContext = 3 * (above0 == Constants.GoldenFrame || above1 == Constants.GoldenFrame ||
left0 == Constants.GoldenFrame || left1 == Constants.GoldenFrame ? 1 : 0); left0 == Constants.GoldenFrame || left1 == Constants.GoldenFrame
? 1
: 0);
} }
else else
{ {
@ -339,7 +380,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
} }
else else
{ {
predContext = 1 + 2 * (crf1 == Constants.GoldenFrame || crf2 == Constants.GoldenFrame ? 1 : 0); predContext =
1 + (2 * (crf1 == Constants.GoldenFrame || crf2 == Constants.GoldenFrame ? 1 : 0));
} }
} }
else else
@ -350,18 +392,20 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
} }
else if (above0 == Constants.LastFrame || left0 == Constants.LastFrame) else if (above0 == Constants.LastFrame || left0 == Constants.LastFrame)
{ {
sbyte edge0 = (above0 == Constants.LastFrame) ? left0 : above0; sbyte edge0 = above0 == Constants.LastFrame ? left0 : above0;
predContext = 4 * (edge0 == Constants.GoldenFrame ? 1 : 0); predContext = 4 * (edge0 == Constants.GoldenFrame ? 1 : 0);
} }
else else
{ {
predContext = 2 * (above0 == Constants.GoldenFrame ? 1 : 0) + 2 * (left0 == Constants.GoldenFrame ? 1 : 0); predContext = (2 * (above0 == Constants.GoldenFrame ? 1 : 0)) +
(2 * (left0 == Constants.GoldenFrame ? 1 : 0));
} }
} }
} }
} }
else if (!xd.AboveMi.IsNull || !xd.LeftMi.IsNull) else if (!xd.AboveMi.IsNull || !xd.LeftMi.IsNull)
{ // One edge available {
// One edge available
ref ModeInfo edgeMi = ref !xd.AboveMi.IsNull ? ref xd.AboveMi.Value : ref xd.LeftMi.Value; ref ModeInfo edgeMi = ref !xd.AboveMi.IsNull ? ref xd.AboveMi.Value : ref xd.LeftMi.Value;
if (!edgeMi.IsInterBlock() || (edgeMi.RefFrame[0] == Constants.LastFrame && !edgeMi.HasSecondRef())) if (!edgeMi.IsInterBlock() || (edgeMi.RefFrame[0] == Constants.LastFrame && !edgeMi.HasSecondRef()))
@ -375,13 +419,17 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
else else
{ {
predContext = 3 * (edgeMi.RefFrame[0] == Constants.GoldenFrame || predContext = 3 * (edgeMi.RefFrame[0] == Constants.GoldenFrame ||
edgeMi.RefFrame[1] == Constants.GoldenFrame ? 1 : 0); edgeMi.RefFrame[1] == Constants.GoldenFrame
? 1
: 0);
} }
} }
else else
{ // No edges available (2) {
// No edges available (2)
predContext = 2; predContext = 2;
} }
Debug.Assert(predContext >= 0 && predContext < Constants.RefContexts); Debug.Assert(predContext >= 0 && predContext < Constants.RefContexts);
return predContext; return predContext;
} }

View file

@ -0,0 +1,94 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.Nvdec.Vp9.Common;
using System;
using System.Diagnostics;
namespace Ryujinx.Graphics.Nvdec.Vp9
{
public static class Prob
{
public const int MaxProb = 255;
private static byte GetProb(uint num, uint den)
{
Debug.Assert(den != 0);
{
int p = (int)((((ulong)num * 256) + (den >> 1)) / den);
// (p > 255) ? 255 : (p < 1) ? 1 : p;
int clippedProb = p | ((255 - p) >> 23) | (p == 0 ? 1 : 0);
return (byte)clippedProb;
}
}
private static byte GetBinaryProb(uint n0, uint n1)
{
uint den = n0 + n1;
if (den == 0)
{
return 128;
}
return GetProb(n0, den);
}
/* This function assumes prob1 and prob2 are already within [1,255] range. */
public static byte WeightedProb(int prob1, int prob2, int factor)
{
return (byte)BitUtils.RoundPowerOfTwo((prob1 * (256 - factor)) + (prob2 * factor), 8);
}
public static byte MergeProbs(byte preProb, ref Array2<uint> ct, uint countSat, uint maxUpdateFactor)
{
byte prob = GetBinaryProb(ct[0], ct[1]);
uint count = Math.Min(ct[0] + ct[1], countSat);
uint factor = maxUpdateFactor * count / countSat;
return WeightedProb(preProb, prob, (int)factor);
}
// MODE_MV_MAX_UPDATE_FACTOR (128) * count / MODE_MV_COUNT_SAT;
private static readonly uint[] CountToUpdateFactor =
{
0, 6, 12, 19, 25, 32, 38, 44, 51, 57, 64, 70, 76, 83, 89, 96, 102, 108, 115, 121, 128
};
private const int ModeMvCountSat = 20;
public static byte ModeMvMergeProbs(byte preProb, ref Array2<uint> ct)
{
uint den = ct[0] + ct[1];
if (den == 0)
{
return preProb;
}
uint count = Math.Min(den, ModeMvCountSat);
uint factor = CountToUpdateFactor[(int)count];
byte prob = GetProb(ct[0], den);
return WeightedProb(preProb, prob, (int)factor);
}
private static uint TreeMergeProbsImpl(
uint i,
sbyte[] tree,
ReadOnlySpan<byte> preProbs,
ReadOnlySpan<uint> counts,
Span<byte> probs)
{
int l = tree[i];
uint leftCount = l <= 0 ? counts[-l] : TreeMergeProbsImpl((uint)l, tree, preProbs, counts, probs);
int r = tree[i + 1];
uint rightCount = r <= 0 ? counts[-r] : TreeMergeProbsImpl((uint)r, tree, preProbs, counts, probs);
Array2<uint> ct = new();
ct[0] = leftCount;
ct[1] = rightCount;
probs[(int)(i >> 1)] = ModeMvMergeProbs(preProbs[(int)(i >> 1)], ref ct);
return leftCount + rightCount;
}
public static void VpxTreeMergeProbs(sbyte[] tree, ReadOnlySpan<byte> preProbs, ReadOnlySpan<uint> counts,
Span<byte> probs)
{
TreeMergeProbsImpl(0, tree, preProbs, counts, probs);
}
}
}

View file

@ -1,163 +1,116 @@
using Ryujinx.Graphics.Nvdec.Vp9.Types; using System;
using System;
using System.Diagnostics; using System.Diagnostics;
namespace Ryujinx.Graphics.Nvdec.Vp9 namespace Ryujinx.Graphics.Nvdec.Vp9
{ {
internal static class QuantCommon internal static class QuantCommon
{ {
public const int MinQ = 0;
public const int MaxQ = 255; public const int MaxQ = 255;
public const int QindexBits = 8;
private static readonly short[] DcQlookup = new short[] private static readonly short[] DcQlookup =
{ {
4, 8, 8, 9, 10, 11, 12, 12, 13, 14, 15, 16, 17, 18, 4, 8, 8, 9, 10, 11, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 23, 24, 25, 26, 26, 27, 28, 29,
19, 19, 20, 21, 22, 23, 24, 25, 26, 26, 27, 28, 29, 30, 30, 31, 32, 32, 33, 34, 35, 36, 37, 38, 38, 39, 40, 41, 42, 43, 43, 44, 45, 46, 47, 48, 48, 49, 50, 51,
31, 32, 32, 33, 34, 35, 36, 37, 38, 38, 39, 40, 41, 42, 52, 53, 53, 54, 55, 56, 57, 57, 58, 59, 60, 61, 62, 62, 63, 64, 65, 66, 66, 67, 68, 69, 70, 70, 71, 72,
43, 43, 44, 45, 46, 47, 48, 48, 49, 50, 51, 52, 53, 53, 73, 74, 74, 75, 76, 77, 78, 78, 79, 80, 81, 81, 82, 83, 84, 85, 85, 87, 88, 90, 92, 93, 95, 96, 98, 99,
54, 55, 56, 57, 57, 58, 59, 60, 61, 62, 62, 63, 64, 65, 101, 102, 104, 105, 107, 108, 110, 111, 113, 114, 116, 117, 118, 120, 121, 123, 125, 127, 129, 131, 134,
66, 66, 67, 68, 69, 70, 70, 71, 72, 73, 74, 74, 75, 76, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 161, 164, 166, 169, 172, 174, 177, 180, 182,
77, 78, 78, 79, 80, 81, 81, 82, 83, 84, 85, 85, 87, 88, 185, 187, 190, 192, 195, 199, 202, 205, 208, 211, 214, 217, 220, 223, 226, 230, 233, 237, 240, 243, 247,
90, 92, 93, 95, 96, 98, 99, 101, 102, 104, 105, 107, 108, 110, 250, 253, 257, 261, 265, 269, 272, 276, 280, 284, 288, 292, 296, 300, 304, 309, 313, 317, 322, 326, 330,
111, 113, 114, 116, 117, 118, 120, 121, 123, 125, 127, 129, 131, 134, 335, 340, 344, 349, 354, 359, 364, 369, 374, 379, 384, 389, 395, 400, 406, 411, 417, 423, 429, 435, 441,
136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 161, 164, 447, 454, 461, 467, 475, 482, 489, 497, 505, 513, 522, 530, 539, 549, 559, 569, 579, 590, 602, 614, 626,
166, 169, 172, 174, 177, 180, 182, 185, 187, 190, 192, 195, 199, 202, 640, 654, 668, 684, 700, 717, 736, 755, 775, 796, 819, 843, 869, 896, 925, 955, 988, 1022, 1058, 1098,
205, 208, 211, 214, 217, 220, 223, 226, 230, 233, 237, 240, 243, 247, 1139, 1184, 1232, 1282, 1336
250, 253, 257, 261, 265, 269, 272, 276, 280, 284, 288, 292, 296, 300,
304, 309, 313, 317, 322, 326, 330, 335, 340, 344, 349, 354, 359, 364,
369, 374, 379, 384, 389, 395, 400, 406, 411, 417, 423, 429, 435, 441,
447, 454, 461, 467, 475, 482, 489, 497, 505, 513, 522, 530, 539, 549,
559, 569, 579, 590, 602, 614, 626, 640, 654, 668, 684, 700, 717, 736,
755, 775, 796, 819, 843, 869, 896, 925, 955, 988, 1022, 1058, 1098, 1139,
1184, 1232, 1282, 1336,
}; };
private static readonly short[] DcQlookup10 = new short[] private static readonly short[] DcQlookup10 =
{ {
4, 9, 10, 13, 15, 17, 20, 22, 25, 28, 31, 34, 37, 4, 9, 10, 13, 15, 17, 20, 22, 25, 28, 31, 34, 37, 40, 43, 47, 50, 53, 57, 60, 64, 68, 71, 75, 78, 82,
40, 43, 47, 50, 53, 57, 60, 64, 68, 71, 75, 78, 82, 86, 90, 93, 97, 101, 105, 109, 113, 116, 120, 124, 128, 132, 136, 140, 143, 147, 151, 155, 159, 163,
86, 90, 93, 97, 101, 105, 109, 113, 116, 120, 124, 128, 132, 166, 170, 174, 178, 182, 185, 189, 193, 197, 200, 204, 208, 212, 215, 219, 223, 226, 230, 233, 237, 241,
136, 140, 143, 147, 151, 155, 159, 163, 166, 170, 174, 178, 182, 244, 248, 251, 255, 259, 262, 266, 269, 273, 276, 280, 283, 287, 290, 293, 297, 300, 304, 307, 310, 314,
185, 189, 193, 197, 200, 204, 208, 212, 215, 219, 223, 226, 230, 317, 321, 324, 327, 331, 334, 337, 343, 350, 356, 362, 369, 375, 381, 387, 394, 400, 406, 412, 418, 424,
233, 237, 241, 244, 248, 251, 255, 259, 262, 266, 269, 273, 276, 430, 436, 442, 448, 454, 460, 466, 472, 478, 484, 490, 499, 507, 516, 525, 533, 542, 550, 559, 567, 576,
280, 283, 287, 290, 293, 297, 300, 304, 307, 310, 314, 317, 321, 584, 592, 601, 609, 617, 625, 634, 644, 655, 666, 676, 687, 698, 708, 718, 729, 739, 749, 759, 770, 782,
324, 327, 331, 334, 337, 343, 350, 356, 362, 369, 375, 381, 387, 795, 807, 819, 831, 844, 856, 868, 880, 891, 906, 920, 933, 947, 961, 975, 988, 1001, 1015, 1030, 1045,
394, 400, 406, 412, 418, 424, 430, 436, 442, 448, 454, 460, 466, 1061, 1076, 1090, 1105, 1120, 1137, 1153, 1170, 1186, 1202, 1218, 1236, 1253, 1271, 1288, 1306, 1323,
472, 478, 484, 490, 499, 507, 516, 525, 533, 542, 550, 559, 567, 1342, 1361, 1379, 1398, 1416, 1436, 1456, 1476, 1496, 1516, 1537, 1559, 1580, 1601, 1624, 1647, 1670,
576, 584, 592, 601, 609, 617, 625, 634, 644, 655, 666, 676, 687, 1692, 1717, 1741, 1766, 1791, 1817, 1844, 1871, 1900, 1929, 1958, 1990, 2021, 2054, 2088, 2123, 2159,
698, 708, 718, 729, 739, 749, 759, 770, 782, 795, 807, 819, 831, 2197, 2236, 2276, 2319, 2363, 2410, 2458, 2508, 2561, 2616, 2675, 2737, 2802, 2871, 2944, 3020, 3102,
844, 856, 868, 880, 891, 906, 920, 933, 947, 961, 975, 988, 1001, 3188, 3280, 3375, 3478, 3586, 3702, 3823, 3953, 4089, 4236, 4394, 4559, 4737, 4929, 5130, 5347
1015, 1030, 1045, 1061, 1076, 1090, 1105, 1120, 1137, 1153, 1170, 1186, 1202,
1218, 1236, 1253, 1271, 1288, 1306, 1323, 1342, 1361, 1379, 1398, 1416, 1436,
1456, 1476, 1496, 1516, 1537, 1559, 1580, 1601, 1624, 1647, 1670, 1692, 1717,
1741, 1766, 1791, 1817, 1844, 1871, 1900, 1929, 1958, 1990, 2021, 2054, 2088,
2123, 2159, 2197, 2236, 2276, 2319, 2363, 2410, 2458, 2508, 2561, 2616, 2675,
2737, 2802, 2871, 2944, 3020, 3102, 3188, 3280, 3375, 3478, 3586, 3702, 3823,
3953, 4089, 4236, 4394, 4559, 4737, 4929, 5130, 5347,
}; };
private static readonly short[] DcQlookup12 = new short[] private static readonly short[] DcQlookup12 =
{ {
4, 12, 18, 25, 33, 41, 50, 60, 70, 80, 91, 4, 12, 18, 25, 33, 41, 50, 60, 70, 80, 91, 103, 115, 127, 140, 153, 166, 180, 194, 208, 222, 237, 251,
103, 115, 127, 140, 153, 166, 180, 194, 208, 222, 237, 266, 281, 296, 312, 327, 343, 358, 374, 390, 405, 421, 437, 453, 469, 484, 500, 516, 532, 548, 564, 580,
251, 266, 281, 296, 312, 327, 343, 358, 374, 390, 405, 596, 611, 627, 643, 659, 674, 690, 706, 721, 737, 752, 768, 783, 798, 814, 829, 844, 859, 874, 889, 904,
421, 437, 453, 469, 484, 500, 516, 532, 548, 564, 580, 919, 934, 949, 964, 978, 993, 1008, 1022, 1037, 1051, 1065, 1080, 1094, 1108, 1122, 1136, 1151, 1165,
596, 611, 627, 643, 659, 674, 690, 706, 721, 737, 752, 1179, 1192, 1206, 1220, 1234, 1248, 1261, 1275, 1288, 1302, 1315, 1329, 1342, 1368, 1393, 1419, 1444,
768, 783, 798, 814, 829, 844, 859, 874, 889, 904, 919, 1469, 1494, 1519, 1544, 1569, 1594, 1618, 1643, 1668, 1692, 1717, 1741, 1765, 1789, 1814, 1838, 1862,
934, 949, 964, 978, 993, 1008, 1022, 1037, 1051, 1065, 1080, 1885, 1909, 1933, 1957, 1992, 2027, 2061, 2096, 2130, 2165, 2199, 2233, 2267, 2300, 2334, 2367, 2400,
1094, 1108, 1122, 1136, 1151, 1165, 1179, 1192, 1206, 1220, 1234, 2434, 2467, 2499, 2532, 2575, 2618, 2661, 2704, 2746, 2788, 2830, 2872, 2913, 2954, 2995, 3036, 3076,
1248, 1261, 1275, 1288, 1302, 1315, 1329, 1342, 1368, 1393, 1419, 3127, 3177, 3226, 3275, 3324, 3373, 3421, 3469, 3517, 3565, 3621, 3677, 3733, 3788, 3843, 3897, 3951,
1444, 1469, 1494, 1519, 1544, 1569, 1594, 1618, 1643, 1668, 1692, 4005, 4058, 4119, 4181, 4241, 4301, 4361, 4420, 4479, 4546, 4612, 4677, 4742, 4807, 4871, 4942, 5013,
1717, 1741, 1765, 1789, 1814, 1838, 1862, 1885, 1909, 1933, 1957, 5083, 5153, 5222, 5291, 5367, 5442, 5517, 5591, 5665, 5745, 5825, 5905, 5984, 6063, 6149, 6234, 6319,
1992, 2027, 2061, 2096, 2130, 2165, 2199, 2233, 2267, 2300, 2334, 6404, 6495, 6587, 6678, 6769, 6867, 6966, 7064, 7163, 7269, 7376, 7483, 7599, 7715, 7832, 7958, 8085,
2367, 2400, 2434, 2467, 2499, 2532, 2575, 2618, 2661, 2704, 2746, 8214, 8352, 8492, 8635, 8788, 8945, 9104, 9275, 9450, 9639, 9832, 10031, 10245, 10465, 10702, 10946,
2788, 2830, 2872, 2913, 2954, 2995, 3036, 3076, 3127, 3177, 3226, 11210, 11482, 11776, 12081, 12409, 12750, 13118, 13501, 13913, 14343, 14807, 15290, 15812, 16356, 16943,
3275, 3324, 3373, 3421, 3469, 3517, 3565, 3621, 3677, 3733, 3788, 17575, 18237, 18949, 19718, 20521, 21387
3843, 3897, 3951, 4005, 4058, 4119, 4181, 4241, 4301, 4361, 4420,
4479, 4546, 4612, 4677, 4742, 4807, 4871, 4942, 5013, 5083, 5153,
5222, 5291, 5367, 5442, 5517, 5591, 5665, 5745, 5825, 5905, 5984,
6063, 6149, 6234, 6319, 6404, 6495, 6587, 6678, 6769, 6867, 6966,
7064, 7163, 7269, 7376, 7483, 7599, 7715, 7832, 7958, 8085, 8214,
8352, 8492, 8635, 8788, 8945, 9104, 9275, 9450, 9639, 9832, 10031,
10245, 10465, 10702, 10946, 11210, 11482, 11776, 12081, 12409, 12750, 13118,
13501, 13913, 14343, 14807, 15290, 15812, 16356, 16943, 17575, 18237, 18949,
19718, 20521, 21387,
}; };
private static readonly short[] AcQlookup = new short[] private static readonly short[] AcQlookup =
{ {
4, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 4, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85,
46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 104, 106, 108, 110, 112, 114,
59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 155, 158,
72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 161, 164, 167, 170, 173, 176, 179, 182, 185, 188, 191, 194, 197, 200, 203, 207, 211, 215, 219, 223, 227,
85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 231, 235, 239, 243, 247, 251, 255, 260, 265, 270, 275, 280, 285, 290, 295, 300, 305, 311, 317, 323, 329,
98, 99, 100, 101, 102, 104, 106, 108, 110, 112, 114, 116, 118, 335, 341, 347, 353, 359, 366, 373, 380, 387, 394, 401, 408, 416, 424, 432, 440, 448, 456, 465, 474, 483,
120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 492, 501, 510, 520, 530, 540, 550, 560, 571, 582, 593, 604, 615, 627, 639, 651, 663, 676, 689, 702, 715,
146, 148, 150, 152, 155, 158, 161, 164, 167, 170, 173, 176, 179, 729, 743, 757, 771, 786, 801, 816, 832, 848, 864, 881, 898, 915, 933, 951, 969, 988, 1007, 1026, 1046,
182, 185, 188, 191, 194, 197, 200, 203, 207, 211, 215, 219, 223, 1066, 1087, 1108, 1129, 1151, 1173, 1196, 1219, 1243, 1267, 1292, 1317, 1343, 1369, 1396, 1423, 1451,
227, 231, 235, 239, 243, 247, 251, 255, 260, 265, 270, 275, 280, 1479, 1508, 1537, 1567, 1597, 1628, 1660, 1692, 1725, 1759, 1793, 1828
285, 290, 295, 300, 305, 311, 317, 323, 329, 335, 341, 347, 353,
359, 366, 373, 380, 387, 394, 401, 408, 416, 424, 432, 440, 448,
456, 465, 474, 483, 492, 501, 510, 520, 530, 540, 550, 560, 571,
582, 593, 604, 615, 627, 639, 651, 663, 676, 689, 702, 715, 729,
743, 757, 771, 786, 801, 816, 832, 848, 864, 881, 898, 915, 933,
951, 969, 988, 1007, 1026, 1046, 1066, 1087, 1108, 1129, 1151, 1173, 1196,
1219, 1243, 1267, 1292, 1317, 1343, 1369, 1396, 1423, 1451, 1479, 1508, 1537,
1567, 1597, 1628, 1660, 1692, 1725, 1759, 1793, 1828,
}; };
private static readonly short[] AcQlookup10 = new short[] private static readonly short[] AcQlookup10 =
{ {
4, 9, 11, 13, 16, 18, 21, 24, 27, 30, 33, 37, 40, 4, 9, 11, 13, 16, 18, 21, 24, 27, 30, 33, 37, 40, 44, 48, 51, 55, 59, 63, 67, 71, 75, 79, 83, 88, 92,
44, 48, 51, 55, 59, 63, 67, 71, 75, 79, 83, 88, 92, 96, 100, 105, 109, 114, 118, 122, 127, 131, 136, 140, 145, 149, 154, 158, 163, 168, 172, 177, 181, 186,
96, 100, 105, 109, 114, 118, 122, 127, 131, 136, 140, 145, 149, 190, 195, 199, 204, 208, 213, 217, 222, 226, 231, 235, 240, 244, 249, 253, 258, 262, 267, 271, 275, 280,
154, 158, 163, 168, 172, 177, 181, 186, 190, 195, 199, 204, 208, 284, 289, 293, 297, 302, 306, 311, 315, 319, 324, 328, 332, 337, 341, 345, 349, 354, 358, 362, 367, 371,
213, 217, 222, 226, 231, 235, 240, 244, 249, 253, 258, 262, 267, 375, 379, 384, 388, 392, 396, 401, 409, 417, 425, 433, 441, 449, 458, 466, 474, 482, 490, 498, 506, 514,
271, 275, 280, 284, 289, 293, 297, 302, 306, 311, 315, 319, 324, 523, 531, 539, 547, 555, 563, 571, 579, 588, 596, 604, 616, 628, 640, 652, 664, 676, 688, 700, 713, 725,
328, 332, 337, 341, 345, 349, 354, 358, 362, 367, 371, 375, 379, 737, 749, 761, 773, 785, 797, 809, 825, 841, 857, 873, 889, 905, 922, 938, 954, 970, 986, 1002, 1018,
384, 388, 392, 396, 401, 409, 417, 425, 433, 441, 449, 458, 466, 1038, 1058, 1078, 1098, 1118, 1138, 1158, 1178, 1198, 1218, 1242, 1266, 1290, 1314, 1338, 1362, 1386,
474, 482, 490, 498, 506, 514, 523, 531, 539, 547, 555, 563, 571, 1411, 1435, 1463, 1491, 1519, 1547, 1575, 1603, 1631, 1663, 1695, 1727, 1759, 1791, 1823, 1859, 1895,
579, 588, 596, 604, 616, 628, 640, 652, 664, 676, 688, 700, 713, 1931, 1967, 2003, 2039, 2079, 2119, 2159, 2199, 2239, 2283, 2327, 2371, 2415, 2459, 2507, 2555, 2603,
725, 737, 749, 761, 773, 785, 797, 809, 825, 841, 857, 873, 889, 2651, 2703, 2755, 2807, 2859, 2915, 2971, 3027, 3083, 3143, 3203, 3263, 3327, 3391, 3455, 3523, 3591,
905, 922, 938, 954, 970, 986, 1002, 1018, 1038, 1058, 1078, 1098, 1118, 3659, 3731, 3803, 3876, 3952, 4028, 4104, 4184, 4264, 4348, 4432, 4516, 4604, 4692, 4784, 4876, 4972,
1138, 1158, 1178, 1198, 1218, 1242, 1266, 1290, 1314, 1338, 1362, 1386, 1411, 5068, 5168, 5268, 5372, 5476, 5584, 5692, 5804, 5916, 6032, 6148, 6268, 6388, 6512, 6640, 6768, 6900,
1435, 1463, 1491, 1519, 1547, 1575, 1603, 1631, 1663, 1695, 1727, 1759, 1791, 7036, 7172, 7312
1823, 1859, 1895, 1931, 1967, 2003, 2039, 2079, 2119, 2159, 2199, 2239, 2283,
2327, 2371, 2415, 2459, 2507, 2555, 2603, 2651, 2703, 2755, 2807, 2859, 2915,
2971, 3027, 3083, 3143, 3203, 3263, 3327, 3391, 3455, 3523, 3591, 3659, 3731,
3803, 3876, 3952, 4028, 4104, 4184, 4264, 4348, 4432, 4516, 4604, 4692, 4784,
4876, 4972, 5068, 5168, 5268, 5372, 5476, 5584, 5692, 5804, 5916, 6032, 6148,
6268, 6388, 6512, 6640, 6768, 6900, 7036, 7172, 7312,
}; };
private static readonly short[] AcQlookup12 = new short[] private static readonly short[] AcQlookup12 =
{ {
4, 13, 19, 27, 35, 44, 54, 64, 75, 87, 99, 4, 13, 19, 27, 35, 44, 54, 64, 75, 87, 99, 112, 126, 139, 154, 168, 183, 199, 214, 230, 247, 263, 280,
112, 126, 139, 154, 168, 183, 199, 214, 230, 247, 263, 297, 314, 331, 349, 366, 384, 402, 420, 438, 456, 475, 493, 511, 530, 548, 567, 586, 604, 623, 642, 660,
280, 297, 314, 331, 349, 366, 384, 402, 420, 438, 456, 679, 698, 716, 735, 753, 772, 791, 809, 828, 846, 865, 884, 902, 920, 939, 957, 976, 994, 1012, 1030,
475, 493, 511, 530, 548, 567, 586, 604, 623, 642, 660, 1049, 1067, 1085, 1103, 1121, 1139, 1157, 1175, 1193, 1211, 1229, 1246, 1264, 1282, 1299, 1317, 1335,
679, 698, 716, 735, 753, 772, 791, 809, 828, 846, 865, 1352, 1370, 1387, 1405, 1422, 1440, 1457, 1474, 1491, 1509, 1526, 1543, 1560, 1577, 1595, 1627, 1660,
884, 902, 920, 939, 957, 976, 994, 1012, 1030, 1049, 1067, 1693, 1725, 1758, 1791, 1824, 1856, 1889, 1922, 1954, 1987, 2020, 2052, 2085, 2118, 2150, 2183, 2216,
1085, 1103, 1121, 1139, 1157, 1175, 1193, 1211, 1229, 1246, 1264, 2248, 2281, 2313, 2346, 2378, 2411, 2459, 2508, 2556, 2605, 2653, 2701, 2750, 2798, 2847, 2895, 2943,
1282, 1299, 1317, 1335, 1352, 1370, 1387, 1405, 1422, 1440, 1457, 2992, 3040, 3088, 3137, 3185, 3234, 3298, 3362, 3426, 3491, 3555, 3619, 3684, 3748, 3812, 3876, 3941,
1474, 1491, 1509, 1526, 1543, 1560, 1577, 1595, 1627, 1660, 1693, 4005, 4069, 4149, 4230, 4310, 4390, 4470, 4550, 4631, 4711, 4791, 4871, 4967, 5064, 5160, 5256, 5352,
1725, 1758, 1791, 1824, 1856, 1889, 1922, 1954, 1987, 2020, 2052, 5448, 5544, 5641, 5737, 5849, 5961, 6073, 6185, 6297, 6410, 6522, 6650, 6778, 6906, 7034, 7162, 7290,
2085, 2118, 2150, 2183, 2216, 2248, 2281, 2313, 2346, 2378, 2411, 7435, 7579, 7723, 7867, 8011, 8155, 8315, 8475, 8635, 8795, 8956, 9132, 9308, 9484, 9660, 9836, 10028,
2459, 2508, 2556, 2605, 2653, 2701, 2750, 2798, 2847, 2895, 2943, 10220, 10412, 10604, 10812, 11020, 11228, 11437, 11661, 11885, 12109, 12333, 12573, 12813, 13053, 13309,
2992, 3040, 3088, 3137, 3185, 3234, 3298, 3362, 3426, 3491, 3555, 13565, 13821, 14093, 14365, 14637, 14925, 15213, 15502, 15806, 16110, 16414, 16734, 17054, 17390, 17726,
3619, 3684, 3748, 3812, 3876, 3941, 4005, 4069, 4149, 4230, 4310, 18062, 18414, 18766, 19134, 19502, 19886, 20270, 20670, 21070, 21486, 21902, 22334, 22766, 23214, 23662,
4390, 4470, 4550, 4631, 4711, 4791, 4871, 4967, 5064, 5160, 5256, 24126, 24590, 25070, 25551, 26047, 26559, 27071, 27599, 28143, 28687, 29247
5352, 5448, 5544, 5641, 5737, 5849, 5961, 6073, 6185, 6297, 6410,
6522, 6650, 6778, 6906, 7034, 7162, 7290, 7435, 7579, 7723, 7867,
8011, 8155, 8315, 8475, 8635, 8795, 8956, 9132, 9308, 9484, 9660,
9836, 10028, 10220, 10412, 10604, 10812, 11020, 11228, 11437, 11661, 11885,
12109, 12333, 12573, 12813, 13053, 13309, 13565, 13821, 14093, 14365, 14637,
14925, 15213, 15502, 15806, 16110, 16414, 16734, 17054, 17390, 17726, 18062,
18414, 18766, 19134, 19502, 19886, 20270, 20670, 21070, 21486, 21902, 22334,
22766, 23214, 23662, 24126, 24590, 25070, 25551, 26047, 26559, 27071, 27599,
28143, 28687, 29247,
}; };
public static short DcQuant(int qindex, int delta, BitDepth bitDepth) public static short DcQuant(int qindex, int delta, BitDepth bitDepth)
@ -168,7 +121,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
case BitDepth.Bits10: return DcQlookup10[Math.Clamp(qindex + delta, 0, MaxQ)]; case BitDepth.Bits10: return DcQlookup10[Math.Clamp(qindex + delta, 0, MaxQ)];
case BitDepth.Bits12: return DcQlookup12[Math.Clamp(qindex + delta, 0, MaxQ)]; case BitDepth.Bits12: return DcQlookup12[Math.Clamp(qindex + delta, 0, MaxQ)];
default: default:
Debug.Assert(false, "bit_depth should be VPX_BITS_8, VPX_BITS_10 or VPX_BITS_12"); Debug.Assert(false, "bitDepth should be Bits8, Bits10 or Bits12");
return -1; return -1;
} }
} }
@ -181,23 +134,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
case BitDepth.Bits10: return AcQlookup10[Math.Clamp(qindex + delta, 0, MaxQ)]; case BitDepth.Bits10: return AcQlookup10[Math.Clamp(qindex + delta, 0, MaxQ)];
case BitDepth.Bits12: return AcQlookup12[Math.Clamp(qindex + delta, 0, MaxQ)]; case BitDepth.Bits12: return AcQlookup12[Math.Clamp(qindex + delta, 0, MaxQ)];
default: default:
Debug.Assert(false, "bit_depth should be VPX_BITS_8, VPX_BITS_10 or VPX_BITS_12"); Debug.Assert(false, "bitDepth should be Bits8, Bits10 or Bits12");
return -1; return -1;
} }
} }
public static int GetQIndex(ref Segmentation seg, int segmentId, int baseQIndex)
{
if (seg.IsSegFeatureActive(segmentId, SegLvlFeatures.SegLvlAltQ) != 0)
{
int data = seg.GetSegData(segmentId, SegLvlFeatures.SegLvlAltQ);
int segQIndex = seg.AbsDelta == Constants.SegmentAbsData ? data : baseQIndex + data;
return Math.Clamp(segQIndex, 0, MaxQ);
}
else
{
return baseQIndex;
}
}
} }
} }

View file

@ -0,0 +1,96 @@
using Ryujinx.Graphics.Nvdec.Vp9.Types;
using System;
using System.Diagnostics;
using System.Numerics;
namespace Ryujinx.Graphics.Nvdec.Vp9
{
public ref struct ReadBitBuffer
{
public ReadOnlySpan<byte> BitBuffer;
public ulong BitOffset;
public object ErrorHandlerData;
private static int GetMsb(uint n)
{
Debug.Assert(n != 0);
return 31 ^ BitOperations.LeadingZeroCount(n);
}
private static int GetUnsignedBits(uint numValues)
{
return numValues > 0 ? GetMsb(numValues) + 1 : 0;
}
public int DecodeUnsignedMax(int max)
{
int data = ReadLiteral(GetUnsignedBits((uint)max));
return data > max ? max : data;
}
public ulong BytesRead()
{
return (BitOffset + 7) >> 3;
}
public int ReadBit()
{
ulong off = BitOffset;
ulong p = off >> 3;
int q = 7 - (int)(off & 0x7);
if (p < (ulong)BitBuffer.Length)
{
int bit = (BitBuffer[(int)p] >> q) & 1;
BitOffset = off + 1;
return bit;
}
return 0;
}
public int ReadLiteral(int bits)
{
int value = 0, bit;
for (bit = bits - 1; bit >= 0; bit--)
{
value |= ReadBit() << bit;
}
return value;
}
public int ReadSignedLiteral(int bits)
{
int value = ReadLiteral(bits);
return ReadBit() != 0 ? -value : value;
}
public int ReadInvSignedLiteral(int bits)
{
return ReadSignedLiteral(bits);
}
public int ReadDeltaQ()
{
return ReadBit() != 0 ? ReadSignedLiteral(4) : 0;
}
public void ReadFrameSize(out int width, out int height)
{
width = ReadLiteral(16) + 1;
height = ReadLiteral(16) + 1;
}
public BitstreamProfile ReadProfile()
{
int profile = ReadBit();
profile |= ReadBit() << 1;
if (profile > 2)
{
profile += ReadBit();
}
return (BitstreamProfile)profile;
}
}
}

View file

@ -77,67 +77,38 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
bd); bd);
} }
private static int RoundMvCompQ4(int value) public static int RoundMvCompQ4(int value)
{ {
return (value < 0 ? value - 2 : value + 2) / 4; return (value < 0 ? value - 2 : value + 2) / 4;
} }
private static Mv MiMvPredQ4(ref ModeInfo mi, int idx) public static int RoundMvCompQ2(int value)
{
Mv res = new Mv()
{
Row = (short)RoundMvCompQ4(
mi.Bmi[0].Mv[idx].Row + mi.Bmi[1].Mv[idx].Row +
mi.Bmi[2].Mv[idx].Row + mi.Bmi[3].Mv[idx].Row),
Col = (short)RoundMvCompQ4(
mi.Bmi[0].Mv[idx].Col + mi.Bmi[1].Mv[idx].Col +
mi.Bmi[2].Mv[idx].Col + mi.Bmi[3].Mv[idx].Col)
};
return res;
}
private static int RoundMvCompQ2(int value)
{ {
return (value < 0 ? value - 1 : value + 1) / 2; return (value < 0 ? value - 1 : value + 1) / 2;
} }
private static Mv MiMvPredQ2(ref ModeInfo mi, int idx, int block0, int block1)
{
Mv res = new Mv()
{
Row = (short)RoundMvCompQ2(
mi.Bmi[block0].Mv[idx].Row +
mi.Bmi[block1].Mv[idx].Row),
Col = (short)RoundMvCompQ2(
mi.Bmi[block0].Mv[idx].Col +
mi.Bmi[block1].Mv[idx].Col)
};
return res;
}
public static Mv ClampMvToUmvBorderSb(ref MacroBlockD xd, ref Mv srcMv, int bw, int bh, int ssX, int ssY) public static Mv ClampMvToUmvBorderSb(ref MacroBlockD xd, ref Mv srcMv, int bw, int bh, int ssX, int ssY)
{ {
// If the MV points so far into the UMV border that no visible pixels // If the MV points so far into the UMV border that no visible pixels
// are used for reconstruction, the subpel part of the MV can be // are used for reconstruction, the subpel part of the MV can be
// discarded and the MV limited to 16 pixels with equivalent results. // discarded and the MV limited to 16 pixels with equivalent results.
int spelLeft = (Constants.Vp9InterpExtend + bw) << SubpelBits; int spelLeft = (Constants.InterpExtend + bw) << SubpelBits;
int spelRight = spelLeft - SubpelShifts; int spelRight = spelLeft - SubpelShifts;
int spelTop = (Constants.Vp9InterpExtend + bh) << SubpelBits; int spelTop = (Constants.InterpExtend + bh) << SubpelBits;
int spelBottom = spelTop - SubpelShifts; int spelBottom = spelTop - SubpelShifts;
Mv clampedMv = new Mv() Mv clampedMv = new()
{ {
Row = (short)(srcMv.Row * (1 << (1 - ssY))), Row = (short)(srcMv.Row * (1 << (1 - ssY))), Col = (short)(srcMv.Col * (1 << (1 - ssX)))
Col = (short)(srcMv.Col * (1 << (1 - ssX)))
}; };
Debug.Assert(ssX <= 1); Debug.Assert(ssX <= 1);
Debug.Assert(ssY <= 1); Debug.Assert(ssY <= 1);
clampedMv.ClampMv( clampedMv.Clamp(
xd.MbToLeftEdge * (1 << (1 - ssX)) - spelLeft, (xd.MbToLeftEdge * (1 << (1 - ssX))) - spelLeft,
xd.MbToRightEdge * (1 << (1 - ssX)) + spelRight, (xd.MbToRightEdge * (1 << (1 - ssX))) + spelRight,
xd.MbToTopEdge * (1 << (1 - ssY)) - spelTop, (xd.MbToTopEdge * (1 << (1 - ssY))) - spelTop,
xd.MbToBottomEdge * (1 << (1 - ssY)) + spelBottom); (xd.MbToBottomEdge * (1 << (1 - ssY))) + spelBottom);
return clampedMv; return clampedMv;
} }
@ -145,15 +116,26 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
public static Mv AverageSplitMvs(ref MacroBlockDPlane pd, ref ModeInfo mi, int refr, int block) public static Mv AverageSplitMvs(ref MacroBlockDPlane pd, ref ModeInfo mi, int refr, int block)
{ {
int ssIdx = ((pd.SubsamplingX > 0 ? 1 : 0) << 1) | (pd.SubsamplingY > 0 ? 1 : 0); int ssIdx = ((pd.SubsamplingX > 0 ? 1 : 0) << 1) | (pd.SubsamplingY > 0 ? 1 : 0);
Mv res = new Mv(); Mv res = new();
switch (ssIdx) switch (ssIdx)
{ {
case 0: res = mi.Bmi[block].Mv[refr]; break; case 0:
case 1: res = MiMvPredQ2(ref mi, refr, block, block + 2); break; res = mi.Bmi[block].Mv[refr];
case 2: res = MiMvPredQ2(ref mi, refr, block, block + 1); break; break;
case 3: res = MiMvPredQ4(ref mi, refr); break; case 1:
default: Debug.Assert(ssIdx <= 3 && ssIdx >= 0); break; res = mi.MvPredQ2(refr, block, block + 2);
break;
case 2:
res = mi.MvPredQ2(refr, block, block + 1);
break;
case 3:
res = mi.MvPredQ4(refr);
break;
default:
Debug.Assert(ssIdx <= 3 && ssIdx >= 0);
break;
} }
return res; return res;
} }
@ -161,7 +143,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
{ {
int x = !sf.IsNull ? sf.Value.ScaleValueX(xOffset) : xOffset; int x = !sf.IsNull ? sf.Value.ScaleValueX(xOffset) : xOffset;
int y = !sf.IsNull ? sf.Value.ScaleValueY(yOffset) : yOffset; int y = !sf.IsNull ? sf.Value.ScaleValueY(yOffset) : yOffset;
return y * stride + x; return (y * stride) + x;
} }
private static void SetupPredPlanes( private static void SetupPredPlanes(
@ -194,12 +176,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
strides[0] = src.Stride; strides[0] = src.Stride;
strides[1] = src.UvStride; strides[1] = src.UvStride;
strides[2] = src.UvStride; strides[2] = src.UvStride;
int i;
for (i = 0; i < Constants.MaxMbPlane; ++i) for (int i = 0; i < Constants.MaxMbPlane; ++i)
{ {
ref MacroBlockDPlane pd = ref planes[i]; ref MacroBlockDPlane pd = ref planes[i];
SetupPredPlanes(ref pd.Dst, buffers[i], strides[i], miRow, miCol, Ptr<ScaleFactors>.Null, pd.SubsamplingX, pd.SubsamplingY); SetupPredPlanes(ref pd.Dst, buffers[i], strides[i], miRow, miCol, Ptr<ScaleFactors>.Null,
pd.SubsamplingX, pd.SubsamplingY);
} }
} }
@ -221,12 +203,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
strides[0] = src.Stride; strides[0] = src.Stride;
strides[1] = src.UvStride; strides[1] = src.UvStride;
strides[2] = src.UvStride; strides[2] = src.UvStride;
int i;
for (i = 0; i < Constants.MaxMbPlane; ++i) for (int i = 0; i < Constants.MaxMbPlane; ++i)
{ {
ref MacroBlockDPlane pd = ref xd.Plane[i]; ref MacroBlockDPlane pd = ref xd.Plane[i];
SetupPredPlanes(ref pd.Pre[idx], buffers[i], strides[i], miRow, miCol, sf, pd.SubsamplingX, pd.SubsamplingY); SetupPredPlanes(ref pd.Pre[idx], buffers[i], strides[i], miRow, miCol, sf, pd.SubsamplingX,
pd.SubsamplingY);
} }
} }
} }

View file

@ -7,7 +7,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
{ {
internal static class ReconIntra internal static class ReconIntra
{ {
public static readonly TxType[] IntraModeToTxTypeLookup = new TxType[] public static readonly TxType[] IntraModeToTxTypeLookup =
{ {
TxType.DctDct, // DC TxType.DctDct, // DC
TxType.AdstDct, // V TxType.AdstDct, // V
@ -36,232 +36,120 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
NeedLeft | NeedAbove, // D153 NeedLeft | NeedAbove, // D153
NeedLeft, // D207 NeedLeft, // D207
NeedAboveRight, // D63 NeedAboveRight, // D63
NeedLeft | NeedAbove, // TM NeedLeft | NeedAbove // TM
}; };
private unsafe delegate void IntraPredFn(byte* dst, int stride, byte* above, byte* left); private unsafe delegate void IntraPredFn(byte* dst, int stride, byte* above, byte* left);
private static unsafe IntraPredFn[][] _pred = new IntraPredFn[][] private static readonly unsafe IntraPredFn[][] Pred =
{ {
new IntraPredFn[] new IntraPredFn[] { null, null, null, null },
{ new IntraPredFn[] { VPredictor4x4, VPredictor8x8, VPredictor16x16, VPredictor32x32 },
null, new IntraPredFn[] { HPredictor4x4, HPredictor8x8, HPredictor16x16, HPredictor32x32 },
null, new IntraPredFn[] { D45Predictor4x4, D45Predictor8x8, D45Predictor16x16, D45Predictor32x32 },
null, new IntraPredFn[] { D135Predictor4x4, D135Predictor8x8, D135Predictor16x16, D135Predictor32x32 },
null new IntraPredFn[] { D117Predictor4x4, D117Predictor8x8, D117Predictor16x16, D117Predictor32x32 },
}, new IntraPredFn[] { D153Predictor4x4, D153Predictor8x8, D153Predictor16x16, D153Predictor32x32 },
new IntraPredFn[] new IntraPredFn[] { D207Predictor4x4, D207Predictor8x8, D207Predictor16x16, D207Predictor32x32 },
{ new IntraPredFn[] { D63Predictor4x4, D63Predictor8x8, D63Predictor16x16, D63Predictor32x32 },
VPredictor4x4, new IntraPredFn[] { TmPredictor4x4, TmPredictor8x8, TmPredictor16x16, TmPredictor32x32 }
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[][][] private static readonly unsafe IntraPredFn[][][] DcPred =
{ {
new IntraPredFn[][] new[]
{ {
new IntraPredFn[] new IntraPredFn[]
{ {
Dc128Predictor4x4, Dc128Predictor4x4, Dc128Predictor8x8, Dc128Predictor16x16, Dc128Predictor32x32
Dc128Predictor8x8,
Dc128Predictor16x16,
Dc128Predictor32x32
}, },
new IntraPredFn[] new IntraPredFn[]
{ {
DcTopPredictor4x4, DcTopPredictor4x4, DcTopPredictor8x8, DcTopPredictor16x16, DcTopPredictor32x32
DcTopPredictor8x8,
DcTopPredictor16x16,
DcTopPredictor32x32
} }
}, },
new IntraPredFn[][] new[]
{ {
new IntraPredFn[] new IntraPredFn[]
{ {
DcLeftPredictor4x4, DcLeftPredictor4x4, DcLeftPredictor8x8, DcLeftPredictor16x16, DcLeftPredictor32x32
DcLeftPredictor8x8,
DcLeftPredictor16x16,
DcLeftPredictor32x32
}, },
new IntraPredFn[] new IntraPredFn[] { DcPredictor4x4, DcPredictor8x8, DcPredictor16x16, DcPredictor32x32 }
{
DcPredictor4x4,
DcPredictor8x8,
DcPredictor16x16,
DcPredictor32x32
}
} }
}; };
private unsafe delegate void IntraHighPredFn(ushort* dst, int stride, ushort* above, ushort* left, int bd); private unsafe delegate void IntraHighPredFn(ushort* dst, int stride, ushort* above, ushort* left, int bd);
private static unsafe IntraHighPredFn[][] _predHigh = new IntraHighPredFn[][] private static readonly unsafe IntraHighPredFn[][] PredHigh =
{ {
new IntraHighPredFn[] { null, null, null, null },
new IntraHighPredFn[] new IntraHighPredFn[]
{ {
null, HighbdVPredictor4x4, HighbdVPredictor8x8, HighbdVPredictor16x16, HighbdVPredictor32x32
null,
null,
null
}, },
new IntraHighPredFn[] new IntraHighPredFn[]
{ {
HighbdVPredictor4x4, HighbdHPredictor4x4, HighbdHPredictor8x8, HighbdHPredictor16x16, HighbdHPredictor32x32
HighbdVPredictor8x8,
HighbdVPredictor16x16,
HighbdVPredictor32x32
}, },
new IntraHighPredFn[] new IntraHighPredFn[]
{ {
HighbdHPredictor4x4, HighbdD45Predictor4x4, HighbdD45Predictor8x8, HighbdD45Predictor16x16, HighbdD45Predictor32x32
HighbdHPredictor8x8,
HighbdHPredictor16x16,
HighbdHPredictor32x32
}, },
new IntraHighPredFn[] new IntraHighPredFn[]
{ {
HighbdD45Predictor4x4, HighbdD135Predictor4x4, HighbdD135Predictor8x8, HighbdD135Predictor16x16,
HighbdD45Predictor8x8,
HighbdD45Predictor16x16,
HighbdD45Predictor32x32
},
new IntraHighPredFn[]
{
HighbdD135Predictor4x4,
HighbdD135Predictor8x8,
HighbdD135Predictor16x16,
HighbdD135Predictor32x32 HighbdD135Predictor32x32
}, },
new IntraHighPredFn[] new IntraHighPredFn[]
{ {
HighbdD117Predictor4x4, HighbdD117Predictor4x4, HighbdD117Predictor8x8, HighbdD117Predictor16x16,
HighbdD117Predictor8x8,
HighbdD117Predictor16x16,
HighbdD117Predictor32x32 HighbdD117Predictor32x32
}, },
new IntraHighPredFn[] new IntraHighPredFn[]
{ {
HighbdD153Predictor4x4, HighbdD153Predictor4x4, HighbdD153Predictor8x8, HighbdD153Predictor16x16,
HighbdD153Predictor8x8,
HighbdD153Predictor16x16,
HighbdD153Predictor32x32 HighbdD153Predictor32x32
}, },
new IntraHighPredFn[] new IntraHighPredFn[]
{ {
HighbdD207Predictor4x4, HighbdD207Predictor4x4, HighbdD207Predictor8x8, HighbdD207Predictor16x16,
HighbdD207Predictor8x8,
HighbdD207Predictor16x16,
HighbdD207Predictor32x32 HighbdD207Predictor32x32
}, },
new IntraHighPredFn[] new IntraHighPredFn[]
{ {
HighbdD63Predictor4x4, HighbdD63Predictor4x4, HighbdD63Predictor8x8, HighbdD63Predictor16x16, HighbdD63Predictor32x32
HighbdD63Predictor8x8,
HighbdD63Predictor16x16,
HighbdD63Predictor32x32
}, },
new IntraHighPredFn[] new IntraHighPredFn[]
{ {
HighbdTMPredictor4x4, HighbdTmPredictor4x4, HighbdTmPredictor8x8, HighbdTmPredictor16x16, HighbdTmPredictor32x32
HighbdTMPredictor8x8,
HighbdTMPredictor16x16,
HighbdTMPredictor32x32
} }
}; };
private static unsafe IntraHighPredFn[][][] _dcPredHigh = new IntraHighPredFn[][][] private static readonly unsafe IntraHighPredFn[][][] DcPredHigh =
{ {
new IntraHighPredFn[][] new[]
{ {
new IntraHighPredFn[] new IntraHighPredFn[]
{ {
HighbdDc128Predictor4x4, HighbdDc128Predictor4x4, HighbdDc128Predictor8x8, HighbdDc128Predictor16x16,
HighbdDc128Predictor8x8,
HighbdDc128Predictor16x16,
HighbdDc128Predictor32x32 HighbdDc128Predictor32x32
}, },
new IntraHighPredFn[] new IntraHighPredFn[]
{ {
HighbdDcTopPredictor4x4, HighbdDcTopPredictor4x4, HighbdDcTopPredictor8x8, HighbdDcTopPredictor16x16,
HighbdDcTopPredictor8x8,
HighbdDcTopPredictor16x16,
HighbdDcTopPredictor32x32 HighbdDcTopPredictor32x32
} }
}, },
new IntraHighPredFn[][] new[]
{ {
new IntraHighPredFn[] new IntraHighPredFn[]
{ {
HighbdDcLeftPredictor4x4, HighbdDcLeftPredictor4x4, HighbdDcLeftPredictor8x8, HighbdDcLeftPredictor16x16,
HighbdDcLeftPredictor8x8,
HighbdDcLeftPredictor16x16,
HighbdDcLeftPredictor32x32 HighbdDcLeftPredictor32x32
}, },
new IntraHighPredFn[] new IntraHighPredFn[]
{ {
HighbdDcPredictor4x4, HighbdDcPredictor4x4, HighbdDcPredictor8x8, HighbdDcPredictor16x16,
HighbdDcPredictor8x8,
HighbdDcPredictor16x16,
HighbdDcPredictor32x32 HighbdDcPredictor32x32
} }
} }
@ -332,7 +220,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
{ {
for (i = 0; i < bs; ++i) for (i = 0; i < bs; ++i)
{ {
leftCol[i] = refr[i * refStride - 1]; leftCol[i] = refr[(i * refStride) - 1];
} }
} }
else else
@ -340,12 +228,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
int extendBottom = frameHeight - y0; int extendBottom = frameHeight - y0;
for (i = 0; i < extendBottom; ++i) for (i = 0; i < extendBottom; ++i)
{ {
leftCol[i] = refr[i * refStride - 1]; leftCol[i] = refr[(i * refStride) - 1];
} }
for (; i < bs; ++i) for (; i < bs; ++i)
{ {
leftCol[i] = refr[(extendBottom - 1) * refStride - 1]; leftCol[i] = refr[((extendBottom - 1) * refStride) - 1];
} }
} }
} }
@ -354,7 +242,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
/* faster path if the block does not need extension */ /* faster path if the block does not need extension */
for (i = 0; i < bs; ++i) for (i = 0; i < bs; ++i)
{ {
leftCol[i] = refr[i * refStride - 1]; leftCol[i] = refr[(i * refStride) - 1];
} }
} }
} }
@ -396,6 +284,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
MemoryUtil.Copy(aboveRow, aboveRef, bs); MemoryUtil.Copy(aboveRow, aboveRef, bs);
} }
} }
aboveRow[-1] = leftAvailable != 0 ? aboveRef[-1] : (ushort)(baseVal + 1); aboveRow[-1] = leftAvailable != 0 ? aboveRef[-1] : (ushort)(baseVal + 1);
} }
else else
@ -414,7 +303,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
if (xd.MbToRightEdge < 0) if (xd.MbToRightEdge < 0)
{ {
/* slower path if the block needs border extension */ /* slower path if the block needs border extension */
if (x0 + 2 * bs <= frameWidth) if (x0 + (2 * bs) <= frameWidth)
{ {
if (rightAvailable != 0 && bs == 4) if (rightAvailable != 0 && bs == 4)
{ {
@ -432,7 +321,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
if (rightAvailable != 0 && bs == 4) if (rightAvailable != 0 && bs == 4)
{ {
MemoryUtil.Copy(aboveRow, aboveRef, r); MemoryUtil.Copy(aboveRow, aboveRef, r);
MemoryUtil.Fill(aboveRow + r, aboveRow[r - 1], x0 + 2 * bs - frameWidth); MemoryUtil.Fill(aboveRow + r, aboveRow[r - 1], x0 + (2 * bs) - frameWidth);
} }
else else
{ {
@ -444,8 +333,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
{ {
int r = frameWidth - x0; int r = frameWidth - x0;
MemoryUtil.Copy(aboveRow, aboveRef, r); MemoryUtil.Copy(aboveRow, aboveRef, r);
MemoryUtil.Fill(aboveRow + r, aboveRow[r - 1], x0 + 2 * bs - frameWidth); MemoryUtil.Fill(aboveRow + r, aboveRow[r - 1], x0 + (2 * bs) - frameWidth);
} }
aboveRow[-1] = leftAvailable != 0 ? aboveRef[-1] : (ushort)(baseVal + 1); aboveRow[-1] = leftAvailable != 0 ? aboveRef[-1] : (ushort)(baseVal + 1);
} }
else else
@ -481,11 +371,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
// Predict // Predict
if (mode == PredictionMode.DcPred) if (mode == PredictionMode.DcPred)
{ {
_dcPredHigh[leftAvailable][upAvailable][(int)txSize](dst, dstStride, constAboveRow, leftCol, xd.Bd); DcPredHigh[leftAvailable][upAvailable][(int)txSize](dst, dstStride, constAboveRow, leftCol, xd.Bd);
} }
else else
{ {
_predHigh[(int)mode][(int)txSize](dst, dstStride, constAboveRow, leftCol, xd.Bd); PredHigh[(int)mode][(int)txSize](dst, dstStride, constAboveRow, leftCol, xd.Bd);
} }
} }
@ -549,7 +439,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
{ {
for (i = 0; i < bs; ++i) for (i = 0; i < bs; ++i)
{ {
leftCol[i] = refr[i * refStride - 1]; leftCol[i] = refr[(i * refStride) - 1];
} }
} }
else else
@ -557,12 +447,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
int extendBottom = frameHeight - y0; int extendBottom = frameHeight - y0;
for (i = 0; i < extendBottom; ++i) for (i = 0; i < extendBottom; ++i)
{ {
leftCol[i] = refr[i * refStride - 1]; leftCol[i] = refr[(i * refStride) - 1];
} }
for (; i < bs; ++i) for (; i < bs; ++i)
{ {
leftCol[i] = refr[(extendBottom - 1) * refStride - 1]; leftCol[i] = refr[((extendBottom - 1) * refStride) - 1];
} }
} }
} }
@ -571,7 +461,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
/* Faster path if the block does not need extension */ /* Faster path if the block does not need extension */
for (i = 0; i < bs; ++i) for (i = 0; i < bs; ++i)
{ {
leftCol[i] = refr[i * refStride - 1]; leftCol[i] = refr[(i * refStride) - 1];
} }
} }
} }
@ -613,6 +503,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
MemoryUtil.Copy(aboveRow, aboveRef, bs); MemoryUtil.Copy(aboveRow, aboveRef, bs);
} }
} }
aboveRow[-1] = leftAvailable != 0 ? aboveRef[-1] : (byte)129; aboveRow[-1] = leftAvailable != 0 ? aboveRef[-1] : (byte)129;
} }
else else
@ -631,7 +522,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
if (xd.MbToRightEdge < 0) if (xd.MbToRightEdge < 0)
{ {
/* Slower path if the block needs border extension */ /* Slower path if the block needs border extension */
if (x0 + 2 * bs <= frameWidth) if (x0 + (2 * bs) <= frameWidth)
{ {
if (rightAvailable != 0 && bs == 4) if (rightAvailable != 0 && bs == 4)
{ {
@ -649,7 +540,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
if (rightAvailable != 0 && bs == 4) if (rightAvailable != 0 && bs == 4)
{ {
MemoryUtil.Copy(aboveRow, aboveRef, r); MemoryUtil.Copy(aboveRow, aboveRef, r);
MemoryUtil.Fill(aboveRow + r, aboveRow[r - 1], x0 + 2 * bs - frameWidth); MemoryUtil.Fill(aboveRow + r, aboveRow[r - 1], x0 + (2 * bs) - frameWidth);
} }
else else
{ {
@ -661,7 +552,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
{ {
int r = frameWidth - x0; int r = frameWidth - x0;
MemoryUtil.Copy(aboveRow, aboveRef, r); MemoryUtil.Copy(aboveRow, aboveRef, r);
MemoryUtil.Fill(aboveRow + r, aboveRow[r - 1], x0 + 2 * bs - frameWidth); MemoryUtil.Fill(aboveRow + r, aboveRow[r - 1], x0 + (2 * bs) - frameWidth);
} }
} }
else else
@ -684,6 +575,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
} }
} }
} }
aboveRow[-1] = leftAvailable != 0 ? aboveRef[-1] : (byte)129; aboveRow[-1] = leftAvailable != 0 ? aboveRef[-1] : (byte)129;
} }
else else
@ -696,11 +588,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
// Predict // Predict
if (mode == PredictionMode.DcPred) if (mode == PredictionMode.DcPred)
{ {
_dcPred[leftAvailable][upAvailable][(int)txSize](dst, dstStride, constAboveRow, leftCol); DcPred[leftAvailable][upAvailable][(int)txSize](dst, dstStride, constAboveRow, leftCol);
} }
else else
{ {
_pred[(int)mode][(int)txSize](dst, dstStride, constAboveRow, leftCol); Pred[(int)mode][(int)txSize](dst, dstStride, constAboveRow, leftCol);
} }
} }
@ -721,7 +613,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
int txw = 1 << (int)txSize; int txw = 1 << (int)txSize;
int haveTop = loff != 0 || !xd.AboveMi.IsNull ? 1 : 0; int haveTop = loff != 0 || !xd.AboveMi.IsNull ? 1 : 0;
int haveLeft = aoff != 0 || !xd.LeftMi.IsNull ? 1 : 0; int haveLeft = aoff != 0 || !xd.LeftMi.IsNull ? 1 : 0;
int haveRight = (aoff + txw) < bw ? 1 : 0; int haveRight = aoff + txw < bw ? 1 : 0;
int x = aoff * 4; int x = aoff * 4;
int y = loff * 4; int y = loff * 4;
@ -743,6 +635,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
plane); plane);
return; return;
} }
BuildIntraPredictors( BuildIntraPredictors(
ref xd, ref xd,
refr, refr,

View file

@ -12,9 +12,20 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
public int BufEnd; public int BufEnd;
public Reader BitReader; public Reader BitReader;
public Vp9BackwardUpdates Counts; public Vp9BackwardUpdates Counts;
public MacroBlockD Xd; public MacroBlockD Xd;
/* dqcoeff are shared by all the planes. So planes must be decoded serially */ /* dqcoeff are shared by all the planes. So planes must be decoded serially */
public Array32<Array32<int>> Dqcoeff; public Array32<Array32<int>> Dqcoeff;
public InternalErrorInfo ErrorInfo; public InternalErrorInfo ErrorInfo;
public int DecPartitionPlaneContext(int miRow, int miCol, int bsl)
{
ref sbyte aboveCtx = ref Xd.AboveSegContext[miCol];
ref sbyte leftCtx = ref Xd.LeftSegContext[miRow & Constants.MiMask];
int above = (aboveCtx >> bsl) & 1, left = (leftCtx >> bsl) & 1;
return (left * 2) + above + (bsl * Constants.PartitionPloffset);
}
} }
} }

View file

@ -0,0 +1,11 @@
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
{
public enum BitstreamProfile
{
Profile0,
Profile1,
Profile2,
Profile3,
MaxProfiles
}
}

View file

@ -2,20 +2,20 @@
{ {
internal enum BlockSize internal enum BlockSize
{ {
Block4x4 = 0, Block4x4,
Block4x8 = 1, Block4x8,
Block8x4 = 2, Block8x4,
Block8x8 = 3, Block8x8,
Block8x16 = 4, Block8x16,
Block16x8 = 5, Block16x8,
Block16x16 = 6, Block16x16,
Block16x32 = 7, Block16x32,
Block32x16 = 8, Block32x16,
Block32x32 = 9, Block32x32,
Block32x64 = 10, Block32x64,
Block64x32 = 11, Block64x32,
Block64x64 = 12, Block64x64,
BlockSizes = 13, BlockSizes,
BlockInvalid = BlockSizes BlockInvalid = BlockSizes
} }
} }

View file

@ -0,0 +1,18 @@
using Ryujinx.Common.Memory;
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
{
internal struct BufferPool
{
// Private data associated with the frame buffer callbacks.
public Ptr<InternalFrameBufferList> CbPriv;
// vpx_get_frame_buffer_cb_fn_t get_fb_cb;
// vpx_release_frame_buffer_cb_fn_t release_fb_cb;
public Array12<RefCntBuffer> FrameBufs;
// Frame buffers allocated internally by the codec.
public InternalFrameBufferList IntFrameBuffers;
}
}

View file

@ -23,5 +23,18 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
public ArrayPtr<LoopFilterMask> Lfm; public ArrayPtr<LoopFilterMask> Lfm;
public int LfmStride; public int LfmStride;
public void SetDefaultLfDeltas()
{
ModeRefDeltaEnabled = true;
ModeRefDeltaUpdate = true;
RefDeltas[Constants.IntraFrame] = 1;
RefDeltas[Constants.LastFrame] = 0;
RefDeltas[Constants.GoldenFrame] = -1;
RefDeltas[Constants.AltRefFrame] = -1;
ModeDeltas[0] = 0;
ModeDeltas[1] = 0;
}
} }
} }

View file

@ -1,4 +1,5 @@
using Ryujinx.Common.Memory; using Ryujinx.Common.Memory;
using Ryujinx.Graphics.Nvdec.Vp9.Common;
using Ryujinx.Graphics.Video; using Ryujinx.Graphics.Video;
namespace Ryujinx.Graphics.Nvdec.Vp9.Types namespace Ryujinx.Graphics.Nvdec.Vp9.Types
@ -82,19 +83,19 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
{ {
return leftType; return leftType;
} }
else if (leftType == Constants.SwitchableFilters)
if (leftType == Constants.SwitchableFilters)
{ {
return aboveType; return aboveType;
} }
else if (aboveType == Constants.SwitchableFilters)
if (aboveType == Constants.SwitchableFilters)
{ {
return leftType; return leftType;
} }
else
{
return Constants.SwitchableFilters; return Constants.SwitchableFilters;
} }
}
// The mode info data structure has a one element border above and to the // The mode info data structure has a one element border above and to the
// left of the entries corresponding to real macroblocks. // left of the entries corresponding to real macroblocks.
@ -106,15 +107,19 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
public int GetIntraInterContext() public int GetIntraInterContext()
{ {
if (!AboveMi.IsNull && !LeftMi.IsNull) if (!AboveMi.IsNull && !LeftMi.IsNull)
{ // Both edges available {
// Both edges available
bool aboveIntra = !AboveMi.Value.IsInterBlock(); bool aboveIntra = !AboveMi.Value.IsInterBlock();
bool leftIntra = !LeftMi.Value.IsInterBlock(); bool leftIntra = !LeftMi.Value.IsInterBlock();
return leftIntra && aboveIntra ? 3 : (leftIntra || aboveIntra ? 1 : 0); return leftIntra && aboveIntra ? 3 : leftIntra || aboveIntra ? 1 : 0;
} }
else if (!AboveMi.IsNull || !LeftMi.IsNull)
{ // One edge available if (!AboveMi.IsNull || !LeftMi.IsNull)
{
// One edge available
return 2 * (!(!AboveMi.IsNull ? AboveMi.Value : LeftMi.Value).IsInterBlock() ? 1 : 0); return 2 * (!(!AboveMi.IsNull ? AboveMi.Value : LeftMi.Value).IsInterBlock() ? 1 : 0);
} }
return 0; return 0;
} }
@ -125,8 +130,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
public int GetTxSizeContext() public int GetTxSizeContext()
{ {
int maxTxSize = (int)Luts.MaxTxSizeLookup[(int)Mi[0].Value.SbType]; int maxTxSize = (int)Luts.MaxTxSizeLookup[(int)Mi[0].Value.SbType];
int aboveCtx = (!AboveMi.IsNull && AboveMi.Value.Skip == 0) ? (int)AboveMi.Value.TxSize : maxTxSize; int aboveCtx = !AboveMi.IsNull && AboveMi.Value.Skip == 0 ? (int)AboveMi.Value.TxSize : maxTxSize;
int leftCtx = (!LeftMi.IsNull && LeftMi.Value.Skip == 0) ? (int)LeftMi.Value.TxSize : maxTxSize; int leftCtx = !LeftMi.IsNull && LeftMi.Value.Skip == 0 ? (int)LeftMi.Value.TxSize : maxTxSize;
if (LeftMi.IsNull) if (LeftMi.IsNull)
{ {
leftCtx = aboveCtx; leftCtx = aboveCtx;
@ -137,14 +142,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
aboveCtx = leftCtx; aboveCtx = leftCtx;
} }
return (aboveCtx + leftCtx) > maxTxSize ? 1 : 0; return aboveCtx + leftCtx > maxTxSize ? 1 : 0;
} }
public void SetupBlockPlanes(int ssX, int ssY) public void SetupBlockPlanes(int ssX, int ssY)
{ {
int i; for (int i = 0; i < Constants.MaxMbPlane; i++)
for (i = 0; i < Constants.MaxMbPlane; i++)
{ {
Plane[i].SubsamplingX = i != 0 ? ssX : 0; Plane[i].SubsamplingX = i != 0 ? ssX : 0;
Plane[i].SubsamplingY = i != 0 ? ssY : 0; Plane[i].SubsamplingY = i != 0 ? ssY : 0;
@ -155,25 +158,36 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
{ {
int aboveIdx = miCol * 2; int aboveIdx = miCol * 2;
int leftIdx = (miRow * 2) & 15; int leftIdx = (miRow * 2) & 15;
int i;
for (i = 0; i < Constants.MaxMbPlane; ++i) for (int i = 0; i < Constants.MaxMbPlane; ++i)
{ {
ref MacroBlockDPlane pd = ref Plane[i]; ref MacroBlockDPlane pd = ref Plane[i];
pd.AboveContext = AboveContext[i].Slice(aboveIdx >> pd.SubsamplingX); pd.AboveContext = AboveContext[i].Slice(aboveIdx >> pd.SubsamplingX);
pd.LeftContext = new ArrayPtr<sbyte>(ref LeftContext[i][leftIdx >> pd.SubsamplingY], 16 - (leftIdx >> pd.SubsamplingY)); pd.LeftContext = new ArrayPtr<sbyte>(ref LeftContext[i][leftIdx >> pd.SubsamplingY],
16 - (leftIdx >> pd.SubsamplingY));
} }
} }
internal void SetMiRowCol(ref TileInfo tile, int miRow, int bh, int miCol, int bw, int miRows, int miCols) internal void SetMiRowCol(ref TileInfo tile, int miRow, int bh, int miCol, int bw, int miRows, int miCols)
{ {
MbToTopEdge = -((miRow * Constants.MiSize) * 8); MbToTopEdge = -(miRow * Constants.MiSize * 8);
MbToBottomEdge = ((miRows - bh - miRow) * Constants.MiSize) * 8; MbToBottomEdge = (miRows - bh - miRow) * Constants.MiSize * 8;
MbToLeftEdge = -((miCol * Constants.MiSize) * 8); MbToLeftEdge = -(miCol * Constants.MiSize * 8);
MbToRightEdge = ((miCols - bw - miCol) * Constants.MiSize) * 8; MbToRightEdge = (miCols - bw - miCol) * Constants.MiSize * 8;
// Are edges available for intra prediction? // Are edges available for intra prediction?
AboveMi = (miRow != 0) ? Mi[-MiStride] : Ptr<ModeInfo>.Null; AboveMi = miRow != 0 ? Mi[-MiStride] : Ptr<ModeInfo>.Null;
LeftMi = (miCol > tile.MiColStart) ? Mi[-1] : Ptr<ModeInfo>.Null; LeftMi = miCol > tile.MiColStart ? Mi[-1] : Ptr<ModeInfo>.Null;
}
public unsafe void DecResetSkipContext()
{
for (int i = 0; i < Constants.MaxMbPlane; i++)
{
ref MacroBlockDPlane pd = ref Plane[i];
MemoryUtil.Fill(pd.AboveContext.ToPointer(), (sbyte)0, pd.N4W);
MemoryUtil.Fill(pd.LeftContext.ToPointer(), (sbyte)0, pd.N4H);
}
} }
} }
} }

View file

@ -15,6 +15,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
// Number of 4x4s in current block // Number of 4x4s in current block
public ushort N4W, N4H; public ushort N4W, N4H;
// Log2 of N4W, N4H // Log2 of N4W, N4H
public byte N4Wl, N4Hl; public byte N4Wl, N4Hl;
} }

View file

@ -49,9 +49,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
return RefFrame[1] > Constants.IntraFrame; return RefFrame[1] > Constants.IntraFrame;
} }
private static readonly int[][] IdxNColumnToSubblock = new int[][] private static readonly int[][] IdxNColumnToSubblock =
{ {
new int[] { 1, 2 }, new int[] { 1, 3 }, new int[] { 3, 2 }, new int[] { 3, 3 } new[] { 1, 2 }, new[] { 1, 3 }, new[] { 3, 2 }, new[] { 3, 3 }
}; };
// This function returns either the appropriate sub block or block's mv // This function returns either the appropriate sub block or block's mv
@ -62,5 +62,46 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
? Bmi[IdxNColumnToSubblock[blockIdx][searchCol == 0 ? 1 : 0]].Mv[whichMv] ? Bmi[IdxNColumnToSubblock[blockIdx][searchCol == 0 ? 1 : 0]].Mv[whichMv]
: Mv[whichMv]; : Mv[whichMv];
} }
public Mv MvPredQ4(int idx)
{
Mv res = new()
{
Row = (short)ReconInter.RoundMvCompQ4(
Bmi[0].Mv[idx].Row + Bmi[1].Mv[idx].Row +
Bmi[2].Mv[idx].Row + Bmi[3].Mv[idx].Row),
Col = (short)ReconInter.RoundMvCompQ4(
Bmi[0].Mv[idx].Col + Bmi[1].Mv[idx].Col +
Bmi[2].Mv[idx].Col + Bmi[3].Mv[idx].Col)
};
return res;
}
public Mv MvPredQ2(int idx, int block0, int block1)
{
Mv res = new()
{
Row = (short)ReconInter.RoundMvCompQ2(
Bmi[block0].Mv[idx].Row +
Bmi[block1].Mv[idx].Row),
Col = (short)ReconInter.RoundMvCompQ2(
Bmi[block0].Mv[idx].Col +
Bmi[block1].Mv[idx].Col)
};
return res;
}
// Performs mv sign inversion if indicated by the reference frame combination.
public Mv ScaleMv(int refr, sbyte thisRefFrame, ref Array4<sbyte> refSignBias)
{
Mv mv = Mv[refr];
if (refSignBias[RefFrame[refr]] != refSignBias[thisRefFrame])
{
mv.Row *= -1;
mv.Col *= -1;
}
return mv;
}
} }
} }

View file

@ -12,96 +12,86 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
private static ReadOnlySpan<byte> LogInBase2 => new byte[] private static ReadOnlySpan<byte> LogInBase2 => new byte[]
{ {
0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5,
4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10
}; };
public bool UseMvHp() public bool UseHp()
{ {
const int kMvRefThresh = 64; // Threshold for use of high-precision 1/8 mv const int kMvRefThresh = 64; // Threshold for use of high-precision 1/8 mv
return Math.Abs(Row) < kMvRefThresh && Math.Abs(Col) < kMvRefThresh; return Math.Abs(Row) < kMvRefThresh && Math.Abs(Col) < kMvRefThresh;
} }
public static bool MvJointVertical(MvJointType type) public static bool JointVertical(MvJointType type)
{ {
return type == MvJointType.MvJointHzvnz || type == MvJointType.MvJointHnzvnz; return type == MvJointType.Hzvnz || type == MvJointType.Hnzvnz;
} }
public static bool MvJointHorizontal(MvJointType type) public static bool JointHorizontal(MvJointType type)
{ {
return type == MvJointType.MvJointHnzvz || type == MvJointType.MvJointHnzvnz; return type == MvJointType.Hnzvz || type == MvJointType.Hnzvnz;
} }
private static int MvClassBase(MvClassType c) private static int ClassBase(MvClassType c)
{ {
return c != 0 ? Constants.Class0Size << ((int)c + 2) : 0; return c != 0 ? Constants.Class0Size << ((int)c + 2) : 0;
} }
private static MvClassType GetMvClass(int z, Ptr<int> offset) private static MvClassType GetClass(int z, Ptr<int> offset)
{ {
MvClassType c = (z >= Constants.Class0Size * 4096) ? MvClassType.MvClass10 : (MvClassType)LogInBase2[z >> 3]; MvClassType c = z >= Constants.Class0Size * 4096 ? MvClassType.Class10 : (MvClassType)LogInBase2[z >> 3];
if (!offset.IsNull) if (!offset.IsNull)
{ {
offset.Value = z - MvClassBase(c); offset.Value = z - ClassBase(c);
} }
return c; return c;
} }
private static void IncMvComponent(int v, ref Vp9BackwardUpdates counts, int comp, int incr, int usehp) private static void IncComponent(int v, ref Vp9BackwardUpdates counts, int comp, int incr, int usehp)
{ {
int s, z, c, o = 0, d, e, f; int o = 0;
Debug.Assert(v != 0); /* Should not be zero */ Debug.Assert(v != 0); /* Should not be zero */
s = v < 0 ? 1 : 0; int s = v < 0 ? 1 : 0;
counts.Sign[comp][s] += (uint)incr; counts.Sign[comp][s] += (uint)incr;
z = (s != 0 ? -v : v) - 1; /* Magnitude - 1 */ int z = (s != 0 ? -v : v) - 1 /* Magnitude - 1 */;
c = (int)GetMvClass(z, new Ptr<int>(ref o)); int c = (int)GetClass(z, new Ptr<int>(ref o));
counts.Classes[comp][c] += (uint)incr; counts.Classes[comp][c] += (uint)incr;
d = (o >> 3); /* Int mv data */ int d = o >> 3 /* Int mv data */;
f = (o >> 1) & 3; /* Fractional pel mv data */ int f = (o >> 1) & 3 /* Fractional pel mv data */;
e = (o & 1); /* High precision mv data */ int e = o & 1 /* High precision mv data */;
if (c == (int)MvClassType.MvClass0) if (c == (int)MvClassType.Class0)
{ {
counts.Class0[comp][d] += (uint)incr; counts.Class0[comp][d] += (uint)incr;
counts.Class0Fp[comp][d][f] += (uint)incr; counts.Class0Fp[comp][d][f] += (uint)incr;
@ -109,11 +99,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
} }
else else
{ {
int i;
int b = c + Constants.Class0Bits - 1; // Number of bits int b = c + Constants.Class0Bits - 1; // Number of bits
for (i = 0; i < b; ++i) for (int i = 0; i < b; ++i)
{ {
counts.Bits[comp][i][((d >> i) & 1)] += (uint)incr; counts.Bits[comp][i][(d >> i) & 1] += (uint)incr;
} }
counts.Fp[comp][f] += (uint)incr; counts.Fp[comp][f] += (uint)incr;
@ -121,58 +110,56 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
} }
} }
private MvJointType GetMvJoint() public MvJointType GetJoint()
{ {
if (Row == 0) if (Row == 0)
{ {
return Col == 0 ? MvJointType.MvJointZero : MvJointType.MvJointHnzvz; return Col == 0 ? MvJointType.Zero : MvJointType.Hnzvz;
}
else
{
return Col == 0 ? MvJointType.MvJointHzvnz : MvJointType.MvJointHnzvnz;
}
} }
internal void IncMv(Ptr<Vp9BackwardUpdates> counts) return Col == 0 ? MvJointType.Hzvnz : MvJointType.Hnzvnz;
}
internal void Inc(Ptr<Vp9BackwardUpdates> counts)
{ {
if (!counts.IsNull) if (!counts.IsNull)
{ {
MvJointType j = GetMvJoint(); MvJointType j = GetJoint();
++counts.Value.Joints[(int)j]; ++counts.Value.Joints[(int)j];
if (MvJointVertical(j)) if (JointVertical(j))
{ {
IncMvComponent(Row, ref counts.Value, 0, 1, 1); IncComponent(Row, ref counts.Value, 0, 1, 1);
} }
if (MvJointHorizontal(j)) if (JointHorizontal(j))
{ {
IncMvComponent(Col, ref counts.Value, 1, 1, 1); IncComponent(Col, ref counts.Value, 1, 1, 1);
} }
} }
} }
public void ClampMv(int minCol, int maxCol, int minRow, int maxRow) public void Clamp(int minCol, int maxCol, int minRow, int maxRow)
{ {
Col = (short)Math.Clamp(Col, minCol, maxCol); Col = (short)Math.Clamp(Col, minCol, maxCol);
Row = (short)Math.Clamp(Row, minRow, maxRow); Row = (short)Math.Clamp(Row, minRow, maxRow);
} }
private const int MvBorder = (16 << 3); // Allow 16 pels in 1/8th pel units private const int Border = 16 << 3; // Allow 16 pels in 1/8th pel units
public void ClampMvRef(ref MacroBlockD xd) public void ClampRef(ref MacroBlockD xd)
{ {
ClampMv( Clamp(
xd.MbToLeftEdge - MvBorder, xd.MbToLeftEdge - Border,
xd.MbToRightEdge + MvBorder, xd.MbToRightEdge + Border,
xd.MbToTopEdge - MvBorder, xd.MbToTopEdge - Border,
xd.MbToBottomEdge + MvBorder); xd.MbToBottomEdge + Border);
} }
public void LowerMvPrecision(bool allowHP) public void LowerPrecision(bool allowHp)
{ {
bool useHP = allowHP && UseMvHp(); bool useHp = allowHp && UseHp();
if (!useHP) if (!useHp)
{ {
if ((Row & 1) != 0) if ((Row & 1) != 0)
{ {
@ -185,5 +172,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
} }
} }
} }
public bool IsValid()
{
return Row is > Constants.MvLow and < Constants.MvUpp &&
Col is > Constants.MvLow and < Constants.MvUpp;
}
} }
} }

View file

@ -2,16 +2,16 @@
{ {
internal enum MvClassType internal enum MvClassType
{ {
MvClass0 = 0, /* (0, 2] integer pel */ Class0, /* (0, 2] integer pel */
MvClass1 = 1, /* (2, 4] integer pel */ Class1, /* (2, 4] integer pel */
MvClass2 = 2, /* (4, 8] integer pel */ Class2, /* (4, 8] integer pel */
MvClass3 = 3, /* (8, 16] integer pel */ Class3, /* (8, 16] integer pel */
MvClass4 = 4, /* (16, 32] integer pel */ Class4, /* (16, 32] integer pel */
MvClass5 = 5, /* (32, 64] integer pel */ Class5, /* (32, 64] integer pel */
MvClass6 = 6, /* (64, 128] integer pel */ Class6, /* (64, 128] integer pel */
MvClass7 = 7, /* (128, 256] integer pel */ Class7, /* (128, 256] integer pel */
MvClass8 = 8, /* (256, 512] integer pel */ Class8, /* (256, 512] integer pel */
MvClass9 = 9, /* (512, 1024] integer pel */ Class9, /* (512, 1024] integer pel */
MvClass10 = 10, /* (1024,2048] integer pel */ Class10 /* (1024,2048] integer pel */
} }
} }

View file

@ -2,9 +2,9 @@
{ {
internal enum MvJointType internal enum MvJointType
{ {
MvJointZero = 0, /* Zero vector */ Zero, /* Zero vector */
MvJointHnzvz = 1, /* Vert zero, hor nonzero */ Hnzvz, /* Vert zero, hor nonzero */
MvJointHzvnz = 2, /* Hor zero, vert nonzero */ Hzvnz, /* Hor zero, vert nonzero */
MvJointHnzvnz = 3, /* Both components nonzero */ Hnzvnz /* Both components nonzero */
} }
} }

View file

@ -2,8 +2,8 @@
{ {
internal enum PlaneType internal enum PlaneType
{ {
Y = 0, Y,
Uv = 1, Uv,
PlaneTypes PlaneTypes
} }
} }

View file

@ -2,20 +2,20 @@
{ {
internal enum PredictionMode internal enum PredictionMode
{ {
DcPred = 0, // Average of above and left pixels DcPred, // Average of above and left pixels
VPred = 1, // Vertical VPred, // Vertical
HPred = 2, // Horizontal HPred, // Horizontal
D45Pred = 3, // Directional 45 deg = round(arctan(1 / 1) * 180 / pi) D45Pred, // Directional 45 deg = round(arctan(1 / 1) * 180 / pi)
D135Pred = 4, // Directional 135 deg = 180 - 45 D135Pred, // Directional 135 deg = 180 - 45
D117Pred = 5, // Directional 117 deg = 180 - 63 D117Pred, // Directional 117 deg = 180 - 63
D153Pred = 6, // Directional 153 deg = 180 - 27 D153Pred, // Directional 153 deg = 180 - 27
D207Pred = 7, // Directional 207 deg = 180 + 27 D207Pred, // Directional 207 deg = 180 + 27
D63Pred = 8, // Directional 63 deg = round(arctan(2 / 1) * 180 / pi) D63Pred, // Directional 63 deg = round(arctan(2 / 1) * 180 / pi)
TmPred = 9, // True-motion TmPred, // True-motion
NearestMv = 10, NearestMv,
NearMv = 11, NearMv,
ZeroMv = 12, ZeroMv,
NewMv = 13, NewMv,
MbModeCount = 14 MbModeCount
} }
} }

View file

@ -2,6 +2,9 @@
{ {
internal struct RefBuffer internal struct RefBuffer
{ {
public const int InvalidIdx = -1; // Invalid buffer index.
public int Idx;
public Surface Buf; public Surface Buf;
public ScaleFactors Sf; public ScaleFactors Sf;
} }

View file

@ -0,0 +1,12 @@
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
{
internal struct RefCntBuffer
{
public int RefCount;
public int MiRows;
public int MiCols;
public byte Released;
public VpxCodecFrameBuffer RawFrameBuffer;
public Surface Buf;
}
}

View file

@ -2,9 +2,9 @@
{ {
internal enum ReferenceMode internal enum ReferenceMode
{ {
SingleReference = 0, Single,
CompoundReference = 1, Compound,
ReferenceModeSelect = 2, Select,
ReferenceModes = 3 ReferenceModes
} }
} }

View file

@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
internal struct ScaleFactors internal struct ScaleFactors
{ {
private const int RefScaleShift = 14; private const int RefScaleShift = 14;
private const int RefNoScale = (1 << RefScaleShift); private const int RefNoScale = 1 << RefScaleShift;
private const int RefInvalidScale = -1; private const int RefInvalidScale = -1;
private unsafe delegate void ConvolveFn( private unsafe delegate void ConvolveFn(
@ -38,248 +38,99 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
int h, int h,
int bd); int bd);
private static readonly unsafe ConvolveFn[][][] PredictX16Y16 = new ConvolveFn[][][] private static readonly unsafe ConvolveFn[][][] PredictX16Y16 =
{ {
new ConvolveFn[][] new[]
{ {
new ConvolveFn[] new ConvolveFn[] { ConvolveCopy, ConvolveAvg },
{ new ConvolveFn[] { Convolve8Vert, Convolve8AvgVert }
ConvolveCopy,
ConvolveAvg
}, },
new ConvolveFn[] new[]
{ {
Convolve8Vert, new ConvolveFn[] { Convolve8Horiz, Convolve8AvgHoriz },
Convolve8AvgVert new ConvolveFn[] { Convolve8, Convolve8Avg }
}
},
new ConvolveFn[][]
{
new ConvolveFn[]
{
Convolve8Horiz,
Convolve8AvgHoriz
},
new ConvolveFn[]
{
Convolve8,
Convolve8Avg
}
} }
}; };
private static readonly unsafe ConvolveFn[][][] PredictX16 = new ConvolveFn[][][] private static readonly unsafe ConvolveFn[][][] PredictX16 =
{ {
new ConvolveFn[][] new[]
{ {
new ConvolveFn[] new ConvolveFn[] { ScaledVert, ScaledAvgVert }, new ConvolveFn[] { ScaledVert, ScaledAvgVert }
{
ScaledVert,
ScaledAvgVert
}, },
new ConvolveFn[] new[] { new ConvolveFn[] { Scaled2D, ScaledAvg2D }, new ConvolveFn[] { Scaled2D, ScaledAvg2D } }
};
private static readonly unsafe ConvolveFn[][][] PredictY16 =
{ {
ScaledVert, new[] { new ConvolveFn[] { ScaledHoriz, ScaledAvgHoriz }, new ConvolveFn[] { Scaled2D, ScaledAvg2D } },
ScaledAvgVert new[] { new ConvolveFn[] { ScaledHoriz, ScaledAvgHoriz }, new ConvolveFn[] { Scaled2D, ScaledAvg2D } }
} };
private static readonly unsafe ConvolveFn[][][] Predict =
{
new[] { new ConvolveFn[] { Scaled2D, ScaledAvg2D }, new ConvolveFn[] { Scaled2D, ScaledAvg2D } },
new[] { new ConvolveFn[] { Scaled2D, ScaledAvg2D }, new ConvolveFn[] { Scaled2D, ScaledAvg2D } }
};
private static readonly unsafe HighbdConvolveFn[][][] HighbdPredictX16Y16 =
{
new[]
{
new HighbdConvolveFn[] { HighbdConvolveCopy, HighbdConvolveAvg },
new HighbdConvolveFn[] { HighbdConvolve8Vert, HighbdConvolve8AvgVert }
}, },
new ConvolveFn[][] new[]
{ {
new ConvolveFn[] new HighbdConvolveFn[] { HighbdConvolve8Horiz, HighbdConvolve8AvgHoriz },
{ new HighbdConvolveFn[] { HighbdConvolve8, HighbdConvolve8Avg }
Scaled2D,
ScaledAvg2D
},
new ConvolveFn[]
{
Scaled2D,
ScaledAvg2D
}
} }
}; };
private static readonly unsafe ConvolveFn[][][] PredictY16 = new ConvolveFn[][][] private static readonly unsafe HighbdConvolveFn[][][] HighbdPredictX16 =
{ {
new ConvolveFn[][] new[]
{ {
new ConvolveFn[] new HighbdConvolveFn[] { HighbdConvolve8Vert, HighbdConvolve8AvgVert },
{ new HighbdConvolveFn[] { HighbdConvolve8Vert, HighbdConvolve8AvgVert }
ScaledHoriz,
ScaledAvgHoriz
}, },
new ConvolveFn[] new[]
{ {
Scaled2D, new HighbdConvolveFn[] { HighbdConvolve8, HighbdConvolve8Avg },
ScaledAvg2D new HighbdConvolveFn[] { HighbdConvolve8, HighbdConvolve8Avg }
}
},
new ConvolveFn[][]
{
new ConvolveFn[]
{
ScaledHoriz,
ScaledAvgHoriz
},
new ConvolveFn[]
{
Scaled2D,
ScaledAvg2D
}
} }
}; };
private static readonly unsafe ConvolveFn[][][] Predict = new ConvolveFn[][][] private static readonly unsafe HighbdConvolveFn[][][] HighbdPredictY16 =
{ {
new ConvolveFn[][] new[]
{ {
new ConvolveFn[] new HighbdConvolveFn[] { HighbdConvolve8Horiz, HighbdConvolve8AvgHoriz },
{ new HighbdConvolveFn[] { HighbdConvolve8, HighbdConvolve8Avg }
Scaled2D,
ScaledAvg2D
}, },
new ConvolveFn[] new[]
{ {
Scaled2D, new HighbdConvolveFn[] { HighbdConvolve8Horiz, HighbdConvolve8AvgHoriz },
ScaledAvg2D new HighbdConvolveFn[] { HighbdConvolve8, HighbdConvolve8Avg }
}
},
new ConvolveFn[][]
{
new ConvolveFn[]
{
Scaled2D,
ScaledAvg2D
},
new ConvolveFn[]
{
Scaled2D,
ScaledAvg2D
}
} }
}; };
private static readonly unsafe HighbdConvolveFn[][][] HighbdPredictX16Y16 = new HighbdConvolveFn[][][] private static readonly unsafe HighbdConvolveFn[][][] HighbdPredict =
{ {
new HighbdConvolveFn[][] new[]
{ {
new HighbdConvolveFn[] new HighbdConvolveFn[] { HighbdConvolve8, HighbdConvolve8Avg },
{ new HighbdConvolveFn[] { HighbdConvolve8, HighbdConvolve8Avg }
HighbdConvolveCopy,
HighbdConvolveAvg
}, },
new HighbdConvolveFn[] new[]
{ {
HighbdConvolve8Vert, new HighbdConvolveFn[] { HighbdConvolve8, HighbdConvolve8Avg },
HighbdConvolve8AvgVert new HighbdConvolveFn[] { HighbdConvolve8, HighbdConvolve8Avg }
}
},
new HighbdConvolveFn[][]
{
new HighbdConvolveFn[]
{
HighbdConvolve8Horiz,
HighbdConvolve8AvgHoriz
},
new HighbdConvolveFn[]
{
HighbdConvolve8,
HighbdConvolve8Avg
}
} }
}; };
private static readonly unsafe HighbdConvolveFn[][][] HighbdPredictX16 = new HighbdConvolveFn[][][] public int XScaleFp; // Horizontal fixed point scale factor
{ public int YScaleFp; // Vertical fixed point scale factor
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 XStepQ4;
public int YStepQ4; public int YStepQ4;
@ -315,12 +166,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
if (YStepQ4 == 16) if (YStepQ4 == 16)
{ {
// No scaling in either direction. // No scaling in either direction.
PredictX16Y16[horiz][vert][avg](src, srcStride, dst, dstStride, kernel, subpelX, xs, subpelY, ys, w, h); PredictX16Y16[horiz][vert][avg](src, srcStride, dst, dstStride, kernel, subpelX, xs, subpelY, ys, w,
h);
} }
else else
{ {
// No scaling in x direction. Must always scale in the y direction. // 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); PredictX16[horiz][vert][avg](src, srcStride, dst, dstStride, kernel, subpelX, xs, subpelY, ys, w,
h);
} }
} }
else else
@ -328,7 +181,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
if (YStepQ4 == 16) if (YStepQ4 == 16)
{ {
// No scaling in the y direction. Must always scale in the x direction. // 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); PredictY16[horiz][vert][avg](src, srcStride, dst, dstStride, kernel, subpelX, xs, subpelY, ys, w,
h);
} }
else else
{ {
@ -361,12 +215,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
if (YStepQ4 == 16) if (YStepQ4 == 16)
{ {
// No scaling in either direction. // No scaling in either direction.
HighbdPredictX16Y16[horiz][vert][avg](src, srcStride, dst, dstStride, kernel, subpelX, xs, subpelY, ys, w, h, bd); HighbdPredictX16Y16[horiz][vert][avg](src, srcStride, dst, dstStride, kernel, subpelX, xs, subpelY,
ys, w, h, bd);
} }
else else
{ {
// No scaling in x direction. Must always scale in the y direction. // 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); HighbdPredictX16[horiz][vert][avg](src, srcStride, dst, dstStride, kernel, subpelX, xs, subpelY, ys,
w, h, bd);
} }
} }
else else
@ -374,24 +230,26 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
if (YStepQ4 == 16) if (YStepQ4 == 16)
{ {
// No scaling in the y direction. Must always scale in the x direction. // 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); HighbdPredictY16[horiz][vert][avg](src, srcStride, dst, dstStride, kernel, subpelX, xs, subpelY, ys,
w, h, bd);
} }
else else
{ {
// Must always scale in both directions. // Must always scale in both directions.
HighbdPredict[horiz][vert][avg](src, srcStride, dst, dstStride, kernel, subpelX, xs, subpelY, ys, w, h, bd); HighbdPredict[horiz][vert][avg](src, srcStride, dst, dstStride, kernel, subpelX, xs, subpelY, ys, w,
h, bd);
} }
} }
} }
private int ScaledX(int val) private int ScaledX(int val)
{ {
return (int)((long)val * XScaleFP >> RefScaleShift); return (int)(((long)val * XScaleFp) >> RefScaleShift);
} }
private int ScaledY(int val) private int ScaledY(int val)
{ {
return (int)((long)val * YScaleFP >> RefScaleShift); return (int)(((long)val * YScaleFp) >> RefScaleShift);
} }
private static int GetFixedPointScaleFactor(int otherSize, int thisSize) private static int GetFixedPointScaleFactor(int otherSize, int thisSize)
@ -407,22 +265,18 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
{ {
int xOffQ4 = ScaledX(x << SubpelBits) & SubpelMask; int xOffQ4 = ScaledX(x << SubpelBits) & SubpelMask;
int yOffQ4 = ScaledY(y << SubpelBits) & SubpelMask; int yOffQ4 = ScaledY(y << SubpelBits) & SubpelMask;
Mv32 res = new Mv32() Mv32 res = new() { Row = ScaledY(mv.Row) + yOffQ4, Col = ScaledX(mv.Col) + xOffQ4 };
{
Row = ScaledY(mv.Row) + yOffQ4,
Col = ScaledX(mv.Col) + xOffQ4
};
return res; return res;
} }
public bool IsValidScale() public bool IsValidScale()
{ {
return XScaleFP != RefInvalidScale && YScaleFP != RefInvalidScale; return XScaleFp != RefInvalidScale && YScaleFp != RefInvalidScale;
} }
public bool IsScaled() public bool IsScaled()
{ {
return IsValidScale() && (XScaleFP != RefNoScale || YScaleFP != RefNoScale); return IsValidScale() && (XScaleFp != RefNoScale || YScaleFp != RefNoScale);
} }
public static bool ValidRefFrameSize(int refWidth, int refHeight, int thisWidth, int thisHeight) public static bool ValidRefFrameSize(int refWidth, int refHeight, int thisWidth, int thisHeight)
@ -437,13 +291,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
{ {
if (!ValidRefFrameSize(otherW, otherH, thisW, thisH)) if (!ValidRefFrameSize(otherW, otherH, thisW, thisH))
{ {
XScaleFP = RefInvalidScale; XScaleFp = RefInvalidScale;
YScaleFP = RefInvalidScale; YScaleFp = RefInvalidScale;
return; return;
} }
XScaleFP = GetFixedPointScaleFactor(otherW, thisW); XScaleFp = GetFixedPointScaleFactor(otherW, thisW);
YScaleFP = GetFixedPointScaleFactor(otherH, thisH); YScaleFp = GetFixedPointScaleFactor(otherH, thisH);
XStepQ4 = ScaledX(16); XStepQ4 = ScaledX(16);
YStepQ4 = ScaledY(16); YStepQ4 = ScaledY(16);
} }

View file

@ -2,10 +2,10 @@
{ {
internal enum SegLvlFeatures internal enum SegLvlFeatures
{ {
SegLvlAltQ = 0, // Use alternate Quantizer .... AltQ, // Use alternate Quantizer ....
SegLvlAltLf = 1, // Use alternate loop filter value... AltLf, // Use alternate loop filter value...
SegLvlRefFrame = 2, // Optional Segment reference frame RefFrame, // Optional Segment reference frame
SegLvlSkip = 3, // Optional Segment (0,0) + skip mode Skip, // Optional Segment (0,0) + skip mode
SegLvlMax = 4 // Number of features supported Max // Number of features supported
} }
} }

View file

@ -1,4 +1,6 @@
using Ryujinx.Common.Memory; using Ryujinx.Common.Memory;
using Ryujinx.Graphics.Video;
using System;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -6,8 +8,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
{ {
internal struct Segmentation internal struct Segmentation
{ {
private static readonly int[] SegFeatureDataSigned = new int[] { 1, 1, 0, 0 }; public const int SegmentDeltadata = 0;
private static readonly int[] SegFeatureDataMax = new int[] { QuantCommon.MaxQ, Vp9.LoopFilter.MaxLoopFilter, 3, 0 }; public const int SegmentAbsdata = 1;
public const int MaxSegments = 8;
public const int SegTreeProbs = MaxSegments - 1;
public const int PredictionProbs = 3;
private static readonly int[] SegFeatureDataSigned = { 1, 1, 0, 0 };
private static readonly int[] SegFeatureDataMax = { QuantCommon.MaxQ, Vp9.LoopFilter.MaxLoopFilter, 3, 0 };
public bool Enabled; public bool Enabled;
public bool UpdateMap; public bool UpdateMap;
@ -26,8 +36,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
public void ClearAllSegFeatures() public void ClearAllSegFeatures()
{ {
MemoryMarshal.CreateSpan(ref FeatureData[0][0], 8 * 4).Fill(0); MemoryMarshal.CreateSpan(ref FeatureData[0][0], 8 * 4).Clear();
MemoryMarshal.CreateSpan(ref FeatureMask[0], 8).Fill(0); MemoryMarshal.CreateSpan(ref FeatureMask[0], 8).Clear();
AqAvOffset = 0; AqAvOffset = 0;
} }
@ -67,5 +77,88 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
{ {
return FeatureData[segmentId][(int)featureId]; return FeatureData[segmentId][(int)featureId];
} }
public int GetQIndex(int segmentId, int baseQIndex)
{
if (IsSegFeatureActive(segmentId, SegLvlFeatures.AltQ) != 0)
{
int data = GetSegData(segmentId, SegLvlFeatures.AltQ);
int segQIndex = AbsDelta == Constants.SegmentAbsData ? data : baseQIndex + data;
return Math.Clamp(segQIndex, 0, QuantCommon.MaxQ);
}
return baseQIndex;
}
public void SetupSegmentation(ref Vp9EntropyProbs fc, ref ReadBitBuffer rb)
{
UpdateMap = false;
UpdateData = 0;
Enabled = rb.ReadBit() != 0;
if (!Enabled)
{
return;
}
// Segmentation map update
UpdateMap = rb.ReadBit() != 0;
if (UpdateMap)
{
for (int i = 0; i < SegTreeProbs; i++)
{
fc.SegTreeProb[i] = rb.ReadBit() != 0
? (byte)rb.ReadLiteral(8)
: (byte)Prob.MaxProb;
}
TemporalUpdate = rb.ReadBit() != 0;
if (TemporalUpdate)
{
for (int i = 0; i < PredictionProbs; i++)
{
fc.SegPredProb[i] = rb.ReadBit() != 0
? (byte)rb.ReadLiteral(8)
: (byte)Prob.MaxProb;
}
}
else
{
for (int i = 0; i < PredictionProbs; i++)
{
fc.SegPredProb[i] = Prob.MaxProb;
}
}
}
// Segmentation data update
UpdateData = (byte)rb.ReadBit();
if (UpdateData != 0)
{
AbsDelta = (byte)rb.ReadBit();
ClearAllSegFeatures();
for (int i = 0; i < Constants.MaxSegments; i++)
{
for (int j = 0; j < (int)SegLvlFeatures.Max; j++)
{
int data = 0;
int featureEnabled = rb.ReadBit();
if (featureEnabled != 0)
{
EnableSegFeature(i, (SegLvlFeatures)j);
data = rb.DecodeUnsignedMax(FeatureDataMax((SegLvlFeatures)j));
if (IsSegFeatureSigned((SegLvlFeatures)j) != 0)
{
data = rb.ReadBit() != 0 ? -data : data;
}
}
SetSegData(i, (SegLvlFeatures)j, data);
}
}
}
}
} }
} }

View file

@ -1,33 +1,66 @@
using Ryujinx.Common.Memory; using Ryujinx.Common.Memory;
using Ryujinx.Graphics.Nvdec.Vp9.Common;
using Ryujinx.Graphics.Video; using Ryujinx.Graphics.Video;
using System; using System;
using System.Diagnostics;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Nvdec.Vp9.Types namespace Ryujinx.Graphics.Nvdec.Vp9.Types
{ {
internal delegate int VpxGetFrameBufferCbFnT(MemoryAllocator allocator, Ptr<InternalFrameBufferList> cbPriv,
ulong minSize, ref VpxCodecFrameBuffer fb);
internal struct Surface : ISurface internal struct Surface : ISurface
{ {
public const int Innerborderinpixels = 96;
public const int InterpExtend = 4;
public const int EncBorderInPixels = 160;
public const int DecBorderInPixels = 32;
public const int Yv12FlagHighbitdepth = 8;
public ArrayPtr<byte> YBuffer; public ArrayPtr<byte> YBuffer;
public ArrayPtr<byte> UBuffer; public ArrayPtr<byte> UBuffer;
public ArrayPtr<byte> VBuffer; public ArrayPtr<byte> VBuffer;
public unsafe Plane YPlane => new Plane((IntPtr)YBuffer.ToPointer(), YBuffer.Length); public unsafe Plane YPlane => new((IntPtr)YBuffer.ToPointer(), YBuffer.Length);
public unsafe Plane UPlane => new Plane((IntPtr)UBuffer.ToPointer(), UBuffer.Length); public unsafe Plane UPlane => new((IntPtr)UBuffer.ToPointer(), UBuffer.Length);
public unsafe Plane VPlane => new Plane((IntPtr)VBuffer.ToPointer(), VBuffer.Length); public unsafe Plane VPlane => new((IntPtr)VBuffer.ToPointer(), VBuffer.Length);
public FrameField Field => FrameField.Progressive; public FrameField Field => FrameField.Progressive;
public int Width { get; } public int Width { get; private set; }
public int Height { get; } public int Height { get; private set; }
public int AlignedWidth { get; } public int AlignedWidth { get; private set; }
public int AlignedHeight { get; } public int AlignedHeight { get; private set; }
public int Stride { get; } public int Stride { get; private set; }
public int UvWidth { get; } public int UvWidth { get; private set; }
public int UvHeight { get; } public int UvHeight { get; private set; }
public int UvAlignedWidth { get; } public int UvAlignedWidth { get; private set; }
public int UvAlignedHeight { get; } public int UvAlignedHeight { get; private set; }
public int UvStride { get; } public int UvStride { get; private set; }
public bool HighBd => false; public bool HighBd { get; private set; }
public int FrameSize { get; private set; }
public int Border { get; private set; }
public int YCropWidth => Width;
public int YCropHeight => Height;
public int UvCropWidth => UvWidth;
public int UvCropHeight => UvHeight;
public ArrayPtr<byte> BufferAlloc;
public int BufferAllocSz;
public int SubsamplingX;
public int SubsamplingY;
public uint BitDepth;
public VpxColorSpace ColorSpace;
public VpxColorRange ColorRange;
public int RenderWidth;
public int RenderHeight;
public int Corrupted;
public int Flags;
private readonly IntPtr _pointer; private readonly IntPtr _pointer;
@ -40,16 +73,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
int alignedWidth = (width + 7) & ~7; int alignedWidth = (width + 7) & ~7;
int alignedHeight = (height + 7) & ~7; int alignedHeight = (height + 7) & ~7;
int yStride = ((alignedWidth + 2 * border) + 31) & ~31; int yStride = (alignedWidth + (2 * border) + 31) & ~31;
int yplaneSize = (alignedHeight + 2 * border) * yStride; int yplaneSize = (alignedHeight + (2 * border)) * yStride;
int uvWidth = alignedWidth >> ssX; int uvWidth = alignedWidth >> ssX;
int uvHeight = alignedHeight >> ssY; int uvHeight = alignedHeight >> ssY;
int uvStride = yStride >> ssX; int uvStride = yStride >> ssX;
int uvBorderW = border >> ssX; int uvBorderW = border >> ssX;
int uvBorderH = border >> ssY; int uvBorderH = border >> ssY;
int uvplaneSize = (uvHeight + 2 * uvBorderH) * uvStride; int uvplaneSize = (uvHeight + (2 * uvBorderH)) * uvStride;
int frameSize = (highbd ? 2 : 1) * (yplaneSize + 2 * uvplaneSize); int frameSize = (highbd ? 2 : 1) * (yplaneSize + (2 * uvplaneSize));
IntPtr pointer = Marshal.AllocHGlobal(frameSize); IntPtr pointer = Marshal.AllocHGlobal(frameSize);
_pointer = pointer; _pointer = pointer;
@ -74,6 +107,131 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
VBuffer = NewPlane(yplaneSize + uvplaneSize, uvplaneSize, (uvBorderH * uvStride) + uvBorderW); VBuffer = NewPlane(yplaneSize + uvplaneSize, uvplaneSize, (uvBorderH * uvStride) + uvBorderW);
} }
public unsafe int ReallocFrameBuffer(
MemoryAllocator allocator,
int width,
int height,
int ssX,
int ssY,
bool useHighbitdepth,
int border,
int byteAlignment,
Ptr<VpxCodecFrameBuffer> fb,
VpxGetFrameBufferCbFnT cb,
Ptr<InternalFrameBufferList> cbPriv)
{
int byteAlign = byteAlignment == 0 ? 1 : byteAlignment; // TODO: Is it safe to ignore the alignment?
int alignedWidth = (width + 7) & ~7;
int alignedHeight = (height + 7) & ~7;
int yStride = (alignedWidth + (2 * border) + 31) & ~31;
ulong yplaneSize =
((ulong)(alignedHeight + (2 * border)) * (ulong)yStride) + (ulong)byteAlignment;
int uvWidth = alignedWidth >> ssX;
int uvHeight = alignedHeight >> ssY;
int uvStride = yStride >> ssX;
int uvBorderW = border >> ssX;
int uvBorderH = border >> ssY;
ulong uvplaneSize =
((ulong)(uvHeight + (2 * uvBorderH)) * (ulong)uvStride) + (ulong)byteAlignment;
ulong frameSize = (ulong)(1 + (useHighbitdepth ? 1 : 0)) * (yplaneSize + (2 * uvplaneSize));
ArrayPtr<byte> buf = ArrayPtr<byte>.Null;
// frame_size is stored in buffer_alloc_sz, which is an int. If it won't
// fit, fail early.
if (frameSize > int.MaxValue)
{
return -1;
}
if (cb != null)
{
const int alignAddrExtraSize = 31;
ulong externalFrameSize = frameSize + alignAddrExtraSize;
Debug.Assert(!fb.IsNull);
// Allocation to hold larger frame, or first allocation.
if (cb(allocator, cbPriv, externalFrameSize, ref fb.Value) < 0)
{
return -1;
}
if (fb.Value.Data.IsNull || (ulong)fb.Value.Data.Length < externalFrameSize)
{
return -1;
}
BufferAlloc = fb.Value.Data;
}
else if (frameSize > (ulong)BufferAllocSz)
{
// Allocation to hold larger frame, or first allocation.
allocator.Free(BufferAlloc);
BufferAlloc = ArrayPtr<byte>.Null;
BufferAlloc = allocator.Allocate<byte>((int)frameSize);
if (BufferAlloc.IsNull)
{
return -1;
}
BufferAllocSz = (int)frameSize;
// This memset is needed for fixing valgrind error from C loop filter
// due to access uninitialized memory in frame border. It could be
// removed if border is totally removed.
MemoryUtil.Fill(BufferAlloc.ToPointer(), (byte)0, BufferAllocSz);
}
/* Only support allocating buffers that have a border that's a multiple
* of 32. The border restriction is required to get 16-byte alignment of
* the start of the chroma rows without introducing an arbitrary gap
* between planes, which would break the semantics of things like
* vpx_img_set_rect(). */
if ((border & 0x1f) != 0)
{
return -3;
}
Width = width;
Height = height;
AlignedWidth = alignedWidth;
AlignedHeight = alignedHeight;
Stride = yStride;
UvWidth = (width + ssX) >> ssX;
UvHeight = (height + ssY) >> ssY;
UvAlignedWidth = uvWidth;
UvAlignedHeight = uvHeight;
UvStride = uvStride;
Border = border;
FrameSize = (int)frameSize;
SubsamplingX = ssX;
SubsamplingY = ssY;
buf = BufferAlloc;
if (useHighbitdepth)
{
// Store uint16 addresses when using 16bit framebuffers
buf = BufferAlloc;
Flags = Yv12FlagHighbitdepth;
}
else
{
Flags = 0;
}
YBuffer = buf.Slice((border * yStride) + border);
UBuffer = buf.Slice((int)yplaneSize + (uvBorderH * uvStride) + uvBorderW);
VBuffer = buf.Slice((int)yplaneSize + (int)uvplaneSize + (uvBorderH * uvStride) + uvBorderW);
Corrupted = 0; /* assume not corrupted by errors */
return 0;
}
public void Dispose() public void Dispose()
{ {
Marshal.FreeHGlobal(_pointer); Marshal.FreeHGlobal(_pointer);

View file

@ -55,7 +55,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
private static int GetMinLog2TileCols(int sb64Cols) private static int GetMinLog2TileCols(int sb64Cols)
{ {
int minLog2 = 0; int minLog2 = 0;
while ((MaxTileWidthB64 << minLog2) < sb64Cols) while (MaxTileWidthB64 << minLog2 < sb64Cols)
{ {
++minLog2; ++minLog2;
} }
@ -66,7 +66,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
private static int GetMaxLog2TileCols(int sb64Cols) private static int GetMaxLog2TileCols(int sb64Cols)
{ {
int maxLog2 = 1; int maxLog2 = 1;
while ((sb64Cols >> maxLog2) >= MinTileWidthB64) while (sb64Cols >> maxLog2 >= MinTileWidthB64)
{ {
++maxLog2; ++maxLog2;
} }
@ -74,7 +74,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
return maxLog2 - 1; return maxLog2 - 1;
} }
public static void GetTileNBits(int miCols, ref int minLog2TileCols, ref int maxLog2TileCols) public static void GetTileNBits(int miCols, out int minLog2TileCols, out int maxLog2TileCols)
{ {
int sb64Cols = MiColsAlignedToSb(miCols) >> Constants.MiBlockSizeLog2; int sb64Cols = MiColsAlignedToSb(miCols) >> Constants.MiBlockSizeLog2;
minLog2TileCols = GetMinLog2TileCols(sb64Cols); minLog2TileCols = GetMinLog2TileCols(sb64Cols);

View file

@ -2,11 +2,11 @@
{ {
public enum TxMode public enum TxMode
{ {
Only4X4 = 0, // Only 4x4 transform used Only4x4, // Only 4x4 transform used
Allow8X8 = 1, // Allow block transform size up to 8x8 Allow8x8, // Allow block transform size up to 8x8
Allow16X16 = 2, // Allow block transform size up to 16x16 Allow16x16, // Allow block transform size up to 16x16
Allow32X32 = 3, // Allow block transform size up to 32x32 Allow32x32, // Allow block transform size up to 32x32
TxModeSelect = 4, // Transform specified for each block TxModeSelect, // Transform specified for each block
TxModes = 5 TxModes
} }
} }

View file

@ -2,10 +2,10 @@
{ {
public enum TxSize public enum TxSize
{ {
Tx4x4 = 0, // 4x4 transform Tx4x4, // 4x4 transform
Tx8x8 = 1, // 8x8 transform Tx8x8, // 8x8 transform
Tx16x16 = 2, // 16x16 transform Tx16x16, // 16x16 transform
Tx32x32 = 3, // 32x32 transform Tx32x32, // 32x32 transform
TxSizes = 4 TxSizes
} }
} }

View file

@ -2,10 +2,10 @@
{ {
internal enum TxType internal enum TxType
{ {
DctDct = 0, // DCT in both horizontal and vertical DctDct, // DCT in both horizontal and vertical
AdstDct = 1, // ADST in vertical, DCT in horizontal AdstDct, // ADST in vertical, DCT in horizontal
DctAdst = 2, // DCT in vertical, ADST in horizontal DctAdst, // DCT in vertical, ADST in horizontal
AdstAdst = 3, // ADST in both directions AdstAdst, // ADST in both directions
TxTypes = 4 TxTypes
} }
} }

View file

@ -1,6 +1,8 @@
using Ryujinx.Common.Memory; using Ryujinx.Common.Memory;
using Ryujinx.Graphics.Nvdec.Vp9.Common; using Ryujinx.Graphics.Nvdec.Vp9.Common;
using Ryujinx.Graphics.Nvdec.Vp9.Dsp;
using Ryujinx.Graphics.Video; using Ryujinx.Graphics.Video;
using System;
namespace Ryujinx.Graphics.Nvdec.Vp9.Types namespace Ryujinx.Graphics.Nvdec.Vp9.Types
{ {
@ -9,27 +11,62 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
public MacroBlockD Mb; public MacroBlockD Mb;
public ArrayPtr<TileWorkerData> TileWorkerData; public ArrayPtr<TileWorkerData> TileWorkerData;
public int TotalTiles;
public InternalErrorInfo Error; public InternalErrorInfo Error;
public VpxColorSpace ColorSpace;
public VpxColorRange ColorRange;
public int Width; public int Width;
public int Height; public int Height;
public int RenderWidth;
public int RenderHeight;
public int LastWidth;
public int LastHeight;
public int SubsamplingX; public int SubsamplingX;
public int SubsamplingY; public int SubsamplingY;
public bool UseHighBitDepth;
public ArrayPtr<MvRef> PrevFrameMvs; public ArrayPtr<MvRef> PrevFrameMvs;
public ArrayPtr<MvRef> CurFrameMvs; public ArrayPtr<MvRef> CurFrameMvs;
public Ptr<Surface> FrameToShow;
public Ptr<RefCntBuffer> PrevFrame;
public Ptr<RefCntBuffer> CurFrame;
public Array8<int> RefFrameMap; /* maps fb_idx to reference slot */
// Prepare ref_frame_map for the next frame.
// Only used in frame parallel decode.
public Array8<int> NextRefFrameMap;
public Array3<RefBuffer> FrameRefs; public Array3<RefBuffer> FrameRefs;
public int NewFbIdx;
public int CurShowFrameFbIdx;
public FrameType LastFrameType;
public FrameType FrameType; public FrameType FrameType;
public int ShowFrame;
public int LastShowFrame;
public int ShowExistingFrame;
// Flag signaling that the frame is encoded using only Intra modes. // Flag signaling that the frame is encoded using only Intra modes.
public bool IntraOnly; public bool IntraOnly;
public bool LastIntraOnly;
public bool AllowHighPrecisionMv; public bool AllowHighPrecisionMv;
public int ResetFrameContext;
// MBs, MbRows/Cols is in 16-pixel units; MiRows/Cols is in // MBs, MbRows/Cols is in 16-pixel units; MiRows/Cols is in
// ModeInfo (8-pixel) units. // ModeInfo (8-pixel) units.
public int MBs; public int MBs;
@ -49,9 +86,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
/* We allocate a ModeInfo struct for each macroblock, together with /* We allocate a ModeInfo struct for each macroblock, together with
an extra row on top and column on the left to simplify prediction. */ an extra row on top and column on the left to simplify prediction. */
public int MiAllocSize;
public ArrayPtr<ModeInfo> Mip; /* Base of allocated array */ public ArrayPtr<ModeInfo> Mip; /* Base of allocated array */
public ArrayPtr<ModeInfo> Mi; /* Corresponds to upper left visible macroblock */ public ArrayPtr<ModeInfo> Mi; /* Corresponds to upper left visible macroblock */
// prev_mip and prev_mi will only be allocated in VP9 encoder.
public Ptr<ModeInfo> PrevMip; /* MODE_INFO array 'mip' from last decoded frame */
public Ptr<ModeInfo> PrevMi; /* 'mi' from last frame (points into prev_mip) */
public ArrayPtr<Ptr<ModeInfo>> MiGridBase; public ArrayPtr<Ptr<ModeInfo>> MiGridBase;
public ArrayPtr<Ptr<ModeInfo>> MiGridVisible; public ArrayPtr<Ptr<ModeInfo>> MiGridVisible;
@ -70,6 +112,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
public LoopFilterInfoN LfInfo; public LoopFilterInfoN LfInfo;
public int RefreshFrameContext; /* Two state 0 = NO, 1 = YES */
public Array4<sbyte> RefFrameSignBias; /* Two state 0, 1 */ public Array4<sbyte> RefFrameSignBias; /* Two state 0, 1 */
public LoopFilter Lf; public LoopFilter Lf;
@ -81,10 +125,26 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
public ReferenceMode ReferenceMode; public ReferenceMode ReferenceMode;
public Ptr<Vp9EntropyProbs> Fc; public Ptr<Vp9EntropyProbs> Fc;
public ArrayPtr<Vp9EntropyProbs> FrameContexts; // FRAME_CONTEXTS
public uint FrameContextIdx; /* Context to use/update */
public Ptr<Vp9BackwardUpdates> Counts; public Ptr<Vp9BackwardUpdates> Counts;
public uint CurrentVideoFrame;
public BitstreamProfile Profile;
public BitDepth BitDepth;
public BitDepth DequantBitDepth; // bit_depth of current dequantizer
public int ErrorResilientMode;
public int FrameParallelDecodingMode;
public int Log2TileCols, Log2TileRows; public int Log2TileCols, Log2TileRows;
public int ByteAlignment;
public int SkipLoopFilter;
public Ptr<BufferPool> BufferPool;
public ArrayPtr<sbyte> AboveSegContext; public ArrayPtr<sbyte> AboveSegContext;
public ArrayPtr<sbyte> AboveContext; public ArrayPtr<sbyte> AboveContext;
@ -95,8 +155,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
public bool CompoundReferenceAllowed() public bool CompoundReferenceAllowed()
{ {
int i; for (int i = 1; i < Constants.RefsPerFrame; ++i)
for (i = 1; i < Constants.RefsPerFrame; ++i)
{ {
if (RefFrameSignBias[i + 1] != RefFrameSignBias[1]) if (RefFrameSignBias[i + 1] != RefFrameSignBias[1])
{ {
@ -107,6 +166,47 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
return false; return false;
} }
public ref Surface GetFrameNewBuffer()
{
return ref BufferPool.Value.FrameBufs[NewFbIdx].Buf;
}
public int GetFreeFb()
{
ref Array12<RefCntBuffer> frameBufs = ref BufferPool.Value.FrameBufs;
int i;
for (i = 0; i < Constants.FrameBuffers; ++i)
{
if (frameBufs[i].RefCount == 0)
{
break;
}
}
if (i != Constants.FrameBuffers)
{
frameBufs[i].RefCount = 1;
}
else
{
// Reset i to be INVALID_IDX to indicate no free buffer found.
i = RefBuffer.InvalidIdx;
}
return i;
}
public void SwapCurrentAndLastSegMap()
{
// Swap indices.
(SegMapIdx, PrevSegMapIdx) = (PrevSegMapIdx, SegMapIdx);
CurrentFrameSegMap = SegMapArray[SegMapIdx];
LastFrameSegMap = SegMapArray[PrevSegMapIdx];
}
private static int CalcMiSize(int len) private static int CalcMiSize(int len)
{ {
// Len is in mi units. // Len is in mi units.
@ -129,7 +229,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
public void AllocTileWorkerData(MemoryAllocator allocator, int tileCols, int tileRows, int maxThreads) public void AllocTileWorkerData(MemoryAllocator allocator, int tileCols, int tileRows, int maxThreads)
{ {
TileWorkerData = allocator.Allocate<TileWorkerData>(tileCols * tileRows + (maxThreads > 1 ? maxThreads : 0)); TileWorkerData =
allocator.Allocate<TileWorkerData>((tileCols * tileRows) + (maxThreads > 1 ? maxThreads : 0));
} }
public void FreeTileWorkerData(MemoryAllocator allocator) public void FreeTileWorkerData(MemoryAllocator allocator)
@ -139,9 +240,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
private void AllocSegMap(MemoryAllocator allocator, int segMapSize) private void AllocSegMap(MemoryAllocator allocator, int segMapSize)
{ {
int i; for (int i = 0; i < Constants.NumPingPongBuffers; ++i)
for (i = 0; i < Constants.NumPingPongBuffers; ++i)
{ {
SegMapArray[i] = allocator.Allocate<byte>(segMapSize); SegMapArray[i] = allocator.Allocate<byte>(segMapSize);
} }
@ -156,9 +255,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
private void FreeSegMap(MemoryAllocator allocator) private void FreeSegMap(MemoryAllocator allocator)
{ {
int i; for (int i = 0; i < Constants.NumPingPongBuffers; ++i)
for (i = 0; i < Constants.NumPingPongBuffers; ++i)
{ {
allocator.Free(SegMapArray[i]); allocator.Free(SegMapArray[i]);
SegMapArray[i] = ArrayPtr<byte>.Null; SegMapArray[i] = ArrayPtr<byte>.Null;
@ -194,6 +291,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
Lf.Lfm = ArrayPtr<LoopFilterMask>.Null; Lf.Lfm = ArrayPtr<LoopFilterMask>.Null;
allocator.Free(CurFrameMvs); allocator.Free(CurFrameMvs);
CurFrameMvs = ArrayPtr<MvRef>.Null; CurFrameMvs = ArrayPtr<MvRef>.Null;
if (UsePrevFrameMvs) if (UsePrevFrameMvs)
{ {
allocator.Free(PrevFrameMvs); allocator.Free(PrevFrameMvs);
@ -209,7 +307,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
Lf.Lfm = allocator.Allocate<LoopFilterMask>(((MiRows + (Constants.MiBlockSize - 1)) >> 3) * Lf.LfmStride); Lf.Lfm = allocator.Allocate<LoopFilterMask>(((MiRows + (Constants.MiBlockSize - 1)) >> 3) * Lf.LfmStride);
} }
public void AllocContextBuffers(MemoryAllocator allocator, int width, int height) public bool AllocContextBuffers(MemoryAllocator allocator, int width, int height)
{ {
SetMbMi(width, height); SetMbMi(width, height);
int newMiSize = MiStride * CalcMiSize(MiRows); int newMiSize = MiStride * CalcMiSize(MiRows);
@ -239,6 +337,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
{ {
PrevFrameMvs = allocator.Allocate<MvRef>(MiRows * MiCols); PrevFrameMvs = allocator.Allocate<MvRef>(MiRows * MiCols);
} }
return false;
} }
private unsafe void DecSetupMi() private unsafe void DecSetupMi()
@ -266,9 +366,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
internal void InitMacroBlockD(ref MacroBlockD xd, ArrayPtr<int> dqcoeff) internal void InitMacroBlockD(ref MacroBlockD xd, ArrayPtr<int> dqcoeff)
{ {
int i; for (int i = 0; i < Constants.MaxMbPlane; ++i)
for (i = 0; i < Constants.MaxMbPlane; ++i)
{ {
xd.Plane[i].DqCoeff = dqcoeff; xd.Plane[i].DqCoeff = dqcoeff;
xd.AboveContext[i] = AboveContext.Slice(i * 2 * TileInfo.MiColsAlignedToSb(MiCols)); xd.AboveContext[i] = AboveContext.Slice(i * 2 * TileInfo.MiColsAlignedToSb(MiCols));
@ -281,6 +379,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
{ {
MemoryUtil.Copy(ref xd.Plane[i].SegDequant, ref UvDequant); MemoryUtil.Copy(ref xd.Plane[i].SegDequant, ref UvDequant);
} }
xd.Fc = new Ptr<Vp9EntropyProbs>(ref Fc.Value); xd.Fc = new Ptr<Vp9EntropyProbs>(ref Fc.Value);
} }
@ -293,29 +392,27 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
public void SetupSegmentationDequant() public void SetupSegmentationDequant()
{ {
const BitDepth bitDepth = BitDepth.Bits8; // TODO: Configurable
// Build y/uv dequant values based on segmentation. // Build y/uv dequant values based on segmentation.
if (Seg.Enabled) if (Seg.Enabled)
{ {
int i; for (int i = 0; i < Constants.MaxSegments; ++i)
for (i = 0; i < Constants.MaxSegments; ++i)
{ {
int qIndex = QuantCommon.GetQIndex(ref Seg, i, BaseQindex); int qindex = Seg.GetQIndex(i, BaseQindex);
YDequant[i][0] = QuantCommon.DcQuant(qIndex, YDcDeltaQ, bitDepth); YDequant[i][0] = QuantCommon.DcQuant(qindex, YDcDeltaQ, BitDepth);
YDequant[i][1] = QuantCommon.AcQuant(qIndex, 0, bitDepth); YDequant[i][1] = QuantCommon.AcQuant(qindex, 0, BitDepth);
UvDequant[i][0] = QuantCommon.DcQuant(qIndex, UvDcDeltaQ, bitDepth); UvDequant[i][0] = QuantCommon.DcQuant(qindex, UvDcDeltaQ, BitDepth);
UvDequant[i][1] = QuantCommon.AcQuant(qIndex, UvAcDeltaQ, bitDepth); UvDequant[i][1] = QuantCommon.AcQuant(qindex, UvAcDeltaQ, BitDepth);
} }
} }
else else
{ {
int qIndex = BaseQindex; int qindex = BaseQindex;
// When segmentation is disabled, only the first value is used. The // When segmentation is disabled, only the first value is used. The
// remaining are don't cares. // remaining are don't cares.
YDequant[0][0] = QuantCommon.DcQuant(qIndex, YDcDeltaQ, bitDepth); YDequant[0][0] = QuantCommon.DcQuant(qindex, YDcDeltaQ, BitDepth);
YDequant[0][1] = QuantCommon.AcQuant(qIndex, 0, bitDepth); YDequant[0][1] = QuantCommon.AcQuant(qindex, 0, BitDepth);
UvDequant[0][0] = QuantCommon.DcQuant(qIndex, UvDcDeltaQ, bitDepth); UvDequant[0][0] = QuantCommon.DcQuant(qindex, UvDcDeltaQ, BitDepth);
UvDequant[0][1] = QuantCommon.AcQuant(qIndex, UvAcDeltaQ, bitDepth); UvDequant[0][1] = QuantCommon.AcQuant(qindex, UvAcDeltaQ, BitDepth);
} }
} }
@ -327,5 +424,576 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
refBuf.Sf.SetupScaleFactorsForFrame(refBuf.Buf.Width, refBuf.Buf.Height, Width, Height); refBuf.Sf.SetupScaleFactorsForFrame(refBuf.Buf.Width, refBuf.Buf.Height, Width, Height);
} }
} }
public void ReadFrameReferenceModeProbs(ref Reader r)
{
ref Vp9EntropyProbs fc = ref Fc.Value;
if (ReferenceMode == ReferenceMode.Select)
{
for (int i = 0; i < Constants.CompInterContexts; ++i)
{
r.DiffUpdateProb(ref fc.CompInterProb[i]);
}
}
if (ReferenceMode != ReferenceMode.Compound)
{
for (int i = 0; i < Constants.RefContexts; ++i)
{
r.DiffUpdateProb(ref fc.SingleRefProb[i][0]);
r.DiffUpdateProb(ref fc.SingleRefProb[i][1]);
}
}
if (ReferenceMode != ReferenceMode.Single)
{
for (int i = 0; i < Constants.RefContexts; ++i)
{
r.DiffUpdateProb(ref fc.CompRefProb[i]);
}
}
}
public ReferenceMode ReadFrameReferenceMode(ref Reader r)
{
if (CompoundReferenceAllowed())
{
return r.ReadBit() != 0
? r.ReadBit() != 0 ? ReferenceMode.Select : ReferenceMode.Compound
: ReferenceMode.Single;
}
return ReferenceMode.Single;
}
public void SetupCompoundReferenceMode()
{
if (RefFrameSignBias[Constants.LastFrame] == RefFrameSignBias[Constants.GoldenFrame])
{
CompFixedRef = Constants.AltRefFrame;
CompVarRef[0] = Constants.LastFrame;
CompVarRef[1] = Constants.GoldenFrame;
}
else if (RefFrameSignBias[Constants.LastFrame] == RefFrameSignBias[Constants.AltRefFrame])
{
CompFixedRef = Constants.GoldenFrame;
CompVarRef[0] = Constants.LastFrame;
CompVarRef[1] = Constants.AltRefFrame;
}
else
{
CompFixedRef = Constants.LastFrame;
CompVarRef[0] = Constants.GoldenFrame;
CompVarRef[1] = Constants.AltRefFrame;
}
}
public void InitMvProbs()
{
Fc.Value.Joints[0] = 32;
Fc.Value.Joints[1] = 64;
Fc.Value.Joints[2] = 96;
Fc.Value.Sign[0] = 128;
Fc.Value.Classes[0][0] = 224;
Fc.Value.Classes[0][1] = 144;
Fc.Value.Classes[0][2] = 192;
Fc.Value.Classes[0][3] = 168;
Fc.Value.Classes[0][4] = 192;
Fc.Value.Classes[0][5] = 176;
Fc.Value.Classes[0][6] = 192;
Fc.Value.Classes[0][7] = 198;
Fc.Value.Classes[0][8] = 198;
Fc.Value.Classes[0][9] = 245;
Fc.Value.Class0[0][0] = 216;
Fc.Value.Bits[0][0] = 136;
Fc.Value.Bits[0][1] = 140;
Fc.Value.Bits[0][2] = 148;
Fc.Value.Bits[0][3] = 160;
Fc.Value.Bits[0][4] = 176;
Fc.Value.Bits[0][5] = 192;
Fc.Value.Bits[0][6] = 224;
Fc.Value.Bits[0][7] = 234;
Fc.Value.Bits[0][8] = 234;
Fc.Value.Bits[0][9] = 240;
Fc.Value.Class0Fp[0][0][0] = 128;
Fc.Value.Class0Fp[0][0][1] = 128;
Fc.Value.Class0Fp[0][0][2] = 64;
Fc.Value.Class0Fp[0][1][0] = 96;
Fc.Value.Class0Fp[0][1][1] = 112;
Fc.Value.Class0Fp[0][1][2] = 64;
Fc.Value.Fp[0][0] = 64;
Fc.Value.Fp[0][1] = 96;
Fc.Value.Fp[0][2] = 64;
Fc.Value.Class0Hp[0] = 160;
Fc.Value.Hp[0] = 128;
Fc.Value.Sign[1] = 128;
Fc.Value.Classes[1][0] = 216;
Fc.Value.Classes[1][1] = 128;
Fc.Value.Classes[1][2] = 176;
Fc.Value.Classes[1][3] = 160;
Fc.Value.Classes[1][4] = 176;
Fc.Value.Classes[1][5] = 176;
Fc.Value.Classes[1][6] = 192;
Fc.Value.Classes[1][7] = 198;
Fc.Value.Classes[1][8] = 198;
Fc.Value.Classes[1][9] = 208;
Fc.Value.Class0[1][0] = 208;
Fc.Value.Bits[1][0] = 136;
Fc.Value.Bits[1][1] = 140;
Fc.Value.Bits[1][2] = 148;
Fc.Value.Bits[1][3] = 160;
Fc.Value.Bits[1][4] = 176;
Fc.Value.Bits[1][5] = 192;
Fc.Value.Bits[1][6] = 224;
Fc.Value.Bits[1][7] = 234;
Fc.Value.Bits[1][8] = 234;
Fc.Value.Bits[1][9] = 240;
Fc.Value.Class0Fp[1][0][0] = 128;
Fc.Value.Class0Fp[1][0][1] = 128;
Fc.Value.Class0Fp[1][0][2] = 64;
Fc.Value.Class0Fp[1][1][0] = 96;
Fc.Value.Class0Fp[1][1][1] = 112;
Fc.Value.Class0Fp[1][1][2] = 64;
Fc.Value.Fp[1][0] = 64;
Fc.Value.Fp[1][1] = 96;
Fc.Value.Fp[1][2] = 64;
Fc.Value.Class0Hp[1] = 160;
Fc.Value.Hp[1] = 128;
}
public void AdaptMvProbs(bool allowHp)
{
ref Vp9EntropyProbs fc = ref Fc.Value;
ref Vp9EntropyProbs preFc = ref FrameContexts[(int)FrameContextIdx];
ref Vp9BackwardUpdates counts = ref Counts.Value;
Prob.VpxTreeMergeProbs(
EntropyMv.JointTree,
preFc.Joints.AsSpan(),
counts.Joints.AsSpan(),
fc.Joints.AsSpan());
for (int i = 0; i < 2; ++i)
{
fc.Sign[i] = Prob.ModeMvMergeProbs(preFc.Sign[i], ref counts.Sign[i]);
Prob.VpxTreeMergeProbs(
EntropyMv.ClassTree,
preFc.Classes[i].AsSpan(),
counts.Classes[i].AsSpan(),
fc.Classes[i].AsSpan());
Prob.VpxTreeMergeProbs(
EntropyMv.Class0Tree,
preFc.Class0[i].AsSpan(),
counts.Class0[i].AsSpan(),
fc.Class0[i].AsSpan());
for (int j = 0; j < EntropyMv.OffsetBits; ++j)
{
fc.Bits[i][j] = Prob.ModeMvMergeProbs(preFc.Bits[i][j], ref counts.Bits[i][j]);
}
for (int j = 0; j < EntropyMv.Class0Size; ++j)
{
Prob.VpxTreeMergeProbs(
EntropyMv.FpTree,
preFc.Class0Fp[i][j].AsSpan(),
counts.Class0Fp[i][j].AsSpan(),
fc.Class0Fp[i][j].AsSpan());
}
Prob.VpxTreeMergeProbs(EntropyMv.FpTree, preFc.Fp[i].AsSpan(), counts.Fp[i].AsSpan(),
fc.Fp[i].AsSpan());
if (allowHp)
{
fc.Class0Hp[i] = Prob.ModeMvMergeProbs(preFc.Class0Hp[i], ref counts.Class0Hp[i]);
fc.Hp[i] = Prob.ModeMvMergeProbs(preFc.Hp[i], ref counts.Hp[i]);
}
}
}
public void ResizeContextBuffers(MemoryAllocator allocator, int width, int height)
{
if (Width != width || Height != height)
{
int newMiRows = BitUtils.AlignPowerOfTwo(height, Constants.MiSizeLog2) >> Constants.MiSizeLog2;
int newMiCols = BitUtils.AlignPowerOfTwo(width, Constants.MiSizeLog2) >> Constants.MiSizeLog2;
// Allocations in AllocContextBuffers() depend on individual
// dimensions as well as the overall size.
if (newMiCols > MiCols || newMiRows > MiRows)
{
if (AllocContextBuffers(allocator, width, height))
{
// The Mi* values have been cleared and any existing context
// buffers have been freed. Clear Width and Height to be
// consistent and to force a realloc next time.
Width = 0;
Height = 0;
Error.InternalError(CodecErr.MemError, "Failed to allocate context buffers");
}
}
else
{
SetMbMi(width, height);
}
InitContextBuffers();
Width = width;
Height = height;
}
if (CurFrameMvs.IsNull ||
MiRows > CurFrame.Value.MiRows ||
MiCols > CurFrame.Value.MiCols)
{
ResizeMvBuffer(allocator);
}
}
public void CheckMemError<T>(ref ArrayPtr<T> lval, ArrayPtr<T> expr)
where T : unmanaged
{
lval = expr;
if (lval.IsNull)
{
Error.InternalError(CodecErr.MemError, "Failed to allocate");
}
}
private void ResizeMvBuffer(MemoryAllocator allocator)
{
allocator.Free(CurFrameMvs);
CurFrame.Value.MiRows = MiRows;
CurFrame.Value.MiCols = MiCols;
CheckMemError(ref CurFrameMvs, allocator.Allocate<MvRef>(MiRows * MiCols));
}
public void CheckMemError<T>(ref Ptr<T> lval, Ptr<T> expr) where T : unmanaged
{
lval = expr;
if (lval.IsNull)
{
Error.InternalError(CodecErr.MemError, "Failed to allocate");
}
}
public void SetupTileInfo(ref ReadBitBuffer rb)
{
int minLog2TileCols = 0, maxLog2TileCols = 0, maxOnes;
TileInfo.GetTileNBits(MiCols, out minLog2TileCols, out maxLog2TileCols);
// columns
maxOnes = maxLog2TileCols - minLog2TileCols;
Log2TileCols = minLog2TileCols;
while (maxOnes-- != 0 && rb.ReadBit() != 0)
{
Log2TileCols++;
}
if (Log2TileCols > 6)
{
Error.InternalError(CodecErr.CorruptFrame, "Invalid number of tile columns");
}
// rows
Log2TileRows = rb.ReadBit();
if (Log2TileRows != 0)
{
Log2TileRows += rb.ReadBit();
}
}
public void ReadBitdepthColorspaceSampling(ref ReadBitBuffer rb)
{
if (Profile >= BitstreamProfile.Profile2)
{
BitDepth = rb.ReadBit() != 0 ? BitDepth.Bits12 : BitDepth.Bits10;
UseHighBitDepth = true;
}
else
{
BitDepth = BitDepth.Bits8;
UseHighBitDepth = false;
}
ColorSpace = (VpxColorSpace)rb.ReadLiteral(3);
if (ColorSpace != VpxColorSpace.Srgb)
{
ColorRange = (VpxColorRange)rb.ReadBit();
if (Profile == BitstreamProfile.Profile1 || Profile == BitstreamProfile.Profile3)
{
SubsamplingX = rb.ReadBit();
SubsamplingY = rb.ReadBit();
if (SubsamplingX == 1 && SubsamplingY == 1)
{
Error.InternalError(CodecErr.UnsupBitstream,
"4:2:0 color not supported in profile 1 or 3");
}
if (rb.ReadBit() != 0)
{
Error.InternalError(CodecErr.UnsupBitstream, "Reserved bit set");
}
}
else
{
SubsamplingY = SubsamplingX = 1;
}
}
else
{
ColorRange = VpxColorRange.Full;
if (Profile == BitstreamProfile.Profile1 || Profile == BitstreamProfile.Profile3)
{
// Note if colorspace is SRGB then 4:4:4 chroma sampling is assumed.
// 4:2:2 or 4:4:0 chroma sampling is not allowed.
SubsamplingY = SubsamplingX = 0;
if (rb.ReadBit() != 0)
{
Error.InternalError(CodecErr.UnsupBitstream, "Reserved bit set");
}
}
else
{
Error.InternalError(CodecErr.UnsupBitstream, "4:4:4 color not supported in profile 0 or 2");
}
}
}
public void AdaptModeProbs()
{
ref Vp9EntropyProbs fc = ref Fc.Value;
ref Vp9EntropyProbs preFc = ref FrameContexts[(int)FrameContextIdx];
ref Vp9BackwardUpdates counts = ref Counts.Value;
for (int i = 0; i < Constants.IntraInterContexts; i++)
{
fc.IntraInterProb[i] = Prob.ModeMvMergeProbs(preFc.IntraInterProb[i], ref counts.IntraInter[i]);
}
for (int i = 0; i < Constants.CompInterContexts; i++)
{
fc.CompInterProb[i] = Prob.ModeMvMergeProbs(preFc.CompInterProb[i], ref counts.CompInter[i]);
}
for (int i = 0; i < Constants.RefContexts; i++)
{
fc.CompRefProb[i] = Prob.ModeMvMergeProbs(preFc.CompRefProb[i], ref counts.CompRef[i]);
}
for (int i = 0; i < Constants.RefContexts; i++)
{
for (int j = 0; j < 2; j++)
{
fc.SingleRefProb[i][j] =
Prob.ModeMvMergeProbs(preFc.SingleRefProb[i][j], ref counts.SingleRef[i][j]);
}
}
for (int i = 0; i < Constants.InterModeContexts; i++)
{
Prob.VpxTreeMergeProbs(
EntropyMode.InterModeTree,
preFc.InterModeProb[i].AsSpan(),
counts.InterMode[i].AsSpan(),
fc.InterModeProb[i].AsSpan());
}
for (int i = 0; i < EntropyMode.BlockSizeGroups; i++)
{
Prob.VpxTreeMergeProbs(
EntropyMode.IntraModeTree,
preFc.YModeProb[i].AsSpan(),
counts.YMode[i].AsSpan(),
fc.YModeProb[i].AsSpan());
}
for (int i = 0; i < Constants.IntraModes; ++i)
{
Prob.VpxTreeMergeProbs(
EntropyMode.IntraModeTree,
preFc.UvModeProb[i].AsSpan(),
counts.UvMode[i].AsSpan(),
fc.UvModeProb[i].AsSpan());
}
for (int i = 0; i < Constants.PartitionContexts; i++)
{
Prob.VpxTreeMergeProbs(
EntropyMode.PartitionTree,
preFc.PartitionProb[i].AsSpan(),
counts.Partition[i].AsSpan(),
fc.PartitionProb[i].AsSpan());
}
if (InterpFilter == Constants.Switchable)
{
for (int i = 0; i < Constants.SwitchableFilterContexts; i++)
{
Prob.VpxTreeMergeProbs(
EntropyMode.SwitchableInterpTree,
preFc.SwitchableInterpProb[i].AsSpan(),
counts.SwitchableInterp[i].AsSpan(),
fc.SwitchableInterpProb[i].AsSpan());
}
}
if (TxMode == TxMode.TxModeSelect)
{
Array1<Array2<uint>> branchCt8x8P = new();
Array2<Array2<uint>> branchCt16x16P = new();
Array3<Array2<uint>> branchCt32x32P = new();
for (int i = 0; i < EntropyMode.TxSizeContexts; ++i)
{
EntropyMode.TxCountsToBranchCounts8x8(counts.Tx8x8[i].AsSpan(), ref branchCt8x8P);
for (int j = 0; j < (int)TxSize.TxSizes - 3; ++j)
{
fc.Tx8x8Prob[i][j] = Prob.ModeMvMergeProbs(preFc.Tx8x8Prob[i][j], ref branchCt8x8P[j]);
}
EntropyMode.TxCountsToBranchCounts16x16(counts.Tx16x16[i].AsSpan(), ref branchCt16x16P);
for (int j = 0; j < (int)TxSize.TxSizes - 2; ++j)
{
fc.Tx16x16Prob[i][j] =
Prob.ModeMvMergeProbs(preFc.Tx16x16Prob[i][j], ref branchCt16x16P[j]);
}
EntropyMode.TxCountsToBranchCounts32x32(counts.Tx32x32[i].AsSpan(), ref branchCt32x32P);
for (int j = 0; j < (int)TxSize.TxSizes - 1; ++j)
{
fc.Tx32x32Prob[i][j] =
Prob.ModeMvMergeProbs(preFc.Tx32x32Prob[i][j], ref branchCt32x32P[j]);
}
}
}
for (int i = 0; i < Constants.SkipContexts; ++i)
{
fc.SkipProb[i] = Prob.ModeMvMergeProbs(preFc.SkipProb[i], ref counts.Skip[i]);
}
}
public void AdaptCoefProbs()
{
byte t;
uint countSat, updateFactor;
if (FrameIsIntraOnly())
{
updateFactor = Entropy.CoefMaxUpdateFactorKey;
countSat = Entropy.CoefCountSatKey;
}
else if (LastFrameType == FrameType.KeyFrame)
{
updateFactor = Entropy.CoefMaxUpdateFactorAfterKey; /* adapt quickly */
countSat = Entropy.CoefCountSatAfterKey;
}
else
{
updateFactor = Entropy.CoefMaxUpdateFactor;
countSat = Entropy.CoefCountSat;
}
for (t = (int)TxSize.Tx4x4; t <= (int)TxSize.Tx32x32; t++)
{
AdaptCoefProbs(t, countSat, updateFactor);
}
}
public void SetMvs(ReadOnlySpan<Vp9MvRef> mvs)
{
if (mvs.Length > PrevFrameMvs.Length)
{
throw new ArgumentException(
$"Size mismatch, expected: {PrevFrameMvs.Length}, but got: {mvs.Length}.");
}
for (int i = 0; i < mvs.Length; i++)
{
ref MvRef mv = ref PrevFrameMvs[i];
mv.Mv[0].Row = mvs[i].Mvs[0].Row;
mv.Mv[0].Col = mvs[i].Mvs[0].Col;
mv.Mv[1].Row = mvs[i].Mvs[1].Row;
mv.Mv[1].Col = mvs[i].Mvs[1].Col;
mv.RefFrame[0] = (sbyte)mvs[i].RefFrames[0];
mv.RefFrame[1] = (sbyte)mvs[i].RefFrames[1];
}
}
public void GetMvs(Span<Vp9MvRef> mvs)
{
if (mvs.Length > CurFrameMvs.Length)
{
throw new ArgumentException(
$"Size mismatch, expected: {CurFrameMvs.Length}, but got: {mvs.Length}.");
}
for (int i = 0; i < mvs.Length; i++)
{
ref MvRef mv = ref CurFrameMvs[i];
mvs[i].Mvs[0].Row = mv.Mv[0].Row;
mvs[i].Mvs[0].Col = mv.Mv[0].Col;
mvs[i].Mvs[1].Row = mv.Mv[1].Row;
mvs[i].Mvs[1].Col = mv.Mv[1].Col;
mvs[i].RefFrames[0] = mv.RefFrame[0];
mvs[i].RefFrames[1] = mv.RefFrame[1];
}
}
private void AdaptCoefProbs(byte txSize, uint countSat, uint updateFactor)
{
ref Vp9EntropyProbs preFc = ref FrameContexts[(int)FrameContextIdx];
ref Array2<Array2<Array6<Array6<Array3<byte>>>>> probs = ref Fc.Value.CoefProbs[txSize];
ref Array2<Array2<Array6<Array6<Array3<byte>>>>> preProbs = ref preFc.CoefProbs[txSize];
ref Array2<Array2<Array6<Array6<Array4<uint>>>>> counts = ref Counts.Value.Coef[txSize];
ref Array2<Array2<Array6<Array6<uint>>>> eobCounts = ref Counts.Value.EobBranch[txSize];
for (int i = 0; i < Constants.PlaneTypes; ++i)
{
for (int j = 0; j < Entropy.RefTypes; ++j)
{
for (int k = 0; k < Entropy.CoefBands; ++k)
{
for (int l = 0; l < Entropy.BAND_COEFF_CONTEXTS(k); ++l)
{
int n0 = (int)counts[i][j][k][l][Entropy.ZeroToken];
int n1 = (int)counts[i][j][k][l][Entropy.OneToken];
int n2 = (int)counts[i][j][k][l][Entropy.TwoToken];
int neob = (int)counts[i][j][k][l][Entropy.EobModelToken];
Array3<Array2<uint>> branchCt = new();
branchCt[0][0] = (uint)neob;
branchCt[0][1] = (uint)(eobCounts[i][j][k][l] - neob);
branchCt[1][0] = (uint)n0;
branchCt[1][1] = (uint)(n1 + n2);
branchCt[2][0] = (uint)n1;
branchCt[2][1] = (uint)n2;
for (int m = 0; m < Entropy.UnconstrainedNodes; ++m)
{
probs[i][j][k][l][m] = Prob.MergeProbs(preProbs[i][j][k][l][m], ref branchCt[m],
countSat, updateFactor);
}
}
}
}
}
}
public void DefaultCoefProbs()
{
Entropy.CopyProbs(ref Fc.Value.CoefProbs[(int)TxSize.Tx4x4], Entropy.DefaultCoefProbs4x4);
Entropy.CopyProbs(ref Fc.Value.CoefProbs[(int)TxSize.Tx8x8], Entropy.DefaultCoefProbs8x8);
Entropy.CopyProbs(ref Fc.Value.CoefProbs[(int)TxSize.Tx16x16], Entropy.DefaultCoefProbs16x16);
Entropy.CopyProbs(ref Fc.Value.CoefProbs[(int)TxSize.Tx32x32], Entropy.DefaultCoefProbs32x32);
}
} }
} }

View file

@ -0,0 +1,410 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.Nvdec.Vp9.Common;
using Ryujinx.Graphics.Video;
using System.Diagnostics;
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
{
internal struct Vp9Decoder
{
public Vp9Common Common;
public int ReadyForNewData;
public int RefreshFrameFlags;
public int NeedResync; // Wait for key/intra-only frame.
public int HoldRefBuf; // Hold the reference buffer.
private static void DecreaseRefCount(int idx, ref Array12<RefCntBuffer> frameBufs, ref BufferPool pool)
{
if (idx >= 0 && frameBufs[idx].RefCount > 0)
{
--frameBufs[idx].RefCount;
// A worker may only get a free framebuffer index when calling GetFreeFb.
// But the private buffer is not set up until finish decoding header.
// So any error happens during decoding header, the frame_bufs will not
// have valid priv buffer.
if (frameBufs[idx].Released == 0 && frameBufs[idx].RefCount == 0 &&
!frameBufs[idx].RawFrameBuffer.Priv.IsNull)
{
FrameBuffers.ReleaseFrameBuffer(pool.CbPriv, ref frameBufs[idx].RawFrameBuffer);
frameBufs[idx].Released = 1;
}
}
}
public void Create(MemoryAllocator allocator, ref BufferPool pool)
{
ref Vp9Common cm = ref Common;
cm.CheckMemError(ref cm.Fc,
new Ptr<Vp9EntropyProbs>(ref allocator.Allocate<Vp9EntropyProbs>(1)[0]));
cm.CheckMemError(ref cm.FrameContexts,
allocator.Allocate<Vp9EntropyProbs>(Constants.FrameContexts));
for (int i = 0; i < EntropyMode.KfYModeProb.Length; i++)
{
for (int j = 0; j < EntropyMode.KfYModeProb[i].Length; j++)
{
for (int k = 0; k < EntropyMode.KfYModeProb[i][j].Length; k++)
{
cm.Fc.Value.KfYModeProb[i][j][k] = EntropyMode.KfYModeProb[i][j][k];
}
}
}
for (int i = 0; i < EntropyMode.KfUvModeProb.Length; i++)
{
for (int j = 0; j < EntropyMode.KfUvModeProb[i].Length; j++)
{
cm.Fc.Value.KfUvModeProb[i][j] = EntropyMode.KfUvModeProb[i][j];
}
}
byte[][] KfPartitionProbs =
{
// 8x8 . 4x4
new byte[] { 158, 97, 94 }, // a/l both not split
new byte[] { 93, 24, 99 }, // a split, l not split
new byte[] { 85, 119, 44 }, // l split, a not split
new byte[] { 62, 59, 67 }, // a/l both split
// 16x16 . 8x8
new byte[] { 149, 53, 53 }, // a/l both not split
new byte[] { 94, 20, 48 }, // a split, l not split
new byte[] { 83, 53, 24 }, // l split, a not split
new byte[] { 52, 18, 18 }, // a/l both split
// 32x32 . 16x16
new byte[] { 150, 40, 39 }, // a/l both not split
new byte[] { 78, 12, 26 }, // a split, l not split
new byte[] { 67, 33, 11 }, // l split, a not split
new byte[] { 24, 7, 5 }, // a/l both split
// 64x64 . 32x32
new byte[] { 174, 35, 49 }, // a/l both not split
new byte[] { 68, 11, 27 }, // a split, l not split
new byte[] { 57, 15, 9 }, // l split, a not split
new byte[] { 12, 3, 3 } // a/l both split
};
for (int i = 0; i < KfPartitionProbs.Length; i++)
{
for (int j = 0; j < KfPartitionProbs[i].Length; j++)
{
cm.Fc.Value.KfPartitionProb[i][j] = KfPartitionProbs[i][j];
}
}
cm.Counts = new Ptr<Vp9BackwardUpdates>(ref allocator.Allocate<Vp9BackwardUpdates>(1)[0]);
NeedResync = 1;
// Initialize the references to not point to any frame buffers.
for (int i = 0; i < 8; i++)
{
cm.RefFrameMap[i] = -1;
cm.NextRefFrameMap[i] = -1;
}
cm.CurrentVideoFrame = 0;
ReadyForNewData = 1;
Common.BufferPool = new Ptr<BufferPool>(ref pool);
cm.BitDepth = BitDepth.Bits8;
cm.DequantBitDepth = BitDepth.Bits8;
// vp9_loop_filter_init(ref cm);
}
/* If any buffer updating is signaled it should be done here. */
private void SwapFrameBuffers()
{
int refIndex = 0, mask;
ref Vp9Common cm = ref Common;
ref BufferPool pool = ref cm.BufferPool.Value;
ref Array12<RefCntBuffer> frameBufs = ref cm.BufferPool.Value.FrameBufs;
for (mask = RefreshFrameFlags; mask != 0; mask >>= 1)
{
int oldIdx = cm.RefFrameMap[refIndex];
// Current thread releases the holding of reference frame.
DecreaseRefCount(oldIdx, ref frameBufs, ref pool);
// Release the reference frame in reference map.
if ((mask & 1) != 0)
{
DecreaseRefCount(oldIdx, ref frameBufs, ref pool);
}
cm.RefFrameMap[refIndex] = cm.NextRefFrameMap[refIndex];
++refIndex;
}
// Current thread releases the holding of reference frame.
for (; refIndex < Constants.RefFrames && cm.ShowExistingFrame == 0; ++refIndex)
{
int oldIdx = cm.RefFrameMap[refIndex];
DecreaseRefCount(oldIdx, ref frameBufs, ref pool);
cm.RefFrameMap[refIndex] = cm.NextRefFrameMap[refIndex];
}
HoldRefBuf = 0;
cm.FrameToShow = new Ptr<Surface>(ref cm.GetFrameNewBuffer());
--frameBufs[cm.NewFbIdx].RefCount;
// Invalidate these references until the next frame starts.
for (refIndex = 0; refIndex < 3; refIndex++)
{
cm.FrameRefs[refIndex].Idx = RefBuffer.InvalidIdx;
}
}
public CodecErr ReceiveCompressedData(MemoryAllocator allocator, ulong size, ref ArrayPtr<byte> psource)
{
ref Vp9Common cm = ref Common;
ref BufferPool pool = ref cm.BufferPool.Value;
ref Array12<RefCntBuffer> frameBufs = ref cm.BufferPool.Value.FrameBufs;
ArrayPtr<byte> source = psource;
CodecErr retcode = 0;
cm.Error.ErrorCode = CodecErr.Ok;
if (size == 0)
{
// This is used to signal that we are missing frames.
// We do not know if the missing frame(s) was supposed to update
// any of the reference buffers, but we act conservative and
// mark only the last buffer as corrupted.
if (cm.FrameRefs[0].Idx > 0)
{
cm.FrameRefs[0].Buf.Corrupted = 1;
}
}
ReadyForNewData = 0;
// Check if the previous frame was a frame without any references to it.
if (cm.NewFbIdx >= 0 && frameBufs[cm.NewFbIdx].RefCount == 0 &&
frameBufs[cm.NewFbIdx].Released == 0)
{
FrameBuffers.ReleaseFrameBuffer(pool.CbPriv, ref frameBufs[cm.NewFbIdx].RawFrameBuffer);
frameBufs[cm.NewFbIdx].Released = 1;
}
// Find a free frame buffer. Return error if can not find any.
cm.NewFbIdx = cm.GetFreeFb();
if (cm.NewFbIdx == RefBuffer.InvalidIdx)
{
ReadyForNewData = 1;
cm.Error.InternalError(CodecErr.MemError, "Unable to find free frame buffer");
return cm.Error.ErrorCode;
}
// Assign a MV array to the frame buffer.
cm.CurFrame = new Ptr<RefCntBuffer>(ref pool.FrameBufs[cm.NewFbIdx]);
HoldRefBuf = 0;
DecodeFrame.Decode(allocator, ref this, new ArrayPtr<byte>(ref source[0], (int)size), out psource);
SwapFrameBuffers();
// vpx_clear_system_state();
if (cm.ShowExistingFrame == 0)
{
cm.LastShowFrame = cm.ShowFrame;
cm.PrevFrame = cm.CurFrame;
if (cm.PrevFrameMvs.IsNull || cm.PrevFrameMvs.Length != cm.CurFrameMvs.Length)
{
allocator.Free(cm.PrevFrameMvs);
cm.PrevFrameMvs = allocator.Allocate<MvRef>(cm.CurFrameMvs.Length);
}
cm.CurFrameMvs.AsSpan().CopyTo(cm.PrevFrameMvs.AsSpan());
if (cm.Seg.Enabled)
{
cm.SwapCurrentAndLastSegMap();
}
}
if (cm.ShowFrame != 0)
{
cm.CurShowFrameFbIdx = cm.NewFbIdx;
}
// Update progress in frame parallel decode.
cm.LastWidth = cm.Width;
cm.LastHeight = cm.Height;
if (cm.ShowFrame != 0)
{
cm.CurrentVideoFrame++;
}
return retcode;
}
public int GetRawFrame(ref Surface sd)
{
ref Vp9Common cm = ref Common;
int ret = -1;
if (ReadyForNewData == 1)
{
return ret;
}
ReadyForNewData = 1;
if (cm.ShowFrame == 0)
{
return ret;
}
ReadyForNewData = 1;
sd = cm.FrameToShow.Value;
ret = 0;
return ret;
}
public CodecErr Decode(MemoryAllocator allocator, ArrayPtr<byte> data)
{
ArrayPtr<byte> dataStart = data;
CodecErr res;
Array8<uint> frameSizes = new();
int frameCount = 0;
res = Types.Decoder.ParseSuperframeIndex(data, (ulong)data.Length, ref frameSizes, out frameCount);
if (res != CodecErr.Ok)
{
return res;
}
// Decode in serial mode.
if (frameCount > 0)
{
for (int i = 0; i < frameCount; ++i)
{
ArrayPtr<byte> dataStartCopy = dataStart;
uint frameSize = frameSizes[i];
if (frameSize > (uint)dataStart.Length)
{
return CodecErr.CorruptFrame;
}
res = ReceiveCompressedData(allocator, frameSize, ref dataStartCopy);
if (res != CodecErr.Ok)
{
return res;
}
dataStart = dataStart.Slice((int)frameSize);
}
}
else
{
while (dataStart.Length != 0)
{
uint frameSize = (uint)dataStart.Length;
res = ReceiveCompressedData(allocator, frameSize, ref dataStart);
if (res != CodecErr.Ok)
{
return res;
}
// Account for suboptimal termination by the encoder.
while (dataStart.Length != 0)
{
byte marker = Types.Decoder.ReadMarker(dataStart);
if (marker != 0)
{
break;
}
dataStart = dataStart.Slice(1);
}
}
}
return res;
}
}
internal static class Decoder
{
public static byte ReadMarker(ArrayPtr<byte> data)
{
return data[0];
}
public static CodecErr ParseSuperframeIndex(ArrayPtr<byte> data, ulong dataSz, ref Array8<uint> sizes, out int count)
{
// A chunk ending with a byte matching 0xc0 is an invalid chunk unless
// it is a super frame index. If the last byte of real video compression
// data is 0xc0 the encoder must add a 0 byte. If we have the marker but
// not the associated matching marker byte at the front of the index we have
// an invalid bitstream and need to return an error.
byte marker;
Debug.Assert(dataSz != 0);
marker = ReadMarker(data.Slice((int)dataSz - 1));
count = 0;
if ((marker & 0xe0) == 0xc0)
{
uint frames = (uint)(marker & 0x7) + 1;
uint mag = (uint)((marker >> 3) & 0x3) + 1;
ulong indexSz = 2 + (mag * frames);
// This chunk is marked as having a superframe index but doesn't have
// enough data for it, thus it's an invalid superframe index.
if (dataSz < indexSz)
{
return CodecErr.CorruptFrame;
}
{
byte marker2 = ReadMarker(data.Slice((int)(dataSz - indexSz)));
// This chunk is marked as having a superframe index but doesn't have
// the matching marker byte at the front of the index therefore it's an
// invalid chunk.
if (marker != marker2)
{
return CodecErr.CorruptFrame;
}
}
{
// Found a valid superframe index.
ArrayPtr<byte> x = data.Slice((int)(dataSz - indexSz + 1));
for (int i = 0; i < frames; ++i)
{
uint thisSz = 0;
for (int j = 0; j < mag; ++j)
{
thisSz |= (uint)x[0] << j * 8;
x = x.Slice(1);
}
sizes[i] = thisSz;
}
count = (int)frames;
}
}
return CodecErr.Ok;
}
}
}

View file

@ -0,0 +1,10 @@
using Ryujinx.Common.Memory;
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
{
internal struct VpxCodecFrameBuffer
{
public ArrayPtr<byte> Data;
public Ptr<InternalFrameBuffer> Priv;
}
}

View file

@ -0,0 +1,11 @@
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
{
internal enum VpxColorRange
{
// Y [16..235], UV [16..240]
Studio,
// YUV/RGB [0..255]
Full
}
}

View file

@ -0,0 +1,29 @@
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
{
internal enum VpxColorSpace
{
// Unknown
Unknown,
// BT.601
Bt601,
// BT.709
Bt709,
// SMPTE.170
Smpte170,
// SMPTE.240
Smpte240,
// BT.2020
Bt2020,
// Reserved
Reserved,
// sRGB
Srgb
}
}

View file

@ -59,6 +59,8 @@ namespace Ryujinx.Graphics.Nvdec.Types.Vp9
Flags.HasFlag(FrameFlags.LastShowFrame) && Flags.HasFlag(FrameFlags.LastShowFrame) &&
!Flags.HasFlag(FrameFlags.LastFrameIsKeyFrame), !Flags.HasFlag(FrameFlags.LastFrameIsKeyFrame),
RefFrameSignBias = RefFrameSignBias, RefFrameSignBias = RefFrameSignBias,
LoopFilterLevel = FirstLevel,
LoopFilterSharpnessLevel = SharpnessLevel,
BaseQIndex = BaseQIndex, BaseQIndex = BaseQIndex,
YDcDeltaQ = YDcDeltaQ, YDcDeltaQ = YDcDeltaQ,
UvDcDeltaQ = UvDcDeltaQ, UvDcDeltaQ = UvDcDeltaQ,

View file

@ -10,6 +10,8 @@ namespace Ryujinx.Graphics.Video
public bool IsKeyFrame; public bool IsKeyFrame;
public bool IntraOnly; public bool IntraOnly;
public Array4<sbyte> RefFrameSignBias; public Array4<sbyte> RefFrameSignBias;
public int LoopFilterLevel;
public int LoopFilterSharpnessLevel;
public int BaseQIndex; public int BaseQIndex;
public int YDcDeltaQ; public int YDcDeltaQ;
public int UvDcDeltaQ; public int UvDcDeltaQ;