Implement GPU syncpoints (#980)

* Implement GPU syncpoints

This adds support for GPU syncpoints on the GPU backend & nvservices.

Everything that was implemented here is based on my researches,
hardware testing of the GM20B and reversing of nvservices (8.1.0).

Thanks to @fincs for the informations about some behaviours of the pusher
and for the initial informations about syncpoints.

* syncpoint: address gdkchan's comments

* Add some missing logic to handle SubmitGpfifo correctly

* Handle the NV event API correctly

* evnt => hostEvent

* Finish addressing gdkchan's comments

* nvservices: write the output buffer even when an error is returned

* dma pusher: Implemnet prefetch barrier

lso fix when the commands should be prefetch.

* Partially fix prefetch barrier

* Add a missing syncpoint check in QueryEvent of NvHostSyncPt

* Address Ac_K's comments and fix GetSyncpoint for ChannelResourcePolicy == Channel

* fix SyncptWait & SyncptWaitEx cmds logic

* Address ripinperi's comments

* Address gdkchan's comments

* Move user event management to the control channel

* Fix mm implementation, nvdec works again

* Address ripinperi's comments

* Address gdkchan's comments

* Implement nvhost-ctrl close accurately + make nvservices dispose channels when stopping the emulator

* Fix typo in MultiMediaOperationType
This commit is contained in:
Thog 2020-04-19 03:25:57 +02:00 committed by GitHub
parent 4960ab85f8
commit 644de99e86
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
37 changed files with 1576 additions and 386 deletions

View file

@ -1,3 +1,4 @@
using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu;
@ -5,7 +6,9 @@ using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
@ -117,15 +120,37 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
private ResultCode GbpDequeueBuffer(ServiceCtx context, BinaryReader parcelReader)
{
// TODO: Errors.
int format = parcelReader.ReadInt32();
int width = parcelReader.ReadInt32();
int height = parcelReader.ReadInt32();
int getTimestamps = parcelReader.ReadInt32();
int usage = parcelReader.ReadInt32();
int async = parcelReader.ReadInt32();
int width = parcelReader.ReadInt32();
int height = parcelReader.ReadInt32();
int format = parcelReader.ReadInt32();
int usage = parcelReader.ReadInt32();
int slot = GetFreeSlotBlocking(width, height);
return MakeReplyParcel(context, slot, 1, 0x24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
MultiFence multiFence = MultiFence.NoFence;
using (MemoryStream ms = new MemoryStream())
{
BinaryWriter writer = new BinaryWriter(ms);
// Allocated slot
writer.Write(slot);
// Has multi fence
writer.Write(1);
// Write the multi fnece
WriteFlattenedObject(writer, multiFence);
// Padding
writer.Write(0);
// Status
writer.Write(0);
return MakeReplyParcel(context, ms.ToArray());
}
}
private ResultCode GbpQueueBuffer(ServiceCtx context, BinaryReader parcelReader)
@ -142,9 +167,9 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
parcelReader.BaseStream.Position = Position;
_bufferQueue[slot].Transform = queueBufferObject.Transform;
_bufferQueue[slot].Fence = queueBufferObject.Fence;
_bufferQueue[slot].Crop = queueBufferObject.Crop;
_bufferQueue[slot].State = BufferState.Queued;
_bufferQueue[slot].State = BufferState.Queued;
SendFrameBuffer(context, slot);
@ -219,14 +244,19 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
return reader.ReadBytes((int)flattenedObjectSize);
}
private unsafe T ReadFlattenedObject<T>(BinaryReader reader) where T: struct
private T ReadFlattenedObject<T>(BinaryReader reader) where T: struct
{
byte[] data = ReadFlattenedObject(reader);
long flattenedObjectSize = reader.ReadInt64();
fixed (byte* ptr = data)
{
return Marshal.PtrToStructure<T>((IntPtr)ptr);
}
Debug.Assert(flattenedObjectSize == Unsafe.SizeOf<T>());
return reader.ReadStruct<T>();
}
private unsafe void WriteFlattenedObject<T>(BinaryWriter writer, T value) where T : struct
{
writer.Write(Unsafe.SizeOf<T>());
writer.WriteStruct(value);
}
private ResultCode MakeReplyParcel(ServiceCtx context, params int[] ints)
@ -328,10 +358,21 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
format,
bytesPerPixel,
crop,
AcquireBuffer,
ReleaseBuffer,
slot);
}
private void AcquireBuffer(GpuContext context, object slot)
{
AcquireBuffer(context, (int)slot);
}
private void AcquireBuffer(GpuContext context, int slot)
{
_bufferQueue[slot].Fence.WaitForever(context);
}
private void ReleaseBuffer(object slot)
{
ReleaseBuffer((int)slot);

View file

@ -8,6 +8,8 @@
public Rect Crop;
public MultiFence Fence;
public GbpBuffer Data;
}
}

View file

@ -1,24 +1,49 @@
using Ryujinx.HLE.HOS.Services.Nv.Types;
using Ryujinx.Graphics.Gpu;
using Ryujinx.HLE.HOS.Services.Nv.Types;
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
{
[StructLayout(LayoutKind.Explicit, Size = 0x24)]
[StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x24)]
struct MultiFence
{
[FieldOffset(0x0)]
public int FenceCount;
[FieldOffset(0x4)]
public NvFence Fence0;
private byte _fenceStorageStart;
[FieldOffset(0xC)]
public NvFence Fence1;
private Span<byte> _storage => MemoryMarshal.CreateSpan(ref _fenceStorageStart, Unsafe.SizeOf<NvFence>() * 4);
[FieldOffset(0x14)]
public NvFence Fence2;
private Span<NvFence> _nvFences => MemoryMarshal.Cast<byte, NvFence>(_storage);
[FieldOffset(0x1C)]
public NvFence Fence3;
public static MultiFence NoFence
{
get
{
MultiFence fence = new MultiFence
{
FenceCount = 0
};
fence._nvFences[0].Id = NvFence.InvalidSyncPointId;
return fence;
}
}
public void WaitForever(GpuContext gpuContext)
{
Wait(gpuContext, Timeout.InfiniteTimeSpan);
}
public void Wait(GpuContext gpuContext, TimeSpan timeout)
{
for (int i = 0; i < FenceCount; i++)
{
_nvFences[i].Wait(gpuContext, timeout);
}
}
}
}

View file

@ -2,7 +2,7 @@
namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
{
[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Explicit, Pack = 1)]
struct QueueBufferObject
{
[FieldOffset(0x0)]