From 5bf1904ca81ad871fef7b03a3b97d939c0ad4d73 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 13:17:48 +0000 Subject: [PATCH] Lock the video render mode against concurrent readers VIConfigure writes the mode on the game side while the GX thread, the frame worker and the window code read its size. The resize request is made after the lock is released. From upstream patchzyy/Wiicompiled 6f14bde (#244). Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01Wg7mB8ogCWmp9GH19Uc82B --- aurora-main/lib/dolphin/vi/vi.cpp | 39 +++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/aurora-main/lib/dolphin/vi/vi.cpp b/aurora-main/lib/dolphin/vi/vi.cpp index d036b86..37f49d6 100644 --- a/aurora-main/lib/dolphin/vi/vi.cpp +++ b/aurora-main/lib/dolphin/vi/vi.cpp @@ -7,11 +7,13 @@ #include #include #include +#include namespace aurora::vi { std::optional g_renderMode; namespace { std::atomic g_presentAspectCorrection{1.f}; +std::mutex g_renderModeMutex; float calculate_present_aspect_correction(const GXRenderModeObj& rm) noexcept { if (rm.viWidth == 0 || rm.viHeight == 0) { @@ -29,9 +31,8 @@ float calculate_present_aspect_correction(const GXRenderModeObj& rm) noexcept { const float verticalFill = static_cast(rm.viHeight) / nominalActiveHeight; return horizontalFill / verticalFill; } -} // namespace -Vec2 render_mode_size() noexcept { +Vec2 render_mode_size_locked() noexcept { if (!g_renderMode) { return {640, 528}; } @@ -40,18 +41,31 @@ Vec2 render_mode_size() noexcept { return {std::max(g_renderMode->fbWidth, 640), std::max(g_renderMode->efbHeight, 528)}; } +} // namespace + +Vec2 render_mode_size() noexcept { + std::lock_guard lock(g_renderModeMutex); + return render_mode_size_locked(); +} + void configure(const GXRenderModeObj* rm) noexcept { - const auto oldSize = render_mode_size(); - if (rm == nullptr) { - g_renderMode.reset(); - } else { - g_renderMode = *rm; - g_presentAspectCorrection.store(calculate_present_aspect_correction(*rm), std::memory_order_release); + bool sizeChanged = false; + { + std::lock_guard lock(g_renderModeMutex); + const auto oldSize = render_mode_size_locked(); + if (rm == nullptr) { + g_renderMode.reset(); + } else { + g_renderMode = *rm; + g_presentAspectCorrection.store(calculate_present_aspect_correction(*rm), std::memory_order_release); + } + if (rm == nullptr) { + g_presentAspectCorrection.store(1.f, std::memory_order_release); + } + sizeChanged = render_mode_size_locked() != oldSize; } - if (rm == nullptr) { - g_presentAspectCorrection.store(1.f, std::memory_order_release); - } - if (render_mode_size() != oldSize) { + // Never hold the mode lock across a resize request or a renderer callback. + if (sizeChanged) { window::request_frame_buffer_resize(); } } @@ -61,6 +75,7 @@ Vec2 configured_fb_size() noexcept { } Vec2 visible_fb_size() noexcept { + std::lock_guard lock(g_renderModeMutex); if (!g_renderMode) { return {640, 528}; }