aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn <john@eden-emu.dev>2026-10-26 17:25:47 +0100
committercrueter <crueter@eden-emu.dev>2026-10-26 17:25:47 +0100
commitcbd4cf2d8ce9b66936bff8a19be4715e770e0c71 (patch)
tree19a801331313cb67205f872b64709bfb708f38d1 /src
parenta3debcf731143aabd6eefee406d511551d3c9a73 (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')
-rw-r--r--src/core/core.cpp40
-rw-r--r--src/core/core.h4
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_storage.cpp12
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_storage.h6
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp11
-rw-r--r--src/core/hle/service/service.cpp16
-rw-r--r--src/core/hle/service/service.h2
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.