mirror of
https://git.743378673.xyz/MeloNX/MeloNX.git
synced 2025-08-02 10:47:11 +02:00
Rewrite nvservices (#800)
* Start rewriting nvservices internals TODO: - nvgpu device interface - nvhost generic device interface * Some clean up and fixes - Make sure to remove the fd of a closed channel. - NvFileDevice now doesn't implement Disposable as it was never used. - Rename NvHostCtrlGetConfigurationArgument to GetConfigurationArguments to follow calling convention. - Make sure to check every ioctls magic. * Finalize migration for ioctl standard variant TODO: ioctl2 migration * Implement SubmitGpfifoEx and fix nvdec * Implement Ioctl3 * Implement some ioctl3 required by recent games * Remove unused code and outdated comments * Return valid event handles with QueryEvent Also add an exception for unimplemented event ids. This commit doesn't implement accurately the events, this only define different events for different event ids. * Rename all occurance of FileDevice to DeviceFile * Restub SetClientPid to not cause regressions * Address comments * Remove GlobalStateTable * Address comments * Align variables in ioctl3 * Some missing alignments * GetVaRegionsArguments realign * Make Owner public in NvDeviceFile * Address LDj3SNuD's comments
This commit is contained in:
parent
c414a356a0
commit
be9b9c7cdf
75 changed files with 2798 additions and 2005 deletions
|
@ -0,0 +1,347 @@
|
|||
using ARMeilleure.Memory;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Graphics;
|
||||
using Ryujinx.Graphics.Memory;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
||||
{
|
||||
class NvHostChannelDeviceFile : NvDeviceFile
|
||||
{
|
||||
private uint _timeout;
|
||||
private uint _submitTimeout;
|
||||
private uint _timeslice;
|
||||
private NvGpu _gpu;
|
||||
private MemoryManager _memory;
|
||||
|
||||
public NvHostChannelDeviceFile(ServiceCtx context) : base(context)
|
||||
{
|
||||
_gpu = context.Device.Gpu;
|
||||
_memory = context.Memory;
|
||||
_timeout = 3000;
|
||||
_submitTimeout = 0;
|
||||
_timeslice = 0;
|
||||
}
|
||||
|
||||
public override NvInternalResult Ioctl(NvIoctl command, Span<byte> arguments)
|
||||
{
|
||||
NvInternalResult result = NvInternalResult.NotImplemented;
|
||||
|
||||
if (command.Type == NvIoctl.NvHostCustomMagic)
|
||||
{
|
||||
switch (command.Number)
|
||||
{
|
||||
case 0x01:
|
||||
result = Submit(arguments);
|
||||
break;
|
||||
case 0x02:
|
||||
result = CallIoctlMethod<GetParameterArguments>(GetSyncpoint, arguments);
|
||||
break;
|
||||
case 0x03:
|
||||
result = CallIoctlMethod<GetParameterArguments>(GetWaitBase, arguments);
|
||||
break;
|
||||
case 0x07:
|
||||
result = CallIoctlMethod<uint>(SetSubmitTimeout, arguments);
|
||||
break;
|
||||
case 0x09:
|
||||
result = MapCommandBuffer(arguments);
|
||||
break;
|
||||
case 0x0a:
|
||||
result = UnmapCommandBuffer(arguments);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (command.Type == NvIoctl.NvHostMagic)
|
||||
{
|
||||
switch (command.Number)
|
||||
{
|
||||
case 0x01:
|
||||
result = CallIoctlMethod<int>(SetNvMapFd, arguments);
|
||||
break;
|
||||
case 0x03:
|
||||
result = CallIoctlMethod<uint>(SetTimeout, arguments);
|
||||
break;
|
||||
case 0x08:
|
||||
result = SubmitGpfifo(arguments);
|
||||
break;
|
||||
case 0x09:
|
||||
result = CallIoctlMethod<AllocObjCtxArguments>(AllocObjCtx, arguments);
|
||||
break;
|
||||
case 0x0b:
|
||||
result = CallIoctlMethod<ZcullBindArguments>(ZcullBind, arguments);
|
||||
break;
|
||||
case 0x0c:
|
||||
result = CallIoctlMethod<SetErrorNotifierArguments>(SetErrorNotifier, arguments);
|
||||
break;
|
||||
case 0x0d:
|
||||
result = CallIoctlMethod<NvChannelPriority>(SetPriority, arguments);
|
||||
break;
|
||||
case 0x18:
|
||||
result = CallIoctlMethod<AllocGpfifoExArguments>(AllocGpfifoEx, arguments);
|
||||
break;
|
||||
case 0x1a:
|
||||
result = CallIoctlMethod<AllocGpfifoExArguments>(AllocGpfifoEx2, arguments);
|
||||
break;
|
||||
case 0x1d:
|
||||
result = CallIoctlMethod<uint>(SetTimeslice, arguments);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (command.Type == NvIoctl.NvGpuMagic)
|
||||
{
|
||||
switch (command.Number)
|
||||
{
|
||||
case 0x14:
|
||||
result = CallIoctlMethod<ulong>(SetUserData, arguments);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private NvInternalResult Submit(Span<byte> arguments)
|
||||
{
|
||||
int headerSize = Unsafe.SizeOf<SubmitArguments>();
|
||||
SubmitArguments submitHeader = MemoryMarshal.Cast<byte, SubmitArguments>(arguments)[0];
|
||||
Span<CommandBuffer> commandBufferEntries = MemoryMarshal.Cast<byte, CommandBuffer>(arguments.Slice(headerSize)).Slice(0, submitHeader.CmdBufsCount);
|
||||
NvGpuVmm vmm = NvHostAsGpuDeviceFile.GetAddressSpaceContext(Owner).Vmm;
|
||||
|
||||
foreach (CommandBuffer commandBufferEntry in commandBufferEntries)
|
||||
{
|
||||
NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, commandBufferEntry.MemoryId);
|
||||
|
||||
int[] commandBufferData = new int[commandBufferEntry.WordsCount];
|
||||
|
||||
for (int offset = 0; offset < commandBufferData.Length; offset++)
|
||||
{
|
||||
commandBufferData[offset] = _memory.ReadInt32(map.Address + commandBufferEntry.Offset + offset * 4);
|
||||
}
|
||||
|
||||
_gpu.PushCommandBuffer(vmm, commandBufferData);
|
||||
}
|
||||
|
||||
return NvInternalResult.Success;
|
||||
}
|
||||
|
||||
private NvInternalResult GetSyncpoint(ref GetParameterArguments arguments)
|
||||
{
|
||||
arguments.Value = 0;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv);
|
||||
|
||||
return NvInternalResult.Success;
|
||||
}
|
||||
|
||||
private NvInternalResult GetWaitBase(ref GetParameterArguments arguments)
|
||||
{
|
||||
arguments.Value = 0;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv);
|
||||
|
||||
return NvInternalResult.Success;
|
||||
}
|
||||
|
||||
private NvInternalResult SetSubmitTimeout(ref uint submitTimeout)
|
||||
{
|
||||
_submitTimeout = submitTimeout;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv);
|
||||
|
||||
return NvInternalResult.Success;
|
||||
}
|
||||
|
||||
private NvInternalResult MapCommandBuffer(Span<byte> arguments)
|
||||
{
|
||||
int headerSize = Unsafe.SizeOf<MapCommandBufferArguments>();
|
||||
MapCommandBufferArguments commandBufferHeader = MemoryMarshal.Cast<byte, MapCommandBufferArguments>(arguments)[0];
|
||||
Span<CommandBufferHandle> commandBufferEntries = MemoryMarshal.Cast<byte, CommandBufferHandle>(arguments.Slice(headerSize)).Slice(0, commandBufferHeader.NumEntries);
|
||||
NvGpuVmm vmm = NvHostAsGpuDeviceFile.GetAddressSpaceContext(Owner).Vmm;
|
||||
|
||||
foreach (ref CommandBufferHandle commandBufferEntry in commandBufferEntries)
|
||||
{
|
||||
NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, commandBufferEntry.MapHandle);
|
||||
|
||||
if (map == null)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{commandBufferEntry.MapHandle:x8}!");
|
||||
|
||||
return NvInternalResult.InvalidInput;
|
||||
}
|
||||
|
||||
lock (map)
|
||||
{
|
||||
if (map.DmaMapAddress == 0)
|
||||
{
|
||||
map.DmaMapAddress = vmm.MapLow(map.Address, map.Size);
|
||||
}
|
||||
|
||||
commandBufferEntry.MapAddress = (int)map.DmaMapAddress;
|
||||
}
|
||||
}
|
||||
|
||||
return NvInternalResult.Success;
|
||||
}
|
||||
|
||||
private NvInternalResult UnmapCommandBuffer(Span<byte> arguments)
|
||||
{
|
||||
int headerSize = Unsafe.SizeOf<MapCommandBufferArguments>();
|
||||
MapCommandBufferArguments commandBufferHeader = MemoryMarshal.Cast<byte, MapCommandBufferArguments>(arguments)[0];
|
||||
Span<CommandBufferHandle> commandBufferEntries = MemoryMarshal.Cast<byte, CommandBufferHandle>(arguments.Slice(headerSize)).Slice(0, commandBufferHeader.NumEntries);
|
||||
NvGpuVmm vmm = NvHostAsGpuDeviceFile.GetAddressSpaceContext(Owner).Vmm;
|
||||
|
||||
foreach (ref CommandBufferHandle commandBufferEntry in commandBufferEntries)
|
||||
{
|
||||
NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, commandBufferEntry.MapHandle);
|
||||
|
||||
if (map == null)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid handle 0x{commandBufferEntry.MapHandle:x8}!");
|
||||
|
||||
return NvInternalResult.InvalidInput;
|
||||
}
|
||||
|
||||
lock (map)
|
||||
{
|
||||
if (map.DmaMapAddress != 0)
|
||||
{
|
||||
vmm.Free(map.DmaMapAddress, map.Size);
|
||||
|
||||
map.DmaMapAddress = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NvInternalResult.Success;
|
||||
}
|
||||
|
||||
private NvInternalResult SetNvMapFd(ref int nvMapFd)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceNv);
|
||||
|
||||
return NvInternalResult.Success;
|
||||
}
|
||||
|
||||
private NvInternalResult SetTimeout(ref uint timeout)
|
||||
{
|
||||
_timeout = timeout;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv);
|
||||
|
||||
return NvInternalResult.Success;
|
||||
}
|
||||
|
||||
private NvInternalResult SubmitGpfifo(Span<byte> arguments)
|
||||
{
|
||||
int headerSize = Unsafe.SizeOf<SubmitGpfifoArguments>();
|
||||
SubmitGpfifoArguments gpfifoSubmissionHeader = MemoryMarshal.Cast<byte, SubmitGpfifoArguments>(arguments)[0];
|
||||
Span<long> gpfifoEntries = MemoryMarshal.Cast<byte, long>(arguments.Slice(headerSize)).Slice(0, gpfifoSubmissionHeader.NumEntries);
|
||||
|
||||
return SubmitGpfifo(ref gpfifoSubmissionHeader, gpfifoEntries);
|
||||
}
|
||||
|
||||
private NvInternalResult AllocObjCtx(ref AllocObjCtxArguments arguments)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceNv);
|
||||
|
||||
return NvInternalResult.Success;
|
||||
}
|
||||
|
||||
private NvInternalResult ZcullBind(ref ZcullBindArguments arguments)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceNv);
|
||||
|
||||
return NvInternalResult.Success;
|
||||
}
|
||||
|
||||
private NvInternalResult SetErrorNotifier(ref SetErrorNotifierArguments arguments)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceNv);
|
||||
|
||||
return NvInternalResult.Success;
|
||||
}
|
||||
|
||||
private NvInternalResult SetPriority(ref NvChannelPriority priority)
|
||||
{
|
||||
switch (priority)
|
||||
{
|
||||
case NvChannelPriority.Low:
|
||||
_timeslice = 1300; // Timeslice low priority in micro-seconds
|
||||
break;
|
||||
case NvChannelPriority.Medium:
|
||||
_timeslice = 2600; // Timeslice medium priority in micro-seconds
|
||||
break;
|
||||
case NvChannelPriority.High:
|
||||
_timeslice = 5200; // Timeslice high priority in micro-seconds
|
||||
break;
|
||||
default:
|
||||
return NvInternalResult.InvalidInput;
|
||||
}
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv);
|
||||
|
||||
// TODO: disable and preempt channel when GPU scheduler will be implemented.
|
||||
|
||||
return NvInternalResult.Success;
|
||||
}
|
||||
|
||||
private NvInternalResult AllocGpfifoEx(ref AllocGpfifoExArguments arguments)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceNv);
|
||||
|
||||
return NvInternalResult.Success;
|
||||
}
|
||||
|
||||
private NvInternalResult AllocGpfifoEx2(ref AllocGpfifoExArguments arguments)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceNv);
|
||||
|
||||
return NvInternalResult.Success;
|
||||
}
|
||||
|
||||
private NvInternalResult SetTimeslice(ref uint timeslice)
|
||||
{
|
||||
if (timeslice < 1000 || timeslice > 50000)
|
||||
{
|
||||
return NvInternalResult.InvalidInput;
|
||||
}
|
||||
|
||||
_timeslice = timeslice; // in micro-seconds
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv);
|
||||
|
||||
// TODO: disable and preempt channel when GPU scheduler will be implemented.
|
||||
|
||||
return NvInternalResult.Success;
|
||||
}
|
||||
|
||||
private NvInternalResult SetUserData(ref ulong userData)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceNv);
|
||||
|
||||
return NvInternalResult.Success;
|
||||
}
|
||||
|
||||
protected NvInternalResult SubmitGpfifo(ref SubmitGpfifoArguments header, Span<long> entries)
|
||||
{
|
||||
NvGpuVmm vmm = NvHostAsGpuDeviceFile.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() { }
|
||||
}
|
||||
}
|
|
@ -1,371 +0,0 @@
|
|||
using ARMeilleure.Memory;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Graphics.Memory;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvGpuAS;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
||||
{
|
||||
class NvHostChannelIoctl
|
||||
{
|
||||
private static ConcurrentDictionary<KProcess, NvChannel> _channels;
|
||||
|
||||
static NvHostChannelIoctl()
|
||||
{
|
||||
_channels = new ConcurrentDictionary<KProcess, NvChannel>();
|
||||
}
|
||||
|
||||
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 0x0007: return SetSubmitTimeout (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);
|
||||
case 0x4808: return SubmitGpfifo (context);
|
||||
case 0x4809: return AllocObjCtx (context);
|
||||
case 0x480b: return ZcullBind (context);
|
||||
case 0x480c: return SetErrorNotifier (context);
|
||||
case 0x480d: return SetPriority (context);
|
||||
case 0x481a: return AllocGpfifoEx2 (context);
|
||||
case 0x481b: return KickoffPbWithAttr(context);
|
||||
case 0x481d: return SetTimeslice (context);
|
||||
}
|
||||
|
||||
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 SetSubmitTimeout(ServiceCtx context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
|
||||
GetChannel(context).SubmitTimeout = context.Memory.ReadInt32(inputPosition);
|
||||
|
||||
// TODO: Handle the timeout in the submit method.
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv);
|
||||
|
||||
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;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv);
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int SetNvMap(ServiceCtx context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv);
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int SetTimeout(ServiceCtx context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
|
||||
GetChannel(context).Timeout = context.Memory.ReadInt32(inputPosition);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv);
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int SubmitGpfifo(ServiceCtx context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
|
||||
NvHostChannelSubmitGpfifo args = MemoryHelper.Read<NvHostChannelSubmitGpfifo>(context.Memory, inputPosition);
|
||||
|
||||
NvGpuVmm vmm = NvGpuASIoctl.GetASCtx(context).Vmm;
|
||||
|
||||
for (int index = 0; index < args.NumEntries; index++)
|
||||
{
|
||||
long gpfifo = context.Memory.ReadInt64(inputPosition + 0x18 + index * 8);
|
||||
|
||||
PushGpfifo(context, vmm, gpfifo);
|
||||
}
|
||||
|
||||
args.SyncptId = 0;
|
||||
args.SyncptValue = 0;
|
||||
|
||||
MemoryHelper.Write(context.Memory, outputPosition, args);
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int AllocObjCtx(ServiceCtx context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv);
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int ZcullBind(ServiceCtx context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv);
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int SetErrorNotifier(ServiceCtx context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv);
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int SetPriority(ServiceCtx context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
|
||||
switch ((NvChannelPriority)context.Memory.ReadInt32(inputPosition))
|
||||
{
|
||||
case NvChannelPriority.Low:
|
||||
GetChannel(context).Timeslice = 1300; // Timeslice low priority in micro-seconds
|
||||
break;
|
||||
case NvChannelPriority.Medium:
|
||||
GetChannel(context).Timeslice = 2600; // Timeslice medium priority in micro-seconds
|
||||
break;
|
||||
case NvChannelPriority.High:
|
||||
GetChannel(context).Timeslice = 5200; // Timeslice high priority in micro-seconds
|
||||
break;
|
||||
default:
|
||||
return NvResult.InvalidInput;
|
||||
}
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv);
|
||||
|
||||
// TODO: disable and preempt channel when GPU scheduler will be implemented.
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int AllocGpfifoEx2(ServiceCtx context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv);
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int KickoffPbWithAttr(ServiceCtx context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
long outputPosition = context.Request.GetBufferType0x22().Position;
|
||||
|
||||
NvHostChannelSubmitGpfifo args = MemoryHelper.Read<NvHostChannelSubmitGpfifo>(context.Memory, inputPosition);
|
||||
|
||||
NvGpuVmm vmm = NvGpuASIoctl.GetASCtx(context).Vmm;
|
||||
|
||||
for (int index = 0; index < args.NumEntries; index++)
|
||||
{
|
||||
long gpfifo = context.Memory.ReadInt64(args.Address + index * 8);
|
||||
|
||||
PushGpfifo(context, vmm, gpfifo);
|
||||
}
|
||||
|
||||
args.SyncptId = 0;
|
||||
args.SyncptValue = 0;
|
||||
|
||||
MemoryHelper.Write(context.Memory, outputPosition, args);
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static int SetTimeslice(ServiceCtx context)
|
||||
{
|
||||
long inputPosition = context.Request.GetBufferType0x21().Position;
|
||||
int timeslice = context.Memory.ReadInt32(inputPosition);
|
||||
|
||||
if (timeslice < 1000 || timeslice > 50000)
|
||||
{
|
||||
return NvResult.InvalidInput;
|
||||
}
|
||||
|
||||
GetChannel(context).Timeslice = timeslice; // in micro-seconds
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNv);
|
||||
|
||||
// TODO: disable and preempt channel when GPU scheduler will be implemented.
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
private static void PushGpfifo(ServiceCtx context, NvGpuVmm vmm, long gpfifo)
|
||||
{
|
||||
context.Device.Gpu.Pusher.Push(vmm, gpfifo);
|
||||
}
|
||||
|
||||
public static NvChannel GetChannel(ServiceCtx context)
|
||||
{
|
||||
return _channels.GetOrAdd(context.Process, (key) => new NvChannel());
|
||||
}
|
||||
|
||||
public static void UnloadProcess(KProcess process)
|
||||
{
|
||||
_channels.TryRemove(process, out _);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
||||
{
|
||||
internal class NvHostGpuDeviceFile : NvHostChannelDeviceFile
|
||||
{
|
||||
private KEvent _smExceptionBptIntReportEvent;
|
||||
private KEvent _smExceptionBptPauseReportEvent;
|
||||
private KEvent _errorNotifierEvent;
|
||||
|
||||
public NvHostGpuDeviceFile(ServiceCtx context) : base(context)
|
||||
{
|
||||
_smExceptionBptIntReportEvent = new KEvent(context.Device.System);
|
||||
_smExceptionBptPauseReportEvent = new KEvent(context.Device.System);
|
||||
_errorNotifierEvent = new KEvent(context.Device.System);
|
||||
}
|
||||
|
||||
public override NvInternalResult Ioctl2(NvIoctl command, Span<byte> arguments, Span<byte> inlineInBuffer)
|
||||
{
|
||||
NvInternalResult result = NvInternalResult.NotImplemented;
|
||||
|
||||
if (command.Type == NvIoctl.NvHostMagic)
|
||||
{
|
||||
switch (command.Number)
|
||||
{
|
||||
case 0x1b:
|
||||
result = CallIoctlMethod<SubmitGpfifoArguments, long>(SubmitGpfifoEx, arguments, inlineInBuffer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override NvInternalResult QueryEvent(out int eventHandle, uint eventId)
|
||||
{
|
||||
// TODO: accurately represent and implement those events.
|
||||
KEvent targetEvent = null;
|
||||
|
||||
switch (eventId)
|
||||
{
|
||||
case 0x1:
|
||||
targetEvent = _smExceptionBptIntReportEvent;
|
||||
break;
|
||||
case 0x2:
|
||||
targetEvent = _smExceptionBptPauseReportEvent;
|
||||
break;
|
||||
case 0x3:
|
||||
targetEvent = _errorNotifierEvent;
|
||||
break;
|
||||
}
|
||||
|
||||
if (targetEvent != null)
|
||||
{
|
||||
if (Owner.HandleTable.GenerateHandle(targetEvent.ReadableEvent, out eventHandle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eventHandle = 0;
|
||||
|
||||
return NvInternalResult.InvalidInput;
|
||||
}
|
||||
|
||||
return NvInternalResult.Success;
|
||||
}
|
||||
|
||||
private NvInternalResult SubmitGpfifoEx(ref SubmitGpfifoArguments arguments, Span<long> inlineData)
|
||||
{
|
||||
return SubmitGpfifo(ref arguments, inlineData);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
using Ryujinx.HLE.HOS.Services.Nv.Types;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct AllocGpfifoExArguments
|
||||
{
|
||||
public uint NumEntries;
|
||||
public uint NumJobs;
|
||||
public uint Flags;
|
||||
public NvFence Fence;
|
||||
public uint Reserved1;
|
||||
public uint Reserved2;
|
||||
public uint Reserved3;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct AllocObjCtxArguments
|
||||
{
|
||||
public uint ClassNumber;
|
||||
public uint Flags;
|
||||
public ulong ObjectId;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct GetParameterArguments
|
||||
{
|
||||
public uint Parameter;
|
||||
public uint Value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct CommandBufferHandle
|
||||
{
|
||||
public int MapHandle;
|
||||
public int MapAddress;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct MapCommandBufferArguments
|
||||
{
|
||||
public int NumEntries;
|
||||
public int DataAddress; // Ignored by the driver.
|
||||
public bool AttachHostChDas;
|
||||
public byte Padding1;
|
||||
public short Padding2;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
||||
{
|
||||
enum NvChannelPriority
|
||||
enum NvChannelPriority : uint
|
||||
{
|
||||
Low = 50,
|
||||
Medium = 100,
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Size = 8, Pack = 4)]
|
||||
struct NvHostChannelCmdBuf
|
||||
{
|
||||
public int MemoryId;
|
||||
public int Offset;
|
||||
public int WordsCount;
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Size = 8, Pack = 4)]
|
||||
struct NvHostChannelGetParamArg
|
||||
{
|
||||
public int Param;
|
||||
public int Value;
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0xc, Pack = 4)]
|
||||
struct NvHostChannelMapBuffer
|
||||
{
|
||||
public int NumEntries;
|
||||
public int DataAddress; // Ignored by the driver.
|
||||
public bool AttachHostChDas;
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Size = 8, Pack = 4)]
|
||||
struct NvHostChannelSubmit
|
||||
{
|
||||
public int CmdBufsCount;
|
||||
public int RelocsCount;
|
||||
public int SyncptIncrsCount;
|
||||
public int WaitchecksCount;
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
||||
{
|
||||
struct NvHostChannelSubmitGpfifo
|
||||
{
|
||||
public long Address;
|
||||
public int NumEntries;
|
||||
public int Flags;
|
||||
public int SyncptId;
|
||||
public int SyncptValue;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct SetErrorNotifierArguments
|
||||
{
|
||||
public ulong Offset;
|
||||
public ulong Size;
|
||||
public uint Mem;
|
||||
public uint Reserved;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct CommandBuffer
|
||||
{
|
||||
public int MemoryId;
|
||||
public int Offset;
|
||||
public int WordsCount;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct SubmitArguments
|
||||
{
|
||||
public int CmdBufsCount;
|
||||
public int RelocsCount;
|
||||
public int SyncptIncrsCount;
|
||||
public int WaitchecksCount;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
using Ryujinx.HLE.HOS.Services.Nv.Types;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct SubmitGpfifoArguments
|
||||
{
|
||||
public long Address;
|
||||
public int NumEntries;
|
||||
public int Flags;
|
||||
public NvFence Fence;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel.Types
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct ZcullBindArguments
|
||||
{
|
||||
public ulong GpuVirtualAddress;
|
||||
public uint Mode;
|
||||
public uint Reserved;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue