Initial support for separate GPU address spaces (#2394)
* Make GPU memory manager a member of GPU channel * Move physical memory instance to the memory manager, and the caches to the physical memory * PR feedback
This commit is contained in:
parent
8cc872fb60
commit
fbb4019ed5
44 changed files with 780 additions and 481 deletions
|
@ -1,27 +1,34 @@
|
|||
using ARMeilleure.Memory;
|
||||
using ARMeilleure.State;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Graphics.Gpu;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using Ryujinx.Memory;
|
||||
|
||||
namespace Ryujinx.HLE.HOS
|
||||
{
|
||||
class ArmProcessContext<T> : IProcessContext where T : class, IVirtualMemoryManager, IMemoryManager
|
||||
class ArmProcessContext<T> : IProcessContext where T : class, IVirtualMemoryManagerTracked, IMemoryManager
|
||||
{
|
||||
private readonly long _pid;
|
||||
private readonly GpuContext _gpuContext;
|
||||
private readonly CpuContext _cpuContext;
|
||||
private T _memoryManager;
|
||||
|
||||
public IVirtualMemoryManager AddressSpace => _memoryManager;
|
||||
|
||||
public ArmProcessContext(T memoryManager, bool for64Bit)
|
||||
public ArmProcessContext(long pid, GpuContext gpuContext, T memoryManager, bool for64Bit)
|
||||
{
|
||||
if (memoryManager is IRefCounted rc)
|
||||
{
|
||||
rc.IncrementReferenceCount();
|
||||
}
|
||||
|
||||
_memoryManager = memoryManager;
|
||||
gpuContext.RegisterProcess(pid, memoryManager);
|
||||
|
||||
_pid = pid;
|
||||
_gpuContext = gpuContext;
|
||||
_cpuContext = new CpuContext(memoryManager, for64Bit);
|
||||
_memoryManager = memoryManager;
|
||||
}
|
||||
|
||||
public void Execute(ExecutionContext context, ulong codeAddress)
|
||||
|
@ -36,6 +43,7 @@ namespace Ryujinx.HLE.HOS
|
|||
rc.DecrementReferenceCount();
|
||||
|
||||
_memoryManager = null;
|
||||
_gpuContext.UnregisterProcess(_pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Graphics.Gpu;
|
||||
using Ryujinx.HLE.HOS.Kernel;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using Ryujinx.Memory;
|
||||
|
@ -9,19 +10,26 @@ namespace Ryujinx.HLE.HOS
|
|||
{
|
||||
class ArmProcessContextFactory : IProcessContextFactory
|
||||
{
|
||||
public IProcessContext Create(KernelContext context, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler, bool for64Bit)
|
||||
private readonly GpuContext _gpu;
|
||||
|
||||
public ArmProcessContextFactory(GpuContext gpu)
|
||||
{
|
||||
_gpu = gpu;
|
||||
}
|
||||
|
||||
public IProcessContext Create(KernelContext context, long pid, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler, bool for64Bit)
|
||||
{
|
||||
MemoryManagerMode mode = context.Device.Configuration.MemoryManagerMode;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case MemoryManagerMode.SoftwarePageTable:
|
||||
return new ArmProcessContext<MemoryManager>(new MemoryManager(addressSpaceSize, invalidAccessHandler), for64Bit);
|
||||
return new ArmProcessContext<MemoryManager>(pid, _gpu, new MemoryManager(addressSpaceSize, invalidAccessHandler), for64Bit);
|
||||
|
||||
case MemoryManagerMode.HostMapped:
|
||||
case MemoryManagerMode.HostMappedUnsafe:
|
||||
bool unsafeMode = mode == MemoryManagerMode.HostMappedUnsafe;
|
||||
return new ArmProcessContext<MemoryManagerHostMapped>(new MemoryManagerHostMapped(addressSpaceSize, unsafeMode, invalidAccessHandler), for64Bit);
|
||||
return new ArmProcessContext<MemoryManagerHostMapped>(pid, _gpu, new MemoryManagerHostMapped(addressSpaceSize, unsafeMode, invalidAccessHandler), for64Bit);
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
|
|
@ -4,6 +4,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
{
|
||||
interface IProcessContextFactory
|
||||
{
|
||||
IProcessContext Create(KernelContext context, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler, bool for64Bit);
|
||||
IProcessContext Create(KernelContext context, long pid, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler, bool for64Bit);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,6 +126,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
|
||||
AddressSpaceType addrSpaceType = (AddressSpaceType)((int)(creationInfo.Flags & ProcessCreationFlags.AddressSpaceMask) >> (int)ProcessCreationFlags.AddressSpaceShift);
|
||||
|
||||
Pid = KernelContext.NewKipId();
|
||||
|
||||
if (Pid == 0 || (ulong)Pid >= KernelConstants.InitialProcessId)
|
||||
{
|
||||
throw new InvalidOperationException($"Invalid KIP Id {Pid}.");
|
||||
}
|
||||
|
||||
InitializeMemoryManager(creationInfo.Flags);
|
||||
|
||||
bool aslrEnabled = creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr);
|
||||
|
@ -171,13 +178,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
return result;
|
||||
}
|
||||
|
||||
Pid = KernelContext.NewKipId();
|
||||
|
||||
if (Pid == 0 || (ulong)Pid >= KernelConstants.InitialProcessId)
|
||||
{
|
||||
throw new InvalidOperationException($"Invalid KIP Id {Pid}.");
|
||||
}
|
||||
|
||||
return ParseProcessInfo(creationInfo);
|
||||
}
|
||||
|
||||
|
@ -233,6 +233,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
|
||||
AddressSpaceType addrSpaceType = (AddressSpaceType)((int)(creationInfo.Flags & ProcessCreationFlags.AddressSpaceMask) >> (int)ProcessCreationFlags.AddressSpaceShift);
|
||||
|
||||
Pid = KernelContext.NewProcessId();
|
||||
|
||||
if (Pid == -1 || (ulong)Pid < KernelConstants.InitialProcessId)
|
||||
{
|
||||
throw new InvalidOperationException($"Invalid Process Id {Pid}.");
|
||||
}
|
||||
|
||||
InitializeMemoryManager(creationInfo.Flags);
|
||||
|
||||
bool aslrEnabled = creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr);
|
||||
|
@ -286,13 +293,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
return result;
|
||||
}
|
||||
|
||||
Pid = KernelContext.NewProcessId();
|
||||
|
||||
if (Pid == -1 || (ulong)Pid < KernelConstants.InitialProcessId)
|
||||
{
|
||||
throw new InvalidOperationException($"Invalid Process Id {Pid}.");
|
||||
}
|
||||
|
||||
result = ParseProcessInfo(creationInfo);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
|
@ -1051,14 +1051,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
|
||||
bool for64Bit = flags.HasFlag(ProcessCreationFlags.Is64Bit);
|
||||
|
||||
Context = _contextFactory.Create(KernelContext, 1UL << addrSpaceBits, InvalidAccessHandler, for64Bit);
|
||||
|
||||
// TODO: This should eventually be removed.
|
||||
// The GPU shouldn't depend on the CPU memory manager at all.
|
||||
if (flags.HasFlag(ProcessCreationFlags.IsApplication))
|
||||
{
|
||||
KernelContext.Device.Gpu.SetVmm((IVirtualMemoryManagerTracked)CpuMemory);
|
||||
}
|
||||
Context = _contextFactory.Create(KernelContext, Pid, 1UL << addrSpaceBits, InvalidAccessHandler, for64Bit);
|
||||
|
||||
if (Context.AddressSpace is MemoryManagerHostMapped)
|
||||
{
|
||||
|
|
|
@ -4,7 +4,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
{
|
||||
class ProcessContextFactory : IProcessContextFactory
|
||||
{
|
||||
public IProcessContext Create(KernelContext context, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler, bool for64Bit)
|
||||
public IProcessContext Create(KernelContext context, long pid, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler, bool for64Bit)
|
||||
{
|
||||
return new ProcessContext(new AddressSpaceManager(addressSpaceSize));
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
KProcess process = new KProcess(context);
|
||||
|
||||
var processContextFactory = new ArmProcessContextFactory();
|
||||
var processContextFactory = new ArmProcessContextFactory(context.Device.Gpu);
|
||||
|
||||
result = process.InitializeKip(
|
||||
creationInfo,
|
||||
|
@ -228,7 +228,7 @@ namespace Ryujinx.HLE.HOS
|
|||
return false;
|
||||
}
|
||||
|
||||
var processContextFactory = new ArmProcessContextFactory();
|
||||
var processContextFactory = new ArmProcessContextFactory(context.Device.Gpu);
|
||||
|
||||
result = process.Initialize(
|
||||
creationInfo,
|
||||
|
|
47
Ryujinx.HLE/HOS/Services/Nv/Host1xContext.cs
Normal file
47
Ryujinx.HLE/HOS/Services/Nv/Host1xContext.cs
Normal file
|
@ -0,0 +1,47 @@
|
|||
using Ryujinx.Graphics.Gpu;
|
||||
using Ryujinx.Graphics.Gpu.Memory;
|
||||
using Ryujinx.Graphics.Host1x;
|
||||
using Ryujinx.Graphics.Nvdec;
|
||||
using Ryujinx.Graphics.Vic;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv
|
||||
{
|
||||
class Host1xContext : IDisposable
|
||||
{
|
||||
public MemoryManager Smmu { get; }
|
||||
public NvMemoryAllocator MemoryAllocator { get; }
|
||||
public Host1xDevice Host1x { get;}
|
||||
|
||||
public Host1xContext(GpuContext gpu, long pid)
|
||||
{
|
||||
MemoryAllocator = new NvMemoryAllocator();
|
||||
Host1x = new Host1xDevice(gpu.Synchronization);
|
||||
Smmu = gpu.CreateMemoryManager(pid);
|
||||
var nvdec = new NvdecDevice(Smmu);
|
||||
var vic = new VicDevice(Smmu);
|
||||
Host1x.RegisterDevice(ClassId.Nvdec, nvdec);
|
||||
Host1x.RegisterDevice(ClassId.Vic, vic);
|
||||
|
||||
nvdec.FrameDecoded += (FrameDecodedEventArgs e) =>
|
||||
{
|
||||
// FIXME:
|
||||
// Figure out what is causing frame ordering issues on H264.
|
||||
// For now this is needed as workaround.
|
||||
if (e.CodecId == CodecId.H264)
|
||||
{
|
||||
vic.SetSurfaceOverride(e.LumaOffset, e.ChromaOffset, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
vic.DisableSurfaceOverride();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Host1x.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,6 @@ using Ryujinx.Common.Logging;
|
|||
using Ryujinx.Cpu;
|
||||
using Ryujinx.HLE.Exceptions;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel;
|
||||
|
@ -24,8 +23,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
|||
[Service("nvdrv:t")]
|
||||
class INvDrvServices : IpcService
|
||||
{
|
||||
private static Dictionary<string, Type> _deviceFileRegistry =
|
||||
new Dictionary<string, Type>()
|
||||
private static Dictionary<string, Type> _deviceFileRegistry = new Dictionary<string, Type>()
|
||||
{
|
||||
{ "/dev/nvmap", typeof(NvMapDeviceFile) },
|
||||
{ "/dev/nvhost-ctrl", typeof(NvHostCtrlDeviceFile) },
|
||||
|
@ -39,7 +37,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
|||
//{ "/dev/nvhost-display", typeof(NvHostChannelDeviceFile) },
|
||||
};
|
||||
|
||||
private static IdDictionary _deviceFileIdRegistry = new IdDictionary();
|
||||
public static IdDictionary DeviceFileIdRegistry = new IdDictionary();
|
||||
|
||||
private IVirtualMemoryManager _clientMemory;
|
||||
private long _owner;
|
||||
|
@ -61,7 +59,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
|||
|
||||
deviceFile.Path = path;
|
||||
|
||||
return _deviceFileIdRegistry.Add(deviceFile);
|
||||
return DeviceFileIdRegistry.Add(deviceFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -139,7 +137,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
|||
return NvResult.InvalidParameter;
|
||||
}
|
||||
|
||||
deviceFile = _deviceFileIdRegistry.GetData<NvDeviceFile>(fd);
|
||||
deviceFile = DeviceFileIdRegistry.GetData<NvDeviceFile>(fd);
|
||||
|
||||
if (deviceFile == null)
|
||||
{
|
||||
|
@ -302,7 +300,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
|||
{
|
||||
deviceFile.Close();
|
||||
|
||||
_deviceFileIdRegistry.Delete(fd);
|
||||
DeviceFileIdRegistry.Delete(fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -569,14 +567,16 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
|||
|
||||
public static void Destroy()
|
||||
{
|
||||
foreach (object entry in _deviceFileIdRegistry.Values)
|
||||
NvHostChannelDeviceFile.Destroy();
|
||||
|
||||
foreach (object entry in DeviceFileIdRegistry.Values)
|
||||
{
|
||||
NvDeviceFile deviceFile = (NvDeviceFile)entry;
|
||||
|
||||
deviceFile.Close();
|
||||
}
|
||||
|
||||
_deviceFileIdRegistry.Clear();
|
||||
DeviceFileIdRegistry.Clear();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,22 +1,22 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Graphics.Gpu.Memory;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
|
||||
using Ryujinx.Memory;
|
||||
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>();
|
||||
private NvMemoryAllocator _memoryAllocator;
|
||||
private readonly AddressSpaceContext _asContext;
|
||||
private readonly NvMemoryAllocator _memoryAllocator;
|
||||
|
||||
public NvHostAsGpuDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, long owner) : base(context, owner)
|
||||
{
|
||||
_memoryAllocator = context.Device.MemoryAllocator;
|
||||
_asContext = new AddressSpaceContext(context.Device.Gpu.CreateMemoryManager(owner));
|
||||
_memoryAllocator = new NvMemoryAllocator();
|
||||
}
|
||||
|
||||
public override NvInternalResult Ioctl(NvIoctl command, Span<byte> arguments)
|
||||
|
@ -77,20 +77,24 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
|
|||
|
||||
private NvInternalResult BindChannel(ref BindChannelArguments arguments)
|
||||
{
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceNv);
|
||||
var channelDeviceFile = INvDrvServices.DeviceFileIdRegistry.GetData<NvHostChannelDeviceFile>(arguments.Fd);
|
||||
if (channelDeviceFile == null)
|
||||
{
|
||||
// TODO: Return invalid Fd error.
|
||||
}
|
||||
|
||||
channelDeviceFile.Channel.BindMemory(_asContext.Gmm);
|
||||
|
||||
return NvInternalResult.Success;
|
||||
}
|
||||
|
||||
private NvInternalResult AllocSpace(ref AllocSpaceArguments arguments)
|
||||
{
|
||||
AddressSpaceContext addressSpaceContext = GetAddressSpaceContext(Context);
|
||||
|
||||
ulong size = (ulong)arguments.Pages * (ulong)arguments.PageSize;
|
||||
|
||||
NvInternalResult result = NvInternalResult.Success;
|
||||
|
||||
lock (addressSpaceContext)
|
||||
lock (_asContext)
|
||||
{
|
||||
// Note: When the fixed offset flag is not set,
|
||||
// the Offset field holds the alignment size instead.
|
||||
|
@ -132,7 +136,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
|
|||
}
|
||||
else
|
||||
{
|
||||
addressSpaceContext.AddReservation(arguments.Offset, size);
|
||||
_asContext.AddReservation(arguments.Offset, size);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,18 +145,16 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
|
|||
|
||||
private NvInternalResult FreeSpace(ref FreeSpaceArguments arguments)
|
||||
{
|
||||
AddressSpaceContext addressSpaceContext = GetAddressSpaceContext(Context);
|
||||
ulong size = (ulong)arguments.Pages * (ulong)arguments.PageSize;
|
||||
|
||||
NvInternalResult result = NvInternalResult.Success;
|
||||
|
||||
lock (addressSpaceContext)
|
||||
lock (_asContext)
|
||||
{
|
||||
ulong size = (ulong)arguments.Pages * (ulong)arguments.PageSize;
|
||||
|
||||
if (addressSpaceContext.RemoveReservation(arguments.Offset))
|
||||
if (_asContext.RemoveReservation(arguments.Offset))
|
||||
{
|
||||
_memoryAllocator.DeallocateRange(arguments.Offset, size);
|
||||
addressSpaceContext.Gmm.Unmap(arguments.Offset, size);
|
||||
_asContext.Gmm.Unmap(arguments.Offset, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -168,16 +170,14 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
|
|||
|
||||
private NvInternalResult UnmapBuffer(ref UnmapBufferArguments arguments)
|
||||
{
|
||||
AddressSpaceContext addressSpaceContext = GetAddressSpaceContext(Context);
|
||||
|
||||
lock (addressSpaceContext)
|
||||
lock (_asContext)
|
||||
{
|
||||
if (addressSpaceContext.RemoveMap(arguments.Offset, out ulong size))
|
||||
if (_asContext.RemoveMap(arguments.Offset, out ulong size))
|
||||
{
|
||||
if (size != 0)
|
||||
{
|
||||
_memoryAllocator.DeallocateRange(arguments.Offset, size);
|
||||
addressSpaceContext.Gmm.Unmap(arguments.Offset, size);
|
||||
_asContext.Gmm.Unmap(arguments.Offset, size);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -191,22 +191,20 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
|
|||
|
||||
private NvInternalResult MapBufferEx(ref MapBufferExArguments arguments)
|
||||
{
|
||||
const string mapErrorMsg = "Failed to map fixed buffer with offset 0x{0:x16}, size 0x{1:x16} and alignment 0x{2:x16}!";
|
||||
|
||||
AddressSpaceContext addressSpaceContext = GetAddressSpaceContext(Context);
|
||||
const string MapErrorMsg = "Failed to map fixed buffer with offset 0x{0:x16}, size 0x{1:x16} and alignment 0x{2:x16}!";
|
||||
|
||||
ulong physicalAddress;
|
||||
|
||||
if ((arguments.Flags & AddressSpaceFlags.RemapSubRange) != 0)
|
||||
{
|
||||
lock (addressSpaceContext)
|
||||
lock (_asContext)
|
||||
{
|
||||
if (addressSpaceContext.TryGetMapPhysicalAddress(arguments.Offset, out physicalAddress))
|
||||
if (_asContext.TryGetMapPhysicalAddress(arguments.Offset, out physicalAddress))
|
||||
{
|
||||
ulong virtualAddress = arguments.Offset + arguments.BufferOffset;
|
||||
|
||||
physicalAddress += arguments.BufferOffset;
|
||||
addressSpaceContext.Gmm.Map(physicalAddress, virtualAddress, arguments.MappingSize);
|
||||
_asContext.Gmm.Map(physicalAddress, virtualAddress, arguments.MappingSize);
|
||||
|
||||
return NvInternalResult.Success;
|
||||
}
|
||||
|
@ -246,7 +244,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
|
|||
|
||||
NvInternalResult result = NvInternalResult.Success;
|
||||
|
||||
lock (addressSpaceContext)
|
||||
lock (_asContext)
|
||||
{
|
||||
// Note: When the fixed offset flag is not set,
|
||||
// the Offset field holds the alignment size instead.
|
||||
|
@ -254,13 +252,13 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
|
|||
|
||||
if (!virtualAddressAllocated)
|
||||
{
|
||||
if (addressSpaceContext.ValidateFixedBuffer(arguments.Offset, size, pageSize))
|
||||
if (_asContext.ValidateFixedBuffer(arguments.Offset, size, pageSize))
|
||||
{
|
||||
addressSpaceContext.Gmm.Map(physicalAddress, arguments.Offset, size);
|
||||
_asContext.Gmm.Map(physicalAddress, arguments.Offset, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
string message = string.Format(mapErrorMsg, arguments.Offset, size, pageSize);
|
||||
string message = string.Format(MapErrorMsg, arguments.Offset, size, pageSize);
|
||||
|
||||
Logger.Warning?.Print(LogClass.ServiceNv, message);
|
||||
|
||||
|
@ -275,7 +273,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
|
|||
_memoryAllocator.AllocateRange(va, size, freeAddressStartPosition);
|
||||
}
|
||||
|
||||
addressSpaceContext.Gmm.Map(physicalAddress, va, size);
|
||||
_asContext.Gmm.Map(physicalAddress, va, size);
|
||||
arguments.Offset = va;
|
||||
}
|
||||
|
||||
|
@ -289,7 +287,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
|
|||
}
|
||||
else
|
||||
{
|
||||
addressSpaceContext.AddMap(arguments.Offset, size, physicalAddress, virtualAddressAllocated);
|
||||
_asContext.AddMap(arguments.Offset, size, physicalAddress, virtualAddressAllocated);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -312,12 +310,10 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
|
|||
|
||||
private NvInternalResult Remap(Span<RemapArguments> arguments)
|
||||
{
|
||||
AddressSpaceContext addressSpaceContext = GetAddressSpaceContext(Context);
|
||||
MemoryManager gmm = _asContext.Gmm;
|
||||
|
||||
for (int index = 0; index < arguments.Length; index++)
|
||||
{
|
||||
MemoryManager gmm = GetAddressSpaceContext(Context).Gmm;
|
||||
|
||||
ulong mapOffs = (ulong)arguments[index].MapOffset << 16;
|
||||
ulong gpuVa = (ulong)arguments[index].GpuOffset << 16;
|
||||
ulong size = (ulong)arguments[index].Pages << 16;
|
||||
|
@ -345,10 +341,5 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
|
|||
}
|
||||
|
||||
public override void Close() { }
|
||||
|
||||
public static AddressSpaceContext GetAddressSpaceContext(ServiceCtx context)
|
||||
{
|
||||
return _addressSpaceContextRegistry.GetOrAdd(context.Process, (key) => new AddressSpaceContext(context));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,9 +34,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types
|
|||
private readonly SortedList<ulong, Range> _maps;
|
||||
private readonly SortedList<ulong, Range> _reservations;
|
||||
|
||||
public AddressSpaceContext(ServiceCtx context)
|
||||
public AddressSpaceContext(MemoryManager gmm)
|
||||
{
|
||||
Gmm = context.Device.Gpu.MemoryManager;
|
||||
Gmm = gmm;
|
||||
|
||||
_maps = new SortedList<ulong, Range>();
|
||||
_reservations = new SortedList<ulong, Range>();
|
||||
|
@ -123,7 +123,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types
|
|||
return _reservations.Remove(gpuVa);
|
||||
}
|
||||
|
||||
private Range BinarySearch(SortedList<ulong, Range> list, ulong address)
|
||||
private static Range BinarySearch(SortedList<ulong, Range> list, ulong address)
|
||||
{
|
||||
int left = 0;
|
||||
int right = list.Count - 1;
|
||||
|
@ -154,7 +154,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types
|
|||
return null;
|
||||
}
|
||||
|
||||
private Range BinarySearchLt(SortedList<ulong, Range> list, ulong address)
|
||||
private static Range BinarySearchLt(SortedList<ulong, Range> list, ulong address)
|
||||
{
|
||||
Range ltRg = null;
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Graphics.Gpu;
|
||||
using Ryujinx.Graphics.Gpu.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.NvHostCtrl;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.Types;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
|
@ -15,6 +15,8 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
|||
{
|
||||
class NvHostChannelDeviceFile : NvDeviceFile
|
||||
{
|
||||
private static readonly ConcurrentDictionary<long, Host1xContext> _host1xContextRegistry = new();
|
||||
|
||||
private const uint MaxModuleSyncpoint = 16;
|
||||
|
||||
private uint _timeout;
|
||||
|
@ -24,8 +26,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
|||
private readonly Switch _device;
|
||||
|
||||
private readonly IVirtualMemoryManager _memory;
|
||||
private readonly NvMemoryAllocator _memoryAllocator;
|
||||
private readonly GpuChannel _channel;
|
||||
private readonly Host1xContext _host1xContext;
|
||||
|
||||
public GpuChannel Channel { get; }
|
||||
|
||||
public enum ResourcePolicy
|
||||
{
|
||||
|
@ -43,13 +46,13 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
|||
|
||||
public NvHostChannelDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, long owner) : base(context, owner)
|
||||
{
|
||||
_device = context.Device;
|
||||
_memory = memory;
|
||||
_timeout = 3000;
|
||||
_submitTimeout = 0;
|
||||
_timeslice = 0;
|
||||
_memoryAllocator = _device.MemoryAllocator;
|
||||
_channel = _device.Gpu.CreateChannel();
|
||||
_device = context.Device;
|
||||
_memory = memory;
|
||||
_timeout = 3000;
|
||||
_submitTimeout = 0;
|
||||
_timeslice = 0;
|
||||
_host1xContext = GetHost1XContext(context.Device.Gpu, owner);
|
||||
Channel = _device.Gpu.CreateChannel();
|
||||
|
||||
ChannelSyncpoints = new uint[MaxModuleSyncpoint];
|
||||
|
||||
|
@ -162,7 +165,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
|||
|
||||
var data = _memory.GetSpan(map.Address + commandBuffer.Offset, commandBuffer.WordsCount * 4);
|
||||
|
||||
_device.Host1x.Submit(MemoryMarshal.Cast<byte, int>(data));
|
||||
_host1xContext.Host1x.Submit(MemoryMarshal.Cast<byte, int>(data));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -172,7 +175,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
|||
|
||||
tmpCmdBuff[0] = (4 << 28) | (int)fences[0].Id;
|
||||
|
||||
_device.Host1x.Submit(tmpCmdBuff);
|
||||
_host1xContext.Host1x.Submit(tmpCmdBuff);
|
||||
|
||||
return NvInternalResult.Success;
|
||||
}
|
||||
|
@ -233,7 +236,6 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
|||
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);
|
||||
MemoryManager gmm = NvHostAsGpuDeviceFile.GetAddressSpaceContext(Context).Gmm;
|
||||
|
||||
foreach (ref CommandBufferHandle commandBufferEntry in commandBufferEntries)
|
||||
{
|
||||
|
@ -250,12 +252,12 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
|||
{
|
||||
if (map.DmaMapAddress == 0)
|
||||
{
|
||||
ulong va = _memoryAllocator.GetFreeAddress((ulong) map.Size, out ulong freeAddressStartPosition, 1, MemoryManager.PageSize);
|
||||
ulong va = _host1xContext.MemoryAllocator.GetFreeAddress((ulong)map.Size, out ulong freeAddressStartPosition, 1, MemoryManager.PageSize);
|
||||
|
||||
if (va != NvMemoryAllocator.PteUnmapped && va <= uint.MaxValue && (va + (uint)map.Size) <= uint.MaxValue)
|
||||
{
|
||||
_memoryAllocator.AllocateRange(va, (uint)map.Size, freeAddressStartPosition);
|
||||
gmm.Map(map.Address, va, (uint)map.Size);
|
||||
_host1xContext.MemoryAllocator.AllocateRange(va, (uint)map.Size, freeAddressStartPosition);
|
||||
_host1xContext.Smmu.Map(map.Address, va, (uint)map.Size);
|
||||
map.DmaMapAddress = va;
|
||||
}
|
||||
else
|
||||
|
@ -276,7 +278,6 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
|||
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);
|
||||
MemoryManager gmm = NvHostAsGpuDeviceFile.GetAddressSpaceContext(Context).Gmm;
|
||||
|
||||
foreach (ref CommandBufferHandle commandBufferEntry in commandBufferEntries)
|
||||
{
|
||||
|
@ -297,7 +298,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
|||
// To make unmapping work, we need separate address space per channel.
|
||||
// Right now NVDEC and VIC share the GPU address space which is not correct at all.
|
||||
|
||||
// gmm.Free((ulong)map.DmaMapAddress, (uint)map.Size);
|
||||
// _host1xContext.MemoryAllocator.Free((ulong)map.DmaMapAddress, (uint)map.Size);
|
||||
|
||||
// map.DmaMapAddress = 0;
|
||||
}
|
||||
|
@ -431,10 +432,10 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
|||
|
||||
if (header.Flags.HasFlag(SubmitGpfifoFlags.FenceWait) && !_device.System.HostSyncpoint.IsSyncpointExpired(header.Fence.Id, header.Fence.Value))
|
||||
{
|
||||
_channel.PushHostCommandBuffer(CreateWaitCommandBuffer(header.Fence));
|
||||
Channel.PushHostCommandBuffer(CreateWaitCommandBuffer(header.Fence));
|
||||
}
|
||||
|
||||
_channel.PushEntries(entries);
|
||||
Channel.PushEntries(entries);
|
||||
|
||||
header.Fence.Id = _channelSyncpoint.Id;
|
||||
|
||||
|
@ -456,7 +457,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
|||
|
||||
if (header.Flags.HasFlag(SubmitGpfifoFlags.FenceIncrement))
|
||||
{
|
||||
_channel.PushHostCommandBuffer(CreateIncrementCommandBuffer(ref header.Fence, header.Flags));
|
||||
Channel.PushHostCommandBuffer(CreateIncrementCommandBuffer(ref header.Fence, header.Flags));
|
||||
}
|
||||
|
||||
header.Flags = SubmitGpfifoFlags.None;
|
||||
|
@ -545,7 +546,22 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
|||
|
||||
public override void Close()
|
||||
{
|
||||
_channel.Dispose();
|
||||
Channel.Dispose();
|
||||
}
|
||||
|
||||
private static Host1xContext GetHost1XContext(GpuContext gpu, long pid)
|
||||
{
|
||||
return _host1xContextRegistry.GetOrAdd(pid, (long key) => new Host1xContext(gpu, key));
|
||||
}
|
||||
|
||||
public static void Destroy()
|
||||
{
|
||||
foreach (Host1xContext host1xContext in _host1xContextRegistry.Values)
|
||||
{
|
||||
host1xContext.Dispose();
|
||||
}
|
||||
|
||||
_host1xContextRegistry.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ using System;
|
|||
using Ryujinx.Graphics.Gpu.Memory;
|
||||
using Ryujinx.Common.Logging;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv
|
||||
{
|
||||
class NvMemoryAllocator
|
||||
{
|
||||
|
|
|
@ -49,8 +49,8 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||
|
||||
private class TextureCallbackInformation
|
||||
{
|
||||
public Layer Layer;
|
||||
public BufferItem Item;
|
||||
public Layer Layer;
|
||||
public BufferItem Item;
|
||||
}
|
||||
|
||||
public SurfaceFlinger(Switch device)
|
||||
|
@ -385,6 +385,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||
}
|
||||
|
||||
_device.Gpu.Window.EnqueueFrameThreadSafe(
|
||||
layer.Owner,
|
||||
frameBufferAddress,
|
||||
frameBufferWidth,
|
||||
frameBufferHeight,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue