From 7faa63ea4ec99aec08f4e732462319048924a1a7 Mon Sep 17 00:00:00 2001 From: SDK Chan Date: Wed, 17 Sep 2025 15:12:29 +0000 Subject: [PATCH 01/12] [gpu/nvdrv] Unstub SetErrorNotifier, add PostErrorNotification function --- .../hle/service/nvdrv/devices/nvhost_gpu.cpp | 120 +++++++++++++++++- .../hle/service/nvdrv/devices/nvhost_gpu.h | 12 ++ 2 files changed, 127 insertions(+), 5 deletions(-) diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 5f754650d9..87012246fa 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -8,6 +8,7 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/core.h" +#include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_process.h" #include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/core/nvmap.h" @@ -161,11 +162,115 @@ NvResult nvhost_gpu::ZCullBind(IoctlZCullBind& params) { } NvResult nvhost_gpu::SetErrorNotifier(IoctlSetErrorNotifier& params) { - LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset, - params.size, params.mem); + LOG_DEBUG(Service_NVDRV, "called, offset={:#X}, size={:#X}, mem={:#X}", + params.offset, params.size, params.mem); + + if (!params.mem || !params.size) { + std::scoped_lock lk(channel_mutex); + if (!channel_state->initialized) { + LOG_CRITICAL(Service_NVDRV, "No address space bound for setting up error notifier!"); + return NvResult::NotInitialized; + } + + error_notifier_params = {}; + LOG_DEBUG(Service_NVDRV, "Error notifier disabled!"); + return NvResult::Success; + } + + constexpr u64 error_notification_size = sizeof(IoctlGetErrorNotification); + if (params.size < error_notification_size) { + LOG_ERROR(Service_NVDRV, "Error notification size: {:#X} is too small. Need at least {:#X}", params.size, + error_notification_size); + return NvResult::InvalidSize; + } + + auto handle = nvmap.GetHandle(static_cast(params.mem)); + if (!handle) { + LOG_ERROR(Service_NVDRV, "Unknown nvmap handle id {:#X}", params.mem); + return NvResult::BadParameter; + } + + + if (params.offset > handle->size || params.size > (handle->size - params.offset)) { + LOG_ERROR(Service_NVDRV, "Error notifier out of bounds: offset={:#X} size={:#X} handle size={:#X}", params.offset, + params.size, handle->size); + return NvResult::InvalidSize; + } + + u64 write_address, write_offset, handle_id; + { + std::scoped_lock lk(channel_mutex); + if (!channel_state->initialized) { + LOG_CRITICAL(Service_NVDRV, "No address space bound for setting up error notifier!"); + return NvResult::NotInitialized; + } + + error_notifier_params = params; + write_address = handle->address; + write_offset = params.offset; + handle_id = handle->id; + } + + if (write_address) { + IoctlGetErrorNotification error_notification{}; + error_notification.status = static_cast(NotifierStatus::NoError); + system.ApplicationMemory().WriteBlock(write_address + write_offset, &error_notification, sizeof(error_notification)); + } else { + LOG_WARNING(Service_NVDRV, + "nvmap handle id {:#X} has no virtual address assigned; " + "skipping initialization write for error notification!", + handle_id); + } + return NvResult::Success; } +void nvhost_gpu::PostErrorNotification(u32 info32, u16 info16, NotifierStatus status) { + IoctlSetErrorNotifier error_notifier_params_snapshot{}; + Kernel::KEvent *error_notifier_event_snapshot{}; + { + std::scoped_lock lk(channel_mutex); + error_notifier_params_snapshot = error_notifier_params; + error_notifier_event_snapshot = error_notifier_event; + } + + if (!error_notifier_params_snapshot.mem || error_notifier_params_snapshot.size < sizeof(IoctlGetErrorNotification)) { + LOG_DEBUG(Service_NVDRV, "PostErrorNotification: notifier not configured or too small!"); + return; + } + + auto handle = nvmap.GetHandle(static_cast(error_notifier_params_snapshot.mem)); + if (!handle || !handle->address) { + LOG_ERROR(Service_NVDRV, "PostErrorNotification: invalid handle or virtual address!"); + return; + } + + IoctlGetErrorNotification error_init{}; + error_init.info32 = info32; + error_init.info16 = info16; + error_init.status = static_cast(status); + const u64 write_size = std::min(sizeof(IoctlGetErrorNotification), + error_notifier_params_snapshot.size); + if (error_notifier_params_snapshot.offset >= handle->size || + write_size > (handle->size - error_notifier_params_snapshot.offset)) { + LOG_ERROR(Service_NVDRV, "PostErrorNotification: bounds check failed!"); + return; + } + + const u64 virtual_address = handle->address + error_notifier_params_snapshot.offset; + if (virtual_address < handle->address) { + LOG_ERROR(Service_NVDRV, "PostErrorNotification: virtual address overflow!"); + return; + } + + auto &application_memory = system.ApplicationMemory(); + application_memory.WriteBlock(virtual_address, &error_init, write_size); + + if (error_notifier_event_snapshot) { + error_notifier_event_snapshot->Signal(); + } +} + NvResult nvhost_gpu::SetChannelPriority(IoctlChannelSetPriority& params) { channel_priority = params.priority; LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); @@ -251,7 +356,7 @@ NvResult nvhost_gpu::AllocateObjectContext(IoctlAllocObjCtx& params) { params.flags = allowed_mask; } - s32_le ctx_class_number_index = + s32_le ctx_class_number_index = GetObjectContextClassNumberIndex(static_cast(params.class_num)); if (ctx_class_number_index < 0) { LOG_ERROR(Service_NVDRV, "Invalid class number for object context: {:#X}", @@ -324,6 +429,7 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandL if (flags.fence_wait.Value()) { if (flags.increment_value.Value()) { + PostErrorNotification(flags.raw, 0, NotifierStatus::GenericError); return NvResult::BadParameter; } @@ -357,7 +463,11 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandL NvResult nvhost_gpu::SubmitGPFIFOBase1(IoctlSubmitGpfifo& params, std::span commands, bool kickoff) { if (params.num_entries > commands.size()) { - UNIMPLEMENTED(); + LOG_ERROR(Service_NVDRV, + "SubmitGPFIFO: num_entries={:#X} > provided commands={:#X}", + params.num_entries, commands.size()); + + PostErrorNotification(params.num_entries, 0, NotifierStatus::BadGpfifo); return NvResult::InvalidSize; } @@ -376,7 +486,7 @@ NvResult nvhost_gpu::SubmitGPFIFOBase1(IoctlSubmitGpfifo& params, NvResult nvhost_gpu::SubmitGPFIFOBase2(IoctlSubmitGpfifo& params, std::span commands) { if (params.num_entries > commands.size()) { - UNIMPLEMENTED(); + PostErrorNotification(params.num_entries, 0, NotifierStatus::BadGpfifo); return NvResult::InvalidSize; } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index fb0a5be959..16c4a95474 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -66,6 +66,16 @@ private: CtxChannelGPFIFO = 0xB06F, }; + enum class NotifierStatus : u16_le { + NoError = 0xFFFF, + GenericError = 0x0001, + MmuFault = 0x0002, + IllegalMethod= 0x0003, + InvalidObject= 0x0004, + BadGpfifo = 0x0005, + TimeoutHang = 0x0006, + }; + struct IoctlSetNvmapFD { s32_le nvmap_fd{}; }; @@ -172,6 +182,8 @@ private: s32_le nvmap_fd{}; u64_le user_data{}; IoctlZCullBind zcull_params{}; + IoctlSetErrorNotifier error_notifier_params{}; + void PostErrorNotification(u32 info32, u16 info16, NotifierStatus status); std::array, 6> ctxObjs{}; u32_le channel_priority{}; u32_le channel_timeslice{}; From e81a358d8398908c76c034848c2c1bab092e518e Mon Sep 17 00:00:00 2001 From: SDK Chan Date: Wed, 17 Sep 2025 15:16:04 +0000 Subject: [PATCH 02/12] [gpu/nvdrv] Remove redundant whitespace --- src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 87012246fa..eb209bf599 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -190,7 +190,6 @@ NvResult nvhost_gpu::SetErrorNotifier(IoctlSetErrorNotifier& params) { return NvResult::BadParameter; } - if (params.offset > handle->size || params.size > (handle->size - params.offset)) { LOG_ERROR(Service_NVDRV, "Error notifier out of bounds: offset={:#X} size={:#X} handle size={:#X}", params.offset, params.size, handle->size); From a3c0d59dc9cbc8648d779e81df79b4f5e7ba6e16 Mon Sep 17 00:00:00 2001 From: lizzie Date: Fri, 19 Sep 2025 16:57:34 +0200 Subject: [PATCH 03/12] [android] update translations for dynarmic to say it's jit, remove "(slow)" from paranoid (#2527) Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2527 Reviewed-by: MaranBr Reviewed-by: crueter Co-authored-by: lizzie Co-committed-by: lizzie --- src/android/app/src/main/res/values-ar/strings.xml | 4 ++-- src/android/app/src/main/res/values-es/strings.xml | 4 ++-- src/android/app/src/main/res/values-fa/strings.xml | 4 ++-- src/android/app/src/main/res/values-fr/strings.xml | 4 ++-- src/android/app/src/main/res/values-he/strings.xml | 4 ++-- src/android/app/src/main/res/values-hu/strings.xml | 4 ++-- src/android/app/src/main/res/values-id/strings.xml | 4 ++-- src/android/app/src/main/res/values-ja/strings.xml | 4 ++-- src/android/app/src/main/res/values-ko/strings.xml | 4 ++-- src/android/app/src/main/res/values-pt-rBR/strings.xml | 4 ++-- src/android/app/src/main/res/values-pt-rPT/strings.xml | 4 ++-- src/android/app/src/main/res/values-ru/strings.xml | 4 ++-- src/android/app/src/main/res/values-sr/strings.xml | 4 ++-- src/android/app/src/main/res/values-zh-rCN/strings.xml | 4 ++-- src/android/app/src/main/res/values-zh-rTW/strings.xml | 4 ++-- src/android/app/src/main/res/values/strings.xml | 4 ++-- 16 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/android/app/src/main/res/values-ar/strings.xml b/src/android/app/src/main/res/values-ar/strings.xml index a758e1c7cd..35f7d20198 100644 --- a/src/android/app/src/main/res/values-ar/strings.xml +++ b/src/android/app/src/main/res/values-ar/strings.xml @@ -836,13 +836,13 @@ تمتد إلى النافذة - Dynarmic (بطيء) + Dynarmic (JIT) تنفيذ التعليمات البرمجية الأصلية (NCE) دقه غير آمن - Paranoid (بطيء) + Paranoid الأسهم diff --git a/src/android/app/src/main/res/values-es/strings.xml b/src/android/app/src/main/res/values-es/strings.xml index 2ee0e1783a..1f73df7385 100644 --- a/src/android/app/src/main/res/values-es/strings.xml +++ b/src/android/app/src/main/res/values-es/strings.xml @@ -919,13 +919,13 @@ Ajustar a la ventana - DynARMic (lento) + Dynarmic (JIT) Ejecución nativa de código (NCE) Preciso Impreciso - Paranoico (Lento) + Paranoico Cruceta diff --git a/src/android/app/src/main/res/values-fa/strings.xml b/src/android/app/src/main/res/values-fa/strings.xml index 79cf5f49e6..fd5c6ae6ca 100644 --- a/src/android/app/src/main/res/values-fa/strings.xml +++ b/src/android/app/src/main/res/values-fa/strings.xml @@ -918,13 +918,13 @@ کشش تا پر کردن پنجره - دینارمیک (کند) + Dynarmic (JIT) اجرای کد اصلی (NCE) دقیق ناامن - بدگمان (کند) + بدگمان کلیدهای جهتی diff --git a/src/android/app/src/main/res/values-fr/strings.xml b/src/android/app/src/main/res/values-fr/strings.xml index e9df08a4de..97496ef33d 100644 --- a/src/android/app/src/main/res/values-fr/strings.xml +++ b/src/android/app/src/main/res/values-fr/strings.xml @@ -967,13 +967,13 @@ Étirer à la fenêtre - Dynarmic (Lent) + Dynarmic (JIT) Exécution de code natif (NCE) Précis Risqué - Paranoïaque (Lent) + Paranoïaque Pavé directionnel diff --git a/src/android/app/src/main/res/values-he/strings.xml b/src/android/app/src/main/res/values-he/strings.xml index 4e1624a556..359e8dff9a 100644 --- a/src/android/app/src/main/res/values-he/strings.xml +++ b/src/android/app/src/main/res/values-he/strings.xml @@ -844,13 +844,13 @@ הרחב לגודל המסך - דינמי (איטי) + דינמי ביצוע קוד מקורי (NCE) מדויק לא בטוח - פראנואידי (איטי) + פראנואידי D-pad diff --git a/src/android/app/src/main/res/values-hu/strings.xml b/src/android/app/src/main/res/values-hu/strings.xml index 061ac07388..36157d1578 100644 --- a/src/android/app/src/main/res/values-hu/strings.xml +++ b/src/android/app/src/main/res/values-hu/strings.xml @@ -954,13 +954,13 @@ Ablakhoz nyújtás - Dinamikus (lassú) + Dynarmic (JIT) Natív kód végrehajtás (Native code execution (NCE)) Pontos Nem biztonságos - Paranoid (Lassú) + Paranoid D-pad diff --git a/src/android/app/src/main/res/values-id/strings.xml b/src/android/app/src/main/res/values-id/strings.xml index 6e3b64953f..18e881a97b 100644 --- a/src/android/app/src/main/res/values-id/strings.xml +++ b/src/android/app/src/main/res/values-id/strings.xml @@ -911,13 +911,13 @@ Merentangkan - Dynamic (Lambat) + Dynarmic (JIT) Native code execution (NCE) Akurat Berbahaya - Paranoid (Slow) + Paranoid D Pad diff --git a/src/android/app/src/main/res/values-ja/strings.xml b/src/android/app/src/main/res/values-ja/strings.xml index 179601f182..0a873b04eb 100644 --- a/src/android/app/src/main/res/values-ja/strings.xml +++ b/src/android/app/src/main/res/values-ja/strings.xml @@ -834,13 +834,13 @@ 画面に合わせる - Dynarmic (低速) + Dynarmic (JIT) ネイティブコード実行 (NCE) 正確 不安定 - パラノイド (低速) + パラノイド 方向ボタン diff --git a/src/android/app/src/main/res/values-ko/strings.xml b/src/android/app/src/main/res/values-ko/strings.xml index 6f4dd42af2..e598bb1120 100644 --- a/src/android/app/src/main/res/values-ko/strings.xml +++ b/src/android/app/src/main/res/values-ko/strings.xml @@ -910,13 +910,13 @@ 화면에 맞춤 - Dynarmic (느림) + Dynarmic (JIT) 네이티브 코드 실행 (NCE) 정확함 최적화 (안전하지 않음) - 최적화하지 않음 (느림) + 최적화하지 않음 십자키 diff --git a/src/android/app/src/main/res/values-pt-rBR/strings.xml b/src/android/app/src/main/res/values-pt-rBR/strings.xml index eec3fdf715..5571c2aea4 100644 --- a/src/android/app/src/main/res/values-pt-rBR/strings.xml +++ b/src/android/app/src/main/res/values-pt-rBR/strings.xml @@ -968,13 +968,13 @@ uma tentativa de mapeamento automático Esticar à janela - Dynarmic (Lenta) + Dynarmic (JIT) Execução de código nativo (NCE) Precisa Não segura - Paranoica (Lenta) + Paranoica Botões Direcionais diff --git a/src/android/app/src/main/res/values-pt-rPT/strings.xml b/src/android/app/src/main/res/values-pt-rPT/strings.xml index d45bf4bfc9..81aa7e92c0 100644 --- a/src/android/app/src/main/res/values-pt-rPT/strings.xml +++ b/src/android/app/src/main/res/values-pt-rPT/strings.xml @@ -968,13 +968,13 @@ uma tentativa de mapeamento automático Esticar à janela - Dynarmic (Lento) + Dynarmic (JIT) Native code execution (NCE) Preciso Inseguro - Paranoid (Lento) + Paranoid Botões Direcionais diff --git a/src/android/app/src/main/res/values-ru/strings.xml b/src/android/app/src/main/res/values-ru/strings.xml index 2f7714257f..eee249c44a 100644 --- a/src/android/app/src/main/res/values-ru/strings.xml +++ b/src/android/app/src/main/res/values-ru/strings.xml @@ -969,13 +969,13 @@ Растянуть до окна - Dynarmic (Медленно) + Dynarmic (JIT) Нативное выполнение (NCE) Точно Небезопасно - Параноик (медленно) + Параноик Крестовина diff --git a/src/android/app/src/main/res/values-sr/strings.xml b/src/android/app/src/main/res/values-sr/strings.xml index e261772fc4..b123757f5a 100644 --- a/src/android/app/src/main/res/values-sr/strings.xml +++ b/src/android/app/src/main/res/values-sr/strings.xml @@ -988,13 +988,13 @@ Протезање до прозора - Динамина (споро) + Dynarmic (JIT) Извођење изворног кода (НЦЕ) Тачан Несигуран - Параноичан (споро) + Параноичан Д-пад diff --git a/src/android/app/src/main/res/values-zh-rCN/strings.xml b/src/android/app/src/main/res/values-zh-rCN/strings.xml index bfdc3af3d3..5cf657ef3d 100644 --- a/src/android/app/src/main/res/values-zh-rCN/strings.xml +++ b/src/android/app/src/main/res/values-zh-rCN/strings.xml @@ -961,13 +961,13 @@ 拉伸窗口 - 动态编译 (慢速) + Dynarmic (JIT) 本机代码执行 (NCE) 高精度 低精度 - 偏执模式 (慢速) + 偏执模式 十字方向键 diff --git a/src/android/app/src/main/res/values-zh-rTW/strings.xml b/src/android/app/src/main/res/values-zh-rTW/strings.xml index e64aaa9a54..f4d690dbaa 100644 --- a/src/android/app/src/main/res/values-zh-rTW/strings.xml +++ b/src/android/app/src/main/res/values-zh-rTW/strings.xml @@ -966,13 +966,13 @@ 延展視窗 - 動態 (慢) + Dynarmic (JIT) 機器碼執行 (NCE) 高精度 低精度 - 不合理 (慢) + 不合理 方向鍵 diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 2cef5903cb..3b76c0ba79 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -1014,13 +1014,13 @@ Stretch to window - Dynarmic (Slow) + Dynarmic (JIT) Native code execution (NCE) Accurate Unsafe - Paranoid (Slow) + Paranoid D-pad From a487cea683ab4a43c25989637a8c7a9c39a7e695 Mon Sep 17 00:00:00 2001 From: Caio Oliveira Date: Fri, 19 Sep 2025 17:02:53 +0200 Subject: [PATCH 04/12] [core] Fix buiding with fmt 10 (#2524) Signed-off-by: Caio Oliveira Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2524 Reviewed-by: MaranBr Reviewed-by: crueter Co-authored-by: Caio Oliveira Co-committed-by: Caio Oliveira --- src/core/perf_stats.cpp | 12 +++++++++++- src/core/reporter.cpp | 7 ++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/core/perf_stats.cpp b/src/core/perf_stats.cpp index 4439611d2e..35e76624f4 100644 --- a/src/core/perf_stats.cpp +++ b/src/core/perf_stats.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2017 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -41,7 +44,14 @@ PerfStats::~PerfStats() { const auto path = Common::FS::GetEdenPath(Common::FS::EdenPath::LogDir); // %F Date format expanded is "%Y-%m-%d" - const auto filename = fmt::format("{:%F-%H-%M}_{:016X}.csv", *std::localtime(&t), title_id); + const auto filename = fmt::format("{}_{:016X}.csv", + [&] { + std::ostringstream oss; + oss << std::put_time(std::localtime(&t), "%F-%H-%M"); + return oss.str(); + }(), + title_id); + const auto filepath = path / filename; if (Common::FS::CreateParentDir(filepath)) { diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp index 4bac8142c3..1723636811 100644 --- a/src/core/reporter.cpp +++ b/src/core/reporter.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -33,7 +36,9 @@ std::filesystem::path GetPath(std::string_view type, u64 title_id, std::string_v std::string GetTimestamp() { const auto time = std::time(nullptr); - return fmt::format("{:%FT%H-%M-%S}", *std::localtime(&time)); + std::ostringstream oss; + oss << std::put_time(std::localtime(&time), "%FT%H-%M-%S"); + return oss.str(); } using namespace nlohmann; From 6510818fca962ebee78089e79e972221dfbe3ef4 Mon Sep 17 00:00:00 2001 From: crueter Date: Fri, 19 Sep 2025 18:20:51 +0200 Subject: [PATCH 05/12] [docs] fixup codeowners (#2529) Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2529 Reviewed-by: MaranBr Reviewed-by: Shinmegumi --- docs/CODEOWNERS | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/docs/CODEOWNERS b/docs/CODEOWNERS index 503f9ec1fe..dcb97a5e83 100644 --- a/docs/CODEOWNERS +++ b/docs/CODEOWNERS @@ -10,17 +10,18 @@ /.ci @crueter # cmake -*.cmake @crueter -*/CMakeLists.txt @crueter -*.in @crueter +*.cmake @crueter +*CMakeLists.txt @crueter +*.in @crueter # individual stuff -/src/web_service @AleksandrPopovich -/src/dynarmic @Lizzie -/src/core @Lizzie @Maufeat @PavelBARABANOV @MrPurple666 -/src/core/hle @Maufeat @PavelBARABANOV @SDK-Chan -/src/*_room @AleksandrPopovich -/src/video_core @CamilleLaVey @MaranBr @Wildcard @weakboson +src/web_service @AleksandrPopovich +src/dynarmic @Lizzie +src/core @Lizzie @Maufeat @PavelBARABANOV @MrPurple666 @JPikachu +src/core/hle @Maufeat @PavelBARABANOV @SDK-Chan +src/core/arm @Lizzie @MrPurple666 +src/*_room @AleksandrPopovich +src/video_core @CamilleLaVey @MaranBr @Wildcard @weakboson # Global owners/triage * @CamilleLaVey @Maufeat @crueter @MrPurple666 @MaranBr @Lizzie \ No newline at end of file From 725407b989b5f9021ae7f1aae664f7204cc94a47 Mon Sep 17 00:00:00 2001 From: MaranBr Date: Sat, 20 Sep 2025 14:17:07 +0200 Subject: [PATCH 06/12] [video_core] Add ability for integrated devices to control the amount of memory used by the emulator (#2528) This adds the ability for integrated devices to control the amount of memory used by the emulator. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2528 Reviewed-by: Lizzie Reviewed-by: Shinmegumi Co-authored-by: MaranBr Co-committed-by: MaranBr --- src/qt_common/shared_translation.cpp | 5 +---- src/video_core/vulkan_common/vulkan_device.cpp | 15 ++++++--------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/qt_common/shared_translation.cpp b/src/qt_common/shared_translation.cpp index cdc05e60e0..eb413f28e9 100644 --- a/src/qt_common/shared_translation.cpp +++ b/src/qt_common/shared_translation.cpp @@ -246,10 +246,7 @@ std::unique_ptr InitializeTranslations(QObject* parent) INSERT(Settings, vram_usage_mode, tr("VRAM Usage Mode:"), - tr("Selects whether the emulator should prefer to conserve memory or make maximum usage " - "of available video memory for performance.\nHas no effect on integrated graphics. " - "Aggressive mode may severely impact the performance of other applications such as " - "recording software.")); + tr("Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance.\nAggressive mode may severely impact the performance of other applications such as recording software.")); INSERT(Settings, skip_cpu_inner_invalidation, tr("Skip CPU Inner Invalidation"), diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 6d7c33099b..41917a1b90 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -1395,23 +1395,20 @@ void Device::CollectPhysicalMemoryInfo() { } device_access_memory += mem_properties.memoryHeaps[element].size; } - if (!is_integrated) { + if (is_integrated) { + const s64 available_memory = static_cast(device_access_memory - device_initial_usage); + const u64 memory_size = Settings::values.vram_usage_mode.GetValue() == Settings::VramUsageMode::Aggressive ? 6_GiB : 4_GiB; + device_access_memory = static_cast(std::max(std::min(available_memory - 8_GiB, memory_size), std::min(local_memory, memory_size))); + } else { const u64 reserve_memory = std::min(device_access_memory / 8, 1_GiB); device_access_memory -= reserve_memory; - if (Settings::values.vram_usage_mode.GetValue() != Settings::VramUsageMode::Aggressive) { // Account for resolution scaling in memory limits const size_t normal_memory = 6_GiB; const size_t scaler_memory = 1_GiB * Settings::values.resolution_info.ScaleUp(1); - device_access_memory = - std::min(device_access_memory, normal_memory + scaler_memory); + device_access_memory = std::min(device_access_memory, normal_memory + scaler_memory); } - - return; } - const s64 available_memory = static_cast(device_access_memory - device_initial_usage); - device_access_memory = static_cast(std::max( - std::min(available_memory - 8_GiB, 6_GiB), std::min(local_memory, 6_GiB))); } void Device::CollectToolingInfo() { From 87d42cf542a9d7c9c6222459bd71927958a78359 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 20 Sep 2025 17:43:59 +0200 Subject: [PATCH 07/12] [fs] remove usage of subpar PooledBuffer (#342) PoolBuffer is a subpar "reimplementation" of an equivalent std::vector Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/342 Reviewed-by: crueter Reviewed-by: Shinmegumi Co-authored-by: lizzie Co-committed-by: lizzie --- src/core/CMakeLists.txt | 3 +- .../fssystem/fssystem_aes_ctr_storage.cpp | 30 ++---- .../fssystem/fssystem_aes_xts_storage.cpp | 16 ++-- .../fssystem_alignment_matching_storage.h | 28 ++---- .../fssystem/fssystem_bucket_tree.cpp | 24 +---- .../fssystem_bucket_tree_template_impl.h | 32 +++---- .../fssystem/fssystem_compressed_storage.h | 36 +++---- .../fssystem/fssystem_pooled_buffer.cpp | 61 ------------ .../fssystem/fssystem_pooled_buffer.h | 95 ------------------- 9 files changed, 54 insertions(+), 271 deletions(-) delete mode 100644 src/core/file_sys/fssystem/fssystem_pooled_buffer.cpp delete mode 100644 src/core/file_sys/fssystem/fssystem_pooled_buffer.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 4d9566a60f..3c28ebd911 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -107,8 +107,7 @@ add_library(core STATIC file_sys/fssystem/fssystem_nca_header.cpp file_sys/fssystem/fssystem_nca_header.h file_sys/fssystem/fssystem_nca_reader.cpp - file_sys/fssystem/fssystem_pooled_buffer.cpp - file_sys/fssystem/fssystem_pooled_buffer.h + file_sys/fssystem/fssystem_passthrough_storage.h file_sys/fssystem/fssystem_sparse_storage.cpp file_sys/fssystem/fssystem_sparse_storage.h file_sys/fssystem/fssystem_switch_storage.h diff --git a/src/core/file_sys/fssystem/fssystem_aes_ctr_storage.cpp b/src/core/file_sys/fssystem/fssystem_aes_ctr_storage.cpp index c18fde18f4..aaf7788801 100644 --- a/src/core/file_sys/fssystem/fssystem_aes_ctr_storage.cpp +++ b/src/core/file_sys/fssystem/fssystem_aes_ctr_storage.cpp @@ -1,10 +1,12 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "common/alignment.h" #include "common/swap.h" #include "core/file_sys/fssystem/fssystem_aes_ctr_storage.h" -#include "core/file_sys/fssystem/fssystem_pooled_buffer.h" #include "core/file_sys/fssystem/fssystem_utility.h" namespace FileSys { @@ -76,13 +78,6 @@ size_t AesCtrStorage::Write(const u8* buffer, size_t size, size_t offset) { ASSERT(Common::IsAligned(offset, BlockSize)); ASSERT(Common::IsAligned(size, BlockSize)); - // Get a pooled buffer. - PooledBuffer pooled_buffer; - const bool use_work_buffer = true; - if (use_work_buffer) { - pooled_buffer.Allocate(size, BlockSize); - } - // Setup the counter. std::array ctr; std::memcpy(ctr.data(), m_iv.data(), IvSize); @@ -91,25 +86,20 @@ size_t AesCtrStorage::Write(const u8* buffer, size_t size, size_t offset) { // Loop until all data is written. size_t remaining = size; s64 cur_offset = 0; + + // Get a pooled buffer. + std::vector pooled_buffer(BlockSize); while (remaining > 0) { // Determine data we're writing and where. - const size_t write_size = - use_work_buffer ? (std::min)(pooled_buffer.GetSize(), remaining) : remaining; - - void* write_buf; - if (use_work_buffer) { - write_buf = pooled_buffer.GetBuffer(); - } else { - write_buf = const_cast(buffer); - } + const size_t write_size = std::min(pooled_buffer.size(), remaining); + u8* write_buf = reinterpret_cast(pooled_buffer.data()); // Encrypt the data. m_cipher->SetIV(ctr); - m_cipher->Transcode(buffer, write_size, reinterpret_cast(write_buf), - Core::Crypto::Op::Encrypt); + m_cipher->Transcode(buffer, write_size, write_buf, Core::Crypto::Op::Encrypt); // Write the encrypted data. - m_base_storage->Write(reinterpret_cast(write_buf), write_size, offset + cur_offset); + m_base_storage->Write(write_buf, write_size, offset + cur_offset); // Advance. cur_offset += write_size; diff --git a/src/core/file_sys/fssystem/fssystem_aes_xts_storage.cpp b/src/core/file_sys/fssystem/fssystem_aes_xts_storage.cpp index 5ef2544dfb..9e7a104c89 100644 --- a/src/core/file_sys/fssystem/fssystem_aes_xts_storage.cpp +++ b/src/core/file_sys/fssystem/fssystem_aes_xts_storage.cpp @@ -1,11 +1,12 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "common/alignment.h" #include "common/swap.h" -#include "core/file_sys/errors.h" #include "core/file_sys/fssystem/fssystem_aes_xts_storage.h" -#include "core/file_sys/fssystem/fssystem_pooled_buffer.h" #include "core/file_sys/fssystem/fssystem_utility.h" namespace FileSys { @@ -69,17 +70,14 @@ size_t AesXtsStorage::Read(u8* buffer, size_t size, size_t offset) const { // Decrypt into a pooled buffer. { - PooledBuffer tmp_buf(m_block_size, m_block_size); - ASSERT(tmp_buf.GetSize() >= m_block_size); - - std::memset(tmp_buf.GetBuffer(), 0, skip_size); - std::memcpy(tmp_buf.GetBuffer() + skip_size, buffer, data_size); + std::vector tmp_buf(m_block_size, 0); + std::memcpy(tmp_buf.data() + skip_size, buffer, data_size); m_cipher->SetIV(ctr); - m_cipher->Transcode(tmp_buf.GetBuffer(), m_block_size, tmp_buf.GetBuffer(), + m_cipher->Transcode(tmp_buf.data(), m_block_size, tmp_buf.data(), Core::Crypto::Op::Decrypt); - std::memcpy(buffer, tmp_buf.GetBuffer() + skip_size, data_size); + std::memcpy(buffer, tmp_buf.data() + skip_size, data_size); } AddCounter(ctr.data(), IvSize, 1); diff --git a/src/core/file_sys/fssystem/fssystem_alignment_matching_storage.h b/src/core/file_sys/fssystem/fssystem_alignment_matching_storage.h index f96691d03d..60a6d24435 100644 --- a/src/core/file_sys/fssystem/fssystem_alignment_matching_storage.h +++ b/src/core/file_sys/fssystem/fssystem_alignment_matching_storage.h @@ -1,13 +1,14 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include "common/alignment.h" -#include "core/file_sys/errors.h" #include "core/file_sys/fssystem/fs_i_storage.h" #include "core/file_sys/fssystem/fssystem_alignment_matching_storage_impl.h" -#include "core/file_sys/fssystem/fssystem_pooled_buffer.h" namespace FileSys { @@ -89,10 +90,11 @@ private: VirtualFile m_base_storage; s64 m_base_storage_size; size_t m_data_align; + mutable std::vector work_buffer; public: explicit AlignmentMatchingStoragePooledBuffer(VirtualFile bs, size_t da) - : m_base_storage(std::move(bs)), m_data_align(da) { + : m_base_storage(std::move(bs)), m_data_align(da), work_buffer(da) { ASSERT(Common::IsPowerOfTwo(da)); } @@ -104,16 +106,10 @@ public: // Validate arguments. ASSERT(buffer != nullptr); - s64 bs_size = this->GetSize(); ASSERT(R_SUCCEEDED(IStorage::CheckAccessRange(offset, size, bs_size))); - - // Allocate a pooled buffer. - PooledBuffer pooled_buffer; - pooled_buffer.AllocateParticularlyLarge(m_data_align, m_data_align); - - return AlignmentMatchingStorageImpl::Read(m_base_storage, pooled_buffer.GetBuffer(), - pooled_buffer.GetSize(), m_data_align, + return AlignmentMatchingStorageImpl::Read(m_base_storage, work_buffer.data(), + work_buffer.size(), m_data_align, BufferAlign, offset, buffer, size); } @@ -125,16 +121,10 @@ public: // Validate arguments. ASSERT(buffer != nullptr); - s64 bs_size = this->GetSize(); ASSERT(R_SUCCEEDED(IStorage::CheckAccessRange(offset, size, bs_size))); - - // Allocate a pooled buffer. - PooledBuffer pooled_buffer; - pooled_buffer.AllocateParticularlyLarge(m_data_align, m_data_align); - - return AlignmentMatchingStorageImpl::Write(m_base_storage, pooled_buffer.GetBuffer(), - pooled_buffer.GetSize(), m_data_align, + return AlignmentMatchingStorageImpl::Write(m_base_storage, work_buffer.data(), + work_buffer.size(), m_data_align, BufferAlign, offset, buffer, size); } diff --git a/src/core/file_sys/fssystem/fssystem_bucket_tree.cpp b/src/core/file_sys/fssystem/fssystem_bucket_tree.cpp index f58b154968..ce3b62f26d 100644 --- a/src/core/file_sys/fssystem/fssystem_bucket_tree.cpp +++ b/src/core/file_sys/fssystem/fssystem_bucket_tree.cpp @@ -7,7 +7,6 @@ #include "core/file_sys/errors.h" #include "core/file_sys/fssystem/fssystem_bucket_tree.h" #include "core/file_sys/fssystem/fssystem_bucket_tree_utils.h" -#include "core/file_sys/fssystem/fssystem_pooled_buffer.h" namespace FileSys { @@ -465,16 +464,8 @@ Result BucketTree::Visitor::Find(s64 virtual_address) { } Result BucketTree::Visitor::FindEntrySet(s32* out_index, s64 virtual_address, s32 node_index) { - const auto node_size = m_tree->m_node_size; - - PooledBuffer pool(node_size, 1); - if (node_size <= pool.GetSize()) { - R_RETURN( - this->FindEntrySetWithBuffer(out_index, virtual_address, node_index, pool.GetBuffer())); - } else { - pool.Deallocate(); - R_RETURN(this->FindEntrySetWithoutBuffer(out_index, virtual_address, node_index)); - } + std::vector pool(m_tree->m_node_size); + R_RETURN(FindEntrySetWithBuffer(out_index, virtual_address, node_index, pool.data())); } Result BucketTree::Visitor::FindEntrySetWithBuffer(s32* out_index, s64 virtual_address, @@ -525,15 +516,8 @@ Result BucketTree::Visitor::FindEntrySetWithoutBuffer(s32* out_index, s64 virtua } Result BucketTree::Visitor::FindEntry(s64 virtual_address, s32 entry_set_index) { - const auto entry_set_size = m_tree->m_node_size; - - PooledBuffer pool(entry_set_size, 1); - if (entry_set_size <= pool.GetSize()) { - R_RETURN(this->FindEntryWithBuffer(virtual_address, entry_set_index, pool.GetBuffer())); - } else { - pool.Deallocate(); - R_RETURN(this->FindEntryWithoutBuffer(virtual_address, entry_set_index)); - } + std::vector pool(m_tree->m_node_size); + R_RETURN(FindEntryWithBuffer(virtual_address, entry_set_index, pool.data())); } Result BucketTree::Visitor::FindEntryWithBuffer(s64 virtual_address, s32 entry_set_index, diff --git a/src/core/file_sys/fssystem/fssystem_bucket_tree_template_impl.h b/src/core/file_sys/fssystem/fssystem_bucket_tree_template_impl.h index 030b2916b0..fac6c37214 100644 --- a/src/core/file_sys/fssystem/fssystem_bucket_tree_template_impl.h +++ b/src/core/file_sys/fssystem/fssystem_bucket_tree_template_impl.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -6,7 +9,6 @@ #include "core/file_sys/errors.h" #include "core/file_sys/fssystem/fssystem_bucket_tree.h" #include "core/file_sys/fssystem/fssystem_bucket_tree_utils.h" -#include "core/file_sys/fssystem/fssystem_pooled_buffer.h" namespace FileSys { @@ -35,23 +37,19 @@ Result BucketTree::ScanContinuousReading(ContinuousReadingInfo* out_info, R_UNLESS(entry.GetVirtualOffset() <= cur_offset, ResultOutOfRange); // Create a pooled buffer for our scan. - PooledBuffer pool(m_node_size, 1); - char* buffer = nullptr; - + std::vector pool(m_node_size); s64 entry_storage_size = m_entry_storage->GetSize(); // Read the node. - if (m_node_size <= pool.GetSize()) { - buffer = pool.GetBuffer(); - const auto ofs = param.entry_set.index * static_cast(m_node_size); - R_UNLESS(m_node_size + ofs <= static_cast(entry_storage_size), - ResultInvalidBucketTreeNodeEntryCount); + u8* buffer = reinterpret_cast(pool.data()); + const auto ofs = param.entry_set.index * s64(m_node_size); + R_UNLESS(m_node_size + ofs <= size_t(entry_storage_size), + ResultInvalidBucketTreeNodeEntryCount); - m_entry_storage->Read(reinterpret_cast(buffer), m_node_size, ofs); - } + m_entry_storage->Read(buffer, m_node_size, ofs); // Calculate extents. - const auto end_offset = cur_offset + static_cast(param.size); + const auto end_offset = cur_offset + s64(param.size); s64 phys_offset = entry.GetPhysicalOffset(); // Start merge tracking. @@ -76,14 +74,8 @@ Result BucketTree::ScanContinuousReading(ContinuousReadingInfo* out_info, s64 next_entry_offset; if (entry_index + 1 < entry_count) { - if (buffer != nullptr) { - const auto ofs = impl::GetBucketTreeEntryOffset(0, m_entry_size, entry_index + 1); - std::memcpy(std::addressof(next_entry), buffer + ofs, m_entry_size); - } else { - const auto ofs = impl::GetBucketTreeEntryOffset(param.entry_set.index, m_node_size, - m_entry_size, entry_index + 1); - m_entry_storage->ReadObject(std::addressof(next_entry), ofs); - } + const auto offset = impl::GetBucketTreeEntryOffset(0, m_entry_size, entry_index + 1); + std::memcpy(std::addressof(next_entry), buffer + offset, m_entry_size); next_entry_offset = next_entry.GetVirtualOffset(); R_UNLESS(param.offsets.IsInclude(next_entry_offset), ResultInvalidIndirectEntryOffset); diff --git a/src/core/file_sys/fssystem/fssystem_compressed_storage.h b/src/core/file_sys/fssystem/fssystem_compressed_storage.h index 74c98630ec..223d51647e 100644 --- a/src/core/file_sys/fssystem/fssystem_compressed_storage.h +++ b/src/core/file_sys/fssystem/fssystem_compressed_storage.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -9,8 +12,6 @@ #include "core/file_sys/fssystem/fs_i_storage.h" #include "core/file_sys/fssystem/fssystem_bucket_tree.h" #include "core/file_sys/fssystem/fssystem_compression_common.h" -#include "core/file_sys/fssystem/fssystem_pooled_buffer.h" -#include "core/file_sys/vfs/vfs.h" namespace FileSys { @@ -317,23 +318,11 @@ private: R_SUCCEED_IF(entry_count == 0); // Get the remaining size in a convenient form. - const size_t total_required_size = - static_cast(required_access_physical_size); + const size_t total_required_size = size_t(required_access_physical_size); // Perform the read based on whether we need to allocate a buffer. if (will_allocate_pooled_buffer) { - // Allocate a pooled buffer. - PooledBuffer pooled_buffer; - if (pooled_buffer.GetAllocatableSizeMax() >= total_required_size) { - pooled_buffer.Allocate(total_required_size, m_block_size_max); - } else { - pooled_buffer.AllocateParticularlyLarge( - std::min( - total_required_size, - PooledBuffer::GetAllocatableParticularlyLargeSizeMax()), - m_block_size_max); - } - + std::vector pooled_buffer(std::max(m_block_size_max, total_required_size)); // Read each of the entries. for (s32 entry_idx = 0; entry_idx < entry_count; ++entry_idx) { // Determine the current read size. @@ -342,13 +331,13 @@ private: if (const size_t target_entry_size = static_cast(entries[entry_idx].physical_size) + static_cast(entries[entry_idx].gap_from_prev); - target_entry_size <= pooled_buffer.GetSize()) { + target_entry_size <= pooled_buffer.size()) { // We'll be using the pooled buffer. will_use_pooled_buffer = true; // Determine how much we can read. const size_t max_size = std::min( - required_access_physical_size, pooled_buffer.GetSize()); + required_access_physical_size, pooled_buffer.size()); size_t read_size = 0; for (auto n = entry_idx; n < entry_count; ++n) { @@ -376,7 +365,7 @@ private: // Perform the read based on whether or not we'll use the pooled buffer. if (will_use_pooled_buffer) { // Read the compressed data into the pooled buffer. - auto* const buffer = pooled_buffer.GetBuffer(); + auto* const buffer = pooled_buffer.data(); m_data_storage->Read(reinterpret_cast(buffer), cur_read_size, required_access_physical_offset); @@ -863,11 +852,9 @@ private: static_cast(unaligned_range->virtual_size)); // Get a pooled buffer for our read. - PooledBuffer pooled_buffer; - pooled_buffer.Allocate(size_buffer_required, size_buffer_required); - + std::vector pooled_buffer(size_buffer_required); // Perform read. - Result rc = read_impl(pooled_buffer.GetBuffer(), size_buffer_required); + Result rc = read_impl(pooled_buffer.data(), size_buffer_required); if (R_FAILED(rc)) { R_THROW(rc); } @@ -876,8 +863,7 @@ private: const size_t skip_size = cur_offset - unaligned_range->virtual_offset; const size_t copy_size = std::min( cur_size, unaligned_range->GetEndVirtualOffset() - cur_offset); - - std::memcpy(cur_dst, pooled_buffer.GetBuffer() + skip_size, copy_size); + std::memcpy(cur_dst, pooled_buffer.data() + skip_size, copy_size); // Advance. cur_dst += copy_size; diff --git a/src/core/file_sys/fssystem/fssystem_pooled_buffer.cpp b/src/core/file_sys/fssystem/fssystem_pooled_buffer.cpp deleted file mode 100644 index dcd08dac3e..0000000000 --- a/src/core/file_sys/fssystem/fssystem_pooled_buffer.cpp +++ /dev/null @@ -1,61 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "common/alignment.h" -#include "core/file_sys/fssystem/fssystem_pooled_buffer.h" - -namespace FileSys { - -namespace { - -constexpr size_t HeapBlockSize = BufferPoolAlignment; -static_assert(HeapBlockSize == 4_KiB); - -// A heap block is 4KiB. An order is a power of two. -// This gives blocks of the order 32KiB, 512KiB, 4MiB. -constexpr s32 HeapOrderMax = 7; -constexpr s32 HeapOrderMaxForLarge = HeapOrderMax + 3; - -constexpr size_t HeapAllocatableSizeMax = HeapBlockSize * (static_cast(1) << HeapOrderMax); -constexpr size_t HeapAllocatableSizeMaxForLarge = - HeapBlockSize * (static_cast(1) << HeapOrderMaxForLarge); - -} // namespace - -size_t PooledBuffer::GetAllocatableSizeMaxCore(bool large) { - return large ? HeapAllocatableSizeMaxForLarge : HeapAllocatableSizeMax; -} - -void PooledBuffer::AllocateCore(size_t ideal_size, size_t required_size, bool large) { - // Ensure preconditions. - ASSERT(m_buffer == nullptr); - - // Check that we can allocate this size. - ASSERT(required_size <= GetAllocatableSizeMaxCore(large)); - - const size_t target_size = - (std::min)((std::max)(ideal_size, required_size), GetAllocatableSizeMaxCore(large)); - - // Dummy implementation for allocate. - if (target_size > 0) { - m_buffer = - reinterpret_cast(::operator new(target_size, std::align_val_t{HeapBlockSize})); - m_size = target_size; - - // Ensure postconditions. - ASSERT(m_buffer != nullptr); - } -} - -void PooledBuffer::Shrink(size_t ideal_size) { - ASSERT(ideal_size <= GetAllocatableSizeMaxCore(true)); - - // Shrinking to zero means that we have no buffer. - if (ideal_size == 0) { - ::operator delete(m_buffer, std::align_val_t{HeapBlockSize}); - m_buffer = nullptr; - m_size = ideal_size; - } -} - -} // namespace FileSys diff --git a/src/core/file_sys/fssystem/fssystem_pooled_buffer.h b/src/core/file_sys/fssystem/fssystem_pooled_buffer.h deleted file mode 100644 index 9a6adbcb5a..0000000000 --- a/src/core/file_sys/fssystem/fssystem_pooled_buffer.h +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "common/common_funcs.h" -#include "common/common_types.h" -#include "common/literals.h" -#include "core/hle/result.h" - -namespace FileSys { - -using namespace Common::Literals; - -constexpr inline size_t BufferPoolAlignment = 4_KiB; -constexpr inline size_t BufferPoolWorkSize = 320; - -class PooledBuffer { - YUZU_NON_COPYABLE(PooledBuffer); - -public: - // Constructor/Destructor. - constexpr PooledBuffer() : m_buffer(), m_size() {} - - PooledBuffer(size_t ideal_size, size_t required_size) : m_buffer(), m_size() { - this->Allocate(ideal_size, required_size); - } - - ~PooledBuffer() { - this->Deallocate(); - } - - // Move and assignment. - explicit PooledBuffer(PooledBuffer&& rhs) : m_buffer(rhs.m_buffer), m_size(rhs.m_size) { - rhs.m_buffer = nullptr; - rhs.m_size = 0; - } - - PooledBuffer& operator=(PooledBuffer&& rhs) { - PooledBuffer(std::move(rhs)).Swap(*this); - return *this; - } - - // Allocation API. - void Allocate(size_t ideal_size, size_t required_size) { - return this->AllocateCore(ideal_size, required_size, false); - } - - void AllocateParticularlyLarge(size_t ideal_size, size_t required_size) { - return this->AllocateCore(ideal_size, required_size, true); - } - - void Shrink(size_t ideal_size); - - void Deallocate() { - // Shrink the buffer to empty. - this->Shrink(0); - ASSERT(m_buffer == nullptr); - } - - char* GetBuffer() const { - ASSERT(m_buffer != nullptr); - return m_buffer; - } - - size_t GetSize() const { - ASSERT(m_buffer != nullptr); - return m_size; - } - -public: - static size_t GetAllocatableSizeMax() { - return GetAllocatableSizeMaxCore(false); - } - static size_t GetAllocatableParticularlyLargeSizeMax() { - return GetAllocatableSizeMaxCore(true); - } - -private: - static size_t GetAllocatableSizeMaxCore(bool large); - -private: - void Swap(PooledBuffer& rhs) { - std::swap(m_buffer, rhs.m_buffer); - std::swap(m_size, rhs.m_size); - } - - void AllocateCore(size_t ideal_size, size_t required_size, bool large); - -private: - char* m_buffer; - size_t m_size; -}; - -} // namespace FileSys From 28b8159da1d5c9a82042cf43a86cec01d5758254 Mon Sep 17 00:00:00 2001 From: wildcard Date: Sat, 20 Sep 2025 17:52:40 +0200 Subject: [PATCH 08/12] [VK] Change barrier to transfer in present manager (#315) There is no Color_attachment happening here only transfer operation and hence the gpu should only wait for transfer not color_attachment_output_bit(may fix async presentation, not likely though) Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/315 Reviewed-by: Shinmegumi Reviewed-by: MaranBr Co-authored-by: wildcard Co-committed-by: wildcard --- src/video_core/renderer_vulkan/vk_present_manager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_present_manager.cpp b/src/video_core/renderer_vulkan/vk_present_manager.cpp index 2c76584c72..23279e49b9 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_present_manager.cpp @@ -470,8 +470,8 @@ void PresentManager::CopyToSwapchainImpl(Frame* frame) { const std::array wait_semaphores = {present_semaphore, *frame->render_ready}; static constexpr std::array wait_stage_masks{ - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, }; const VkSubmitInfo submit_info{ From 4b558e530324492c8321ba7e582a40442331d0d8 Mon Sep 17 00:00:00 2001 From: Gamer64 Date: Sat, 20 Sep 2025 17:54:14 +0200 Subject: [PATCH 09/12] [hw_composer]: Add some enhancements to improve its performance and logic (#225) These changes should mostly improve the performance for most of games and reduce reallocations from framebuffer releases. Co-authored-by: Gamer64 <76565986+Gamer64ytb@users.noreply.github.com> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/225 Reviewed-by: MaranBr Reviewed-by: Lizzie Co-authored-by: Gamer64 Co-committed-by: Gamer64 --- .../service/nvnflinger/hardware_composer.cpp | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/core/hle/service/nvnflinger/hardware_composer.cpp b/src/core/hle/service/nvnflinger/hardware_composer.cpp index a262a3dcd5..5c0515d473 100644 --- a/src/core/hle/service/nvnflinger/hardware_composer.cpp +++ b/src/core/hle/service/nvnflinger/hardware_composer.cpp @@ -53,6 +53,19 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display, // Set default speed limit to 100%. *out_speed_scale = 1.0f; + // If no layers are available, skip the logic. + bool any_visible = false; + for (auto& layer : display.stack.layers) { + if (layer->visible) { + any_visible = true; + break; + } + } + if (!any_visible) { + *out_speed_scale = 1.0f; + return 1; + } + // Determine the number of vsync periods to wait before composing again. std::optional swap_interval{}; bool has_acquired_buffer{}; @@ -110,7 +123,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display, } // If any new buffers were acquired, we can present. - if (has_acquired_buffer) { + if (has_acquired_buffer && !composition_stack.empty()) { // Sort by Z-index. std::stable_sort(composition_stack.begin(), composition_stack.end(), [&](auto& l, auto& r) { return l.z_index < r.z_index; }); @@ -119,6 +132,19 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display, nvdisp.Composite(composition_stack); } + // Batch framebuffer releases, instead of one-into-one. + std::vector> to_release; + for (auto& [layer_id, framebuffer] : m_framebuffers) { + if (framebuffer.release_frame_number > m_frame_number || !framebuffer.is_acquired) + continue; + if (auto layer = display.stack.FindLayer(layer_id); layer) + to_release.emplace_back(layer.get(), &framebuffer); + } + for (auto& [layer, framebuffer] : to_release) { + layer->buffer_item_consumer->ReleaseBuffer(framebuffer->item, android::Fence::NoFence()); + framebuffer->is_acquired = false; + } + // Advance by at least one frame. const u32 frame_advance = swap_interval.value_or(1); m_frame_number += frame_advance; From d623e0460699adc2f8a70e8a52b549b20477ef30 Mon Sep 17 00:00:00 2001 From: Shinmegumi Date: Sat, 20 Sep 2025 18:19:44 +0200 Subject: [PATCH 10/12] Fix src/core/cmakelists.txt (#2537) Removed entry that was added back trying to fix a conflict in a PR. Signed-off-by: Shinmegumi Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2537 Reviewed-by: Lizzie Reviewed-by: MaranBr Co-authored-by: Shinmegumi Co-committed-by: Shinmegumi --- src/core/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 3c28ebd911..6b64ab7820 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -107,7 +107,6 @@ add_library(core STATIC file_sys/fssystem/fssystem_nca_header.cpp file_sys/fssystem/fssystem_nca_header.h file_sys/fssystem/fssystem_nca_reader.cpp - file_sys/fssystem/fssystem_passthrough_storage.h file_sys/fssystem/fssystem_sparse_storage.cpp file_sys/fssystem/fssystem_sparse_storage.h file_sys/fssystem/fssystem_switch_storage.h From 8f1a574fe04d0976833d68ac952c1dfe0805c196 Mon Sep 17 00:00:00 2001 From: SDK Chan Date: Wed, 17 Sep 2025 15:12:29 +0000 Subject: [PATCH 11/12] [gpu/nvdrv] Unstub SetErrorNotifier, add PostErrorNotification function --- .../hle/service/nvdrv/devices/nvhost_gpu.cpp | 120 +++++++++++++++++- .../hle/service/nvdrv/devices/nvhost_gpu.h | 12 ++ 2 files changed, 127 insertions(+), 5 deletions(-) diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 5f754650d9..87012246fa 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -8,6 +8,7 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/core.h" +#include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_process.h" #include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/core/nvmap.h" @@ -161,11 +162,115 @@ NvResult nvhost_gpu::ZCullBind(IoctlZCullBind& params) { } NvResult nvhost_gpu::SetErrorNotifier(IoctlSetErrorNotifier& params) { - LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset, - params.size, params.mem); + LOG_DEBUG(Service_NVDRV, "called, offset={:#X}, size={:#X}, mem={:#X}", + params.offset, params.size, params.mem); + + if (!params.mem || !params.size) { + std::scoped_lock lk(channel_mutex); + if (!channel_state->initialized) { + LOG_CRITICAL(Service_NVDRV, "No address space bound for setting up error notifier!"); + return NvResult::NotInitialized; + } + + error_notifier_params = {}; + LOG_DEBUG(Service_NVDRV, "Error notifier disabled!"); + return NvResult::Success; + } + + constexpr u64 error_notification_size = sizeof(IoctlGetErrorNotification); + if (params.size < error_notification_size) { + LOG_ERROR(Service_NVDRV, "Error notification size: {:#X} is too small. Need at least {:#X}", params.size, + error_notification_size); + return NvResult::InvalidSize; + } + + auto handle = nvmap.GetHandle(static_cast(params.mem)); + if (!handle) { + LOG_ERROR(Service_NVDRV, "Unknown nvmap handle id {:#X}", params.mem); + return NvResult::BadParameter; + } + + + if (params.offset > handle->size || params.size > (handle->size - params.offset)) { + LOG_ERROR(Service_NVDRV, "Error notifier out of bounds: offset={:#X} size={:#X} handle size={:#X}", params.offset, + params.size, handle->size); + return NvResult::InvalidSize; + } + + u64 write_address, write_offset, handle_id; + { + std::scoped_lock lk(channel_mutex); + if (!channel_state->initialized) { + LOG_CRITICAL(Service_NVDRV, "No address space bound for setting up error notifier!"); + return NvResult::NotInitialized; + } + + error_notifier_params = params; + write_address = handle->address; + write_offset = params.offset; + handle_id = handle->id; + } + + if (write_address) { + IoctlGetErrorNotification error_notification{}; + error_notification.status = static_cast(NotifierStatus::NoError); + system.ApplicationMemory().WriteBlock(write_address + write_offset, &error_notification, sizeof(error_notification)); + } else { + LOG_WARNING(Service_NVDRV, + "nvmap handle id {:#X} has no virtual address assigned; " + "skipping initialization write for error notification!", + handle_id); + } + return NvResult::Success; } +void nvhost_gpu::PostErrorNotification(u32 info32, u16 info16, NotifierStatus status) { + IoctlSetErrorNotifier error_notifier_params_snapshot{}; + Kernel::KEvent *error_notifier_event_snapshot{}; + { + std::scoped_lock lk(channel_mutex); + error_notifier_params_snapshot = error_notifier_params; + error_notifier_event_snapshot = error_notifier_event; + } + + if (!error_notifier_params_snapshot.mem || error_notifier_params_snapshot.size < sizeof(IoctlGetErrorNotification)) { + LOG_DEBUG(Service_NVDRV, "PostErrorNotification: notifier not configured or too small!"); + return; + } + + auto handle = nvmap.GetHandle(static_cast(error_notifier_params_snapshot.mem)); + if (!handle || !handle->address) { + LOG_ERROR(Service_NVDRV, "PostErrorNotification: invalid handle or virtual address!"); + return; + } + + IoctlGetErrorNotification error_init{}; + error_init.info32 = info32; + error_init.info16 = info16; + error_init.status = static_cast(status); + const u64 write_size = std::min(sizeof(IoctlGetErrorNotification), + error_notifier_params_snapshot.size); + if (error_notifier_params_snapshot.offset >= handle->size || + write_size > (handle->size - error_notifier_params_snapshot.offset)) { + LOG_ERROR(Service_NVDRV, "PostErrorNotification: bounds check failed!"); + return; + } + + const u64 virtual_address = handle->address + error_notifier_params_snapshot.offset; + if (virtual_address < handle->address) { + LOG_ERROR(Service_NVDRV, "PostErrorNotification: virtual address overflow!"); + return; + } + + auto &application_memory = system.ApplicationMemory(); + application_memory.WriteBlock(virtual_address, &error_init, write_size); + + if (error_notifier_event_snapshot) { + error_notifier_event_snapshot->Signal(); + } +} + NvResult nvhost_gpu::SetChannelPriority(IoctlChannelSetPriority& params) { channel_priority = params.priority; LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); @@ -251,7 +356,7 @@ NvResult nvhost_gpu::AllocateObjectContext(IoctlAllocObjCtx& params) { params.flags = allowed_mask; } - s32_le ctx_class_number_index = + s32_le ctx_class_number_index = GetObjectContextClassNumberIndex(static_cast(params.class_num)); if (ctx_class_number_index < 0) { LOG_ERROR(Service_NVDRV, "Invalid class number for object context: {:#X}", @@ -324,6 +429,7 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandL if (flags.fence_wait.Value()) { if (flags.increment_value.Value()) { + PostErrorNotification(flags.raw, 0, NotifierStatus::GenericError); return NvResult::BadParameter; } @@ -357,7 +463,11 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandL NvResult nvhost_gpu::SubmitGPFIFOBase1(IoctlSubmitGpfifo& params, std::span commands, bool kickoff) { if (params.num_entries > commands.size()) { - UNIMPLEMENTED(); + LOG_ERROR(Service_NVDRV, + "SubmitGPFIFO: num_entries={:#X} > provided commands={:#X}", + params.num_entries, commands.size()); + + PostErrorNotification(params.num_entries, 0, NotifierStatus::BadGpfifo); return NvResult::InvalidSize; } @@ -376,7 +486,7 @@ NvResult nvhost_gpu::SubmitGPFIFOBase1(IoctlSubmitGpfifo& params, NvResult nvhost_gpu::SubmitGPFIFOBase2(IoctlSubmitGpfifo& params, std::span commands) { if (params.num_entries > commands.size()) { - UNIMPLEMENTED(); + PostErrorNotification(params.num_entries, 0, NotifierStatus::BadGpfifo); return NvResult::InvalidSize; } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index fb0a5be959..16c4a95474 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -66,6 +66,16 @@ private: CtxChannelGPFIFO = 0xB06F, }; + enum class NotifierStatus : u16_le { + NoError = 0xFFFF, + GenericError = 0x0001, + MmuFault = 0x0002, + IllegalMethod= 0x0003, + InvalidObject= 0x0004, + BadGpfifo = 0x0005, + TimeoutHang = 0x0006, + }; + struct IoctlSetNvmapFD { s32_le nvmap_fd{}; }; @@ -172,6 +182,8 @@ private: s32_le nvmap_fd{}; u64_le user_data{}; IoctlZCullBind zcull_params{}; + IoctlSetErrorNotifier error_notifier_params{}; + void PostErrorNotification(u32 info32, u16 info16, NotifierStatus status); std::array, 6> ctxObjs{}; u32_le channel_priority{}; u32_le channel_timeslice{}; From 1722ef66c57cf4396096ca8f0d494e75c30f4226 Mon Sep 17 00:00:00 2001 From: SDK Chan Date: Wed, 17 Sep 2025 15:16:04 +0000 Subject: [PATCH 12/12] [gpu/nvdrv] Remove redundant whitespace --- src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 87012246fa..eb209bf599 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -190,7 +190,6 @@ NvResult nvhost_gpu::SetErrorNotifier(IoctlSetErrorNotifier& params) { return NvResult::BadParameter; } - if (params.offset > handle->size || params.size > (handle->size - params.offset)) { LOG_ERROR(Service_NVDRV, "Error notifier out of bounds: offset={:#X} size={:#X} handle size={:#X}", params.offset, params.size, handle->size);