From 72db77fbe64309f55ef72716f16e194282d15a5c Mon Sep 17 00:00:00 2001 From: Thog Date: Mon, 28 Oct 2019 23:42:36 +0100 Subject: [PATCH] Implement SubmitGpfifoEx and fix nvdec --- Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs | 61 +++++++++++++++---- .../Services/Nv/NvDrvServices/NvFileDevice.cs | 14 ++++- .../NvHostChannel/NvHostChannelFileDevice.cs | 27 ++++---- .../NvHostChannel/NvHostGpuFileDevice.cs | 33 ++++++++++ .../Types/MapCommandBufferArguments.cs | 5 +- .../Types/NvIoctlNotImplementedException.cs | 3 + 6 files changed, 116 insertions(+), 27 deletions(-) create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostGpuFileDevice.cs diff --git a/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs b/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs index 50c4ec1e38..b46e6193db 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs @@ -32,7 +32,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv { "/dev/nvhost-ctrl", typeof(NvHostCtrlFileDevice) }, { "/dev/nvhost-ctrl-gpu", typeof(NvHostCtrlGpuFileDevice) }, { "/dev/nvhost-as-gpu", typeof(NvHostAsGpuFileDevice) }, - { "/dev/nvhost-gpu", typeof(NvHostChannelFileDevice) }, + { "/dev/nvhost-gpu", typeof(NvHostGpuFileDevice) }, //{ "/dev/nvhost-msenc", typeof(NvHostChannelFileDevice) }, { "/dev/nvhost-nvdec", typeof(NvHostChannelFileDevice) }, //{ "/dev/nvhost-nvjpg", typeof(NvHostChannelFileDevice) }, @@ -67,13 +67,10 @@ namespace Ryujinx.HLE.HOS.Services.Nv } else { - + Logger.PrintWarning(LogClass.ServiceNv, $"Cannot find file device \"{path}\"!"); } } - - Logger.PrintWarning(LogClass.ServiceNv, $"Cannot find file device \"{path}\"!"); - return -1; } @@ -85,8 +82,8 @@ namespace Ryujinx.HLE.HOS.Services.Nv NvIoctl.Direction ioctlDirection = ioctlCommand.GetDirectionValue(); uint ioctlSize = ioctlCommand.GetSizeValue(); - bool isRead = (ioctlDirection & NvIoctl.Direction.Read) == NvIoctl.Direction.Read; - bool isWrite = (ioctlDirection & NvIoctl.Direction.Write) == NvIoctl.Direction.Write; + bool isRead = (ioctlDirection & NvIoctl.Direction.Read) != 0; + bool isWrite = (ioctlDirection & NvIoctl.Direction.Write) != 0; if ((isWrite && ioctlSize > outputDataSize) || (isRead && ioctlSize > inputDataSize)) { @@ -403,7 +400,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv // DumpGraphicsMemoryInfo() public ResultCode DumpGraphicsMemoryInfo(ServiceCtx context) { - throw new ServiceNotImplementedException(context); + Logger.PrintStub(LogClass.ServiceNv); + + return ResultCode.Success; } [Command(10)] // 3.0.0+ @@ -414,10 +413,48 @@ namespace Ryujinx.HLE.HOS.Services.Nv } [Command(11)] // 3.0.0+ - // Ioctl2(s32 fd, u32 ioctl_cmd, buffer in_args, buffer in_additional_buffer) -> (u32 error_code, buffer out_args) + // Ioctl2(s32 fd, u32 ioctl_cmd, buffer in_args, buffer inline_in_buffer) -> (u32 error_code, buffer out_args) public ResultCode Ioctl2(ServiceCtx context) { - throw new ServiceNotImplementedException(context); + NvResult errorCode = EnsureInitialized(); + + if (errorCode == NvResult.Success) + { + int fd = context.RequestData.ReadInt32(); + NvIoctl ioctlCommand = context.RequestData.ReadStruct(); + + (long inlineInBufferPosition, long inlineInBufferSize) = context.Request.GetBufferType0x21(1); + + errorCode = GetIoctlArgument(context, ioctlCommand, out Span arguments); + + Span inlineInBuffer = new Span(context.Memory.ReadBytes(inlineInBufferPosition, inlineInBufferSize)); + + if (errorCode == NvResult.Success) + { + errorCode = GetFileDeviceFromFd(fd, out NvFileDevice fileDevice); + + if (errorCode == NvResult.Success) + { + NvInternalResult internalResult = fileDevice.Ioctl2(ioctlCommand, arguments, inlineInBuffer); + + if (internalResult == NvInternalResult.NotImplemented) + { + throw new NvIoctlNotImplementedException(context, fileDevice, ioctlCommand); + } + + errorCode = ConvertInternalErrorCode(internalResult); + + if (errorCode == NvResult.Success && (ioctlCommand.GetDirectionValue() & NvIoctl.Direction.Write) != 0) + { + context.Memory.WriteBytes(context.Request.GetBufferType0x22(0).Position, arguments.ToArray()); + } + } + } + } + + context.ResponseData.Write((uint)errorCode); + + return ResultCode.Success; } [Command(12)] // 3.0.0+ @@ -431,7 +468,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv // FinishInitialize(unknown<8>) public ResultCode FinishInitialize(ServiceCtx context) { - throw new ServiceNotImplementedException(context); + Logger.PrintStub(LogClass.ServiceNv); + + return ResultCode.Success; } } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvFileDevice.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvFileDevice.cs index 4f111c0fa6..4d52cfe130 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvFileDevice.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvFileDevice.cs @@ -2,6 +2,7 @@ using Ryujinx.HLE.HOS.Kernel.Process; using System; using System.Diagnostics; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices @@ -37,25 +38,32 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices return NvInternalResult.NotImplemented; } - public virtual NvInternalResult Ioctl2(NvIoctl command, Span arguments, Span inBuffer) + public virtual NvInternalResult Ioctl2(NvIoctl command, Span arguments, Span inlineInBuffer) { return NvInternalResult.NotImplemented; } - public virtual NvInternalResult Ioctl3(NvIoctl command, Span arguments, Span outBuffer) + public virtual NvInternalResult Ioctl3(NvIoctl command, Span arguments, Span inlineOutBuffer) { return NvInternalResult.NotImplemented; } protected delegate NvInternalResult IoctlProcessor(ref T arguments); protected delegate NvInternalResult IoctlProcessorSpan(Span arguments); + protected delegate NvInternalResult IoctlProcessorInline(ref T arguments, Span inlineData); protected static NvInternalResult CallIoctlMethod(IoctlProcessor callback, Span arguments) where T : struct { - Debug.Assert(arguments.Length == Marshal.SizeOf()); + Debug.Assert(arguments.Length == Unsafe.SizeOf()); return callback(ref MemoryMarshal.Cast(arguments)[0]); } + protected static NvInternalResult CallIoctlMethod(IoctlProcessorInline callback, Span arguments, Span inlineInBuffer) where T : struct where Y : struct + { + Debug.Assert(arguments.Length == Unsafe.SizeOf()); + return callback(ref MemoryMarshal.Cast(arguments)[0], MemoryMarshal.Cast(inlineInBuffer)); + } + protected static NvInternalResult CallIoctlMethod(IoctlProcessorSpan callback, Span arguments) where T : struct { return callback(MemoryMarshal.Cast(arguments)); diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelFileDevice.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelFileDevice.cs index 2ef8ec5e73..49a4190109 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelFileDevice.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelFileDevice.cs @@ -243,17 +243,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel SubmitGpfifoArguments gpfifoSubmissionHeader = MemoryMarshal.Cast(arguments)[0]; Span gpfifoEntries = MemoryMarshal.Cast(arguments.Slice(headerSize)).Slice(0, gpfifoSubmissionHeader.NumEntries); - NvGpuVmm vmm = NvHostAsGpuFileDevice.GetAddressSpaceContext(_owner).Vmm; - - foreach (long entry in gpfifoEntries) - { - _gpu.Pusher.Push(vmm, entry); - } - - gpfifoSubmissionHeader.Fence.Id = 0; - gpfifoSubmissionHeader.Fence.Value = 0; - - return NvInternalResult.Success; + return SubmitGpfifo(ref gpfifoSubmissionHeader, gpfifoEntries); } private NvInternalResult AllocObjCtx(ref AllocObjCtxArguments arguments) @@ -338,6 +328,21 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel return NvInternalResult.Success; } + protected NvInternalResult SubmitGpfifo(ref SubmitGpfifoArguments header, Span entries) + { + NvGpuVmm vmm = NvHostAsGpuFileDevice.GetAddressSpaceContext(_owner).Vmm; + + foreach (long entry in entries) + { + _gpu.Pusher.Push(vmm, entry); + } + + header.Fence.Id = 0; + header.Fence.Value = 0; + + return NvInternalResult.Success; + } + public override void Close() { // TODO diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostGpuFileDevice.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostGpuFileDevice.cs new file mode 100644 index 0000000000..74b253784d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostGpuFileDevice.cs @@ -0,0 +1,33 @@ +using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types; +using System; + +namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel +{ + internal class NvHostGpuFileDevice : NvHostChannelFileDevice + { + public NvHostGpuFileDevice(ServiceCtx context) : base(context) + { + } + + public override NvInternalResult Ioctl2(NvIoctl command, Span arguments, Span inlineInBuffer) + { + NvInternalResult result = NvInternalResult.NotImplemented; + + if (command.GetTypeValue() == NvIoctl.NvHostMagic) + { + switch (command.GetNumberValue()) + { + case 0x1b: + result = CallIoctlMethod(SubmitGpfifoEx, arguments, inlineInBuffer); + break; + } + } + return result; + } + + private NvInternalResult SubmitGpfifoEx(ref SubmitGpfifoArguments arguments, Span inlineData) + { + return SubmitGpfifo(ref arguments, inlineData); + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/MapCommandBufferArguments.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/MapCommandBufferArguments.cs index 6de8ff1a78..062b057edc 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/MapCommandBufferArguments.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/Types/MapCommandBufferArguments.cs @@ -9,12 +9,13 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types public int MapAddress; } - [StructLayout(LayoutKind.Sequential)] + [StructLayout(LayoutKind.Sequential, Pack = 1)] struct MapCommandBufferArguments { public int NumEntries; public int DataAddress; // Ignored by the driver. - public bool AttachHostChDas; + [MarshalAs(UnmanagedType.I1)] + public bool AttachHostChDas; public byte Padding1; public short Padding2; } diff --git a/Ryujinx.HLE/HOS/Services/Nv/Types/NvIoctlNotImplementedException.cs b/Ryujinx.HLE/HOS/Services/Nv/Types/NvIoctlNotImplementedException.cs index 0ec4e67429..988913cd09 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/Types/NvIoctlNotImplementedException.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/Types/NvIoctlNotImplementedException.cs @@ -37,6 +37,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv.Types { StringBuilder sb = new StringBuilder(); + sb.AppendLine($"Device File: {FileDevice.GetType().Name}"); + sb.AppendLine(); + sb.AppendLine($"Ioctl (0x{Command.RawValue:x8})"); sb.AppendLine($"\tNumber: 0x{Command.GetNumberValue():x8}"); sb.AppendLine($"\tType: 0x{Command.GetTypeValue():x8}");