Improve SteadyClock implementation accuracy
This commit is contained in:
parent
4ad3936afd
commit
5a7b8122a4
4 changed files with 146 additions and 14 deletions
|
@ -9,6 +9,7 @@ using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||||
using Ryujinx.HLE.HOS.Services.Sm;
|
using Ryujinx.HLE.HOS.Services.Sm;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
||||||
using Ryujinx.HLE.HOS.SystemState;
|
using Ryujinx.HLE.HOS.SystemState;
|
||||||
using Ryujinx.HLE.Loaders.Executables;
|
using Ryujinx.HLE.Loaders.Executables;
|
||||||
using Ryujinx.HLE.Loaders.Npdm;
|
using Ryujinx.HLE.Loaders.Npdm;
|
||||||
|
@ -195,6 +196,11 @@ namespace Ryujinx.HLE.HOS
|
||||||
LoadKeySet();
|
LoadKeySet();
|
||||||
|
|
||||||
ContentManager = new ContentManager(device);
|
ContentManager = new ContentManager(device);
|
||||||
|
|
||||||
|
// NOTE: Now we set the default internal offset of the steady clock like Nintendo does... even if it's strange this is accurate.
|
||||||
|
// TODO: use bpc:r and set:sys (and set external clock source id from settings)
|
||||||
|
DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||||
|
SteadyClockCore.Instance.SetInternalOffset(new TimeSpanType(((ulong)(DateTime.Now.ToUniversalTime() - UnixEpoch).TotalSeconds) * 1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadCart(string exeFsDir, string romFsFile = null)
|
public void LoadCart(string exeFsDir, string romFsFile = null)
|
||||||
|
|
34
Ryujinx.HLE/HOS/Services/Time/Clock/ClockTypes.cs
Normal file
34
Ryujinx.HLE/HOS/Services/Time/Clock/ClockTypes.cs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
using Ryujinx.HLE.Utilities;
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||||
|
{
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct TimeSpanType
|
||||||
|
{
|
||||||
|
public ulong NanoSeconds;
|
||||||
|
|
||||||
|
public TimeSpanType(ulong nanoSeconds)
|
||||||
|
{
|
||||||
|
NanoSeconds = nanoSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ulong ToSeconds()
|
||||||
|
{
|
||||||
|
return NanoSeconds * 1000000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TimeSpanType FromTicks(ulong ticks, ulong frequency)
|
||||||
|
{
|
||||||
|
return new TimeSpanType((ticks * 1000) / frequency);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct SteadyClockTimePoint
|
||||||
|
{
|
||||||
|
public ulong TimePoint;
|
||||||
|
public UInt128 ClockSourceId;
|
||||||
|
}
|
||||||
|
}
|
78
Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs
Normal file
78
Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||||
|
using Ryujinx.HLE.Utilities;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||||
|
{
|
||||||
|
class SteadyClockCore
|
||||||
|
{
|
||||||
|
private TimeSpanType _testOffset;
|
||||||
|
private TimeSpanType _internalOffset;
|
||||||
|
private UInt128 _clockSourceId;
|
||||||
|
|
||||||
|
private static SteadyClockCore instance;
|
||||||
|
|
||||||
|
public static SteadyClockCore Instance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (instance == null)
|
||||||
|
{
|
||||||
|
instance = new SteadyClockCore();
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private SteadyClockCore()
|
||||||
|
{
|
||||||
|
_testOffset = new TimeSpanType(0);
|
||||||
|
_internalOffset = new TimeSpanType(0);
|
||||||
|
_clockSourceId = new UInt128(Guid.NewGuid().ToByteArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
private SteadyClockTimePoint GetTimePoint(KThread thread)
|
||||||
|
{
|
||||||
|
SteadyClockTimePoint result = new SteadyClockTimePoint
|
||||||
|
{
|
||||||
|
TimePoint = 0,
|
||||||
|
ClockSourceId = _clockSourceId
|
||||||
|
};
|
||||||
|
|
||||||
|
result.TimePoint = _internalOffset.ToSeconds() + TimeSpanType.FromTicks(thread.Context.ThreadState.CntpctEl0, thread.Context.ThreadState.CntfrqEl0).ToSeconds();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SteadyClockTimePoint GetCurrentTimePoint(KThread thread)
|
||||||
|
{
|
||||||
|
SteadyClockTimePoint result = GetTimePoint(thread);
|
||||||
|
|
||||||
|
result.TimePoint += _testOffset.ToSeconds();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimeSpanType GetTestOffset()
|
||||||
|
{
|
||||||
|
return _testOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetTestOffset(TimeSpanType testOffset)
|
||||||
|
{
|
||||||
|
_testOffset = testOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check if this is accurate
|
||||||
|
public TimeSpanType GetInternalOffset()
|
||||||
|
{
|
||||||
|
return _internalOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check if this is accurate
|
||||||
|
public void SetInternalOffset(TimeSpanType internalOffset)
|
||||||
|
{
|
||||||
|
_internalOffset = internalOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,26 +1,18 @@
|
||||||
using System;
|
using Ryujinx.Common;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Time
|
namespace Ryujinx.HLE.HOS.Services.Time
|
||||||
{
|
{
|
||||||
class ISteadyClock : IpcService
|
class ISteadyClock : IpcService
|
||||||
{
|
{
|
||||||
private ulong _testOffset;
|
|
||||||
|
|
||||||
public ISteadyClock()
|
|
||||||
{
|
|
||||||
_testOffset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command(0)]
|
[Command(0)]
|
||||||
// GetCurrentTimePoint() -> nn::time::SteadyClockTimePoint
|
// GetCurrentTimePoint() -> nn::time::SteadyClockTimePoint
|
||||||
public ResultCode GetCurrentTimePoint(ServiceCtx context)
|
public ResultCode GetCurrentTimePoint(ServiceCtx context)
|
||||||
{
|
{
|
||||||
context.ResponseData.Write((long)(System.Diagnostics.Process.GetCurrentProcess().StartTime - DateTime.Now).TotalSeconds);
|
SteadyClockTimePoint currentTimePoint = SteadyClockCore.Instance.GetCurrentTimePoint(context.Thread);
|
||||||
|
|
||||||
for (int i = 0; i < 0x10; i++)
|
context.ResponseData.WriteStruct(currentTimePoint);
|
||||||
{
|
|
||||||
context.ResponseData.Write((byte)0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
@ -29,7 +21,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||||
// GetTestOffset() -> nn::TimeSpanType
|
// GetTestOffset() -> nn::TimeSpanType
|
||||||
public ResultCode GetTestOffset(ServiceCtx context)
|
public ResultCode GetTestOffset(ServiceCtx context)
|
||||||
{
|
{
|
||||||
context.ResponseData.Write(_testOffset);
|
context.ResponseData.WriteStruct(SteadyClockCore.Instance.GetTestOffset());
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
@ -38,7 +30,29 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||||
// SetTestOffset(nn::TimeSpanType)
|
// SetTestOffset(nn::TimeSpanType)
|
||||||
public ResultCode SetTestOffset(ServiceCtx context)
|
public ResultCode SetTestOffset(ServiceCtx context)
|
||||||
{
|
{
|
||||||
_testOffset = context.RequestData.ReadUInt64();
|
TimeSpanType testOffset = context.RequestData.ReadStruct<TimeSpanType>();
|
||||||
|
|
||||||
|
SteadyClockCore.Instance.SetTestOffset(testOffset);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command(200)] // 3.0.0+
|
||||||
|
// GetInternalOffset() -> nn::TimeSpanType
|
||||||
|
public long GetInternalOffset(ServiceCtx context)
|
||||||
|
{
|
||||||
|
context.ResponseData.WriteStruct(SteadyClockCore.Instance.GetInternalOffset());
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command(201)] // 3.0.0-3.0.2
|
||||||
|
// SetInternalOffset(nn::TimeSpanType)
|
||||||
|
public long SetInternalOffset(ServiceCtx context)
|
||||||
|
{
|
||||||
|
TimeSpanType internalOffset = context.RequestData.ReadStruct<TimeSpanType>();
|
||||||
|
|
||||||
|
SteadyClockCore.Instance.SetInternalOffset(internalOffset);
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue