diff options
| author | Thog <me@thog.eu> | 2020-04-19 03:25:57 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-04-19 11:25:57 +1000 |
| commit | 644de99e86856bad3fe24a0324c06f96cee6a401 (patch) | |
| tree | 1615bc5acb7af4e9de0337bfad6ceac749cec0a0 /Ryujinx.HLE/HOS/Services/Mm | |
| parent | 4960ab85f81f48553b7217261f4181e31d812a10 (diff) | |
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
Diffstat (limited to 'Ryujinx.HLE/HOS/Services/Mm')
| -rw-r--r-- | Ryujinx.HLE/HOS/Services/Mm/IRequest.cs | 141 | ||||
| -rw-r--r-- | Ryujinx.HLE/HOS/Services/Mm/Types/MultiMediaOperationType.cs | 11 | ||||
| -rw-r--r-- | Ryujinx.HLE/HOS/Services/Mm/Types/MultiMediaSession.cs | 24 |
3 files changed, 153 insertions, 23 deletions
diff --git a/Ryujinx.HLE/HOS/Services/Mm/IRequest.cs b/Ryujinx.HLE/HOS/Services/Mm/IRequest.cs index cdd47295..f2891497 100644 --- a/Ryujinx.HLE/HOS/Services/Mm/IRequest.cs +++ b/Ryujinx.HLE/HOS/Services/Mm/IRequest.cs @@ -1,21 +1,30 @@ using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Services.Mm.Types; +using System.Collections.Generic; namespace Ryujinx.HLE.HOS.Services.Mm { [Service("mm:u")] class IRequest : IpcService { - public IRequest(ServiceCtx context) { } + private static object _sessionListLock = new object(); + private static List<MultiMediaSession> _sessionList = new List<MultiMediaSession>(); + + private static uint _uniqueId = 1; + + public IRequest(ServiceCtx context) {} [Command(0)] // InitializeOld(u32, u32, u32) public ResultCode InitializeOld(ServiceCtx context) { - int unknown0 = context.RequestData.ReadInt32(); - int unknown1 = context.RequestData.ReadInt32(); - int unknown2 = context.RequestData.ReadInt32(); + MultiMediaOperationType operationType = (MultiMediaOperationType)context.RequestData.ReadUInt32(); + int fgmId = context.RequestData.ReadInt32(); + bool isAutoClearEvent = context.RequestData.ReadInt32() != 0; - Logger.PrintStub(LogClass.ServiceMm, new { unknown0, unknown1, unknown2 }); + Logger.PrintStub(LogClass.ServiceMm, new { operationType, fgmId, isAutoClearEvent }); + + Register(operationType, fgmId, isAutoClearEvent); return ResultCode.Success; } @@ -24,7 +33,14 @@ namespace Ryujinx.HLE.HOS.Services.Mm // FinalizeOld(u32) public ResultCode FinalizeOld(ServiceCtx context) { - Logger.PrintStub(LogClass.ServiceMm); + MultiMediaOperationType operationType = (MultiMediaOperationType)context.RequestData.ReadUInt32(); + + Logger.PrintStub(LogClass.ServiceMm, new { operationType }); + + lock (_sessionListLock) + { + _sessionList.Remove(GetSessionByType(operationType)); + } return ResultCode.Success; } @@ -33,11 +49,17 @@ namespace Ryujinx.HLE.HOS.Services.Mm // SetAndWaitOld(u32, u32, u32) public ResultCode SetAndWaitOld(ServiceCtx context) { - int unknown0 = context.RequestData.ReadInt32(); - int unknown1 = context.RequestData.ReadInt32(); - int unknown2 = context.RequestData.ReadInt32(); + MultiMediaOperationType operationType = (MultiMediaOperationType)context.RequestData.ReadUInt32(); + uint value = context.RequestData.ReadUInt32(); + int timeout = context.RequestData.ReadInt32(); + + Logger.PrintStub(LogClass.ServiceMm, new { operationType, value, timeout }); + + lock (_sessionListLock) + { + GetSessionByType(operationType)?.SetAndWait(value, timeout); + } - Logger.PrintStub(LogClass.ServiceMm, new { unknown0, unknown1, unknown2 }); return ResultCode.Success; } @@ -45,20 +67,35 @@ namespace Ryujinx.HLE.HOS.Services.Mm // GetOld(u32) -> u32 public ResultCode GetOld(ServiceCtx context) { - int unknown0 = context.RequestData.ReadInt32(); + MultiMediaOperationType operationType = (MultiMediaOperationType)context.RequestData.ReadUInt32(); - Logger.PrintStub(LogClass.ServiceMm, new { unknown0 }); + Logger.PrintStub(LogClass.ServiceMm, new { operationType }); - context.ResponseData.Write(0); + lock (_sessionListLock) + { + MultiMediaSession session = GetSessionByType(operationType); + + uint currentValue = session == null ? 0 : session.CurrentValue; + + context.ResponseData.Write(currentValue); + } return ResultCode.Success; } [Command(4)] - // Initialize() + // Initialize(u32, u32, u32) -> u32 public ResultCode Initialize(ServiceCtx context) { - Logger.PrintStub(LogClass.ServiceMm); + MultiMediaOperationType operationType = (MultiMediaOperationType)context.RequestData.ReadUInt32(); + int fgmId = context.RequestData.ReadInt32(); + bool isAutoClearEvent = context.RequestData.ReadInt32() != 0; + + Logger.PrintStub(LogClass.ServiceMm, new { operationType, fgmId, isAutoClearEvent }); + + uint id = Register(operationType, fgmId, isAutoClearEvent); + + context.ResponseData.Write(id); return ResultCode.Success; } @@ -67,7 +104,14 @@ namespace Ryujinx.HLE.HOS.Services.Mm // Finalize(u32) public ResultCode Finalize(ServiceCtx context) { - Logger.PrintStub(LogClass.ServiceMm); + uint id = context.RequestData.ReadUInt32(); + + Logger.PrintStub(LogClass.ServiceMm, new { id }); + + lock (_sessionListLock) + { + _sessionList.Remove(GetSessionById(id)); + } return ResultCode.Success; } @@ -76,11 +120,16 @@ namespace Ryujinx.HLE.HOS.Services.Mm // SetAndWait(u32, u32, u32) public ResultCode SetAndWait(ServiceCtx context) { - int unknown0 = context.RequestData.ReadInt32(); - int unknown1 = context.RequestData.ReadInt32(); - int unknown2 = context.RequestData.ReadInt32(); + uint id = context.RequestData.ReadUInt32(); + uint value = context.RequestData.ReadUInt32(); + int timeout = context.RequestData.ReadInt32(); - Logger.PrintStub(LogClass.ServiceMm, new { unknown0, unknown1, unknown2 }); + Logger.PrintStub(LogClass.ServiceMm, new { id, value, timeout }); + + lock (_sessionListLock) + { + GetSessionById(id)?.SetAndWait(value, timeout); + } return ResultCode.Success; } @@ -89,13 +138,59 @@ namespace Ryujinx.HLE.HOS.Services.Mm // Get(u32) -> u32 public ResultCode Get(ServiceCtx context) { - int unknown0 = context.RequestData.ReadInt32(); + uint id = context.RequestData.ReadUInt32(); + + Logger.PrintStub(LogClass.ServiceMm, new { id }); - Logger.PrintStub(LogClass.ServiceMm, new { unknown0 }); + lock (_sessionListLock) + { + MultiMediaSession session = GetSessionById(id); - context.ResponseData.Write(0); + uint currentValue = session == null ? 0 : session.CurrentValue; + + context.ResponseData.Write(currentValue); + } return ResultCode.Success; } + + private MultiMediaSession GetSessionById(uint id) + { + foreach (MultiMediaSession session in _sessionList) + { + if (session.Id == id) + { + return session; + } + } + + return null; + } + + private MultiMediaSession GetSessionByType(MultiMediaOperationType type) + { + foreach (MultiMediaSession session in _sessionList) + { + if (session.Type == type) + { + return session; + } + } + + return null; + } + + private uint Register(MultiMediaOperationType type, int fgmId, bool isAutoClearEvent) + { + lock (_sessionListLock) + { + // Nintendo ignore the fgm id as the other interfaces were deprecated. + MultiMediaSession session = new MultiMediaSession(_uniqueId++, type, isAutoClearEvent); + + _sessionList.Add(session); + + return session.Id; + } + } } }
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Mm/Types/MultiMediaOperationType.cs b/Ryujinx.HLE/HOS/Services/Mm/Types/MultiMediaOperationType.cs new file mode 100644 index 00000000..cf4cdf20 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Mm/Types/MultiMediaOperationType.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.HLE.HOS.Services.Mm.Types +{ + enum MultiMediaOperationType : uint + { + // TODO: figure out the unknown variants. + Unknown2 = 2, + VideoDecode = 5, + VideoEncode = 6, + Unknown7 = 7 + } +} diff --git a/Ryujinx.HLE/HOS/Services/Mm/Types/MultiMediaSession.cs b/Ryujinx.HLE/HOS/Services/Mm/Types/MultiMediaSession.cs new file mode 100644 index 00000000..a6723eca --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Mm/Types/MultiMediaSession.cs @@ -0,0 +1,24 @@ +namespace Ryujinx.HLE.HOS.Services.Mm.Types +{ + class MultiMediaSession + { + public MultiMediaOperationType Type { get; } + + public bool IsAutoClearEvent { get; } + public uint Id { get; } + public uint CurrentValue { get; private set; } + + public MultiMediaSession(uint id, MultiMediaOperationType type, bool isAutoClearEvent) + { + Type = type; + Id = id; + IsAutoClearEvent = isAutoClearEvent; + CurrentValue = 0; + } + + public void SetAndWait(uint value, int timeout) + { + CurrentValue = value; + } + } +} |
