mirror of
https://git.743378673.xyz/MeloNX/MeloNX.git
synced 2025-08-02 15:07: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,318 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Graphics.Memory;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
|
||||
{
|
||||
class NvHostAsGpuDeviceFile : NvDeviceFile
|
||||
{
|
||||
private static ConcurrentDictionary<KProcess, AddressSpaceContext> _addressSpaceContextRegistry = new ConcurrentDictionary<KProcess, AddressSpaceContext>();
|
||||
|
||||
public NvHostAsGpuDeviceFile(ServiceCtx context) : base(context) { }
|
||||
|
||||
public override NvInternalResult Ioctl(NvIoctl command, Span<byte> arguments)
|
||||
{
|
||||
NvInternalResult result = NvInternalResult.NotImplemented;
|
||||
|
||||
if (command.Type == NvIoctl.NvGpuAsMagic)
|
||||
{
|
||||
switch (command.Number)
|
||||
{
|
||||
case 0x01:
|
||||
result = CallIoctlMethod<BindChannelArguments>(BindChannel, arguments);
|
||||
break;
|
||||
case 0x02:
|
||||
result = CallIoctlMethod<AllocSpaceArguments>(AllocSpace, arguments);
|
||||
break;
|
||||
case 0x03:
|
||||
result = CallIoctlMethod<FreeSpaceArguments>(FreeSpace, arguments);
|
||||
break;
|
||||
case 0x05:
|
||||
result = CallIoctlMethod<UnmapBufferArguments>(UnmapBuffer, arguments);
|
||||
break;
|
||||
case 0x06:
|
||||
result = CallIoctlMethod<MapBufferExArguments>(MapBufferEx, arguments);
|
||||
break;
|
||||
case 0x08:
|
||||
result = CallIoctlMethod<GetVaRegionsArguments>(GetVaRegions, arguments);
|
||||
break;
|
||||
case 0x09:
|
||||
result = CallIoctlMethod<InitializeExArguments>(InitializeEx, arguments);
|
||||
break;
|
||||
case 0x14:
|
||||
result = CallIoctlMethod<RemapArguments>(Remap, arguments);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override NvInternalResult Ioctl3(NvIoctl command, Span<byte> arguments, Span<byte> inlineOutBuffer)
|
||||
{
|
||||
NvInternalResult result = NvInternalResult.NotImplemented;
|
||||
|
||||
if (command.Type == NvIoctl.NvGpuAsMagic)
|
||||
{
|
||||
switch (command.Number)
|
||||
{
|
||||
case 0x08:
|
||||
// This is the same as the one in ioctl as inlineOutBuffer is empty.
|
||||
result = CallIoctlMethod<GetVaRegionsArguments>(GetVaRegions, arguments);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private NvInternalResult BindChannel(ref BindChannelArguments arguments)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceNv);
|
||||
|
||||
return NvInternalResult.Success;
|
||||
}
|
||||
|
||||
private NvInternalResult AllocSpace(ref AllocSpaceArguments arguments)
|
||||
{
|
||||
AddressSpaceContext addressSpaceContext = GetAddressSpaceContext(Owner);
|
||||
|
||||
ulong size = (ulong)arguments.Pages * (ulong)arguments.PageSize;
|
||||
|
||||
NvInternalResult result = NvInternalResult.Success;
|
||||
|
||||
lock (addressSpaceContext)
|
||||
{
|
||||
// Note: When the fixed offset flag is not set,
|
||||
// the Offset field holds the alignment size instead.
|
||||
if ((arguments.Flags & AddressSpaceFlags.FixedOffset) != 0)
|
||||
{
|
||||
arguments.Offset = addressSpaceContext.Vmm.ReserveFixed(arguments.Offset, (long)size);
|
||||
}
|
||||
else
|
||||
{
|
||||
arguments.Offset = addressSpaceContext.Vmm.Reserve((long)size, arguments.Offset);
|
||||
}
|
||||
|
||||
if (arguments.Offset < 0)
|
||||
{
|
||||
arguments.Offset = 0;
|
||||
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Failed to allocate size {size:x16}!");
|
||||
|
||||
result = NvInternalResult.OutOfMemory;
|
||||
}
|
||||
else
|
||||
{
|
||||
addressSpaceContext.AddReservation(arguments.Offset, (long)size);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private NvInternalResult FreeSpace(ref FreeSpaceArguments arguments)
|
||||
{
|
||||
AddressSpaceContext addressSpaceContext = GetAddressSpaceContext(Owner);
|
||||
|
||||
NvInternalResult result = NvInternalResult.Success;
|
||||
|
||||
lock (addressSpaceContext)
|
||||
{
|
||||
ulong size = (ulong)arguments.Pages * (ulong)arguments.PageSize;
|
||||
|
||||
if (addressSpaceContext.RemoveReservation(arguments.Offset))
|
||||
{
|
||||
addressSpaceContext.Vmm.Free(arguments.Offset, (long)size);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.PrintWarning(LogClass.ServiceNv,
|
||||
$"Failed to free offset 0x{arguments.Offset:x16} size 0x{size:x16}!");
|
||||
|
||||
result = NvInternalResult.InvalidInput;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private NvInternalResult UnmapBuffer(ref UnmapBufferArguments arguments)
|
||||
{
|
||||
AddressSpaceContext addressSpaceContext = GetAddressSpaceContext(Owner);
|
||||
|
||||
lock (addressSpaceContext)
|
||||
{
|
||||
if (addressSpaceContext.RemoveMap(arguments.Offset, out long size))
|
||||
{
|
||||
if (size != 0)
|
||||
{
|
||||
addressSpaceContext.Vmm.Free(arguments.Offset, size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid buffer offset {arguments.Offset:x16}!");
|
||||
}
|
||||
}
|
||||
|
||||
return NvInternalResult.Success;
|
||||
}
|
||||
|
||||
private NvInternalResult MapBufferEx(ref MapBufferExArguments arguments)
|
||||
{
|
||||
const string mapErrorMsg = "Failed to map fixed buffer with offset 0x{0:x16} and size 0x{1:x16}!";
|
||||
|
||||
AddressSpaceContext addressSpaceContext = GetAddressSpaceContext(Owner);
|
||||
|
||||
NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, arguments.NvMapHandle, true);
|
||||
|
||||
if (map == null)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{arguments.NvMapHandle:x8}!");
|
||||
|
||||
return NvInternalResult.InvalidInput;
|
||||
}
|
||||
|
||||
long physicalAddress;
|
||||
|
||||
if ((arguments.Flags & AddressSpaceFlags.RemapSubRange) != 0)
|
||||
{
|
||||
lock (addressSpaceContext)
|
||||
{
|
||||
if (addressSpaceContext.TryGetMapPhysicalAddress(arguments.Offset, out physicalAddress))
|
||||
{
|
||||
long virtualAddress = arguments.Offset + arguments.BufferOffset;
|
||||
|
||||
physicalAddress += arguments.BufferOffset;
|
||||
|
||||
if (addressSpaceContext.Vmm.Map(physicalAddress, virtualAddress, arguments.MappingSize) < 0)
|
||||
{
|
||||
string message = string.Format(mapErrorMsg, virtualAddress, arguments.MappingSize);
|
||||
|
||||
Logger.PrintWarning(LogClass.ServiceNv, message);
|
||||
|
||||
return NvInternalResult.InvalidInput;
|
||||
}
|
||||
|
||||
return NvInternalResult.Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Address 0x{arguments.Offset:x16} not mapped!");
|
||||
|
||||
return NvInternalResult.InvalidInput;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
physicalAddress = map.Address + arguments.BufferOffset;
|
||||
|
||||
long size = arguments.MappingSize;
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
size = (uint)map.Size;
|
||||
}
|
||||
|
||||
NvInternalResult result = NvInternalResult.Success;
|
||||
|
||||
lock (addressSpaceContext)
|
||||
{
|
||||
// Note: When the fixed offset flag is not set,
|
||||
// the Offset field holds the alignment size instead.
|
||||
bool virtualAddressAllocated = (arguments.Flags & AddressSpaceFlags.FixedOffset) == 0;
|
||||
|
||||
if (!virtualAddressAllocated)
|
||||
{
|
||||
if (addressSpaceContext.ValidateFixedBuffer(arguments.Offset, size))
|
||||
{
|
||||
arguments.Offset = addressSpaceContext.Vmm.Map(physicalAddress, arguments.Offset, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
string message = string.Format(mapErrorMsg, arguments.Offset, size);
|
||||
|
||||
Logger.PrintWarning(LogClass.ServiceNv, message);
|
||||
|
||||
result = NvInternalResult.InvalidInput;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
arguments.Offset = addressSpaceContext.Vmm.Map(physicalAddress, size);
|
||||
}
|
||||
|
||||
if (arguments.Offset < 0)
|
||||
{
|
||||
arguments.Offset = 0;
|
||||
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Failed to map size 0x{size:x16}!");
|
||||
|
||||
result = NvInternalResult.InvalidInput;
|
||||
}
|
||||
else
|
||||
{
|
||||
addressSpaceContext.AddMap(arguments.Offset, size, physicalAddress, virtualAddressAllocated);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private NvInternalResult GetVaRegions(ref GetVaRegionsArguments arguments)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceNv);
|
||||
|
||||
return NvInternalResult.Success;
|
||||
}
|
||||
|
||||
private NvInternalResult InitializeEx(ref InitializeExArguments arguments)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceNv);
|
||||
|
||||
return NvInternalResult.Success;
|
||||
}
|
||||
|
||||
private NvInternalResult Remap(Span<RemapArguments> arguments)
|
||||
{
|
||||
for (int index = 0; index < arguments.Length; index++)
|
||||
{
|
||||
NvGpuVmm vmm = GetAddressSpaceContext(Owner).Vmm;
|
||||
|
||||
NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, arguments[index].NvMapHandle, true);
|
||||
|
||||
if (map == null)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{arguments[index].NvMapHandle:x8}!");
|
||||
|
||||
return NvInternalResult.InvalidInput;
|
||||
}
|
||||
|
||||
long result = vmm.Map(map.Address, (long)arguments[index].Offset << 16,
|
||||
(long)arguments[index].Pages << 16);
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.ServiceNv,
|
||||
$"Page 0x{arguments[index].Offset:x16} size 0x{arguments[index].Pages:x16} not allocated!");
|
||||
|
||||
return NvInternalResult.InvalidInput;
|
||||
}
|
||||
}
|
||||
|
||||
return NvInternalResult.Success;
|
||||
}
|
||||
|
||||
public override void Close() { }
|
||||
|
||||
public static AddressSpaceContext GetAddressSpaceContext(KProcess process)
|
||||
{
|
||||
return _addressSpaceContextRegistry.GetOrAdd(process, (key) => new AddressSpaceContext(process));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,204 @@
|
|||
using ARMeilleure.Memory;
|
||||
using Ryujinx.Graphics.Memory;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types
|
||||
{
|
||||
class AddressSpaceContext
|
||||
{
|
||||
public NvGpuVmm Vmm { get; private set; }
|
||||
|
||||
private class Range
|
||||
{
|
||||
public ulong Start { get; private set; }
|
||||
public ulong End { get; private set; }
|
||||
|
||||
public Range(long position, long size)
|
||||
{
|
||||
Start = (ulong)position;
|
||||
End = (ulong)size + Start;
|
||||
}
|
||||
}
|
||||
|
||||
private class MappedMemory : Range
|
||||
{
|
||||
public long PhysicalAddress { get; private set; }
|
||||
public bool VaAllocated { get; private set; }
|
||||
|
||||
public MappedMemory(
|
||||
long position,
|
||||
long size,
|
||||
long physicalAddress,
|
||||
bool vaAllocated) : base(position, size)
|
||||
{
|
||||
PhysicalAddress = physicalAddress;
|
||||
VaAllocated = vaAllocated;
|
||||
}
|
||||
}
|
||||
|
||||
private SortedList<long, Range> _maps;
|
||||
private SortedList<long, Range> _reservations;
|
||||
|
||||
public AddressSpaceContext(KProcess process)
|
||||
{
|
||||
Vmm = new NvGpuVmm(process.CpuMemory);
|
||||
|
||||
_maps = new SortedList<long, Range>();
|
||||
_reservations = new SortedList<long, Range>();
|
||||
}
|
||||
|
||||
public bool ValidateFixedBuffer(long position, long size)
|
||||
{
|
||||
long mapEnd = position + size;
|
||||
|
||||
// Check if size is valid (0 is also not allowed).
|
||||
if ((ulong)mapEnd <= (ulong)position)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if address is page aligned.
|
||||
if ((position & NvGpuVmm.PageMask) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if region is reserved.
|
||||
if (BinarySearch(_reservations, position) == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for overlap with already mapped buffers.
|
||||
Range map = BinarySearchLt(_maps, mapEnd);
|
||||
|
||||
if (map != null && map.End > (ulong)position)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void AddMap(
|
||||
long position,
|
||||
long size,
|
||||
long physicalAddress,
|
||||
bool vaAllocated)
|
||||
{
|
||||
_maps.Add(position, new MappedMemory(position, size, physicalAddress, vaAllocated));
|
||||
}
|
||||
|
||||
public bool RemoveMap(long position, out long size)
|
||||
{
|
||||
size = 0;
|
||||
|
||||
if (_maps.Remove(position, out Range value))
|
||||
{
|
||||
MappedMemory map = (MappedMemory)value;
|
||||
|
||||
if (map.VaAllocated)
|
||||
{
|
||||
size = (long)(map.End - map.Start);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGetMapPhysicalAddress(long position, out long physicalAddress)
|
||||
{
|
||||
Range map = BinarySearch(_maps, position);
|
||||
|
||||
if (map != null)
|
||||
{
|
||||
physicalAddress = ((MappedMemory)map).PhysicalAddress;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
physicalAddress = 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void AddReservation(long position, long size)
|
||||
{
|
||||
_reservations.Add(position, new Range(position, size));
|
||||
}
|
||||
|
||||
public bool RemoveReservation(long position)
|
||||
{
|
||||
return _reservations.Remove(position);
|
||||
}
|
||||
|
||||
private Range BinarySearch(SortedList<long, Range> lst, long position)
|
||||
{
|
||||
int left = 0;
|
||||
int right = lst.Count - 1;
|
||||
|
||||
while (left <= right)
|
||||
{
|
||||
int size = right - left;
|
||||
|
||||
int middle = left + (size >> 1);
|
||||
|
||||
Range rg = lst.Values[middle];
|
||||
|
||||
if ((ulong)position >= rg.Start && (ulong)position < rg.End)
|
||||
{
|
||||
return rg;
|
||||
}
|
||||
|
||||
if ((ulong)position < rg.Start)
|
||||
{
|
||||
right = middle - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
left = middle + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Range BinarySearchLt(SortedList<long, Range> lst, long position)
|
||||
{
|
||||
Range ltRg = null;
|
||||
|
||||
int left = 0;
|
||||
int right = lst.Count - 1;
|
||||
|
||||
while (left <= right)
|
||||
{
|
||||
int size = right - left;
|
||||
|
||||
int middle = left + (size >> 1);
|
||||
|
||||
Range rg = lst.Values[middle];
|
||||
|
||||
if ((ulong)position < rg.Start)
|
||||
{
|
||||
right = middle - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
left = middle + 1;
|
||||
|
||||
if ((ulong)position > rg.Start)
|
||||
{
|
||||
ltRg = rg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ltRg;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types
|
||||
{
|
||||
[Flags]
|
||||
enum AddressSpaceFlags : uint
|
||||
{
|
||||
FixedOffset = 1,
|
||||
RemapSubRange = 0x100,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct AllocSpaceArguments
|
||||
{
|
||||
public uint Pages;
|
||||
public uint PageSize;
|
||||
public AddressSpaceFlags Flags;
|
||||
public uint Padding;
|
||||
public long Offset;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct BindChannelArguments
|
||||
{
|
||||
public int Fd;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct FreeSpaceArguments
|
||||
{
|
||||
public long Offset;
|
||||
public uint Pages;
|
||||
public uint PageSize;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct VaRegion
|
||||
{
|
||||
public ulong Offset;
|
||||
public uint PageSize;
|
||||
public uint Padding;
|
||||
public ulong Pages;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct GetVaRegionsArguments
|
||||
{
|
||||
public ulong Unused;
|
||||
public uint BufferSize;
|
||||
public uint Padding;
|
||||
public VaRegion Region0;
|
||||
public VaRegion Region1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct InitializeExArguments
|
||||
{
|
||||
public uint Flags;
|
||||
public int AsFd;
|
||||
public uint BigPageSize;
|
||||
public uint Reserved;
|
||||
public ulong Unknown0;
|
||||
public ulong Unknown1;
|
||||
public ulong Unknown2;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct MapBufferExArguments
|
||||
{
|
||||
public AddressSpaceFlags Flags;
|
||||
public int Kind;
|
||||
public int NvMapHandle;
|
||||
public int PageSize;
|
||||
public long BufferOffset;
|
||||
public long MappingSize;
|
||||
public long Offset;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct RemapArguments
|
||||
{
|
||||
public ushort Flags;
|
||||
public ushort Kind;
|
||||
public int NvMapHandle;
|
||||
public int Padding;
|
||||
public uint Offset;
|
||||
public uint Pages;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types
|
||||
{
|
||||
struct UnmapBufferArguments
|
||||
{
|
||||
public long Offset;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue