diff options
| author | John <john@eden-emu.dev> | 2026-10-26 17:25:47 +0100 |
|---|---|---|
| committer | crueter <crueter@eden-emu.dev> | 2026-10-26 17:25:47 +0100 |
| commit | cbd4cf2d8ce9b66936bff8a19be4715e770e0c71 (patch) | |
| tree | 19a801331313cb67205f872b64709bfb708f38d1 /src/core | |
| parent | a3debcf731143aabd6eefee406d511551d3c9a73 (diff) | |
[hle][core] Hang Freeze Fix - Video Fixes - Revert Microsleep (#4316) (#4525)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.
-------------------
Credit: amicuchu
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Fixes Mario Strikers Intro Freezing from legacy.
- Microsleep no longer needed for Absolum Video freezing and other videos freezing.
- Revert `[service, nvhost] added machinery to allow microsleep between nvdec read requests to avoid guest panic in some games #4316`
- Tested with CPU/GPU decoding on Linux/Windows.
Special thanks to xbzk
<video src="/attachments/9f4a4494-78ee-4b65-ad26-628e83d5c83b" title="strikers" controls></video>
Co-authored-by: Your Name <John@John.localdomain>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4525
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/core.cpp | 40 | ||||
| -rw-r--r-- | src/core/core.h | 4 | ||||
| -rw-r--r-- | src/core/hle/service/filesystem/fsp/fs_i_storage.cpp | 12 | ||||
| -rw-r--r-- | src/core/hle/service/filesystem/fsp/fs_i_storage.h | 6 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp | 11 | ||||
| -rw-r--r-- | src/core/hle/service/service.cpp | 16 | ||||
| -rw-r--r-- | src/core/hle/service/service.h | 2 |
7 files changed, 28 insertions, 63 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp index 046ee53346..06543b0833 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -4,7 +4,6 @@ #include <array> #include <atomic> #include <memory> -#include <unordered_map> #include <utility> #include "game_settings.h" @@ -249,30 +248,12 @@ struct System::Impl { } } - void NotifyNVDECChannelOpen(u64 process_id) { - std::scoped_lock lock{nvdec_active_mutex}; - ++nvdec_active_channels[process_id]; - } - - void NotifyNVDECChannelClose(u64 process_id) { - std::scoped_lock lock{nvdec_active_mutex}; - const auto it = nvdec_active_channels.find(process_id); - if (it == nvdec_active_channels.end()) { - return; - } - if (--it->second == 0) { - nvdec_active_channels.erase(it); - } + void SetNVDECActive(bool is_nvdec_active) { + nvdec_active = is_nvdec_active; } bool GetNVDECActive() { - std::scoped_lock lock{nvdec_active_mutex}; - return !nvdec_active_channels.empty(); - } - - bool IsNVDECActiveForProcess(u64 process_id) { - std::scoped_lock lock{nvdec_active_mutex}; - return nvdec_active_channels.contains(process_id); + return nvdec_active; } void InitializeDebugger(System& system, u16 port) { @@ -528,8 +509,6 @@ struct System::Impl { mutable std::mutex suspend_guard; std::mutex general_channel_mutex; - std::mutex nvdec_active_mutex; - std::unordered_map<u64, u32> nvdec_active_channels; std::atomic_bool is_paused{}; std::atomic_bool is_shutting_down{}; std::atomic_bool is_powered_on{}; @@ -537,6 +516,7 @@ struct System::Impl { bool extended_memory_layout : 1 = false; bool exit_locked : 1 = false; bool exit_requested : 1 = false; + bool nvdec_active : 1 = false; void EnsureGeneralChannelInitialized(System& system) { if (!general_channel_event) { @@ -600,22 +580,14 @@ void System::UnstallApplication() { impl->UnstallApplication(); } -void System::NotifyNVDECChannelOpen(u64 process_id) { - impl->NotifyNVDECChannelOpen(process_id); -} - -void System::NotifyNVDECChannelClose(u64 process_id) { - impl->NotifyNVDECChannelClose(process_id); +void System::SetNVDECActive(bool is_nvdec_active) { + impl->SetNVDECActive(is_nvdec_active); } bool System::GetNVDECActive() { return impl->GetNVDECActive(); } -bool System::IsNVDECActiveForProcess(u64 process_id) { - return impl->IsNVDECActiveForProcess(process_id); -} - void System::InitializeDebugger() { impl->InitializeDebugger(*this, Settings::values.gdbstub_port.GetValue()); } diff --git a/src/core/core.h b/src/core/core.h index e26093f260..d88ed64151 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -191,10 +191,8 @@ public: std::unique_lock<std::mutex> StallApplication(); void UnstallApplication(); - void NotifyNVDECChannelOpen(u64 process_id); - void NotifyNVDECChannelClose(u64 process_id); + void SetNVDECActive(bool is_nvdec_active); [[nodiscard]] bool GetNVDECActive(); - [[nodiscard]] bool IsNVDECActiveForProcess(u64 process_id); /** * Initialize the debugger. diff --git a/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp b/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp index 50b7d1e765..8541c17817 100644 --- a/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp +++ b/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp @@ -4,6 +4,10 @@ // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include <algorithm> +#include <chrono> +#include <thread> + #include "core/file_sys/errors.h" #include "core/hle/service/cmif_serialization.h" #include "core/hle/service/filesystem/fsp/fs_i_storage.h" @@ -31,6 +35,14 @@ Result IStorage::Read( R_UNLESS(length >= 0, FileSys::ResultInvalidSize); R_UNLESS(offset >= 0, FileSys::ResultInvalidOffset); + const auto now = std::chrono::steady_clock::now(); + if (now < next_read_tick) { + std::this_thread::sleep_for(next_read_tick - now); + } + next_read_tick = std::chrono::steady_clock::now() + + std::chrono::nanoseconds{std::min(length, MaxChargedReadSize) * + 1'000'000'000 / ReadBytesPerSecond}; + // Read the data from the Storage backend backend->Read(out_bytes.data(), length, offset); diff --git a/src/core/hle/service/filesystem/fsp/fs_i_storage.h b/src/core/hle/service/filesystem/fsp/fs_i_storage.h index e676c52220..bac72d73c7 100644 --- a/src/core/hle/service/filesystem/fsp/fs_i_storage.h +++ b/src/core/hle/service/filesystem/fsp/fs_i_storage.h @@ -6,6 +6,8 @@ #pragma once +#include <chrono> + #include "core/file_sys/vfs/vfs.h" #include "core/hle/service/cmif_types.h" #include "core/hle/service/filesystem/filesystem.h" @@ -20,6 +22,10 @@ public: private: FileSys::VirtualFile backend; + static constexpr s64 ReadBytesPerSecond = 40'000'000; + static constexpr s64 MaxChargedReadSize = 64 * 1024; + std::chrono::steady_clock::time_point next_read_tick{}; + Result Read( OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_bytes, s64 offset, s64 length); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index f47369adb8..7ac3dfaa46 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp @@ -8,7 +8,6 @@ #include "common/assert.h" #include "common/logging.h" #include "core/core.h" -#include "core/hle/kernel/k_process.h" #include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/devices/ioctl_serialization.h" #include "core/hle/service/nvdrv/devices/nvhost_nvdec.h" @@ -72,23 +71,17 @@ NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in void nvhost_nvdec::OnOpen(NvCore::SessionId session_id, DeviceFD fd) { LOG_INFO(Service_NVDRV, "NVDEC video stream started"); + system.SetNVDECActive(true); sessions[fd] = session_id; - if (const auto* session = core.GetSession(session_id); - session != nullptr && session->process != nullptr) { - system.NotifyNVDECChannelOpen(session->process->GetId()); - } host1x.StartDevice(fd, Tegra::Host1x::ChannelType::NvDec, channel_syncpoint); } void nvhost_nvdec::OnClose(DeviceFD fd) { LOG_INFO(Service_NVDRV, "NVDEC video stream ended"); host1x.StopDevice(fd, Tegra::Host1x::ChannelType::NvDec); + system.SetNVDECActive(false); auto it = sessions.find(fd); if (it != sessions.end()) { - if (const auto* session = core.GetSession(it->second); - session != nullptr && session->process != nullptr) { - system.NotifyNVDECChannelClose(session->process->GetId()); - } sessions.erase(it); } } diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 225b92a783..b4fe2b3ed5 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -4,16 +4,12 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include <chrono> #include <fmt/ranges.h> -#include <string_view> -#include <thread> #include "common/assert.h" #include "common/logging.h" #include "common/settings.h" #include "core/core.h" #include "core/hle/ipc.h" -#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/kernel.h" #include "core/hle/service/ipc_helpers.h" #include "core/hle/service/service.h" @@ -37,7 +33,6 @@ ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* se : SessionRequestHandler(system_.Kernel(), service_name_) , system{system_} , service_name{service_name_} - , is_i_storage{std::string_view{service_name_} == "IStorage"} , handler_invoker{handler_invoker_} , max_sessions{max_sessions_} {} @@ -82,22 +77,13 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(HLERequestContext& ctx, } void ServiceFrameworkBase::InvokeRequest(HLERequestContext& ctx) { - const auto command = ctx.GetCommand(); - auto it = handlers.find(command); - const bool is_cmd_read = command == 0; + auto it = handlers.find(ctx.GetCommand()); FunctionInfoBase const* info = it == handlers.end() ? nullptr : &it->second; if (info == nullptr || info->handler_callback == nullptr) return ReportUnimplementedFunction(ctx, info); LOG_TRACE(Service, "{}", MakeFunctionString(info->name, GetServiceName(), ctx.CommandBuffer())); handler_invoker(this, info->handler_callback, ctx); - - if (is_i_storage && is_cmd_read) { - const auto* const process = ctx.GetThread().GetOwnerProcess(); - if (process != nullptr && system.IsNVDECActiveForProcess(process->GetId())) { - std::this_thread::sleep_for(std::chrono::microseconds{600}); - } - } } void ServiceFrameworkBase::InvokeRequestTipc(HLERequestContext& ctx) { diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index ea98897e79..68b0d636d8 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -107,8 +107,6 @@ protected: Core::System& system; /// Identifier string used to connect to the service. const char* service_name; - /// Whether this is the IStorage service. - const bool is_i_storage; /// Function used to safely up-cast pointers to the derived class before invoking a handler. InvokerFn* handler_invoker; /// Maximum number of concurrent sessions that this service can handle. |
