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,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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue