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:
gdkchan 2021-06-29 14:32:02 -03:00 committed by GitHub
parent 8cc872fb60
commit fbb4019ed5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
44 changed files with 780 additions and 481 deletions

View file

@ -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);
}
}
}

View file

@ -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();

View file

@ -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);
}
}

View file

@ -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)
{

View file

@ -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));
}

View file

@ -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,

View 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();
}
}
}

View file

@ -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();
}
}
}

View file

@ -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));
}
}
}

View file

@ -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;

View file

@ -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();
}
}
}

View file

@ -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
{

View file

@ -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,