aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/Services/Mm
diff options
context:
space:
mode:
authorThog <me@thog.eu>2020-04-19 03:25:57 +0200
committerGitHub <noreply@github.com>2020-04-19 11:25:57 +1000
commit644de99e86856bad3fe24a0324c06f96cee6a401 (patch)
tree1615bc5acb7af4e9de0337bfad6ceac749cec0a0 /Ryujinx.HLE/HOS/Services/Mm
parent4960ab85f81f48553b7217261f4181e31d812a10 (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.cs141
-rw-r--r--Ryujinx.HLE/HOS/Services/Mm/Types/MultiMediaOperationType.cs11
-rw-r--r--Ryujinx.HLE/HOS/Services/Mm/Types/MultiMediaSession.cs24
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;
+ }
+ }
+}