From 811cc18d7489c6faac9ddff9280c1e870e09e9af Mon Sep 17 00:00:00 2001 From: lizzie Date: Sun, 22 Mar 2026 17:37:21 +0100 Subject: [PATCH 1/9] [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 2/9] [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 3/9] [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 4/9] [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 5/9] [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 6/9] [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 24fe223692af988770bcc336d5b1138a2ba91399 Mon Sep 17 00:00:00 2001 From: lizzie Date: Wed, 25 Mar 2026 10:48:53 +0100 Subject: [PATCH 7/9] [dynarmic] Remove last FPT LUT table, removing around 30kb worth of unused functions (#3718) Lets do the quick math There was 1 LUT for every fsize() instancing Now... the number of functions on each lut was (fsize + 1), multiplied by 5 (number of rounding modes) 8 = 9 * 5 = 45 16 = 17 * 5 = 85 32 = 33 * 5 = 165 64 = 65 * 5 = 325 this is just pure insanity - look at what fucking nm reported: ``` 0000000003dc39b8 0000000000000008 V guard variable for void Dynarmic::Backend::X64::EmitFPVectorToFixed<16ul, false>(Dynarmic::Backend::X64::BlockOfCode&, Dynarmic::Backend::X64::EmitContext&, Dynarmic::IR::Inst*)::lut 0000000003dc3a18 0000000000000008 V guard variable for void Dynarmic::Backend::X64::EmitFPVectorToFixed<16ul, true>(Dynarmic::Backend::X64::BlockOfCode&, Dynarmic::Backend::X64::EmitContext&, Dynarmic::IR::Inst*)::lut 0000000003dc39d8 0000000000000008 V guard variable for void Dynarmic::Backend::X64::EmitFPVectorToFixed<32ul, false>(Dynarmic::Backend::X64::BlockOfCode&, Dynarmic::Backend::X64::EmitContext&, Dynarmic::IR::Inst*)::lut 0000000003dc3a38 0000000000000008 V guard variable for void Dynarmic::Backend::X64::EmitFPVectorToFixed<32ul, true>(Dynarmic::Backend::X64::BlockOfCode&, Dynarmic::Backend::X64::EmitContext&, Dynarmic::IR::Inst*)::lut 0000000003dc39f8 0000000000000008 V guard variable for void Dynarmic::Backend::X64::EmitFPVectorToFixed<64ul, false>(Dynarmic::Backend::X64::BlockOfCode&, Dynarmic::Backend::X64::EmitContext&, Dynarmic::IR::Inst*)::lut 0000000003dc3a58 0000000000000008 V guard variable for void Dynarmic::Backend::X64::EmitFPVectorToFixed<64ul, true>(Dynarmic::Backend::X64::BlockOfCode&, Dynarmic::Backend::X64::EmitContext&, Dynarmic::IR::Inst*)::lut ``` "ah its not bad" - OH MATE ITS JUST THE GUARD VARIABLES - i attached a file with just the functions generated for each case... now with this PR only 6 * 6 functions are made (still not ideal, but way better), 36 is way better than 1156 FUCKING FUNCTIONS Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3718 Reviewed-by: DraVee Reviewed-by: Maufeat Co-authored-by: lizzie Co-committed-by: lizzie --- src/dynarmic/src/dynarmic/CMakeLists.txt | 1 - .../emit_arm64_vector_floating_point.cpp | 3 +- .../backend/x64/emit_x64_floating_point.cpp | 1 - .../x64/emit_x64_vector_floating_point.cpp | 57 ++++++++++++------- .../src/dynarmic/common/lut_from_list.h | 55 ------------------ 5 files changed, 36 insertions(+), 81 deletions(-) delete mode 100644 src/dynarmic/src/dynarmic/common/lut_from_list.h diff --git a/src/dynarmic/src/dynarmic/CMakeLists.txt b/src/dynarmic/src/dynarmic/CMakeLists.txt index 3d2ea4d42e..50bf5a4604 100644 --- a/src/dynarmic/src/dynarmic/CMakeLists.txt +++ b/src/dynarmic/src/dynarmic/CMakeLists.txt @@ -53,7 +53,6 @@ add_library(dynarmic STATIC common/fp/util.h common/llvm_disassemble.cpp common/llvm_disassemble.h - common/lut_from_list.h common/math_util.cpp common/math_util.h common/safe_ops.h diff --git a/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_vector_floating_point.cpp b/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_vector_floating_point.cpp index 4d11c62abd..431d51c081 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_vector_floating_point.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_vector_floating_point.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. @@ -31,7 +31,6 @@ #include "dynarmic/common/fp/info.h" #include "dynarmic/common/fp/op.h" #include "dynarmic/common/fp/rounding_mode.h" -#include "dynarmic/common/lut_from_list.h" #include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/microinstruction.h" #include "dynarmic/ir/opcodes.h" diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_floating_point.cpp b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_floating_point.cpp index 76c103ec6f..abe04b53ff 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_floating_point.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_floating_point.cpp @@ -31,7 +31,6 @@ #include "dynarmic/common/fp/info.h" #include "dynarmic/common/fp/op.h" #include "dynarmic/common/fp/rounding_mode.h" -#include "dynarmic/common/lut_from_list.h" #include "dynarmic/interface/optimization_flags.h" #include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/microinstruction.h" diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp index 2247b18fcd..ee9ec39f46 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp @@ -31,7 +31,6 @@ #include "dynarmic/common/fp/info.h" #include "dynarmic/common/fp/op.h" #include "dynarmic/common/fp/util.h" -#include "dynarmic/common/lut_from_list.h" #include "dynarmic/interface/optimization_flags.h" #include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/microinstruction.h" @@ -2127,28 +2126,42 @@ void EmitFPVectorToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) { } } - using fbits_list = mp::lift_sequence>; - using rounding_list = mp::list< - mp::lift_value, - mp::lift_value, - mp::lift_value, - mp::lift_value, - mp::lift_value>; - - static const auto lut = Common::GenerateLookupTableFromList([](I) { - using FPT = mcl::unsigned_integer_of_size; // WORKAROUND: For issue 678 on MSVC - return std::pair{ - mp::lower_to_tuple_v, - Common::FptrCast([](VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { - constexpr size_t fbits = mp::get<0, I>::value; - constexpr FP::RoundingMode rounding_mode = mp::get<1, I>::value; + using FPT = mcl::unsigned_integer_of_size; // WORKAROUND: For issue 678 on MSVC + auto const func = [rounding]() -> void(*)(VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { + switch (rounding) { + case FP::RoundingMode::ToNearest_TieEven: + return [](VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { for (size_t i = 0; i < output.size(); ++i) - output[i] = FPT(FP::FPToFixed(fsize, input[i], fbits, unsigned_, fpcr, rounding_mode, fpsr)); - }) - }; - }, mp::cartesian_product{}); - - EmitTwoOpFallback<3>(code, ctx, inst, lut.at(std::make_tuple(fbits, rounding))); + output[i] = FPT(FP::FPToFixed(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::ToNearest_TieEven, fpsr)); + }; + case FP::RoundingMode::TowardsPlusInfinity: + return [](VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { + for (size_t i = 0; i < output.size(); ++i) + output[i] = FPT(FP::FPToFixed(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::TowardsPlusInfinity, fpsr)); + }; + case FP::RoundingMode::TowardsMinusInfinity: + return [](VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { + for (size_t i = 0; i < output.size(); ++i) + output[i] = FPT(FP::FPToFixed(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::TowardsMinusInfinity, fpsr)); + }; + case FP::RoundingMode::TowardsZero: + return [](VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { + for (size_t i = 0; i < output.size(); ++i) + output[i] = FPT(FP::FPToFixed(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::TowardsZero, fpsr)); + }; + case FP::RoundingMode::ToNearest_TieAwayFromZero: + return [](VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { + for (size_t i = 0; i < output.size(); ++i) + output[i] = FPT(FP::FPToFixed(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::ToNearest_TieAwayFromZero, fpsr)); + }; + case FP::RoundingMode::ToOdd: + return [](VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { + for (size_t i = 0; i < output.size(); ++i) + output[i] = FPT(FP::FPToFixed(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::ToOdd, fpsr)); + }; + } + }(); + EmitTwoOpFallback<3>(code, ctx, inst, func); } void EmitX64::EmitFPVectorToSignedFixed16(EmitContext& ctx, IR::Inst* inst) { diff --git a/src/dynarmic/src/dynarmic/common/lut_from_list.h b/src/dynarmic/src/dynarmic/common/lut_from_list.h deleted file mode 100644 index 633b62aeda..0000000000 --- a/src/dynarmic/src/dynarmic/common/lut_from_list.h +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2025 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 - */ - -#pragma once - -#include -#include -#include - -#include -#include -#include - -#ifdef _MSC_VER -# include -#endif - -namespace Dynarmic::Common { - -// prevents this function from printing 56,000 character warning messages -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wno-stack-usage" -#endif -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wno-stack-usage" -#endif - -template -inline auto GenerateLookupTableFromList(Function f, mcl::mp::list) { -#ifdef _MSC_VER - using PairT = std::invoke_result_t>>; -#else - using PairT = std::common_type_t...>; -#endif - using MapT = mcl::mp::apply; - static_assert(mcl::is_instance_of_template_v); - const std::initializer_list pair_array{f(Values{})...}; - return MapT(pair_array.begin(), pair_array.end()); -} - -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -} // namespace Dynarmic::Common From f0d77e86e34cde3813f7b1dbfc4d1a9e8940b21b Mon Sep 17 00:00:00 2001 From: xbzk Date: Wed, 25 Mar 2026 12:13:04 +0100 Subject: [PATCH 8/9] [android,ui] driver management: fixed driver add/removal unsync (#3757) Complementary for 3750. User found a way to get same driver doubled and deleting one would lead to a crash. Reason: manual driver install was still adding drivers directly to adapter, instead of thru drivermodel. fixed. Also added guards against crash upon driver removal. Thoroughly tested. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3757 Reviewed-by: Maufeat Reviewed-by: MaranBr Co-authored-by: xbzk Co-committed-by: xbzk --- .../fragments/DriverManagerFragment.kt | 13 +++++++----- .../yuzu/yuzu_emu/model/DriverViewModel.kt | 21 ++++++++++++++++--- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt index 877097dc80..3aa55522e6 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt @@ -29,7 +29,6 @@ import org.yuzu.yuzu_emu.databinding.FragmentDriverManagerBinding import org.yuzu.yuzu_emu.features.settings.model.Settings import org.yuzu.yuzu_emu.features.settings.model.StringSetting import org.yuzu.yuzu_emu.features.settings.ui.SettingsSubscreen -import org.yuzu.yuzu_emu.model.Driver.Companion.toDriver import org.yuzu.yuzu_emu.model.DriverViewModel import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.utils.FileUtil @@ -216,19 +215,23 @@ class DriverManagerFragment : Fragment() { val driverData = GpuDriverHelper.getMetadataFromZip(driverFile) val driverInList = - driverViewModel.driverData.firstOrNull { it.second == driverData } + driverViewModel.driverData.firstOrNull { + it.first == driverPath || it.second == driverData + } if (driverInList != null) { return@newInstance getString(R.string.driver_already_installed) } else { driverViewModel.onDriverAdded(Pair(driverPath, driverData)) withContext(Dispatchers.Main) { if (_binding != null) { + refreshDriverList() val adapter = binding.listDrivers.adapter as DriverAdapter - adapter.addItem(driverData.toDriver()) - adapter.selectItem(adapter.currentList.indices.last) + val selectedPosition = adapter.currentList + .indexOfFirst { it.selected } + .let { if (it == -1) 0 else it } driverViewModel.showClearButton(!StringSetting.DRIVER_PATH.global) binding.listDrivers - .smoothScrollToPosition(adapter.currentList.indices.last) + .smoothScrollToPosition(selectedPosition) } } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt index fc7fbc9bfc..3904f83279 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt @@ -154,15 +154,30 @@ class DriverViewModel : ViewModel() { } fun onDriverRemoved(removedPosition: Int, selectedPosition: Int) { - driversToDelete.add(driverData[removedPosition - 1].first) - driverData.removeAt(removedPosition - 1) - onDriverSelected(selectedPosition) + val driverIndex = removedPosition - 1 + if (driverIndex !in driverData.indices) { + updateDriverList() + return + } + + driversToDelete.add(driverData[driverIndex].first) + driverData.removeAt(driverIndex) + val safeSelectedPosition = selectedPosition.coerceIn(0, driverData.size) + onDriverSelected(safeSelectedPosition) } fun onDriverAdded(driver: Pair) { if (driversToDelete.contains(driver.first)) { driversToDelete.remove(driver.first) } + + val existingDriverIndex = driverData.indexOfFirst { + it.first == driver.first || it.second == driver.second + } + if (existingDriverIndex != -1) { + onDriverSelected(existingDriverIndex + 1) + return + } driverData.add(driver) onDriverSelected(driverData.size) } From 3eb537ed8263baec4f2a36238724456de3ebefb7 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 21 Mar 2026 18:06:49 +0000 Subject: [PATCH 9/9] [video_core/engines/maxwell3d] memory inline DrawState to reduce indirection on hot paths Signed-off-by: lizzie --- src/video_core/CMakeLists.txt | 1 - src/video_core/buffer_cache/buffer_cache.h | 32 +-- .../buffer_cache/buffer_cache_base.h | 6 +- src/video_core/engines/draw_manager.cpp | 242 ++++++++---------- src/video_core/engines/draw_manager.h | 117 --------- src/video_core/engines/maxwell_3d.cpp | 13 +- src/video_core/engines/maxwell_3d.h | 73 +++++- src/video_core/gpu_thread.cpp | 6 +- src/video_core/macro.cpp | 32 +-- .../renderer_opengl/gl_rasterizer.cpp | 18 +- .../renderer_opengl/gl_shader_cache.cpp | 6 +- .../renderer_vulkan/fixed_pipeline_state.cpp | 6 +- .../renderer_vulkan/vk_pipeline_cache.cpp | 2 +- .../renderer_vulkan/vk_query_cache.cpp | 4 +- .../renderer_vulkan/vk_rasterizer.cpp | 23 +- 15 files changed, 231 insertions(+), 350 deletions(-) delete mode 100644 src/video_core/engines/draw_manager.h diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 3324682639..259e4801d3 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -44,7 +44,6 @@ add_library(video_core STATIC engines/sw_blitter/converter.h engines/const_buffer_info.h engines/draw_manager.cpp - engines/draw_manager.h engines/engine_interface.h engines/engine_upload.cpp engines/engine_upload.h diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index 014b4a318e..83c94b2fc3 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -356,7 +356,7 @@ void BufferCache

::BindHostGeometryBuffers(bool is_indexed) { if (is_indexed) { BindHostIndexBuffer(); } else if constexpr (!HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) { - const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); + const auto& draw_state = maxwell3d->draw_manager.draw_state; if (draw_state.topology == Maxwell::PrimitiveTopology::Quads || draw_state.topology == Maxwell::PrimitiveTopology::QuadStrip) { runtime.BindQuadIndexBuffer(draw_state.topology, draw_state.vertex_buffer.first, @@ -740,30 +740,25 @@ void BufferCache

::BindHostIndexBuffer() { TouchBuffer(buffer, channel_state->index_buffer.buffer_id); const u32 offset = buffer.Offset(channel_state->index_buffer.device_addr); const u32 size = channel_state->index_buffer.size; - const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); - if (!draw_state.inline_index_draw_indexes.empty()) [[unlikely]] { + const auto& draw_state = maxwell3d->draw_manager.draw_state; + if (draw_state.inline_index_draw_indexes.empty()) { + SynchronizeBuffer(buffer, channel_state->index_buffer.device_addr, size); + } else { if constexpr (USE_MEMORY_MAPS_FOR_UPLOADS) { auto upload_staging = runtime.UploadStagingBuffer(size); - std::array copies{ - {BufferCopy{.src_offset = upload_staging.offset, .dst_offset = 0, .size = size}}}; - std::memcpy(upload_staging.mapped_span.data(), - draw_state.inline_index_draw_indexes.data(), size); + std::array copies{{BufferCopy{.src_offset = upload_staging.offset, .dst_offset = 0, .size = size}}}; + std::memcpy(upload_staging.mapped_span.data(), draw_state.inline_index_draw_indexes.data(), size); runtime.CopyBuffer(buffer, upload_staging.buffer, copies, true); } else { buffer.ImmediateUpload(0, draw_state.inline_index_draw_indexes); } - } else { - SynchronizeBuffer(buffer, channel_state->index_buffer.device_addr, size); } if constexpr (HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) { - const u32 new_offset = - offset + draw_state.index_buffer.first * draw_state.index_buffer.FormatSizeInBytes(); + const u32 new_offset = offset + draw_state.index_buffer.first * draw_state.index_buffer.FormatSizeInBytes(); runtime.BindIndexBuffer(buffer, new_offset, size); } else { buffer.MarkUsage(offset, size); - runtime.BindIndexBuffer(draw_state.topology, draw_state.index_buffer.format, - draw_state.index_buffer.first, draw_state.index_buffer.count, - buffer, offset, size); + runtime.BindIndexBuffer(draw_state.topology, draw_state.index_buffer.format, draw_state.index_buffer.first, draw_state.index_buffer.count, buffer, offset, size); } } @@ -945,10 +940,9 @@ void BufferCache

::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32 return alignment > 1 && (offset % alignment) != 0; } }(); - const bool use_fast_buffer = needs_alignment_stream || - (has_host_buffer && - size <= channel_state->uniform_buffer_skip_cache_size && - !memory_tracker.IsRegionGpuModified(device_addr, size)); + const bool use_fast_buffer = needs_alignment_stream + || (has_host_buffer && size <= channel_state->uniform_buffer_skip_cache_size + && !memory_tracker.IsRegionGpuModified(device_addr, size)); if (use_fast_buffer) { if constexpr (IS_OPENGL) { if (runtime.HasFastBufferSubData()) { @@ -1226,7 +1220,7 @@ template void BufferCache

::UpdateIndexBuffer() { // We have to check for the dirty flags and index count // The index count is currently changed without updating the dirty flags - const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); + const auto& draw_state = maxwell3d->draw_manager.draw_state; const auto& index_buffer_ref = draw_state.index_buffer; auto& flags = maxwell3d->dirty.flags; if (!flags[Dirty::IndexBuffer]) { diff --git a/src/video_core/buffer_cache/buffer_cache_base.h b/src/video_core/buffer_cache/buffer_cache_base.h index 08524bd854..473cc6842e 100644 --- a/src/video_core/buffer_cache/buffer_cache_base.h +++ b/src/video_core/buffer_cache/buffer_cache_base.h @@ -32,7 +32,7 @@ #include "video_core/control/channel_state_cache.h" #include "video_core/delayed_destruction_ring.h" #include "video_core/dirty_flags.h" -#include "video_core/engines/draw_manager.h" +#include "video_core/engines/maxwell_3d.h" #include "video_core/engines/kepler_compute.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/memory_manager.h" @@ -305,7 +305,7 @@ public: [[nodiscard]] bool IsRegionCpuModified(DAddr addr, size_t size); void SetDrawIndirect( - const Tegra::Engines::DrawManager::IndirectParams* current_draw_indirect_) { + const Tegra::Engines::Maxwell3D::DrawManager::IndirectParams* current_draw_indirect_) { current_draw_indirect = current_draw_indirect_; } @@ -480,7 +480,7 @@ private: #endif DelayedDestructionRing delayed_destruction_ring; - const Tegra::Engines::DrawManager::IndirectParams* current_draw_indirect{}; + const Tegra::Engines::Maxwell3D::DrawManager::IndirectParams* current_draw_indirect{}; u32 last_index_count = 0; diff --git a/src/video_core/engines/draw_manager.cpp b/src/video_core/engines/draw_manager.cpp index 971025cb55..079c7bdc09 100644 --- a/src/video_core/engines/draw_manager.cpp +++ b/src/video_core/engines/draw_manager.cpp @@ -1,23 +1,24 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "common/settings.h" #include "video_core/dirty_flags.h" -#include "video_core/engines/draw_manager.h" +#include "video_core/engines/maxwell_3d.h" #include "video_core/rasterizer_interface.h" namespace Tegra::Engines { -DrawManager::DrawManager(Maxwell3D* maxwell3d_) : maxwell3d(maxwell3d_) {} -void DrawManager::ProcessMethodCall(u32 method, u32 argument) { - const auto& regs{maxwell3d->regs}; +void Maxwell3D::DrawManager::ProcessMethodCall(Maxwell3D& maxwell3d, u32 method, u32 argument) { switch (method) { case MAXWELL3D_REG_INDEX(clear_surface): - return Clear(1); + return Clear(maxwell3d, 1); case MAXWELL3D_REG_INDEX(draw.begin): - return DrawBegin(); + return DrawBegin(maxwell3d); case MAXWELL3D_REG_INDEX(draw.end): - return DrawEnd(); + return DrawEnd(maxwell3d); case MAXWELL3D_REG_INDEX(vertex_buffer.first): case MAXWELL3D_REG_INDEX(vertex_buffer.count): case MAXWELL3D_REG_INDEX(index_buffer.first): @@ -33,33 +34,29 @@ void DrawManager::ProcessMethodCall(u32 method, u32 argument) { case MAXWELL3D_REG_INDEX(index_buffer32_first): case MAXWELL3D_REG_INDEX(index_buffer16_first): case MAXWELL3D_REG_INDEX(index_buffer8_first): - return DrawIndexSmall(argument); + return DrawIndexSmall(maxwell3d, argument); case MAXWELL3D_REG_INDEX(draw_inline_index): - SetInlineIndexBuffer(argument); + SetInlineIndexBuffer(maxwell3d, argument); break; case MAXWELL3D_REG_INDEX(inline_index_2x16.even): - SetInlineIndexBuffer(regs.inline_index_2x16.even); - SetInlineIndexBuffer(regs.inline_index_2x16.odd); + SetInlineIndexBuffer(maxwell3d, maxwell3d.regs.inline_index_2x16.even); + SetInlineIndexBuffer(maxwell3d, maxwell3d.regs.inline_index_2x16.odd); break; case MAXWELL3D_REG_INDEX(inline_index_4x8.index0): - SetInlineIndexBuffer(regs.inline_index_4x8.index0); - SetInlineIndexBuffer(regs.inline_index_4x8.index1); - SetInlineIndexBuffer(regs.inline_index_4x8.index2); - SetInlineIndexBuffer(regs.inline_index_4x8.index3); + SetInlineIndexBuffer(maxwell3d, maxwell3d.regs.inline_index_4x8.index0); + SetInlineIndexBuffer(maxwell3d, maxwell3d.regs.inline_index_4x8.index1); + SetInlineIndexBuffer(maxwell3d, maxwell3d.regs.inline_index_4x8.index2); + SetInlineIndexBuffer(maxwell3d, maxwell3d.regs.inline_index_4x8.index3); break; case MAXWELL3D_REG_INDEX(vertex_array_instance_first): - DrawArrayInstanced(regs.vertex_array_instance_first.topology.Value(), - regs.vertex_array_instance_first.start.Value(), - regs.vertex_array_instance_first.count.Value(), false); + DrawArrayInstanced(maxwell3d, maxwell3d.regs.vertex_array_instance_first.topology.Value(), maxwell3d.regs.vertex_array_instance_first.start.Value(), maxwell3d.regs.vertex_array_instance_first.count.Value(), false); break; case MAXWELL3D_REG_INDEX(vertex_array_instance_subsequent): { - DrawArrayInstanced(regs.vertex_array_instance_subsequent.topology.Value(), - regs.vertex_array_instance_subsequent.start.Value(), - regs.vertex_array_instance_subsequent.count.Value(), true); + DrawArrayInstanced(maxwell3d, maxwell3d.regs.vertex_array_instance_subsequent.topology.Value(), maxwell3d.regs.vertex_array_instance_subsequent.start.Value(), maxwell3d.regs.vertex_array_instance_subsequent.count.Value(), true); break; } case MAXWELL3D_REG_INDEX(draw_texture.src_y0): { - DrawTexture(); + DrawTexture(maxwell3d); break; } default: @@ -67,101 +64,87 @@ void DrawManager::ProcessMethodCall(u32 method, u32 argument) { } } -void DrawManager::Clear(u32 layer_count) { - if (maxwell3d->ShouldExecute()) { - maxwell3d->rasterizer->Clear(layer_count); +void Maxwell3D::DrawManager::Clear(Maxwell3D& maxwell3d, u32 layer_count) { + if (maxwell3d.ShouldExecute()) { + maxwell3d.rasterizer->Clear(layer_count); } } -void DrawManager::DrawDeferred() { +void Maxwell3D::DrawManager::DrawDeferred(Maxwell3D& maxwell3d) { if (draw_state.draw_mode != DrawMode::Instance || draw_state.instance_count == 0) { return; } - DrawEnd(draw_state.instance_count + 1, true); + DrawEnd(maxwell3d, draw_state.instance_count + 1, true); draw_state.instance_count = 0; } -void DrawManager::DrawArray(PrimitiveTopology topology, u32 vertex_first, u32 vertex_count, - u32 base_instance, u32 num_instances) { +void Maxwell3D::DrawManager::DrawArray(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology, u32 vertex_first, u32 vertex_count, u32 base_instance, u32 num_instances) { draw_state.topology = topology; draw_state.vertex_buffer.first = vertex_first; draw_state.vertex_buffer.count = vertex_count; draw_state.base_instance = base_instance; - ProcessDraw(false, num_instances); + ProcessDraw(maxwell3d, false, num_instances); } -void DrawManager::DrawArrayInstanced(PrimitiveTopology topology, u32 vertex_first, u32 vertex_count, - bool subsequent) { +void Maxwell3D::DrawManager::DrawArrayInstanced(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology, u32 vertex_first, u32 vertex_count, bool subsequent) { draw_state.topology = topology; draw_state.vertex_buffer.first = vertex_first; draw_state.vertex_buffer.count = vertex_count; - if (!subsequent) { draw_state.instance_count = 1; } - draw_state.base_instance = draw_state.instance_count - 1; draw_state.draw_mode = DrawMode::Instance; draw_state.instance_count++; - ProcessDraw(false, 1); + ProcessDraw(maxwell3d, false, 1); } -void DrawManager::DrawIndex(PrimitiveTopology topology, u32 index_first, u32 index_count, - u32 base_index, u32 base_instance, u32 num_instances) { - const auto& regs{maxwell3d->regs}; +void Maxwell3D::DrawManager::DrawIndex(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology, u32 index_first, u32 index_count, u32 base_index, u32 base_instance, u32 num_instances) { draw_state.topology = topology; - draw_state.index_buffer = regs.index_buffer; + draw_state.index_buffer = maxwell3d.regs.index_buffer; draw_state.index_buffer.first = index_first; draw_state.index_buffer.count = index_count; draw_state.base_index = base_index; draw_state.base_instance = base_instance; - ProcessDraw(true, num_instances); + ProcessDraw(maxwell3d, true, num_instances); } -void DrawManager::DrawArrayIndirect(PrimitiveTopology topology) { +void Maxwell3D::DrawManager::DrawArrayIndirect(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology) { draw_state.topology = topology; - - ProcessDrawIndirect(); + ProcessDrawIndirect(maxwell3d); } -void DrawManager::DrawIndexedIndirect(PrimitiveTopology topology, u32 index_first, - u32 index_count) { - const auto& regs{maxwell3d->regs}; +void Maxwell3D::DrawManager::DrawIndexedIndirect(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology, u32 index_first, u32 index_count) { draw_state.topology = topology; - draw_state.index_buffer = regs.index_buffer; + draw_state.index_buffer = maxwell3d.regs.index_buffer; draw_state.index_buffer.first = index_first; draw_state.index_buffer.count = index_count; - - ProcessDrawIndirect(); + ProcessDrawIndirect(maxwell3d); } -void DrawManager::SetInlineIndexBuffer(u32 index) { - draw_state.inline_index_draw_indexes.push_back(static_cast(index & 0x000000ff)); - draw_state.inline_index_draw_indexes.push_back(static_cast((index & 0x0000ff00) >> 8)); - draw_state.inline_index_draw_indexes.push_back(static_cast((index & 0x00ff0000) >> 16)); - draw_state.inline_index_draw_indexes.push_back(static_cast((index & 0xff000000) >> 24)); +void Maxwell3D::DrawManager::SetInlineIndexBuffer(Maxwell3D& maxwell3d, u32 index) { + draw_state.inline_index_draw_indexes.push_back(u8(index & 0x000000ff)); + draw_state.inline_index_draw_indexes.push_back(u8((index & 0x0000ff00) >> 8)); + draw_state.inline_index_draw_indexes.push_back(u8((index & 0x00ff0000) >> 16)); + draw_state.inline_index_draw_indexes.push_back(u8((index & 0xff000000) >> 24)); draw_state.draw_mode = DrawMode::InlineIndex; } -void DrawManager::DrawBegin() { - const auto& regs{maxwell3d->regs}; - auto reset_instance_count = regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::First; - auto increment_instance_count = - regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent; +void Maxwell3D::DrawManager::DrawBegin(Maxwell3D& maxwell3d) { + auto reset_instance_count = maxwell3d.regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::First; + auto increment_instance_count = maxwell3d.regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent; if (reset_instance_count) { - DrawDeferred(); + DrawDeferred(maxwell3d); draw_state.instance_count = 0; draw_state.draw_mode = DrawMode::General; } else if (increment_instance_count) { draw_state.instance_count++; draw_state.draw_mode = DrawMode::Instance; } - - draw_state.topology = regs.draw.topology; + draw_state.topology = maxwell3d.regs.draw.topology; } -void DrawManager::DrawEnd(u32 instance_count, bool force_draw) { - const auto& regs{maxwell3d->regs}; +void Maxwell3D::DrawManager::DrawEnd(Maxwell3D& maxwell3d, u32 instance_count, bool force_draw) { switch (draw_state.draw_mode) { case DrawMode::Instance: if (!force_draw) { @@ -169,119 +152,100 @@ void DrawManager::DrawEnd(u32 instance_count, bool force_draw) { } [[fallthrough]]; case DrawMode::General: - draw_state.base_instance = regs.global_base_instance_index; - draw_state.base_index = regs.global_base_vertex_index; + draw_state.base_instance = maxwell3d.regs.global_base_instance_index; + draw_state.base_index = maxwell3d.regs.global_base_vertex_index; if (draw_state.draw_indexed) { - draw_state.index_buffer = regs.index_buffer; - ProcessDraw(true, instance_count); + draw_state.index_buffer = maxwell3d.regs.index_buffer; + ProcessDraw(maxwell3d, true, instance_count); } else { - draw_state.vertex_buffer = regs.vertex_buffer; - ProcessDraw(false, instance_count); + draw_state.vertex_buffer = maxwell3d.regs.vertex_buffer; + ProcessDraw(maxwell3d, false, instance_count); } draw_state.draw_indexed = false; break; case DrawMode::InlineIndex: - draw_state.base_instance = regs.global_base_instance_index; - draw_state.base_index = regs.global_base_vertex_index; - draw_state.index_buffer = regs.index_buffer; - draw_state.index_buffer.count = - static_cast(draw_state.inline_index_draw_indexes.size() / 4); + draw_state.base_instance = maxwell3d.regs.global_base_instance_index; + draw_state.base_index = maxwell3d.regs.global_base_vertex_index; + draw_state.index_buffer = maxwell3d.regs.index_buffer; + draw_state.index_buffer.count = u32(draw_state.inline_index_draw_indexes.size() / 4); draw_state.index_buffer.format = Maxwell3D::Regs::IndexFormat::UnsignedInt; - maxwell3d->dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; - ProcessDraw(true, instance_count); + maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; + ProcessDraw(maxwell3d, true, instance_count); draw_state.inline_index_draw_indexes.clear(); break; } } -void DrawManager::DrawIndexSmall(u32 argument) { - const auto& regs{maxwell3d->regs}; - IndexBufferSmall index_small_params{argument}; - draw_state.base_instance = regs.global_base_instance_index; - draw_state.base_index = regs.global_base_vertex_index; - draw_state.index_buffer = regs.index_buffer; +void Maxwell3D::DrawManager::DrawIndexSmall(Maxwell3D& maxwell3d, u32 argument) { + Maxwell3D::Regs::IndexBufferSmall index_small_params{argument}; + draw_state.base_instance = maxwell3d.regs.global_base_instance_index; + draw_state.base_index = maxwell3d.regs.global_base_vertex_index; + draw_state.index_buffer = maxwell3d.regs.index_buffer; draw_state.index_buffer.first = index_small_params.first; draw_state.index_buffer.count = index_small_params.count; draw_state.topology = index_small_params.topology; - maxwell3d->dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; - ProcessDraw(true, 1); + maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; + ProcessDraw(maxwell3d, true, 1); } -void DrawManager::DrawTexture() { - const auto& regs{maxwell3d->regs}; - draw_texture_state.dst_x0 = static_cast(regs.draw_texture.dst_x0) / 4096.f; - draw_texture_state.dst_y0 = static_cast(regs.draw_texture.dst_y0) / 4096.f; - const auto dst_width = static_cast(regs.draw_texture.dst_width) / 4096.f; - const auto dst_height = static_cast(regs.draw_texture.dst_height) / 4096.f; - const bool lower_left{regs.window_origin.mode != - Maxwell3D::Regs::WindowOrigin::Mode::UpperLeft}; +void Maxwell3D::DrawManager::DrawTexture(Maxwell3D& maxwell3d) { + draw_texture_state.dst_x0 = f32(maxwell3d.regs.draw_texture.dst_x0) / 4096.f; + draw_texture_state.dst_y0 = f32(maxwell3d.regs.draw_texture.dst_y0) / 4096.f; + const auto dst_width = f32(maxwell3d.regs.draw_texture.dst_width) / 4096.f; + const auto dst_height = f32(maxwell3d.regs.draw_texture.dst_height) / 4096.f; + const bool lower_left{maxwell3d.regs.window_origin.mode != Maxwell3D::Regs::WindowOrigin::Mode::UpperLeft}; if (lower_left) { - draw_texture_state.dst_y0 = - static_cast(regs.surface_clip.height) - draw_texture_state.dst_y0; + draw_texture_state.dst_y0 = f32(maxwell3d.regs.surface_clip.height) - draw_texture_state.dst_y0; } draw_texture_state.dst_x1 = draw_texture_state.dst_x0 + dst_width; draw_texture_state.dst_y1 = draw_texture_state.dst_y0 + dst_height; - draw_texture_state.src_x0 = static_cast(regs.draw_texture.src_x0) / 4096.f; - draw_texture_state.src_y0 = static_cast(regs.draw_texture.src_y0) / 4096.f; - draw_texture_state.src_x1 = - (static_cast(regs.draw_texture.dx_du) / 4294967296.f) * dst_width + - draw_texture_state.src_x0; - draw_texture_state.src_y1 = - (static_cast(regs.draw_texture.dy_dv) / 4294967296.f) * dst_height + - draw_texture_state.src_y0; - draw_texture_state.src_sampler = regs.draw_texture.src_sampler; - draw_texture_state.src_texture = regs.draw_texture.src_texture; - maxwell3d->rasterizer->DrawTexture(); + draw_texture_state.src_x0 = f32(maxwell3d.regs.draw_texture.src_x0) / 4096.f; + draw_texture_state.src_y0 = f32(maxwell3d.regs.draw_texture.src_y0) / 4096.f; + draw_texture_state.src_x1 = (f32(maxwell3d.regs.draw_texture.dx_du) / 4294967296.f) * dst_width + draw_texture_state.src_x0; + draw_texture_state.src_y1 = (f32(maxwell3d.regs.draw_texture.dy_dv) / 4294967296.f) * dst_height + draw_texture_state.src_y0; + draw_texture_state.src_sampler = maxwell3d.regs.draw_texture.src_sampler; + draw_texture_state.src_texture = maxwell3d.regs.draw_texture.src_texture; + maxwell3d.rasterizer->DrawTexture(); } -void DrawManager::UpdateTopology() { - const auto& regs{maxwell3d->regs}; - switch (regs.primitive_topology_control) { - case PrimitiveTopologyControl::UseInBeginMethods: +void Maxwell3D::DrawManager::UpdateTopology(Maxwell3D& maxwell3d) { + switch (maxwell3d.regs.primitive_topology_control) { + case Maxwell3D::Regs::PrimitiveTopologyControl::UseInBeginMethods: break; - case PrimitiveTopologyControl::UseSeparateState: - switch (regs.topology_override) { - case PrimitiveTopologyOverride::None: + case Maxwell3D::Regs::PrimitiveTopologyControl::UseSeparateState: + switch (maxwell3d.regs.topology_override) { + case Maxwell3D::Regs::PrimitiveTopologyOverride::None: break; - case PrimitiveTopologyOverride::Points: - draw_state.topology = PrimitiveTopology::Points; + case Maxwell3D::Regs::PrimitiveTopologyOverride::Points: + draw_state.topology = Maxwell3D::Regs::PrimitiveTopology::Points; break; - case PrimitiveTopologyOverride::Lines: - draw_state.topology = PrimitiveTopology::Lines; + case Maxwell3D::Regs::PrimitiveTopologyOverride::Lines: + draw_state.topology = Maxwell3D::Regs::PrimitiveTopology::Lines; break; - case PrimitiveTopologyOverride::LineStrip: - draw_state.topology = PrimitiveTopology::LineStrip; + case Maxwell3D::Regs::PrimitiveTopologyOverride::LineStrip: + draw_state.topology = Maxwell3D::Regs::PrimitiveTopology::LineStrip; break; default: - draw_state.topology = static_cast(regs.topology_override); + draw_state.topology = Maxwell3D::Regs::PrimitiveTopology(maxwell3d.regs.topology_override); break; } break; } } -void DrawManager::ProcessDraw(bool draw_indexed, u32 instance_count) { - LOG_TRACE(HW_GPU, "called, topology={}, count={}", draw_state.topology, - draw_indexed ? draw_state.index_buffer.count : draw_state.vertex_buffer.count); - - UpdateTopology(); - - if (maxwell3d->ShouldExecute()) { - maxwell3d->rasterizer->Draw(draw_indexed, instance_count); +void Maxwell3D::DrawManager::ProcessDraw(Maxwell3D& maxwell3d, bool draw_indexed, u32 instance_count) { + LOG_TRACE(HW_GPU, "called, topology={}, count={}", draw_state.topology, draw_indexed ? draw_state.index_buffer.count : draw_state.vertex_buffer.count); + UpdateTopology(maxwell3d); + if (maxwell3d.ShouldExecute()) { + maxwell3d.rasterizer->Draw(draw_indexed, instance_count); } } -void DrawManager::ProcessDrawIndirect() { - LOG_TRACE( - HW_GPU, - "called, topology={}, is_indexed={}, includes_count={}, buffer_size={}, max_draw_count={}", - draw_state.topology, indirect_state.is_indexed, indirect_state.include_count, - indirect_state.buffer_size, indirect_state.max_draw_counts); - - UpdateTopology(); - - if (maxwell3d->ShouldExecute()) { - maxwell3d->rasterizer->DrawIndirect(); +void Maxwell3D::DrawManager::ProcessDrawIndirect(Maxwell3D& maxwell3d) { + LOG_TRACE(HW_GPU, "called, topology={}, is_indexed={}, includes_count={}, buffer_size={}, max_draw_count={}", draw_state.topology, indirect_state.is_indexed, indirect_state.include_count, indirect_state.buffer_size, indirect_state.max_draw_counts); + UpdateTopology(maxwell3d); + if (maxwell3d.ShouldExecute()) { + maxwell3d.rasterizer->DrawIndirect(); } } } // namespace Tegra::Engines diff --git a/src/video_core/engines/draw_manager.h b/src/video_core/engines/draw_manager.h deleted file mode 100644 index cfc8127fc6..0000000000 --- a/src/video_core/engines/draw_manager.h +++ /dev/null @@ -1,117 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once -#include "common/common_types.h" -#include "video_core/engines/maxwell_3d.h" - -namespace VideoCore { -class RasterizerInterface; -} - -namespace Tegra::Engines { -using PrimitiveTopologyControl = Maxwell3D::Regs::PrimitiveTopologyControl; -using PrimitiveTopology = Maxwell3D::Regs::PrimitiveTopology; -using PrimitiveTopologyOverride = Maxwell3D::Regs::PrimitiveTopologyOverride; -using IndexBuffer = Maxwell3D::Regs::IndexBuffer; -using VertexBuffer = Maxwell3D::Regs::VertexBuffer; -using IndexBufferSmall = Maxwell3D::Regs::IndexBufferSmall; - -class DrawManager { -public: - enum class DrawMode : u32 { General = 0, Instance, InlineIndex }; - struct State { - PrimitiveTopology topology{}; - DrawMode draw_mode{}; - bool draw_indexed{}; - u32 base_index{}; - VertexBuffer vertex_buffer; - IndexBuffer index_buffer; - u32 base_instance{}; - u32 instance_count{}; - std::vector inline_index_draw_indexes; - }; - - struct DrawTextureState { - f32 dst_x0; - f32 dst_y0; - f32 dst_x1; - f32 dst_y1; - f32 src_x0; - f32 src_y0; - f32 src_x1; - f32 src_y1; - u32 src_sampler; - u32 src_texture; - }; - - struct IndirectParams { - bool is_byte_count; - bool is_indexed; - bool include_count; - GPUVAddr count_start_address; - GPUVAddr indirect_start_address; - size_t buffer_size; - size_t max_draw_counts; - size_t stride; - }; - - explicit DrawManager(Maxwell3D* maxwell_3d); - - void ProcessMethodCall(u32 method, u32 argument); - - void Clear(u32 layer_count); - - void DrawDeferred(); - - void DrawArray(PrimitiveTopology topology, u32 vertex_first, u32 vertex_count, - u32 base_instance, u32 num_instances); - void DrawArrayInstanced(PrimitiveTopology topology, u32 vertex_first, u32 vertex_count, - bool subsequent); - - void DrawIndex(PrimitiveTopology topology, u32 index_first, u32 index_count, u32 base_index, - u32 base_instance, u32 num_instances); - - void DrawArrayIndirect(PrimitiveTopology topology); - - void DrawIndexedIndirect(PrimitiveTopology topology, u32 index_first, u32 index_count); - - const State& GetDrawState() const { - return draw_state; - } - - const DrawTextureState& GetDrawTextureState() const { - return draw_texture_state; - } - - IndirectParams& GetIndirectParams() { - return indirect_state; - } - - const IndirectParams& GetIndirectParams() const { - return indirect_state; - } - -private: - void SetInlineIndexBuffer(u32 index); - - void DrawBegin(); - - void DrawEnd(u32 instance_count = 1, bool force_draw = false); - - void DrawIndexSmall(u32 argument); - - void DrawTexture(); - - void UpdateTopology(); - - void ProcessDraw(bool draw_indexed, u32 instance_count); - - void ProcessDrawIndirect(); - - Maxwell3D* maxwell3d{}; - State draw_state{}; - DrawTextureState draw_texture_state{}; - IndirectParams indirect_state{}; -}; -} // namespace Tegra::Engines diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 6d9ebd6296..9aaa99f7ff 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -13,7 +13,7 @@ #include "core/core.h" #include "core/core_timing.h" #include "video_core/dirty_flags.h" -#include "video_core/engines/draw_manager.h" +#include "video_core/engines/maxwell_3d.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/gpu.h" #include "video_core/memory_manager.h" @@ -26,7 +26,8 @@ namespace Tegra::Engines { constexpr u32 MacroRegistersStart = 0xE00; Maxwell3D::Maxwell3D(Core::System& system_, MemoryManager& memory_manager_) - : draw_manager{std::make_unique(this)}, system{system_} + : draw_manager() + , system{system_} , memory_manager{memory_manager_} #ifdef ARCHITECTURE_x86_64 , macro_engine(bool(Settings::values.disable_macro_jit)) @@ -373,8 +374,7 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume case MAXWELL3D_REG_INDEX(sync_info): return ProcessSyncPoint(); case MAXWELL3D_REG_INDEX(launch_dma): - return upload_state.ProcessExec(regs.launch_dma.memory_layout.Value() == - Regs::LaunchDMA::Layout::Pitch); + return upload_state.ProcessExec(regs.launch_dma.memory_layout.Value() == Regs::LaunchDMA::Layout::Pitch); case MAXWELL3D_REG_INDEX(inline_data): upload_state.ProcessData(argument, is_last_call); return; @@ -386,7 +386,7 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume case MAXWELL3D_REG_INDEX(tiled_cache_barrier): return rasterizer->TiledCacheBarrier(); default: - draw_manager->ProcessMethodCall(method, argument); + draw_manager.ProcessMethodCall(*this, method, argument); break; } } @@ -401,8 +401,7 @@ void Maxwell3D::CallMacroMethod(u32 method, const std::vector& parameters) // Execute the current macro. macro_engine.Execute(*this, macro_positions[entry], parameters); - - draw_manager->DrawDeferred(); + draw_manager.DrawDeferred(*this); } void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) { diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index b73082b7ef..3ac79e0eb8 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -25,6 +25,7 @@ #include "video_core/gpu.h" #include "video_core/macro.h" #include "video_core/textures/texture.h" +#include "video_core/engines/maxwell_3d.h" namespace Core { class System; @@ -40,8 +41,6 @@ class RasterizerInterface; namespace Tegra::Engines { -class DrawManager; - /** * This Engine is known as GF100_3D. Documentation can be found in: * https://github.com/NVIDIA/open-gpu-doc/blob/master/classes/3d/clb197.h @@ -543,7 +542,7 @@ public: } GPUVAddr StorageLimitAddress() const { return (GPUVAddr{storage_limit_address_high} << 32) | - GPUVAddr{storage_limit_address_low}; + GPUVAddr{storage_limit_address_low}; } }; @@ -819,7 +818,7 @@ public: u32 Map(std::size_t index) const { const std::array maps{target0, target1, target2, target3, - target4, target5, target6, target7}; + target4, target5, target6, target7}; ASSERT(index < maps.size()); return maps[index]; } @@ -1831,7 +1830,7 @@ public: bool AnyEnabled() const { return output0_enable || output1_enable || output2_enable || output3_enable || - output4_enable || output5_enable || output6_enable || output7_enable; + output4_enable || output5_enable || output6_enable || output7_enable; } }; @@ -1870,7 +1869,7 @@ public: bool AnyEnabled() const { return plane0 || plane1 || plane2 || plane3 || plane4 || plane5 || plane6 || - plane7; + plane7; } }; @@ -3023,8 +3022,7 @@ public: u32 bindless_texture_const_buffer_slot; ///< 0x2608 u32 trap_handler; ///< 0x260C INSERT_PADDING_BYTES_NOINIT(0x1F0); - std::array, NumTransformFeedbackBuffers> - stream_out_layout; ///< 0x2800 + std::array, NumTransformFeedbackBuffers> stream_out_layout; ///< 0x2800 INSERT_PADDING_BYTES_NOINIT(0x93C); ShaderPerformance shader_performance; ///< 0x333C INSERT_PADDING_BYTES_NOINIT(0x18); @@ -3035,6 +3033,62 @@ public: }; // clang-format on + struct DrawManager { + enum class DrawMode : u32 { General = 0, Instance, InlineIndex }; + struct State { + Maxwell3D::Regs::PrimitiveTopology topology{}; + DrawMode draw_mode{}; + bool draw_indexed{}; + u32 base_index{}; + Maxwell3D::Regs::VertexBuffer vertex_buffer; + Maxwell3D::Regs::IndexBuffer index_buffer; + u32 base_instance{}; + u32 instance_count{}; + std::vector inline_index_draw_indexes; + }; + struct DrawTextureState { + f32 dst_x0; + f32 dst_y0; + f32 dst_x1; + f32 dst_y1; + f32 src_x0; + f32 src_y0; + f32 src_x1; + f32 src_y1; + u32 src_sampler; + u32 src_texture; + }; + struct IndirectParams { + bool is_byte_count; + bool is_indexed; + bool include_count; + GPUVAddr count_start_address; + GPUVAddr indirect_start_address; + size_t buffer_size; + size_t max_draw_counts; + size_t stride; + }; + void ProcessMethodCall(Maxwell3D& maxwell3d, u32 method, u32 argument); + void Clear(Maxwell3D& maxwell3d, u32 layer_count); + void DrawDeferred(Maxwell3D& maxwell3d); + void DrawArray(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology, u32 vertex_first, u32 vertex_count, u32 base_instance, u32 num_instances); + void DrawArrayInstanced(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology, u32 vertex_first, u32 vertex_count, bool subsequent); + void DrawIndex(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology, u32 index_first, u32 index_count, u32 base_index, u32 base_instance, u32 num_instances); + void DrawArrayIndirect(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology); + void DrawIndexedIndirect(Maxwell3D& maxwell3d, Maxwell3D::Regs::PrimitiveTopology topology, u32 index_first, u32 index_count); + void SetInlineIndexBuffer(Maxwell3D& maxwell3d, u32 index); + void DrawBegin(Maxwell3D& maxwell3d); + void DrawEnd(Maxwell3D& maxwell3d, u32 instance_count = 1, bool force_draw = false); + void DrawIndexSmall(Maxwell3D& maxwell3d, u32 argument); + void DrawTexture(Maxwell3D& maxwell3d); + void UpdateTopology(Maxwell3D& maxwell3d); + void ProcessDraw(Maxwell3D& maxwell3d, bool draw_indexed, u32 instance_count); + void ProcessDrawIndirect(Maxwell3D& maxwell3d); + State draw_state{}; + DrawTextureState draw_texture_state{}; + IndirectParams indirect_state{}; + }; + Regs regs{}; /// Store temporary hw register values, used by some calls to restore state after a operation @@ -3102,8 +3156,7 @@ public: Tables tables{}; } dirty; - std::unique_ptr draw_manager; - friend class DrawManager; + DrawManager draw_manager; GPUVAddr GetMacroAddress(size_t index) const { return macro_addresses[index]; diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp index 8d8d857a02..f7cd27b0d3 100644 --- a/src/video_core/gpu_thread.cpp +++ b/src/video_core/gpu_thread.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 2019 yuzu Emulator Project @@ -63,9 +63,7 @@ ThreadManager::ThreadManager(Core::System& system_, bool is_async_) ThreadManager::~ThreadManager() = default; -void ThreadManager::StartThread(VideoCore::RendererBase& renderer, - Core::Frontend::GraphicsContext& context, - Tegra::Control::Scheduler& scheduler) { +void ThreadManager::StartThread(VideoCore::RendererBase& renderer, Core::Frontend::GraphicsContext& context, Tegra::Control::Scheduler& scheduler) { rasterizer = renderer.ReadRasterizer(); thread = std::jthread(RunThread, std::ref(system), std::ref(renderer), std::ref(context), std::ref(scheduler), std::ref(state)); diff --git a/src/video_core/macro.cpp b/src/video_core/macro.cpp index 66cea5afbd..cbd21a0743 100644 --- a/src/video_core/macro.cpp +++ b/src/video_core/macro.cpp @@ -31,7 +31,7 @@ #include "common/settings.h" #include "common/container_hash.h" #include "video_core/engines/maxwell_3d.h" -#include "video_core/engines/draw_manager.h" +#include "video_core/engines/maxwell_3d.h" #include "video_core/dirty_flags.h" #include "video_core/rasterizer_interface.h" #include "video_core/macro.h" @@ -83,7 +83,7 @@ void HLE_DrawArraysIndirect::Execute(Engines::Maxwell3D& maxwell3d, std::spanGetIndirectParams(); + auto& params = maxwell3d.draw_manager.indirect_state; params.is_byte_count = false; params.is_indexed = false; params.include_count = false; @@ -98,7 +98,7 @@ void HLE_DrawArraysIndirect::Execute(Engines::Maxwell3D& maxwell3d, std::spanDrawArrayIndirect(topology); + maxwell3d.draw_manager.DrawArrayIndirect(maxwell3d, topology); if (extended) { maxwell3d.engine_state = Maxwell3D::EngineHint::None; @@ -127,7 +127,7 @@ void HLE_DrawArraysIndirect::Fallback(Engines::Maxwell3D& maxwell3d, std::spanDrawArray(topology, vertex_first, vertex_count, base_instance, instance_count); + maxwell3d.draw_manager.DrawArray(maxwell3d, topology, vertex_first, vertex_count, base_instance, instance_count); if (extended) { maxwell3d.regs.global_base_instance_index = 0; maxwell3d.engine_state = Maxwell3D::EngineHint::None; @@ -154,7 +154,7 @@ void HLE_DrawIndexedIndirect::Execute(Engines::Maxwell3D& maxwell3d, std::spanGetIndirectParams(); + auto& params = maxwell3d.draw_manager.indirect_state; params.is_byte_count = false; params.is_indexed = true; params.include_count = false; @@ -164,7 +164,7 @@ void HLE_DrawIndexedIndirect::Execute(Engines::Maxwell3D& maxwell3d, std::spanDrawIndexedIndirect(topology, 0, estimate); + maxwell3d.draw_manager.DrawIndexedIndirect(maxwell3d, topology, 0, estimate); maxwell3d.regs.vertex_id_base = 0x0; maxwell3d.regs.global_base_vertex_index = 0x0; maxwell3d.regs.global_base_instance_index = 0x0; @@ -187,7 +187,7 @@ void HLE_DrawIndexedIndirect::Fallback(Engines::Maxwell3D& maxwell3d, std::span< maxwell3d.SetHLEReplacementAttributeType(0, 0x640, Maxwell3D::HLEReplacementAttributeType::BaseVertex); maxwell3d.SetHLEReplacementAttributeType(0, 0x644, Maxwell3D::HLEReplacementAttributeType::BaseInstance); } - maxwell3d.draw_manager->DrawIndex(Tegra::Maxwell3D::Regs::PrimitiveTopology(parameters[0]), parameters[3], parameters[1], element_base, base_instance, instance_count); + maxwell3d.draw_manager.DrawIndex(maxwell3d, Tegra::Maxwell3D::Regs::PrimitiveTopology(parameters[0]), parameters[3], parameters[1], element_base, base_instance, instance_count); maxwell3d.regs.vertex_id_base = 0x0; maxwell3d.regs.global_base_vertex_index = 0x0; maxwell3d.regs.global_base_instance_index = 0x0; @@ -206,7 +206,7 @@ void HLE_MultiLayerClear::Execute(Engines::Maxwell3D& maxwell3d, std::spanClear(num_layers); + maxwell3d.draw_manager.Clear(maxwell3d, num_layers); } void HLE_MultiDrawIndexedIndirectCount::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { const auto topology = Maxwell3D::Regs::PrimitiveTopology(parameters[2]); @@ -230,7 +230,7 @@ void HLE_MultiDrawIndexedIndirectCount::Execute(Engines::Maxwell3D& maxwell3d, s const std::size_t draw_count = end_indirect - start_indirect; const u32 estimate = static_cast(maxwell3d.EstimateIndexBufferSize()); maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; - auto& params = maxwell3d.draw_manager->GetIndirectParams(); + auto& params = maxwell3d.draw_manager.indirect_state; params.is_byte_count = false; params.is_indexed = true; params.include_count = true; @@ -244,7 +244,7 @@ void HLE_MultiDrawIndexedIndirectCount::Execute(Engines::Maxwell3D& maxwell3d, s maxwell3d.SetHLEReplacementAttributeType(0, 0x640, Maxwell3D::HLEReplacementAttributeType::BaseVertex); maxwell3d.SetHLEReplacementAttributeType(0, 0x644, Maxwell3D::HLEReplacementAttributeType::BaseInstance); maxwell3d.SetHLEReplacementAttributeType(0, 0x648, Maxwell3D::HLEReplacementAttributeType::DrawID); - maxwell3d.draw_manager->DrawIndexedIndirect(topology, 0, estimate); + maxwell3d.draw_manager.DrawIndexedIndirect(maxwell3d, topology, 0, estimate); maxwell3d.engine_state = Maxwell3D::EngineHint::None; maxwell3d.replace_table.clear(); } @@ -280,7 +280,7 @@ void HLE_MultiDrawIndexedIndirectCount::Fallback(Engines::Maxwell3D& maxwell3d, maxwell3d.CallMethod(0x8e3, 0x648, true); maxwell3d.CallMethod(0x8e4, static_cast(index), true); maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; - maxwell3d.draw_manager->DrawIndex(topology, parameters[base + 2], parameters[base], base_vertex, base_instance, parameters[base + 1]); + maxwell3d.draw_manager.DrawIndex(maxwell3d, topology, parameters[base + 2], parameters[base], base_vertex, base_instance, parameters[base + 1]); } } void HLE_DrawIndirectByteCount::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { @@ -290,7 +290,7 @@ void HLE_DrawIndirectByteCount::Execute(Engines::Maxwell3D& maxwell3d, std::span Fallback(maxwell3d, parameters); return; } - auto& params = maxwell3d.draw_manager->GetIndirectParams(); + auto& params = maxwell3d.draw_manager.indirect_state; params.is_byte_count = true; params.is_indexed = false; params.include_count = false; @@ -302,18 +302,14 @@ void HLE_DrawIndirectByteCount::Execute(Engines::Maxwell3D& maxwell3d, std::span maxwell3d.regs.draw.begin = parameters[0]; maxwell3d.regs.draw_auto_stride = parameters[1]; maxwell3d.regs.draw_auto_byte_count = parameters[2]; - maxwell3d.draw_manager->DrawArrayIndirect(topology); + maxwell3d.draw_manager.DrawArrayIndirect(maxwell3d, topology); } void HLE_DrawIndirectByteCount::Fallback(Engines::Maxwell3D& maxwell3d, std::span parameters) { maxwell3d.RefreshParameters(); - maxwell3d.regs.draw.begin = parameters[0]; maxwell3d.regs.draw_auto_stride = parameters[1]; maxwell3d.regs.draw_auto_byte_count = parameters[2]; - - maxwell3d.draw_manager->DrawArray( - maxwell3d.regs.draw.topology, 0, - maxwell3d.regs.draw_auto_byte_count / maxwell3d.regs.draw_auto_stride, 0, 1); + maxwell3d.draw_manager.DrawArray(maxwell3d, maxwell3d.regs.draw.topology, 0, maxwell3d.regs.draw_auto_byte_count / maxwell3d.regs.draw_auto_stride, 0, 1); } void HLE_C713C83D8F63CCF3::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { maxwell3d.RefreshParameters(); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index e268c4d2c6..3ce367e0d3 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -245,7 +245,7 @@ void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) { SyncState(); - const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); + const auto& draw_state = maxwell3d->draw_manager.draw_state; const GLenum primitive_mode = MaxwellToGL::PrimitiveTopology(draw_state.topology); BeginTransformFeedback(pipeline, primitive_mode); @@ -260,12 +260,12 @@ void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) { void RasterizerOpenGL::Draw(bool is_indexed, u32 instance_count) { PrepareDraw(is_indexed, [this, is_indexed, instance_count](GLenum primitive_mode) { - const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); - const GLuint base_instance = static_cast(draw_state.base_instance); - const GLsizei num_instances = static_cast(instance_count); + const auto& draw_state = maxwell3d->draw_manager.draw_state; + const GLuint base_instance = GLuint(draw_state.base_instance); + const GLsizei num_instances = GLsizei(instance_count); if (is_indexed) { - const GLint base_vertex = static_cast(draw_state.base_index); - const GLsizei num_vertices = static_cast(draw_state.index_buffer.count); + const GLint base_vertex = GLint(draw_state.base_index); + const GLsizei num_vertices = GLsizei(draw_state.index_buffer.count); const GLvoid* const offset = buffer_cache_runtime.IndexOffset(); const GLenum format = MaxwellToGL::IndexFormat(draw_state.index_buffer.format); if (num_instances == 1 && base_instance == 0 && base_vertex == 0) { @@ -302,7 +302,7 @@ void RasterizerOpenGL::Draw(bool is_indexed, u32 instance_count) { } void RasterizerOpenGL::DrawIndirect() { - const auto& params = maxwell3d->draw_manager->GetIndirectParams(); + const auto& params = maxwell3d->draw_manager.indirect_state; buffer_cache.SetDrawIndirect(¶ms); PrepareDraw(params.is_indexed, [this, ¶ms](GLenum primitive_mode) { if (params.is_byte_count) { @@ -358,12 +358,12 @@ void RasterizerOpenGL::DrawTexture() { SyncState(); - const auto& draw_texture_state = maxwell3d->draw_manager->GetDrawTextureState(); + const auto& draw_texture_state = maxwell3d->draw_manager.draw_texture_state; const auto& sampler = texture_cache.GetGraphicsSampler(draw_texture_state.src_sampler); const auto& texture = texture_cache.GetImageView(draw_texture_state.src_texture); const auto Scale = [&](auto dim) -> s32 { - return Settings::values.resolution_info.ScaleUp(static_cast(dim)); + return Settings::values.resolution_info.ScaleUp(s32(dim)); }; Region2D dst_region = { diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index aac7732005..18df857bc2 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -25,7 +25,7 @@ #include "shader_recompiler/frontend/maxwell/control_flow.h" #include "shader_recompiler/frontend/maxwell/translate_program.h" #include "shader_recompiler/profile.h" -#include "video_core/engines/draw_manager.h" +#include "video_core/engines/maxwell_3d.h" #include "video_core/engines/kepler_compute.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/memory_manager.h" @@ -362,7 +362,7 @@ GraphicsPipeline* ShaderCache::CurrentGraphicsPipeline() { const auto& regs{maxwell3d->regs}; graphics_key.raw = 0; graphics_key.early_z.Assign(regs.mandated_early_z != 0 ? 1 : 0); - graphics_key.gs_input_topology.Assign(maxwell3d->draw_manager->GetDrawState().topology); + graphics_key.gs_input_topology.Assign(maxwell3d->draw_manager.draw_state.topology); graphics_key.tessellation_primitive.Assign(regs.tessellation.params.domain_type.Value()); graphics_key.tessellation_spacing.Assign(regs.tessellation.params.spacing.Value()); graphics_key.tessellation_clockwise.Assign( @@ -402,7 +402,7 @@ GraphicsPipeline* ShaderCache::BuiltPipeline(GraphicsPipeline* pipeline) const n // If games are using a small index count, we can assume these are full screen quads. // Usually these shaders are only used once for building textures so we can assume they // can't be built async - const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); + const auto& draw_state = maxwell3d->draw_manager.draw_state; if (draw_state.index_buffer.count <= 6 || draw_state.vertex_buffer.count <= 6) { return pipeline; } diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp index 06cbd9e6da..8e95b7ad53 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.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 2019 yuzu Emulator Project @@ -12,7 +12,7 @@ #include "common/cityhash.h" #include "common/common_types.h" #include "common/settings.h" -#include "video_core/engines/draw_manager.h" +#include "video_core/engines/maxwell_3d.h" #include "video_core/renderer_vulkan/fixed_pipeline_state.h" #include "video_core/renderer_vulkan/vk_state_tracker.h" @@ -54,7 +54,7 @@ void RefreshXfbState(VideoCommon::TransformFeedbackState& state, const Maxwell& void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFeatures& features) { const Maxwell& regs = maxwell3d.regs; - const auto topology_ = maxwell3d.draw_manager->GetDrawState().topology; + const auto topology_ = maxwell3d.draw_manager.draw_state.topology; raw1 = 0; extended_dynamic_state.Assign(features.has_extended_dynamic_state ? 1 : 0); diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 77a4e8616a..c73ccf8436 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -675,7 +675,7 @@ GraphicsPipeline* PipelineCache::BuiltPipeline(GraphicsPipeline* pipeline) const // If games are using a small index count, we can assume these are full screen quads. // Usually these shaders are only used once for building textures so we can assume they // can't be built async - const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); + const auto& draw_state = maxwell3d->draw_manager.draw_state; if (draw_state.index_buffer.count <= 6 || draw_state.vertex_buffer.count <= 6) { return pipeline; } diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp index 8518d89eee..94cec29ca7 100644 --- a/src/video_core/renderer_vulkan/vk_query_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp @@ -16,7 +16,7 @@ #include "video_core/renderer_vulkan/vk_texture_cache.h" #include "common/bit_util.h" #include "common/common_types.h" -#include "video_core/engines/draw_manager.h" +#include "video_core/engines/maxwell_3d.h" #include "video_core/host1x/gpu_device_memory_manager.h" #include "video_core/query_cache/query_cache.h" #include "video_core/rasterizer_interface.h" @@ -902,7 +902,7 @@ private: streams_mask = 0; // reset previously recorded streams runtime.View3DRegs([this](Maxwell3D& maxwell3d) { buffers_count = 0; - out_topology = maxwell3d.draw_manager->GetDrawState().topology; + out_topology = maxwell3d.draw_manager.draw_state.topology; for (size_t i = 0; i < Maxwell3D::Regs::NumTransformFeedbackBuffers; i++) { const auto& tf = maxwell3d.regs.transform_feedback; if (tf.buffers[i].enable == 0) { diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index f867980a6f..efe6691c92 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -20,7 +20,7 @@ #include "video_core/buffer_cache/buffer_cache.h" #include "video_core/gpu_logging/gpu_logging.h" #include "video_core/control/channel_state.h" -#include "video_core/engines/draw_manager.h" +#include "video_core/engines/maxwell_3d.h" #include "video_core/engines/kepler_compute.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/host1x/gpu_device_memory_manager.h" @@ -46,7 +46,6 @@ namespace Vulkan { using Maxwell = Tegra::Engines::Maxwell3D::Regs; -using MaxwellDrawState = Tegra::Engines::DrawManager::State; using VideoCommon::ImageViewId; using VideoCommon::ImageViewType; @@ -151,7 +150,7 @@ VkRect2D GetScissorState(const Maxwell& regs, size_t index, u32 up_scale = 1, u3 return scissor; } -DrawParams MakeDrawParams(const MaxwellDrawState& draw_state, u32 num_instances, bool is_indexed) { +DrawParams MakeDrawParams(const Tegra::Engines::Maxwell3D::DrawManager::State& draw_state, u32 num_instances, bool is_indexed) { DrawParams params{ .base_instance = draw_state.base_instance, .num_instances = num_instances, @@ -231,15 +230,13 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) { UpdateDynamicStates(); HandleTransformFeedback(); - query_cache.CounterEnable(VideoCommon::QueryType::ZPassPixelCount64, - maxwell3d->regs.zpass_pixel_count_enable); - + query_cache.CounterEnable(VideoCommon::QueryType::ZPassPixelCount64, maxwell3d->regs.zpass_pixel_count_enable); draw_func(); } void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) { PrepareDraw(is_indexed, [this, is_indexed, instance_count] { - const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); + const auto& draw_state = maxwell3d->draw_manager.draw_state; const u32 num_instances{instance_count}; const DrawParams draw_params{MakeDrawParams(draw_state, num_instances, is_indexed)}; @@ -298,7 +295,7 @@ void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) { } void RasterizerVulkan::DrawIndirect() { - const auto& params = maxwell3d->draw_manager->GetIndirectParams(); + const auto& params = maxwell3d->draw_manager.indirect_state; buffer_cache.SetDrawIndirect(¶ms); PrepareDraw(params.is_indexed, [this, ¶ms] { const auto indirect_buffer = buffer_cache.GetDrawIndirectBuffer(); @@ -368,9 +365,8 @@ void RasterizerVulkan::DrawTexture() { UpdateDynamicStates(); - query_cache.CounterEnable(VideoCommon::QueryType::ZPassPixelCount64, - maxwell3d->regs.zpass_pixel_count_enable); - const auto& draw_texture_state = maxwell3d->draw_manager->GetDrawTextureState(); + query_cache.CounterEnable(VideoCommon::QueryType::ZPassPixelCount64, maxwell3d->regs.zpass_pixel_count_enable); + const auto& draw_texture_state = maxwell3d->draw_manager.draw_texture_state; const auto& sampler = texture_cache.GetGraphicsSampler(draw_texture_state.src_sampler); const auto& texture = texture_cache.GetImageView(draw_texture_state.src_texture); const auto* framebuffer = texture_cache.GetFramebuffer(); @@ -1530,10 +1526,9 @@ void RasterizerVulkan::UpdateDepthBiasEnable(Tegra::Engines::Maxwell3D::Regs& re regs.polygon_offset_line_enable, regs.polygon_offset_fill_enable, }; - const u32 topology_index = static_cast(maxwell3d->draw_manager->GetDrawState().topology); + const u32 topology_index = u32(maxwell3d->draw_manager.draw_state.topology); const u32 enable = enabled_lut[POLYGON_OFFSET_ENABLE_LUT[topology_index]]; - scheduler.Record( - [enable](vk::CommandBuffer cmdbuf) { cmdbuf.SetDepthBiasEnableEXT(enable != 0); }); + scheduler.Record([enable](vk::CommandBuffer cmdbuf) { cmdbuf.SetDepthBiasEnableEXT(enable != 0); }); } void RasterizerVulkan::UpdateLogicOpEnable(Tegra::Engines::Maxwell3D::Regs& regs) {