Decoder.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. using Ryujinx.Common.Memory;
  2. using Ryujinx.Graphics.Nvdec.Vp9.Common;
  3. using Ryujinx.Graphics.Nvdec.Vp9.Types;
  4. using Ryujinx.Graphics.Video;
  5. using System;
  6. namespace Ryujinx.Graphics.Nvdec.Vp9
  7. {
  8. public sealed class Decoder : IVp9Decoder
  9. {
  10. public bool IsHardwareAccelerated => false;
  11. private readonly MemoryAllocator _allocator = new();
  12. public ISurface CreateSurface(int width, int height) => new Surface(width, height);
  13. private static ReadOnlySpan<byte> LiteralToFilter => new byte[]
  14. {
  15. Constants.EightTapSmooth,
  16. Constants.EightTap,
  17. Constants.EightTapSharp,
  18. Constants.Bilinear,
  19. };
  20. public unsafe bool Decode(
  21. ref Vp9PictureInfo pictureInfo,
  22. ISurface output,
  23. ReadOnlySpan<byte> bitstream,
  24. ReadOnlySpan<Vp9MvRef> mvsIn,
  25. Span<Vp9MvRef> mvsOut)
  26. {
  27. Vp9Common cm = new()
  28. {
  29. FrameType = pictureInfo.IsKeyFrame ? FrameType.KeyFrame : FrameType.InterFrame,
  30. IntraOnly = pictureInfo.IntraOnly,
  31. Width = output.Width,
  32. Height = output.Height,
  33. SubsamplingX = 1,
  34. SubsamplingY = 1,
  35. UsePrevFrameMvs = pictureInfo.UsePrevInFindMvRefs,
  36. RefFrameSignBias = pictureInfo.RefFrameSignBias,
  37. BaseQindex = pictureInfo.BaseQIndex,
  38. YDcDeltaQ = pictureInfo.YDcDeltaQ,
  39. UvAcDeltaQ = pictureInfo.UvAcDeltaQ,
  40. UvDcDeltaQ = pictureInfo.UvDcDeltaQ,
  41. };
  42. cm.Mb.Lossless = pictureInfo.Lossless;
  43. cm.Mb.Bd = 8;
  44. cm.TxMode = (TxMode)pictureInfo.TransformMode;
  45. cm.AllowHighPrecisionMv = pictureInfo.AllowHighPrecisionMv;
  46. cm.InterpFilter = (byte)pictureInfo.InterpFilter;
  47. if (cm.InterpFilter != Constants.Switchable)
  48. {
  49. cm.InterpFilter = LiteralToFilter[cm.InterpFilter];
  50. }
  51. cm.ReferenceMode = (ReferenceMode)pictureInfo.ReferenceMode;
  52. cm.CompFixedRef = pictureInfo.CompFixedRef;
  53. cm.CompVarRef = pictureInfo.CompVarRef;
  54. cm.Log2TileCols = pictureInfo.Log2TileCols;
  55. cm.Log2TileRows = pictureInfo.Log2TileRows;
  56. cm.Seg.Enabled = pictureInfo.SegmentEnabled;
  57. cm.Seg.UpdateMap = pictureInfo.SegmentMapUpdate;
  58. cm.Seg.TemporalUpdate = pictureInfo.SegmentMapTemporalUpdate;
  59. cm.Seg.AbsDelta = (byte)pictureInfo.SegmentAbsDelta;
  60. cm.Seg.FeatureMask = pictureInfo.SegmentFeatureEnable;
  61. cm.Seg.FeatureData = pictureInfo.SegmentFeatureData;
  62. cm.Lf.ModeRefDeltaEnabled = pictureInfo.ModeRefDeltaEnabled;
  63. cm.Lf.RefDeltas = pictureInfo.RefDeltas;
  64. cm.Lf.ModeDeltas = pictureInfo.ModeDeltas;
  65. cm.Fc = new Ptr<Vp9EntropyProbs>(ref pictureInfo.Entropy);
  66. cm.Counts = new Ptr<Vp9BackwardUpdates>(ref pictureInfo.BackwardUpdateCounts);
  67. cm.FrameRefs[0].Buf = (Surface)pictureInfo.LastReference;
  68. cm.FrameRefs[1].Buf = (Surface)pictureInfo.GoldenReference;
  69. cm.FrameRefs[2].Buf = (Surface)pictureInfo.AltReference;
  70. cm.Mb.CurBuf = (Surface)output;
  71. cm.Mb.SetupBlockPlanes(1, 1);
  72. int tileCols = 1 << pictureInfo.Log2TileCols;
  73. int tileRows = 1 << pictureInfo.Log2TileRows;
  74. // Video usually have only 4 columns, so more threads won't make a difference for those.
  75. // Try to not take all CPU cores for video decoding.
  76. int maxThreads = Math.Min(4, Environment.ProcessorCount / 2);
  77. cm.AllocTileWorkerData(_allocator, tileCols, tileRows, maxThreads);
  78. cm.AllocContextBuffers(_allocator, output.Width, output.Height);
  79. cm.InitContextBuffers();
  80. cm.SetupSegmentationDequant();
  81. cm.SetupScaleFactors();
  82. SetMvs(ref cm, mvsIn);
  83. fixed (byte* dataPtr = bitstream)
  84. {
  85. try
  86. {
  87. if (maxThreads > 1 && tileRows == 1 && tileCols > 1)
  88. {
  89. DecodeFrame.DecodeTilesMt(ref cm, new ArrayPtr<byte>(dataPtr, bitstream.Length), maxThreads);
  90. }
  91. else
  92. {
  93. DecodeFrame.DecodeTiles(ref cm, new ArrayPtr<byte>(dataPtr, bitstream.Length));
  94. }
  95. }
  96. catch (InternalErrorException)
  97. {
  98. return false;
  99. }
  100. }
  101. GetMvs(ref cm, mvsOut);
  102. cm.FreeTileWorkerData(_allocator);
  103. cm.FreeContextBuffers(_allocator);
  104. return true;
  105. }
  106. private static void SetMvs(ref Vp9Common cm, ReadOnlySpan<Vp9MvRef> mvs)
  107. {
  108. if (mvs.Length > cm.PrevFrameMvs.Length)
  109. {
  110. throw new ArgumentException($"Size mismatch, expected: {cm.PrevFrameMvs.Length}, but got: {mvs.Length}.");
  111. }
  112. for (int i = 0; i < mvs.Length; i++)
  113. {
  114. ref var mv = ref cm.PrevFrameMvs[i];
  115. mv.Mv[0].Row = mvs[i].Mvs[0].Row;
  116. mv.Mv[0].Col = mvs[i].Mvs[0].Col;
  117. mv.Mv[1].Row = mvs[i].Mvs[1].Row;
  118. mv.Mv[1].Col = mvs[i].Mvs[1].Col;
  119. mv.RefFrame[0] = (sbyte)mvs[i].RefFrames[0];
  120. mv.RefFrame[1] = (sbyte)mvs[i].RefFrames[1];
  121. }
  122. }
  123. private static void GetMvs(ref Vp9Common cm, Span<Vp9MvRef> mvs)
  124. {
  125. if (mvs.Length > cm.CurFrameMvs.Length)
  126. {
  127. throw new ArgumentException($"Size mismatch, expected: {cm.CurFrameMvs.Length}, but got: {mvs.Length}.");
  128. }
  129. for (int i = 0; i < mvs.Length; i++)
  130. {
  131. ref var mv = ref cm.CurFrameMvs[i];
  132. mvs[i].Mvs[0].Row = mv.Mv[0].Row;
  133. mvs[i].Mvs[0].Col = mv.Mv[0].Col;
  134. mvs[i].Mvs[1].Row = mv.Mv[1].Row;
  135. mvs[i].Mvs[1].Col = mv.Mv[1].Col;
  136. mvs[i].RefFrames[0] = mv.RefFrame[0];
  137. mvs[i].RefFrames[1] = mv.RefFrame[1];
  138. }
  139. }
  140. public void Dispose() => _allocator.Dispose();
  141. }
  142. }