aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Nvdec.Vp9/Types/MacroBlockD.cs
blob: 6305664dfe7bdc1d0fa357ace7e45578483b4a09 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.Video;

namespace Ryujinx.Graphics.Nvdec.Vp9.Types
{
    internal struct MacroBlockD
    {
        public Array3<MacroBlockDPlane> Plane;
        public byte BmodeBlocksWl;
        public byte BmodeBlocksHl;

        public Ptr<Vp9BackwardUpdates> Counts;
        public TileInfo Tile;

        public int MiStride;

        // Grid of 8x8 cells is placed over the block.
        // If some of them belong to the same mbtree-block
        // they will just have same mi[i][j] value
        public ArrayPtr<Ptr<ModeInfo>> Mi;
        public Ptr<ModeInfo> LeftMi;
        public Ptr<ModeInfo> AboveMi;

        public uint MaxBlocksWide;
        public uint MaxBlocksHigh;

        public ArrayPtr<Array3<byte>> PartitionProbs;

        /* Distance of MB away from frame edges */
        public int MbToLeftEdge;
        public int MbToRightEdge;
        public int MbToTopEdge;
        public int MbToBottomEdge;

        public Ptr<Vp9EntropyProbs> Fc;

        /* pointers to reference frames */
        public Array2<Ptr<RefBuffer>> BlockRefs;

        /* pointer to current frame */
        public Surface CurBuf;

        public Array3<ArrayPtr<sbyte>> AboveContext;
        public Array3<Array16<sbyte>> LeftContext;

        public ArrayPtr<sbyte> AboveSegContext;
        public Array8<sbyte> LeftSegContext;

        /* Bit depth: 8, 10, 12 */
        public int Bd;

        public bool Lossless;
        public bool Corrupted;

        public Ptr<InternalErrorInfo> ErrorInfo;

        public readonly int GetPredContextSegId()
        {
            sbyte aboveSip = !AboveMi.IsNull ? AboveMi.Value.SegIdPredicted : (sbyte)0;
            sbyte leftSip = !LeftMi.IsNull ? LeftMi.Value.SegIdPredicted : (sbyte)0;

            return aboveSip + leftSip;
        }

        public readonly 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()
        {
            // Note:
            // The mode info data structure has a one element border above and to the
            // left of the entries corresponding to real macroblocks.
            // The prediction flags in these dummy entries are initialized to 0.
            int leftType = !LeftMi.IsNull ? LeftMi.Value.InterpFilter : Constants.SwitchableFilters;
            int aboveType = !AboveMi.IsNull ? AboveMi.Value.InterpFilter : Constants.SwitchableFilters;

            if (leftType == aboveType)
            {
                return leftType;
            }
            else if (leftType == Constants.SwitchableFilters)
            {
                return aboveType;
            }
            else if (aboveType == Constants.SwitchableFilters)
            {
                return leftType;
            }
            else
            {
                return Constants.SwitchableFilters;
            }
        }

        // The mode info data structure has a one element border above and to the
        // left of the entries corresponding to real macroblocks.
        // The prediction flags in these dummy entries are initialized to 0.
        // 0 - inter/inter, inter/--, --/inter, --/--
        // 1 - intra/inter, inter/intra
        // 2 - intra/--, --/intra
        // 3 - intra/intra
        public readonly int GetIntraInterContext()
        {
            if (!AboveMi.IsNull && !LeftMi.IsNull)
            { // Both edges available
                bool aboveIntra = !AboveMi.Value.IsInterBlock();
                bool leftIntra = !LeftMi.Value.IsInterBlock();

                return leftIntra && aboveIntra ? 3 : (leftIntra || aboveIntra ? 1 : 0);
            }

            if (!AboveMi.IsNull || !LeftMi.IsNull)
            { // One edge available
                return 2 * (!(!AboveMi.IsNull ? AboveMi.Value : LeftMi.Value).IsInterBlock() ? 1 : 0);
            }
            return 0;
        }

        // Returns a context number for the given MB prediction signal
        // 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()
        {
            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;
            if (LeftMi.IsNull)
            {
                leftCtx = aboveCtx;
            }

            if (AboveMi.IsNull)
            {
                aboveCtx = leftCtx;
            }

            return (aboveCtx + leftCtx) > maxTxSize ? 1 : 0;
        }

        public void SetupBlockPlanes(int ssX, int ssY)
        {
            int i;

            for (i = 0; i < Constants.MaxMbPlane; i++)
            {
                Plane[i].SubsamplingX = i != 0 ? ssX : 0;
                Plane[i].SubsamplingY = i != 0 ? ssY : 0;
            }
        }

        public void SetSkipContext(int miRow, int miCol)
        {
            int aboveIdx = miCol * 2;
            int leftIdx = (miRow * 2) & 15;
            int i;
            for (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));
            }
        }

        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;

            // Are edges available for intra prediction?
            AboveMi = (miRow != 0) ? Mi[-MiStride] : Ptr<ModeInfo>.Null;
            LeftMi = (miCol > tile.MiColStart) ? Mi[-1] : Ptr<ModeInfo>.Null;
        }
    }
}