openMSX
RealTime.cc
Go to the documentation of this file.
1#include "RealTime.hh"
2
3#include "BooleanSetting.hh"
4#include "Event.hh"
5#include "EventDelay.hh"
6#include "EventDistributor.hh"
7#include "GlobalSettings.hh"
8#include "MSXMotherBoard.hh"
9#include "Reactor.hh"
10#include "ThrottleManager.hh"
11#include "Timer.hh"
12
13#include "narrow.hh"
14#include "unreachable.hh"
15
16namespace openmsx {
17
18const double SYNC_INTERVAL = 0.08; // s
19const int64_t MAX_LAG = 200000; // us
20const uint64_t ALLOWED_LAG = 20000; // us
21
23 MSXMotherBoard& motherBoard_, GlobalSettings& globalSettings,
24 EventDelay& eventDelay_)
25 : Schedulable(motherBoard_.getScheduler())
26 , motherBoard(motherBoard_)
27 , eventDistributor(motherBoard.getReactor().getEventDistributor())
28 , eventDelay(eventDelay_)
29 , speedManager (globalSettings.getSpeedManager())
30 , throttleManager(globalSettings.getThrottleManager())
31 , pauseSetting (globalSettings.getPauseSetting())
32 , powerSetting (globalSettings.getPowerSetting())
33{
34 speedManager.attach(*this);
35 throttleManager.attach(*this);
36 pauseSetting.attach(*this);
37 powerSetting.attach(*this);
38
39 resync();
40
42 eventDistributor.registerEventListener(type, *this);
43 }
44}
45
47{
49 eventDistributor.unregisterEventListener(type, *this);
50 }
51 powerSetting.detach(*this);
52 pauseSetting.detach(*this);
53 throttleManager.detach(*this);
54 speedManager.detach(*this);
55}
56
57double RealTime::getRealDuration(EmuTime::param time1, EmuTime::param time2) const
58{
59 return (time2 - time1).toDouble() / speedManager.getSpeed();
60}
61
63{
64 return EmuDuration(realDur * speedManager.getSpeed());
65}
66
67bool RealTime::timeLeft(uint64_t us, EmuTime::param time) const
68{
69 auto realDuration = static_cast<uint64_t>(
70 getRealDuration(emuTime, time) * 1000000ULL);
71 auto currentRealTime = Timer::getTime();
72 return (currentRealTime + us) <
73 (idealRealTime + realDuration + ALLOWED_LAG);
74}
75
76void RealTime::sync(EmuTime::param time, bool allowSleep)
77{
78 if (allowSleep) {
80 }
81 internalSync(time, allowSleep);
82 if (allowSleep) {
84 }
85}
86
87void RealTime::internalSync(EmuTime::param time, bool allowSleep)
88{
89 if (throttleManager.isThrottled()) {
90 auto realDuration = static_cast<uint64_t>(
91 getRealDuration(emuTime, time) * 1000000ULL);
92 idealRealTime += realDuration;
93 auto currentRealTime = Timer::getTime();
94 auto sleep = narrow_cast<int64_t>(idealRealTime - currentRealTime);
95 if (allowSleep) {
96 // want to sleep for 'sleep' us
97 sleep += narrow_cast<int64_t>(sleepAdjust);
98 int64_t delta = 0;
99 if (sleep > 0) {
100 Timer::sleep(sleep); // request to sleep for 'sleep+sleepAdjust'
101 auto slept = narrow<int64_t>(Timer::getTime() - currentRealTime);
102 delta = sleep - slept; // actually slept for 'slept' us
103 }
104 const double ALPHA = 0.2;
105 sleepAdjust = sleepAdjust * (1 - ALPHA) + narrow_cast<double>(delta) * ALPHA;
106 }
107 if (-sleep > MAX_LAG) {
108 idealRealTime = currentRealTime - MAX_LAG / 2;
109 }
110 }
111 if (allowSleep) {
112 eventDelay.sync(time);
113 }
114
115 emuTime = time;
116}
117
118void RealTime::executeUntil(EmuTime::param time)
119{
120 internalSync(time, true);
122}
123
124int RealTime::signalEvent(const Event& event)
125{
126 if (!motherBoard.isActive() || !enabled) {
127 // these are global events, only the active machine should
128 // synchronize with real time
129 return 0;
130 }
131 visit(overloaded{
132 [&](const FinishFrameEvent& ffe) {
133 if (!ffe.needRender()) {
134 // sync but don't sleep
135 sync(getCurrentTime(), false);
136 }
137 },
138 [&](const FrameDrawnEvent&) {
139 // sync and possibly sleep
140 sync(getCurrentTime(), true);
141 },
142 [&](const EventBase /*e*/) {
144 }
145 }, event);
146 return 0;
147}
148
149void RealTime::update(const Setting& /*setting*/) noexcept
150{
151 resync();
152}
153
154void RealTime::update(const SpeedManager& /*speedManager*/) noexcept
155{
156 resync();
157}
158
159void RealTime::update(const ThrottleManager& /*throttleManager*/) noexcept
160{
161 resync();
162}
163
165{
166 if (!enabled) return;
167
168 idealRealTime = Timer::getTime();
169 sleepAdjust = 0.0;
171 emuTime = getCurrentTime();
173}
174
176{
177 enabled = true;
178 resync();
179}
180
182{
183 enabled = false;
185}
186
187} // namespace openmsx
This class is responsible for translating host events into MSX events.
Definition EventDelay.hh:27
void sync(EmuTime::param curEmu)
Definition EventDelay.cc:63
void unregisterEventListener(EventType type, EventListener &listener)
Unregisters a previously registered event listener.
void registerEventListener(EventType type, EventListener &listener, Priority priority=OTHER)
Registers a given object to receive certain events.
This class contains settings that are used by several other class (including some singletons).
bool timeLeft(uint64_t us, EmuTime::param time) const
Check that there is enough real time left before we reach as certain point in emulated time.
Definition RealTime.cc:67
double getRealDuration(EmuTime::param time1, EmuTime::param time2) const
Convert EmuTime to RealTime.
Definition RealTime.cc:57
EmuDuration getEmuDuration(double realDur) const
Convert RealTime to EmuTime.
Definition RealTime.cc:62
RealTime(MSXMotherBoard &motherBoard, GlobalSettings &globalSettings, EventDelay &eventDelay)
Definition RealTime.cc:22
Every class that wants to get scheduled at some point must inherit from this class.
void setSyncPoint(EmuTime::param timestamp)
EmuTime::param getCurrentTime() const
Convenience method: This is the same as getScheduler().getCurrentTime().
double getSpeed() const
Return the desired ratio between EmuTime and real time.
void detach(Observer< T > &observer)
Definition Subject.hh:60
void attach(Observer< T > &observer)
Definition Subject.hh:54
bool isThrottled() const
Ask if throttling is enabled.
uint64_t getTime()
Get current (real) time in us.
Definition Timer.cc:7
void sleep(uint64_t us)
Sleep for the specified amount of time (in us).
Definition Timer.cc:27
This file implemented 3 utility functions:
Definition Autofire.cc:11
const double SYNC_INTERVAL
Definition RealTime.cc:18
const uint64_t ALLOWED_LAG
Definition RealTime.cc:20
std::variant< KeyUpEvent, KeyDownEvent, MouseMotionEvent, MouseButtonUpEvent, MouseButtonDownEvent, MouseWheelEvent, JoystickAxisMotionEvent, JoystickHatEvent, JoystickButtonUpEvent, JoystickButtonDownEvent, OsdControlReleaseEvent, OsdControlPressEvent, WindowEvent, TextEvent, FileDropEvent, QuitEvent, FinishFrameEvent, CliCommandEvent, GroupEvent, BootEvent, FrameDrawnEvent, BreakEvent, SwitchRendererEvent, TakeReverseSnapshotEvent, AfterTimedEvent, MachineLoadedEvent, MachineActivatedEvent, MachineDeactivatedEvent, MidiInReaderEvent, MidiInWindowsEvent, MidiInCoreMidiEvent, MidiInCoreMidiVirtualEvent, MidiInALSAEvent, Rs232TesterEvent, Rs232NetEvent, ImGuiDelayedActionEvent, ImGuiActiveEvent > Event
Definition Event.hh:446
const int64_t MAX_LAG
Definition RealTime.cc:19
#define UNREACHABLE