mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-07-23 08:47:10 +02:00
Implement VP9 loop filtering (#550)
Unmerged PR from OG Ryujinx (#4367). From @gdkchan: > The main goal of this change is porting the loop filtering from libvpx, which should fix the block artifacts on some VP9 videos on games using NVDEC to decode them. In addition to that, there are two other changes: > > - The remaining decoder code required to decode a VP9 video (with headers included) has been added. That was done because it's much better to test the decoder standalone with a video file. I decided to keep that code on the emulator, even if some of it is unused, since it makes standalone testing easier in the future too, and we can include unit tests with video files. > - Large refactoring of both new and existing code to conform with our conding [sic] styles, done by @TSRBerry (thanks!) Some of it has been automated. > > Since we had no loop filtering before, this change will make video decoding slower. That may cause frame drop etc if the decoder is not fast enough in some games. I plan to optimize the decoder more in the future to make up for that, but if possible I'd prefer to not do it as part of this PR, but if the perf loss is too severe I might consider. > > This will need to be tested on games that had the block artifacts, it would be nice to confirm if they match hardware now, and get some before/after screenshots etc. Comment from @Bjorn29512: > Significantly improves the block artifacts in FE: Engage. > > Before: >  > > After: >  --------- Co-authored-by: gdkchan <gab.dark.100@gmail.com> Co-authored-by: TSR Berry <20988865+TSRBerry@users.noreply.github.com>
This commit is contained in:
parent
920933bc9f
commit
f91cd05260
79 changed files with 11343 additions and 3036 deletions
|
@ -7,4 +7,4 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
public PredictionMode Mode;
|
||||
public Array2<Mv> Mv; // First, second inter predictor motion vectors
|
||||
}
|
||||
}
|
||||
}
|
11
src/Ryujinx.Graphics.Nvdec.Vp9/Types/BitstreamProfile.cs
Normal file
11
src/Ryujinx.Graphics.Nvdec.Vp9/Types/BitstreamProfile.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
{
|
||||
public enum BitstreamProfile
|
||||
{
|
||||
Profile0,
|
||||
Profile1,
|
||||
Profile2,
|
||||
Profile3,
|
||||
MaxProfiles
|
||||
}
|
||||
}
|
|
@ -1,21 +1,21 @@
|
|||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
{
|
||||
internal enum BlockSize
|
||||
{
|
||||
Block4x4 = 0,
|
||||
Block4x8 = 1,
|
||||
Block8x4 = 2,
|
||||
Block8x8 = 3,
|
||||
Block8x16 = 4,
|
||||
Block16x8 = 5,
|
||||
Block16x16 = 6,
|
||||
Block16x32 = 7,
|
||||
Block32x16 = 8,
|
||||
Block32x32 = 9,
|
||||
Block32x64 = 10,
|
||||
Block64x32 = 11,
|
||||
Block64x64 = 12,
|
||||
BlockSizes = 13,
|
||||
BlockInvalid = BlockSizes,
|
||||
Block4x4,
|
||||
Block4x8,
|
||||
Block8x4,
|
||||
Block8x8,
|
||||
Block8x16,
|
||||
Block16x8,
|
||||
Block16x16,
|
||||
Block16x32,
|
||||
Block32x16,
|
||||
Block32x32,
|
||||
Block32x64,
|
||||
Block64x32,
|
||||
Block64x64,
|
||||
BlockSizes,
|
||||
BlockInvalid = BlockSizes
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,4 +7,4 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
public ArrayPtr<byte> Buf;
|
||||
public int Stride;
|
||||
}
|
||||
}
|
||||
}
|
18
src/Ryujinx.Graphics.Nvdec.Vp9/Types/BufferPool.cs
Normal file
18
src/Ryujinx.Graphics.Nvdec.Vp9/Types/BufferPool.cs
Normal 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;
|
||||
}
|
||||
}
|
|
@ -5,4 +5,4 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
KeyFrame = 0,
|
||||
InterFrame = 1,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,5 +23,18 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
|
||||
public ArrayPtr<LoopFilterMask> Lfm;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,4 +7,4 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
public Array64<LoopFilterThresh> Lfthr;
|
||||
public Array8<Array4<Array2<byte>>> Lvl;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,4 +21,4 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
public ushort Int4x4Uv;
|
||||
public Array64<byte> LflY;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,4 +12,4 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
public Array16<byte> HevThr;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Graphics.Nvdec.Vp9.Common;
|
||||
using Ryujinx.Graphics.Video;
|
||||
|
||||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
|
@ -54,7 +55,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
|
||||
public Ptr<InternalErrorInfo> ErrorInfo;
|
||||
|
||||
public readonly int GetPredContextSegId()
|
||||
public int GetPredContextSegId()
|
||||
{
|
||||
sbyte aboveSip = !AboveMi.IsNull ? AboveMi.Value.SegIdPredicted : (sbyte)0;
|
||||
sbyte leftSip = !LeftMi.IsNull ? LeftMi.Value.SegIdPredicted : (sbyte)0;
|
||||
|
@ -62,15 +63,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
return aboveSip + leftSip;
|
||||
}
|
||||
|
||||
public readonly int GetSkipContext()
|
||||
public int GetSkipContext()
|
||||
{
|
||||
int aboveSkip = !AboveMi.IsNull ? AboveMi.Value.Skip : 0;
|
||||
int leftSkip = !LeftMi.IsNull ? LeftMi.Value.Skip : 0;
|
||||
|
||||
return aboveSkip + leftSkip;
|
||||
}
|
||||
|
||||
public readonly int GetPredContextSwitchableInterp()
|
||||
public int GetPredContextSwitchableInterp()
|
||||
{
|
||||
// Note:
|
||||
// The mode info data structure has a one element border above and to the
|
||||
|
@ -83,18 +83,18 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
{
|
||||
return leftType;
|
||||
}
|
||||
else if (leftType == Constants.SwitchableFilters)
|
||||
|
||||
if (leftType == Constants.SwitchableFilters)
|
||||
{
|
||||
return aboveType;
|
||||
}
|
||||
else if (aboveType == Constants.SwitchableFilters)
|
||||
|
||||
if (aboveType == Constants.SwitchableFilters)
|
||||
{
|
||||
return leftType;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Constants.SwitchableFilters;
|
||||
}
|
||||
|
||||
return Constants.SwitchableFilters;
|
||||
}
|
||||
|
||||
// The mode info data structure has a one element border above and to the
|
||||
|
@ -104,20 +104,22 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
// 1 - intra/inter, inter/intra
|
||||
// 2 - intra/--, --/intra
|
||||
// 3 - intra/intra
|
||||
public readonly int GetIntraInterContext()
|
||||
public int GetIntraInterContext()
|
||||
{
|
||||
if (!AboveMi.IsNull && !LeftMi.IsNull)
|
||||
{ // Both edges available
|
||||
{
|
||||
// Both edges available
|
||||
bool aboveIntra = !AboveMi.Value.IsInterBlock();
|
||||
bool leftIntra = !LeftMi.Value.IsInterBlock();
|
||||
|
||||
return leftIntra && aboveIntra ? 3 : (leftIntra || aboveIntra ? 1 : 0);
|
||||
return leftIntra && aboveIntra ? 3 : leftIntra || aboveIntra ? 1 : 0;
|
||||
}
|
||||
|
||||
if (!AboveMi.IsNull || !LeftMi.IsNull)
|
||||
{ // One edge available
|
||||
{
|
||||
// One edge available
|
||||
return 2 * (!(!AboveMi.IsNull ? AboveMi.Value : LeftMi.Value).IsInterBlock() ? 1 : 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -125,11 +127,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
// The mode info data structure has a one element border above and to the
|
||||
// left of the entries corresponding to real blocks.
|
||||
// The prediction flags in these dummy entries are initialized to 0.
|
||||
public readonly int GetTxSizeContext()
|
||||
public int GetTxSizeContext()
|
||||
{
|
||||
int maxTxSize = (int)Luts.MaxTxSizeLookup[(int)Mi[0].Value.SbType];
|
||||
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 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;
|
||||
if (LeftMi.IsNull)
|
||||
{
|
||||
leftCtx = aboveCtx;
|
||||
|
@ -140,14 +142,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
aboveCtx = leftCtx;
|
||||
}
|
||||
|
||||
return (aboveCtx + leftCtx) > maxTxSize ? 1 : 0;
|
||||
return aboveCtx + leftCtx > maxTxSize ? 1 : 0;
|
||||
}
|
||||
|
||||
public void SetupBlockPlanes(int ssX, int ssY)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < Constants.MaxMbPlane; i++)
|
||||
for (int i = 0; i < Constants.MaxMbPlane; i++)
|
||||
{
|
||||
Plane[i].SubsamplingX = i != 0 ? ssX : 0;
|
||||
Plane[i].SubsamplingY = i != 0 ? ssY : 0;
|
||||
|
@ -158,25 +158,36 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
{
|
||||
int aboveIdx = miCol * 2;
|
||||
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];
|
||||
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)
|
||||
{
|
||||
MbToTopEdge = -((miRow * Constants.MiSize) * 8);
|
||||
MbToBottomEdge = ((miRows - bh - miRow) * Constants.MiSize) * 8;
|
||||
MbToLeftEdge = -((miCol * Constants.MiSize) * 8);
|
||||
MbToRightEdge = ((miCols - bw - miCol) * Constants.MiSize) * 8;
|
||||
MbToTopEdge = -(miRow * Constants.MiSize * 8);
|
||||
MbToBottomEdge = (miRows - bh - miRow) * Constants.MiSize * 8;
|
||||
MbToLeftEdge = -(miCol * Constants.MiSize * 8);
|
||||
MbToRightEdge = (miCols - bw - miCol) * Constants.MiSize * 8;
|
||||
|
||||
// Are edges available for intra prediction?
|
||||
AboveMi = (miRow != 0) ? Mi[-MiStride] : Ptr<ModeInfo>.Null;
|
||||
LeftMi = (miCol > tile.MiColStart) ? Mi[-1] : Ptr<ModeInfo>.Null;
|
||||
AboveMi = miRow != 0 ? Mi[-MiStride] : 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,7 +15,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
|
||||
// Number of 4x4s in current block
|
||||
public ushort N4W, N4H;
|
||||
|
||||
// Log2 of N4W, N4H
|
||||
public byte N4Wl, N4Hl;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
|
@ -32,11 +32,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
return SbType < BlockSize.Block8x8 ? Bmi[block].Mode : Mode;
|
||||
}
|
||||
|
||||
public readonly TxSize GetUvTxSize(ref MacroBlockDPlane pd)
|
||||
public TxSize GetUvTxSize(ref MacroBlockDPlane pd)
|
||||
{
|
||||
Debug.Assert(SbType < BlockSize.Block8x8 ||
|
||||
Luts.SsSizeLookup[(int)SbType][pd.SubsamplingX][pd.SubsamplingY] != BlockSize.BlockInvalid);
|
||||
|
||||
Luts.SsSizeLookup[(int)SbType][pd.SubsamplingX][pd.SubsamplingY] != BlockSize.BlockInvalid);
|
||||
return Luts.UvTxsizeLookup[(int)SbType][(int)TxSize][pd.SubsamplingX][pd.SubsamplingY];
|
||||
}
|
||||
|
||||
|
@ -50,8 +49,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
return RefFrame[1] > Constants.IntraFrame;
|
||||
}
|
||||
|
||||
private static readonly int[][] _idxNColumnToSubblock = {
|
||||
new[] { 1, 2 }, new[] { 1, 3 }, new[] { 3, 2 }, new[] { 3, 3 },
|
||||
private static readonly int[][] IdxNColumnToSubblock =
|
||||
{
|
||||
new[] { 1, 2 }, new[] { 1, 3 }, new[] { 3, 2 }, new[] { 3, 3 }
|
||||
};
|
||||
|
||||
// This function returns either the appropriate sub block or block's mv
|
||||
|
@ -59,8 +59,49 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
public Mv GetSubBlockMv(int whichMv, int searchCol, int blockIdx)
|
||||
{
|
||||
return blockIdx >= 0 && SbType < BlockSize.Block8x8
|
||||
? Bmi[_idxNColumnToSubblock[blockIdx][searchCol == 0 ? 1 : 0]].Mv[whichMv]
|
||||
? Bmi[IdxNColumnToSubblock[blockIdx][searchCol == 0 ? 1 : 0]].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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,4 +11,4 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
BothIntra = 6,
|
||||
InvalidCase = 9,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Graphics.Video;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
@ -12,96 +12,86 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
|
||||
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,
|
||||
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,
|
||||
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
|
||||
};
|
||||
|
||||
public readonly bool UseMvHp()
|
||||
public bool UseHp()
|
||||
{
|
||||
const int KMvRefThresh = 64; // Threshold for use of high-precision 1/8 mv
|
||||
return Math.Abs(Row) < KMvRefThresh && Math.Abs(Col) < KMvRefThresh;
|
||||
const int kMvRefThresh = 64; // Threshold for use of high-precision 1/8 mv
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
offset.Value = z - MvClassBase(c);
|
||||
offset.Value = z - ClassBase(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 */
|
||||
s = v < 0 ? 1 : 0;
|
||||
int s = v < 0 ? 1 : 0;
|
||||
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;
|
||||
|
||||
d = (o >> 3); /* Int mv data */
|
||||
f = (o >> 1) & 3; /* Fractional pel mv data */
|
||||
e = (o & 1); /* High precision mv data */
|
||||
int d = o >> 3 /* Int mv data */;
|
||||
int f = (o >> 1) & 3 /* Fractional pel 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.Class0Fp[comp][d][f] += (uint)incr;
|
||||
|
@ -109,11 +99,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
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;
|
||||
|
@ -121,56 +110,56 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
}
|
||||
}
|
||||
|
||||
private readonly MvJointType GetMvJoint()
|
||||
public MvJointType GetJoint()
|
||||
{
|
||||
if (Row == 0)
|
||||
{
|
||||
return Col == 0 ? MvJointType.MvJointZero : MvJointType.MvJointHnzvz;
|
||||
return Col == 0 ? MvJointType.Zero : MvJointType.Hnzvz;
|
||||
}
|
||||
|
||||
return Col == 0 ? MvJointType.MvJointHzvnz : MvJointType.MvJointHnzvnz;
|
||||
return Col == 0 ? MvJointType.Hzvnz : MvJointType.Hnzvnz;
|
||||
}
|
||||
|
||||
internal readonly void IncMv(Ptr<Vp9BackwardUpdates> counts)
|
||||
internal void Inc(Ptr<Vp9BackwardUpdates> counts)
|
||||
{
|
||||
if (!counts.IsNull)
|
||||
{
|
||||
MvJointType j = GetMvJoint();
|
||||
MvJointType j = GetJoint();
|
||||
++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);
|
||||
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(
|
||||
xd.MbToLeftEdge - MvBorder,
|
||||
xd.MbToRightEdge + MvBorder,
|
||||
xd.MbToTopEdge - MvBorder,
|
||||
xd.MbToBottomEdge + MvBorder);
|
||||
Clamp(
|
||||
xd.MbToLeftEdge - Border,
|
||||
xd.MbToRightEdge + Border,
|
||||
xd.MbToTopEdge - Border,
|
||||
xd.MbToBottomEdge + Border);
|
||||
}
|
||||
|
||||
public void LowerMvPrecision(bool allowHP)
|
||||
public void LowerPrecision(bool allowHp)
|
||||
{
|
||||
bool useHP = allowHP && UseMvHp();
|
||||
if (!useHP)
|
||||
bool useHp = allowHp && UseHp();
|
||||
if (!useHp)
|
||||
{
|
||||
if ((Row & 1) != 0)
|
||||
{
|
||||
|
@ -183,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,4 +5,4 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
public int Row;
|
||||
public int Col;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,16 +2,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
{
|
||||
internal enum MvClassType
|
||||
{
|
||||
MvClass0 = 0, /* (0, 2] integer pel */
|
||||
MvClass1 = 1, /* (2, 4] integer pel */
|
||||
MvClass2 = 2, /* (4, 8] integer pel */
|
||||
MvClass3 = 3, /* (8, 16] integer pel */
|
||||
MvClass4 = 4, /* (16, 32] integer pel */
|
||||
MvClass5 = 5, /* (32, 64] integer pel */
|
||||
MvClass6 = 6, /* (64, 128] integer pel */
|
||||
MvClass7 = 7, /* (128, 256] integer pel */
|
||||
MvClass8 = 8, /* (256, 512] integer pel */
|
||||
MvClass9 = 9, /* (512, 1024] integer pel */
|
||||
MvClass10 = 10, /* (1024,2048] integer pel */
|
||||
Class0, /* (0, 2] integer pel */
|
||||
Class1, /* (2, 4] integer pel */
|
||||
Class2, /* (4, 8] integer pel */
|
||||
Class3, /* (8, 16] integer pel */
|
||||
Class4, /* (16, 32] integer pel */
|
||||
Class5, /* (32, 64] integer pel */
|
||||
Class6, /* (64, 128] integer pel */
|
||||
Class7, /* (128, 256] integer pel */
|
||||
Class8, /* (256, 512] integer pel */
|
||||
Class9, /* (512, 1024] integer pel */
|
||||
Class10 /* (1024,2048] integer pel */
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,9 +2,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
{
|
||||
internal enum MvJointType
|
||||
{
|
||||
MvJointZero = 0, /* Zero vector */
|
||||
MvJointHnzvz = 1, /* Vert zero, hor nonzero */
|
||||
MvJointHzvnz = 2, /* Hor zero, vert nonzero */
|
||||
MvJointHnzvnz = 3, /* Both components nonzero */
|
||||
Zero, /* Zero vector */
|
||||
Hnzvz, /* Vert zero, hor nonzero */
|
||||
Hzvnz, /* Hor zero, vert nonzero */
|
||||
Hnzvnz /* Both components nonzero */
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,4 +7,4 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
public Array2<Mv> Mv;
|
||||
public Array2<sbyte> RefFrame;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,4 +9,4 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
PartitionTypes,
|
||||
PartitionInvalid = PartitionTypes,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
{
|
||||
internal enum PlaneType
|
||||
{
|
||||
Y = 0,
|
||||
Uv = 1,
|
||||
PlaneTypes,
|
||||
Y,
|
||||
Uv,
|
||||
PlaneTypes
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,4 +11,4 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
Col = col;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,21 +1,21 @@
|
|||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
{
|
||||
internal enum PredictionMode
|
||||
{
|
||||
DcPred = 0, // Average of above and left pixels
|
||||
VPred = 1, // Vertical
|
||||
HPred = 2, // Horizontal
|
||||
D45Pred = 3, // Directional 45 deg = round(arctan(1 / 1) * 180 / pi)
|
||||
D135Pred = 4, // Directional 135 deg = 180 - 45
|
||||
D117Pred = 5, // Directional 117 deg = 180 - 63
|
||||
D153Pred = 6, // Directional 153 deg = 180 - 27
|
||||
D207Pred = 7, // Directional 207 deg = 180 + 27
|
||||
D63Pred = 8, // Directional 63 deg = round(arctan(2 / 1) * 180 / pi)
|
||||
TmPred = 9, // True-motion
|
||||
NearestMv = 10,
|
||||
NearMv = 11,
|
||||
ZeroMv = 12,
|
||||
NewMv = 13,
|
||||
MbModeCount = 14,
|
||||
DcPred, // Average of above and left pixels
|
||||
VPred, // Vertical
|
||||
HPred, // Horizontal
|
||||
D45Pred, // Directional 45 deg = round(arctan(1 / 1) * 180 / pi)
|
||||
D135Pred, // Directional 135 deg = 180 - 45
|
||||
D117Pred, // Directional 117 deg = 180 - 63
|
||||
D153Pred, // Directional 153 deg = 180 - 27
|
||||
D207Pred, // Directional 207 deg = 180 + 27
|
||||
D63Pred, // Directional 63 deg = round(arctan(2 / 1) * 180 / pi)
|
||||
TmPred, // True-motion
|
||||
NearestMv,
|
||||
NearMv,
|
||||
ZeroMv,
|
||||
NewMv,
|
||||
MbModeCount
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
{
|
||||
internal struct RefBuffer
|
||||
{
|
||||
public const int InvalidIdx = -1; // Invalid buffer index.
|
||||
|
||||
public int Idx;
|
||||
public Surface Buf;
|
||||
public ScaleFactors Sf;
|
||||
}
|
||||
}
|
||||
}
|
12
src/Ryujinx.Graphics.Nvdec.Vp9/Types/RefCntBuffer.cs
Normal file
12
src/Ryujinx.Graphics.Nvdec.Vp9/Types/RefCntBuffer.cs
Normal 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;
|
||||
}
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
{
|
||||
internal enum ReferenceMode
|
||||
{
|
||||
SingleReference = 0,
|
||||
CompoundReference = 1,
|
||||
ReferenceModeSelect = 2,
|
||||
ReferenceModes = 3,
|
||||
Single,
|
||||
Compound,
|
||||
Select,
|
||||
ReferenceModes
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System.Runtime.CompilerServices;
|
||||
using static Ryujinx.Graphics.Nvdec.Vp9.Dsp.Convolve;
|
||||
using static Ryujinx.Graphics.Nvdec.Vp9.Dsp.Filter;
|
||||
|
@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
internal struct ScaleFactors
|
||||
{
|
||||
private const int RefScaleShift = 14;
|
||||
private const int RefNoScale = (1 << RefScaleShift);
|
||||
private const int RefNoScale = 1 << RefScaleShift;
|
||||
private const int RefInvalidScale = -1;
|
||||
|
||||
private unsafe delegate void ConvolveFn(
|
||||
|
@ -38,255 +38,114 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
int h,
|
||||
int bd);
|
||||
|
||||
private static readonly unsafe ConvolveFn[][][] _predictX16Y16 = {
|
||||
private static readonly unsafe ConvolveFn[][][] PredictX16Y16 =
|
||||
{
|
||||
new[]
|
||||
{
|
||||
new ConvolveFn[]
|
||||
{
|
||||
ConvolveCopy,
|
||||
ConvolveAvg,
|
||||
},
|
||||
new ConvolveFn[]
|
||||
{
|
||||
Convolve8Vert,
|
||||
Convolve8AvgVert,
|
||||
},
|
||||
new ConvolveFn[] { ConvolveCopy, ConvolveAvg },
|
||||
new ConvolveFn[] { Convolve8Vert, Convolve8AvgVert }
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new ConvolveFn[]
|
||||
{
|
||||
Convolve8Horiz,
|
||||
Convolve8AvgHoriz,
|
||||
},
|
||||
new ConvolveFn[]
|
||||
{
|
||||
Convolve8,
|
||||
Convolve8Avg,
|
||||
},
|
||||
},
|
||||
new ConvolveFn[] { Convolve8Horiz, Convolve8AvgHoriz },
|
||||
new ConvolveFn[] { Convolve8, Convolve8Avg }
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly unsafe ConvolveFn[][][] _predictX16 = {
|
||||
private static readonly unsafe ConvolveFn[][][] PredictX16 =
|
||||
{
|
||||
new[]
|
||||
{
|
||||
new ConvolveFn[]
|
||||
{
|
||||
ScaledVert,
|
||||
ScaledAvgVert,
|
||||
},
|
||||
new ConvolveFn[]
|
||||
{
|
||||
ScaledVert,
|
||||
ScaledAvgVert,
|
||||
},
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new ConvolveFn[]
|
||||
{
|
||||
Scaled2D,
|
||||
ScaledAvg2D,
|
||||
},
|
||||
new ConvolveFn[]
|
||||
{
|
||||
Scaled2D,
|
||||
ScaledAvg2D,
|
||||
},
|
||||
new ConvolveFn[] { ScaledVert, ScaledAvgVert }, new ConvolveFn[] { ScaledVert, ScaledAvgVert }
|
||||
},
|
||||
new[] { new ConvolveFn[] { Scaled2D, ScaledAvg2D }, new ConvolveFn[] { Scaled2D, ScaledAvg2D } }
|
||||
};
|
||||
|
||||
private static readonly unsafe ConvolveFn[][][] _predictY16 = {
|
||||
new[]
|
||||
{
|
||||
new ConvolveFn[]
|
||||
{
|
||||
ScaledHoriz,
|
||||
ScaledAvgHoriz,
|
||||
},
|
||||
new ConvolveFn[]
|
||||
{
|
||||
Scaled2D,
|
||||
ScaledAvg2D,
|
||||
},
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new ConvolveFn[]
|
||||
{
|
||||
ScaledHoriz,
|
||||
ScaledAvgHoriz,
|
||||
},
|
||||
new ConvolveFn[]
|
||||
{
|
||||
Scaled2D,
|
||||
ScaledAvg2D,
|
||||
},
|
||||
},
|
||||
private static readonly unsafe ConvolveFn[][][] PredictY16 =
|
||||
{
|
||||
new[] { new ConvolveFn[] { ScaledHoriz, ScaledAvgHoriz }, new ConvolveFn[] { Scaled2D, ScaledAvg2D } },
|
||||
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 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 = {
|
||||
private static readonly unsafe HighbdConvolveFn[][][] HighbdPredictX16Y16 =
|
||||
{
|
||||
new[]
|
||||
{
|
||||
new HighbdConvolveFn[]
|
||||
{
|
||||
HighbdConvolveCopy,
|
||||
HighbdConvolveAvg,
|
||||
},
|
||||
new HighbdConvolveFn[]
|
||||
{
|
||||
HighbdConvolve8Vert,
|
||||
HighbdConvolve8AvgVert,
|
||||
},
|
||||
new HighbdConvolveFn[] { HighbdConvolveCopy, HighbdConvolveAvg },
|
||||
new HighbdConvolveFn[] { HighbdConvolve8Vert, HighbdConvolve8AvgVert }
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new HighbdConvolveFn[]
|
||||
{
|
||||
HighbdConvolve8Horiz,
|
||||
HighbdConvolve8AvgHoriz,
|
||||
},
|
||||
new HighbdConvolveFn[]
|
||||
{
|
||||
HighbdConvolve8,
|
||||
HighbdConvolve8Avg,
|
||||
},
|
||||
},
|
||||
new HighbdConvolveFn[] { HighbdConvolve8Horiz, HighbdConvolve8AvgHoriz },
|
||||
new HighbdConvolveFn[] { HighbdConvolve8, HighbdConvolve8Avg }
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly unsafe HighbdConvolveFn[][][] _highbdPredictX16 = {
|
||||
private static readonly unsafe HighbdConvolveFn[][][] HighbdPredictX16 =
|
||||
{
|
||||
new[]
|
||||
{
|
||||
new HighbdConvolveFn[]
|
||||
{
|
||||
HighbdConvolve8Vert,
|
||||
HighbdConvolve8AvgVert,
|
||||
},
|
||||
new HighbdConvolveFn[]
|
||||
{
|
||||
HighbdConvolve8Vert,
|
||||
HighbdConvolve8AvgVert,
|
||||
},
|
||||
new HighbdConvolveFn[] { HighbdConvolve8Vert, HighbdConvolve8AvgVert },
|
||||
new HighbdConvolveFn[] { HighbdConvolve8Vert, HighbdConvolve8AvgVert }
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new HighbdConvolveFn[]
|
||||
{
|
||||
HighbdConvolve8,
|
||||
HighbdConvolve8Avg,
|
||||
},
|
||||
new HighbdConvolveFn[]
|
||||
{
|
||||
HighbdConvolve8,
|
||||
HighbdConvolve8Avg,
|
||||
},
|
||||
},
|
||||
new HighbdConvolveFn[] { HighbdConvolve8, HighbdConvolve8Avg },
|
||||
new HighbdConvolveFn[] { HighbdConvolve8, HighbdConvolve8Avg }
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly unsafe HighbdConvolveFn[][][] _highbdPredictY16 = {
|
||||
private static readonly unsafe HighbdConvolveFn[][][] HighbdPredictY16 =
|
||||
{
|
||||
new[]
|
||||
{
|
||||
new HighbdConvolveFn[]
|
||||
{
|
||||
HighbdConvolve8Horiz,
|
||||
HighbdConvolve8AvgHoriz,
|
||||
},
|
||||
new HighbdConvolveFn[]
|
||||
{
|
||||
HighbdConvolve8,
|
||||
HighbdConvolve8Avg,
|
||||
},
|
||||
new HighbdConvolveFn[] { HighbdConvolve8Horiz, HighbdConvolve8AvgHoriz },
|
||||
new HighbdConvolveFn[] { HighbdConvolve8, HighbdConvolve8Avg }
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new HighbdConvolveFn[]
|
||||
{
|
||||
HighbdConvolve8Horiz,
|
||||
HighbdConvolve8AvgHoriz,
|
||||
},
|
||||
new HighbdConvolveFn[]
|
||||
{
|
||||
HighbdConvolve8,
|
||||
HighbdConvolve8Avg,
|
||||
},
|
||||
},
|
||||
new HighbdConvolveFn[] { HighbdConvolve8Horiz, HighbdConvolve8AvgHoriz },
|
||||
new HighbdConvolveFn[] { HighbdConvolve8, HighbdConvolve8Avg }
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly unsafe HighbdConvolveFn[][][] _highbdPredict = {
|
||||
private static readonly unsafe HighbdConvolveFn[][][] HighbdPredict =
|
||||
{
|
||||
new[]
|
||||
{
|
||||
new HighbdConvolveFn[]
|
||||
{
|
||||
HighbdConvolve8,
|
||||
HighbdConvolve8Avg,
|
||||
},
|
||||
new HighbdConvolveFn[]
|
||||
{
|
||||
HighbdConvolve8,
|
||||
HighbdConvolve8Avg,
|
||||
},
|
||||
new HighbdConvolveFn[] { HighbdConvolve8, HighbdConvolve8Avg },
|
||||
new HighbdConvolveFn[] { HighbdConvolve8, HighbdConvolve8Avg }
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new HighbdConvolveFn[]
|
||||
{
|
||||
HighbdConvolve8,
|
||||
HighbdConvolve8Avg,
|
||||
},
|
||||
new HighbdConvolveFn[]
|
||||
{
|
||||
HighbdConvolve8,
|
||||
HighbdConvolve8Avg,
|
||||
},
|
||||
},
|
||||
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 XScaleFp; // Horizontal fixed point scale factor
|
||||
public int YScaleFp; // Vertical fixed point scale factor
|
||||
public int XStepQ4;
|
||||
public int YStepQ4;
|
||||
|
||||
public readonly int ScaleValueX(int val)
|
||||
public int ScaleValueX(int val)
|
||||
{
|
||||
return IsScaled() ? ScaledX(val) : val;
|
||||
}
|
||||
|
||||
public readonly int ScaleValueY(int val)
|
||||
public int ScaleValueY(int val)
|
||||
{
|
||||
return IsScaled() ? ScaledY(val) : val;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public readonly unsafe void InterPredict(
|
||||
public unsafe void InterPredict(
|
||||
int horiz,
|
||||
int vert,
|
||||
int avg,
|
||||
|
@ -307,12 +166,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
if (YStepQ4 == 16)
|
||||
{
|
||||
// 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
|
||||
{
|
||||
// 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
|
||||
|
@ -320,18 +181,19 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
if (YStepQ4 == 16)
|
||||
{
|
||||
// No scaling in the y direction. Must always scale in the x direction.
|
||||
_predictY16[horiz][vert][avg](src, srcStride, dst, dstStride, kernel, subpelX, xs, subpelY, ys, w, h);
|
||||
PredictY16[horiz][vert][avg](src, srcStride, dst, dstStride, kernel, subpelX, xs, subpelY, ys, w,
|
||||
h);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Must always scale in both directions.
|
||||
_predict[horiz][vert][avg](src, srcStride, dst, dstStride, kernel, subpelX, xs, subpelY, ys, w, h);
|
||||
Predict[horiz][vert][avg](src, srcStride, dst, dstStride, kernel, subpelX, xs, subpelY, ys, w, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public readonly unsafe void HighbdInterPredict(
|
||||
public unsafe void HighbdInterPredict(
|
||||
int horiz,
|
||||
int vert,
|
||||
int avg,
|
||||
|
@ -353,12 +215,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
if (YStepQ4 == 16)
|
||||
{
|
||||
// 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
|
||||
{
|
||||
// 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
|
||||
|
@ -366,24 +230,26 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
if (YStepQ4 == 16)
|
||||
{
|
||||
// No scaling in the y direction. Must always scale in the x direction.
|
||||
_highbdPredictY16[horiz][vert][avg](src, srcStride, dst, dstStride, kernel, subpelX, xs, subpelY, ys, w, h, bd);
|
||||
HighbdPredictY16[horiz][vert][avg](src, srcStride, dst, dstStride, kernel, subpelX, xs, subpelY, ys,
|
||||
w, h, bd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Must always scale in both directions.
|
||||
_highbdPredict[horiz][vert][avg](src, srcStride, dst, dstStride, kernel, subpelX, xs, subpelY, ys, w, h, bd);
|
||||
HighbdPredict[horiz][vert][avg](src, srcStride, dst, dstStride, kernel, subpelX, xs, subpelY, ys, w,
|
||||
h, bd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly int ScaledX(int val)
|
||||
private int ScaledX(int val)
|
||||
{
|
||||
return (int)((long)val * XScaleFP >> RefScaleShift);
|
||||
return (int)(((long)val * XScaleFp) >> RefScaleShift);
|
||||
}
|
||||
|
||||
private readonly 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)
|
||||
|
@ -399,23 +265,18 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
{
|
||||
int xOffQ4 = ScaledX(x << SubpelBits) & SubpelMask;
|
||||
int yOffQ4 = ScaledY(y << SubpelBits) & SubpelMask;
|
||||
Mv32 res = new()
|
||||
{
|
||||
Row = ScaledY(mv.Row) + yOffQ4,
|
||||
Col = ScaledX(mv.Col) + xOffQ4,
|
||||
};
|
||||
|
||||
Mv32 res = new() { Row = ScaledY(mv.Row) + yOffQ4, Col = ScaledX(mv.Col) + xOffQ4 };
|
||||
return res;
|
||||
}
|
||||
|
||||
public readonly bool IsValidScale()
|
||||
public bool IsValidScale()
|
||||
{
|
||||
return XScaleFP != RefInvalidScale && YScaleFP != RefInvalidScale;
|
||||
return XScaleFp != RefInvalidScale && YScaleFp != RefInvalidScale;
|
||||
}
|
||||
|
||||
public readonly 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)
|
||||
|
@ -430,16 +291,15 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
{
|
||||
if (!ValidRefFrameSize(otherW, otherH, thisW, thisH))
|
||||
{
|
||||
XScaleFP = RefInvalidScale;
|
||||
YScaleFP = RefInvalidScale;
|
||||
|
||||
XScaleFp = RefInvalidScale;
|
||||
YScaleFp = RefInvalidScale;
|
||||
return;
|
||||
}
|
||||
|
||||
XScaleFP = GetFixedPointScaleFactor(otherW, thisW);
|
||||
YScaleFP = GetFixedPointScaleFactor(otherH, thisH);
|
||||
XScaleFp = GetFixedPointScaleFactor(otherW, thisW);
|
||||
YScaleFp = GetFixedPointScaleFactor(otherH, thisH);
|
||||
XStepQ4 = ScaledX(16);
|
||||
YStepQ4 = ScaledY(16);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
{
|
||||
internal enum SegLvlFeatures
|
||||
{
|
||||
SegLvlAltQ = 0, // Use alternate Quantizer ....
|
||||
SegLvlAltLf = 1, // Use alternate loop filter value...
|
||||
SegLvlRefFrame = 2, // Optional Segment reference frame
|
||||
SegLvlSkip = 3, // Optional Segment (0,0) + skip mode
|
||||
SegLvlMax = 4, // Number of features supported
|
||||
AltQ, // Use alternate Quantizer ....
|
||||
AltLf, // Use alternate loop filter value...
|
||||
RefFrame, // Optional Segment reference frame
|
||||
Skip, // Optional Segment (0,0) + skip mode
|
||||
Max // Number of features supported
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Graphics.Video;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
|
@ -6,8 +8,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
{
|
||||
internal struct Segmentation
|
||||
{
|
||||
private static readonly int[] _segFeatureDataSigned = { 1, 1, 0, 0 };
|
||||
private static readonly int[] _segFeatureDataMax = { QuantCommon.MaxQ, Vp9.LoopFilter.MaxLoopFilter, 3, 0 };
|
||||
public const int SegmentDeltadata = 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 UpdateMap;
|
||||
|
@ -38,21 +48,21 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
|
||||
internal static int FeatureDataMax(SegLvlFeatures featureId)
|
||||
{
|
||||
return _segFeatureDataMax[(int)featureId];
|
||||
return SegFeatureDataMax[(int)featureId];
|
||||
}
|
||||
|
||||
internal static int IsSegFeatureSigned(SegLvlFeatures featureId)
|
||||
{
|
||||
return _segFeatureDataSigned[(int)featureId];
|
||||
return SegFeatureDataSigned[(int)featureId];
|
||||
}
|
||||
|
||||
internal void SetSegData(int segmentId, SegLvlFeatures featureId, int segData)
|
||||
{
|
||||
Debug.Assert(segData <= _segFeatureDataMax[(int)featureId]);
|
||||
Debug.Assert(segData <= SegFeatureDataMax[(int)featureId]);
|
||||
if (segData < 0)
|
||||
{
|
||||
Debug.Assert(_segFeatureDataSigned[(int)featureId] != 0);
|
||||
Debug.Assert(-segData <= _segFeatureDataMax[(int)featureId]);
|
||||
Debug.Assert(SegFeatureDataSigned[(int)featureId] != 0);
|
||||
Debug.Assert(-segData <= SegFeatureDataMax[(int)featureId]);
|
||||
}
|
||||
|
||||
FeatureData[segmentId][(int)featureId] = (short)segData;
|
||||
|
@ -67,5 +77,88 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,23 @@
|
|||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Graphics.Nvdec.Vp9.Common;
|
||||
using Ryujinx.Graphics.Video;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
{
|
||||
internal delegate int VpxGetFrameBufferCbFnT(MemoryAllocator allocator, Ptr<InternalFrameBufferList> cbPriv,
|
||||
ulong minSize, ref VpxCodecFrameBuffer fb);
|
||||
|
||||
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> UBuffer;
|
||||
public ArrayPtr<byte> VBuffer;
|
||||
|
@ -14,43 +26,62 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
public readonly unsafe Plane UPlane => new((nint)UBuffer.ToPointer(), UBuffer.Length);
|
||||
public readonly unsafe Plane VPlane => new((nint)VBuffer.ToPointer(), VBuffer.Length);
|
||||
|
||||
public readonly FrameField Field => FrameField.Progressive;
|
||||
public FrameField Field => FrameField.Progressive;
|
||||
|
||||
public int Width { get; }
|
||||
public int Height { get; }
|
||||
public int AlignedWidth { get; }
|
||||
public int AlignedHeight { get; }
|
||||
public int Stride { get; }
|
||||
public int UvWidth { get; }
|
||||
public int UvHeight { get; }
|
||||
public int UvAlignedWidth { get; }
|
||||
public int UvAlignedHeight { get; }
|
||||
public int UvStride { get; }
|
||||
public int Width { get; private set; }
|
||||
public int Height { get; private set; }
|
||||
public int AlignedWidth { get; private set; }
|
||||
public int AlignedHeight { get; private set; }
|
||||
public int Stride { get; private set; }
|
||||
public int UvWidth { get; private set; }
|
||||
public int UvHeight { get; private set; }
|
||||
public int UvAlignedWidth { get; private set; }
|
||||
public int UvAlignedHeight { get; private set; }
|
||||
public int UvStride { get; private set; }
|
||||
public bool HighBd { get; private set; }
|
||||
|
||||
public bool HighBd { get; }
|
||||
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 nint _pointer;
|
||||
|
||||
public Surface(int width, int height)
|
||||
{
|
||||
HighBd = false;
|
||||
|
||||
const int Border = 32;
|
||||
const int SsX = 1;
|
||||
const int SsY = 1;
|
||||
const int border = 32;
|
||||
const int ssX = 1;
|
||||
const int ssY = 1;
|
||||
const bool highbd = false;
|
||||
|
||||
int alignedWidth = (width + 7) & ~7;
|
||||
int alignedHeight = (height + 7) & ~7;
|
||||
int yStride = ((alignedWidth + 2 * Border) + 31) & ~31;
|
||||
int yplaneSize = (alignedHeight + 2 * Border) * yStride;
|
||||
int uvWidth = alignedWidth >> SsX;
|
||||
int uvHeight = alignedHeight >> SsY;
|
||||
int uvStride = yStride >> SsX;
|
||||
int uvBorderW = Border >> SsX;
|
||||
int uvBorderH = Border >> SsY;
|
||||
int uvplaneSize = (uvHeight + 2 * uvBorderH) * uvStride;
|
||||
int yStride = (alignedWidth + (2 * border) + 31) & ~31;
|
||||
int yplaneSize = (alignedHeight + (2 * border)) * yStride;
|
||||
int uvWidth = alignedWidth >> ssX;
|
||||
int uvHeight = alignedHeight >> ssY;
|
||||
int uvStride = yStride >> ssX;
|
||||
int uvBorderW = border >> ssX;
|
||||
int uvBorderH = border >> ssY;
|
||||
int uvplaneSize = (uvHeight + (2 * uvBorderH)) * uvStride;
|
||||
|
||||
int frameSize = (HighBd ? 2 : 1) * (yplaneSize + 2 * uvplaneSize);
|
||||
int frameSize = (highbd ? 2 : 1) * (yplaneSize + (2 * uvplaneSize));
|
||||
|
||||
nint pointer = Marshal.AllocHGlobal(frameSize);
|
||||
_pointer = pointer;
|
||||
|
@ -59,23 +90,148 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
AlignedWidth = alignedWidth;
|
||||
AlignedHeight = alignedHeight;
|
||||
Stride = yStride;
|
||||
UvWidth = (width + SsX) >> SsX;
|
||||
UvHeight = (height + SsY) >> SsY;
|
||||
UvWidth = (width + ssX) >> ssX;
|
||||
UvHeight = (height + ssY) >> ssY;
|
||||
UvAlignedWidth = uvWidth;
|
||||
UvAlignedHeight = uvHeight;
|
||||
UvStride = uvStride;
|
||||
|
||||
ArrayPtr<byte> NewPlane(int start, int size, int planeBorder)
|
||||
ArrayPtr<byte> NewPlane(int start, int size, int border)
|
||||
{
|
||||
return new ArrayPtr<byte>(pointer + start + planeBorder, size - planeBorder);
|
||||
return new ArrayPtr<byte>(pointer + start + border, size - border);
|
||||
}
|
||||
|
||||
YBuffer = NewPlane(0, yplaneSize, (Border * yStride) + Border);
|
||||
YBuffer = NewPlane(0, yplaneSize, (border * yStride) + border);
|
||||
UBuffer = NewPlane(yplaneSize, uvplaneSize, (uvBorderH * uvStride) + uvBorderW);
|
||||
VBuffer = NewPlane(yplaneSize + uvplaneSize, uvplaneSize, (uvBorderH * uvStride) + uvBorderW);
|
||||
}
|
||||
|
||||
public readonly void Dispose()
|
||||
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()
|
||||
{
|
||||
Marshal.FreeHGlobal(_pointer);
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
private static int GetMinLog2TileCols(int sb64Cols)
|
||||
{
|
||||
int minLog2 = 0;
|
||||
while ((MaxTileWidthB64 << minLog2) < sb64Cols)
|
||||
while (MaxTileWidthB64 << minLog2 < sb64Cols)
|
||||
{
|
||||
++minLog2;
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
private static int GetMaxLog2TileCols(int sb64Cols)
|
||||
{
|
||||
int maxLog2 = 1;
|
||||
while ((sb64Cols >> maxLog2) >= MinTileWidthB64)
|
||||
while (sb64Cols >> maxLog2 >= MinTileWidthB64)
|
||||
{
|
||||
++maxLog2;
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
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;
|
||||
minLog2TileCols = GetMinLog2TileCols(sb64Cols);
|
||||
|
@ -83,4 +83,4 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
Debug.Assert(minLog2TileCols <= maxLog2TileCols);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +1,12 @@
|
|||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
{
|
||||
public enum TxMode
|
||||
{
|
||||
Only4X4 = 0, // Only 4x4 transform used
|
||||
Allow8X8 = 1, // Allow block transform size up to 8x8
|
||||
Allow16X16 = 2, // Allow block transform size up to 16x16
|
||||
Allow32X32 = 3, // Allow block transform size up to 32x32
|
||||
TxModeSelect = 4, // Transform specified for each block
|
||||
TxModes = 5,
|
||||
Only4x4, // Only 4x4 transform used
|
||||
Allow8x8, // Allow block transform size up to 8x8
|
||||
Allow16x16, // Allow block transform size up to 16x16
|
||||
Allow32x32, // Allow block transform size up to 32x32
|
||||
TxModeSelect, // Transform specified for each block
|
||||
TxModes
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
{
|
||||
public enum TxSize
|
||||
{
|
||||
Tx4x4 = 0, // 4x4 transform
|
||||
Tx8x8 = 1, // 8x8 transform
|
||||
Tx16x16 = 2, // 16x16 transform
|
||||
Tx32x32 = 3, // 32x32 transform
|
||||
TxSizes = 4,
|
||||
Tx4x4, // 4x4 transform
|
||||
Tx8x8, // 8x8 transform
|
||||
Tx16x16, // 16x16 transform
|
||||
Tx32x32, // 32x32 transform
|
||||
TxSizes
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
{
|
||||
internal enum TxType
|
||||
{
|
||||
DctDct = 0, // DCT in both horizontal and vertical
|
||||
AdstDct = 1, // ADST in vertical, DCT in horizontal
|
||||
DctAdst = 2, // DCT in vertical, ADST in horizontal
|
||||
AdstAdst = 3, // ADST in both directions
|
||||
TxTypes = 4,
|
||||
DctDct, // DCT in both horizontal and vertical
|
||||
AdstDct, // ADST in vertical, DCT in horizontal
|
||||
DctAdst, // DCT in vertical, ADST in horizontal
|
||||
AdstAdst, // ADST in both directions
|
||||
TxTypes
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Graphics.Nvdec.Vp9.Common;
|
||||
using Ryujinx.Graphics.Nvdec.Vp9.Dsp;
|
||||
using Ryujinx.Graphics.Video;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
{
|
||||
|
@ -9,27 +11,62 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
public MacroBlockD Mb;
|
||||
|
||||
public ArrayPtr<TileWorkerData> TileWorkerData;
|
||||
public int TotalTiles;
|
||||
|
||||
public InternalErrorInfo Error;
|
||||
|
||||
public VpxColorSpace ColorSpace;
|
||||
public VpxColorRange ColorRange;
|
||||
|
||||
public int Width;
|
||||
public int Height;
|
||||
|
||||
public int RenderWidth;
|
||||
public int RenderHeight;
|
||||
|
||||
public int LastWidth;
|
||||
public int LastHeight;
|
||||
|
||||
public int SubsamplingX;
|
||||
public int SubsamplingY;
|
||||
|
||||
public bool UseHighBitDepth;
|
||||
|
||||
public ArrayPtr<MvRef> PrevFrameMvs;
|
||||
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 int NewFbIdx;
|
||||
|
||||
public int CurShowFrameFbIdx;
|
||||
|
||||
public FrameType LastFrameType;
|
||||
public FrameType FrameType;
|
||||
|
||||
public int ShowFrame;
|
||||
public int LastShowFrame;
|
||||
public int ShowExistingFrame;
|
||||
|
||||
// Flag signaling that the frame is encoded using only Intra modes.
|
||||
public bool IntraOnly;
|
||||
public bool LastIntraOnly;
|
||||
|
||||
public bool AllowHighPrecisionMv;
|
||||
|
||||
public int ResetFrameContext;
|
||||
|
||||
// MBs, MbRows/Cols is in 16-pixel units; MiRows/Cols is in
|
||||
// ModeInfo (8-pixel) units.
|
||||
public int MBs;
|
||||
|
@ -49,8 +86,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
|
||||
/* We allocate a ModeInfo struct for each macroblock, together with
|
||||
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> 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>> MiGridVisible;
|
||||
|
@ -70,6 +112,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
|
||||
public LoopFilterInfoN LfInfo;
|
||||
|
||||
public int RefreshFrameContext; /* Two state 0 = NO, 1 = YES */
|
||||
|
||||
public Array4<sbyte> RefFrameSignBias; /* Two state 0, 1 */
|
||||
|
||||
public LoopFilter Lf;
|
||||
|
@ -81,22 +125,37 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
public ReferenceMode ReferenceMode;
|
||||
|
||||
public Ptr<Vp9EntropyProbs> Fc;
|
||||
public ArrayPtr<Vp9EntropyProbs> FrameContexts; // FRAME_CONTEXTS
|
||||
public uint FrameContextIdx; /* Context to use/update */
|
||||
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 ByteAlignment;
|
||||
public int SkipLoopFilter;
|
||||
|
||||
public Ptr<BufferPool> BufferPool;
|
||||
|
||||
public ArrayPtr<sbyte> AboveSegContext;
|
||||
public ArrayPtr<sbyte> AboveContext;
|
||||
|
||||
public readonly bool FrameIsIntraOnly()
|
||||
public bool FrameIsIntraOnly()
|
||||
{
|
||||
return FrameType == FrameType.KeyFrame || IntraOnly;
|
||||
}
|
||||
|
||||
public bool CompoundReferenceAllowed()
|
||||
{
|
||||
int i;
|
||||
for (i = 1; i < Constants.RefsPerFrame; ++i)
|
||||
for (int i = 1; i < Constants.RefsPerFrame; ++i)
|
||||
{
|
||||
if (RefFrameSignBias[i + 1] != RefFrameSignBias[1])
|
||||
{
|
||||
|
@ -107,6 +166,47 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
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)
|
||||
{
|
||||
// Len is in mi units.
|
||||
|
@ -129,19 +229,18 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
|
||||
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 readonly void FreeTileWorkerData(MemoryAllocator allocator)
|
||||
public void FreeTileWorkerData(MemoryAllocator allocator)
|
||||
{
|
||||
allocator.Free(TileWorkerData);
|
||||
}
|
||||
|
||||
private void AllocSegMap(MemoryAllocator allocator, int segMapSize)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < Constants.NumPingPongBuffers; ++i)
|
||||
for (int i = 0; i < Constants.NumPingPongBuffers; ++i)
|
||||
{
|
||||
SegMapArray[i] = allocator.Allocate<byte>(segMapSize);
|
||||
}
|
||||
|
@ -156,9 +255,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
|
||||
private void FreeSegMap(MemoryAllocator allocator)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < Constants.NumPingPongBuffers; ++i)
|
||||
for (int i = 0; i < Constants.NumPingPongBuffers; ++i)
|
||||
{
|
||||
allocator.Free(SegMapArray[i]);
|
||||
SegMapArray[i] = ArrayPtr<byte>.Null;
|
||||
|
@ -194,6 +291,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
Lf.Lfm = ArrayPtr<LoopFilterMask>.Null;
|
||||
allocator.Free(CurFrameMvs);
|
||||
CurFrameMvs = ArrayPtr<MvRef>.Null;
|
||||
|
||||
if (UsePrevFrameMvs)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
public void AllocContextBuffers(MemoryAllocator allocator, int width, int height)
|
||||
public bool AllocContextBuffers(MemoryAllocator allocator, int width, int height)
|
||||
{
|
||||
SetMbMi(width, height);
|
||||
int newMiSize = MiStride * CalcMiSize(MiRows);
|
||||
|
@ -239,6 +337,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
{
|
||||
PrevFrameMvs = allocator.Allocate<MvRef>(MiRows * MiCols);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private unsafe void DecSetupMi()
|
||||
|
@ -257,7 +357,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
}
|
||||
}
|
||||
|
||||
private readonly void SetPartitionProbs(ref MacroBlockD xd)
|
||||
private void SetPartitionProbs(ref MacroBlockD xd)
|
||||
{
|
||||
xd.PartitionProbs = FrameIsIntraOnly()
|
||||
? new ArrayPtr<Array3<byte>>(ref Fc.Value.KfPartitionProb[0], 16)
|
||||
|
@ -266,9 +366,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
|
||||
internal void InitMacroBlockD(ref MacroBlockD xd, ArrayPtr<int> dqcoeff)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < Constants.MaxMbPlane; ++i)
|
||||
for (int i = 0; i < Constants.MaxMbPlane; ++i)
|
||||
{
|
||||
xd.Plane[i].DqCoeff = dqcoeff;
|
||||
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);
|
||||
}
|
||||
|
||||
xd.Fc = new Ptr<Vp9EntropyProbs>(ref Fc.Value);
|
||||
}
|
||||
|
||||
|
@ -293,29 +392,27 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||
|
||||
public void SetupSegmentationDequant()
|
||||
{
|
||||
const BitDepth BitDepth = BitDepth.Bits8; // TODO: Configurable
|
||||
// Build y/uv dequant values based on segmentation.
|
||||
if (Seg.Enabled)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < Constants.MaxSegments; ++i)
|
||||
for (int i = 0; i < Constants.MaxSegments; ++i)
|
||||
{
|
||||
int qIndex = QuantCommon.GetQIndex(ref Seg, i, BaseQindex);
|
||||
YDequant[i][0] = QuantCommon.DcQuant(qIndex, YDcDeltaQ, BitDepth);
|
||||
YDequant[i][1] = QuantCommon.AcQuant(qIndex, 0, BitDepth);
|
||||
UvDequant[i][0] = QuantCommon.DcQuant(qIndex, UvDcDeltaQ, BitDepth);
|
||||
UvDequant[i][1] = QuantCommon.AcQuant(qIndex, UvAcDeltaQ, BitDepth);
|
||||
int qindex = Seg.GetQIndex(i, BaseQindex);
|
||||
YDequant[i][0] = QuantCommon.DcQuant(qindex, YDcDeltaQ, BitDepth);
|
||||
YDequant[i][1] = QuantCommon.AcQuant(qindex, 0, BitDepth);
|
||||
UvDequant[i][0] = QuantCommon.DcQuant(qindex, UvDcDeltaQ, BitDepth);
|
||||
UvDequant[i][1] = QuantCommon.AcQuant(qindex, UvAcDeltaQ, BitDepth);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int qIndex = BaseQindex;
|
||||
int qindex = BaseQindex;
|
||||
// When segmentation is disabled, only the first value is used. The
|
||||
// remaining are don't cares.
|
||||
YDequant[0][0] = QuantCommon.DcQuant(qIndex, YDcDeltaQ, BitDepth);
|
||||
YDequant[0][1] = QuantCommon.AcQuant(qIndex, 0, BitDepth);
|
||||
UvDequant[0][0] = QuantCommon.DcQuant(qIndex, UvDcDeltaQ, BitDepth);
|
||||
UvDequant[0][1] = QuantCommon.AcQuant(qIndex, UvAcDeltaQ, BitDepth);
|
||||
YDequant[0][0] = QuantCommon.DcQuant(qindex, YDcDeltaQ, BitDepth);
|
||||
YDequant[0][1] = QuantCommon.AcQuant(qindex, 0, BitDepth);
|
||||
UvDequant[0][0] = QuantCommon.DcQuant(qindex, UvDcDeltaQ, 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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
410
src/Ryujinx.Graphics.Nvdec.Vp9/Types/Vp9Decoder.cs
Normal file
410
src/Ryujinx.Graphics.Nvdec.Vp9/Types/Vp9Decoder.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
10
src/Ryujinx.Graphics.Nvdec.Vp9/Types/VpxCodecFrameBuffer.cs
Normal file
10
src/Ryujinx.Graphics.Nvdec.Vp9/Types/VpxCodecFrameBuffer.cs
Normal 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;
|
||||
}
|
||||
}
|
11
src/Ryujinx.Graphics.Nvdec.Vp9/Types/VpxColorRange.cs
Normal file
11
src/Ryujinx.Graphics.Nvdec.Vp9/Types/VpxColorRange.cs
Normal 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
|
||||
}
|
||||
}
|
29
src/Ryujinx.Graphics.Nvdec.Vp9/Types/VpxColorSpace.cs
Normal file
29
src/Ryujinx.Graphics.Nvdec.Vp9/Types/VpxColorSpace.cs
Normal 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
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue