VideoDecoder.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. using ChocolArm64.Memory;
  2. using Ryujinx.Graphics.Gal;
  3. using Ryujinx.Graphics.Memory;
  4. using Ryujinx.Graphics.Texture;
  5. using Ryujinx.Graphics.Vic;
  6. using System;
  7. namespace Ryujinx.Graphics.VDec
  8. {
  9. unsafe class VideoDecoder
  10. {
  11. private NvGpu Gpu;
  12. private H264Decoder H264Decoder;
  13. private Vp9Decoder Vp9Decoder;
  14. private VideoCodec CurrentVideoCodec;
  15. private long DecoderContextAddress;
  16. private long FrameDataAddress;
  17. private long VpxCurrLumaAddress;
  18. private long VpxRef0LumaAddress;
  19. private long VpxRef1LumaAddress;
  20. private long VpxRef2LumaAddress;
  21. private long VpxCurrChromaAddress;
  22. private long VpxRef0ChromaAddress;
  23. private long VpxRef1ChromaAddress;
  24. private long VpxRef2ChromaAddress;
  25. private long VpxProbTablesAddress;
  26. public VideoDecoder(NvGpu Gpu)
  27. {
  28. this.Gpu = Gpu;
  29. H264Decoder = new H264Decoder();
  30. Vp9Decoder = new Vp9Decoder();
  31. }
  32. public void Process(NvGpuVmm Vmm, int MethodOffset, int[] Arguments)
  33. {
  34. VideoDecoderMeth Method = (VideoDecoderMeth)MethodOffset;
  35. switch (Method)
  36. {
  37. case VideoDecoderMeth.SetVideoCodec: SetVideoCodec (Vmm, Arguments); break;
  38. case VideoDecoderMeth.Execute: Execute (Vmm, Arguments); break;
  39. case VideoDecoderMeth.SetDecoderCtxAddr: SetDecoderCtxAddr (Vmm, Arguments); break;
  40. case VideoDecoderMeth.SetFrameDataAddr: SetFrameDataAddr (Vmm, Arguments); break;
  41. case VideoDecoderMeth.SetVpxCurrLumaAddr: SetVpxCurrLumaAddr (Vmm, Arguments); break;
  42. case VideoDecoderMeth.SetVpxRef0LumaAddr: SetVpxRef0LumaAddr (Vmm, Arguments); break;
  43. case VideoDecoderMeth.SetVpxRef1LumaAddr: SetVpxRef1LumaAddr (Vmm, Arguments); break;
  44. case VideoDecoderMeth.SetVpxRef2LumaAddr: SetVpxRef2LumaAddr (Vmm, Arguments); break;
  45. case VideoDecoderMeth.SetVpxCurrChromaAddr: SetVpxCurrChromaAddr(Vmm, Arguments); break;
  46. case VideoDecoderMeth.SetVpxRef0ChromaAddr: SetVpxRef0ChromaAddr(Vmm, Arguments); break;
  47. case VideoDecoderMeth.SetVpxRef1ChromaAddr: SetVpxRef1ChromaAddr(Vmm, Arguments); break;
  48. case VideoDecoderMeth.SetVpxRef2ChromaAddr: SetVpxRef2ChromaAddr(Vmm, Arguments); break;
  49. case VideoDecoderMeth.SetVpxProbTablesAddr: SetVpxProbTablesAddr(Vmm, Arguments); break;
  50. }
  51. }
  52. private void SetVideoCodec(NvGpuVmm Vmm, int[] Arguments)
  53. {
  54. CurrentVideoCodec = (VideoCodec)Arguments[0];
  55. }
  56. private void Execute(NvGpuVmm Vmm, int[] Arguments)
  57. {
  58. if (CurrentVideoCodec == VideoCodec.H264)
  59. {
  60. int FrameDataSize = Vmm.ReadInt32(DecoderContextAddress + 0x48);
  61. H264ParameterSets Params = MemoryHelper.Read<H264ParameterSets>(Vmm.Memory, Vmm.GetPhysicalAddress(DecoderContextAddress + 0x58));
  62. H264Matrices Matrices = new H264Matrices()
  63. {
  64. ScalingMatrix4 = Vmm.ReadBytes(DecoderContextAddress + 0x1c0, 6 * 16),
  65. ScalingMatrix8 = Vmm.ReadBytes(DecoderContextAddress + 0x220, 2 * 64)
  66. };
  67. byte[] FrameData = Vmm.ReadBytes(FrameDataAddress, FrameDataSize);
  68. H264Decoder.Decode(Params, Matrices, FrameData);
  69. }
  70. else if (CurrentVideoCodec == VideoCodec.Vp9)
  71. {
  72. int FrameDataSize = Vmm.ReadInt32(DecoderContextAddress + 0x30);
  73. Vp9FrameKeys Keys = new Vp9FrameKeys()
  74. {
  75. CurrKey = Vmm.GetPhysicalAddress(VpxCurrLumaAddress),
  76. Ref0Key = Vmm.GetPhysicalAddress(VpxRef0LumaAddress),
  77. Ref1Key = Vmm.GetPhysicalAddress(VpxRef1LumaAddress),
  78. Ref2Key = Vmm.GetPhysicalAddress(VpxRef2LumaAddress)
  79. };
  80. Vp9FrameHeader Header = MemoryHelper.Read<Vp9FrameHeader>(Vmm.Memory, Vmm.GetPhysicalAddress(DecoderContextAddress + 0x48));
  81. Vp9ProbabilityTables Probs = new Vp9ProbabilityTables()
  82. {
  83. SegmentationTreeProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x387, 0x7),
  84. SegmentationPredProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x38e, 0x3),
  85. Tx8x8Probs = Vmm.ReadBytes(VpxProbTablesAddress + 0x470, 0x2),
  86. Tx16x16Probs = Vmm.ReadBytes(VpxProbTablesAddress + 0x472, 0x4),
  87. Tx32x32Probs = Vmm.ReadBytes(VpxProbTablesAddress + 0x476, 0x6),
  88. CoefProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x5a0, 0x900),
  89. SkipProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x537, 0x3),
  90. InterModeProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x400, 0x1c),
  91. InterpFilterProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x52a, 0x8),
  92. IsInterProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x41c, 0x4),
  93. CompModeProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x532, 0x5),
  94. SingleRefProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x580, 0xa),
  95. CompRefProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x58a, 0x5),
  96. YModeProbs0 = Vmm.ReadBytes(VpxProbTablesAddress + 0x480, 0x20),
  97. YModeProbs1 = Vmm.ReadBytes(VpxProbTablesAddress + 0x47c, 0x4),
  98. PartitionProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x4e0, 0x40),
  99. MvJointProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x53b, 0x3),
  100. MvSignProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x53e, 0x3),
  101. MvClassProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x54c, 0x14),
  102. MvClass0BitProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x540, 0x3),
  103. MvBitsProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x56c, 0x14),
  104. MvClass0FrProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x560, 0xc),
  105. MvFrProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x542, 0x6),
  106. MvClass0HpProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x548, 0x2),
  107. MvHpProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x54a, 0x2)
  108. };
  109. byte[] FrameData = Vmm.ReadBytes(FrameDataAddress, FrameDataSize);
  110. Vp9Decoder.Decode(Keys, Header, Probs, FrameData);
  111. }
  112. else
  113. {
  114. ThrowUnimplementedCodec();
  115. }
  116. }
  117. private void SetDecoderCtxAddr(NvGpuVmm Vmm, int[] Arguments)
  118. {
  119. DecoderContextAddress = GetAddress(Arguments);
  120. }
  121. private void SetFrameDataAddr(NvGpuVmm Vmm, int[] Arguments)
  122. {
  123. FrameDataAddress = GetAddress(Arguments);
  124. }
  125. private void SetVpxCurrLumaAddr(NvGpuVmm Vmm, int[] Arguments)
  126. {
  127. VpxCurrLumaAddress = GetAddress(Arguments);
  128. }
  129. private void SetVpxRef0LumaAddr(NvGpuVmm Vmm, int[] Arguments)
  130. {
  131. VpxRef0LumaAddress = GetAddress(Arguments);
  132. }
  133. private void SetVpxRef1LumaAddr(NvGpuVmm Vmm, int[] Arguments)
  134. {
  135. VpxRef1LumaAddress = GetAddress(Arguments);
  136. }
  137. private void SetVpxRef2LumaAddr(NvGpuVmm Vmm, int[] Arguments)
  138. {
  139. VpxRef2LumaAddress = GetAddress(Arguments);
  140. }
  141. private void SetVpxCurrChromaAddr(NvGpuVmm Vmm, int[] Arguments)
  142. {
  143. VpxCurrChromaAddress = GetAddress(Arguments);
  144. }
  145. private void SetVpxRef0ChromaAddr(NvGpuVmm Vmm, int[] Arguments)
  146. {
  147. VpxRef0ChromaAddress = GetAddress(Arguments);
  148. }
  149. private void SetVpxRef1ChromaAddr(NvGpuVmm Vmm, int[] Arguments)
  150. {
  151. VpxRef1ChromaAddress = GetAddress(Arguments);
  152. }
  153. private void SetVpxRef2ChromaAddr(NvGpuVmm Vmm, int[] Arguments)
  154. {
  155. VpxRef2ChromaAddress = GetAddress(Arguments);
  156. }
  157. private void SetVpxProbTablesAddr(NvGpuVmm Vmm, int[] Arguments)
  158. {
  159. VpxProbTablesAddress = GetAddress(Arguments);
  160. }
  161. private static long GetAddress(int[] Arguments)
  162. {
  163. return (long)(uint)Arguments[0] << 8;
  164. }
  165. internal void CopyPlanes(NvGpuVmm Vmm, SurfaceOutputConfig OutputConfig)
  166. {
  167. switch (OutputConfig.PixelFormat)
  168. {
  169. case SurfacePixelFormat.RGBA8: CopyPlanesRgba8 (Vmm, OutputConfig); break;
  170. case SurfacePixelFormat.YUV420P: CopyPlanesYuv420p(Vmm, OutputConfig); break;
  171. default: ThrowUnimplementedPixelFormat(OutputConfig.PixelFormat); break;
  172. }
  173. }
  174. private void CopyPlanesRgba8(NvGpuVmm Vmm, SurfaceOutputConfig OutputConfig)
  175. {
  176. FFmpegFrame Frame = FFmpegWrapper.GetFrameRgba();
  177. if ((Frame.Width | Frame.Height) == 0)
  178. {
  179. return;
  180. }
  181. GalImage Image = new GalImage(
  182. OutputConfig.SurfaceWidth,
  183. OutputConfig.SurfaceHeight, 1,
  184. OutputConfig.GobBlockHeight,
  185. GalMemoryLayout.BlockLinear,
  186. GalImageFormat.RGBA8 | GalImageFormat.Unorm);
  187. ImageUtils.WriteTexture(Vmm, Image, Vmm.GetPhysicalAddress(OutputConfig.SurfaceLumaAddress), Frame.Data);
  188. }
  189. private void CopyPlanesYuv420p(NvGpuVmm Vmm, SurfaceOutputConfig OutputConfig)
  190. {
  191. FFmpegFrame Frame = FFmpegWrapper.GetFrame();
  192. if ((Frame.Width | Frame.Height) == 0)
  193. {
  194. return;
  195. }
  196. int HalfSrcWidth = Frame.Width / 2;
  197. int HalfWidth = Frame.Width / 2;
  198. int HalfHeight = Frame.Height / 2;
  199. int AlignedWidth = (OutputConfig.SurfaceWidth + 0xff) & ~0xff;
  200. for (int Y = 0; Y < Frame.Height; Y++)
  201. {
  202. int Src = Y * Frame.Width;
  203. int Dst = Y * AlignedWidth;
  204. int Size = Frame.Width;
  205. for (int Offset = 0; Offset < Size; Offset++)
  206. {
  207. Vmm.WriteByte(OutputConfig.SurfaceLumaAddress + Dst + Offset, *(Frame.LumaPtr + Src + Offset));
  208. }
  209. }
  210. //Copy chroma data from both channels with interleaving.
  211. for (int Y = 0; Y < HalfHeight; Y++)
  212. {
  213. int Src = Y * HalfSrcWidth;
  214. int Dst = Y * AlignedWidth;
  215. for (int X = 0; X < HalfWidth; X++)
  216. {
  217. Vmm.WriteByte(OutputConfig.SurfaceChromaUAddress + Dst + X * 2 + 0, *(Frame.ChromaBPtr + Src + X));
  218. Vmm.WriteByte(OutputConfig.SurfaceChromaUAddress + Dst + X * 2 + 1, *(Frame.ChromaRPtr + Src + X));
  219. }
  220. }
  221. }
  222. private void ThrowUnimplementedCodec()
  223. {
  224. throw new NotImplementedException("Codec \"" + CurrentVideoCodec + "\" is not supported!");
  225. }
  226. private void ThrowUnimplementedPixelFormat(SurfacePixelFormat PixelFormat)
  227. {
  228. throw new NotImplementedException("Pixel format \"" + PixelFormat + "\" is not supported!");
  229. }
  230. }
  231. }