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