summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorspycrab <spycrab@users.noreply.github.com>2017-08-30 16:44:28 +0200
committerspycrab <spycrab@users.noreply.github.com>2017-11-19 22:06:32 +0100
commit474b1c2d5c8a8b48274f15ea7140b3e8ddc50c6a (patch)
tree922c2739a4494d15ce52a089be16091470d5b9d4 /Source/Core
parentaa8bf7133319ac3a02ca621d81021b96b63514cf (diff)
Qt: Implement FIFO Player
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Core/FifoPlayer/FifoPlayer.h3
-rw-r--r--Source/Core/Core/FifoPlayer/FifoRecorder.h5
-rw-r--r--Source/Core/DolphinQt2/CMakeLists.txt1
-rw-r--r--Source/Core/DolphinQt2/DolphinQt2.vcxproj3
-rw-r--r--Source/Core/DolphinQt2/FIFOPlayerWindow.cpp342
-rw-r--r--Source/Core/DolphinQt2/FIFOPlayerWindow.h62
-rw-r--r--Source/Core/DolphinQt2/MainWindow.cpp15
-rw-r--r--Source/Core/DolphinQt2/MainWindow.h3
-rw-r--r--Source/Core/DolphinQt2/MenuBar.cpp2
-rw-r--r--Source/Core/DolphinQt2/MenuBar.h4
10 files changed, 435 insertions, 5 deletions
diff --git a/Source/Core/Core/FifoPlayer/FifoPlayer.h b/Source/Core/Core/FifoPlayer/FifoPlayer.h
index 12f5ae0745..48b6b5db7d 100644
--- a/Source/Core/Core/FifoPlayer/FifoPlayer.h
+++ b/Source/Core/Core/FifoPlayer/FifoPlayer.h
@@ -4,6 +4,7 @@
#pragma once
+#include <functional>
#include <memory>
#include <string>
#include <vector>
@@ -56,7 +57,7 @@ extern bool IsPlayingBackFifologWithBrokenEFBCopies;
class FifoPlayer
{
public:
- typedef void (*CallbackFunc)(void);
+ using CallbackFunc = std::function<void()>;
~FifoPlayer();
diff --git a/Source/Core/Core/FifoPlayer/FifoRecorder.h b/Source/Core/Core/FifoPlayer/FifoRecorder.h
index 7410f474a5..98f7b34046 100644
--- a/Source/Core/Core/FifoPlayer/FifoRecorder.h
+++ b/Source/Core/Core/FifoPlayer/FifoRecorder.h
@@ -4,6 +4,7 @@
#pragma once
+#include <functional>
#include <memory>
#include <mutex>
#include <vector>
@@ -13,7 +14,7 @@
class FifoRecorder
{
public:
- typedef void (*CallbackFunc)(void);
+ using CallbackFunc = std::function<void()>;
FifoRecorder();
@@ -56,7 +57,7 @@ private:
bool m_WasRecording = false;
bool m_RequestedRecordingEnd = false;
s32 m_RecordFramesRemaining = 0;
- CallbackFunc m_FinishedCb = nullptr;
+ CallbackFunc m_FinishedCb;
std::unique_ptr<FifoDataFile> m_File;
// Accessed only from video thread
diff --git a/Source/Core/DolphinQt2/CMakeLists.txt b/Source/Core/DolphinQt2/CMakeLists.txt
index ff66dada5a..ea8b9be430 100644
--- a/Source/Core/DolphinQt2/CMakeLists.txt
+++ b/Source/Core/DolphinQt2/CMakeLists.txt
@@ -18,6 +18,7 @@ set(CMAKE_AUTOMOC ON)
set(SRCS
AboutDialog.cpp
+ FIFOPlayerWindow.cpp
HotkeyScheduler.cpp
Host.cpp
InDevelopmentWarning.cpp
diff --git a/Source/Core/DolphinQt2/DolphinQt2.vcxproj b/Source/Core/DolphinQt2/DolphinQt2.vcxproj
index 8ac0466b49..82d1a653bb 100644
--- a/Source/Core/DolphinQt2/DolphinQt2.vcxproj
+++ b/Source/Core/DolphinQt2/DolphinQt2.vcxproj
@@ -83,6 +83,7 @@
<QtMoc Include="Config\InfoWidget.h" />
<QtMoc Include="Config\PropertiesDialog.h" />
<QtMoc Include="Config\SettingsWindow.h" />
+ <QtMoc Include="FIFOPlayerWindow.h" />
<QtMoc Include="GameList\GameFile.h" />
<QtMoc Include="GameList\GameList.h" />
<QtMoc Include="GameList\GameListModel.h" />
@@ -118,6 +119,7 @@
<ClCompile Include="$(QtMocOutPrefix)CheatWarningWidget.cpp" />
<ClCompile Include="$(QtMocOutPrefix)ControllersWindow.cpp" />
<ClCompile Include="$(QtMocOutPrefix)EnhancementsWidget.cpp" />
+ <ClCompile Include="$(QtMocOutPrefix)FIFOPlayerWindow.cpp" />
<ClCompile Include="$(QtMocOutPrefix)FilesystemWidget.cpp" />
<ClCompile Include="$(QtMocOutPrefix)WindowActivationEventFilter.cpp" />
<ClCompile Include="$(QtMocOutPrefix)GameList.cpp" />
@@ -198,6 +200,7 @@
<ClCompile Include="Config\LogWidget.cpp" />
<ClCompile Include="Config\PropertiesDialog.cpp" />
<ClCompile Include="Config\SettingsWindow.cpp" />
+ <ClCompile Include="FIFOPlayerWindow.cpp" />
<ClCompile Include="GameList\GameFile.cpp" />
<ClCompile Include="GameList\GameFileCache.cpp" />
<ClCompile Include="GameList\GameList.cpp" />
diff --git a/Source/Core/DolphinQt2/FIFOPlayerWindow.cpp b/Source/Core/DolphinQt2/FIFOPlayerWindow.cpp
new file mode 100644
index 0000000000..2173914a18
--- /dev/null
+++ b/Source/Core/DolphinQt2/FIFOPlayerWindow.cpp
@@ -0,0 +1,342 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include "DolphinQt2/FIFOPlayerWindow.h"
+
+#include <QCheckBox>
+#include <QDialogButtonBox>
+#include <QFileDialog>
+#include <QGroupBox>
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QMessageBox>
+#include <QPushButton>
+#include <QSpinBox>
+#include <QVBoxLayout>
+
+#include <algorithm>
+
+#include "Core/Core.h"
+#include "Core/FifoPlayer/FifoDataFile.h"
+#include "Core/FifoPlayer/FifoPlaybackAnalyzer.h"
+#include "Core/FifoPlayer/FifoPlayer.h"
+#include "Core/FifoPlayer/FifoRecorder.h"
+
+#include "DolphinQt2/QtUtils/QueueOnObject.h"
+#include "DolphinQt2/Settings.h"
+
+FIFOPlayerWindow::FIFOPlayerWindow(QWidget* parent) : QDialog(parent)
+{
+ setWindowTitle(tr("FIFO Player"));
+
+ CreateWidgets();
+ ConnectWidgets();
+
+ UpdateInfo();
+
+ UpdateControls();
+
+ FifoPlayer::GetInstance().SetFileLoadedCallback(
+ [this] { QueueOnObject(this, &FIFOPlayerWindow::OnFIFOLoaded); });
+ FifoPlayer::GetInstance().SetFrameWrittenCallback(
+ [this] { QueueOnObject(this, &FIFOPlayerWindow::OnFIFOLoaded); });
+
+ connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) {
+ if (state == Core::State::Running)
+ OnEmulationStarted();
+ else if (state == Core::State::Uninitialized)
+ OnEmulationStopped();
+ });
+}
+
+FIFOPlayerWindow::~FIFOPlayerWindow()
+{
+ FifoPlayer::GetInstance().SetFileLoadedCallback({});
+ FifoPlayer::GetInstance().SetFrameWrittenCallback({});
+}
+
+void FIFOPlayerWindow::CreateWidgets()
+{
+ auto* layout = new QVBoxLayout;
+
+ // Info
+ auto* info_group = new QGroupBox(tr("File Info"));
+ auto* info_layout = new QHBoxLayout;
+
+ m_info_label = new QLabel;
+ info_layout->addWidget(m_info_label);
+ info_group->setLayout(info_layout);
+
+ m_info_label->setFixedHeight(QFontMetrics(font()).lineSpacing() * 3);
+
+ // Object Range
+ auto* object_range_group = new QGroupBox(tr("Object Range"));
+ auto* object_range_layout = new QHBoxLayout;
+
+ m_object_range_from = new QSpinBox;
+ m_object_range_from_label = new QLabel(tr("From:"));
+ m_object_range_to = new QSpinBox;
+ m_object_range_to_label = new QLabel(tr("To:"));
+
+ object_range_layout->addWidget(m_object_range_from_label);
+ object_range_layout->addWidget(m_object_range_from);
+ object_range_layout->addWidget(m_object_range_to_label);
+ object_range_layout->addWidget(m_object_range_to);
+ object_range_group->setLayout(object_range_layout);
+
+ // Frame Range
+ auto* frame_range_group = new QGroupBox(tr("Frame Range"));
+ auto* frame_range_layout = new QHBoxLayout;
+
+ m_frame_range_from = new QSpinBox;
+ m_frame_range_from_label = new QLabel(tr("From:"));
+ m_frame_range_to = new QSpinBox;
+ m_frame_range_to_label = new QLabel(tr("To:"));
+
+ frame_range_layout->addWidget(m_frame_range_from_label);
+ frame_range_layout->addWidget(m_frame_range_from);
+ frame_range_layout->addWidget(m_frame_range_to_label);
+ frame_range_layout->addWidget(m_frame_range_to);
+ frame_range_group->setLayout(frame_range_layout);
+
+ // Playback Options
+ auto* playback_group = new QGroupBox(tr("Playback Options"));
+ auto* playback_layout = new QGridLayout;
+ m_early_memory_updates = new QCheckBox(tr("Early Memory Updates"));
+
+ playback_layout->addWidget(object_range_group, 0, 0);
+ playback_layout->addWidget(frame_range_group, 0, 1);
+ playback_layout->addWidget(m_early_memory_updates, 1, 0, 1, -1);
+ playback_group->setLayout(playback_layout);
+
+ // Recording Options
+ auto* recording_group = new QGroupBox(tr("Recording Options"));
+ auto* recording_layout = new QHBoxLayout;
+ m_frame_record_count = new QSpinBox;
+ m_frame_record_count_label = new QLabel(tr("Frames to Record:"));
+
+ m_frame_record_count->setMinimum(1);
+ m_frame_record_count->setMaximum(3600);
+ m_frame_record_count->setValue(3);
+
+ recording_layout->addWidget(m_frame_record_count_label);
+ recording_layout->addWidget(m_frame_record_count);
+ recording_group->setLayout(recording_layout);
+
+ m_button_box = new QDialogButtonBox(QDialogButtonBox::Close);
+
+ // Action Buttons
+ m_load = m_button_box->addButton(tr("Load..."), QDialogButtonBox::ActionRole);
+ m_save = m_button_box->addButton(tr("Save..."), QDialogButtonBox::ActionRole);
+ m_record = m_button_box->addButton(tr("Record"), QDialogButtonBox::ActionRole);
+ m_stop = m_button_box->addButton(tr("Stop"), QDialogButtonBox::ActionRole);
+
+ layout->addWidget(info_group);
+ layout->addWidget(playback_group);
+ layout->addWidget(recording_group);
+ layout->addWidget(m_button_box);
+
+ setLayout(layout);
+}
+
+void FIFOPlayerWindow::ConnectWidgets()
+{
+ connect(m_load, &QPushButton::pressed, this, &FIFOPlayerWindow::LoadRecording);
+ connect(m_save, &QPushButton::pressed, this, &FIFOPlayerWindow::SaveRecording);
+ connect(m_record, &QPushButton::pressed, this, &FIFOPlayerWindow::StartRecording);
+ connect(m_stop, &QPushButton::pressed, this, &FIFOPlayerWindow::StopRecording);
+ connect(m_button_box, &QDialogButtonBox::rejected, this, &FIFOPlayerWindow::reject);
+ connect(m_early_memory_updates, &QCheckBox::toggled, this,
+ &FIFOPlayerWindow::OnEarlyMemoryUpdatesChanged);
+ connect(m_frame_range_from, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this,
+ &FIFOPlayerWindow::OnLimitsChanged);
+ connect(m_frame_range_to, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this,
+ &FIFOPlayerWindow::OnLimitsChanged);
+
+ connect(m_object_range_from, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this,
+ &FIFOPlayerWindow::OnLimitsChanged);
+ connect(m_object_range_to, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this,
+ &FIFOPlayerWindow::OnLimitsChanged);
+}
+
+void FIFOPlayerWindow::LoadRecording()
+{
+ QString path = QFileDialog::getOpenFileName(this, tr("Open FIFO log"), QString(),
+ tr("Dolphin FIFO Log (*.dff)"));
+
+ if (path.isEmpty())
+ return;
+
+ emit LoadFIFORequested(path);
+}
+
+void FIFOPlayerWindow::SaveRecording()
+{
+ QString path = QFileDialog::getSaveFileName(this, tr("Save FIFO log"), QString(),
+ tr("Dolphin FIFO Log (*.dff)"));
+
+ if (path.isEmpty())
+ return;
+
+ FifoDataFile* file = FifoRecorder::GetInstance().GetRecordedFile();
+
+ bool result = file->Save(path.toStdString());
+
+ if (!result)
+ QMessageBox::critical(this, tr("Error"), tr("Failed to save FIFO log."));
+}
+
+void FIFOPlayerWindow::StartRecording()
+{
+ // Start recording
+ FifoRecorder::GetInstance().StartRecording(m_frame_record_count->value(), [this] {
+ QueueOnObject(this, [this] { OnRecordingDone(); });
+ });
+
+ UpdateControls();
+
+ UpdateInfo();
+}
+
+void FIFOPlayerWindow::StopRecording()
+{
+ FifoRecorder::GetInstance().StopRecording();
+
+ UpdateControls();
+ UpdateInfo();
+}
+
+void FIFOPlayerWindow::OnEmulationStarted()
+{
+ UpdateControls();
+}
+
+void FIFOPlayerWindow::OnEmulationStopped()
+{
+ // If we have previously been recording, stop now.
+ if (FifoRecorder::GetInstance().IsRecording())
+ StopRecording();
+
+ UpdateControls();
+}
+
+void FIFOPlayerWindow::OnRecordingDone()
+{
+ UpdateInfo();
+ UpdateControls();
+}
+
+void FIFOPlayerWindow::UpdateInfo()
+{
+ if (FifoPlayer::GetInstance().IsPlaying())
+ {
+ FifoDataFile* file = FifoPlayer::GetInstance().GetFile();
+ m_info_label->setText(
+ tr("%1 frame(s)\n%2 object(s)\nCurrent Frame: %3")
+ .arg(QString::number(file->GetFrameCount()),
+ QString::number(FifoPlayer::GetInstance().GetFrameObjectCount()),
+ QString::number(FifoPlayer::GetInstance().GetCurrentFrameNum())));
+ return;
+ }
+
+ if (FifoRecorder::GetInstance().IsRecordingDone())
+ {
+ FifoDataFile* file = FifoRecorder::GetInstance().GetRecordedFile();
+ size_t fifo_bytes = 0;
+ size_t mem_bytes = 0;
+
+ for (u32 i = 0; i < file->GetFrameCount(); ++i)
+ {
+ fifo_bytes += file->GetFrame(i).fifoData.size();
+ for (const auto& mem_update : file->GetFrame(i).memoryUpdates)
+ mem_bytes += mem_update.data.size();
+ }
+
+ m_info_label->setText(tr("%1 FIFO bytes\n%2 memory bytes\n%3 frames")
+ .arg(QString::number(fifo_bytes), QString::number(mem_bytes),
+ QString::number(file->GetFrameCount())));
+ return;
+ }
+
+ if (Core::IsRunning() && FifoRecorder::GetInstance().IsRecording())
+ {
+ m_info_label->setText(tr("Recording..."));
+ return;
+ }
+
+ m_info_label->setText(tr("No file loaded / recorded."));
+}
+
+void FIFOPlayerWindow::OnFIFOLoaded()
+{
+ FifoDataFile* file = FifoPlayer::GetInstance().GetFile();
+
+ auto object_count = FifoPlayer::GetInstance().GetFrameObjectCount();
+ auto frame_count = file->GetFrameCount();
+
+ m_frame_range_to->setMaximum(frame_count);
+ m_object_range_to->setMaximum(object_count);
+
+ m_frame_range_to->setValue(frame_count);
+ m_object_range_to->setValue(object_count);
+
+ UpdateInfo();
+ UpdateLimits();
+ UpdateControls();
+}
+
+void FIFOPlayerWindow::OnEarlyMemoryUpdatesChanged(bool enabled)
+{
+ FifoPlayer::GetInstance().SetEarlyMemoryUpdates(enabled);
+}
+
+void FIFOPlayerWindow::OnLimitsChanged()
+{
+ FifoPlayer& player = FifoPlayer::GetInstance();
+
+ player.SetFrameRangeStart(m_frame_range_from->value());
+ player.SetFrameRangeEnd(m_frame_range_to->value());
+ player.SetObjectRangeStart(m_object_range_from->value());
+ player.SetObjectRangeEnd(m_object_range_to->value());
+ UpdateLimits();
+}
+
+void FIFOPlayerWindow::UpdateLimits()
+{
+ m_frame_range_from->setMaximum(std::max(m_frame_range_to->value() - 1, 0));
+ m_frame_range_to->setMinimum(m_frame_range_from->value() + 1);
+ m_object_range_from->setMaximum(std::max(m_object_range_to->value() - 1, 0));
+ m_object_range_to->setMinimum(m_object_range_from->value() + 1);
+}
+
+void FIFOPlayerWindow::UpdateControls()
+{
+ bool running = Core::IsRunning();
+ bool is_recording = FifoRecorder::GetInstance().IsRecording();
+ bool is_playing = FifoPlayer::GetInstance().IsPlaying();
+
+ m_frame_range_from->setEnabled(is_playing);
+ m_frame_range_from_label->setEnabled(is_playing);
+ m_frame_range_to->setEnabled(is_playing);
+ m_frame_range_to_label->setEnabled(is_playing);
+ m_object_range_from->setEnabled(is_playing);
+ m_object_range_from_label->setEnabled(is_playing);
+ m_object_range_to->setEnabled(is_playing);
+ m_object_range_to_label->setEnabled(is_playing);
+
+ m_early_memory_updates->setEnabled(is_playing);
+
+ bool enable_frame_record_count = !is_playing && !is_recording;
+
+ m_frame_record_count_label->setEnabled(enable_frame_record_count);
+ m_frame_record_count->setEnabled(enable_frame_record_count);
+
+ m_load->setEnabled(!running);
+ m_record->setEnabled(running && !is_playing);
+
+ m_stop->setVisible(running && is_recording);
+ m_record->setVisible(!m_stop->isVisible());
+
+ m_save->setEnabled(FifoRecorder::GetInstance().IsRecordingDone());
+}
diff --git a/Source/Core/DolphinQt2/FIFOPlayerWindow.h b/Source/Core/DolphinQt2/FIFOPlayerWindow.h
new file mode 100644
index 0000000000..4f422aa8f0
--- /dev/null
+++ b/Source/Core/DolphinQt2/FIFOPlayerWindow.h
@@ -0,0 +1,62 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <QDialog>
+
+class QCheckBox;
+class QDialogButtonBox;
+class QLabel;
+class QPushButton;
+class QSpinBox;
+
+class FIFOPlayerWindow : public QDialog
+{
+ Q_OBJECT
+public:
+ explicit FIFOPlayerWindow(QWidget* parent = nullptr);
+ ~FIFOPlayerWindow();
+
+signals:
+ void LoadFIFORequested(const QString& path);
+
+private:
+ void CreateWidgets();
+ void ConnectWidgets();
+
+ void LoadRecording();
+ void SaveRecording();
+ void StartRecording();
+ void StopRecording();
+
+ void OnEmulationStarted();
+ void OnEmulationStopped();
+ void OnLimitsChanged();
+ void OnEarlyMemoryUpdatesChanged(bool enabled);
+ void OnRecordingDone();
+ void OnFIFOLoaded();
+
+ void UpdateControls();
+ void UpdateInfo();
+ void UpdateLimits();
+
+ QLabel* m_info_label;
+ QPushButton* m_load;
+ QPushButton* m_save;
+ QPushButton* m_record;
+ QPushButton* m_stop;
+ QSpinBox* m_frame_range_from;
+ QLabel* m_frame_range_from_label;
+ QSpinBox* m_frame_range_to;
+ QLabel* m_frame_range_to_label;
+ QSpinBox* m_frame_record_count;
+ QLabel* m_frame_record_count_label;
+ QSpinBox* m_object_range_from;
+ QLabel* m_object_range_from_label;
+ QSpinBox* m_object_range_to;
+ QLabel* m_object_range_to_label;
+ QCheckBox* m_early_memory_updates;
+ QDialogButtonBox* m_button_box;
+};
diff --git a/Source/Core/DolphinQt2/MainWindow.cpp b/Source/Core/DolphinQt2/MainWindow.cpp
index 3c7d265aea..06a769554b 100644
--- a/Source/Core/DolphinQt2/MainWindow.cpp
+++ b/Source/Core/DolphinQt2/MainWindow.cpp
@@ -45,6 +45,7 @@
#include "DolphinQt2/Config/LogWidget.h"
#include "DolphinQt2/Config/Mapping/MappingWindow.h"
#include "DolphinQt2/Config/SettingsWindow.h"
+#include "DolphinQt2/FIFOPlayerWindow.h"
#include "DolphinQt2/Host.h"
#include "DolphinQt2/HotkeyScheduler.h"
#include "DolphinQt2/MainWindow.h"
@@ -155,9 +156,15 @@ void MainWindow::CreateComponents()
m_stack = new QStackedWidget(this);
m_controllers_window = new ControllersWindow(this);
m_settings_window = new SettingsWindow(this);
+
m_hotkey_window = new MappingWindow(this, MappingWindow::Type::MAPPING_HOTKEYS, 0);
+
m_log_widget = new LogWidget(this);
m_log_config_widget = new LogConfigWidget(this);
+ m_fifo_window = new FIFOPlayerWindow(this);
+
+ connect(m_fifo_window, &FIFOPlayerWindow::LoadFIFORequested, this,
+ static_cast<void (MainWindow::*)(const QString&)>(&MainWindow::StartGame));
#if defined(HAVE_XRANDR) && HAVE_XRANDR
m_graphics_window = new GraphicsWindow(
@@ -215,6 +222,7 @@ void MainWindow::ConnectMenuBar()
connect(m_menu_bar, &MenuBar::PerformOnlineUpdate, this, &MainWindow::PerformOnlineUpdate);
connect(m_menu_bar, &MenuBar::BootWiiSystemMenu, this, &MainWindow::BootWiiSystemMenu);
connect(m_menu_bar, &MenuBar::StartNetPlay, this, &MainWindow::ShowNetPlaySetupDialog);
+ connect(m_menu_bar, &MenuBar::ShowFIFOPlayer, this, &MainWindow::ShowFIFOPlayer);
// Movie
connect(m_menu_bar, &MenuBar::PlayRecording, this, &MainWindow::OnPlayRecording);
@@ -590,6 +598,13 @@ void MainWindow::ShowNetPlaySetupDialog()
m_netplay_setup_dialog->activateWindow();
}
+void MainWindow::ShowFIFOPlayer()
+{
+ m_fifo_window->show();
+ m_fifo_window->raise();
+ m_fifo_window->activateWindow();
+}
+
void MainWindow::StateLoad()
{
QString path = QFileDialog::getOpenFileName(this, tr("Select a File"), QDir::currentPath(),
diff --git a/Source/Core/DolphinQt2/MainWindow.h b/Source/Core/DolphinQt2/MainWindow.h
index d8db4fc01b..33288e9830 100644
--- a/Source/Core/DolphinQt2/MainWindow.h
+++ b/Source/Core/DolphinQt2/MainWindow.h
@@ -17,6 +17,7 @@
#include "DolphinQt2/ToolBar.h"
struct BootParameters;
+class FIFOPlayerWindow;
class HotkeyScheduler;
class LogConfigWidget;
class LogWidget;
@@ -98,6 +99,7 @@ private:
void ShowAboutDialog();
void ShowHotkeyDialog();
void ShowNetPlaySetupDialog();
+ void ShowFIFOPlayer();
void NetPlayInit();
bool NetPlayJoin();
@@ -137,4 +139,5 @@ private:
GraphicsWindow* m_graphics_window;
LogWidget* m_log_widget;
LogConfigWidget* m_log_config_widget;
+ FIFOPlayerWindow* m_fifo_window;
};
diff --git a/Source/Core/DolphinQt2/MenuBar.cpp b/Source/Core/DolphinQt2/MenuBar.cpp
index 98ad117a99..485e72190d 100644
--- a/Source/Core/DolphinQt2/MenuBar.cpp
+++ b/Source/Core/DolphinQt2/MenuBar.cpp
@@ -116,6 +116,8 @@ void MenuBar::AddToolsMenu()
AddAction(gc_ipl, tr("PAL"), this, [this] { emit BootGameCubeIPL(DiscIO::Region::PAL); });
AddAction(tools_menu, tr("Start &NetPlay..."), this, &MenuBar::StartNetPlay);
+ AddAction(tools_menu, tr("FIFO Player"), this, &MenuBar::ShowFIFOPlayer);
+
tools_menu->addSeparator();
// Label will be set by a NANDRefresh later
diff --git a/Source/Core/DolphinQt2/MenuBar.h b/Source/Core/DolphinQt2/MenuBar.h
index d9745e7e67..3bbb51345a 100644
--- a/Source/Core/DolphinQt2/MenuBar.h
+++ b/Source/Core/DolphinQt2/MenuBar.h
@@ -62,6 +62,8 @@ signals:
// Tools
void BootGameCubeIPL(DiscIO::Region region);
+ void ShowFIFOPlayer();
+ void ShowAboutDialog();
// Options
void Configure();
@@ -77,8 +79,6 @@ signals:
void GameListPlatformVisibilityToggled(const QString& row, bool visible);
void GameListRegionVisibilityToggled(const QString& row, bool visible);
- void ShowAboutDialog();
-
// Movie
void PlayRecording();
void StartRecording();