/ src / Ryujinx.Graphics.Nvdec.Vp9 / PredCommon.cs
PredCommon.cs
  1  using Ryujinx.Graphics.Nvdec.Vp9.Types;
  2  using System.Diagnostics;
  3  
  4  namespace Ryujinx.Graphics.Nvdec.Vp9
  5  {
  6      internal static class PredCommon
  7      {
  8          public static int GetReferenceModeContext(ref Vp9Common cm, ref MacroBlockD xd)
  9          {
 10              int ctx;
 11              // Note:
 12              // The mode info data structure has a one element border above and to the
 13              // left of the entries corresponding to real macroblocks.
 14              // The prediction flags in these dummy entries are initialized to 0.
 15              if (!xd.AboveMi.IsNull && !xd.LeftMi.IsNull)
 16              { // both edges available
 17                  if (!xd.AboveMi.Value.HasSecondRef() && !xd.LeftMi.Value.HasSecondRef())
 18                  {
 19                      // Neither edge uses comp pred (0/1)
 20                      ctx = (xd.AboveMi.Value.RefFrame[0] == cm.CompFixedRef ? 1 : 0) ^
 21                            (xd.LeftMi.Value.RefFrame[0] == cm.CompFixedRef ? 1 : 0);
 22                  }
 23                  else if (!xd.AboveMi.Value.HasSecondRef())
 24                  {
 25                      // One of two edges uses comp pred (2/3)
 26                      ctx = 2 + (xd.AboveMi.Value.RefFrame[0] == cm.CompFixedRef || !xd.AboveMi.Value.IsInterBlock() ? 1 : 0);
 27                  }
 28                  else if (!xd.LeftMi.Value.HasSecondRef())
 29                  {
 30                      // One of two edges uses comp pred (2/3)
 31                      ctx = 2 + (xd.LeftMi.Value.RefFrame[0] == cm.CompFixedRef || !xd.LeftMi.Value.IsInterBlock() ? 1 : 0);
 32                  }
 33                  else // Both edges use comp pred (4)
 34                  {
 35                      ctx = 4;
 36                  }
 37              }
 38              else if (!xd.AboveMi.IsNull || !xd.LeftMi.IsNull)
 39              { // One edge available
 40                  ref ModeInfo edgeMi = ref !xd.AboveMi.IsNull ? ref xd.AboveMi.Value : ref xd.LeftMi.Value;
 41  
 42                  if (!edgeMi.HasSecondRef())
 43                  {
 44                      // Edge does not use comp pred (0/1)
 45                      ctx = edgeMi.RefFrame[0] == cm.CompFixedRef ? 1 : 0;
 46                  }
 47                  else
 48                  {
 49                      // Edge uses comp pred (3)
 50                      ctx = 3;
 51                  }
 52              }
 53              else
 54              { // No edges available (1)
 55                  ctx = 1;
 56              }
 57              Debug.Assert(ctx >= 0 && ctx < Constants.CompInterContexts);
 58  
 59              return ctx;
 60          }
 61  
 62          // Returns a context number for the given MB prediction signal
 63          public static int GetPredContextCompRefP(ref Vp9Common cm, ref MacroBlockD xd)
 64          {
 65              int predContext;
 66              // Note:
 67              // The mode info data structure has a one element border above and to the
 68              // left of the entries corresponding to real macroblocks.
 69              // The prediction flags in these dummy entries are initialized to 0.
 70              int fixRefIdx = cm.RefFrameSignBias[cm.CompFixedRef];
 71              int varRefIdx = fixRefIdx == 0 ? 1 : 0;
 72  
 73              if (!xd.AboveMi.IsNull && !xd.LeftMi.IsNull)
 74              { // Both edges available
 75                  bool aboveIntra = !xd.AboveMi.Value.IsInterBlock();
 76                  bool leftIntra = !xd.LeftMi.Value.IsInterBlock();
 77  
 78                  if (aboveIntra && leftIntra)
 79                  { // Intra/Intra (2)
 80                      predContext = 2;
 81                  }
 82                  else if (aboveIntra || leftIntra)
 83                  { // Intra/Inter
 84                      ref ModeInfo edgeMi = ref aboveIntra ? ref xd.LeftMi.Value : ref xd.AboveMi.Value;
 85  
 86                      if (!edgeMi.HasSecondRef()) // single pred (1/3)
 87                      {
 88                          predContext = 1 + 2 * (edgeMi.RefFrame[0] != cm.CompVarRef[1] ? 1 : 0);
 89                      }
 90                      else // Comp pred (1/3)
 91                      {
 92                          predContext = 1 + 2 * (edgeMi.RefFrame[varRefIdx] != cm.CompVarRef[1] ? 1 : 0);
 93                      }
 94                  }
 95                  else
 96                  { // Inter/Inter
 97                      bool lSg = !xd.LeftMi.Value.HasSecondRef();
 98                      bool aSg = !xd.AboveMi.Value.HasSecondRef();
 99                      sbyte vrfa = aSg ? xd.AboveMi.Value.RefFrame[0] : xd.AboveMi.Value.RefFrame[varRefIdx];
100                      sbyte vrfl = lSg ? xd.LeftMi.Value.RefFrame[0] : xd.LeftMi.Value.RefFrame[varRefIdx];
101  
102                      if (vrfa == vrfl && cm.CompVarRef[1] == vrfa)
103                      {
104                          predContext = 0;
105                      }
106                      else if (lSg && aSg)
107                      { // Single/Single
108                          if ((vrfa == cm.CompFixedRef && vrfl == cm.CompVarRef[0]) ||
109                              (vrfl == cm.CompFixedRef && vrfa == cm.CompVarRef[0]))
110                          {
111                              predContext = 4;
112                          }
113                          else if (vrfa == vrfl)
114                          {
115                              predContext = 3;
116                          }
117                          else
118                          {
119                              predContext = 1;
120                          }
121                      }
122                      else if (lSg || aSg)
123                      { // Single/Comp
124                          sbyte vrfc = lSg ? vrfa : vrfl;
125                          sbyte rfs = aSg ? vrfa : vrfl;
126                          if (vrfc == cm.CompVarRef[1] && rfs != cm.CompVarRef[1])
127                          {
128                              predContext = 1;
129                          }
130                          else if (rfs == cm.CompVarRef[1] && vrfc != cm.CompVarRef[1])
131                          {
132                              predContext = 2;
133                          }
134                          else
135                          {
136                              predContext = 4;
137                          }
138                      }
139                      else if (vrfa == vrfl)
140                      { // Comp/Comp
141                          predContext = 4;
142                      }
143                      else
144                      {
145                          predContext = 2;
146                      }
147                  }
148              }
149              else if (!xd.AboveMi.IsNull || !xd.LeftMi.IsNull)
150              { // One edge available
151                  ref ModeInfo edgeMi = ref !xd.AboveMi.IsNull ? ref xd.AboveMi.Value : ref xd.LeftMi.Value;
152  
153                  if (!edgeMi.IsInterBlock())
154                  {
155                      predContext = 2;
156                  }
157                  else
158                  {
159                      if (edgeMi.HasSecondRef())
160                      {
161                          predContext = 4 * (edgeMi.RefFrame[varRefIdx] != cm.CompVarRef[1] ? 1 : 0);
162                      }
163                      else
164                      {
165                          predContext = 3 * (edgeMi.RefFrame[0] != cm.CompVarRef[1] ? 1 : 0);
166                      }
167                  }
168              }
169              else
170              { // No edges available (2)
171                  predContext = 2;
172              }
173              Debug.Assert(predContext >= 0 && predContext < Constants.RefContexts);
174  
175              return predContext;
176          }
177  
178          public static int GetPredContextSingleRefP1(ref MacroBlockD xd)
179          {
180              int predContext;
181              // Note:
182              // The mode info data structure has a one element border above and to the
183              // left of the entries corresponding to real macroblocks.
184              // The prediction flags in these dummy entries are initialized to 0.
185              if (!xd.AboveMi.IsNull && !xd.LeftMi.IsNull)
186              { // Both edges available
187                  bool aboveIntra = !xd.AboveMi.Value.IsInterBlock();
188                  bool leftIntra = !xd.LeftMi.Value.IsInterBlock();
189  
190                  if (aboveIntra && leftIntra)
191                  { // Intra/Intra
192                      predContext = 2;
193                  }
194                  else if (aboveIntra || leftIntra)
195                  { // Intra/Inter or Inter/Intra
196                      ref ModeInfo edgeMi = ref aboveIntra ? ref xd.LeftMi.Value : ref xd.AboveMi.Value;
197                      if (!edgeMi.HasSecondRef())
198                      {
199                          predContext = 4 * (edgeMi.RefFrame[0] == Constants.LastFrame ? 1 : 0);
200                      }
201                      else
202                      {
203                          predContext = 1 + (edgeMi.RefFrame[0] == Constants.LastFrame ||
204                                             edgeMi.RefFrame[1] == Constants.LastFrame ? 1 : 0);
205                      }
206                  }
207                  else
208                  { // Inter/Inter
209                      bool aboveHasSecond = xd.AboveMi.Value.HasSecondRef();
210                      bool leftHasSecond = xd.LeftMi.Value.HasSecondRef();
211                      sbyte above0 = xd.AboveMi.Value.RefFrame[0];
212                      sbyte above1 = xd.AboveMi.Value.RefFrame[1];
213                      sbyte left0 = xd.LeftMi.Value.RefFrame[0];
214                      sbyte left1 = xd.LeftMi.Value.RefFrame[1];
215  
216                      if (aboveHasSecond && leftHasSecond)
217                      {
218                          predContext = 1 + (above0 == Constants.LastFrame || above1 == Constants.LastFrame ||
219                                              left0 == Constants.LastFrame || left1 == Constants.LastFrame ? 1 : 0);
220                      }
221                      else if (aboveHasSecond || leftHasSecond)
222                      {
223                          sbyte rfs = !aboveHasSecond ? above0 : left0;
224                          sbyte crf1 = aboveHasSecond ? above0 : left0;
225                          sbyte crf2 = aboveHasSecond ? above1 : left1;
226  
227                          if (rfs == Constants.LastFrame)
228                          {
229                              predContext = 3 + (crf1 == Constants.LastFrame || crf2 == Constants.LastFrame ? 1 : 0);
230                          }
231                          else
232                          {
233                              predContext = (crf1 == Constants.LastFrame || crf2 == Constants.LastFrame ? 1 : 0);
234                          }
235                      }
236                      else
237                      {
238                          predContext = 2 * (above0 == Constants.LastFrame ? 1 : 0) + 2 * (left0 == Constants.LastFrame ? 1 : 0);
239                      }
240                  }
241              }
242              else if (!xd.AboveMi.IsNull || !xd.LeftMi.IsNull)
243              { // One edge available
244                  ref ModeInfo edgeMi = ref !xd.AboveMi.IsNull ? ref xd.AboveMi.Value : ref xd.LeftMi.Value;
245                  if (!edgeMi.IsInterBlock())
246                  { // Intra
247                      predContext = 2;
248                  }
249                  else
250                  { // Inter
251                      if (!edgeMi.HasSecondRef())
252                      {
253                          predContext = 4 * (edgeMi.RefFrame[0] == Constants.LastFrame ? 1 : 0);
254                      }
255                      else
256                      {
257                          predContext = 1 + (edgeMi.RefFrame[0] == Constants.LastFrame ||
258                                             edgeMi.RefFrame[1] == Constants.LastFrame ? 1 : 0);
259                      }
260                  }
261              }
262              else
263              { // No edges available
264                  predContext = 2;
265              }
266              Debug.Assert(predContext >= 0 && predContext < Constants.RefContexts);
267  
268              return predContext;
269          }
270  
271          public static int GetPredContextSingleRefP2(ref MacroBlockD xd)
272          {
273              int predContext;
274  
275              // Note:
276              // The mode info data structure has a one element border above and to the
277              // left of the entries corresponding to real macroblocks.
278              // The prediction flags in these dummy entries are initialized to 0.
279              if (!xd.AboveMi.IsNull && !xd.LeftMi.IsNull)
280              { // Both edges available
281                  bool aboveIntra = !xd.AboveMi.Value.IsInterBlock();
282                  bool leftIntra = !xd.LeftMi.Value.IsInterBlock();
283  
284                  if (aboveIntra && leftIntra)
285                  { // Intra/Intra
286                      predContext = 2;
287                  }
288                  else if (aboveIntra || leftIntra)
289                  { // Intra/Inter or Inter/Intra
290                      ref ModeInfo edgeMi = ref aboveIntra ? ref xd.LeftMi.Value : ref xd.AboveMi.Value;
291                      if (!edgeMi.HasSecondRef())
292                      {
293                          if (edgeMi.RefFrame[0] == Constants.LastFrame)
294                          {
295                              predContext = 3;
296                          }
297                          else
298                          {
299                              predContext = 4 * (edgeMi.RefFrame[0] == Constants.GoldenFrame ? 1 : 0);
300                          }
301                      }
302                      else
303                      {
304                          predContext = 1 + 2 * (edgeMi.RefFrame[0] == Constants.GoldenFrame ||
305                                                 edgeMi.RefFrame[1] == Constants.GoldenFrame ? 1 : 0);
306                      }
307                  }
308                  else
309                  { // Inter/Inter
310                      bool aboveHasSecond = xd.AboveMi.Value.HasSecondRef();
311                      bool leftHasSecond = xd.LeftMi.Value.HasSecondRef();
312                      sbyte above0 = xd.AboveMi.Value.RefFrame[0];
313                      sbyte above1 = xd.AboveMi.Value.RefFrame[1];
314                      sbyte left0 = xd.LeftMi.Value.RefFrame[0];
315                      sbyte left1 = xd.LeftMi.Value.RefFrame[1];
316  
317                      if (aboveHasSecond && leftHasSecond)
318                      {
319                          if (above0 == left0 && above1 == left1)
320                          {
321                              predContext = 3 * (above0 == Constants.GoldenFrame || above1 == Constants.GoldenFrame ||
322                                                  left0 == Constants.GoldenFrame || left1 == Constants.GoldenFrame ? 1 : 0);
323                          }
324                          else
325                          {
326                              predContext = 2;
327                          }
328                      }
329                      else if (aboveHasSecond || leftHasSecond)
330                      {
331                          sbyte rfs = !aboveHasSecond ? above0 : left0;
332                          sbyte crf1 = aboveHasSecond ? above0 : left0;
333                          sbyte crf2 = aboveHasSecond ? above1 : left1;
334  
335                          if (rfs == Constants.GoldenFrame)
336                          {
337                              predContext = 3 + (crf1 == Constants.GoldenFrame || crf2 == Constants.GoldenFrame ? 1 : 0);
338                          }
339                          else if (rfs == Constants.AltRefFrame)
340                          {
341                              predContext = crf1 == Constants.GoldenFrame || crf2 == Constants.GoldenFrame ? 1 : 0;
342                          }
343                          else
344                          {
345                              predContext = 1 + 2 * (crf1 == Constants.GoldenFrame || crf2 == Constants.GoldenFrame ? 1 : 0);
346                          }
347                      }
348                      else
349                      {
350                          if (above0 == Constants.LastFrame && left0 == Constants.LastFrame)
351                          {
352                              predContext = 3;
353                          }
354                          else if (above0 == Constants.LastFrame || left0 == Constants.LastFrame)
355                          {
356                              sbyte edge0 = (above0 == Constants.LastFrame) ? left0 : above0;
357                              predContext = 4 * (edge0 == Constants.GoldenFrame ? 1 : 0);
358                          }
359                          else
360                          {
361                              predContext = 2 * (above0 == Constants.GoldenFrame ? 1 : 0) + 2 * (left0 == Constants.GoldenFrame ? 1 : 0);
362                          }
363                      }
364                  }
365              }
366              else if (!xd.AboveMi.IsNull || !xd.LeftMi.IsNull)
367              { // One edge available
368                  ref ModeInfo edgeMi = ref !xd.AboveMi.IsNull ? ref xd.AboveMi.Value : ref xd.LeftMi.Value;
369  
370                  if (!edgeMi.IsInterBlock() || (edgeMi.RefFrame[0] == Constants.LastFrame && !edgeMi.HasSecondRef()))
371                  {
372                      predContext = 2;
373                  }
374                  else if (!edgeMi.HasSecondRef())
375                  {
376                      predContext = 4 * (edgeMi.RefFrame[0] == Constants.GoldenFrame ? 1 : 0);
377                  }
378                  else
379                  {
380                      predContext = 3 * (edgeMi.RefFrame[0] == Constants.GoldenFrame ||
381                                         edgeMi.RefFrame[1] == Constants.GoldenFrame ? 1 : 0);
382                  }
383              }
384              else
385              { // No edges available (2)
386                  predContext = 2;
387              }
388              Debug.Assert(predContext >= 0 && predContext < Constants.RefContexts);
389  
390              return predContext;
391          }
392      }
393  }