ReconIntra.cs
1 using Ryujinx.Graphics.Nvdec.Vp9.Common; 2 using Ryujinx.Graphics.Nvdec.Vp9.Types; 3 using System; 4 using static Ryujinx.Graphics.Nvdec.Vp9.Dsp.IntraPred; 5 6 namespace Ryujinx.Graphics.Nvdec.Vp9 7 { 8 internal static class ReconIntra 9 { 10 public static readonly TxType[] IntraModeToTxTypeLookup = { 11 TxType.DctDct, // DC 12 TxType.AdstDct, // V 13 TxType.DctAdst, // H 14 TxType.DctDct, // D45 15 TxType.AdstAdst, // D135 16 TxType.AdstDct, // D117 17 TxType.DctAdst, // D153 18 TxType.DctAdst, // D207 19 TxType.AdstDct, // D63 20 TxType.AdstAdst, // TM 21 }; 22 23 private const int NeedLeft = 1 << 1; 24 private const int NeedAbove = 1 << 2; 25 private const int NeedAboveRight = 1 << 3; 26 27 private static ReadOnlySpan<byte> ExtendModes => new byte[] 28 { 29 NeedAbove | NeedLeft, // DC 30 NeedAbove, // V 31 NeedLeft, // H 32 NeedAboveRight, // D45 33 NeedLeft | NeedAbove, // D135 34 NeedLeft | NeedAbove, // D117 35 NeedLeft | NeedAbove, // D153 36 NeedLeft, // D207 37 NeedAboveRight, // D63 38 NeedLeft | NeedAbove, // TM 39 }; 40 41 private unsafe delegate void IntraPredFn(byte* dst, int stride, byte* above, byte* left); 42 43 private static readonly unsafe IntraPredFn[][] _pred = { 44 new IntraPredFn[] 45 { 46 null, 47 null, 48 null, 49 null, 50 }, 51 new IntraPredFn[] 52 { 53 VPredictor4x4, 54 VPredictor8x8, 55 VPredictor16x16, 56 VPredictor32x32, 57 }, 58 new IntraPredFn[] 59 { 60 HPredictor4x4, 61 HPredictor8x8, 62 HPredictor16x16, 63 HPredictor32x32, 64 }, 65 new IntraPredFn[] 66 { 67 D45Predictor4x4, 68 D45Predictor8x8, 69 D45Predictor16x16, 70 D45Predictor32x32, 71 }, 72 new IntraPredFn[] 73 { 74 D135Predictor4x4, 75 D135Predictor8x8, 76 D135Predictor16x16, 77 D135Predictor32x32, 78 }, 79 new IntraPredFn[] 80 { 81 D117Predictor4x4, 82 D117Predictor8x8, 83 D117Predictor16x16, 84 D117Predictor32x32, 85 }, 86 new IntraPredFn[] 87 { 88 D153Predictor4x4, 89 D153Predictor8x8, 90 D153Predictor16x16, 91 D153Predictor32x32, 92 }, 93 new IntraPredFn[] 94 { 95 D207Predictor4x4, 96 D207Predictor8x8, 97 D207Predictor16x16, 98 D207Predictor32x32, 99 }, 100 new IntraPredFn[] 101 { 102 D63Predictor4x4, 103 D63Predictor8x8, 104 D63Predictor16x16, 105 D63Predictor32x32, 106 }, 107 new IntraPredFn[] 108 { 109 TMPredictor4x4, 110 TMPredictor8x8, 111 TMPredictor16x16, 112 TMPredictor32x32, 113 }, 114 }; 115 116 private static readonly unsafe IntraPredFn[][][] _dcPred = { 117 new[] 118 { 119 new IntraPredFn[] 120 { 121 Dc128Predictor4x4, 122 Dc128Predictor8x8, 123 Dc128Predictor16x16, 124 Dc128Predictor32x32, 125 }, 126 new IntraPredFn[] 127 { 128 DcTopPredictor4x4, 129 DcTopPredictor8x8, 130 DcTopPredictor16x16, 131 DcTopPredictor32x32, 132 }, 133 }, 134 new[] 135 { 136 new IntraPredFn[] 137 { 138 DcLeftPredictor4x4, 139 DcLeftPredictor8x8, 140 DcLeftPredictor16x16, 141 DcLeftPredictor32x32, 142 }, 143 new IntraPredFn[] 144 { 145 DcPredictor4x4, 146 DcPredictor8x8, 147 DcPredictor16x16, 148 DcPredictor32x32, 149 }, 150 }, 151 }; 152 153 private unsafe delegate void IntraHighPredFn(ushort* dst, int stride, ushort* above, ushort* left, int bd); 154 155 private static readonly unsafe IntraHighPredFn[][] _predHigh = { 156 new IntraHighPredFn[] 157 { 158 null, 159 null, 160 null, 161 null, 162 }, 163 new IntraHighPredFn[] 164 { 165 HighbdVPredictor4x4, 166 HighbdVPredictor8x8, 167 HighbdVPredictor16x16, 168 HighbdVPredictor32x32, 169 }, 170 new IntraHighPredFn[] 171 { 172 HighbdHPredictor4x4, 173 HighbdHPredictor8x8, 174 HighbdHPredictor16x16, 175 HighbdHPredictor32x32, 176 }, 177 new IntraHighPredFn[] 178 { 179 HighbdD45Predictor4x4, 180 HighbdD45Predictor8x8, 181 HighbdD45Predictor16x16, 182 HighbdD45Predictor32x32, 183 }, 184 new IntraHighPredFn[] 185 { 186 HighbdD135Predictor4x4, 187 HighbdD135Predictor8x8, 188 HighbdD135Predictor16x16, 189 HighbdD135Predictor32x32, 190 }, 191 new IntraHighPredFn[] 192 { 193 HighbdD117Predictor4x4, 194 HighbdD117Predictor8x8, 195 HighbdD117Predictor16x16, 196 HighbdD117Predictor32x32, 197 }, 198 new IntraHighPredFn[] 199 { 200 HighbdD153Predictor4x4, 201 HighbdD153Predictor8x8, 202 HighbdD153Predictor16x16, 203 HighbdD153Predictor32x32, 204 }, 205 new IntraHighPredFn[] 206 { 207 HighbdD207Predictor4x4, 208 HighbdD207Predictor8x8, 209 HighbdD207Predictor16x16, 210 HighbdD207Predictor32x32, 211 }, 212 new IntraHighPredFn[] 213 { 214 HighbdD63Predictor4x4, 215 HighbdD63Predictor8x8, 216 HighbdD63Predictor16x16, 217 HighbdD63Predictor32x32, 218 }, 219 new IntraHighPredFn[] 220 { 221 HighbdTMPredictor4x4, 222 HighbdTMPredictor8x8, 223 HighbdTMPredictor16x16, 224 HighbdTMPredictor32x32, 225 }, 226 }; 227 228 private static readonly unsafe IntraHighPredFn[][][] _dcPredHigh = { 229 new[] 230 { 231 new IntraHighPredFn[] 232 { 233 HighbdDc128Predictor4x4, 234 HighbdDc128Predictor8x8, 235 HighbdDc128Predictor16x16, 236 HighbdDc128Predictor32x32, 237 }, 238 new IntraHighPredFn[] 239 { 240 HighbdDcTopPredictor4x4, 241 HighbdDcTopPredictor8x8, 242 HighbdDcTopPredictor16x16, 243 HighbdDcTopPredictor32x32, 244 }, 245 }, 246 new[] 247 { 248 new IntraHighPredFn[] 249 { 250 HighbdDcLeftPredictor4x4, 251 HighbdDcLeftPredictor8x8, 252 HighbdDcLeftPredictor16x16, 253 HighbdDcLeftPredictor32x32, 254 }, 255 new IntraHighPredFn[] 256 { 257 HighbdDcPredictor4x4, 258 HighbdDcPredictor8x8, 259 HighbdDcPredictor16x16, 260 HighbdDcPredictor32x32, 261 }, 262 }, 263 }; 264 265 private static unsafe void BuildIntraPredictorsHigh( 266 ref MacroBlockD xd, 267 byte* ref8, 268 int refStride, 269 byte* dst8, 270 int dstStride, 271 PredictionMode mode, 272 TxSize txSize, 273 int upAvailable, 274 int leftAvailable, 275 int rightAvailable, 276 int x, 277 int y, 278 int plane) 279 { 280 int i; 281 ushort* dst = (ushort*)dst8; 282 ushort* refr = (ushort*)ref8; 283 ushort* leftCol = stackalloc ushort[32]; 284 ushort* aboveData = stackalloc ushort[64 + 16]; 285 ushort* aboveRow = aboveData + 16; 286 ushort* constAboveRow = aboveRow; 287 int bs = 4 << (int)txSize; 288 int frameWidth, frameHeight; 289 int x0, y0; 290 ref MacroBlockDPlane pd = ref xd.Plane[plane]; 291 int needLeft = ExtendModes[(int)mode] & NeedLeft; 292 int needAbove = ExtendModes[(int)mode] & NeedAbove; 293 int needAboveRight = ExtendModes[(int)mode] & NeedAboveRight; 294 int baseVal = 128 << (xd.Bd - 8); 295 // 127 127 127 .. 127 127 127 127 127 127 296 // 129 A B .. Y Z 297 // 129 C D .. W X 298 // 129 E F .. U V 299 // 129 G H .. S T T T T T 300 // For 10 bit and 12 bit, 127 and 129 are replaced by base -1 and base + 1. 301 302 // Get current frame pointer, width and height. 303 if (plane == 0) 304 { 305 frameWidth = xd.CurBuf.Width; 306 frameHeight = xd.CurBuf.Height; 307 } 308 else 309 { 310 frameWidth = xd.CurBuf.UvWidth; 311 frameHeight = xd.CurBuf.UvHeight; 312 } 313 314 // Get block position in current frame. 315 x0 = (-xd.MbToLeftEdge >> (3 + pd.SubsamplingX)) + x; 316 y0 = (-xd.MbToTopEdge >> (3 + pd.SubsamplingY)) + y; 317 318 // NEED_LEFT 319 if (needLeft != 0) 320 { 321 if (leftAvailable != 0) 322 { 323 if (xd.MbToBottomEdge < 0) 324 { 325 /* slower path if the block needs border extension */ 326 if (y0 + bs <= frameHeight) 327 { 328 for (i = 0; i < bs; ++i) 329 { 330 leftCol[i] = refr[i * refStride - 1]; 331 } 332 } 333 else 334 { 335 int extendBottom = frameHeight - y0; 336 for (i = 0; i < extendBottom; ++i) 337 { 338 leftCol[i] = refr[i * refStride - 1]; 339 } 340 341 for (; i < bs; ++i) 342 { 343 leftCol[i] = refr[(extendBottom - 1) * refStride - 1]; 344 } 345 } 346 } 347 else 348 { 349 /* faster path if the block does not need extension */ 350 for (i = 0; i < bs; ++i) 351 { 352 leftCol[i] = refr[i * refStride - 1]; 353 } 354 } 355 } 356 else 357 { 358 MemoryUtil.Fill(leftCol, (ushort)(baseVal + 1), bs); 359 } 360 } 361 362 // NEED_ABOVE 363 if (needAbove != 0) 364 { 365 if (upAvailable != 0) 366 { 367 ushort* aboveRef = refr - refStride; 368 if (xd.MbToRightEdge < 0) 369 { 370 /* slower path if the block needs border extension */ 371 if (x0 + bs <= frameWidth) 372 { 373 MemoryUtil.Copy(aboveRow, aboveRef, bs); 374 } 375 else if (x0 <= frameWidth) 376 { 377 int r = frameWidth - x0; 378 MemoryUtil.Copy(aboveRow, aboveRef, r); 379 MemoryUtil.Fill(aboveRow + r, aboveRow[r - 1], x0 + bs - frameWidth); 380 } 381 } 382 else 383 { 384 /* faster path if the block does not need extension */ 385 if (bs == 4 && rightAvailable != 0 && leftAvailable != 0) 386 { 387 constAboveRow = aboveRef; 388 } 389 else 390 { 391 MemoryUtil.Copy(aboveRow, aboveRef, bs); 392 } 393 } 394 aboveRow[-1] = leftAvailable != 0 ? aboveRef[-1] : (ushort)(baseVal + 1); 395 } 396 else 397 { 398 MemoryUtil.Fill(aboveRow, (ushort)(baseVal - 1), bs); 399 aboveRow[-1] = (ushort)(baseVal - 1); 400 } 401 } 402 403 // NEED_ABOVERIGHT 404 if (needAboveRight != 0) 405 { 406 if (upAvailable != 0) 407 { 408 ushort* aboveRef = refr - refStride; 409 if (xd.MbToRightEdge < 0) 410 { 411 /* slower path if the block needs border extension */ 412 if (x0 + 2 * bs <= frameWidth) 413 { 414 if (rightAvailable != 0 && bs == 4) 415 { 416 MemoryUtil.Copy(aboveRow, aboveRef, 2 * bs); 417 } 418 else 419 { 420 MemoryUtil.Copy(aboveRow, aboveRef, bs); 421 MemoryUtil.Fill(aboveRow + bs, aboveRow[bs - 1], bs); 422 } 423 } 424 else if (x0 + bs <= frameWidth) 425 { 426 int r = frameWidth - x0; 427 if (rightAvailable != 0 && bs == 4) 428 { 429 MemoryUtil.Copy(aboveRow, aboveRef, r); 430 MemoryUtil.Fill(aboveRow + r, aboveRow[r - 1], x0 + 2 * bs - frameWidth); 431 } 432 else 433 { 434 MemoryUtil.Copy(aboveRow, aboveRef, bs); 435 MemoryUtil.Fill(aboveRow + bs, aboveRow[bs - 1], bs); 436 } 437 } 438 else if (x0 <= frameWidth) 439 { 440 int r = frameWidth - x0; 441 MemoryUtil.Copy(aboveRow, aboveRef, r); 442 MemoryUtil.Fill(aboveRow + r, aboveRow[r - 1], x0 + 2 * bs - frameWidth); 443 } 444 aboveRow[-1] = leftAvailable != 0 ? aboveRef[-1] : (ushort)(baseVal + 1); 445 } 446 else 447 { 448 /* faster path if the block does not need extension */ 449 if (bs == 4 && rightAvailable != 0 && leftAvailable != 0) 450 { 451 constAboveRow = aboveRef; 452 } 453 else 454 { 455 MemoryUtil.Copy(aboveRow, aboveRef, bs); 456 if (bs == 4 && rightAvailable != 0) 457 { 458 MemoryUtil.Copy(aboveRow + bs, aboveRef + bs, bs); 459 } 460 else 461 { 462 MemoryUtil.Fill(aboveRow + bs, aboveRow[bs - 1], bs); 463 } 464 465 aboveRow[-1] = leftAvailable != 0 ? aboveRef[-1] : (ushort)(baseVal + 1); 466 } 467 } 468 } 469 else 470 { 471 MemoryUtil.Fill(aboveRow, (ushort)(baseVal - 1), bs * 2); 472 aboveRow[-1] = (ushort)(baseVal - 1); 473 } 474 } 475 476 // Predict 477 if (mode == PredictionMode.DcPred) 478 { 479 _dcPredHigh[leftAvailable][upAvailable][(int)txSize](dst, dstStride, constAboveRow, leftCol, xd.Bd); 480 } 481 else 482 { 483 _predHigh[(int)mode][(int)txSize](dst, dstStride, constAboveRow, leftCol, xd.Bd); 484 } 485 } 486 487 public static unsafe void BuildIntraPredictors( 488 ref MacroBlockD xd, 489 byte* refr, 490 int refStride, 491 byte* dst, 492 int dstStride, 493 PredictionMode mode, 494 TxSize txSize, 495 int upAvailable, 496 int leftAvailable, 497 int rightAvailable, 498 int x, 499 int y, 500 int plane) 501 { 502 int i; 503 byte* leftCol = stackalloc byte[32]; 504 byte* aboveData = stackalloc byte[64 + 16]; 505 byte* aboveRow = aboveData + 16; 506 byte* constAboveRow = aboveRow; 507 int bs = 4 << (int)txSize; 508 int frameWidth, frameHeight; 509 int x0, y0; 510 ref MacroBlockDPlane pd = ref xd.Plane[plane]; 511 512 // 127 127 127 .. 127 127 127 127 127 127 513 // 129 A B .. Y Z 514 // 129 C D .. W X 515 // 129 E F .. U V 516 // 129 G H .. S T T T T T 517 // .. 518 519 // Get current frame pointer, width and height. 520 if (plane == 0) 521 { 522 frameWidth = xd.CurBuf.Width; 523 frameHeight = xd.CurBuf.Height; 524 } 525 else 526 { 527 frameWidth = xd.CurBuf.UvWidth; 528 frameHeight = xd.CurBuf.UvHeight; 529 } 530 531 // Get block position in current frame. 532 x0 = (-xd.MbToLeftEdge >> (3 + pd.SubsamplingX)) + x; 533 y0 = (-xd.MbToTopEdge >> (3 + pd.SubsamplingY)) + y; 534 535 // NEED_LEFT 536 if ((ExtendModes[(int)mode] & NeedLeft) != 0) 537 { 538 if (leftAvailable != 0) 539 { 540 if (xd.MbToBottomEdge < 0) 541 { 542 /* Slower path if the block needs border extension */ 543 if (y0 + bs <= frameHeight) 544 { 545 for (i = 0; i < bs; ++i) 546 { 547 leftCol[i] = refr[i * refStride - 1]; 548 } 549 } 550 else 551 { 552 int extendBottom = frameHeight - y0; 553 for (i = 0; i < extendBottom; ++i) 554 { 555 leftCol[i] = refr[i * refStride - 1]; 556 } 557 558 for (; i < bs; ++i) 559 { 560 leftCol[i] = refr[(extendBottom - 1) * refStride - 1]; 561 } 562 } 563 } 564 else 565 { 566 /* Faster path if the block does not need extension */ 567 for (i = 0; i < bs; ++i) 568 { 569 leftCol[i] = refr[i * refStride - 1]; 570 } 571 } 572 } 573 else 574 { 575 MemoryUtil.Fill(leftCol, (byte)129, bs); 576 } 577 } 578 579 // NEED_ABOVE 580 if ((ExtendModes[(int)mode] & NeedAbove) != 0) 581 { 582 if (upAvailable != 0) 583 { 584 byte* aboveRef = refr - refStride; 585 if (xd.MbToRightEdge < 0) 586 { 587 /* Slower path if the block needs border extension */ 588 if (x0 + bs <= frameWidth) 589 { 590 MemoryUtil.Copy(aboveRow, aboveRef, bs); 591 } 592 else if (x0 <= frameWidth) 593 { 594 int r = frameWidth - x0; 595 MemoryUtil.Copy(aboveRow, aboveRef, r); 596 MemoryUtil.Fill(aboveRow + r, aboveRow[r - 1], x0 + bs - frameWidth); 597 } 598 } 599 else 600 { 601 /* Faster path if the block does not need extension */ 602 if (bs == 4 && rightAvailable != 0 && leftAvailable != 0) 603 { 604 constAboveRow = aboveRef; 605 } 606 else 607 { 608 MemoryUtil.Copy(aboveRow, aboveRef, bs); 609 } 610 } 611 aboveRow[-1] = leftAvailable != 0 ? aboveRef[-1] : (byte)129; 612 } 613 else 614 { 615 MemoryUtil.Fill(aboveRow, (byte)127, bs); 616 aboveRow[-1] = 127; 617 } 618 } 619 620 // NEED_ABOVERIGHT 621 if ((ExtendModes[(int)mode] & NeedAboveRight) != 0) 622 { 623 if (upAvailable != 0) 624 { 625 byte* aboveRef = refr - refStride; 626 if (xd.MbToRightEdge < 0) 627 { 628 /* Slower path if the block needs border extension */ 629 if (x0 + 2 * bs <= frameWidth) 630 { 631 if (rightAvailable != 0 && bs == 4) 632 { 633 MemoryUtil.Copy(aboveRow, aboveRef, 2 * bs); 634 } 635 else 636 { 637 MemoryUtil.Copy(aboveRow, aboveRef, bs); 638 MemoryUtil.Fill(aboveRow + bs, aboveRow[bs - 1], bs); 639 } 640 } 641 else if (x0 + bs <= frameWidth) 642 { 643 int r = frameWidth - x0; 644 if (rightAvailable != 0 && bs == 4) 645 { 646 MemoryUtil.Copy(aboveRow, aboveRef, r); 647 MemoryUtil.Fill(aboveRow + r, aboveRow[r - 1], x0 + 2 * bs - frameWidth); 648 } 649 else 650 { 651 MemoryUtil.Copy(aboveRow, aboveRef, bs); 652 MemoryUtil.Fill(aboveRow + bs, aboveRow[bs - 1], bs); 653 } 654 } 655 else if (x0 <= frameWidth) 656 { 657 int r = frameWidth - x0; 658 MemoryUtil.Copy(aboveRow, aboveRef, r); 659 MemoryUtil.Fill(aboveRow + r, aboveRow[r - 1], x0 + 2 * bs - frameWidth); 660 } 661 } 662 else 663 { 664 /* Faster path if the block does not need extension */ 665 if (bs == 4 && rightAvailable != 0 && leftAvailable != 0) 666 { 667 constAboveRow = aboveRef; 668 } 669 else 670 { 671 MemoryUtil.Copy(aboveRow, aboveRef, bs); 672 if (bs == 4 && rightAvailable != 0) 673 { 674 MemoryUtil.Copy(aboveRow + bs, aboveRef + bs, bs); 675 } 676 else 677 { 678 MemoryUtil.Fill(aboveRow + bs, aboveRow[bs - 1], bs); 679 } 680 } 681 } 682 aboveRow[-1] = leftAvailable != 0 ? aboveRef[-1] : (byte)129; 683 } 684 else 685 { 686 MemoryUtil.Fill(aboveRow, (byte)127, bs * 2); 687 aboveRow[-1] = 127; 688 } 689 } 690 691 // Predict 692 if (mode == PredictionMode.DcPred) 693 { 694 _dcPred[leftAvailable][upAvailable][(int)txSize](dst, dstStride, constAboveRow, leftCol); 695 } 696 else 697 { 698 _pred[(int)mode][(int)txSize](dst, dstStride, constAboveRow, leftCol); 699 } 700 } 701 702 public static unsafe void PredictIntraBlock( 703 ref MacroBlockD xd, 704 int bwlIn, 705 TxSize txSize, 706 PredictionMode mode, 707 byte* refr, 708 int refStride, 709 byte* dst, 710 int dstStride, 711 int aoff, 712 int loff, 713 int plane) 714 { 715 int bw = 1 << bwlIn; 716 int txw = 1 << (int)txSize; 717 int haveTop = loff != 0 || !xd.AboveMi.IsNull ? 1 : 0; 718 int haveLeft = aoff != 0 || !xd.LeftMi.IsNull ? 1 : 0; 719 int haveRight = (aoff + txw) < bw ? 1 : 0; 720 int x = aoff * 4; 721 int y = loff * 4; 722 723 if (xd.CurBuf.HighBd) 724 { 725 BuildIntraPredictorsHigh( 726 ref xd, 727 refr, 728 refStride, 729 dst, 730 dstStride, 731 mode, 732 txSize, 733 haveTop, 734 haveLeft, 735 haveRight, 736 x, 737 y, 738 plane); 739 740 return; 741 } 742 BuildIntraPredictors( 743 ref xd, 744 refr, 745 refStride, 746 dst, 747 dstStride, 748 mode, 749 txSize, 750 haveTop, 751 haveLeft, 752 haveRight, 753 x, 754 y, 755 plane); 756 } 757 } 758 }