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 }