From 3005cc4149a0c9a5d7228d8ec69d5e7e89c4a935 Mon Sep 17 00:00:00 2001 From: Paulo Rossatto Date: Sun, 1 Nov 2026 14:10:03 -0400 Subject: core: do not index registered_processes with an unregistered ASID --- src/core/device_memory_manager.inc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc index 83faa1b3f3..498a1c5f64 100644 --- a/src/core/device_memory_manager.inc +++ b/src/core/device_memory_manager.inc @@ -582,6 +582,11 @@ void DeviceMemoryManager::UpdatePagesCachedCountNoLock(DAddr addr, size_ const size_t page_end = Common::DivCeil(addr + size, Memory::YUZU_PAGESIZE); size_t page = addr >> Memory::YUZU_PAGEBITS; auto [asid, base_vaddress] = ExtractCPUBacking(page); + // Sem processo registrado nao ha o que marcar, e asid.id 0 indexaria um vetor vazio. Acontece + // no alvo de testes, que chama UpdatePagesCachedBatch num DeviceMemoryManager recem-criado. + if (asid.id >= registered_processes.size()) { + return; + } auto* memory_device_inter = registered_processes[asid.id]; const auto release_pending = [&] { if (uncache_bytes > 0) { -- cgit v1.2.3 From 8af82558bb25bb2ab46f3d750d3da55b82512e41 Mon Sep 17 00:00:00 2001 From: rdenno Date: Mon, 2 Nov 2026 06:51:36 -0500 Subject: texture_cache: look up X8Z24 with UNORM, UINT, UNORM, UNORM components X8Z24 was only known with UINT in the last three components. Mario Tennis Fever samples its depth buffer as X8Z24 with components UNORM, UINT, UNORM, UNORM (as S8Z24 already is in the table), which hit the "texture format=42" fallback to A8B8G8R8. The depth image was then copied into a colour image of the wrong format every frame (with "Unimplemented" layer-count asserts) and read as colour, and distant scenery around the court (the arch and the castle stadium) wasn't drawn. Map it to X8_D24_UNORM like the other X8Z24 entry. Assisted-by: Claude Opus 5.5 (diagnosis, fix and testing) --- src/video_core/texture_cache/format_lookup_table.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/video_core/texture_cache/format_lookup_table.cpp b/src/video_core/texture_cache/format_lookup_table.cpp index 20bb96aae3..18be2dcbf3 100644 --- a/src/video_core/texture_cache/format_lookup_table.cpp +++ b/src/video_core/texture_cache/format_lookup_table.cpp @@ -150,6 +150,7 @@ PixelFormat PixelFormatFromTextureInfo(TextureFormat format, ComponentType red, case Hash(TextureFormat::X8Z24, UNORM): return PixelFormat::X8_D24_UNORM; case Hash(TextureFormat::X8Z24, UNORM, UINT, UINT, UINT, LINEAR): + case Hash(TextureFormat::X8Z24, UNORM, UINT, UNORM, UNORM, LINEAR): return PixelFormat::X8_D24_UNORM; case Hash(TextureFormat::Z24S8, UINT, UNORM, UNORM, UNORM, LINEAR): return PixelFormat::S8_UINT_D24_UNORM; -- cgit v1.2.3 From 7f42af81ad657e339f5cba78487cb7422e49e9ae Mon Sep 17 00:00:00 2001 From: Takoroka <137927095+Takoroka@users.noreply.github.com> Date: Mon, 2 Nov 2026 09:25:15 -0500 Subject: video_core: bump the shader cache versions for the FSEL lowering fix The disk shader cache keeps the lowered native code. "shader: apply FSEL's floating operand modifiers" (ef3ae4ae23) changed that code without a version bump, so caches built before it keep programs that drop FSEL's negate until the user deletes them by hand. In Splatoon Raiders those stale programs leave the tutorial island and the dock with no shadows (the depth linearization ends with FSEL R0, -R0, 1.0, P and comes out negated), no aiming reticle and no steam (particle quads pick their corners with FSEL +0.5 / -0.5 and collapse to a point). --- src/video_core/renderer_opengl/gl_shader_cache.cpp | 2 +- src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 277cf222fa..df18f151f1 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -54,7 +54,7 @@ using VideoCommon::LoadPipelines; using VideoCommon::SerializePipeline; using Context = ShaderContext::Context; -constexpr u32 CACHE_VERSION = 15; +constexpr u32 CACHE_VERSION = 16; template auto MakeSpan(Container& container) { diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 05511c10e1..ce5cbf57b4 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -65,7 +65,7 @@ using VideoCommon::FileEnvironment; using VideoCommon::GenericEnvironment; using VideoCommon::GraphicsEnvironment; -constexpr u32 CACHE_VERSION = 18; +constexpr u32 CACHE_VERSION = 19; constexpr size_t VULKAN_CACHE_FLUSH_PIPELINES = 128; constexpr size_t VULKAN_CACHE_FLUSH_MIN_SECONDS = 30; constexpr std::array VULKAN_CACHE_MAGIC_NUMBER{'y', 'u', 'z', 'u', 'v', 'k', 'c', 'h'}; -- cgit v1.2.3 From e64268269f4f91e47087fc86de4d34ec84970992 Mon Sep 17 00:00:00 2001 From: Franz Date: Mon, 2 Nov 2026 17:46:22 +0100 Subject: Prevents crashes when creating game shortcuts by validating the loader before accessing game titles or icons. Adds safe fallbacks for missing titles and icons, allowing shortcuts to be created even when the game loader or icon is unavailable. Fixes a potential crash when creating game shortcuts, as reported in Issue #274. Previously, the shortcut creation process attempted to retrieve the game title and icon even when GetLoader() returned an invalid loader. This could cause a crash when the selected game file could not be loaded correctly. Changes Validate the loader: Check whether the loader is valid before accessing game title or icon data. Preserve title fallback: Continue using the title from game metadata whenever available. If no valid loader is available, fall back to the program ID. Handle missing icons: Only attempt to retrieve the game icon when a valid loader exists. Log a warning if the icon cannot be retrieved. Validate image data: Add a validity check in SaveIconToFile() to prevent empty or invalid images from being processed. Expected Behavior Game shortcuts can now be created even when no valid loader or game icon is available. In such cases, the program ID is used as the display name, and the shortcut is created without a custom game icon. --- src/qt_common/util/game.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/qt_common/util/game.cpp b/src/qt_common/util/game.cpp index ddbe979765..ba669c3acf 100644 --- a/src/qt_common/util/game.cpp +++ b/src/qt_common/util/game.cpp @@ -430,8 +430,10 @@ void CreateShortcut(const std::string& game_path, const u64 program_id, game_title = fmt::format("{:016X}", program_id); if (control.first != nullptr) { game_title = control.first->GetApplicationName(); - } else { + } else if (loader != nullptr) { loader->ReadTitle(game_title); + } else { + LOG_WARNING(Frontend, "Could not load game title from {:s}", game_path); } } @@ -448,7 +450,8 @@ void CreateShortcut(const std::string& game_path, const u64 program_id, std::vector icon_image_file{}; if (control.second != nullptr) { icon_image_file = control.second->ReadAllBytes(); - } else if (loader->ReadIcon(icon_image_file) != Loader::ResultStatus::Success) { + } else if (loader == nullptr || + loader->ReadIcon(icon_image_file) != Loader::ResultStatus::Success) { LOG_WARNING(Frontend, "Could not read icon from {:s}", game_path); } @@ -535,6 +538,10 @@ void CreateHomeMenuShortcut(ShortcutTarget target) { } bool SaveIconToFile(const std::filesystem::path& icon_path, const QImage& image) { + if (image.isNull()) { + return false; + } + #if defined(WIN32) #pragma pack(push, 2) struct IconDir { -- cgit v1.2.3 From 76f6aec860116ed2044e98770fda6e24289a5672 Mon Sep 17 00:00:00 2001 From: Daniel Cabral Date: Mon, 2 Nov 2026 16:06:33 -0300 Subject: tests when building on Windows: compare FindBestUpdatePackage with a size_t FindBestUpdatePackage returns std::optional, and comparing it with an int makes MSVC emit C4388 inside , which WERROR turns into an error, so the tests target does not build on Windows. Part of #326. Assisted-by: Claude Opus 5.5 (diagnosis, fix and commit message draft) --- src/tests/core/nup_writer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/core/nup_writer.cpp b/src/tests/core/nup_writer.cpp index c0230d8694..e598c98868 100644 --- a/src/tests/core/nup_writer.cpp +++ b/src/tests/core/nup_writer.cpp @@ -208,7 +208,7 @@ TEST_CASE("NUP packs base, updates and add-ons and reads back through NupContain REQUIRE(packages[3].kind == NupContainer::PackageKind::Addon); REQUIRE(packages[3].title_id == 0x0400ABCD00011001ULL); REQUIRE(packages[3].exefs_dir == 0xFFFFFFFF); - REQUIRE(nup.FindBestUpdatePackage() == 2); + REQUIRE(nup.FindBestUpdatePackage() == std::size_t{2}); REQUIRE(PackedTree(nup.GetExeFSDir(0)) == SourceTree(root / "Base/ExeFS")); REQUIRE(PackedTree(nup.GetRomFSDir(0)) == SourceTree(root / "Base/RomFS")); -- cgit v1.2.3 From 80bfef8e0c5f9d3112424d04062afbe6c3968320 Mon Sep 17 00:00:00 2001 From: Dennys Kaluzny Pereira <64793570+protonnegativo@users.noreply.github.com> Date: Mon, 2 Nov 2026 15:05:40 -0300 Subject: input_common/sdl: only log motion capabilities when they change On the Steam Deck the log was flooded with the same gyro message, over 3000 times in a single session. Motion capabilities are now only logged when they change, and the sensor restart interval grows exponentially (up to 64x) while the sensor keeps returning zeroed data. Tested with Pokemon Pokopia on the Steam Deck: from ~42 messages in 33s down to 1 for the whole session, controls working normally. Assisted-by: Claude Opus 5.5 (debugging, code, and drafting this message) --- src/input_common/drivers/sdl_driver.cpp | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index c3e9a066b3..a308554071 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -3,6 +3,7 @@ // SPDX-FileCopyrightText: 2018 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include #include #include #include "common/logging.h" @@ -115,7 +116,15 @@ public: } } - LOG_INFO(Input, "Controller motion capabilities: accel={} gyro={}", has_accel, has_gyro); + // EnableMotion is also called to recover a stalled sensor, so only log when the reported + // capabilities actually change instead of on every restart. + if (!motion_capabilities_logged || logged_accel != has_accel || logged_gyro != has_gyro) { + LOG_INFO(Input, "Controller motion capabilities: accel={} gyro={}", has_accel, + has_gyro); + motion_capabilities_logged = true; + logged_accel = has_accel; + logged_gyro = has_gyro; + } } bool HasMotion() const { @@ -163,16 +172,21 @@ public: // Motion data is invalid if (motion.accel_x == 0 && motion.gyro_x == 0 && motion.accel_y == 0 && motion.gyro_y == 0 && motion.accel_z == 0 && motion.gyro_z == 0) { - if (motion_error_count++ < 200) { + if (motion_error_count++ < motion_restart_threshold) { return false; } - // Try restarting the sensor + // Try restarting the sensor. Back off exponentially so a sensor that keeps reporting + // zeros (observed on the Steam Deck) isn't toggled several times a + // second for the whole session. motion_error_count = 0; + motion_restart_threshold = + std::min(motion_restart_threshold * 2, MaxMotionRestartThreshold); EnableMotion(); return false; } motion_error_count = 0; + motion_restart_threshold = InitialMotionRestartThreshold; motion.delta_timestamp = time_difference; return true; } @@ -393,7 +407,13 @@ private: mutable std::mutex mutex; u64 last_motion_update{}; + static constexpr std::size_t InitialMotionRestartThreshold = 200; + static constexpr std::size_t MaxMotionRestartThreshold = 200 * 64; std::size_t motion_error_count{}; + std::size_t motion_restart_threshold{InitialMotionRestartThreshold}; + bool motion_capabilities_logged{false}; + bool logged_accel{false}; + bool logged_gyro{false}; bool has_gyro{false}; bool has_accel{false}; bool has_vibration{false}; -- cgit v1.2.3 From e996661b99f4102f35e2aea596a67646afb127b0 Mon Sep 17 00:00:00 2001 From: Jonas Date: Tue, 3 Nov 2026 04:56:47 +0600 Subject: qt: ask about the recommended MKW settings only when booting MKW The prompt showed at every startup whatever game was launched, and Yes overwrote the global settings for every title. Ask on the first MKW boot of a session instead and apply the preset to that session only. --- src/yuzu/main_window.cpp | 37 ++++++++++++++----------------------- src/yuzu/main_window.h | 1 + 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/src/yuzu/main_window.cpp b/src/yuzu/main_window.cpp index 8fa39e07e3..dbe5ea2334 100644 --- a/src/yuzu/main_window.cpp +++ b/src/yuzu/main_window.cpp @@ -459,29 +459,6 @@ MainWindow::MainWindow(bool has_broken_vulkan) // Gen keys if necessary OnCheckFirmwareDecryption(false); - auto* recommendations = new QMessageBox( - QMessageBox::Question, tr("Recommended Mario Kart World settings"), - tr("Use the recommended settings for Mario Kart World?\n\n" - "Vulkan, 1x resolution, GPU Fast, asynchronous shaders, BC3, conservative VRAM, " - "reactive flushing off, FIFO Relaxed VSync, handheld mode, ScaleForce, and FXAA.\n\n" - "Yes replaces your saved settings. No or closing this window keeps your settings."), - QMessageBox::Yes | QMessageBox::No, this); - recommendations->setAttribute(Qt::WA_DeleteOnClose); - recommendations->setDefaultButton(QMessageBox::No); - recommendations->setEscapeButton(QMessageBox::No); - recommendations->setWindowModality(Qt::NonModal); - connect(recommendations, &QMessageBox::finished, this, [this](int result) { - use_recommended_mkw_settings = result == QMessageBox::Yes; - if (use_recommended_mkw_settings && !emulation_running && !boot_in_progress) { - Settings::SetMarioKartWorldRecommendedSettings(Settings::values, true); - config->SaveAllValues(); - QtCommon::system->ApplySettings(); - UpdateStatusButtons(); - } - LOG_INFO(Config, "MKW recommended settings accepted: {}", use_recommended_mkw_settings); - }); - recommendations->show(); - #ifdef __unix__ OnCheckGraphicsBackend(); #endif @@ -1989,6 +1966,20 @@ void MainWindow::BootGame(const QString& filename, Service::AM::FrontendAppletPa QtCommon::system->ApplySettings(); } + if (title_id == Settings::MarioKartWorldProgramId && !asked_recommended_mkw_settings) { + asked_recommended_mkw_settings = true; + use_recommended_mkw_settings = + QMessageBox::question( + this, tr("Recommended Mario Kart World settings"), + tr("Use the recommended settings for Mario Kart World?\n\n" + "Vulkan, 1x resolution, GPU Fast, asynchronous shaders, BC3, conservative VRAM, " + "reactive flushing off, FIFO Relaxed VSync, handheld mode, ScaleForce, and " + "FXAA.\n\n" + "They apply to Mario Kart World until Eglantine is closed. Your saved settings " + "are not changed."), + QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes; + LOG_INFO(Config, "MKW recommended settings accepted: {}", use_recommended_mkw_settings); + } if (Settings::ApplyMarioKartWorldPreset(Settings::values, title_id, use_recommended_mkw_settings)) { QtCommon::system->ApplySettings(); diff --git a/src/yuzu/main_window.h b/src/yuzu/main_window.h index d6b0e5b312..1bd04a4d8b 100644 --- a/src/yuzu/main_window.h +++ b/src/yuzu/main_window.h @@ -504,6 +504,7 @@ private: MultiplayerState* multiplayer_state = nullptr; bool use_recommended_mkw_settings = false; + bool asked_recommended_mkw_settings = false; GRenderWindow* render_window = nullptr; GameList* game_list = nullptr; -- cgit v1.2.3