Scaler.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. using System;
  2. using System.Runtime.Intrinsics;
  3. using System.Runtime.Intrinsics.X86;
  4. namespace Ryujinx.Graphics.Vic
  5. {
  6. static class Scaler
  7. {
  8. public static void DeinterlaceWeave(Span<byte> data, ReadOnlySpan<byte> prevData, int width, int fieldSize, bool isTopField)
  9. {
  10. // Prev I Curr I Curr P
  11. // TTTTTTTT BBBBBBBB TTTTTTTT
  12. // -------- -------- BBBBBBBB
  13. if (isTopField)
  14. {
  15. for (int offset = 0; offset < data.Length; offset += fieldSize * 2)
  16. {
  17. prevData.Slice(offset >> 1, width).CopyTo(data.Slice(offset + fieldSize, width));
  18. }
  19. }
  20. else
  21. {
  22. for (int offset = 0; offset < data.Length; offset += fieldSize * 2)
  23. {
  24. prevData.Slice(offset >> 1, width).CopyTo(data.Slice(offset, width));
  25. }
  26. }
  27. }
  28. public static void DeinterlaceBob(Span<byte> data, int width, int fieldSize, bool isTopField)
  29. {
  30. // Curr I Curr P
  31. // TTTTTTTT TTTTTTTT
  32. // -------- TTTTTTTT
  33. if (isTopField)
  34. {
  35. for (int offset = 0; offset < data.Length; offset += fieldSize * 2)
  36. {
  37. data.Slice(offset, width).CopyTo(data.Slice(offset + fieldSize, width));
  38. }
  39. }
  40. else
  41. {
  42. for (int offset = 0; offset < data.Length; offset += fieldSize * 2)
  43. {
  44. data.Slice(offset + fieldSize, width).CopyTo(data.Slice(offset, width));
  45. }
  46. }
  47. }
  48. public unsafe static void DeinterlaceMotionAdaptive(
  49. Span<byte> data,
  50. ReadOnlySpan<byte> prevData,
  51. ReadOnlySpan<byte> nextData,
  52. int width,
  53. int fieldSize,
  54. bool isTopField)
  55. {
  56. // Very simple motion adaptive algorithm.
  57. // If the pixel changed between previous and next frame, use Bob, otherwise use Weave.
  58. //
  59. // Example pseudo code:
  60. // C_even = (P_even == N_even) ? P_even : C_odd
  61. // Where: C is current frame, P is previous frame and N is next frame, and even/odd are the fields.
  62. //
  63. // Note: This does not fully match the hardware algorithm.
  64. // The motion adaptive deinterlacing implemented on hardware is considerably more complex,
  65. // and hard to implement accurately without proper documentation as for example, the
  66. // method used for motion estimation is unknown.
  67. int start = isTopField ? fieldSize : 0;
  68. int otherFieldOffset = isTopField ? -fieldSize : fieldSize;
  69. fixed (byte* pData = data, pPrevData = prevData, pNextData = nextData)
  70. {
  71. for (int offset = start; offset < data.Length; offset += fieldSize * 2)
  72. {
  73. int refOffset = (offset - start) >> 1;
  74. int x = 0;
  75. if (Avx2.IsSupported)
  76. {
  77. for (; x < (width & ~0x1f); x += 32)
  78. {
  79. Vector256<byte> prevPixels = Avx.LoadVector256(pPrevData + refOffset + x);
  80. Vector256<byte> nextPixels = Avx.LoadVector256(pNextData + refOffset + x);
  81. Vector256<byte> bob = Avx.LoadVector256(pData + offset + otherFieldOffset + x);
  82. Vector256<byte> diff = Avx2.CompareEqual(prevPixels, nextPixels);
  83. Avx.Store(pData + offset + x, Avx2.BlendVariable(bob, prevPixels, diff));
  84. }
  85. }
  86. else if (Sse41.IsSupported)
  87. {
  88. for (; x < (width & ~0xf); x += 16)
  89. {
  90. Vector128<byte> prevPixels = Sse2.LoadVector128(pPrevData + refOffset + x);
  91. Vector128<byte> nextPixels = Sse2.LoadVector128(pNextData + refOffset + x);
  92. Vector128<byte> bob = Sse2.LoadVector128(pData + offset + otherFieldOffset + x);
  93. Vector128<byte> diff = Sse2.CompareEqual(prevPixels, nextPixels);
  94. Sse2.Store(pData + offset + x, Sse41.BlendVariable(bob, prevPixels, diff));
  95. }
  96. }
  97. for (; x < width; x++)
  98. {
  99. byte prevPixel = prevData[refOffset + x];
  100. byte nextPixel = nextData[refOffset + x];
  101. if (nextPixel != prevPixel)
  102. {
  103. data[offset + x] = data[offset + otherFieldOffset + x];
  104. }
  105. else
  106. {
  107. data[offset + x] = prevPixel;
  108. }
  109. }
  110. }
  111. }
  112. }
  113. }
  114. }