From d1604aa762a3f669a3fecff0a30b7360399954bc Mon Sep 17 00:00:00 2001 From: Ac_K Date: Tue, 12 Oct 2021 22:55:57 +0200 Subject: nvdec: Adding Vp8 codec support (#2707) * first try * second try * working update * Final impl * Fixes nits * Fix everything * remove leftover * Update FFmpegContext.cs * Update Surface.cs * Addresses gdkchan feedback * bool not byte * Addresses gdkchan feedback --- Ryujinx.Graphics.Nvdec/H264Decoder.cs | 6 +- Ryujinx.Graphics.Nvdec/NvdecDecoderContext.cs | 20 ++++-- Ryujinx.Graphics.Nvdec/NvdecDevice.cs | 3 + .../Ryujinx.Graphics.Nvdec.csproj | 2 +- Ryujinx.Graphics.Nvdec/Types/Vp8/PictureInfo.cs | 75 ++++++++++++++++++++++ Ryujinx.Graphics.Nvdec/Vp8Decoder.cs | 33 ++++++++++ 6 files changed, 129 insertions(+), 10 deletions(-) create mode 100644 Ryujinx.Graphics.Nvdec/Types/Vp8/PictureInfo.cs create mode 100644 Ryujinx.Graphics.Nvdec/Vp8Decoder.cs (limited to 'Ryujinx.Graphics.Nvdec') diff --git a/Ryujinx.Graphics.Nvdec/H264Decoder.cs b/Ryujinx.Graphics.Nvdec/H264Decoder.cs index 1ee3997b..69eeb494 100644 --- a/Ryujinx.Graphics.Nvdec/H264Decoder.cs +++ b/Ryujinx.Graphics.Nvdec/H264Decoder.cs @@ -1,4 +1,4 @@ -using Ryujinx.Graphics.Nvdec.H264; +using Ryujinx.Graphics.Nvdec.FFmpeg.H264; using Ryujinx.Graphics.Nvdec.Image; using Ryujinx.Graphics.Nvdec.Types.H264; using Ryujinx.Graphics.Video; @@ -10,7 +10,7 @@ namespace Ryujinx.Graphics.Nvdec { private const int MbSizeInPixels = 16; - public unsafe static void Decode(NvdecDecoderContext context, ResourceManager rm, ref NvdecRegisters state) + public static void Decode(NvdecDecoderContext context, ResourceManager rm, ref NvdecRegisters state) { PictureInfo pictureInfo = rm.Gmm.DeviceRead(state.SetPictureInfoOffset); H264PictureInfo info = pictureInfo.Convert(); @@ -25,7 +25,7 @@ namespace Ryujinx.Graphics.Nvdec uint lumaOffset = state.SetSurfaceLumaOffset[surfaceIndex]; uint chromaOffset = state.SetSurfaceChromaOffset[surfaceIndex]; - Decoder decoder = context.GetDecoder(); + Decoder decoder = context.GetH264Decoder(); ISurface outputSurface = rm.Cache.Get(decoder, 0, 0, width, height); diff --git a/Ryujinx.Graphics.Nvdec/NvdecDecoderContext.cs b/Ryujinx.Graphics.Nvdec/NvdecDecoderContext.cs index 90da0bee..54934bc5 100644 --- a/Ryujinx.Graphics.Nvdec/NvdecDecoderContext.cs +++ b/Ryujinx.Graphics.Nvdec/NvdecDecoderContext.cs @@ -1,21 +1,29 @@ -using Ryujinx.Graphics.Nvdec.H264; using System; namespace Ryujinx.Graphics.Nvdec { class NvdecDecoderContext : IDisposable { - private Decoder _decoder; + private FFmpeg.H264.Decoder _h264Decoder; + private FFmpeg.Vp8.Decoder _vp8Decoder; - public Decoder GetDecoder() + public FFmpeg.H264.Decoder GetH264Decoder() { - return _decoder ??= new Decoder(); + return _h264Decoder ??= new FFmpeg.H264.Decoder(); + } + + public FFmpeg.Vp8.Decoder GetVp8Decoder() + { + return _vp8Decoder ??= new FFmpeg.Vp8.Decoder(); } public void Dispose() { - _decoder?.Dispose(); - _decoder = null; + _h264Decoder?.Dispose(); + _h264Decoder = null; + + _vp8Decoder?.Dispose(); + _vp8Decoder = null; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics.Nvdec/NvdecDevice.cs b/Ryujinx.Graphics.Nvdec/NvdecDevice.cs index 5319429b..18c2fc13 100644 --- a/Ryujinx.Graphics.Nvdec/NvdecDevice.cs +++ b/Ryujinx.Graphics.Nvdec/NvdecDevice.cs @@ -68,6 +68,9 @@ namespace Ryujinx.Graphics.Nvdec case CodecId.H264: H264Decoder.Decode(_currentContext, _rm, ref _state.State); break; + case CodecId.Vp8: + Vp8Decoder.Decode(_currentContext, _rm, ref _state.State); + break; case CodecId.Vp9: Vp9Decoder.Decode(_rm, ref _state.State); break; diff --git a/Ryujinx.Graphics.Nvdec/Ryujinx.Graphics.Nvdec.csproj b/Ryujinx.Graphics.Nvdec/Ryujinx.Graphics.Nvdec.csproj index 4c20979d..095e0e59 100644 --- a/Ryujinx.Graphics.Nvdec/Ryujinx.Graphics.Nvdec.csproj +++ b/Ryujinx.Graphics.Nvdec/Ryujinx.Graphics.Nvdec.csproj @@ -9,7 +9,7 @@ - + diff --git a/Ryujinx.Graphics.Nvdec/Types/Vp8/PictureInfo.cs b/Ryujinx.Graphics.Nvdec/Types/Vp8/PictureInfo.cs new file mode 100644 index 00000000..844f2103 --- /dev/null +++ b/Ryujinx.Graphics.Nvdec/Types/Vp8/PictureInfo.cs @@ -0,0 +1,75 @@ +using Ryujinx.Common.Memory; +using Ryujinx.Graphics.Video; + +namespace Ryujinx.Graphics.Nvdec.Types.Vp8 +{ + struct PictureInfo + { +#pragma warning disable CS0649 + public Array13 Unknown0; + public uint GpTimerTimeoutValue; + public ushort FrameWidth; + public ushort FrameHeight; + public byte KeyFrame; // 1: key frame - 0: not + public byte Version; + public byte Flags0; + // TileFormat : 2 // 0: TBL; 1: KBL; + // GobHeight : 3 // Set GOB height, 0: GOB_2, 1: GOB_4, 2: GOB_8, 3: GOB_16, 4: GOB_32 (NVDEC3 onwards) + // ReserverdSurfaceFormat : 3 + public byte ErrorConcealOn; // 1: error conceal on - 0: off + public uint FirstPartSize; // the size of first partition (frame header and mb header partition) + public uint HistBufferSize; // in units of 256 + public uint VLDBufferSize; // in units of 1 + public Array2 FrameStride; // [y_c] + public uint LumaTopOffset; // offset of luma top field in units of 256 + public uint LumaBotOffset; // offset of luma bottom field in units of 256 + public uint LumaFrameOffset; // offset of luma frame in units of 256 + public uint ChromaTopOffset; // offset of chroma top field in units of 256 + public uint ChromaBotOffset; // offset of chroma bottom field in units of 256 + public uint ChromaFrameOffset; // offset of chroma frame in units of 256 + public uint Flags1; + // EnableTFOutput : 1; // =1, enable dbfdma to output the display surface; if disable, then the following configure on tf is useless. + // Remap for VC1 + // VC1MapYFlag : 1 + // MapYValue : 3 + // VC1MapUVFlag : 1 + // MapUVValue : 3 + // TF + // OutStride : 8 + // TilingFormat : 3; + // OutputStructure : 1 // 0:frame, 1:field + // Reserved0 : 11 + public Array2 OutputTop; // in units of 256 + public Array2 OutputBottom; // in units of 256 + // Histogram + public uint Flags2; + // EnableHistogram : 1 // enable histogram info collection + // HistogramStartX : 12 // start X of Histogram window + // HistogramStartY : 12 // start Y of Histogram window + // Reserved1 : 7 + // HistogramEndX : 12 // end X of Histogram window + // HistogramEndY : 12 // end y of Histogram window + // Reserved2 : 8 + // Decode picture buffer related + public sbyte CurrentOutputMemoryLayout; + public Array3 OutputMemoryLayout; // output NV12/NV24 setting. item 0:golden - 1: altref - 2: last + public byte SegmentationFeatureDataUpdate; + public Array3 Reserved3; + public uint ResultValue; // ucode return result + public Array8 PartitionOffset; + public Array3 Reserved4; +#pragma warning restore CS0649 + + public Vp8PictureInfo Convert() + { + return new Vp8PictureInfo() + { + KeyFrame = KeyFrame != 0, + FirstPartSize = FirstPartSize, + Version = Version, + FrameWidth = FrameWidth, + FrameHeight = FrameHeight + }; + } + } +} diff --git a/Ryujinx.Graphics.Nvdec/Vp8Decoder.cs b/Ryujinx.Graphics.Nvdec/Vp8Decoder.cs new file mode 100644 index 00000000..8a369984 --- /dev/null +++ b/Ryujinx.Graphics.Nvdec/Vp8Decoder.cs @@ -0,0 +1,33 @@ +using Ryujinx.Graphics.Nvdec.FFmpeg.Vp8; +using Ryujinx.Graphics.Nvdec.Image; +using Ryujinx.Graphics.Nvdec.Types.Vp8; +using Ryujinx.Graphics.Video; +using System; + +namespace Ryujinx.Graphics.Nvdec +{ + static class Vp8Decoder + { + public static void Decode(NvdecDecoderContext context, ResourceManager rm, ref NvdecRegisters state) + { + PictureInfo pictureInfo = rm.Gmm.DeviceRead(state.SetPictureInfoOffset); + ReadOnlySpan bitstream = rm.Gmm.DeviceGetSpan(state.SetBitstreamOffset, (int)pictureInfo.VLDBufferSize); + + Decoder decoder = context.GetVp8Decoder(); + + ISurface outputSurface = rm.Cache.Get(decoder, 0, 0, pictureInfo.FrameWidth, pictureInfo.FrameHeight); + + Vp8PictureInfo info = pictureInfo.Convert(); + + uint lumaOffset = state.SetSurfaceLumaOffset[3]; + uint chromaOffset = state.SetSurfaceChromaOffset[3]; + + if (decoder.Decode(ref info, outputSurface, bitstream)) + { + SurfaceWriter.Write(rm.Gmm, outputSurface, lumaOffset, chromaOffset); + } + + rm.Cache.Put(outputSurface); + } + } +} \ No newline at end of file -- cgit v1.2.3