summaryrefslogtreecommitdiff
path: root/src/yuzu
diff options
context:
space:
mode:
Diffstat (limited to 'src/yuzu')
-rw-r--r--src/yuzu/bootmanager.cpp54
-rw-r--r--src/yuzu/bootmanager.h8
-rw-r--r--src/yuzu/configuration/config.cpp3
-rw-r--r--src/yuzu/configuration/config.h2
-rw-r--r--src/yuzu/configuration/configure_general.cpp6
-rw-r--r--src/yuzu/configuration/configure_general.ui7
-rw-r--r--src/yuzu/debugger/wait_tree.cpp54
-rw-r--r--src/yuzu/main.cpp51
-rw-r--r--src/yuzu/main.h2
-rw-r--r--src/yuzu/main.ui6
10 files changed, 153 insertions, 40 deletions
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index 696da2137..4bfce48a4 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -44,49 +44,65 @@ EmuThread::EmuThread() = default;
EmuThread::~EmuThread() = default;
void EmuThread::run() {
- MicroProfileOnThreadCreate("EmuThread");
+ std::string name = "yuzu:EmuControlThread";
+ MicroProfileOnThreadCreate(name.c_str());
+ Common::SetCurrentThreadName(name.c_str());
+
+ auto& system = Core::System::GetInstance();
+
+ system.RegisterHostThread();
+
+ auto& gpu = system.GPU();
// Main process has been loaded. Make the context current to this thread and begin GPU and CPU
// execution.
- Core::System::GetInstance().GPU().Start();
+ gpu.Start();
+
+ gpu.ObtainContext();
emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
- Core::System::GetInstance().Renderer().Rasterizer().LoadDiskResources(
+ system.Renderer().Rasterizer().LoadDiskResources(
stop_run, [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) {
emit LoadProgress(stage, value, total);
});
emit LoadProgress(VideoCore::LoadCallbackStage::Complete, 0, 0);
+ gpu.ReleaseContext();
+
// Holds whether the cpu was running during the last iteration,
// so that the DebugModeLeft signal can be emitted before the
// next execution step
bool was_active = false;
while (!stop_run) {
if (running) {
- if (!was_active)
+ if (was_active) {
emit DebugModeLeft();
+ }
- Core::System::ResultStatus result = Core::System::GetInstance().RunLoop();
+ running_guard = true;
+ Core::System::ResultStatus result = system.Run();
if (result != Core::System::ResultStatus::Success) {
+ running_guard = false;
this->SetRunning(false);
- emit ErrorThrown(result, Core::System::GetInstance().GetStatusDetails());
+ emit ErrorThrown(result, system.GetStatusDetails());
}
+ running_wait.Wait();
+ result = system.Pause();
+ if (result != Core::System::ResultStatus::Success) {
+ running_guard = false;
+ this->SetRunning(false);
+ emit ErrorThrown(result, system.GetStatusDetails());
+ }
+ running_guard = false;
- was_active = running || exec_step;
- if (!was_active && !stop_run)
+ if (!stop_run) {
+ was_active = true;
emit DebugModeEntered();
+ }
} else if (exec_step) {
- if (!was_active)
- emit DebugModeLeft();
-
- exec_step = false;
- Core::System::GetInstance().SingleStep();
- emit DebugModeEntered();
- yieldCurrentThread();
-
- was_active = false;
+ UNIMPLEMENTED();
} else {
std::unique_lock lock{running_mutex};
running_cv.wait(lock, [this] { return IsRunning() || exec_step || stop_run; });
@@ -94,7 +110,7 @@ void EmuThread::run() {
}
// Shutdown the core emulation
- Core::System::GetInstance().Shutdown();
+ system.Shutdown();
#if MICROPROFILE_ENABLED
MicroProfileOnThreadExit();
@@ -360,7 +376,7 @@ QByteArray GRenderWindow::saveGeometry() {
}
qreal GRenderWindow::windowPixelRatio() const {
- return devicePixelRatio();
+ return devicePixelRatioF();
}
std::pair<u32, u32> GRenderWindow::ScaleTouch(const QPointF& pos) const {
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h
index 3626604ca..6c59b4d5c 100644
--- a/src/yuzu/bootmanager.h
+++ b/src/yuzu/bootmanager.h
@@ -59,6 +59,12 @@ public:
this->running = running;
lock.unlock();
running_cv.notify_all();
+ if (!running) {
+ running_wait.Set();
+ /// Wait until effectively paused
+ while (running_guard)
+ ;
+ }
}
/**
@@ -84,6 +90,8 @@ private:
std::atomic_bool stop_run{false};
std::mutex running_mutex;
std::condition_variable running_cv;
+ Common::Event running_wait{};
+ std::atomic_bool running_guard{false};
signals:
/**
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 32c81dc70..bbbd96113 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -211,7 +211,7 @@ const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> Config::default
// This must be in alphabetical order according to action name as it must have the same order as
// UISetting::values.shortcuts, which is alphabetically ordered.
// clang-format off
-const std::array<UISettings::Shortcut, 15> Config::default_hotkeys{{
+const std::array<UISettings::Shortcut, 16> Config::default_hotkeys{{
{QStringLiteral("Capture Screenshot"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+P"), Qt::ApplicationShortcut}},
{QStringLiteral("Change Docked Mode"), QStringLiteral("Main Window"), {QStringLiteral("F10"), Qt::ApplicationShortcut}},
{QStringLiteral("Continue/Pause Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F4"), Qt::WindowShortcut}},
@@ -222,6 +222,7 @@ const std::array<UISettings::Shortcut, 15> Config::default_hotkeys{{
{QStringLiteral("Increase Speed Limit"), QStringLiteral("Main Window"), {QStringLiteral("+"), Qt::ApplicationShortcut}},
{QStringLiteral("Load Amiibo"), QStringLiteral("Main Window"), {QStringLiteral("F2"), Qt::ApplicationShortcut}},
{QStringLiteral("Load File"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+O"), Qt::WindowShortcut}},
+ {QStringLiteral("Mute Audio"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+M"), Qt::WindowShortcut}},
{QStringLiteral("Restart Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F6"), Qt::WindowShortcut}},
{QStringLiteral("Stop Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F5"), Qt::WindowShortcut}},
{QStringLiteral("Toggle Filter Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F"), Qt::WindowShortcut}},
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index 5cd2a5feb..09316382c 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -27,7 +27,7 @@ public:
default_mouse_buttons;
static const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> default_keyboard_keys;
static const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> default_keyboard_mods;
- static const std::array<UISettings::Shortcut, 15> default_hotkeys;
+ static const std::array<UISettings::Shortcut, 16> default_hotkeys;
private:
void ReadValues();
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index cb95423e0..74b2ad537 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -23,6 +23,11 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
ConfigureGeneral::~ConfigureGeneral() = default;
void ConfigureGeneral::SetConfiguration() {
+ const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
+
+ ui->use_multi_core->setEnabled(runtime_lock);
+ ui->use_multi_core->setChecked(Settings::values.use_multi_core);
+
ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing);
ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot);
ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background);
@@ -41,6 +46,7 @@ void ConfigureGeneral::ApplyConfiguration() {
Settings::values.use_frame_limit = ui->toggle_frame_limit->isChecked();
Settings::values.frame_limit = ui->frame_limit->value();
+ Settings::values.use_multi_core = ui->use_multi_core->isChecked();
}
void ConfigureGeneral::changeEvent(QEvent* event) {
diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui
index fc3b7e65a..2711116a2 100644
--- a/src/yuzu/configuration/configure_general.ui
+++ b/src/yuzu/configuration/configure_general.ui
@@ -52,6 +52,13 @@
</layout>
</item>
<item>
+ <widget class="QCheckBox" name="use_multi_core">
+ <property name="text">
+ <string>Multicore CPU Emulation</string>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="QCheckBox" name="toggle_check_exit">
<property name="text">
<string>Confirm exit while emulation is running</string>
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp
index c1ea25fb8..9bb0a0109 100644
--- a/src/yuzu/debugger/wait_tree.cpp
+++ b/src/yuzu/debugger/wait_tree.cpp
@@ -2,10 +2,13 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <fmt/format.h>
+
#include "yuzu/debugger/wait_tree.h"
#include "yuzu/util/util.h"
#include "common/assert.h"
+#include "core/arm/arm_interface.h"
#include "core/core.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/mutex.h"
@@ -59,8 +62,10 @@ std::vector<std::unique_ptr<WaitTreeThread>> WaitTreeItem::MakeThreadItemList()
std::size_t row = 0;
auto add_threads = [&](const std::vector<std::shared_ptr<Kernel::Thread>>& threads) {
for (std::size_t i = 0; i < threads.size(); ++i) {
- item_list.push_back(std::make_unique<WaitTreeThread>(*threads[i]));
- item_list.back()->row = row;
+ if (!threads[i]->IsHLEThread()) {
+ item_list.push_back(std::make_unique<WaitTreeThread>(*threads[i]));
+ item_list.back()->row = row;
+ }
++row;
}
};
@@ -114,20 +119,21 @@ QString WaitTreeCallstack::GetText() const {
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() const {
std::vector<std::unique_ptr<WaitTreeItem>> list;
- constexpr std::size_t BaseRegister = 29;
- auto& memory = Core::System::GetInstance().Memory();
- u64 base_pointer = thread.GetContext64().cpu_registers[BaseRegister];
+ if (thread.IsHLEThread()) {
+ return list;
+ }
- while (base_pointer != 0) {
- const u64 lr = memory.Read64(base_pointer + sizeof(u64));
- if (lr == 0) {
- break;
- }
+ if (thread.GetOwnerProcess() == nullptr || !thread.GetOwnerProcess()->Is64BitProcess()) {
+ return list;
+ }
- list.push_back(std::make_unique<WaitTreeText>(
- tr("0x%1").arg(lr - sizeof(u32), 16, 16, QLatin1Char{'0'})));
+ auto backtrace = Core::ARM_Interface::GetBacktraceFromContext(Core::System::GetInstance(),
+ thread.GetContext64());
- base_pointer = memory.Read64(base_pointer);
+ for (auto& entry : backtrace) {
+ std::string s = fmt::format("{:20}{:016X} {:016X} {:016X} {}", entry.module, entry.address,
+ entry.original_address, entry.offset, entry.name);
+ list.push_back(std::make_unique<WaitTreeText>(QString::fromStdString(s)));
}
return list;
@@ -206,7 +212,15 @@ QString WaitTreeThread::GetText() const {
status = tr("running");
break;
case Kernel::ThreadStatus::Ready:
- status = tr("ready");
+ if (!thread.IsPaused()) {
+ if (thread.WasRunning()) {
+ status = tr("running");
+ } else {
+ status = tr("ready");
+ }
+ } else {
+ status = tr("paused");
+ }
break;
case Kernel::ThreadStatus::Paused:
status = tr("paused");
@@ -254,7 +268,15 @@ QColor WaitTreeThread::GetColor() const {
case Kernel::ThreadStatus::Running:
return QColor(Qt::GlobalColor::darkGreen);
case Kernel::ThreadStatus::Ready:
- return QColor(Qt::GlobalColor::darkBlue);
+ if (!thread.IsPaused()) {
+ if (thread.WasRunning()) {
+ return QColor(Qt::GlobalColor::darkGreen);
+ } else {
+ return QColor(Qt::GlobalColor::darkBlue);
+ }
+ } else {
+ return QColor(Qt::GlobalColor::lightGray);
+ }
case Kernel::ThreadStatus::Paused:
return QColor(Qt::GlobalColor::lightGray);
case Kernel::ThreadStatus::WaitHLEEvent:
@@ -319,7 +341,7 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
if (thread.GetStatus() == Kernel::ThreadStatus::WaitSynch) {
list.push_back(std::make_unique<WaitTreeObjectList>(thread.GetSynchronizationObjects(),
- thread.IsSleepingOnWait()));
+ thread.IsWaitingSync()));
}
list.push_back(std::make_unique<WaitTreeCallstack>(thread));
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 0820f8c7e..880a6a06e 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -56,6 +56,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#include <QShortcut>
#include <QStatusBar>
#include <QSysInfo>
+#include <QUrl>
#include <QtConcurrent/QtConcurrent>
#include <fmt/format.h>
@@ -533,14 +534,36 @@ void GMainWindow::InitializeWidgets() {
if (emulation_running) {
return;
}
- Settings::values.use_asynchronous_gpu_emulation =
- !Settings::values.use_asynchronous_gpu_emulation;
+ bool is_async =
+ !Settings::values.use_asynchronous_gpu_emulation || Settings::values.use_multi_core;
+ Settings::values.use_asynchronous_gpu_emulation = is_async;
async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation);
Settings::Apply();
});
async_status_button->setText(tr("ASYNC"));
async_status_button->setCheckable(true);
async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation);
+
+ // Setup Multicore button
+ multicore_status_button = new QPushButton();
+ multicore_status_button->setObjectName(QStringLiteral("TogglableStatusBarButton"));
+ multicore_status_button->setFocusPolicy(Qt::NoFocus);
+ connect(multicore_status_button, &QPushButton::clicked, [&] {
+ if (emulation_running) {
+ return;
+ }
+ Settings::values.use_multi_core = !Settings::values.use_multi_core;
+ bool is_async =
+ Settings::values.use_asynchronous_gpu_emulation || Settings::values.use_multi_core;
+ Settings::values.use_asynchronous_gpu_emulation = is_async;
+ async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation);
+ multicore_status_button->setChecked(Settings::values.use_multi_core);
+ Settings::Apply();
+ });
+ multicore_status_button->setText(tr("MULTICORE"));
+ multicore_status_button->setCheckable(true);
+ multicore_status_button->setChecked(Settings::values.use_multi_core);
+ statusBar()->insertPermanentWidget(0, multicore_status_button);
statusBar()->insertPermanentWidget(0, async_status_button);
// Setup Renderer API button
@@ -741,6 +764,9 @@ void GMainWindow::InitializeHotkeys() {
Settings::values.use_docked_mode);
dock_status_button->setChecked(Settings::values.use_docked_mode);
});
+ connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Mute Audio"), this),
+ &QShortcut::activated, this,
+ [] { Settings::values.audio_muted = !Settings::values.audio_muted; });
}
void GMainWindow::SetDefaultUIGeometry() {
@@ -841,6 +867,7 @@ void GMainWindow::ConnectMenuEvents() {
connect(ui.action_Stop, &QAction::triggered, this, &GMainWindow::OnStopGame);
connect(ui.action_Report_Compatibility, &QAction::triggered, this,
&GMainWindow::OnMenuReportCompatibility);
+ connect(ui.action_Open_Mods_Page, &QAction::triggered, this, &GMainWindow::OnOpenModsPage);
connect(ui.action_Restart, &QAction::triggered, this, [this] { BootGame(QString(game_path)); });
connect(ui.action_Configure, &QAction::triggered, this, &GMainWindow::OnConfigure);
@@ -921,6 +948,8 @@ bool GMainWindow::LoadROM(const QString& filename) {
nullptr, // E-Commerce
});
+ system.RegisterHostThread();
+
const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())};
const auto drd_callout =
@@ -1037,6 +1066,7 @@ void GMainWindow::BootGame(const QString& filename) {
}
status_bar_update_timer.start(2000);
async_status_button->setDisabled(true);
+ multicore_status_button->setDisabled(true);
renderer_status_button->setDisabled(true);
if (UISettings::values.hide_mouse) {
@@ -1124,6 +1154,7 @@ void GMainWindow::ShutdownGame() {
game_fps_label->setVisible(false);
emu_frametime_label->setVisible(false);
async_status_button->setEnabled(true);
+ multicore_status_button->setEnabled(true);
#ifdef HAS_VULKAN
renderer_status_button->setEnabled(true);
#endif
@@ -1808,6 +1839,16 @@ void GMainWindow::OnMenuReportCompatibility() {
}
}
+void GMainWindow::OnOpenModsPage() {
+ const auto mods_page_url = QStringLiteral("https://github.com/yuzu-emu/yuzu/wiki/Switch-Mods");
+ const QUrl mods_page(mods_page_url);
+ const bool open = QDesktopServices::openUrl(mods_page);
+ if (!open) {
+ QMessageBox::warning(this, tr("Error opening URL"),
+ tr("Unable to open the URL \"%1\".").arg(mods_page_url));
+ }
+}
+
void GMainWindow::ToggleFullscreen() {
if (!emulation_running) {
return;
@@ -1919,7 +1960,11 @@ void GMainWindow::OnConfigure() {
}
dock_status_button->setChecked(Settings::values.use_docked_mode);
+ multicore_status_button->setChecked(Settings::values.use_multi_core);
+ Settings::values.use_asynchronous_gpu_emulation =
+ Settings::values.use_asynchronous_gpu_emulation || Settings::values.use_multi_core;
async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation);
+
#ifdef HAS_VULKAN
renderer_status_button->setChecked(Settings::values.renderer_backend ==
Settings::RendererBackend::Vulkan);
@@ -2046,7 +2091,7 @@ void GMainWindow::UpdateStatusBar() {
game_fps_label->setText(tr("Game: %1 FPS").arg(results.game_fps, 0, 'f', 0));
emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2));
- emu_speed_label->setVisible(true);
+ emu_speed_label->setVisible(!Settings::values.use_multi_core);
game_fps_label->setVisible(true);
emu_frametime_label->setVisible(true);
}
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 4f4c8ddbe..5581874ed 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -181,6 +181,7 @@ private slots:
void OnPauseGame();
void OnStopGame();
void OnMenuReportCompatibility();
+ void OnOpenModsPage();
/// Called whenever a user selects a game in the game list widget.
void OnGameListLoadFile(QString game_path);
void OnGameListOpenFolder(GameListOpenTarget target, const std::string& game_path);
@@ -234,6 +235,7 @@ private:
QLabel* game_fps_label = nullptr;
QLabel* emu_frametime_label = nullptr;
QPushButton* async_status_button = nullptr;
+ QPushButton* multicore_status_button = nullptr;
QPushButton* renderer_status_button = nullptr;
QPushButton* dock_status_button = nullptr;
QTimer status_bar_update_timer;
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui
index 97c90f50b..b5745dfd5 100644
--- a/src/yuzu/main.ui
+++ b/src/yuzu/main.ui
@@ -113,6 +113,7 @@
<string>&amp;Help</string>
</property>
<addaction name="action_Report_Compatibility"/>
+ <addaction name="action_Open_Mods_Page"/>
<addaction name="separator"/>
<addaction name="action_About"/>
</widget>
@@ -256,6 +257,11 @@
<bool>false</bool>
</property>
</action>
+ <action name="action_Open_Mods_Page">
+ <property name="text">
+ <string>Open Mods Page</string>
+ </property>
+ </action>
<action name="action_Open_yuzu_Folder">
<property name="text">
<string>Open yuzu Folder</string>