summaryrefslogtreecommitdiff
path: root/src/yuzu
diff options
context:
space:
mode:
Diffstat (limited to 'src/yuzu')
-rw-r--r--src/yuzu/bootmanager.cpp52
-rw-r--r--src/yuzu/bootmanager.h8
-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.cpp45
-rw-r--r--src/yuzu/main.h1
7 files changed, 132 insertions, 41 deletions
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index bfeb16458..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();
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/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 ba69139e5..880a6a06e 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -534,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
@@ -667,6 +689,11 @@ void GMainWindow::InitializeHotkeys() {
ui.action_Capture_Screenshot->setShortcutContext(
hotkey_registry.GetShortcutContext(main_window, capture_screenshot));
+ ui.action_Fullscreen->setShortcut(
+ hotkey_registry.GetHotkey(main_window, fullscreen, this)->key());
+ ui.action_Fullscreen->setShortcutContext(
+ hotkey_registry.GetShortcutContext(main_window, fullscreen));
+
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load File"), this),
&QShortcut::activated, this, &GMainWindow::OnMenuLoadFile);
connect(
@@ -854,10 +881,6 @@ void GMainWindow::ConnectMenuEvents() {
connect(ui.action_Reset_Window_Size, &QAction::triggered, this, &GMainWindow::ResetWindowSize);
// Fullscreen
- ui.action_Fullscreen->setShortcut(
- hotkey_registry
- .GetHotkey(QStringLiteral("Main Window"), QStringLiteral("Fullscreen"), this)
- ->key());
connect(ui.action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen);
// Movie
@@ -925,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 =
@@ -1041,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) {
@@ -1128,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
@@ -1933,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);
@@ -2060,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 d55e55cc6..5581874ed 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -235,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;