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
This commit is contained in:
Ac_K 2021-10-12 22:55:57 +02:00 committed by GitHub
parent a7109c767b
commit d1604aa762
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 220 additions and 35 deletions

View File

@ -5,27 +5,26 @@ using System.Diagnostics;
using System.IO; using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Nvdec.H264 namespace Ryujinx.Graphics.Nvdec.FFmpeg
{ {
unsafe class FFmpegContext : IDisposable unsafe class FFmpegContext : IDisposable
{ {
private readonly AVCodec_decode _h264Decode; private readonly AVCodec_decode _decodeFrame;
private static readonly av_log_set_callback_callback _logFunc; private static readonly av_log_set_callback_callback _logFunc;
private readonly AVCodec* _codec; private readonly AVCodec* _codec;
private AVPacket* _packet; private AVPacket* _packet;
private AVCodecContext* _context; private AVCodecContext* _context;
public FFmpegContext() public FFmpegContext(AVCodecID codecId)
{ {
_codec = ffmpeg.avcodec_find_decoder(AVCodecID.AV_CODEC_ID_H264); _codec = ffmpeg.avcodec_find_decoder(codecId);
_context = ffmpeg.avcodec_alloc_context3(_codec); _context = ffmpeg.avcodec_alloc_context3(_codec);
_context->debug |= ffmpeg.FF_DEBUG_MMCO;
ffmpeg.avcodec_open2(_context, _codec, null); ffmpeg.avcodec_open2(_context, _codec, null);
_packet = ffmpeg.av_packet_alloc(); _packet = ffmpeg.av_packet_alloc();
_h264Decode = Marshal.GetDelegateForFunctionPointer<AVCodec_decode>(_codec->decode.Pointer); _decodeFrame = Marshal.GetDelegateForFunctionPointer<AVCodec_decode>(_codec->decode.Pointer);
} }
static FFmpegContext() static FFmpegContext()
@ -115,7 +114,7 @@ namespace Ryujinx.Graphics.Nvdec.H264
{ {
_packet->data = ptr; _packet->data = ptr;
_packet->size = bitstream.Length; _packet->size = bitstream.Length;
result = _h264Decode(_context, output.Frame, &gotFrame, _packet); result = _decodeFrame(_context, output.Frame, &gotFrame, _packet);
} }
if (gotFrame == 0) if (gotFrame == 0)
@ -126,7 +125,7 @@ namespace Ryujinx.Graphics.Nvdec.H264
// Get the next delayed frame by passing a 0 length packet. // Get the next delayed frame by passing a 0 length packet.
_packet->data = null; _packet->data = null;
_packet->size = 0; _packet->size = 0;
result = _h264Decode(_context, output.Frame, &gotFrame, _packet); result = _decodeFrame(_context, output.Frame, &gotFrame, _packet);
// We need to set B frames to 0 as we already consumed all delayed frames. // We need to set B frames to 0 as we already consumed all delayed frames.
// This prevents the decoder from trying to return a delayed frame next time. // This prevents the decoder from trying to return a delayed frame next time.
@ -138,6 +137,7 @@ namespace Ryujinx.Graphics.Nvdec.H264
if (gotFrame == 0) if (gotFrame == 0)
{ {
ffmpeg.av_frame_unref(output.Frame); ffmpeg.av_frame_unref(output.Frame);
return -1; return -1;
} }

View File

@ -1,7 +1,8 @@
using Ryujinx.Graphics.Video; using FFmpeg.AutoGen;
using Ryujinx.Graphics.Video;
using System; using System;
namespace Ryujinx.Graphics.Nvdec.H264 namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
{ {
public sealed class Decoder : IH264Decoder public sealed class Decoder : IH264Decoder
{ {
@ -11,7 +12,7 @@ namespace Ryujinx.Graphics.Nvdec.H264
private readonly byte[] _workBuffer = new byte[WorkBufferSize]; private readonly byte[] _workBuffer = new byte[WorkBufferSize];
private FFmpegContext _context = new FFmpegContext(); private FFmpegContext _context = new FFmpegContext(AVCodecID.AV_CODEC_ID_H264);
private int _oldOutputWidth; private int _oldOutputWidth;
private int _oldOutputHeight; private int _oldOutputHeight;
@ -29,7 +30,7 @@ namespace Ryujinx.Graphics.Nvdec.H264
outSurf.RequestedHeight != _oldOutputHeight) outSurf.RequestedHeight != _oldOutputHeight)
{ {
_context.Dispose(); _context.Dispose();
_context = new FFmpegContext(); _context = new FFmpegContext(AVCodecID.AV_CODEC_ID_H264);
_oldOutputWidth = outSurf.RequestedWidth; _oldOutputWidth = outSurf.RequestedWidth;
_oldOutputHeight = outSurf.RequestedHeight; _oldOutputHeight = outSurf.RequestedHeight;

View File

@ -1,7 +1,7 @@
using System; using System;
using System.Numerics; using System.Numerics;
namespace Ryujinx.Graphics.Nvdec.H264 namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
{ {
struct H264BitStreamWriter struct H264BitStreamWriter
{ {

View File

@ -2,7 +2,7 @@
using Ryujinx.Graphics.Video; using Ryujinx.Graphics.Video;
using System; using System;
namespace Ryujinx.Graphics.Nvdec.H264 namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
{ {
static class SpsAndPpsReconstruction static class SpsAndPpsReconstruction
{ {

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net5.0</TargetFramework>
@ -6,10 +6,11 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="FFmpeg.AutoGen" Version="4.4.0" /> <PackageReference Include="FFmpeg.AutoGen" Version="4.4.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.Video\Ryujinx.Graphics.Video.csproj" /> <ProjectReference Include="..\Ryujinx.Graphics.Video\Ryujinx.Graphics.Video.csproj" />
</ItemGroup> </ItemGroup>

View File

@ -2,7 +2,7 @@
using Ryujinx.Graphics.Video; using Ryujinx.Graphics.Video;
using System; using System;
namespace Ryujinx.Graphics.Nvdec.H264 namespace Ryujinx.Graphics.Nvdec.FFmpeg
{ {
unsafe class Surface : ISurface unsafe class Surface : ISurface
{ {

View File

@ -0,0 +1,53 @@
using FFmpeg.AutoGen;
using Ryujinx.Graphics.Video;
using System;
namespace Ryujinx.Graphics.Nvdec.FFmpeg.Vp8
{
public sealed class Decoder : IDecoder
{
public bool IsHardwareAccelerated => false;
private readonly FFmpegContext _context = new FFmpegContext(AVCodecID.AV_CODEC_ID_VP8);
public ISurface CreateSurface(int width, int height)
{
return new Surface(width, height);
}
public bool Decode(ref Vp8PictureInfo pictureInfo, ISurface output, ReadOnlySpan<byte> bitstream)
{
Surface outSurf = (Surface)output;
int uncompHeaderSize = pictureInfo.KeyFrame ? 10 : 3;
byte[] frame = new byte[bitstream.Length + uncompHeaderSize];
uint firstPartSizeShifted = pictureInfo.FirstPartSize << 5;
frame[0] = (byte)(pictureInfo.KeyFrame ? 0 : 1);
frame[0] |= (byte)((pictureInfo.Version & 7) << 1);
frame[0] |= 1 << 4;
frame[0] |= (byte)firstPartSizeShifted;
frame[1] |= (byte)(firstPartSizeShifted >> 8);
frame[2] |= (byte)(firstPartSizeShifted >> 16);
if (pictureInfo.KeyFrame)
{
frame[3] = 0x9d;
frame[4] = 0x01;
frame[5] = 0x2a;
frame[6] = (byte)pictureInfo.FrameWidth;
frame[7] = (byte)((pictureInfo.FrameWidth >> 8) & 0x3F);
frame[8] = (byte)pictureInfo.FrameHeight;
frame[9] = (byte)((pictureInfo.FrameHeight >> 8) & 0x3F);
}
bitstream.CopyTo(new Span<byte>(frame).Slice(uncompHeaderSize));
return _context.DecodeFrame(outSurf, frame) == 0;
}
public void Dispose() => _context.Dispose();
}
}

View File

@ -1,4 +1,4 @@
using Ryujinx.Graphics.Nvdec.H264; using Ryujinx.Graphics.Nvdec.FFmpeg.H264;
using Ryujinx.Graphics.Nvdec.Image; using Ryujinx.Graphics.Nvdec.Image;
using Ryujinx.Graphics.Nvdec.Types.H264; using Ryujinx.Graphics.Nvdec.Types.H264;
using Ryujinx.Graphics.Video; using Ryujinx.Graphics.Video;
@ -10,7 +10,7 @@ namespace Ryujinx.Graphics.Nvdec
{ {
private const int MbSizeInPixels = 16; 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<PictureInfo>(state.SetPictureInfoOffset); PictureInfo pictureInfo = rm.Gmm.DeviceRead<PictureInfo>(state.SetPictureInfoOffset);
H264PictureInfo info = pictureInfo.Convert(); H264PictureInfo info = pictureInfo.Convert();
@ -25,7 +25,7 @@ namespace Ryujinx.Graphics.Nvdec
uint lumaOffset = state.SetSurfaceLumaOffset[surfaceIndex]; uint lumaOffset = state.SetSurfaceLumaOffset[surfaceIndex];
uint chromaOffset = state.SetSurfaceChromaOffset[surfaceIndex]; uint chromaOffset = state.SetSurfaceChromaOffset[surfaceIndex];
Decoder decoder = context.GetDecoder(); Decoder decoder = context.GetH264Decoder();
ISurface outputSurface = rm.Cache.Get(decoder, 0, 0, width, height); ISurface outputSurface = rm.Cache.Get(decoder, 0, 0, width, height);

View File

@ -1,21 +1,29 @@
using Ryujinx.Graphics.Nvdec.H264;
using System; using System;
namespace Ryujinx.Graphics.Nvdec namespace Ryujinx.Graphics.Nvdec
{ {
class NvdecDecoderContext : IDisposable 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() public void Dispose()
{ {
_decoder?.Dispose(); _h264Decoder?.Dispose();
_decoder = null; _h264Decoder = null;
_vp8Decoder?.Dispose();
_vp8Decoder = null;
} }
} }
} }

View File

@ -68,6 +68,9 @@ namespace Ryujinx.Graphics.Nvdec
case CodecId.H264: case CodecId.H264:
H264Decoder.Decode(_currentContext, _rm, ref _state.State); H264Decoder.Decode(_currentContext, _rm, ref _state.State);
break; break;
case CodecId.Vp8:
Vp8Decoder.Decode(_currentContext, _rm, ref _state.State);
break;
case CodecId.Vp9: case CodecId.Vp9:
Vp9Decoder.Decode(_rm, ref _state.State); Vp9Decoder.Decode(_rm, ref _state.State);
break; break;

View File

@ -9,7 +9,7 @@
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" /> <ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.Device\Ryujinx.Graphics.Device.csproj" /> <ProjectReference Include="..\Ryujinx.Graphics.Device\Ryujinx.Graphics.Device.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.Gpu\Ryujinx.Graphics.Gpu.csproj" /> <ProjectReference Include="..\Ryujinx.Graphics.Gpu\Ryujinx.Graphics.Gpu.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.Nvdec.H264\Ryujinx.Graphics.Nvdec.H264.csproj" /> <ProjectReference Include="..\Ryujinx.Graphics.Nvdec.FFmpeg\Ryujinx.Graphics.Nvdec.FFmpeg.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.Nvdec.Vp9\Ryujinx.Graphics.Nvdec.Vp9.csproj" /> <ProjectReference Include="..\Ryujinx.Graphics.Nvdec.Vp9\Ryujinx.Graphics.Nvdec.Vp9.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.Texture\Ryujinx.Graphics.Texture.csproj" /> <ProjectReference Include="..\Ryujinx.Graphics.Texture\Ryujinx.Graphics.Texture.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.Video\Ryujinx.Graphics.Video.csproj" /> <ProjectReference Include="..\Ryujinx.Graphics.Video\Ryujinx.Graphics.Video.csproj" />

View File

@ -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<uint> 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<uint> 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<int> OutputTop; // in units of 256
public Array2<int> 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<sbyte> OutputMemoryLayout; // output NV12/NV24 setting. item 0:golden - 1: altref - 2: last
public byte SegmentationFeatureDataUpdate;
public Array3<byte> Reserved3;
public uint ResultValue; // ucode return result
public Array8<uint> PartitionOffset;
public Array3<uint> Reserved4;
#pragma warning restore CS0649
public Vp8PictureInfo Convert()
{
return new Vp8PictureInfo()
{
KeyFrame = KeyFrame != 0,
FirstPartSize = FirstPartSize,
Version = Version,
FrameWidth = FrameWidth,
FrameHeight = FrameHeight
};
}
}
}

View File

@ -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<PictureInfo>(state.SetPictureInfoOffset);
ReadOnlySpan<byte> 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);
}
}
}

View File

@ -0,0 +1,11 @@
namespace Ryujinx.Graphics.Video
{
public ref struct Vp8PictureInfo
{
public bool KeyFrame;
public uint FirstPartSize;
public uint Version;
public ushort FrameWidth;
public ushort FrameHeight;
}
}

View File

@ -51,8 +51,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.Vp9"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Vic", "Ryujinx.Graphics.Vic\Ryujinx.Graphics.Vic.csproj", "{81BB2C11-9408-4EA3-822E-42987AF54429}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Vic", "Ryujinx.Graphics.Vic\Ryujinx.Graphics.Vic.csproj", "{81BB2C11-9408-4EA3-822E-42987AF54429}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.H264", "Ryujinx.Graphics.Nvdec.H264\Ryujinx.Graphics.Nvdec.H264.csproj", "{990F9601-343E-46CB-8529-B498FA761A92}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Video", "Ryujinx.Graphics.Video\Ryujinx.Graphics.Video.csproj", "{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Video", "Ryujinx.Graphics.Video\Ryujinx.Graphics.Video.csproj", "{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.OpenAL", "Ryujinx.Audio.Backends.OpenAL\Ryujinx.Audio.Backends.OpenAL.csproj", "{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.OpenAL", "Ryujinx.Audio.Backends.OpenAL\Ryujinx.Audio.Backends.OpenAL.csproj", "{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}"
@ -67,7 +65,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.SDL2.Common", "Ryuj
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.SDL2", "Ryujinx.Audio.Backends.SDL2\Ryujinx.Audio.Backends.SDL2.csproj", "{D99A395A-8569-4DB0-B336-900647890052}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.SDL2", "Ryujinx.Audio.Backends.SDL2\Ryujinx.Audio.Backends.SDL2.csproj", "{D99A395A-8569-4DB0-B336-900647890052}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Headless.SDL2", "Ryujinx.Headless.SDL2\Ryujinx.Headless.SDL2.csproj", "{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Headless.SDL2", "Ryujinx.Headless.SDL2\Ryujinx.Headless.SDL2.csproj", "{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Graphics.Nvdec.FFmpeg", "Ryujinx.Graphics.Nvdec.FFmpeg\Ryujinx.Graphics.Nvdec.FFmpeg.csproj", "{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -159,10 +159,6 @@ Global
{81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|Any CPU.Build.0 = Debug|Any CPU {81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|Any CPU.Build.0 = Debug|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Release|Any CPU.ActiveCfg = Release|Any CPU {81BB2C11-9408-4EA3-822E-42987AF54429}.Release|Any CPU.ActiveCfg = Release|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Release|Any CPU.Build.0 = Release|Any CPU {81BB2C11-9408-4EA3-822E-42987AF54429}.Release|Any CPU.Build.0 = Release|Any CPU
{990F9601-343E-46CB-8529-B498FA761A92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{990F9601-343E-46CB-8529-B498FA761A92}.Debug|Any CPU.Build.0 = Debug|Any CPU
{990F9601-343E-46CB-8529-B498FA761A92}.Release|Any CPU.ActiveCfg = Release|Any CPU
{990F9601-343E-46CB-8529-B498FA761A92}.Release|Any CPU.Build.0 = Release|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|Any CPU.Build.0 = Debug|Any CPU {FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|Any CPU.ActiveCfg = Release|Any CPU {FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -195,6 +191,10 @@ Global
{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Debug|Any CPU.Build.0 = Debug|Any CPU {390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Debug|Any CPU.Build.0 = Debug|Any CPU
{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Release|Any CPU.ActiveCfg = Release|Any CPU {390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Release|Any CPU.ActiveCfg = Release|Any CPU
{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Release|Any CPU.Build.0 = Release|Any CPU {390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Release|Any CPU.Build.0 = Release|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -20,7 +20,7 @@
<PackageReference Include="DiscordRichPresence" Version="1.0.175" /> <PackageReference Include="DiscordRichPresence" Version="1.0.175" />
<PackageReference Include="GtkSharp" Version="3.22.25.128" /> <PackageReference Include="GtkSharp" Version="3.22.25.128" />
<PackageReference Include="GtkSharp.Dependencies" Version="1.1.0" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" /> <PackageReference Include="GtkSharp.Dependencies" Version="1.1.0" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="4.4.0-build7" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" /> <PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="4.4.0-build9" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" /> <PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
<PackageReference Include="OpenTK.Graphics" Version="4.5.0" /> <PackageReference Include="OpenTK.Graphics" Version="4.5.0" />
<PackageReference Include="SPB" Version="0.0.3-build15" /> <PackageReference Include="SPB" Version="0.0.3-build15" />