openMSX
ReverseManager.hh
Go to the documentation of this file.
1#ifndef REVERSEMANGER_HH
2#define REVERSEMANGER_HH
3
4#include "Schedulable.hh"
5#include "EventListener.hh"
6#include "Command.hh"
7#include "EmuTime.hh"
8#include "MemBuffer.hh"
9#include "DeltaBlock.hh"
10#include "outer.hh"
11#include <cstdint>
12#include <deque>
13#include <span>
14#include <map>
15#include <memory>
16#include <string_view>
17#include <vector>
18
19namespace openmsx {
20
21class EventDelay;
22class EventDistributor;
23class Interpreter;
24class MSXMotherBoard;
25class Keyboard;
26class StateChange;
27class TclObject;
28
29class ReverseManager final : private EventListener
30{
31public:
32 static constexpr std::string_view REPLAY_DIR = "replays";
33 static constexpr std::string_view REPLAY_EXTENSION = ".omr";
34
35public:
36 explicit ReverseManager(MSXMotherBoard& motherBoard);
38
39 // Keyboard is special because we need to transfer the host keyboard
40 // state on 'reverse goto' to be able to resynchronize when replay
41 // stops. See Keyboard::transferHostKeyMatrix() for more info.
42 void registerKeyboard(Keyboard& keyboard_) {
43 keyboard = &keyboard_;
44 }
45
46 // To not loose any events we need to flush delayed events before
47 // switching machine. See comments in goTo() for more info.
48 void registerEventDelay(EventDelay& eventDelay_) {
49 eventDelay = &eventDelay_;
50 }
51
52 // Should only be used by MSXMotherBoard to be able to transfer
53 // reRecordCount to ReverseManager for version 2 of MSXMotherBoard
54 // serializers.
55 void setReRecordCount(unsigned count) {
56 reRecordCount = count;
57 }
58
59 [[nodiscard]] bool isReplaying() const;
60 void stopReplay(EmuTime::param time) noexcept;
61
62 template<typename T, typename... Args>
63 StateChange& record(EmuTime::param time, Args&& ...args) {
64 assert(!isReplaying());
65 ++replayIndex;
66 history.events.push_back(std::make_unique<T>(time, std::forward<Args>(args)...));
67 return *history.events.back();
68 }
69
70 [[nodiscard]] bool isCollecting() const { return collecting; }
71 [[nodiscard]] bool isViewOnlyMode() const;
72 [[nodiscard]] double getBegin() const;
73 [[nodiscard]] double getEnd() const;
74 [[nodiscard]] double getCurrent() const;
75 [[nodiscard]] std::vector<double> getSnapshotTimes() const;
76
77private:
78 struct ReverseChunk {
79 EmuTime time = EmuTime::zero();
80 std::vector<std::shared_ptr<DeltaBlock>> deltaBlocks;
81 MemBuffer<uint8_t> savestate;
82 size_t size;
83
84 // Number of recorded events (or replay index) when this
85 // snapshot was created. So when going back replay should
86 // start at this index.
87 unsigned eventCount;
88 };
89 using Chunks = std::map<unsigned, ReverseChunk>;
90 using Events = std::deque<std::unique_ptr<StateChange>>;
91
92 struct ReverseHistory {
93 void swap(ReverseHistory& other) noexcept;
94 void clear();
95 [[nodiscard]] unsigned getNextSeqNum(EmuTime::param time) const;
96
97 Chunks chunks;
98 Events events;
99 LastDeltaBlocks lastDeltaBlocks;
100 };
101
102 void start();
103 void stop();
104 void status(TclObject& result) const;
105 void debugInfo(TclObject& result) const;
106 void goBack(std::span<const TclObject> tokens);
107 void goTo(std::span<const TclObject> tokens);
108 void saveReplay(Interpreter& interp,
109 std::span<const TclObject> tokens, TclObject& result);
110 void loadReplay(Interpreter& interp,
111 std::span<const TclObject> tokens, TclObject& result);
112
113 void signalStopReplay(EmuTime::param time);
114 [[nodiscard]] EmuTime::param getEndTime(const ReverseHistory& history) const;
115 void goTo(EmuTime::param targetTime, bool noVideo);
116 void goTo(EmuTime::param targetTime, bool noVideo,
117 ReverseHistory& history, bool sameTimeLine);
118 void transferHistory(ReverseHistory& oldHistory,
119 unsigned oldEventCount);
120 void transferState(MSXMotherBoard& newBoard);
121 void takeSnapshot(EmuTime::param time);
122 void schedule(EmuTime::param time);
123 void replayNextEvent();
124 template<unsigned N> void dropOldSnapshots(unsigned count);
125
126 // Schedulable
127 struct SyncNewSnapshot final : Schedulable {
128 friend class ReverseManager;
129 explicit SyncNewSnapshot(Scheduler& s) : Schedulable(s) {}
130 void executeUntil(EmuTime::param /*time*/) override {
131 auto& rm = OUTER(ReverseManager, syncNewSnapshot);
132 rm.execNewSnapshot();
133 }
134 } syncNewSnapshot;
135 struct SyncInputEvent final : Schedulable {
136 friend class ReverseManager;
137 explicit SyncInputEvent(Scheduler& s) : Schedulable(s) {}
138 void executeUntil(EmuTime::param /*time*/) override {
139 auto& rm = OUTER(ReverseManager, syncInputEvent);
140 rm.execInputEvent();
141 }
142 } syncInputEvent;
143
144 void execNewSnapshot();
145 void execInputEvent();
146 [[nodiscard]] EmuTime::param getCurrentTime() const { return syncNewSnapshot.getCurrentTime(); }
147
148 // EventListener
149 int signalEvent(const Event& event) override;
150
151private:
152 MSXMotherBoard& motherBoard;
153 EventDistributor& eventDistributor;
154
155 struct ReverseCmd final : Command {
156 explicit ReverseCmd(CommandController& controller);
157 void execute(std::span<const TclObject> tokens, TclObject& result) override;
158 [[nodiscard]] std::string help(std::span<const TclObject> tokens) const override;
159 void tabCompletion(std::vector<std::string>& tokens) const override;
160 } reverseCmd;
161
162 Keyboard* keyboard = nullptr;
163 EventDelay* eventDelay = nullptr;
164 ReverseHistory history;
165 unsigned replayIndex = 0;
166 bool collecting = false;
167 bool pendingTakeSnapshot = false;
168
169 unsigned reRecordCount = 0;
170
171 friend struct Replay;
172};
173
174} // namespace openmsx
175
176#endif
This class is responsible for translating host events into MSX events.
Definition EventDelay.hh:27
This class manages the lifetime of a block of memory.
Definition MemBuffer.hh:29
void setReRecordCount(unsigned count)
void registerKeyboard(Keyboard &keyboard_)
void stopReplay(EmuTime::param time) noexcept
std::vector< double > getSnapshotTimes() const
static constexpr std::string_view REPLAY_DIR
void registerEventDelay(EventDelay &eventDelay_)
static constexpr std::string_view REPLAY_EXTENSION
StateChange & record(EmuTime::param time, Args &&...args)
Schedulable(const Schedulable &)=delete
Base class for all external MSX state changing events.
This file implemented 3 utility functions:
Definition Autofire.cc:11
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
#define OUTER(type, member)
Definition outer.hh:42