summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp20
-rw-r--r--src/core/hle/kernel/k_page_table.cpp4
-rw-r--r--src/core/hle/kernel/k_page_table.h2
-rw-r--r--src/core/hle/kernel/k_process.cpp2
-rw-r--r--src/core/hle/kernel/svc.cpp60
-rw-r--r--src/core/hle/service/ldr/ldr.cpp8
-rw-r--r--src/yuzu/bootmanager.cpp9
-rw-r--r--src/yuzu/bootmanager.h6
-rw-r--r--src/yuzu/main.cpp99
-rw-r--r--src/yuzu/main.h5
-rw-r--r--src/yuzu/main.ui90
11 files changed, 236 insertions, 69 deletions
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index 4e73cc03a..56836bd05 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -86,6 +86,26 @@ public:
num_instructions, MemoryReadCode(pc));
}
+ void InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op,
+ VAddr value) override {
+ switch (op) {
+ case Dynarmic::A64::InstructionCacheOperation::InvalidateByVAToPoU: {
+ static constexpr u64 ICACHE_LINE_SIZE = 64;
+
+ const u64 cache_line_start = value & ~(ICACHE_LINE_SIZE - 1);
+ parent.InvalidateCacheRange(cache_line_start, ICACHE_LINE_SIZE);
+ break;
+ }
+ case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoU:
+ parent.ClearInstructionCache();
+ break;
+ case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoUInnerSharable:
+ default:
+ LOG_DEBUG(Core_ARM, "Unprocesseed instruction cache operation: {}", op);
+ break;
+ }
+ }
+
void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override {
switch (exception) {
case Dynarmic::A64::Exception::WaitForInterrupt:
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp
index 526b87241..9bda5c5b2 100644
--- a/src/core/hle/kernel/k_page_table.cpp
+++ b/src/core/hle/kernel/k_page_table.cpp
@@ -685,8 +685,8 @@ ResultCode KPageTable::UnmapPages(VAddr addr, KPageLinkedList& page_linked_list,
return ResultSuccess;
}
-ResultCode KPageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size,
- KMemoryPermission perm) {
+ResultCode KPageTable::SetProcessMemoryPermission(VAddr addr, std::size_t size,
+ KMemoryPermission perm) {
std::lock_guard lock{page_table_lock};
diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h
index 770c4841c..b7ec38f06 100644
--- a/src/core/hle/kernel/k_page_table.h
+++ b/src/core/hle/kernel/k_page_table.h
@@ -41,7 +41,7 @@ public:
ResultCode MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state,
KMemoryPermission perm);
ResultCode UnmapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state);
- ResultCode SetCodeMemoryPermission(VAddr addr, std::size_t size, KMemoryPermission perm);
+ ResultCode SetProcessMemoryPermission(VAddr addr, std::size_t size, KMemoryPermission perm);
KMemoryInfo QueryInfo(VAddr addr);
ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm);
ResultCode ResetTransferMemory(VAddr addr, std::size_t size);
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index 76fd8c285..1aad061e1 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -528,7 +528,7 @@ void KProcess::LoadModule(CodeSet code_set, VAddr base_addr) {
std::lock_guard lock{HLE::g_hle_lock};
const auto ReprotectSegment = [&](const CodeSet::Segment& segment,
KMemoryPermission permission) {
- page_table->SetCodeMemoryPermission(segment.addr + base_addr, segment.size, permission);
+ page_table->SetProcessMemoryPermission(segment.addr + base_addr, segment.size, permission);
};
kernel.System().Memory().WriteBlock(*this, base_addr, code_set.memory.data(),
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index f9d99bc51..f0cd8471e 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1169,6 +1169,8 @@ static u32 GetCurrentProcessorNumber32(Core::System& system) {
return GetCurrentProcessorNumber(system);
}
+namespace {
+
constexpr bool IsValidSharedMemoryPermission(Svc::MemoryPermission perm) {
switch (perm) {
case Svc::MemoryPermission::Read:
@@ -1179,10 +1181,24 @@ constexpr bool IsValidSharedMemoryPermission(Svc::MemoryPermission perm) {
}
}
-constexpr bool IsValidRemoteSharedMemoryPermission(Svc::MemoryPermission perm) {
+[[maybe_unused]] constexpr bool IsValidRemoteSharedMemoryPermission(Svc::MemoryPermission perm) {
return IsValidSharedMemoryPermission(perm) || perm == Svc::MemoryPermission::DontCare;
}
+constexpr bool IsValidProcessMemoryPermission(Svc::MemoryPermission perm) {
+ switch (perm) {
+ case Svc::MemoryPermission::None:
+ case Svc::MemoryPermission::Read:
+ case Svc::MemoryPermission::ReadWrite:
+ case Svc::MemoryPermission::ReadExecute:
+ return true;
+ default:
+ return false;
+ }
+}
+
+} // Anonymous namespace
+
static ResultCode MapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address,
u64 size, Svc::MemoryPermission map_perm) {
LOG_TRACE(Kernel_SVC,
@@ -1262,6 +1278,34 @@ static ResultCode UnmapSharedMemory32(Core::System& system, Handle shmem_handle,
return UnmapSharedMemory(system, shmem_handle, address, size);
}
+static ResultCode SetProcessMemoryPermission(Core::System& system, Handle process_handle,
+ VAddr address, u64 size, Svc::MemoryPermission perm) {
+ LOG_TRACE(Kernel_SVC,
+ "called, process_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}",
+ process_handle, address, size, perm);
+
+ // Validate the address/size.
+ R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
+ R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
+ R_UNLESS(size > 0, ResultInvalidSize);
+ R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
+
+ // Validate the memory permission.
+ R_UNLESS(IsValidProcessMemoryPermission(perm), ResultInvalidNewMemoryPermission);
+
+ // Get the process from its handle.
+ KScopedAutoObject process =
+ system.CurrentProcess()->GetHandleTable().GetObject<KProcess>(process_handle);
+ R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
+
+ // Validate that the address is in range.
+ auto& page_table = process->PageTable();
+ R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
+
+ // Set the memory permission.
+ return page_table.SetProcessMemoryPermission(address, size, ConvertToKMemoryPermission(perm));
+}
+
static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address,
VAddr page_info_address, Handle process_handle,
VAddr address) {
@@ -1459,10 +1503,14 @@ static void ExitProcess32(Core::System& system) {
ExitProcess(system);
}
-static constexpr bool IsValidVirtualCoreId(int32_t core_id) {
+namespace {
+
+constexpr bool IsValidVirtualCoreId(int32_t core_id) {
return (0 <= core_id && core_id < static_cast<int32_t>(Core::Hardware::NUM_CPU_CORES));
}
+} // Anonymous namespace
+
/// Creates a new thread
static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr entry_point, u64 arg,
VAddr stack_bottom, u32 priority, s32 core_id) {
@@ -1846,7 +1894,9 @@ static ResultCode ResetSignal32(Core::System& system, Handle handle) {
return ResetSignal(system, handle);
}
-static constexpr bool IsValidTransferMemoryPermission(MemoryPermission perm) {
+namespace {
+
+constexpr bool IsValidTransferMemoryPermission(MemoryPermission perm) {
switch (perm) {
case MemoryPermission::None:
case MemoryPermission::Read:
@@ -1857,6 +1907,8 @@ static constexpr bool IsValidTransferMemoryPermission(MemoryPermission perm) {
}
}
+} // Anonymous namespace
+
/// Creates a TransferMemory object
static ResultCode CreateTransferMemory(Core::System& system, Handle* out, VAddr address, u64 size,
MemoryPermission map_perm) {
@@ -2588,7 +2640,7 @@ static const FunctionDef SVC_Table_64[] = {
{0x70, nullptr, "CreatePort"},
{0x71, nullptr, "ManageNamedPort"},
{0x72, nullptr, "ConnectToPort"},
- {0x73, nullptr, "SetProcessMemoryPermission"},
+ {0x73, SvcWrap64<SetProcessMemoryPermission>, "SetProcessMemoryPermission"},
{0x74, nullptr, "MapProcessMemory"},
{0x75, nullptr, "UnmapProcessMemory"},
{0x76, SvcWrap64<QueryProcessMemory>, "QueryProcessMemory"},
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp
index 32eff3b2a..3782703d2 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -396,12 +396,12 @@ public:
CopyCode(nro_addr + nro_header.segment_headers[DATA_INDEX].memory_offset, data_start,
nro_header.segment_headers[DATA_INDEX].memory_size);
- CASCADE_CODE(process->PageTable().SetCodeMemoryPermission(
+ CASCADE_CODE(process->PageTable().SetProcessMemoryPermission(
text_start, ro_start - text_start, Kernel::KMemoryPermission::ReadAndExecute));
- CASCADE_CODE(process->PageTable().SetCodeMemoryPermission(ro_start, data_start - ro_start,
- Kernel::KMemoryPermission::Read));
+ CASCADE_CODE(process->PageTable().SetProcessMemoryPermission(
+ ro_start, data_start - ro_start, Kernel::KMemoryPermission::Read));
- return process->PageTable().SetCodeMemoryPermission(
+ return process->PageTable().SetProcessMemoryPermission(
data_start, bss_end_addr - data_start, Kernel::KMemoryPermission::ReadAndWrite);
}
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index 822ba1a34..fd0a130a3 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -303,6 +303,7 @@ GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_,
connect(this, &GRenderWindow::ExecuteProgramSignal, parent, &GMainWindow::OnExecuteProgram,
Qt::QueuedConnection);
connect(this, &GRenderWindow::ExitSignal, parent, &GMainWindow::OnExit, Qt::QueuedConnection);
+ connect(this, &GRenderWindow::TasPlaybackStateChanged, parent, &GMainWindow::OnTasStateChanged);
}
void GRenderWindow::ExecuteProgram(std::size_t program_index) {
@@ -319,10 +320,18 @@ GRenderWindow::~GRenderWindow() {
void GRenderWindow::OnFrameDisplayed() {
input_subsystem->GetTas()->UpdateThread();
+ const TasInput::TasState new_tas_state = std::get<0>(input_subsystem->GetTas()->GetStatus());
+
if (!first_frame) {
+ last_tas_state = new_tas_state;
first_frame = true;
emit FirstFrameDisplayed();
}
+
+ if (new_tas_state != last_tas_state) {
+ last_tas_state = new_tas_state;
+ emit TasPlaybackStateChanged();
+ }
}
bool GRenderWindow::IsShown() const {
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h
index 40fd4a9d6..061e3605f 100644
--- a/src/yuzu/bootmanager.h
+++ b/src/yuzu/bootmanager.h
@@ -41,6 +41,10 @@ enum class LoadCallbackStage;
class RendererBase;
} // namespace VideoCore
+namespace TasInput {
+enum class TasState;
+}
+
class EmuThread final : public QThread {
Q_OBJECT
@@ -203,6 +207,7 @@ signals:
void ExecuteProgramSignal(std::size_t program_index);
void ExitSignal();
void MouseActivity();
+ void TasPlaybackStateChanged();
private:
void TouchBeginEvent(const QTouchEvent* event);
@@ -236,6 +241,7 @@ private:
QWidget* child_widget = nullptr;
bool first_frame = false;
+ TasInput::TasState last_tas_state;
std::array<std::size_t, 16> touch_ids{};
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index c4c76b094..5058c3e4e 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -965,6 +965,9 @@ void GMainWindow::InitializeHotkeys() {
const QString toggle_status_bar = QStringLiteral("Toggle Status Bar");
const QString fullscreen = QStringLiteral("Fullscreen");
const QString capture_screenshot = QStringLiteral("Capture Screenshot");
+ const QString tas_start_stop = QStringLiteral("TAS Start/Stop");
+ const QString tas_record = QStringLiteral("TAS Record");
+ const QString tas_reset = QStringLiteral("TAS Reset");
ui->action_Load_File->setShortcut(hotkey_registry.GetKeySequence(main_window, load_file));
ui->action_Load_File->setShortcutContext(
@@ -1005,6 +1008,18 @@ void GMainWindow::InitializeHotkeys() {
ui->action_Fullscreen->setShortcutContext(
hotkey_registry.GetShortcutContext(main_window, fullscreen));
+ ui->action_TAS_Start->setShortcut(hotkey_registry.GetKeySequence(main_window, tas_start_stop));
+ ui->action_TAS_Start->setShortcutContext(
+ hotkey_registry.GetShortcutContext(main_window, tas_start_stop));
+
+ ui->action_TAS_Record->setShortcut(hotkey_registry.GetKeySequence(main_window, tas_record));
+ ui->action_TAS_Record->setShortcutContext(
+ hotkey_registry.GetShortcutContext(main_window, tas_record));
+
+ ui->action_TAS_Reset->setShortcut(hotkey_registry.GetKeySequence(main_window, tas_reset));
+ ui->action_TAS_Reset->setShortcutContext(
+ hotkey_registry.GetShortcutContext(main_window, tas_reset));
+
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load File"), this),
&QShortcut::activated, this, &GMainWindow::OnMenuLoadFile);
connect(
@@ -1095,28 +1110,6 @@ void GMainWindow::InitializeHotkeys() {
render_window->setAttribute(Qt::WA_Hover, true);
}
});
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("TAS Start/Stop"), this),
- &QShortcut::activated, this, [&] {
- if (!emulation_running) {
- return;
- }
- input_subsystem->GetTas()->StartStop();
- });
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("TAS Reset"), this),
- &QShortcut::activated, this, [&] { input_subsystem->GetTas()->Reset(); });
- connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("TAS Record"), this),
- &QShortcut::activated, this, [&] {
- if (!emulation_running) {
- return;
- }
- bool is_recording = input_subsystem->GetTas()->Record();
- if (!is_recording) {
- const auto res = QMessageBox::question(this, tr("TAS Recording"),
- tr("Overwrite file of player 1?"),
- QMessageBox::Yes | QMessageBox::No);
- input_subsystem->GetTas()->SaveRecording(res == QMessageBox::Yes);
- }
- });
}
void GMainWindow::SetDefaultUIGeometry() {
@@ -1236,11 +1229,11 @@ void GMainWindow::ConnectMenuEvents() {
connect(ui->action_Restart, &QAction::triggered, this,
[this] { BootGame(QString(game_path)); });
connect(ui->action_Configure, &QAction::triggered, this, &GMainWindow::OnConfigure);
- connect(ui->action_Configure_Tas, &QAction::triggered, this, &GMainWindow::OnConfigureTas);
connect(ui->action_Configure_Current_Game, &QAction::triggered, this,
&GMainWindow::OnConfigurePerGame);
// View
+ connect(ui->action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen);
connect(ui->action_Single_Window_Mode, &QAction::triggered, this,
&GMainWindow::ToggleWindowMode);
connect(ui->action_Display_Dock_Widget_Headers, &QAction::triggered, this,
@@ -1258,17 +1251,20 @@ void GMainWindow::ConnectMenuEvents() {
ui->menu_Reset_Window_Size->addAction(ui->action_Reset_Window_Size_900);
ui->menu_Reset_Window_Size->addAction(ui->action_Reset_Window_Size_1080);
- // Fullscreen
- connect(ui->action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen);
-
- // Movie
+ // Tools
+ connect(ui->action_Rederive, &QAction::triggered, this,
+ std::bind(&GMainWindow::OnReinitializeKeys, this, ReinitializeKeyBehavior::Warning));
connect(ui->action_Capture_Screenshot, &QAction::triggered, this,
&GMainWindow::OnCaptureScreenshot);
+ // TAS
+ connect(ui->action_TAS_Start, &QAction::triggered, this, &GMainWindow::OnTasStartStop);
+ connect(ui->action_TAS_Record, &QAction::triggered, this, &GMainWindow::OnTasRecord);
+ connect(ui->action_TAS_Reset, &QAction::triggered, this, &GMainWindow::OnTasReset);
+ connect(ui->action_Configure_Tas, &QAction::triggered, this, &GMainWindow::OnConfigureTas);
+
// Help
connect(ui->action_Open_yuzu_Folder, &QAction::triggered, this, &GMainWindow::OnOpenYuzuFolder);
- connect(ui->action_Rederive, &QAction::triggered, this,
- std::bind(&GMainWindow::OnReinitializeKeys, this, ReinitializeKeyBehavior::Warning));
connect(ui->action_About, &QAction::triggered, this, &GMainWindow::OnAbout);
}
@@ -1582,6 +1578,7 @@ void GMainWindow::ShutdownGame() {
game_list->SetFilterFocus();
tas_label->clear();
input_subsystem->GetTas()->Stop();
+ OnTasStateChanged();
render_window->removeEventFilter(render_window);
render_window->setAttribute(Qt::WA_Hover, false);
@@ -2509,6 +2506,7 @@ void GMainWindow::OnStartGame() {
ui->action_Restart->setEnabled(true);
ui->action_Configure_Current_Game->setEnabled(true);
ui->action_Report_Compatibility->setEnabled(true);
+ OnTasStateChanged();
discord_rpc->Update();
ui->action_Load_Amiibo->setEnabled(true);
@@ -2821,6 +2819,32 @@ void GMainWindow::OnConfigureTas() {
}
}
+void GMainWindow::OnTasStartStop() {
+ if (!emulation_running) {
+ return;
+ }
+ input_subsystem->GetTas()->StartStop();
+ OnTasStateChanged();
+}
+
+void GMainWindow::OnTasRecord() {
+ if (!emulation_running) {
+ return;
+ }
+ const bool is_recording = input_subsystem->GetTas()->Record();
+ if (!is_recording) {
+ const auto res =
+ QMessageBox::question(this, tr("TAS Recording"), tr("Overwrite file of player 1?"),
+ QMessageBox::Yes | QMessageBox::No);
+ input_subsystem->GetTas()->SaveRecording(res == QMessageBox::Yes);
+ }
+ OnTasStateChanged();
+}
+
+void GMainWindow::OnTasReset() {
+ input_subsystem->GetTas()->Reset();
+}
+
void GMainWindow::OnConfigurePerGame() {
const u64 title_id = system->GetCurrentProcessProgramID();
OpenPerGameConfiguration(title_id, game_path.toStdString());
@@ -3014,6 +3038,23 @@ QString GMainWindow::GetTasStateDescription() const {
}
}
+void GMainWindow::OnTasStateChanged() {
+ bool is_running = false;
+ bool is_recording = false;
+ if (emulation_running) {
+ const TasInput::TasState tas_status = std::get<0>(input_subsystem->GetTas()->GetStatus());
+ is_running = tas_status == TasInput::TasState::Running;
+ is_recording = tas_status == TasInput::TasState::Recording;
+ }
+
+ ui->action_TAS_Start->setText(is_running ? tr("&Stop Running") : tr("&Start"));
+ ui->action_TAS_Record->setText(is_recording ? tr("Stop R&ecording") : tr("R&ecord"));
+
+ ui->action_TAS_Start->setEnabled(emulation_running);
+ ui->action_TAS_Record->setEnabled(emulation_running);
+ ui->action_TAS_Reset->setEnabled(emulation_running);
+}
+
void GMainWindow::UpdateStatusBar() {
if (emu_thread == nullptr) {
status_bar_update_timer.stop();
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 24633ff2d..556cbbaf7 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -177,6 +177,7 @@ public slots:
void WebBrowserOpenWebPage(const std::string& main_url, const std::string& additional_args,
bool is_local);
void OnAppFocusStateChanged(Qt::ApplicationState state);
+ void OnTasStateChanged();
private:
void RegisterMetaTypes();
@@ -268,6 +269,9 @@ private slots:
void OnMenuRecentFile();
void OnConfigure();
void OnConfigureTas();
+ void OnTasStartStop();
+ void OnTasRecord();
+ void OnTasReset();
void OnConfigurePerGame();
void OnLoadAmiibo();
void OnOpenYuzuFolder();
@@ -313,6 +317,7 @@ private:
void OpenURL(const QUrl& url);
void LoadTranslation();
void OpenPerGameConfiguration(u64 title_id, const std::string& file_name);
+
QString GetTasStateDescription() const;
std::unique_ptr<Ui::MainWindow> ui;
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui
index a62e39a06..c58aa2866 100644
--- a/src/yuzu/main.ui
+++ b/src/yuzu/main.ui
@@ -79,39 +79,39 @@
<string>&amp;View</string>
</property>
<widget class="QMenu" name="menu_Reset_Window_Size">
- <property name="title">
- <string>&amp;Reset Window Size</string>
- </property>
+ <property name="title">
+ <string>&amp;Reset Window Size</string>
+ </property>
+ </widget>
+ <widget class="QMenu" name="menu_View_Debugging">
+ <property name="title">
+ <string>&amp;Debugging</string>
+ </property>
</widget>
<action name="action_Reset_Window_Size_720">
- <property name="text">
- <string>Reset Window Size to &amp;720p</string>
- </property>
- <property name="iconText">
- <string>Reset Window Size to 720p</string>
- </property>
+ <property name="text">
+ <string>Reset Window Size to &amp;720p</string>
+ </property>
+ <property name="iconText">
+ <string>Reset Window Size to 720p</string>
+ </property>
</action>
<action name="action_Reset_Window_Size_900">
- <property name="text">
- <string>Reset Window Size to &amp;900p</string>
- </property>
- <property name="iconText">
- <string>Reset Window Size to 900p</string>
- </property>
+ <property name="text">
+ <string>Reset Window Size to &amp;900p</string>
+ </property>
+ <property name="iconText">
+ <string>Reset Window Size to 900p</string>
+ </property>
</action>
<action name="action_Reset_Window_Size_1080">
- <property name="text">
- <string>Reset Window Size to &amp;1080p</string>
- </property>
- <property name="iconText">
- <string>Reset Window Size to 1080p</string>
- </property>
- </action>
- <widget class="QMenu" name="menu_View_Debugging">
- <property name="title">
- <string>&amp;Debugging</string>
+ <property name="text">
+ <string>Reset Window Size to &amp;1080p</string>
</property>
- </widget>
+ <property name="iconText">
+ <string>Reset Window Size to 1080p</string>
+ </property>
+ </action>
<addaction name="action_Fullscreen"/>
<addaction name="action_Single_Window_Mode"/>
<addaction name="action_Display_Dock_Widget_Headers"/>
@@ -125,10 +125,20 @@
<property name="title">
<string>&amp;Tools</string>
</property>
+ <widget class="QMenu" name="menuTAS">
+ <property name="title">
+ <string>&amp;TAS</string>
+ </property>
+ <addaction name="action_TAS_Start"/>
+ <addaction name="action_TAS_Record"/>
+ <addaction name="action_TAS_Reset"/>
+ <addaction name="separator"/>
+ <addaction name="action_Configure_Tas"/>
+ </widget>
<addaction name="action_Rederive"/>
<addaction name="separator"/>
<addaction name="action_Capture_Screenshot"/>
- <addaction name="action_Configure_Tas"/>
+ <addaction name="menuTAS"/>
</widget>
<widget class="QMenu" name="menu_Help">
<property name="title">
@@ -309,7 +319,7 @@
</action>
<action name="action_Configure_Tas">
<property name="text">
- <string>Configure &amp;TAS...</string>
+ <string>&amp;Configure TAS...</string>
</property>
</action>
<action name="action_Configure_Current_Game">
@@ -320,6 +330,30 @@
<string>Configure C&amp;urrent Game...</string>
</property>
</action>
+ <action name="action_TAS_Start">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Start</string>
+ </property>
+ </action>
+ <action name="action_TAS_Reset">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Reset</string>
+ </property>
+ </action>
+ <action name="action_TAS_Record">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>R&amp;ecord</string>
+ </property>
+ </action>
</widget>
<resources>
<include location="yuzu.qrc"/>