From 9350c8cefb4148b507acfefdc44a6795b88df9a1 Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 19 Mar 2026 18:01:48 +0000 Subject: [PATCH 01/23] [dynarmic] exclude %rbp from regalloc Signed-off-by: lizzie --- src/dynarmic/src/dynarmic/backend/x64/reg_alloc.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.cpp b/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.cpp index 5c5ed25131..2cfa14ae18 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.cpp @@ -417,7 +417,8 @@ HostLoc RegAlloc::SelectARegister(std::bitset<32> desired_locations) const noexc // While R13 and R14 are technically available, we avoid allocating for them // at all costs, because theoretically skipping them is better than spilling // all over the place - i also fixes bugs with high reg pressure - } else if (i >= HostLoc::R13 && i <= HostLoc::R15) { + // %rbp must not be trashed, so skip it as well + } else if (i == HostLoc::RBP || (i >= HostLoc::R13 && i <= HostLoc::R15)) { // skip, do not touch // Intel recommends to reuse registers as soon as they're overwritable (DO NOT SPILL) } else if (loc_info.IsEmpty()) { From b8a46d1363892f80ed7a3221e9d3130f74d37325 Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 19 Mar 2026 18:05:07 +0000 Subject: [PATCH 02/23] fx --- src/dynarmic/src/dynarmic/backend/x64/abi.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/dynarmic/src/dynarmic/backend/x64/abi.cpp b/src/dynarmic/src/dynarmic/backend/x64/abi.cpp index 413af7b557..b7faaff911 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/abi.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/abi.cpp @@ -47,6 +47,8 @@ void ABI_PushRegistersAndAdjustStack(BlockOfCode& code, const size_t frame_size, const size_t num_xmms = (ABI_ALL_XMMS & regs).count(); const FrameInfo frame_info = CalculateFrameInfo(num_gprs, num_xmms, frame_size); + code.push(rbp); + code.mov(rbp, rsp); for (size_t i = 0; i < regs.size(); ++i) if (regs[i] && HostLocIsGPR(HostLoc(i))) code.push(HostLocToReg64(HostLoc(i))); @@ -87,6 +89,7 @@ void ABI_PopRegistersAndAdjustStack(BlockOfCode& code, const size_t frame_size, for (int32_t i = regs.size() - 1; i >= 0; --i) if (regs[i] && HostLocIsGPR(HostLoc(i))) code.pop(HostLocToReg64(HostLoc(i))); + code.pop(rbp); } void ABI_PushCalleeSaveRegistersAndAdjustStack(BlockOfCode& code, const std::size_t frame_size) { From f262eb57ff76e51b849ee81499b2d9145d309e95 Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 19 Mar 2026 22:01:23 +0000 Subject: [PATCH 03/23] ok fix for winshit --- src/dynarmic/src/dynarmic/backend/x64/abi.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dynarmic/src/dynarmic/backend/x64/abi.cpp b/src/dynarmic/src/dynarmic/backend/x64/abi.cpp index b7faaff911..e3e54989a5 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/abi.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/abi.cpp @@ -43,7 +43,7 @@ static FrameInfo CalculateFrameInfo(const size_t num_gprs, const size_t num_xmms void ABI_PushRegistersAndAdjustStack(BlockOfCode& code, const size_t frame_size, std::bitset<32> const& regs) { using namespace Xbyak::util; - const size_t num_gprs = (ABI_ALL_GPRS & regs).count(); + const size_t num_gprs = (ABI_ALL_GPRS & regs).count() + 1; const size_t num_xmms = (ABI_ALL_XMMS & regs).count(); const FrameInfo frame_info = CalculateFrameInfo(num_gprs, num_xmms, frame_size); @@ -70,7 +70,7 @@ void ABI_PushRegistersAndAdjustStack(BlockOfCode& code, const size_t frame_size, void ABI_PopRegistersAndAdjustStack(BlockOfCode& code, const size_t frame_size, std::bitset<32> const& regs) { using namespace Xbyak::util; - const size_t num_gprs = (ABI_ALL_GPRS & regs).count(); + const size_t num_gprs = (ABI_ALL_GPRS & regs).count() + 1; const size_t num_xmms = (ABI_ALL_XMMS & regs).count(); const FrameInfo frame_info = CalculateFrameInfo(num_gprs, num_xmms, frame_size); From 7ec24e3b1acd6e4879850020a5c38377803b49c8 Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 19 Mar 2026 22:27:47 +0000 Subject: [PATCH 04/23] pot fix --- .../src/dynarmic/backend/x64/a64_emit_x64.cpp | 7 ++++++ src/dynarmic/src/dynarmic/backend/x64/abi.cpp | 7 ++---- .../backend/x64/exception_handler_windows.cpp | 24 +++++++++---------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp index ff82d8b05c..eab6fc038a 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp @@ -90,6 +90,10 @@ A64EmitX64::BlockDescriptor A64EmitX64::Emit(IR::Block& block) noexcept { code.align(); const auto* const entrypoint = code.getCurr(); + code.push(rbp); + code.mov(rbp, rsp); + code.and_(rsp, -16); + DEBUG_ASSERT(block.GetCondition() == IR::Cond::AL); typedef void (EmitX64::*EmitHandlerFn)(EmitContext& context, IR::Inst* inst); constexpr EmitHandlerFn opcode_handlers[] = { @@ -248,6 +252,9 @@ void A64EmitX64::GenTerminalHandlers() { } code.and_(code.ABI_PARAM1.cvt32(), fast_dispatch_table_mask); code.lea(code.ABI_RETURN, code.ptr[code.ABI_PARAM2 + code.ABI_PARAM1]); + + code.mov(rsp, rbp); + code.pop(rbp); code.ret(); PerfMapRegister(fast_dispatch_table_lookup, code.getCurr(), "a64_fast_dispatch_table_lookup"); } diff --git a/src/dynarmic/src/dynarmic/backend/x64/abi.cpp b/src/dynarmic/src/dynarmic/backend/x64/abi.cpp index e3e54989a5..413af7b557 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/abi.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/abi.cpp @@ -43,12 +43,10 @@ static FrameInfo CalculateFrameInfo(const size_t num_gprs, const size_t num_xmms void ABI_PushRegistersAndAdjustStack(BlockOfCode& code, const size_t frame_size, std::bitset<32> const& regs) { using namespace Xbyak::util; - const size_t num_gprs = (ABI_ALL_GPRS & regs).count() + 1; + const size_t num_gprs = (ABI_ALL_GPRS & regs).count(); const size_t num_xmms = (ABI_ALL_XMMS & regs).count(); const FrameInfo frame_info = CalculateFrameInfo(num_gprs, num_xmms, frame_size); - code.push(rbp); - code.mov(rbp, rsp); for (size_t i = 0; i < regs.size(); ++i) if (regs[i] && HostLocIsGPR(HostLoc(i))) code.push(HostLocToReg64(HostLoc(i))); @@ -70,7 +68,7 @@ void ABI_PushRegistersAndAdjustStack(BlockOfCode& code, const size_t frame_size, void ABI_PopRegistersAndAdjustStack(BlockOfCode& code, const size_t frame_size, std::bitset<32> const& regs) { using namespace Xbyak::util; - const size_t num_gprs = (ABI_ALL_GPRS & regs).count() + 1; + const size_t num_gprs = (ABI_ALL_GPRS & regs).count(); const size_t num_xmms = (ABI_ALL_XMMS & regs).count(); const FrameInfo frame_info = CalculateFrameInfo(num_gprs, num_xmms, frame_size); @@ -89,7 +87,6 @@ void ABI_PopRegistersAndAdjustStack(BlockOfCode& code, const size_t frame_size, for (int32_t i = regs.size() - 1; i >= 0; --i) if (regs[i] && HostLocIsGPR(HostLoc(i))) code.pop(HostLocToReg64(HostLoc(i))); - code.pop(rbp); } void ABI_PushCalleeSaveRegistersAndAdjustStack(BlockOfCode& code, const std::size_t frame_size) { diff --git a/src/dynarmic/src/dynarmic/backend/x64/exception_handler_windows.cpp b/src/dynarmic/src/dynarmic/backend/x64/exception_handler_windows.cpp index 3ae553bccd..bae397ff2b 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/exception_handler_windows.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/exception_handler_windows.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -176,7 +176,7 @@ struct ExceptionHandler::Impl final { code.align(16); const u8* exception_handler_without_cb = code.getCurr(); - code.mov(code.eax, static_cast(ExceptionContinueSearch)); + code.mov(code.eax, u32(ExceptionContinueSearch)); code.ret(); code.align(16); @@ -192,20 +192,18 @@ struct ExceptionHandler::Impl final { code.lea(code.rsp, code.ptr[code.rsp - 8]); code.mov(code.ABI_PARAM1, std::bit_cast(&cb)); code.mov(code.ABI_PARAM2, code.ABI_PARAM3); - code.CallLambda( - [](const std::function& cb_, PCONTEXT ctx) { - FakeCall fc = cb_(ctx->Rip); - - ctx->Rsp -= sizeof(u64); - *std::bit_cast(ctx->Rsp) = fc.ret_rip; - ctx->Rip = fc.call_rip; - }); + code.CallLambda([](const std::function& cb_, PCONTEXT ctx) { + FakeCall fc = cb_(ctx->Rip); + ctx->Rsp -= sizeof(u64); + *std::bit_cast(ctx->Rsp) = fc.ret_rip; + ctx->Rip = fc.call_rip; + }); code.add(code.rsp, 8); - code.mov(code.eax, static_cast(ExceptionContinueExecution)); + code.mov(code.eax, u32(ExceptionContinueExecution)); code.ret(); - exception_handler_without_cb_offset = static_cast(exception_handler_without_cb - code.getCode()); - exception_handler_with_cb_offset = static_cast(exception_handler_with_cb - code.getCode()); + exception_handler_without_cb_offset = ULONG(exception_handler_without_cb - code.getCode()); + exception_handler_with_cb_offset = ULONG(exception_handler_with_cb - code.getCode()); code.align(16); UNWIND_INFO* unwind_info = static_cast(code.AllocateFromCodeSpace(sizeof(UNWIND_INFO))); From 88a2d2cecb734bea8d41365b7138eaf674506135 Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 19 Mar 2026 22:50:39 +0000 Subject: [PATCH 05/23] tes1 --- .../src/dynarmic/backend/x64/a64_emit_x64.cpp | 11 +++++------ src/dynarmic/src/dynarmic/backend/x64/stack_layout.h | 4 +--- src/video_core/host_shaders/CMakeLists.txt | 6 +++--- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp index eab6fc038a..d4f9d9daaf 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp @@ -90,9 +90,8 @@ A64EmitX64::BlockDescriptor A64EmitX64::Emit(IR::Block& block) noexcept { code.align(); const auto* const entrypoint = code.getCurr(); - code.push(rbp); - code.mov(rbp, rsp); - code.and_(rsp, -16); + // code.mov(code.qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer)], rbp); + // code.lea(rbp, code.ptr[rsp + ABI_SHADOW_SPACE - 8]); DEBUG_ASSERT(block.GetCondition() == IR::Cond::AL); typedef void (EmitX64::*EmitHandlerFn)(EmitContext& context, IR::Inst* inst); @@ -148,6 +147,9 @@ finish_this_inst: if (conf.enable_cycle_counting) { EmitAddCycles(block.CycleCount()); } + + //code.mov(rbp, code.qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer)]); + EmitTerminal(block.GetTerminal(), ctx.Location().SetSingleStepping(false), ctx.IsSingleStep()); code.int3(); @@ -252,9 +254,6 @@ void A64EmitX64::GenTerminalHandlers() { } code.and_(code.ABI_PARAM1.cvt32(), fast_dispatch_table_mask); code.lea(code.ABI_RETURN, code.ptr[code.ABI_PARAM2 + code.ABI_PARAM1]); - - code.mov(rsp, rbp); - code.pop(rbp); code.ret(); PerfMapRegister(fast_dispatch_table_lookup, code.getCurr(), "a64_fast_dispatch_table_lookup"); } diff --git a/src/dynarmic/src/dynarmic/backend/x64/stack_layout.h b/src/dynarmic/src/dynarmic/backend/x64/stack_layout.h index 50737f12eb..13f3de21a1 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/stack_layout.h +++ b/src/dynarmic/src/dynarmic/backend/x64/stack_layout.h @@ -22,13 +22,11 @@ constexpr size_t SpillCount = 64; #endif struct alignas(16) StackLayout { + u64 abi_base_pointer; s64 cycles_remaining; s64 cycles_to_run; - std::array, SpillCount> spill; - u32 save_host_MXCSR; - bool check_bit; }; diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt index 668f939546..55084f0ff8 100644 --- a/src/video_core/host_shaders/CMakeLists.txt +++ b/src/video_core/host_shaders/CMakeLists.txt @@ -135,7 +135,7 @@ foreach(SOURCE_FILE IN ITEMS ${SHADER_FILES}) ${SOURCE_FILE} DEPENDS ${INPUT_FILE} - ${SHADER_DIR} + # ${SHADER_DIR} # HEADER_GENERATOR should be included here but msbuild seems to assume it's always modified ) set(SHADER_HEADERS ${SHADER_HEADERS} ${SOURCE_HEADER_FILE}) @@ -151,8 +151,8 @@ foreach(SOURCE_FILE IN ITEMS ${SHADER_FILES}) ${GLSLANGVALIDATOR} -V ${QUIET_FLAG} -I"${FIDELITYFX_INCLUDE_DIR}" ${GLSL_FLAGS} --variable-name ${SPIRV_VARIABLE_NAME} -o ${SPIRV_HEADER_FILE} ${SOURCE_FILE} --target-env ${SPIR_V_VERSION} MAIN_DEPENDENCY ${SOURCE_FILE} - DEPENDS - ${SHADER_DIR} + #DEPENDS + # ${SHADER_DIR} ) set(SHADER_HEADERS ${SHADER_HEADERS} ${SPIRV_HEADER_FILE}) endif() From 5368a54ed8131486d82f2f818d129873ddb0d278 Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 19 Mar 2026 23:01:27 +0000 Subject: [PATCH 06/23] fix %rbp --- .../src/dynarmic/backend/x64/a32_emit_x64.cpp | 9 +++++---- .../src/dynarmic/backend/x64/a64_emit_x64.cpp | 17 +++++------------ .../src/dynarmic/backend/x64/stack_layout.h | 5 +++-- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp b/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp index f037919eb0..cd89b89156 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp @@ -115,6 +115,8 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) { // Start emitting. code.align(); const u8* const entrypoint = code.getCurr(); + code.mov(code.qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer)], rbp); + code.lea(rbp, code.ptr[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer) - 8]); EmitCondPrelude(ctx); @@ -147,15 +149,14 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) { reg_alloc.AssertNoMoreUses(); - if (conf.enable_cycle_counting) { + if (conf.enable_cycle_counting) EmitAddCycles(block.CycleCount()); - } + code.mov(rbp, code.qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer)]); EmitTerminal(block.GetTerminal(), ctx.Location().SetSingleStepping(false), ctx.IsSingleStep()); code.int3(); - for (auto& deferred_emit : ctx.deferred_emits) { + for (auto& deferred_emit : ctx.deferred_emits) deferred_emit(); - } code.int3(); const size_t size = size_t(code.getCurr() - entrypoint); diff --git a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp index d4f9d9daaf..f59026929e 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp @@ -89,9 +89,8 @@ A64EmitX64::BlockDescriptor A64EmitX64::Emit(IR::Block& block) noexcept { // Start emitting. code.align(); const auto* const entrypoint = code.getCurr(); - - // code.mov(code.qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer)], rbp); - // code.lea(rbp, code.ptr[rsp + ABI_SHADOW_SPACE - 8]); + code.mov(code.qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer)], rbp); + code.lea(rbp, code.ptr[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer) - 8]); DEBUG_ASSERT(block.GetCondition() == IR::Cond::AL); typedef void (EmitX64::*EmitHandlerFn)(EmitContext& context, IR::Inst* inst); @@ -143,19 +142,13 @@ finish_this_inst: } reg_alloc.AssertNoMoreUses(); - - if (conf.enable_cycle_counting) { + if (conf.enable_cycle_counting) EmitAddCycles(block.CycleCount()); - } - - //code.mov(rbp, code.qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer)]); - + code.mov(rbp, code.qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer)]); EmitTerminal(block.GetTerminal(), ctx.Location().SetSingleStepping(false), ctx.IsSingleStep()); code.int3(); - - for (auto& deferred_emit : ctx.deferred_emits) { + for (auto& deferred_emit : ctx.deferred_emits) deferred_emit(); - } code.int3(); const size_t size = size_t(code.getCurr() - entrypoint); diff --git a/src/dynarmic/src/dynarmic/backend/x64/stack_layout.h b/src/dynarmic/src/dynarmic/backend/x64/stack_layout.h index 13f3de21a1..6e0efb5be0 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/stack_layout.h +++ b/src/dynarmic/src/dynarmic/backend/x64/stack_layout.h @@ -22,12 +22,13 @@ constexpr size_t SpillCount = 64; #endif struct alignas(16) StackLayout { - u64 abi_base_pointer; + // Needs alignment for VMOV and XMM spills + alignas(16) std::array, SpillCount> spill; s64 cycles_remaining; s64 cycles_to_run; - std::array, SpillCount> spill; u32 save_host_MXCSR; bool check_bit; + u64 abi_base_pointer; }; #ifdef _MSC_VER From 4707d8a26a077fd7cbb7012fa251fe8a33a983fb Mon Sep 17 00:00:00 2001 From: lizzie Date: Fri, 20 Mar 2026 07:22:23 +0000 Subject: [PATCH 07/23] license --- src/dynarmic/src/dynarmic/backend/x64/stack_layout.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dynarmic/src/dynarmic/backend/x64/stack_layout.h b/src/dynarmic/src/dynarmic/backend/x64/stack_layout.h index 6e0efb5be0..43a3fc7ab2 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/stack_layout.h +++ b/src/dynarmic/src/dynarmic/backend/x64/stack_layout.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. From 96e177702e0bc7d689df52c544bb26819e704c4c Mon Sep 17 00:00:00 2001 From: lizzie Date: Fri, 20 Mar 2026 22:09:14 +0100 Subject: [PATCH 08/23] [qt_common] remove 109kb worth of duplicate shortcut data (#3756) - repeated 32 times - is like 3432 - 32 * 3432 = 109824 = 109kb - now it's just 3.4kb Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3756 Reviewed-by: MaranBr Reviewed-by: CamilleLaVey Co-authored-by: lizzie Co-committed-by: lizzie --- src/qt_common/config/uisettings.cpp | 44 ++++++++++++++++++++++++++++- src/qt_common/config/uisettings.h | 43 ++-------------------------- 2 files changed, 45 insertions(+), 42 deletions(-) diff --git a/src/qt_common/config/uisettings.cpp b/src/qt_common/config/uisettings.cpp index 0b668c4bb1..f4f5688781 100644 --- a/src/qt_common/config/uisettings.cpp +++ b/src/qt_common/config/uisettings.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: 2016 Citra Emulator Project @@ -25,6 +25,48 @@ namespace FS = Common::FS; namespace UISettings { +// This shouldn't have anything except static initializers (no functions). So +// QKeySequence(...).toString() is NOT ALLOWED HERE. +// 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 default_hotkeys{{ + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+M"), std::string("Home+Dpad_Right"), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("-"), std::string("Home+Dpad_Down"), Qt::ApplicationShortcut, true}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("="), std::string("Home+Dpad_Up"), Qt::ApplicationShortcut, true}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Capture Screenshot")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+P"), std::string("Screenshot"), Qt::WidgetWithChildrenShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Adapting Filter")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F8"), std::string("Home+L"), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Docked Mode")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F10"), std::string("Home+X"), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change GPU Mode")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F9"), std::string("Home+R"), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Configure")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+,"), std::string(""), Qt::WidgetWithChildrenShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Configure Current Game")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+."), std::string(""), Qt::WidgetWithChildrenShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Continue/Pause Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F4"), std::string("Home+Plus"), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Esc"), std::string(""), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit Eden")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+Q"), std::string("Home+Minus"), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F11"), std::string("Home+B"), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+O"), std::string(""), Qt::WidgetWithChildrenShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F2"), std::string("Home+A"), Qt::WidgetWithChildrenShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Browse Public Game Lobby")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+B"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Create Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+N"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Direct Connect to Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+C"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Leave Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+L"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Show Current Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+R"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F6"), std::string("R+Plus+Minus"), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F5"), std::string("L+Plus+Minus"), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Record")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F7"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Reset")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F6"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Start/Stop")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F5"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Filter Bar")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F"), std::string(""), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Framerate Limit")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+U"), std::string("Home+Y"), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Turbo Speed")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+Z"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Slow Speed")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+X"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Mouse Panning")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F9"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Renderdoc Capture")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string(""), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Status Bar")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+S"), std::string(""), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Performance Overlay")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+V"), std::string(""), Qt::WindowShortcut, false}}, +}}; +// clang-format on + const Themes themes{{ {"Default", "default"}, {"Default Colorful", "colorful"}, diff --git a/src/qt_common/config/uisettings.h b/src/qt_common/config/uisettings.h index c2a14858dd..4549a36345 100644 --- a/src/qt_common/config/uisettings.h +++ b/src/qt_common/config/uisettings.h @@ -249,47 +249,8 @@ u32 CalculateWidth(u32 height, Settings::AspectRatio ratio); void SaveWindowState(); void RestoreWindowState(std::unique_ptr& qtConfig); -// This shouldn't have anything except static initializers (no functions). So -// QKeySequence(...).toString() is NOT ALLOWED HERE. -// 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 default_hotkeys{{ - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+M"), std::string("Home+Dpad_Right"), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("-"), std::string("Home+Dpad_Down"), Qt::ApplicationShortcut, true}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("="), std::string("Home+Dpad_Up"), Qt::ApplicationShortcut, true}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Capture Screenshot")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+P"), std::string("Screenshot"), Qt::WidgetWithChildrenShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Adapting Filter")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F8"), std::string("Home+L"), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Docked Mode")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F10"), std::string("Home+X"), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change GPU Mode")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F9"), std::string("Home+R"), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Configure")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+,"), std::string(""), Qt::WidgetWithChildrenShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Configure Current Game")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+."), std::string(""), Qt::WidgetWithChildrenShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Continue/Pause Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F4"), std::string("Home+Plus"), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Esc"), std::string(""), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit Eden")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+Q"), std::string("Home+Minus"), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F11"), std::string("Home+B"), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+O"), std::string(""), Qt::WidgetWithChildrenShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F2"), std::string("Home+A"), Qt::WidgetWithChildrenShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Browse Public Game Lobby")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+B"), std::string(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Create Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+N"), std::string(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Direct Connect to Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+C"), std::string(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Leave Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+L"), std::string(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Show Current Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+R"), std::string(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F6"), std::string("R+Plus+Minus"), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F5"), std::string("L+Plus+Minus"), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Record")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F7"), std::string(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Reset")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F6"), std::string(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Start/Stop")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F5"), std::string(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Filter Bar")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F"), std::string(""), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Framerate Limit")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+U"), std::string("Home+Y"), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Turbo Speed")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+Z"), std::string(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Slow Speed")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+X"), std::string(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Mouse Panning")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F9"), std::string(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Renderdoc Capture")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string(""), std::string(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Status Bar")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+S"), std::string(""), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Performance Overlay")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+V"), std::string(""), Qt::WindowShortcut, false}}, -}}; -// clang-format on +// sync with uisettings.cpp +extern const std::array default_hotkeys; } // namespace UISettings From 5ebdb29afd4d74887f58af139e6f9444ca69c4a3 Mon Sep 17 00:00:00 2001 From: xbzk Date: Sun, 22 Mar 2026 02:06:45 +0100 Subject: [PATCH 09/23] [android,ui] feat fullscreen app setting (#3676) why not? i like it a lot on both phone and TV. toggle in app settings. disabled by default so no hassle. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3676 Reviewed-by: MaranBr Reviewed-by: CamilleLaVey Co-authored-by: xbzk Co-committed-by: xbzk --- .../org/yuzu/yuzu_emu/dialogs/ChatDialog.kt | 23 +++++++- .../org/yuzu/yuzu_emu/dialogs/LobbyBrowser.kt | 17 ++++++ .../yuzu/yuzu_emu/dialogs/NetPlayDialog.kt | 27 +++++++++- .../features/settings/model/Settings.kt | 2 + .../features/settings/ui/SettingsActivity.kt | 17 ++++++ .../settings/ui/SettingsFragmentPresenter.kt | 35 +++++++++++++ .../settings/ui/SettingsSubscreenActivity.kt | 18 +++++++ .../fragments/ProfileManagerFragment.kt | 20 +++++-- .../org/yuzu/yuzu_emu/ui/main/MainActivity.kt | 13 +++++ .../yuzu/yuzu_emu/utils/FullscreenHelper.kt | 52 +++++++++++++++++++ .../res/layout/fragment_profile_manager.xml | 7 +-- .../app/src/main/res/values/strings.xml | 2 + 12 files changed, 223 insertions(+), 10 deletions(-) create mode 100644 src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FullscreenHelper.kt diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/ChatDialog.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/ChatDialog.kt index 5d6679bd28..431125ca8e 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/ChatDialog.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/ChatDialog.kt @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later package org.yuzu.yuzu_emu.dialogs @@ -20,6 +20,8 @@ import org.yuzu.yuzu_emu.databinding.DialogChatBinding import org.yuzu.yuzu_emu.databinding.ItemChatMessageBinding import org.yuzu.yuzu_emu.features.settings.model.StringSetting import org.yuzu.yuzu_emu.network.NetPlayManager +import org.yuzu.yuzu_emu.utils.CompatUtils +import org.yuzu.yuzu_emu.utils.FullscreenHelper import java.text.SimpleDateFormat import java.util.* @@ -34,6 +36,13 @@ class ChatDialog(context: Context) : BottomSheetDialog(context) { private lateinit var binding: DialogChatBinding private lateinit var chatAdapter: ChatAdapter private val handler = Handler(Looper.getMainLooper()) + private val hideSystemBars: Boolean by lazy { + runCatching { + FullscreenHelper.shouldHideSystemBars(CompatUtils.findActivity(context)) + }.getOrElse { + FullscreenHelper.isFullscreenEnabled(context) + } + } // TODO(alekpop, crueter): Top drawer for message notifications, perhaps use system notifs? // TODO(alekpop, crueter): Context menu actions for chat users @@ -41,6 +50,7 @@ class ChatDialog(context: Context) : BottomSheetDialog(context) { @SuppressLint("NotifyDataSetChanged") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + setOnShowListener { applyFullscreenMode() } binding = DialogChatBinding.inflate(LayoutInflater.from(context)) setContentView(binding.root) @@ -75,6 +85,11 @@ class ChatDialog(context: Context) : BottomSheetDialog(context) { } } + override fun onStart() { + super.onStart() + applyFullscreenMode() + } + override fun dismiss() { NetPlayManager.setChatOpen(false) super.dismiss() @@ -108,6 +123,12 @@ class ChatDialog(context: Context) : BottomSheetDialog(context) { private fun scrollToBottom() { binding.chatRecyclerView.scrollToPosition(chatAdapter.itemCount - 1) } + + private fun applyFullscreenMode() { + window?.let { window -> + FullscreenHelper.applyToWindow(window, hideSystemBars) + } + } } class ChatAdapter(private val messages: List) : diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/LobbyBrowser.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/LobbyBrowser.kt index 6d5c6ef23f..10ff2da6c7 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/LobbyBrowser.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/LobbyBrowser.kt @@ -31,15 +31,25 @@ import org.yuzu.yuzu_emu.databinding.DialogLobbyBrowserBinding import org.yuzu.yuzu_emu.databinding.ItemLobbyRoomBinding import org.yuzu.yuzu_emu.features.settings.model.StringSetting import org.yuzu.yuzu_emu.network.NetPlayManager +import org.yuzu.yuzu_emu.utils.CompatUtils +import org.yuzu.yuzu_emu.utils.FullscreenHelper import java.util.Locale class LobbyBrowser(context: Context) : BottomSheetDialog(context) { private lateinit var binding: DialogLobbyBrowserBinding private lateinit var adapter: LobbyRoomAdapter private val handler = Handler(Looper.getMainLooper()) + private val hideSystemBars: Boolean by lazy { + runCatching { + FullscreenHelper.shouldHideSystemBars(CompatUtils.findActivity(context)) + }.getOrElse { + FullscreenHelper.isFullscreenEnabled(context) + } + } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + setOnShowListener { applyFullscreenMode() } behavior.state = BottomSheetBehavior.STATE_EXPANDED behavior.skipCollapsed = @@ -81,6 +91,7 @@ class LobbyBrowser(context: Context) : BottomSheetDialog(context) { behavior.expandedOffset = 0 behavior.skipCollapsed = true behavior.state = BottomSheetBehavior.STATE_EXPANDED + applyFullscreenMode() } private fun setupRecyclerView() { @@ -274,4 +285,10 @@ class LobbyBrowser(context: Context) : BottomSheetDialog(context) { } private inner class ScoreItem(val score: Double, val item: NetPlayManager.RoomInfo) + + private fun applyFullscreenMode() { + window?.let { window -> + FullscreenHelper.applyToWindow(window, hideSystemBars) + } + } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/NetPlayDialog.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/NetPlayDialog.kt index 73452b4b69..45ce5fb0cf 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/NetPlayDialog.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/NetPlayDialog.kt @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later package org.yuzu.yuzu_emu.dialogs @@ -36,6 +36,7 @@ import org.yuzu.yuzu_emu.features.settings.model.StringSetting import org.yuzu.yuzu_emu.network.NetDataValidators import org.yuzu.yuzu_emu.network.NetPlayManager import org.yuzu.yuzu_emu.utils.CompatUtils +import org.yuzu.yuzu_emu.utils.FullscreenHelper import org.yuzu.yuzu_emu.utils.GameHelper class NetPlayDialog(context: Context) : BottomSheetDialog(context) { @@ -43,9 +44,17 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) { private val gameNameList: MutableList> = mutableListOf() private val gameIdList: MutableList> = mutableListOf() + private val hideSystemBars: Boolean by lazy { + runCatching { + FullscreenHelper.shouldHideSystemBars(CompatUtils.findActivity(context)) + }.getOrElse { + FullscreenHelper.isFullscreenEnabled(context) + } + } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + setOnShowListener { applyFullscreenMode() } behavior.state = BottomSheetBehavior.STATE_EXPANDED behavior.state = BottomSheetBehavior.STATE_EXPANDED @@ -118,6 +127,11 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) { } } + override fun onStart() { + super.onStart() + applyFullscreenMode() + } + data class NetPlayItems( val option: Int, val name: String, @@ -352,6 +366,11 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) { TextValidatorWatcher.validStates.clear() val activity = CompatUtils.findActivity(context) val dialog = BottomSheetDialog(activity) + dialog.setOnShowListener { + dialog.window?.let { window -> + FullscreenHelper.applyToWindow(window, hideSystemBars) + } + } dialog.behavior.state = BottomSheetBehavior.STATE_EXPANDED dialog.behavior.state = BottomSheetBehavior.STATE_EXPANDED @@ -582,6 +601,12 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) { dialog.show() } + private fun applyFullscreenMode() { + window?.let { window -> + FullscreenHelper.applyToWindow(window, hideSystemBars) + } + } + private fun showModerationDialog() { val activity = CompatUtils.findActivity(context) val dialog = MaterialAlertDialogBuilder(activity) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt index 0f89533d8e..b438812d58 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt @@ -104,6 +104,8 @@ object Settings { const val PREF_THEME_MODE = "ThemeMode" const val PREF_BLACK_BACKGROUNDS = "BlackBackgrounds" const val PREF_STATIC_THEME_COLOR = "StaticThemeColor" + const val PREF_APP_FULLSCREEN = "AppFullscreen" + const val APP_FULLSCREEN_DEFAULT = false enum class EmulationOrientation(val int: Int) { Unspecified(0), diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt index d33bbc3d7d..ad1ecba64c 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt @@ -103,6 +103,7 @@ class SettingsActivity : AppCompatActivity() { ) setInsets() + applyFullscreenPreference() } fun navigateBack() { @@ -122,6 +123,18 @@ class SettingsActivity : AppCompatActivity() { } } + override fun onResume() { + super.onResume() + applyFullscreenPreference() + } + + override fun onWindowFocusChanged(hasFocus: Boolean) { + super.onWindowFocusChanged(hasFocus) + if (hasFocus) { + applyFullscreenPreference() + } + } + override fun onStop() { super.onStop() Log.info("[SettingsActivity] Settings activity stopping. Saving settings to INI...") @@ -188,4 +201,8 @@ class SettingsActivity : AppCompatActivity() { windowInsets } } + + private fun applyFullscreenPreference() { + FullscreenHelper.applyToActivity(this) + } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index ff25584c92..853e1e3e4b 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -29,6 +29,8 @@ import org.yuzu.yuzu_emu.features.settings.model.view.* import org.yuzu.yuzu_emu.utils.InputHandler import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.DirectoryInitialization +import org.yuzu.yuzu_emu.utils.FullscreenHelper +import androidx.core.content.edit import androidx.fragment.app.FragmentActivity import org.yuzu.yuzu_emu.fragments.MessageDialogFragment @@ -1187,6 +1189,39 @@ class SettingsFragmentPresenter( ) ) + val fullscreenSetting: AbstractBooleanSetting = object : AbstractBooleanSetting { + override fun getBoolean(needsGlobal: Boolean): Boolean = + FullscreenHelper.isFullscreenEnabled(context) + + override fun setBoolean(value: Boolean) { + FullscreenHelper.setFullscreenEnabled(context, value) + settingsViewModel.setShouldRecreate(true) + } + + override val key: String = Settings.PREF_APP_FULLSCREEN + override val isRuntimeModifiable: Boolean = true + override val pairedSettingKey: String = "" + override val isSwitchable: Boolean = false + override var global: Boolean = true + override val isSaveable: Boolean = true + override val defaultValue: Boolean = Settings.APP_FULLSCREEN_DEFAULT + + override fun getValueAsString(needsGlobal: Boolean): String = + getBoolean(needsGlobal).toString() + + override fun reset() { + setBoolean(defaultValue) + } + } + + add( + SwitchSetting( + fullscreenSetting, + titleId = R.string.fullscreen_mode, + descriptionId = R.string.fullscreen_mode_description + ) + ) + add(HeaderSetting(R.string.buttons)) add(BooleanSetting.ENABLE_FOLDER_BUTTON.key) add(BooleanSetting.ENABLE_QLAUNCH_BUTTON.key) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsSubscreenActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsSubscreenActivity.kt index 11ecd355fb..91888dce12 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsSubscreenActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsSubscreenActivity.kt @@ -20,6 +20,7 @@ import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.YuzuApplication import org.yuzu.yuzu_emu.databinding.ActivitySettingsBinding import org.yuzu.yuzu_emu.utils.DirectoryInitialization +import org.yuzu.yuzu_emu.utils.FullscreenHelper import org.yuzu.yuzu_emu.utils.InsetsHelper import org.yuzu.yuzu_emu.utils.ThemeHelper @@ -89,6 +90,7 @@ class SettingsSubscreenActivity : AppCompatActivity() { ) setInsets() + applyFullscreenPreference() } override fun onStart() { @@ -98,6 +100,18 @@ class SettingsSubscreenActivity : AppCompatActivity() { } } + override fun onResume() { + super.onResume() + applyFullscreenPreference() + } + + override fun onWindowFocusChanged(hasFocus: Boolean) { + super.onWindowFocusChanged(hasFocus) + if (hasFocus) { + applyFullscreenPreference() + } + } + fun navigateBack() { val navHostFragment = supportFragmentManager.findFragmentById(R.id.fragment_container) as NavHostFragment @@ -149,4 +163,8 @@ class SettingsSubscreenActivity : AppCompatActivity() { windowInsets } } + + private fun applyFullscreenPreference() { + FullscreenHelper.applyToActivity(this) + } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ProfileManagerFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ProfileManagerFragment.kt index 2786906f6b..bd37c4c9c7 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ProfileManagerFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ProfileManagerFragment.kt @@ -9,6 +9,7 @@ import android.view.View import android.view.ViewGroup import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat +import androidx.core.view.updatePadding import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController @@ -22,6 +23,7 @@ import org.yuzu.yuzu_emu.databinding.FragmentProfileManagerBinding import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.model.UserProfile import org.yuzu.yuzu_emu.utils.NativeConfig +import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins class ProfileManagerFragment : Fragment() { private var _binding: FragmentProfileManagerBinding? = null @@ -172,11 +174,19 @@ class ProfileManagerFragment : Fragment() { val leftInsets = barInsets.left + cutoutInsets.left val rightInsets = barInsets.right + cutoutInsets.right - val fabLayoutParams = binding.buttonAddUser.layoutParams as ViewGroup.MarginLayoutParams - fabLayoutParams.leftMargin = leftInsets + 24 - fabLayoutParams.rightMargin = rightInsets + 24 - fabLayoutParams.bottomMargin = barInsets.bottom + 24 - binding.buttonAddUser.layoutParams = fabLayoutParams + binding.toolbarProfiles.updateMargins(left = leftInsets, right = rightInsets) + binding.listProfiles.updateMargins(left = leftInsets, right = rightInsets) + binding.listProfiles.updatePadding( + bottom = barInsets.bottom + + resources.getDimensionPixelSize(R.dimen.spacing_bottom_list_fab) + ) + + val fabSpacing = resources.getDimensionPixelSize(R.dimen.spacing_fab) + binding.buttonAddUser.updateMargins( + left = leftInsets + fabSpacing, + right = rightInsets + fabSpacing, + bottom = barInsets.bottom + fabSpacing + ) windowInsets } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt index 3a771edfcb..02368bfc16 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt @@ -169,6 +169,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { checkForUpdates() } setInsets() + applyFullscreenPreference() } private fun checkForUpdates() { @@ -345,6 +346,14 @@ class MainActivity : AppCompatActivity(), ThemeProvider { override fun onResume() { ThemeHelper.setCorrectTheme(this) super.onResume() + applyFullscreenPreference() + } + + override fun onWindowFocusChanged(hasFocus: Boolean) { + super.onWindowFocusChanged(hasFocus) + if (hasFocus) { + applyFullscreenPreference() + } } private fun setInsets() = ViewCompat.setOnApplyWindowInsetsListener( @@ -364,6 +373,10 @@ class MainActivity : AppCompatActivity(), ThemeProvider { windowInsets } + private fun applyFullscreenPreference() { + FullscreenHelper.applyToActivity(this) + } + override fun setTheme(resId: Int) { super.setTheme(resId) themeId = resId diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FullscreenHelper.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FullscreenHelper.kt new file mode 100644 index 0000000000..62c83e1806 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FullscreenHelper.kt @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +package org.yuzu.yuzu_emu.utils + +import android.app.Activity +import android.content.Context +import android.view.Window +import androidx.core.content.edit +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.WindowInsetsControllerCompat +import androidx.preference.PreferenceManager +import org.yuzu.yuzu_emu.features.settings.model.Settings + +object FullscreenHelper { + fun isFullscreenEnabled(context: Context): Boolean { + return PreferenceManager.getDefaultSharedPreferences(context).getBoolean( + Settings.PREF_APP_FULLSCREEN, + Settings.APP_FULLSCREEN_DEFAULT + ) + } + + fun setFullscreenEnabled(context: Context, enabled: Boolean) { + PreferenceManager.getDefaultSharedPreferences(context).edit { + putBoolean(Settings.PREF_APP_FULLSCREEN, enabled) + } + } + + fun shouldHideSystemBars(activity: Activity): Boolean { + val rootInsets = ViewCompat.getRootWindowInsets(activity.window.decorView) + val barsCurrentlyHidden = + rootInsets?.isVisible(WindowInsetsCompat.Type.systemBars())?.not() ?: false + return isFullscreenEnabled(activity) || barsCurrentlyHidden + } + + fun applyToWindow(window: Window, hideSystemBars: Boolean) { + val controller = WindowInsetsControllerCompat(window, window.decorView) + + if (hideSystemBars) { + controller.hide(WindowInsetsCompat.Type.systemBars()) + controller.systemBarsBehavior = + WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE + } else { + controller.show(WindowInsetsCompat.Type.systemBars()) + } + } + + fun applyToActivity(activity: Activity) { + applyToWindow(activity.window, isFullscreenEnabled(activity)) + } +} diff --git a/src/android/app/src/main/res/layout/fragment_profile_manager.xml b/src/android/app/src/main/res/layout/fragment_profile_manager.xml index e70a3f3da5..67828ca69e 100644 --- a/src/android/app/src/main/res/layout/fragment_profile_manager.xml +++ b/src/android/app/src/main/res/layout/fragment_profile_manager.xml @@ -5,21 +5,22 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?attr/colorSurface" - android:fitsSystemWindows="true"> + android:background="?attr/colorSurface"> + android:fitsSystemWindows="true" + android:touchscreenBlocksFocus="false"> diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index e9bd0f1d1c..343cc4b21a 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -1160,6 +1160,8 @@ Material You App Settings Theme And Color + Fullscreen mode + Hide Android system bars across app screens. Swipe from an edge to reveal them temporarily. Change theme mode From c5b519380cfed91674483eae0caee40f3a80c7d4 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sun, 22 Mar 2026 04:00:57 +0100 Subject: [PATCH 10/23] [externals] update renderdoc to 1.7.0 (#3751) Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3751 Co-authored-by: lizzie Co-committed-by: lizzie --- externals/renderdoc/renderdoc_app.h | 164 +++++++++++++++++++++++++--- src/core/tools/renderdoc.h | 7 +- 2 files changed, 154 insertions(+), 17 deletions(-) diff --git a/externals/renderdoc/renderdoc_app.h b/externals/renderdoc/renderdoc_app.h index e6c1511deb..c379f0ac40 100644 --- a/externals/renderdoc/renderdoc_app.h +++ b/externals/renderdoc/renderdoc_app.h @@ -7,7 +7,7 @@ /****************************************************************************** * The MIT License (MIT) * - * Copyright (c) 2019-2025 Baldur Karlsson + * Copyright (c) 2015-2026 Baldur Karlsson * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -72,6 +72,10 @@ extern "C" { // truncated version when only a uint64_t is available (e.g. Vulkan tags): #define RENDERDOC_ShaderDebugMagicValue_truncated 0x48656670eab25520ULL +// this is a magic value for vulkan user tags to indicate which dispatchable API objects are which +// for object annotations +#define RENDERDOC_APIObjectAnnotationHelper 0xfbb3b337b664d0adULL + ////////////////////////////////////////////////////////////////////////////////////////////////// // RenderDoc capture options // @@ -564,6 +568,128 @@ typedef uint32_t(RENDERDOC_CC *pRENDERDOC_DiscardFrameCapture)(RENDERDOC_DeviceP // multiple times only the last title will be used. typedef void(RENDERDOC_CC *pRENDERDOC_SetCaptureTitle)(const char *title); +// Annotations API: +// +// These functions allow you to specify annotations either on a per-command level, or a per-object +// level. +// +// Basic types of annotations are supported, as well as vector versions and references to API objects. +// +// The annotations are stored as keys, with the key being a dot-separated path allowing arbitrary +// nesting and user organisation. The keys are sorted in human order so `foo.2.bar` will be displayed +// before `foo.10.bar` to allow creation of arrays if desired. +// +// Deleting an annotation can be done by assigning an empty value to it. + +// the type of an annotation value, or Empty to delete an annotation +typedef enum RENDERDOC_AnnotationType +{ + eRENDERDOC_Empty, + eRENDERDOC_Bool, + eRENDERDOC_Int32, + eRENDERDOC_UInt32, + eRENDERDOC_Int64, + eRENDERDOC_UInt64, + eRENDERDOC_Float, + eRENDERDOC_Double, + eRENDERDOC_String, + eRENDERDOC_APIObject, + eRENDERDOC_AnnotationMax = 0x7FFFFFFF, +} RENDERDOC_AnnotationType; + +// a union with vector annotation value data +typedef union RENDERDOC_AnnotationVectorValue +{ + bool boolean[4]; + int32_t int32[4]; + int64_t int64[4]; + uint32_t uint32[4]; + uint64_t uint64[4]; + float float32[4]; + double float64[4]; +} RENDERDOC_AnnotationVectorValue; + +// a union with scalar annotation value data +typedef union RENDERDOC_AnnotationValue +{ + bool boolean; + int32_t int32; + int64_t int64; + uint32_t uint32; + uint64_t uint64; + float float32; + double float64; + + RENDERDOC_AnnotationVectorValue vector; + + const char *string; + void *apiObject; +} RENDERDOC_AnnotationValue; + +// a struct for specifying a GL object, as we don't have pointers we can use so instead we specify a +// pointer to this struct giving both the type and the name +typedef struct RENDERDOC_GLResourceReference +{ + // this is the same GLenum identifier as passed to glObjectLabel + uint32_t identifier; + uint32_t name; +} GLResourceReference; + +// simple C++ helpers to avoid the need for a temporary objects for value passing and GL object specification +#ifdef __cplusplus +struct RDGLObjectHelper +{ + RENDERDOC_GLResourceReference gl; + + RDGLObjectHelper(uint32_t identifier, uint32_t name) + { + gl.identifier = identifier; + gl.name = name; + } + + operator RENDERDOC_GLResourceReference *() { return ≷ } +}; + +struct RDAnnotationHelper +{ + RENDERDOC_AnnotationValue val; + + RDAnnotationHelper(bool b) { val.boolean = b; } + RDAnnotationHelper(int32_t i) { val.int32 = i; } + RDAnnotationHelper(int64_t i) { val.int64 = i; } + RDAnnotationHelper(uint32_t i) { val.uint32 = i; } + RDAnnotationHelper(uint64_t i) { val.uint64 = i; } + RDAnnotationHelper(float f) { val.float32 = f; } + RDAnnotationHelper(double d) { val.float64 = d; } + RDAnnotationHelper(const char *s) { val.string = s; } + + operator RENDERDOC_AnnotationValue *() { return &val; } +}; +#endif + +// The device is specified in the same way as other API calls that take a RENDERDOC_DevicePointer +// to specify the device. +// +// The object or queue/commandbuffer will depend on the graphics API in question. +// +// Return value: +// 0 - The annotation was applied successfully. +// 1 - The device is unknown/invalid +// 2 - The device is valid but the annotation is not supported for API-specific reasons, such as an +// unrecognised or invalid object or queue/commandbuffer +// 3 - The call is ill-formed or invalid e.g. empty is specified with a value pointer, or non-empty +// is specified with a NULL value pointer +typedef uint32_t(RENDERDOC_CC *pRENDERDOC_SetObjectAnnotation)(RENDERDOC_DevicePointer device, + void *object, const char *key, + RENDERDOC_AnnotationType valueType, + uint32_t valueVectorWidth, + const RENDERDOC_AnnotationValue *value); + +typedef uint32_t(RENDERDOC_CC *pRENDERDOC_SetCommandAnnotation)( + RENDERDOC_DevicePointer device, void *queueOrCommandBuffer, const char *key, + RENDERDOC_AnnotationType valueType, uint32_t valueVectorWidth, + const RENDERDOC_AnnotationValue *value); + ////////////////////////////////////////////////////////////////////////////////////////////////// // RenderDoc API versions // @@ -592,6 +718,7 @@ typedef enum RENDERDOC_Version eRENDERDOC_API_Version_1_4_2 = 10402, // RENDERDOC_API_1_4_2 = 1 04 02 eRENDERDOC_API_Version_1_5_0 = 10500, // RENDERDOC_API_1_5_0 = 1 05 00 eRENDERDOC_API_Version_1_6_0 = 10600, // RENDERDOC_API_1_6_0 = 1 06 00 + eRENDERDOC_API_Version_1_7_0 = 10700, // RENDERDOC_API_1_7_0 = 1 07 00 } RENDERDOC_Version; // API version changelog: @@ -622,8 +749,10 @@ typedef enum RENDERDOC_Version // 1.5.0 - Added feature: ShowReplayUI() to request that the replay UI show itself if connected // 1.6.0 - Added feature: SetCaptureTitle() which can be used to set a title for a // capture made with StartFrameCapture() or EndFrameCapture() +// 1.7.0 - Added feature: SetObjectAnnotation() / SetCommandAnnotation() for adding rich +// annotations to objects and command streams -typedef struct RENDERDOC_API_1_6_0 +typedef struct RENDERDOC_API_1_7_0 { pRENDERDOC_GetAPIVersion GetAPIVersion; @@ -701,20 +830,25 @@ typedef struct RENDERDOC_API_1_6_0 // new function in 1.6.0 pRENDERDOC_SetCaptureTitle SetCaptureTitle; -} RENDERDOC_API_1_6_0; -typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_0_0; -typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_0_1; -typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_0_2; -typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_1_0; -typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_1_1; -typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_1_2; -typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_2_0; -typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_3_0; -typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_4_0; -typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_4_1; -typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_4_2; -typedef RENDERDOC_API_1_6_0 RENDERDOC_API_1_5_0; + // new functions in 1.7.0 + pRENDERDOC_SetObjectAnnotation SetObjectAnnotation; + pRENDERDOC_SetCommandAnnotation SetCommandAnnotation; +} RENDERDOC_API_1_7_0; + +typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_0_0; +typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_0_1; +typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_0_2; +typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_1_0; +typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_1_1; +typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_1_2; +typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_2_0; +typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_3_0; +typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_4_0; +typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_4_1; +typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_4_2; +typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_5_0; +typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_6_0; ////////////////////////////////////////////////////////////////////////////////////////////////// // RenderDoc API entry point diff --git a/src/core/tools/renderdoc.h b/src/core/tools/renderdoc.h index 0e5e43da5b..689b0a383a 100644 --- a/src/core/tools/renderdoc.h +++ b/src/core/tools/renderdoc.h @@ -1,9 +1,12 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once -struct RENDERDOC_API_1_6_0; +struct RENDERDOC_API_1_7_0; namespace Tools { @@ -15,7 +18,7 @@ public: void ToggleCapture(); private: - RENDERDOC_API_1_6_0* rdoc_api{}; + RENDERDOC_API_1_7_0* rdoc_api{}; bool is_capturing{false}; }; From 811cc18d7489c6faac9ddff9280c1e870e09e9af Mon Sep 17 00:00:00 2001 From: lizzie Date: Sun, 22 Mar 2026 17:37:21 +0100 Subject: [PATCH 11/23] [hle/acc] fix (false) return where it's just 2 (#3763) Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3763 Reviewed-by: Maufeat Reviewed-by: MaranBr Co-authored-by: lizzie Co-committed-by: lizzie --- src/core/hle/service/acc/acc.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index d8767f9fed..43c569851d 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -712,9 +712,8 @@ public: private: void CheckAvailability(HLERequestContext& ctx) { LOG_DEBUG(Service_ACC, "(STUBBED) called"); - IPC::ResponseBuilder rb{ctx, 3}; + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); - rb.Push(false); // TODO: Check when this is supposed to return true and when not } void GetAccountId(HLERequestContext& ctx) { From 772e38cb8d9d1076305e7f02a4434c2ab54ae249 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sun, 22 Mar 2026 20:17:44 +0100 Subject: [PATCH 12/23] [hle/service/sockets] fix hogwarts legacy crash due to non-blacklisted domain (#3762) Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3762 Reviewed-by: Maufeat Reviewed-by: MaranBr Co-authored-by: lizzie Co-committed-by: lizzie --- src/core/hle/service/sockets/sfdnsres.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/core/hle/service/sockets/sfdnsres.cpp b/src/core/hle/service/sockets/sfdnsres.cpp index 68d73f0a59..f9f0ee56eb 100644 --- a/src/core/hle/service/sockets/sfdnsres.cpp +++ b/src/core/hle/service/sockets/sfdnsres.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project @@ -53,12 +53,15 @@ enum class NetDbError : s32 { NoData = 4, }; -static const constexpr std::array blockedDomains = {"srv.nintendo.net", - "battle.net", - "microsoft.com", - "mojang.com", - "xboxlive.com", - "minecraftservices.com"}; +static const constexpr std::array blockedDomains = { + "srv.nintendo.net", //obvious + "phoenix-api.wbagora.com", //hogwarts legacy + "battle.net", + "microsoft.com", //minecraft dungeons + other games + "mojang.com", + "xboxlive.com", + "minecraftservices.com" +}; static bool IsBlockedHost(const std::string& host) { return std::any_of( From ad58ab8976dd230cadf40803011dbd58fd5446d5 Mon Sep 17 00:00:00 2001 From: crueter Date: Mon, 23 Mar 2026 17:05:40 +0100 Subject: [PATCH 13/23] [externals] Use Eden mirrors for llvm-mingw and tzdb (#3766) My server is getting hammered, let's just move them here. Signed-off-by: crueter Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3766 --- cpmfile.json | 4 ++-- externals/cpmfile.json | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/cpmfile.json b/cpmfile.json index c938e67e88..1bb29afae4 100644 --- a/cpmfile.json +++ b/cpmfile.json @@ -87,8 +87,8 @@ "bundled": true }, "llvm-mingw": { - "repo": "misc/llvm-mingw", - "git_host": "git.crueter.xyz", + "repo": "eden-emu/llvm-mingw", + "git_host": "git.eden-emu.dev", "tag": "%VERSION%", "version": "20250828", "artifact": "clang-rt-builtins.tar.zst", diff --git a/externals/cpmfile.json b/externals/cpmfile.json index 8209e431a3..d67348cd68 100644 --- a/externals/cpmfile.json +++ b/externals/cpmfile.json @@ -246,12 +246,13 @@ }, "tzdb": { "package": "nx_tzdb", - "repo": "misc/tzdb_to_nx", - "git_host": "git.crueter.xyz", + "repo": "eden-emu/tzdb_to_nx", + "git_host": "git.eden-emu.dev", "artifact": "%VERSION%.tar.gz", "tag": "%VERSION%", - "hash": "dc37a189a44ce8b5c988ca550582431a6c7eadfd3c6e709bee6277116ee803e714333e85c9e6cbb5c69346a14d6f2cc7ed96e8aa09cc5fb8a89f945059651db6", - "version": "121125" + "hash": "cce65a12bf90f4ead43b24a0b95dfad77ac3d9bfbaaf66c55e6701346e7a1e44ca5d2f23f47ee35ee02271eb1082bf1762af207aad9fb236f1c8476812d008ed", + "version": "121125", + "git_version": "230326" }, "vulkan-headers": { "repo": "KhronosGroup/Vulkan-Headers", From 56d3f0e353d63752782020b0777e3803c4832bde Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 23 Mar 2026 18:03:48 +0100 Subject: [PATCH 14/23] [dynarmic] fix dynarmic_tests build issues on xcode due to using relative paths (#3765) Thanks to @chrelliott978 for the initial impl Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3765 Reviewed-by: Maufeat Reviewed-by: crueter Co-authored-by: lizzie Co-committed-by: lizzie --- src/dynarmic/tests/A32/fuzz_arm.cpp | 11 ++--- src/dynarmic/tests/A32/fuzz_thumb.cpp | 37 ++++++++------- .../tests/A32/test_arm_instructions.cpp | 6 +-- src/dynarmic/tests/A32/test_coprocessor.cpp | 6 +-- src/dynarmic/tests/A32/test_svc.cpp | 6 +-- .../tests/A32/test_thumb_instructions.cpp | 6 +-- src/dynarmic/tests/A64/a64.cpp | 4 +- src/dynarmic/tests/A64/fp_min_max.cpp | 6 +-- src/dynarmic/tests/A64/fuzz_with_unicorn.cpp | 47 ++++++++++--------- .../tests/A64/misaligned_page_table.cpp | 6 +-- src/dynarmic/tests/A64/real_world.cpp | 6 +-- src/dynarmic/tests/A64/test_invalidation.cpp | 6 +-- src/dynarmic/tests/A64/verify_unicorn.cpp | 9 ++-- src/dynarmic/tests/fp/FPToFixed.cpp | 4 +- src/dynarmic/tests/fp/mantissa_util_tests.cpp | 4 +- src/dynarmic/tests/fp/unpacked_tests.cpp | 4 +- src/dynarmic/tests/fuzz_util.cpp | 6 +-- src/dynarmic/tests/native/preserve_xmm.cpp | 6 +-- src/dynarmic/tests/test_generator.cpp | 4 +- .../tests/unicorn_emu/a32_unicorn.cpp | 20 +++----- src/dynarmic/tests/unicorn_emu/a32_unicorn.h | 4 +- .../tests/unicorn_emu/a64_unicorn.cpp | 16 ++----- src/dynarmic/tests/unicorn_emu/a64_unicorn.h | 4 +- 23 files changed, 111 insertions(+), 117 deletions(-) diff --git a/src/dynarmic/tests/A32/fuzz_arm.cpp b/src/dynarmic/tests/A32/fuzz_arm.cpp index fd17b3bd01..cd2eade884 100644 --- a/src/dynarmic/tests/A32/fuzz_arm.cpp +++ b/src/dynarmic/tests/A32/fuzz_arm.cpp @@ -20,15 +20,14 @@ #include #include "dynarmic/common/common_types.h" -#include "../fuzz_util.h" -#include "../rand_int.h" -#include "../unicorn_emu/a32_unicorn.h" -#include "./testenv.h" -#include "../native/testenv.h" +#include "dynarmic/tests/fuzz_util.h" +#include "dynarmic/tests/rand_int.h" +#include "dynarmic/tests/unicorn_emu/a32_unicorn.h" +#include "dynarmic/tests/A32/testenv.h" +#include "dynarmic/tests/native/testenv.h" #include "dynarmic/common/fp/fpcr.h" #include "dynarmic/common/fp/fpsr.h" #include "dynarmic/common/llvm_disassemble.h" -#include "dynarmic/common/variant_util.h" #include "dynarmic/frontend/A32/ITState.h" #include "dynarmic/frontend/A32/a32_location_descriptor.h" #include "dynarmic/frontend/A32/a32_types.h" diff --git a/src/dynarmic/tests/A32/fuzz_thumb.cpp b/src/dynarmic/tests/A32/fuzz_thumb.cpp index 3a561a18d9..f985e6f93d 100644 --- a/src/dynarmic/tests/A32/fuzz_thumb.cpp +++ b/src/dynarmic/tests/A32/fuzz_thumb.cpp @@ -19,10 +19,10 @@ #include #include "dynarmic/common/common_types.h" -#include "../rand_int.h" -#include "../unicorn_emu/a32_unicorn.h" -#include "./testenv.h" -#include "../native/testenv.h" +#include "dynarmic/tests/rand_int.h" +#include "dynarmic/tests/unicorn_emu/a32_unicorn.h" +#include "dynarmic/tests/A32/testenv.h" +#include "dynarmic/tests/native/testenv.h" #include "dynarmic/frontend/A32/FPSCR.h" #include "dynarmic/frontend/A32/PSR.h" #include "dynarmic/frontend/A32/a32_location_descriptor.h" @@ -107,7 +107,7 @@ static bool DoesBehaviorMatch(const A32Unicorn& uni, const A32::Ji return std::equal(interp_regs.begin(), interp_regs.end(), jit_regs.begin(), jit_regs.end()) && uni.GetCpsr() == jit.Cpsr() && interp_write_records == jit_write_records; } -static void RunInstance(size_t run_number, ThumbTestEnv& test_env, A32Unicorn& uni, A32::Jit& jit, const ThumbTestEnv::RegisterArray& initial_regs, size_t instruction_count, size_t instructions_to_execute_count) { +static void RunInstance(size_t run_number, ThumbTestEnv& test_env, A32::UserConfig const& config, A32Unicorn& uni, A32::Jit& jit, const ThumbTestEnv::RegisterArray& initial_regs, size_t instruction_count, size_t instructions_to_execute_count) { uni.ClearPageCache(); jit.ClearCache(); @@ -145,9 +145,8 @@ static void RunInstance(size_t run_number, ThumbTestEnv& test_env, A32Unicorn uni{test_env}; - A32::Jit jit{GetUserConfig(&test_env)}; + A32::UserConfig config{GetUserConfig(&test_env)}; + A32::Jit jit{config}; constexpr ThumbTestEnv::RegisterArray initial_regs{ 0xe90ecd70, @@ -534,5 +539,5 @@ TEST_CASE("Verify fix for off by one error in MemoryRead32 worked", "[Thumb][Thu 0xE7FE, // b +#0 }; - RunInstance(1, test_env, uni, jit, initial_regs, 5, 5); + RunInstance(1, test_env, config, uni, jit, initial_regs, 5, 5); } diff --git a/src/dynarmic/tests/A32/test_arm_instructions.cpp b/src/dynarmic/tests/A32/test_arm_instructions.cpp index 2e7e7dc5d8..5a27cd499c 100644 --- a/src/dynarmic/tests/A32/test_arm_instructions.cpp +++ b/src/dynarmic/tests/A32/test_arm_instructions.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -8,8 +8,8 @@ #include -#include "./testenv.h" -#include "../native/testenv.h" +#include "dynarmic/tests/A32/testenv.h" +#include "dynarmic/tests/native/testenv.h" #include "dynarmic/frontend/A32/a32_location_descriptor.h" #include "dynarmic/interface/A32/a32.h" diff --git a/src/dynarmic/tests/A32/test_coprocessor.cpp b/src/dynarmic/tests/A32/test_coprocessor.cpp index 3888d2c68b..66ae6ebb09 100644 --- a/src/dynarmic/tests/A32/test_coprocessor.cpp +++ b/src/dynarmic/tests/A32/test_coprocessor.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -10,8 +10,8 @@ #include -#include "./testenv.h" -#include "../native/testenv.h" +#include "dynarmic/tests/A32/testenv.h" +#include "dynarmic/tests/native/testenv.h" #include "dynarmic/frontend/A32/a32_location_descriptor.h" #include "dynarmic/interface/A32/a32.h" #include "dynarmic/interface/A32/coprocessor.h" diff --git a/src/dynarmic/tests/A32/test_svc.cpp b/src/dynarmic/tests/A32/test_svc.cpp index 0be2432c7b..0cfaf23ec5 100644 --- a/src/dynarmic/tests/A32/test_svc.cpp +++ b/src/dynarmic/tests/A32/test_svc.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -10,8 +10,8 @@ #include -#include "./testenv.h" -#include "../native/testenv.h" +#include "dynarmic/tests/A32/testenv.h" +#include "dynarmic/tests/native/testenv.h" using namespace Dynarmic; diff --git a/src/dynarmic/tests/A32/test_thumb_instructions.cpp b/src/dynarmic/tests/A32/test_thumb_instructions.cpp index d509acdd8d..6aa1b7389b 100644 --- a/src/dynarmic/tests/A32/test_thumb_instructions.cpp +++ b/src/dynarmic/tests/A32/test_thumb_instructions.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -9,8 +9,8 @@ #include #include "dynarmic/common/common_types.h" -#include "./testenv.h" -#include "../native/testenv.h" +#include "dynarmic/tests/A32/testenv.h" +#include "dynarmic/tests/native/testenv.h" #include "dynarmic/interface/A32/a32.h" static Dynarmic::A32::UserConfig GetUserConfig(ThumbTestEnv* testenv) { diff --git a/src/dynarmic/tests/A64/a64.cpp b/src/dynarmic/tests/A64/a64.cpp index d331c5e8a1..4d4484e53e 100644 --- a/src/dynarmic/tests/A64/a64.cpp +++ b/src/dynarmic/tests/A64/a64.cpp @@ -9,8 +9,8 @@ #include #include -#include "./testenv.h" -#include "../native/testenv.h" +#include "dynarmic/tests/A64/testenv.h" +#include "dynarmic/tests/native/testenv.h" #include "dynarmic/common/fp/fpsr.h" #include "dynarmic/interface/exclusive_monitor.h" #include "dynarmic/interface/optimization_flags.h" diff --git a/src/dynarmic/tests/A64/fp_min_max.cpp b/src/dynarmic/tests/A64/fp_min_max.cpp index 1669b63071..313b5e5117 100644 --- a/src/dynarmic/tests/A64/fp_min_max.cpp +++ b/src/dynarmic/tests/A64/fp_min_max.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -11,8 +11,8 @@ #include #include "dynarmic/common/common_types.h" -#include "./testenv.h" -#include "../native/testenv.h" +#include "dynarmic/tests/A64/testenv.h" +#include "dynarmic/tests/native/testenv.h" using namespace Dynarmic; diff --git a/src/dynarmic/tests/A64/fuzz_with_unicorn.cpp b/src/dynarmic/tests/A64/fuzz_with_unicorn.cpp index 2cdf288eab..0c7a30a868 100644 --- a/src/dynarmic/tests/A64/fuzz_with_unicorn.cpp +++ b/src/dynarmic/tests/A64/fuzz_with_unicorn.cpp @@ -15,11 +15,11 @@ #include #include "dynarmic/common/common_types.h" -#include "../fuzz_util.h" -#include "../rand_int.h" -#include "../unicorn_emu/a64_unicorn.h" -#include "./testenv.h" -#include "../native/testenv.h" +#include "dynarmic/tests/fuzz_util.h" +#include "dynarmic/tests/rand_int.h" +#include "dynarmic/tests/unicorn_emu/a64_unicorn.h" +#include "dynarmic/tests/A64/testenv.h" +#include "dynarmic/tests/native/testenv.h" #include "dynarmic/common/fp/fpcr.h" #include "dynarmic/common/fp/fpsr.h" #include "dynarmic/common/llvm_disassemble.h" @@ -168,7 +168,7 @@ static Dynarmic::A64::UserConfig GetUserConfig(A64TestEnv& jit_env) { return jit_user_config; } -static void RunTestInstance(Dynarmic::A64::Jit& jit, A64Unicorn& uni, A64TestEnv& jit_env, A64TestEnv& uni_env, const A64Unicorn::RegisterArray& regs, const A64Unicorn::VectorArray& vecs, const size_t instructions_start, const std::vector& instructions, const u32 pstate, const u32 fpcr) { +static void RunTestInstance(Dynarmic::A64::Jit& jit, A64Unicorn& uni, A64TestEnv& jit_env, A64TestEnv& uni_env, Dynarmic::A64::UserConfig& conf, const A64Unicorn::RegisterArray& regs, const A64Unicorn::VectorArray& vecs, const size_t instructions_start, const std::vector& instructions, const u32 pstate, const u32 fpcr) { jit_env.code_mem = instructions; uni_env.code_mem = instructions; jit_env.code_mem.emplace_back(0x14000000); // B . @@ -269,16 +269,13 @@ static void RunTestInstance(Dynarmic::A64::Jit& jit, A64Unicorn& uni, A64TestEnv fmt::print("\n"); const auto get_code = [&jit_env](u64 vaddr) { return jit_env.MemoryReadCode(vaddr); }; - IR::Block ir_block = A64::Translate({instructions_start, FP::FPCR{fpcr}}, get_code, {}); - fmt::print("IR:\n"); - fmt::print("{}\n", IR::DumpBlock(ir_block)); + const A64::LocationDescriptor location{instructions_start, FP::FPCR{fpcr}}; + IR::Block ir_block{location}; + A64::Translate(ir_block, location, get_code, {}); + fmt::print("IR:\n{}\n", IR::DumpBlock(ir_block)); Optimization::Optimize(ir_block, conf, {}); - fmt::print("Optimized IR:\n"); - fmt::print("{}\n", IR::DumpBlock(ir_block)); - - fmt::print("x86_64:\n"); - fmt::print("{}", jit.Disassemble()); - + fmt::print("Optimized IR:\n{}\n", IR::DumpBlock(ir_block)); + fmt::print("x86_64:\n{}", jit.Disassemble()); fmt::print("Interrupts:\n"); for (auto& i : uni_env.interrupts) { puts(i.c_str()); @@ -304,7 +301,8 @@ TEST_CASE("A64: Single random instruction", "[a64][unicorn]") { A64TestEnv jit_env{}; A64TestEnv uni_env{}; - Dynarmic::A64::Jit jit{GetUserConfig(jit_env)}; + Dynarmic::A64::UserConfig conf{GetUserConfig(jit_env)}; + Dynarmic::A64::Jit jit{conf}; A64Unicorn uni{uni_env}; A64Unicorn::RegisterArray regs; @@ -323,7 +321,7 @@ TEST_CASE("A64: Single random instruction", "[a64][unicorn]") { INFO("Instruction: 0x" << std::hex << instructions[0]); - RunTestInstance(jit, uni, jit_env, uni_env, regs, vecs, start_address, instructions, pstate, fpcr); + RunTestInstance(jit, uni, jit_env, uni_env, conf, regs, vecs, start_address, instructions, pstate, fpcr); } } @@ -331,7 +329,8 @@ TEST_CASE("A64: Floating point instructions", "[a64][unicorn]") { A64TestEnv jit_env{}; A64TestEnv uni_env{}; - Dynarmic::A64::Jit jit{GetUserConfig(jit_env)}; + Dynarmic::A64::UserConfig conf{GetUserConfig(jit_env)}; + Dynarmic::A64::Jit jit{conf}; A64Unicorn uni{uni_env}; static constexpr std::array float_numbers{ @@ -448,7 +447,7 @@ TEST_CASE("A64: Floating point instructions", "[a64][unicorn]") { INFO("Instruction: 0x" << std::hex << instructions[0]); - RunTestInstance(jit, uni, jit_env, uni_env, regs, vecs, start_address, instructions, pstate, fpcr); + RunTestInstance(jit, uni, jit_env, uni_env, conf, regs, vecs, start_address, instructions, pstate, fpcr); } } @@ -456,7 +455,8 @@ TEST_CASE("A64: Small random block", "[a64][unicorn]") { A64TestEnv jit_env{}; A64TestEnv uni_env{}; - Dynarmic::A64::Jit jit{GetUserConfig(jit_env)}; + Dynarmic::A64::UserConfig conf{GetUserConfig(jit_env)}; + Dynarmic::A64::Jit jit{conf}; A64Unicorn uni{uni_env}; A64Unicorn::RegisterArray regs; @@ -483,7 +483,7 @@ TEST_CASE("A64: Small random block", "[a64][unicorn]") { INFO("Instruction 4: 0x" << std::hex << instructions[3]); INFO("Instruction 5: 0x" << std::hex << instructions[4]); - RunTestInstance(jit, uni, jit_env, uni_env, regs, vecs, start_address, instructions, pstate, fpcr); + RunTestInstance(jit, uni, jit_env, uni_env, conf, regs, vecs, start_address, instructions, pstate, fpcr); } } @@ -491,7 +491,8 @@ TEST_CASE("A64: Large random block", "[a64][unicorn]") { A64TestEnv jit_env{}; A64TestEnv uni_env{}; - Dynarmic::A64::Jit jit{GetUserConfig(jit_env)}; + Dynarmic::A64::UserConfig conf{GetUserConfig(jit_env)}; + Dynarmic::A64::Jit jit{conf}; A64Unicorn uni{uni_env}; A64Unicorn::RegisterArray regs; @@ -512,6 +513,6 @@ TEST_CASE("A64: Large random block", "[a64][unicorn]") { const u32 pstate = RandInt(0, 0xF) << 28; const u32 fpcr = RandomFpcr(); - RunTestInstance(jit, uni, jit_env, uni_env, regs, vecs, start_address, instructions, pstate, fpcr); + RunTestInstance(jit, uni, jit_env, uni_env, conf, regs, vecs, start_address, instructions, pstate, fpcr); } } diff --git a/src/dynarmic/tests/A64/misaligned_page_table.cpp b/src/dynarmic/tests/A64/misaligned_page_table.cpp index fc0bc77428..99afba519d 100644 --- a/src/dynarmic/tests/A64/misaligned_page_table.cpp +++ b/src/dynarmic/tests/A64/misaligned_page_table.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -8,8 +8,8 @@ #include -#include "./testenv.h" -#include "../native/testenv.h" +#include "dynarmic/tests/A64/testenv.h" +#include "dynarmic/tests/native/testenv.h" #include "dynarmic/interface/A64/a64.h" TEST_CASE("misaligned load/store do not use page_table when detect_misaligned_access_via_page_table is set", "[a64]") { diff --git a/src/dynarmic/tests/A64/real_world.cpp b/src/dynarmic/tests/A64/real_world.cpp index a083f16d61..c15f307c3d 100644 --- a/src/dynarmic/tests/A64/real_world.cpp +++ b/src/dynarmic/tests/A64/real_world.cpp @@ -1,11 +1,11 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later #include #include -#include "./testenv.h" -#include "../native/testenv.h" +#include "dynarmic/tests/A64/testenv.h" +#include "dynarmic/tests/native/testenv.h" #include "dynarmic/interface/A64/a64.h" using namespace Dynarmic; diff --git a/src/dynarmic/tests/A64/test_invalidation.cpp b/src/dynarmic/tests/A64/test_invalidation.cpp index 0c92f5f606..3b2d5fef98 100644 --- a/src/dynarmic/tests/A64/test_invalidation.cpp +++ b/src/dynarmic/tests/A64/test_invalidation.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -8,8 +8,8 @@ #include -#include "./testenv.h" -#include "../native/testenv.h" +#include "dynarmic/tests/A64/testenv.h" +#include "dynarmic/tests/native/testenv.h" #include "dynarmic/interface/A64/a64.h" using namespace Dynarmic; diff --git a/src/dynarmic/tests/A64/verify_unicorn.cpp b/src/dynarmic/tests/A64/verify_unicorn.cpp index 0c0ccc1609..5bdcd0dc3e 100644 --- a/src/dynarmic/tests/A64/verify_unicorn.cpp +++ b/src/dynarmic/tests/A64/verify_unicorn.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + /* This file is part of the dynarmic project. * Copyright (c) 2018 MerryMage * SPDX-License-Identifier: 0BSD @@ -7,9 +10,9 @@ #include -#include "../rand_int.h" -#include "../unicorn_emu/a64_unicorn.h" -#include "./testenv.h" +#include "dynarmic/tests/rand_int.h" +#include "dynarmic/tests/unicorn_emu/a64_unicorn.h" +#include "dynarmic/tests/A64/testenv.h" using namespace Dynarmic; diff --git a/src/dynarmic/tests/fp/FPToFixed.cpp b/src/dynarmic/tests/fp/FPToFixed.cpp index 570ebcbbd7..e16e4460ed 100644 --- a/src/dynarmic/tests/fp/FPToFixed.cpp +++ b/src/dynarmic/tests/fp/FPToFixed.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -12,7 +12,7 @@ #include #include "dynarmic/common/common_types.h" -#include "../rand_int.h" +#include "dynarmic/tests/rand_int.h" #include "dynarmic/common/fp/fpcr.h" #include "dynarmic/common/fp/fpsr.h" #include "dynarmic/common/fp/op.h" diff --git a/src/dynarmic/tests/fp/mantissa_util_tests.cpp b/src/dynarmic/tests/fp/mantissa_util_tests.cpp index de29d51865..9d16c3624c 100644 --- a/src/dynarmic/tests/fp/mantissa_util_tests.cpp +++ b/src/dynarmic/tests/fp/mantissa_util_tests.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -12,7 +12,7 @@ #include #include "dynarmic/common/common_types.h" -#include "../rand_int.h" +#include "dynarmic/tests/rand_int.h" #include "dynarmic/common/fp/mantissa_util.h" #include "dynarmic/common/safe_ops.h" diff --git a/src/dynarmic/tests/fp/unpacked_tests.cpp b/src/dynarmic/tests/fp/unpacked_tests.cpp index 919f21bf2f..a4f10d1273 100644 --- a/src/dynarmic/tests/fp/unpacked_tests.cpp +++ b/src/dynarmic/tests/fp/unpacked_tests.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -12,7 +12,7 @@ #include #include "dynarmic/common/common_types.h" -#include "../rand_int.h" +#include "dynarmic/tests/rand_int.h" #include "dynarmic/common/fp/fpcr.h" #include "dynarmic/common/fp/fpsr.h" #include "dynarmic/common/fp/unpacked.h" diff --git a/src/dynarmic/tests/fuzz_util.cpp b/src/dynarmic/tests/fuzz_util.cpp index 351eb1e10f..05f0a9e865 100644 --- a/src/dynarmic/tests/fuzz_util.cpp +++ b/src/dynarmic/tests/fuzz_util.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -6,7 +6,7 @@ * SPDX-License-Identifier: 0BSD */ -#include "./fuzz_util.h" +#include "dynarmic/tests/fuzz_util.h" #include @@ -14,7 +14,7 @@ #include #include "dynarmic/common/assert.h" -#include "./rand_int.h" +#include "dynarmic/tests/rand_int.h" #include "dynarmic/common/fp/fpcr.h" #include "dynarmic/common/fp/rounding_mode.h" diff --git a/src/dynarmic/tests/native/preserve_xmm.cpp b/src/dynarmic/tests/native/preserve_xmm.cpp index 7421252063..6369e1a74d 100644 --- a/src/dynarmic/tests/native/preserve_xmm.cpp +++ b/src/dynarmic/tests/native/preserve_xmm.cpp @@ -1,12 +1,12 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later #include #include #include -#include "../A64/testenv.h" -#include "../native/testenv.h" +#include "dynarmic/tests/A64/testenv.h" +#include "dynarmic/tests/native/testenv.h" #include "dynarmic/common/fp/fpsr.h" #include "dynarmic/interface/exclusive_monitor.h" diff --git a/src/dynarmic/tests/test_generator.cpp b/src/dynarmic/tests/test_generator.cpp index 4435e762ae..33e41099ff 100644 --- a/src/dynarmic/tests/test_generator.cpp +++ b/src/dynarmic/tests/test_generator.cpp @@ -22,8 +22,8 @@ #include "./A32/testenv.h" #include "./A64/testenv.h" -#include "./fuzz_util.h" -#include "./rand_int.h" +#include "dynarmic/tests/fuzz_util.h" +#include "dynarmic/tests/rand_int.h" #include "dynarmic/common/fp/fpcr.h" #include "dynarmic/common/fp/fpsr.h" #include "dynarmic/common/llvm_disassemble.h" diff --git a/src/dynarmic/tests/unicorn_emu/a32_unicorn.cpp b/src/dynarmic/tests/unicorn_emu/a32_unicorn.cpp index 1a4f1845d5..66c1e7fd24 100644 --- a/src/dynarmic/tests/unicorn_emu/a32_unicorn.cpp +++ b/src/dynarmic/tests/unicorn_emu/a32_unicorn.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -6,22 +6,14 @@ * SPDX-License-Identifier: 0BSD */ -#include "./a32_unicorn.h" - #include - -#include "dynarmic/common/assert.h" +#include #include +#include "dynarmic/tests/unicorn_emu/a32_unicorn.h" +#include "dynarmic/common/assert.h" +#include "dynarmic/tests/A32/testenv.h" -#include "../A32/testenv.h" - -#define CHECKED(expr) \ - do { \ - if (auto cerr_ = (expr)) { \ - ASSERT(false && "Call " #expr " failed with error: {} ({})\n", static_cast(cerr_), \ - uc_strerror(cerr_)); \ - } \ - } while (0) +#define CHECKED(expr) do if ((expr)) ASSERT(false && "Call " #expr " failed with error\n"); while (0) constexpr u32 BEGIN_ADDRESS = 0; constexpr u32 END_ADDRESS = ~u32(0); diff --git a/src/dynarmic/tests/unicorn_emu/a32_unicorn.h b/src/dynarmic/tests/unicorn_emu/a32_unicorn.h index 79831b8111..d94724d9f2 100644 --- a/src/dynarmic/tests/unicorn_emu/a32_unicorn.h +++ b/src/dynarmic/tests/unicorn_emu/a32_unicorn.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -21,7 +21,7 @@ #include "dynarmic/common/common_types.h" -#include "../A32/testenv.h" +#include "dynarmic/tests/A32/testenv.h" namespace Unicorn::A32 { static constexpr size_t num_gprs = 16; diff --git a/src/dynarmic/tests/unicorn_emu/a64_unicorn.cpp b/src/dynarmic/tests/unicorn_emu/a64_unicorn.cpp index 3f13377f71..c8aa404199 100644 --- a/src/dynarmic/tests/unicorn_emu/a64_unicorn.cpp +++ b/src/dynarmic/tests/unicorn_emu/a64_unicorn.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -6,17 +6,11 @@ * SPDX-License-Identifier: 0BSD */ -#include "./a64_unicorn.h" - +#include +#include "dynarmic/tests/unicorn_emu/a64_unicorn.h" #include "dynarmic/common/assert.h" -#define CHECKED(expr) \ - do { \ - if (auto cerr_ = (expr)) { \ - ASSERT(false && "Call " #expr " failed with error: {} ({})\n", static_cast(cerr_), \ - uc_strerror(cerr_)); \ - } \ - } while (0) +#define CHECKED(expr) do if ((expr)) ASSERT(false && "Call " #expr " failed with error\n"); while (0) constexpr u64 BEGIN_ADDRESS = 0; constexpr u64 END_ADDRESS = ~u64(0); @@ -172,7 +166,7 @@ void A64Unicorn::DumpMemoryInformation() { void A64Unicorn::InterruptHook(uc_engine* uc, u32 int_number, void* user_data) { auto* this_ = static_cast(user_data); - u32 esr; + u32 esr = 0; //CHECKED(uc_reg_read(uc, UC_ARM64_REG_ESR_EL0, &esr)); auto ec = esr >> 26; diff --git a/src/dynarmic/tests/unicorn_emu/a64_unicorn.h b/src/dynarmic/tests/unicorn_emu/a64_unicorn.h index 54f09c3b28..1bc5b1cb8e 100644 --- a/src/dynarmic/tests/unicorn_emu/a64_unicorn.h +++ b/src/dynarmic/tests/unicorn_emu/a64_unicorn.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -21,7 +21,7 @@ #include "dynarmic/common/common_types.h" -#include "../A64/testenv.h" +#include "dynarmic/tests/A64/testenv.h" class A64Unicorn final { public: From b673dad40d6cb8d72b4260c2a381695f3ee27ac9 Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 23 Mar 2026 18:03:54 +0100 Subject: [PATCH 15/23] [hle/service/nifm] fix pack(pop) warning on clang (#3764) fucks up unity builds, also it's an innocuous trivial change for a warning that should've been fixed a while ago Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3764 Reviewed-by: Maufeat Reviewed-by: crueter Co-authored-by: lizzie Co-committed-by: lizzie --- src/core/hle/service/nifm/nifm.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index 710a95a455..a0302a5841 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp @@ -183,8 +183,8 @@ struct NifmWirelessSettingData { static_assert(sizeof(NifmWirelessSettingData) == 0x70, "NifmWirelessSettingData has incorrect size."); -#pragma pack(push, 1) // This is nn::nifm::detail::sf::NetworkProfileData +#pragma pack(push, 1) struct SfNetworkProfileData { IpSettingData ip_setting_data{}; u128 uuid{}; @@ -196,9 +196,11 @@ struct SfNetworkProfileData { SfWirelessSettingData wireless_setting_data{}; INSERT_PADDING_BYTES(1); }; +#pragma pack(pop) static_assert(sizeof(SfNetworkProfileData) == 0x17C, "SfNetworkProfileData has incorrect size."); // This is nn::nifm::NetworkProfileData +#pragma pack(push, 1) struct NifmNetworkProfileData { u128 uuid{}; std::array network_name{}; @@ -210,8 +212,8 @@ struct NifmNetworkProfileData { NifmWirelessSettingData wireless_setting_data{}; IpSettingData ip_setting_data{}; }; -static_assert(sizeof(NifmNetworkProfileData) == 0x18E, - "NifmNetworkProfileData has incorrect size."); +#pragma pack(pop) +static_assert(sizeof(NifmNetworkProfileData) == 0x18E, "NifmNetworkProfileData has incorrect size."); struct PendingProfile { std::array ssid{}; From 8f770618d27a053b8ce70e7fd5e699885e23325e Mon Sep 17 00:00:00 2001 From: PavelBARABANOV Date: Tue, 24 Mar 2026 01:25:44 +0100 Subject: [PATCH 16/23] [android] Rework of frame pacing mode + Surface mode detection per API level. (#3735) This Pr is a reply to certain issues found on Android due to the new artificial waits inside Vulkan (Frame Pacing Mode); which caused GPU/CPU desync's even if TimelineSemaphore (Adreno's drivers) does a constant check to retain synchronization with each frame-data, removes the yield() for all platforms (remains the same on PC) and aligns a new way to handle the output of video by using native Android tools, such as AGP, which makes a bridge inside Vulkan to Android's Surface (screen) and reduces not only the latency, but also improves the smoothness of each frame processed; currently we quantize the amount of frame processed by hinting the surface on Android space and adjust the heuristics of the old handling (yuzu) and we link it to screen refresh rate; this way we ensure that even if the game moves below the screen's HZ, we can always pick up the cadence by clamping the duration of each frame and using a chrono function to work as internal fernce if performance goes below the game speed requirment or game's frame rate requirements. Co-authored-by: CamilleLaVey Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3735 Reviewed-by: CamilleLaVey Reviewed-by: Lizzie Co-authored-by: PavelBARABANOV Co-committed-by: PavelBARABANOV --- .../settings/model/view/SettingsItem.kt | 9 - .../settings/ui/SettingsFragmentPresenter.kt | 1 - .../org/yuzu/yuzu_emu/ui/main/MainActivity.kt | 2 - .../src/main/jni/emu_window/emu_window.cpp | 186 ++++++++++++++++++ .../app/src/main/jni/emu_window/emu_window.h | 19 ++ .../renderer_vulkan/vk_swapchain.cpp | 16 ++ 6 files changed, 221 insertions(+), 12 deletions(-) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt index a20858f0a9..6f25856cbf 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt @@ -670,15 +670,6 @@ abstract class SettingsItem( valuesId = R.array.dmaAccuracyValues ) ) - put( - SingleChoiceSetting( - IntSetting.FRAME_PACING_MODE, - titleId = R.string.frame_pacing_mode, - descriptionId = R.string.frame_pacing_mode_description, - choicesId = R.array.framePacingModeNames, - valuesId = R.array.framePacingModeValues - ) - ) put( SwitchSetting( BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS, diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index 853e1e3e4b..060a6fe9ae 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -256,7 +256,6 @@ class SettingsFragmentPresenter( add(IntSetting.RENDERER_ACCURACY.key) add(IntSetting.DMA_ACCURACY.key) - add(IntSetting.FRAME_PACING_MODE.key) add(IntSetting.MAX_ANISOTROPY.key) add(IntSetting.RENDERER_VRAM_USAGE_MODE.key) add(IntSetting.RENDERER_ASTC_DECODE_METHOD.key) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt index 02368bfc16..584322df50 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt @@ -86,8 +86,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider { binding = ActivityMainBinding.inflate(layoutInflater) - // Since Android 15, google automatically forces "games" to be 60 hrz - // This ensures the display's max refresh rate is actually used display?.let { val supportedModes = it.supportedModes val maxRefreshRate = supportedModes.maxByOrNull { mode -> mode.refreshRate } diff --git a/src/android/app/src/main/jni/emu_window/emu_window.cpp b/src/android/app/src/main/jni/emu_window/emu_window.cpp index 4e6fd560f4..6886dac172 100644 --- a/src/android/app/src/main/jni/emu_window/emu_window.cpp +++ b/src/android/app/src/main/jni/emu_window/emu_window.cpp @@ -6,8 +6,15 @@ #include +#include +#include +#include +#include +#include + #include "common/android/id_cache.h" #include "common/logging.h" +#include "common/settings.h" #include "input_common/drivers/android.h" #include "input_common/drivers/touch_screen.h" #include "input_common/drivers/virtual_amiibo.h" @@ -22,6 +29,12 @@ void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) { m_window_width = 0; m_window_height = 0; window_info.render_surface = nullptr; + m_last_frame_rate_hint = -1.0f; + m_pending_frame_rate_hint = -1.0f; + m_pending_frame_rate_hint_votes = 0; + m_smoothed_present_rate = 0.0f; + m_last_frame_display_time = {}; + m_pending_frame_rate_since = {}; return; } @@ -32,6 +45,7 @@ void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) { UpdateCurrentFramebufferLayout(m_window_width, m_window_height); window_info.render_surface = reinterpret_cast(surface); + UpdateFrameRateHint(); } void EmuWindow_Android::OnTouchPressed(int id, float x, float y) { @@ -51,6 +65,9 @@ void EmuWindow_Android::OnTouchReleased(int id) { } void EmuWindow_Android::OnFrameDisplayed() { + UpdateObservedFrameRate(); + UpdateFrameRateHint(); + if (!m_first_frame) { Common::Android::RunJNIOnFiber( [&](JNIEnv* env) { EmulationSession::GetInstance().OnEmulationStarted(); }); @@ -58,6 +75,175 @@ void EmuWindow_Android::OnFrameDisplayed() { } } +void EmuWindow_Android::UpdateObservedFrameRate() { + const auto now = Clock::now(); + if (m_last_frame_display_time.time_since_epoch().count() != 0) { + const auto frame_time = std::chrono::duration(now - m_last_frame_display_time); + const float seconds = frame_time.count(); + if (seconds > 0.0f) { + const float instantaneous_rate = 1.0f / seconds; + if (std::isfinite(instantaneous_rate) && instantaneous_rate >= 1.0f && + instantaneous_rate <= 240.0f) { + constexpr float SmoothingFactor = 0.15f; + if (m_smoothed_present_rate <= 0.0f) { + m_smoothed_present_rate = instantaneous_rate; + } else { + m_smoothed_present_rate += + (instantaneous_rate - m_smoothed_present_rate) * SmoothingFactor; + } + } + } + } + m_last_frame_display_time = now; +} + +float EmuWindow_Android::QuantizeFrameRateHint(float frame_rate) { + if (!std::isfinite(frame_rate) || frame_rate <= 0.0f) { + return 0.0f; + } + + frame_rate = std::clamp(frame_rate, 1.0f, 240.0f); + + constexpr float Step = 0.5f; + return std::round(frame_rate / Step) * Step; +} + +float EmuWindow_Android::GetFrameTimeVerifiedHint() const { + if (!EmulationSession::GetInstance().IsRunning()) { + return 0.0f; + } + + const double frame_time_scale = + EmulationSession::GetInstance().System().GetPerfStats().GetLastFrameTimeScale(); + if (!std::isfinite(frame_time_scale) || frame_time_scale <= 0.0) { + return 0.0f; + } + + const float verified_rate = + std::clamp(60.0f / static_cast(frame_time_scale), 0.0f, 240.0f); + return QuantizeFrameRateHint(verified_rate); +} + +float EmuWindow_Android::GetFrameRateHint() const { + const float observed_rate = std::clamp(m_smoothed_present_rate, 0.0f, 240.0f); + const float frame_time_verified_hint = GetFrameTimeVerifiedHint(); + + if (m_last_frame_rate_hint > 0.0f && observed_rate > 0.0f) { + const float tolerance = std::max(m_last_frame_rate_hint * 0.12f, 4.0f); + if (std::fabs(observed_rate - m_last_frame_rate_hint) <= tolerance) { + return m_last_frame_rate_hint; + } + } + + const float observed_hint = QuantizeFrameRateHint(observed_rate); + if (observed_hint > 0.0f) { + if (frame_time_verified_hint > 0.0f) { + const float tolerance = std::max(observed_hint * 0.20f, 3.0f); + if (std::fabs(observed_hint - frame_time_verified_hint) <= tolerance) { + return QuantizeFrameRateHint((observed_hint + frame_time_verified_hint) * 0.5f); + } + } + return observed_hint; + } + + if (frame_time_verified_hint > 0.0f) { + return frame_time_verified_hint; + } + + constexpr float NominalFrameRate = 60.0f; + if (!Settings::values.use_speed_limit.GetValue()) { + return NominalFrameRate; + } + + const u16 speed_limit = Settings::SpeedLimit(); + if (speed_limit == 0) { + return 0.0f; + } + + const float speed_limited_rate = + NominalFrameRate * (static_cast(std::min(speed_limit, 100)) / 100.0f); + return QuantizeFrameRateHint(speed_limited_rate); +} + +void EmuWindow_Android::UpdateFrameRateHint() { + auto* const surface = reinterpret_cast(window_info.render_surface); + if (!surface) { + return; + } + + const auto now = Clock::now(); + const float frame_rate_hint = GetFrameRateHint(); + if (std::fabs(frame_rate_hint - m_last_frame_rate_hint) < 0.01f) { + m_pending_frame_rate_hint = frame_rate_hint; + m_pending_frame_rate_hint_votes = 0; + m_pending_frame_rate_since = {}; + return; + } + + if (frame_rate_hint == 0.0f) { + m_pending_frame_rate_hint = frame_rate_hint; + m_pending_frame_rate_hint_votes = 0; + m_pending_frame_rate_since = now; + } else if (m_last_frame_rate_hint >= 0.0f) { + if (std::fabs(frame_rate_hint - m_pending_frame_rate_hint) >= 0.01f) { + m_pending_frame_rate_hint = frame_rate_hint; + m_pending_frame_rate_hint_votes = 1; + m_pending_frame_rate_since = now; + return; + } + + ++m_pending_frame_rate_hint_votes; + if (m_pending_frame_rate_since.time_since_epoch().count() == 0) { + m_pending_frame_rate_since = now; + } + + const auto stable_for = now - m_pending_frame_rate_since; + const float reference_rate = std::max(frame_rate_hint, 1.0f); + const auto stable_duration = std::chrono::duration_cast( + std::chrono::duration(std::clamp(3.0f / reference_rate, 0.15f, 0.40f))); + constexpr std::uint32_t MinStableVotes = 3; + + if (m_pending_frame_rate_hint_votes < MinStableVotes || stable_for < stable_duration) { + return; + } + } else { + m_pending_frame_rate_since = now; + } + + using SetFrameRateWithChangeStrategyFn = + int32_t (*)(ANativeWindow*, float, int8_t, int8_t); + using SetFrameRateFn = int32_t (*)(ANativeWindow*, float, int8_t); + static const auto set_frame_rate_with_change_strategy = + reinterpret_cast( + dlsym(RTLD_DEFAULT, "ANativeWindow_setFrameRateWithChangeStrategy")); + static const auto set_frame_rate = reinterpret_cast( + dlsym(RTLD_DEFAULT, "ANativeWindow_setFrameRate")); + + constexpr int8_t FrameRateCompatibilityDefault = 0; + constexpr int8_t ChangeFrameRateOnlyIfSeamless = 0; + + int32_t result = -1; + if (set_frame_rate_with_change_strategy) { + result = set_frame_rate_with_change_strategy(surface, frame_rate_hint, + FrameRateCompatibilityDefault, + ChangeFrameRateOnlyIfSeamless); + } else if (set_frame_rate) { + result = set_frame_rate(surface, frame_rate_hint, FrameRateCompatibilityDefault); + } else { + return; + } + + if (result != 0) { + LOG_DEBUG(Frontend, "Failed to update Android surface frame rate hint: {}", result); + return; + } + + m_last_frame_rate_hint = frame_rate_hint; + m_pending_frame_rate_hint = frame_rate_hint; + m_pending_frame_rate_hint_votes = 0; + m_pending_frame_rate_since = {}; +} + EmuWindow_Android::EmuWindow_Android(ANativeWindow* surface, std::shared_ptr driver_library) : m_driver_library{driver_library} { diff --git a/src/android/app/src/main/jni/emu_window/emu_window.h b/src/android/app/src/main/jni/emu_window/emu_window.h index d7b5fc6dac..b73e8b9b4d 100644 --- a/src/android/app/src/main/jni/emu_window/emu_window.h +++ b/src/android/app/src/main/jni/emu_window/emu_window.h @@ -1,8 +1,13 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later #pragma once +#include +#include #include #include @@ -50,10 +55,24 @@ public: }; private: + using Clock = std::chrono::steady_clock; + + void UpdateFrameRateHint(); + void UpdateObservedFrameRate(); + [[nodiscard]] float GetFrameRateHint() const; + [[nodiscard]] float GetFrameTimeVerifiedHint() const; + [[nodiscard]] static float QuantizeFrameRateHint(float frame_rate); + float m_window_width{}; float m_window_height{}; std::shared_ptr m_driver_library; bool m_first_frame = false; + float m_last_frame_rate_hint = -1.0f; + float m_pending_frame_rate_hint = -1.0f; + float m_smoothed_present_rate = 0.0f; + Clock::time_point m_last_frame_display_time{}; + Clock::time_point m_pending_frame_rate_since{}; + std::uint32_t m_pending_frame_rate_hint_votes = 0; }; diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index 5d55cf551b..0e4c274d94 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp @@ -9,6 +9,10 @@ #include #include +#ifdef __ANDROID__ +#include +#endif + #include "common/logging.h" #include "common/settings.h" #include "common/settings_enums.h" @@ -170,6 +174,7 @@ bool Swapchain::AcquireNextImage() { break; } + const auto wait_with_frame_pacing = [this] { switch (Settings::values.frame_pacing_mode.GetValue()) { case Settings::FramePacingMode::Target_Auto: scheduler.Wait(resource_ticks[image_index]); @@ -187,6 +192,17 @@ bool Swapchain::AcquireNextImage() { scheduler.Wait(resource_ticks[image_index], 120.0); break; } + }; + +#ifdef __ANDROID__ + if (android_get_device_api_level() >= 30) { + scheduler.Wait(resource_ticks[image_index]); + } else { + wait_with_frame_pacing(); + } +#else + wait_with_frame_pacing(); +#endif resource_ticks[image_index] = scheduler.CurrentTick(); From bc46b957d64d1af5faba283eaaaf7bfbbf2f14ee Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 19 Mar 2026 18:01:48 +0000 Subject: [PATCH 17/23] [dynarmic] exclude %rbp from regalloc Signed-off-by: lizzie --- src/dynarmic/src/dynarmic/backend/x64/reg_alloc.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.cpp b/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.cpp index 5c5ed25131..2cfa14ae18 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.cpp @@ -417,7 +417,8 @@ HostLoc RegAlloc::SelectARegister(std::bitset<32> desired_locations) const noexc // While R13 and R14 are technically available, we avoid allocating for them // at all costs, because theoretically skipping them is better than spilling // all over the place - i also fixes bugs with high reg pressure - } else if (i >= HostLoc::R13 && i <= HostLoc::R15) { + // %rbp must not be trashed, so skip it as well + } else if (i == HostLoc::RBP || (i >= HostLoc::R13 && i <= HostLoc::R15)) { // skip, do not touch // Intel recommends to reuse registers as soon as they're overwritable (DO NOT SPILL) } else if (loc_info.IsEmpty()) { From c88da9d9a4e137b9773e40b65588fe0d5390eb16 Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 19 Mar 2026 18:05:07 +0000 Subject: [PATCH 18/23] fx --- src/dynarmic/src/dynarmic/backend/x64/abi.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/dynarmic/src/dynarmic/backend/x64/abi.cpp b/src/dynarmic/src/dynarmic/backend/x64/abi.cpp index 413af7b557..b7faaff911 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/abi.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/abi.cpp @@ -47,6 +47,8 @@ void ABI_PushRegistersAndAdjustStack(BlockOfCode& code, const size_t frame_size, const size_t num_xmms = (ABI_ALL_XMMS & regs).count(); const FrameInfo frame_info = CalculateFrameInfo(num_gprs, num_xmms, frame_size); + code.push(rbp); + code.mov(rbp, rsp); for (size_t i = 0; i < regs.size(); ++i) if (regs[i] && HostLocIsGPR(HostLoc(i))) code.push(HostLocToReg64(HostLoc(i))); @@ -87,6 +89,7 @@ void ABI_PopRegistersAndAdjustStack(BlockOfCode& code, const size_t frame_size, for (int32_t i = regs.size() - 1; i >= 0; --i) if (regs[i] && HostLocIsGPR(HostLoc(i))) code.pop(HostLocToReg64(HostLoc(i))); + code.pop(rbp); } void ABI_PushCalleeSaveRegistersAndAdjustStack(BlockOfCode& code, const std::size_t frame_size) { From bbea91f8dcdc93143c1acf3580be8e469c71ec28 Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 19 Mar 2026 22:01:23 +0000 Subject: [PATCH 19/23] ok fix for winshit --- src/dynarmic/src/dynarmic/backend/x64/abi.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dynarmic/src/dynarmic/backend/x64/abi.cpp b/src/dynarmic/src/dynarmic/backend/x64/abi.cpp index b7faaff911..e3e54989a5 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/abi.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/abi.cpp @@ -43,7 +43,7 @@ static FrameInfo CalculateFrameInfo(const size_t num_gprs, const size_t num_xmms void ABI_PushRegistersAndAdjustStack(BlockOfCode& code, const size_t frame_size, std::bitset<32> const& regs) { using namespace Xbyak::util; - const size_t num_gprs = (ABI_ALL_GPRS & regs).count(); + const size_t num_gprs = (ABI_ALL_GPRS & regs).count() + 1; const size_t num_xmms = (ABI_ALL_XMMS & regs).count(); const FrameInfo frame_info = CalculateFrameInfo(num_gprs, num_xmms, frame_size); @@ -70,7 +70,7 @@ void ABI_PushRegistersAndAdjustStack(BlockOfCode& code, const size_t frame_size, void ABI_PopRegistersAndAdjustStack(BlockOfCode& code, const size_t frame_size, std::bitset<32> const& regs) { using namespace Xbyak::util; - const size_t num_gprs = (ABI_ALL_GPRS & regs).count(); + const size_t num_gprs = (ABI_ALL_GPRS & regs).count() + 1; const size_t num_xmms = (ABI_ALL_XMMS & regs).count(); const FrameInfo frame_info = CalculateFrameInfo(num_gprs, num_xmms, frame_size); From 0c721ec41ffe69ecd64bf28c36d472868919d1e2 Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 19 Mar 2026 22:27:47 +0000 Subject: [PATCH 20/23] pot fix --- .../src/dynarmic/backend/x64/a64_emit_x64.cpp | 7 ++++++ src/dynarmic/src/dynarmic/backend/x64/abi.cpp | 7 ++---- .../backend/x64/exception_handler_windows.cpp | 24 +++++++++---------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp index ff82d8b05c..eab6fc038a 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp @@ -90,6 +90,10 @@ A64EmitX64::BlockDescriptor A64EmitX64::Emit(IR::Block& block) noexcept { code.align(); const auto* const entrypoint = code.getCurr(); + code.push(rbp); + code.mov(rbp, rsp); + code.and_(rsp, -16); + DEBUG_ASSERT(block.GetCondition() == IR::Cond::AL); typedef void (EmitX64::*EmitHandlerFn)(EmitContext& context, IR::Inst* inst); constexpr EmitHandlerFn opcode_handlers[] = { @@ -248,6 +252,9 @@ void A64EmitX64::GenTerminalHandlers() { } code.and_(code.ABI_PARAM1.cvt32(), fast_dispatch_table_mask); code.lea(code.ABI_RETURN, code.ptr[code.ABI_PARAM2 + code.ABI_PARAM1]); + + code.mov(rsp, rbp); + code.pop(rbp); code.ret(); PerfMapRegister(fast_dispatch_table_lookup, code.getCurr(), "a64_fast_dispatch_table_lookup"); } diff --git a/src/dynarmic/src/dynarmic/backend/x64/abi.cpp b/src/dynarmic/src/dynarmic/backend/x64/abi.cpp index e3e54989a5..413af7b557 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/abi.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/abi.cpp @@ -43,12 +43,10 @@ static FrameInfo CalculateFrameInfo(const size_t num_gprs, const size_t num_xmms void ABI_PushRegistersAndAdjustStack(BlockOfCode& code, const size_t frame_size, std::bitset<32> const& regs) { using namespace Xbyak::util; - const size_t num_gprs = (ABI_ALL_GPRS & regs).count() + 1; + const size_t num_gprs = (ABI_ALL_GPRS & regs).count(); const size_t num_xmms = (ABI_ALL_XMMS & regs).count(); const FrameInfo frame_info = CalculateFrameInfo(num_gprs, num_xmms, frame_size); - code.push(rbp); - code.mov(rbp, rsp); for (size_t i = 0; i < regs.size(); ++i) if (regs[i] && HostLocIsGPR(HostLoc(i))) code.push(HostLocToReg64(HostLoc(i))); @@ -70,7 +68,7 @@ void ABI_PushRegistersAndAdjustStack(BlockOfCode& code, const size_t frame_size, void ABI_PopRegistersAndAdjustStack(BlockOfCode& code, const size_t frame_size, std::bitset<32> const& regs) { using namespace Xbyak::util; - const size_t num_gprs = (ABI_ALL_GPRS & regs).count() + 1; + const size_t num_gprs = (ABI_ALL_GPRS & regs).count(); const size_t num_xmms = (ABI_ALL_XMMS & regs).count(); const FrameInfo frame_info = CalculateFrameInfo(num_gprs, num_xmms, frame_size); @@ -89,7 +87,6 @@ void ABI_PopRegistersAndAdjustStack(BlockOfCode& code, const size_t frame_size, for (int32_t i = regs.size() - 1; i >= 0; --i) if (regs[i] && HostLocIsGPR(HostLoc(i))) code.pop(HostLocToReg64(HostLoc(i))); - code.pop(rbp); } void ABI_PushCalleeSaveRegistersAndAdjustStack(BlockOfCode& code, const std::size_t frame_size) { diff --git a/src/dynarmic/src/dynarmic/backend/x64/exception_handler_windows.cpp b/src/dynarmic/src/dynarmic/backend/x64/exception_handler_windows.cpp index 3ae553bccd..bae397ff2b 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/exception_handler_windows.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/exception_handler_windows.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -176,7 +176,7 @@ struct ExceptionHandler::Impl final { code.align(16); const u8* exception_handler_without_cb = code.getCurr(); - code.mov(code.eax, static_cast(ExceptionContinueSearch)); + code.mov(code.eax, u32(ExceptionContinueSearch)); code.ret(); code.align(16); @@ -192,20 +192,18 @@ struct ExceptionHandler::Impl final { code.lea(code.rsp, code.ptr[code.rsp - 8]); code.mov(code.ABI_PARAM1, std::bit_cast(&cb)); code.mov(code.ABI_PARAM2, code.ABI_PARAM3); - code.CallLambda( - [](const std::function& cb_, PCONTEXT ctx) { - FakeCall fc = cb_(ctx->Rip); - - ctx->Rsp -= sizeof(u64); - *std::bit_cast(ctx->Rsp) = fc.ret_rip; - ctx->Rip = fc.call_rip; - }); + code.CallLambda([](const std::function& cb_, PCONTEXT ctx) { + FakeCall fc = cb_(ctx->Rip); + ctx->Rsp -= sizeof(u64); + *std::bit_cast(ctx->Rsp) = fc.ret_rip; + ctx->Rip = fc.call_rip; + }); code.add(code.rsp, 8); - code.mov(code.eax, static_cast(ExceptionContinueExecution)); + code.mov(code.eax, u32(ExceptionContinueExecution)); code.ret(); - exception_handler_without_cb_offset = static_cast(exception_handler_without_cb - code.getCode()); - exception_handler_with_cb_offset = static_cast(exception_handler_with_cb - code.getCode()); + exception_handler_without_cb_offset = ULONG(exception_handler_without_cb - code.getCode()); + exception_handler_with_cb_offset = ULONG(exception_handler_with_cb - code.getCode()); code.align(16); UNWIND_INFO* unwind_info = static_cast(code.AllocateFromCodeSpace(sizeof(UNWIND_INFO))); From 3f6533602028394a5aead52eaef361d6248d018c Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 19 Mar 2026 22:50:39 +0000 Subject: [PATCH 21/23] tes1 --- .../src/dynarmic/backend/x64/a64_emit_x64.cpp | 11 +++++------ src/dynarmic/src/dynarmic/backend/x64/stack_layout.h | 4 +--- src/video_core/host_shaders/CMakeLists.txt | 6 +++--- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp index eab6fc038a..d4f9d9daaf 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp @@ -90,9 +90,8 @@ A64EmitX64::BlockDescriptor A64EmitX64::Emit(IR::Block& block) noexcept { code.align(); const auto* const entrypoint = code.getCurr(); - code.push(rbp); - code.mov(rbp, rsp); - code.and_(rsp, -16); + // code.mov(code.qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer)], rbp); + // code.lea(rbp, code.ptr[rsp + ABI_SHADOW_SPACE - 8]); DEBUG_ASSERT(block.GetCondition() == IR::Cond::AL); typedef void (EmitX64::*EmitHandlerFn)(EmitContext& context, IR::Inst* inst); @@ -148,6 +147,9 @@ finish_this_inst: if (conf.enable_cycle_counting) { EmitAddCycles(block.CycleCount()); } + + //code.mov(rbp, code.qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer)]); + EmitTerminal(block.GetTerminal(), ctx.Location().SetSingleStepping(false), ctx.IsSingleStep()); code.int3(); @@ -252,9 +254,6 @@ void A64EmitX64::GenTerminalHandlers() { } code.and_(code.ABI_PARAM1.cvt32(), fast_dispatch_table_mask); code.lea(code.ABI_RETURN, code.ptr[code.ABI_PARAM2 + code.ABI_PARAM1]); - - code.mov(rsp, rbp); - code.pop(rbp); code.ret(); PerfMapRegister(fast_dispatch_table_lookup, code.getCurr(), "a64_fast_dispatch_table_lookup"); } diff --git a/src/dynarmic/src/dynarmic/backend/x64/stack_layout.h b/src/dynarmic/src/dynarmic/backend/x64/stack_layout.h index 50737f12eb..13f3de21a1 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/stack_layout.h +++ b/src/dynarmic/src/dynarmic/backend/x64/stack_layout.h @@ -22,13 +22,11 @@ constexpr size_t SpillCount = 64; #endif struct alignas(16) StackLayout { + u64 abi_base_pointer; s64 cycles_remaining; s64 cycles_to_run; - std::array, SpillCount> spill; - u32 save_host_MXCSR; - bool check_bit; }; diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt index 668f939546..55084f0ff8 100644 --- a/src/video_core/host_shaders/CMakeLists.txt +++ b/src/video_core/host_shaders/CMakeLists.txt @@ -135,7 +135,7 @@ foreach(SOURCE_FILE IN ITEMS ${SHADER_FILES}) ${SOURCE_FILE} DEPENDS ${INPUT_FILE} - ${SHADER_DIR} + # ${SHADER_DIR} # HEADER_GENERATOR should be included here but msbuild seems to assume it's always modified ) set(SHADER_HEADERS ${SHADER_HEADERS} ${SOURCE_HEADER_FILE}) @@ -151,8 +151,8 @@ foreach(SOURCE_FILE IN ITEMS ${SHADER_FILES}) ${GLSLANGVALIDATOR} -V ${QUIET_FLAG} -I"${FIDELITYFX_INCLUDE_DIR}" ${GLSL_FLAGS} --variable-name ${SPIRV_VARIABLE_NAME} -o ${SPIRV_HEADER_FILE} ${SOURCE_FILE} --target-env ${SPIR_V_VERSION} MAIN_DEPENDENCY ${SOURCE_FILE} - DEPENDS - ${SHADER_DIR} + #DEPENDS + # ${SHADER_DIR} ) set(SHADER_HEADERS ${SHADER_HEADERS} ${SPIRV_HEADER_FILE}) endif() From 93da9a2e36c396ffdd0c99b0dfa0a451f5f8fe89 Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 19 Mar 2026 23:01:27 +0000 Subject: [PATCH 22/23] fix %rbp --- .../src/dynarmic/backend/x64/a32_emit_x64.cpp | 9 +++++---- .../src/dynarmic/backend/x64/a64_emit_x64.cpp | 17 +++++------------ .../src/dynarmic/backend/x64/stack_layout.h | 5 +++-- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp b/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp index f037919eb0..cd89b89156 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp @@ -115,6 +115,8 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) { // Start emitting. code.align(); const u8* const entrypoint = code.getCurr(); + code.mov(code.qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer)], rbp); + code.lea(rbp, code.ptr[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer) - 8]); EmitCondPrelude(ctx); @@ -147,15 +149,14 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) { reg_alloc.AssertNoMoreUses(); - if (conf.enable_cycle_counting) { + if (conf.enable_cycle_counting) EmitAddCycles(block.CycleCount()); - } + code.mov(rbp, code.qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer)]); EmitTerminal(block.GetTerminal(), ctx.Location().SetSingleStepping(false), ctx.IsSingleStep()); code.int3(); - for (auto& deferred_emit : ctx.deferred_emits) { + for (auto& deferred_emit : ctx.deferred_emits) deferred_emit(); - } code.int3(); const size_t size = size_t(code.getCurr() - entrypoint); diff --git a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp index d4f9d9daaf..f59026929e 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp @@ -89,9 +89,8 @@ A64EmitX64::BlockDescriptor A64EmitX64::Emit(IR::Block& block) noexcept { // Start emitting. code.align(); const auto* const entrypoint = code.getCurr(); - - // code.mov(code.qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer)], rbp); - // code.lea(rbp, code.ptr[rsp + ABI_SHADOW_SPACE - 8]); + code.mov(code.qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer)], rbp); + code.lea(rbp, code.ptr[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer) - 8]); DEBUG_ASSERT(block.GetCondition() == IR::Cond::AL); typedef void (EmitX64::*EmitHandlerFn)(EmitContext& context, IR::Inst* inst); @@ -143,19 +142,13 @@ finish_this_inst: } reg_alloc.AssertNoMoreUses(); - - if (conf.enable_cycle_counting) { + if (conf.enable_cycle_counting) EmitAddCycles(block.CycleCount()); - } - - //code.mov(rbp, code.qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer)]); - + code.mov(rbp, code.qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, abi_base_pointer)]); EmitTerminal(block.GetTerminal(), ctx.Location().SetSingleStepping(false), ctx.IsSingleStep()); code.int3(); - - for (auto& deferred_emit : ctx.deferred_emits) { + for (auto& deferred_emit : ctx.deferred_emits) deferred_emit(); - } code.int3(); const size_t size = size_t(code.getCurr() - entrypoint); diff --git a/src/dynarmic/src/dynarmic/backend/x64/stack_layout.h b/src/dynarmic/src/dynarmic/backend/x64/stack_layout.h index 13f3de21a1..6e0efb5be0 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/stack_layout.h +++ b/src/dynarmic/src/dynarmic/backend/x64/stack_layout.h @@ -22,12 +22,13 @@ constexpr size_t SpillCount = 64; #endif struct alignas(16) StackLayout { - u64 abi_base_pointer; + // Needs alignment for VMOV and XMM spills + alignas(16) std::array, SpillCount> spill; s64 cycles_remaining; s64 cycles_to_run; - std::array, SpillCount> spill; u32 save_host_MXCSR; bool check_bit; + u64 abi_base_pointer; }; #ifdef _MSC_VER From d51284ce57c0854b15133af76ffca2e9f8effc93 Mon Sep 17 00:00:00 2001 From: lizzie Date: Fri, 20 Mar 2026 07:22:23 +0000 Subject: [PATCH 23/23] license --- src/dynarmic/src/dynarmic/backend/x64/stack_layout.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dynarmic/src/dynarmic/backend/x64/stack_layout.h b/src/dynarmic/src/dynarmic/backend/x64/stack_layout.h index 6e0efb5be0..43a3fc7ab2 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/stack_layout.h +++ b/src/dynarmic/src/dynarmic/backend/x64/stack_layout.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project.