time: Update for 15.0.0 changes and fixes long standing issues (#4822)
* time: Update for 15.0.0 changes Last time we did an upgrade on the time service was during 9.x era, it was about time to take back that reverse again! 15.0.0 added a new structure on the shared memory to get steady clock raw timepoints with a granularity in nanoseconds. This commit implements this new part. I plan to write a follow up with a bit of refactoring of this ancient part of the emulator. As always, reverse and work done by your truly. PS: As a reminder, if this change is reused anywhere else, work should be credited as Ryujinx and not my person. * time: Do not set setup value to posix time This should fix local and network clock returning 0 under usage with shared memory. This probably fix #2430. * Address gdkchan's comment * Fix internal offset not working since changes and ensure that user clock have a valid clock id * time: Report auto correcting clock and hardcode steady clock unique id Fix Pokemon Sword Pokejobs for real. * Address gdkchan's comment
This commit is contained in:
parent
5440d4ad5c
commit
470a8031a4
3 changed files with 56 additions and 21 deletions
|
@ -200,9 +200,10 @@ namespace Ryujinx.HLE.HOS
|
||||||
|
|
||||||
LibHacHorizonManager = device.Configuration.LibHacHorizonManager;
|
LibHacHorizonManager = device.Configuration.LibHacHorizonManager;
|
||||||
|
|
||||||
|
// We hardcode a clock source id to avoid it changing between each start.
|
||||||
// TODO: use set:sys (and get external clock source id from settings)
|
// TODO: use set:sys (and get external clock source id from settings)
|
||||||
// TODO: use "time!standard_steady_clock_rtc_update_interval_minutes" and implement a worker thread to be accurate.
|
// TODO: use "time!standard_steady_clock_rtc_update_interval_minutes" and implement a worker thread to be accurate.
|
||||||
UInt128 clockSourceId = UInt128Utils.CreateRandom();
|
UInt128 clockSourceId = new UInt128(0x36a0328702ce8bc1, 0x1608eaba02333284);
|
||||||
IRtcManager.GetExternalRtcValue(out ulong rtcValue);
|
IRtcManager.GetExternalRtcValue(out ulong rtcValue);
|
||||||
|
|
||||||
// We assume the rtc is system time.
|
// We assume the rtc is system time.
|
||||||
|
@ -222,22 +223,22 @@ namespace Ryujinx.HLE.HOS
|
||||||
internalOffset = internalOffset.AddSeconds(-3600L);
|
internalOffset = internalOffset.AddSeconds(-3600L);
|
||||||
}
|
}
|
||||||
|
|
||||||
internalOffset = new TimeSpanType(-internalOffset.NanoSeconds);
|
systemTime = new TimeSpanType(systemTime.NanoSeconds + internalOffset.NanoSeconds);
|
||||||
|
|
||||||
// First init the standard steady clock
|
// First init the standard steady clock
|
||||||
TimeServiceManager.Instance.SetupStandardSteadyClock(TickSource, clockSourceId, systemTime, internalOffset, TimeSpanType.Zero, false);
|
TimeServiceManager.Instance.SetupStandardSteadyClock(TickSource, clockSourceId, TimeSpanType.Zero, TimeSpanType.Zero, TimeSpanType.Zero, false);
|
||||||
TimeServiceManager.Instance.SetupStandardLocalSystemClock(TickSource, new SystemClockContext(), systemTime.ToSeconds());
|
TimeServiceManager.Instance.SetupStandardLocalSystemClock(TickSource, new SystemClockContext(), systemTime.ToSeconds());
|
||||||
|
TimeServiceManager.Instance.StandardLocalSystemClock.GetClockContext(TickSource, out SystemClockContext localSytemClockContext);
|
||||||
|
|
||||||
if (NxSettings.Settings.TryGetValue("time!standard_network_clock_sufficient_accuracy_minutes", out object standardNetworkClockSufficientAccuracyMinutes))
|
if (NxSettings.Settings.TryGetValue("time!standard_network_clock_sufficient_accuracy_minutes", out object standardNetworkClockSufficientAccuracyMinutes))
|
||||||
{
|
{
|
||||||
TimeSpanType standardNetworkClockSufficientAccuracy = new TimeSpanType((int)standardNetworkClockSufficientAccuracyMinutes * 60000000000);
|
TimeSpanType standardNetworkClockSufficientAccuracy = new TimeSpanType((int)standardNetworkClockSufficientAccuracyMinutes * 60000000000);
|
||||||
|
|
||||||
// The network system clock needs a valid system clock, as such we setup this system clock using the local system clock.
|
// The network system clock needs a valid system clock, as such we setup this system clock using the local system clock.
|
||||||
TimeServiceManager.Instance.StandardLocalSystemClock.GetClockContext(TickSource, out SystemClockContext localSytemClockContext);
|
|
||||||
TimeServiceManager.Instance.SetupStandardNetworkSystemClock(localSytemClockContext, standardNetworkClockSufficientAccuracy);
|
TimeServiceManager.Instance.SetupStandardNetworkSystemClock(localSytemClockContext, standardNetworkClockSufficientAccuracy);
|
||||||
}
|
}
|
||||||
|
|
||||||
TimeServiceManager.Instance.SetupStandardUserSystemClock(TickSource, false, SteadyClockTimePoint.GetRandom());
|
TimeServiceManager.Instance.SetupStandardUserSystemClock(TickSource, true, localSytemClockContext.SteadyTimePoint);
|
||||||
|
|
||||||
// FIXME: TimeZone should be init here but it's actually done in ContentManager
|
// FIXME: TimeZone should be init here but it's actually done in ContentManager
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Services.Time.Clock.Types
|
||||||
|
{
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
|
struct ContinuousAdjustmentTimePoint
|
||||||
|
{
|
||||||
|
public ulong ClockOffset;
|
||||||
|
public long Multiplier;
|
||||||
|
public long DivisorLog2;
|
||||||
|
public SystemClockContext Context;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
using Ryujinx.Cpu;
|
using Ryujinx.Cpu;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||||
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Time.Clock.Types;
|
||||||
using Ryujinx.HLE.HOS.Services.Time.Types;
|
using Ryujinx.HLE.HOS.Services.Time.Types;
|
||||||
using Ryujinx.HLE.Utilities;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
@ -20,6 +20,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||||
private const uint LocalSystemClockContextOffset = 0x38;
|
private const uint LocalSystemClockContextOffset = 0x38;
|
||||||
private const uint NetworkSystemClockContextOffset = 0x80;
|
private const uint NetworkSystemClockContextOffset = 0x80;
|
||||||
private const uint AutomaticCorrectionEnabledOffset = 0xC8;
|
private const uint AutomaticCorrectionEnabledOffset = 0xC8;
|
||||||
|
private const uint ContinuousAdjustmentTimePointOffset = 0xD0;
|
||||||
|
|
||||||
public void Initialize(Switch device, KSharedMemory sharedMemory, SharedMemoryStorage timeSharedMemoryStorage, int timeSharedMemorySize)
|
public void Initialize(Switch device, KSharedMemory sharedMemory, SharedMemoryStorage timeSharedMemoryStorage, int timeSharedMemorySize)
|
||||||
{
|
{
|
||||||
|
@ -39,15 +40,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||||
|
|
||||||
public void SetupStandardSteadyClock(ITickSource tickSource, UInt128 clockSourceId, TimeSpanType currentTimePoint)
|
public void SetupStandardSteadyClock(ITickSource tickSource, UInt128 clockSourceId, TimeSpanType currentTimePoint)
|
||||||
{
|
{
|
||||||
TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(tickSource.Counter, tickSource.Frequency);
|
UpdateSteadyClock(tickSource, clockSourceId, currentTimePoint);
|
||||||
|
|
||||||
SteadyClockContext context = new SteadyClockContext
|
|
||||||
{
|
|
||||||
InternalOffset = (ulong)(currentTimePoint.NanoSeconds - ticksTimeSpan.NanoSeconds),
|
|
||||||
ClockSourceId = clockSourceId
|
|
||||||
};
|
|
||||||
|
|
||||||
WriteObjectToSharedMemory(SteadyClockContextOffset, 4, context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetAutomaticCorrectionEnabled(bool isAutomaticCorrectionEnabled)
|
public void SetAutomaticCorrectionEnabled(bool isAutomaticCorrectionEnabled)
|
||||||
|
@ -59,9 +52,37 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||||
public void SetSteadyClockRawTimePoint(ITickSource tickSource, TimeSpanType currentTimePoint)
|
public void SetSteadyClockRawTimePoint(ITickSource tickSource, TimeSpanType currentTimePoint)
|
||||||
{
|
{
|
||||||
SteadyClockContext context = ReadObjectFromSharedMemory<SteadyClockContext>(SteadyClockContextOffset, 4);
|
SteadyClockContext context = ReadObjectFromSharedMemory<SteadyClockContext>(SteadyClockContextOffset, 4);
|
||||||
|
|
||||||
|
UpdateSteadyClock(tickSource, context.ClockSourceId, currentTimePoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateSteadyClock(ITickSource tickSource, UInt128 clockSourceId, TimeSpanType currentTimePoint)
|
||||||
|
{
|
||||||
TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(tickSource.Counter, tickSource.Frequency);
|
TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(tickSource.Counter, tickSource.Frequency);
|
||||||
|
|
||||||
context.InternalOffset = (ulong)(currentTimePoint.NanoSeconds - ticksTimeSpan.NanoSeconds);
|
ContinuousAdjustmentTimePoint adjustmentTimePoint = new ContinuousAdjustmentTimePoint
|
||||||
|
{
|
||||||
|
ClockOffset = (ulong)ticksTimeSpan.NanoSeconds,
|
||||||
|
Multiplier = 1,
|
||||||
|
DivisorLog2 = 0,
|
||||||
|
Context = new SystemClockContext
|
||||||
|
{
|
||||||
|
Offset = 0,
|
||||||
|
SteadyTimePoint = new SteadyClockTimePoint
|
||||||
|
{
|
||||||
|
ClockSourceId = clockSourceId,
|
||||||
|
TimePoint = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
WriteObjectToSharedMemory(ContinuousAdjustmentTimePointOffset, 4, adjustmentTimePoint);
|
||||||
|
|
||||||
|
SteadyClockContext context = new SteadyClockContext
|
||||||
|
{
|
||||||
|
InternalOffset = (ulong)(currentTimePoint.NanoSeconds - ticksTimeSpan.NanoSeconds),
|
||||||
|
ClockSourceId = clockSourceId
|
||||||
|
};
|
||||||
|
|
||||||
WriteObjectToSharedMemory(SteadyClockContextOffset, 4, context);
|
WriteObjectToSharedMemory(SteadyClockContextOffset, 4, context);
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue