diff --git a/runtime/src/hle/input/kpad.cpp b/runtime/src/hle/input/kpad.cpp index c7c2ffa..5246d63 100644 --- a/runtime/src/hle/input/kpad.cpp +++ b/runtime/src/hle/input/kpad.cpp @@ -1,4 +1,5 @@ #include "hle_stubs.h" +#include "input_bindings.h" #include "memory.h" #include "wii_remote_input.h" @@ -203,6 +204,24 @@ void WriteUnifiedStatus(uint32_t addr, const WiiRemoteInput::KpadSample* sample) } } +// Neutral sticks and no buttons while an overlay owns input; the remote stays connected. +bool ReadSample(uint32_t chan, WiiRemoteInput::KpadSample& sample) { + if (!WiiRemoteInput::ReadKpadSample(chan, sample)) { + return false; + } + if (InputBindings::InputBlocked()) { + sample.hold = 0; + sample.clHold = 0; + sample.stick[0] = sample.stick[1] = 0.0f; + sample.clLStick[0] = sample.clLStick[1] = 0.0f; + sample.clRStick[0] = sample.clRStick[1] = 0.0f; + sample.clLStickRaw[0] = sample.clLStickRaw[1] = 0; + sample.clRStickRaw[0] = sample.clRStickRaw[1] = 0; + sample.clTriggerL = sample.clTriggerR = 0; + } + return true; +} + } // namespace // KPADRead: fills KPADStatus[0] for `chan` from the Bluetooth remote, returns the entry count. @@ -212,7 +231,7 @@ extern "C" int32_t KPAD__Read_HLE(uint32_t chan, uint32_t statusPtr, uint32_t co return 0; } WiiRemoteInput::KpadSample sample; - const bool have = WiiRemoteInput::ReadKpadSample(chan, sample); + const bool have = ReadSample(chan, sample); try { return WriteStatus(chan, statusPtr, have ? &sample : nullptr); } catch (const Memory::AccessViolation&) { @@ -234,7 +253,7 @@ extern "C" int32_t KPAD__GetUnifiedWpadStatus_HLE(uint32_t chan, uint32_t status return 0; } WiiRemoteInput::KpadSample sample; - const bool have = WiiRemoteInput::ReadKpadSample(chan, sample); + const bool have = ReadSample(chan, sample); try { const uint32_t entries = std::min(count, kMaxEntries); for (uint32_t i = 0; i < entries; ++i) { diff --git a/runtime/src/settings_overlay.cpp b/runtime/src/settings_overlay.cpp index 616d141..4f62f32 100644 --- a/runtime/src/settings_overlay.cpp +++ b/runtime/src/settings_overlay.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -162,6 +163,11 @@ uint64_t g_presentedFrame = 0; std::atomic_bool g_strapInputAccepted = false; std::atomic_uint64_t g_startupDismissFrame = UINT64_MAX; constexpr uint64_t kStrapTransitionCoverFrames = 60; +std::atomic_bool g_bootShadersReady = false; +bool g_bootShaderNotice = false; +Clock::time_point g_bootShaderWaitStart{}; +constexpr uint32_t kBootShaderNoticeThreshold = 100; +constexpr auto kBootShaderWaitLimit = std::chrono::minutes(3); constexpr std::array kResolutions = {{ {"Auto (window size)", 0.0f}, {"Native (1x)", 1.0f}, {"1.5x", 1.5f}, {"2x", 2.0f}, @@ -1193,12 +1199,36 @@ void DrawStartupScreen() { const float startY = std::max(0.0f, (viewport->Size.y - titleSize.y) * 0.5f); ImGui::SetCursorPos(ImVec2(titleX, startY)); ImGui::TextUnformatted(kTitle); + if (g_bootShaderNotice && !g_bootShadersReady.load(std::memory_order_relaxed)) { + ImGui::SetWindowFontScale(0.9f); + char line[96]; + std::snprintf(line, sizeof(line), "Compiling shaders, please hold on: %u remaining", + aurora_get_queued_pipeline_count()); + const float lineX = std::max(0.0f, (viewport->Size.x - ImGui::CalcTextSize(line).x) * 0.5f); + ImGui::SetCursorPos(ImVec2(lineX, startY + titleSize.y * 1.8f)); + ImGui::TextUnformatted(line); + } } ImGui::End(); ImGui::PopStyleVar(); ImGui::PopStyleColor(); } +void UpdateBootShaderState() { + if (g_bootShadersReady.load(std::memory_order_relaxed)) { + return; + } + const auto now = Clock::now(); + if (g_bootShaderWaitStart == Clock::time_point{}) { + g_bootShaderWaitStart = now; + } + const uint32_t queued = aurora_get_queued_pipeline_count(); + g_bootShaderNotice |= queued > kBootShaderNoticeThreshold; + if (queued == 0 || now - g_bootShaderWaitStart > kBootShaderWaitLimit) { + g_bootShadersReady.store(true, std::memory_order_release); + } +} + void DrawExitPrompt() { constexpr const char* kTitle = "Exit"; if (g_exitPromptOpen && !ImGui::IsPopupOpen(kTitle)) ImGui::OpenPopup(kTitle); @@ -1348,7 +1378,7 @@ void PersistDisplayModeIfChanged() { void ApplyInputBlockState() { const bool blocked = controller_mapping_wizard::IsActive() || g_rebind.active || - g_exitPromptOpen || g_topBarVisible; + g_exitPromptOpen || g_topBarVisible || StartupScreenVisible(); PADBlockInput(blocked); InputBindings::SetInputBlocked(blocked); } @@ -1376,6 +1406,9 @@ void InitializeRuntimeSettings() noexcept { aurora_set_skip_unready_pipelines(g_skipUnreadyPipelines); g_strapInputAccepted.store(false, std::memory_order_relaxed); g_startupDismissFrame.store(UINT64_MAX, std::memory_order_relaxed); + g_bootShadersReady.store(false, std::memory_order_relaxed); + g_bootShaderNotice = false; + g_bootShaderWaitStart = {}; PADBlockInput(false); InputBindings::SetInputBlocked(false); } @@ -1456,6 +1489,7 @@ void Draw() noexcept { ApplyConfiguredMappings(); PersistDisplayModeIfChanged(); UpdateCursorAutoHide(); + UpdateBootShaderState(); if (!StartupScreenVisible()) { DrawShaderCompilationStatus(); } @@ -1469,6 +1503,7 @@ void Draw() noexcept { bool StartupScreenVisible() noexcept { return !g_strapInputAccepted.load(std::memory_order_acquire) || + !g_bootShadersReady.load(std::memory_order_acquire) || g_presentedFrame < g_startupDismissFrame.load(std::memory_order_relaxed); }