diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2018-12-03 00:38:47 -0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-12-03 00:38:47 -0200 |
| commit | c86aacde76b5f8e503e2b412385c8491ecc86b3b (patch) | |
| tree | 8e4737422fba15199c1a6ce7c6345996c0e907b5 /Ryujinx.HLE/HOS | |
| parent | ad00fd02442cf9c0f00c4562635738042b521efa (diff) | |
NVDEC implementation using FFmpeg (#443)
* Initial nvdec implementation using FFmpeg
* Fix swapped channels on the video decoder and the G8R8 texture format
* Fix texture samplers not being set properly (regression)
* Rebased
* Remove unused code introduced on the rebase
* Add support for RGBA8 output format on the video image composer
* Correct spacing
* Some fixes for rebase and other tweaks
* Allow size mismatch on frame copy
* Get rid of GetHostAddress calls on VDec
Diffstat (limited to 'Ryujinx.HLE/HOS')
9 files changed, 214 insertions, 44 deletions
diff --git a/Ryujinx.HLE/HOS/Services/Mm/IRequest.cs b/Ryujinx.HLE/HOS/Services/Mm/IRequest.cs index 88cd57cf..72067d71 100644 --- a/Ryujinx.HLE/HOS/Services/Mm/IRequest.cs +++ b/Ryujinx.HLE/HOS/Services/Mm/IRequest.cs @@ -16,6 +16,7 @@ namespace Ryujinx.HLE.HOS.Services.Mm { { 1, InitializeOld }, { 4, Initialize }, + { 5, Finalize }, { 6, SetAndWait }, { 7, Get } }; @@ -40,6 +41,15 @@ namespace Ryujinx.HLE.HOS.Services.Mm return 0; } + public long Finalize(ServiceCtx Context) + { + Context.Device.Gpu.UninitializeVideoDecoder(); + + Logger.PrintStub(LogClass.ServiceMm, "Stubbed."); + + return 0; + } + public long SetAndWait(ServiceCtx Context) { Logger.PrintStub(LogClass.ServiceMm, "Stubbed."); diff --git a/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs b/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs index 6786d0e2..1b034bfa 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs @@ -23,11 +23,13 @@ namespace Ryujinx.HLE.HOS.Services.Nv private static Dictionary<string, IoctlProcessor> IoctlProcessors = new Dictionary<string, IoctlProcessor>() { - { "/dev/nvhost-as-gpu", ProcessIoctlNvGpuAS }, - { "/dev/nvhost-ctrl", ProcessIoctlNvHostCtrl }, - { "/dev/nvhost-ctrl-gpu", ProcessIoctlNvGpuGpu }, - { "/dev/nvhost-gpu", ProcessIoctlNvHostGpu }, - { "/dev/nvmap", ProcessIoctlNvMap } + { "/dev/nvhost-as-gpu", ProcessIoctlNvGpuAS }, + { "/dev/nvhost-ctrl", ProcessIoctlNvHostCtrl }, + { "/dev/nvhost-ctrl-gpu", ProcessIoctlNvGpuGpu }, + { "/dev/nvhost-gpu", ProcessIoctlNvHostChannel }, + { "/dev/nvhost-nvdec", ProcessIoctlNvHostChannel }, + { "/dev/nvhost-vic", ProcessIoctlNvHostChannel }, + { "/dev/nvmap", ProcessIoctlNvMap } }; public static GlobalStateTable Fds { get; private set; } @@ -166,9 +168,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv return ProcessIoctl(Context, Cmd, NvGpuGpuIoctl.ProcessIoctl); } - private static int ProcessIoctlNvHostGpu(ServiceCtx Context, int Cmd) + private static int ProcessIoctlNvHostChannel(ServiceCtx Context, int Cmd) { - return ProcessIoctl(Context, Cmd, NvHostChannelIoctl.ProcessIoctlGpu); + return ProcessIoctl(Context, Cmd, NvHostChannelIoctl.ProcessIoctl); } private static int ProcessIoctlNvMap(ServiceCtx Context, int Cmd) diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvChannelName.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvChannelName.cs deleted file mode 100644 index a2b5ea4c..00000000 --- a/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvChannelName.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Nv.NvHostChannel -{ - enum NvChannelName - { - Gpu - } -}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelCmdBuf.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelCmdBuf.cs new file mode 100644 index 00000000..44949597 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelCmdBuf.cs @@ -0,0 +1,12 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvHostChannel +{ + [StructLayout(LayoutKind.Sequential, Size = 8, Pack = 4)] + struct NvHostChannelCmdBuf + { + public int MemoryId; + public int Offset; + public int WordsCount; + } +}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelGetParamArg.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelGetParamArg.cs new file mode 100644 index 00000000..5c04e5d4 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelGetParamArg.cs @@ -0,0 +1,11 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvHostChannel +{ + [StructLayout(LayoutKind.Sequential, Size = 8, Pack = 4)] + struct NvHostChannelGetParamArg + { + public int Param; + public int Value; + } +}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs index d9f5602b..466f3e9b 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs @@ -3,6 +3,7 @@ using Ryujinx.Common.Logging; using Ryujinx.Graphics.Memory; using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Services.Nv.NvGpuAS; +using Ryujinx.HLE.HOS.Services.Nv.NvMap; using System; using System.Collections.Concurrent; @@ -10,37 +11,25 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvHostChannel { class NvHostChannelIoctl { - private class ChannelsPerProcess - { - public ConcurrentDictionary<NvChannelName, NvChannel> Channels { get; private set; } - - public ChannelsPerProcess() - { - Channels = new ConcurrentDictionary<NvChannelName, NvChannel>(); - - Channels.TryAdd(NvChannelName.Gpu, new NvChannel()); - } - } - - private static ConcurrentDictionary<KProcess, ChannelsPerProcess> Channels; + private static ConcurrentDictionary<KProcess, NvChannel> Channels; static NvHostChannelIoctl() { - Channels = new ConcurrentDictionary<KProcess, ChannelsPerProcess>(); + Channels = new ConcurrentDictionary<KProcess, NvChannel>(); } - public static int ProcessIoctlGpu(ServiceCtx Context, int Cmd) - { - return ProcessIoctl(Context, NvChannelName.Gpu, Cmd); - } - - public static int ProcessIoctl(ServiceCtx Context, NvChannelName Channel, int Cmd) + public static int ProcessIoctl(ServiceCtx Context, int Cmd) { switch (Cmd & 0xffff) { + case 0x0001: return Submit (Context); + case 0x0002: return GetSyncpoint (Context); + case 0x0003: return GetWaitBase (Context); + case 0x0009: return MapBuffer (Context); + case 0x000a: return UnmapBuffer (Context); case 0x4714: return SetUserData (Context); case 0x4801: return SetNvMap (Context); - case 0x4803: return SetTimeout (Context, Channel); + case 0x4803: return SetTimeout (Context); case 0x4808: return SubmitGpfifo (Context); case 0x4809: return AllocObjCtx (Context); case 0x480b: return ZcullBind (Context); @@ -53,6 +42,138 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvHostChannel throw new NotImplementedException(Cmd.ToString("x8")); } + private static int Submit(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + NvHostChannelSubmit Args = MemoryHelper.Read<NvHostChannelSubmit>(Context.Memory, InputPosition); + + NvGpuVmm Vmm = NvGpuASIoctl.GetASCtx(Context).Vmm; + + for (int Index = 0; Index < Args.CmdBufsCount; Index++) + { + long CmdBufOffset = InputPosition + 0x10 + Index * 0xc; + + NvHostChannelCmdBuf CmdBuf = MemoryHelper.Read<NvHostChannelCmdBuf>(Context.Memory, CmdBufOffset); + + NvMapHandle Map = NvMapIoctl.GetNvMap(Context, CmdBuf.MemoryId); + + int[] CmdBufData = new int[CmdBuf.WordsCount]; + + for (int Offset = 0; Offset < CmdBufData.Length; Offset++) + { + CmdBufData[Offset] = Context.Memory.ReadInt32(Map.Address + CmdBuf.Offset + Offset * 4); + } + + Context.Device.Gpu.PushCommandBuffer(Vmm, CmdBufData); + } + + //TODO: Relocation, waitchecks, etc. + + return NvResult.Success; + } + + private static int GetSyncpoint(ServiceCtx Context) + { + //TODO + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + NvHostChannelGetParamArg Args = MemoryHelper.Read<NvHostChannelGetParamArg>(Context.Memory, InputPosition); + + Args.Value = 0; + + MemoryHelper.Write(Context.Memory, OutputPosition, Args); + + return NvResult.Success; + } + + private static int GetWaitBase(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + NvHostChannelGetParamArg Args = MemoryHelper.Read<NvHostChannelGetParamArg>(Context.Memory, InputPosition); + + Args.Value = 0; + + MemoryHelper.Write(Context.Memory, OutputPosition, Args); + + return NvResult.Success; + } + + private static int MapBuffer(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + long OutputPosition = Context.Request.GetBufferType0x22().Position; + + NvHostChannelMapBuffer Args = MemoryHelper.Read<NvHostChannelMapBuffer>(Context.Memory, InputPosition); + + NvGpuVmm Vmm = NvGpuASIoctl.GetASCtx(Context).Vmm; + + for (int Index = 0; Index < Args.NumEntries; Index++) + { + int Handle = Context.Memory.ReadInt32(InputPosition + 0xc + Index * 8); + + NvMapHandle Map = NvMapIoctl.GetNvMap(Context, Handle); + + if (Map == null) + { + Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Handle:x8}!"); + + return NvResult.InvalidInput; + } + + lock (Map) + { + if (Map.DmaMapAddress == 0) + { + Map.DmaMapAddress = Vmm.MapLow(Map.Address, Map.Size); + } + + Context.Memory.WriteInt32(OutputPosition + 0xc + 4 + Index * 8, (int)Map.DmaMapAddress); + } + } + + return NvResult.Success; + } + + private static int UnmapBuffer(ServiceCtx Context) + { + long InputPosition = Context.Request.GetBufferType0x21().Position; + + NvHostChannelMapBuffer Args = MemoryHelper.Read<NvHostChannelMapBuffer>(Context.Memory, InputPosition); + + NvGpuVmm Vmm = NvGpuASIoctl.GetASCtx(Context).Vmm; + + for (int Index = 0; Index < Args.NumEntries; Index++) + { + int Handle = Context.Memory.ReadInt32(InputPosition + 0xc + Index * 8); + + NvMapHandle Map = NvMapIoctl.GetNvMap(Context, Handle); + + if (Map == null) + { + Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{Handle:x8}!"); + + return NvResult.InvalidInput; + } + + lock (Map) + { + if (Map.DmaMapAddress != 0) + { + Vmm.Free(Map.DmaMapAddress, Map.Size); + + Map.DmaMapAddress = 0; + } + } + } + + return NvResult.Success; + } + private static int SetUserData(ServiceCtx Context) { long InputPosition = Context.Request.GetBufferType0x21().Position; @@ -73,11 +194,11 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvHostChannel return NvResult.Success; } - private static int SetTimeout(ServiceCtx Context, NvChannelName Channel) + private static int SetTimeout(ServiceCtx Context) { long InputPosition = Context.Request.GetBufferType0x21().Position; - GetChannel(Context, Channel).Timeout = Context.Memory.ReadInt32(InputPosition); + GetChannel(Context).Timeout = Context.Memory.ReadInt32(InputPosition); return NvResult.Success; } @@ -185,14 +306,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvHostChannel Context.Device.Gpu.Pusher.Push(Vmm, Gpfifo); } - public static NvChannel GetChannel(ServiceCtx Context, NvChannelName Channel) + public static NvChannel GetChannel(ServiceCtx Context) { - ChannelsPerProcess Cpp = Channels.GetOrAdd(Context.Process, (Key) => - { - return new ChannelsPerProcess(); - }); - - return Cpp.Channels[Channel]; + return Channels.GetOrAdd(Context.Process, (Key) => new NvChannel()); } public static void UnloadProcess(KProcess Process) diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelMapBuffer.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelMapBuffer.cs new file mode 100644 index 00000000..1dfedf2d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelMapBuffer.cs @@ -0,0 +1,12 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvHostChannel +{ + [StructLayout(LayoutKind.Sequential, Size = 0xc, Pack = 4)] + struct NvHostChannelMapBuffer + { + public int NumEntries; + public int DataAddress; //Ignored by the driver. + public bool AttachHostChDas; + } +}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelSubmit.cs b/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelSubmit.cs new file mode 100644 index 00000000..f776ad87 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvHostChannel/NvHostChannelSubmit.cs @@ -0,0 +1,13 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvHostChannel +{ + [StructLayout(LayoutKind.Sequential, Size = 8, Pack = 4)] + struct NvHostChannelSubmit + { + public int CmdBufsCount; + public int RelocsCount; + public int SyncptIncrsCount; + public int WaitchecksCount; + } +}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapHandle.cs b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapHandle.cs index 3f8a1517..e97e4ff4 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapHandle.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapHandle.cs @@ -11,6 +11,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvMap public int Kind; public long Address; public bool Allocated; + public long DmaMapAddress; private long Dupes; |
