mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-05 13:20:11 +00:00
fix(pad): restore the DualSense haptics configuration after a rumble stops
SDL sends scePadSetVibration rumble as report 0x31 with audio haptics turned off. Once the rumble stopped, the stream's haptics came back at a different strength than before it. The stream thread now sends its configuration report 0x31 again 100 ms after slot 0's rumble stops, which brought the haptics back to their level before the rumble. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
986ae87c8a
commit
d7fb2a3ec3
4 files changed
+14
-1
No files matched your search
@@ -17,6 +17,7 @@ constexpr std::size_t SamplesOffset = 13;
|
||||
constexpr std::size_t SamplesBytes = 64;
|
||||
constexpr std::uint8_t ControllerQueueFrames = 64;
|
||||
constexpr std::chrono::nanoseconds ReportInterval{1'000'000'000LL * SamplesBytes / 2 / 3000};
|
||||
constexpr std::chrono::milliseconds RumbleSettle{100};
|
||||
|
||||
inline std::chrono::steady_clock::time_point NextReport(std::chrono::steady_clock::time_point previous, std::chrono::steady_clock::time_point now) {
|
||||
return std::max(previous + ReportInterval, now);
|
||||
|
||||
@@ -81,6 +81,8 @@ private:
|
||||
SDL_hid_device* haptics = nullptr;
|
||||
std::atomic<bool> hapticsRunning{false};
|
||||
std::thread hapticsThread;
|
||||
bool hapticsRumbled = false;
|
||||
std::atomic<std::chrono::steady_clock::rep> hapticsReconfigureAt{0};
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -176,6 +176,10 @@ void PadInput::streamHaptics() {
|
||||
if (std::all_of(samples.begin(), samples.end(), [](std::int8_t sample) { return sample == 0; })) continue;
|
||||
next = DualSenseHaptics::NextReport(next, std::chrono::steady_clock::now());
|
||||
PreciseSleepUntil(next);
|
||||
if (const auto due = hapticsReconfigureAt.load(); due != 0 && std::chrono::steady_clock::now().time_since_epoch().count() >= due) {
|
||||
hapticsReconfigureAt = 0;
|
||||
if (!write(DualSenseHaptics::PowerReport(sequence++))) return;
|
||||
}
|
||||
if (!write(DualSenseHaptics::Report(sequence++, counter++, samples))) return;
|
||||
}
|
||||
}
|
||||
@@ -187,6 +191,8 @@ void PadInput::closeHaptics() {
|
||||
if (hapticsThread.joinable()) hapticsThread.join();
|
||||
SDL_hid_close(haptics);
|
||||
haptics = nullptr;
|
||||
hapticsRumbled = false;
|
||||
hapticsReconfigureAt = 0;
|
||||
}
|
||||
|
||||
void PadInput::closeController(int slot) {
|
||||
@@ -279,6 +285,10 @@ void PadInput::applyOutput() {
|
||||
slots[slot].outputPending = false;
|
||||
slots[slot].nextRumbleRefresh = now + std::chrono::milliseconds(700);
|
||||
SDL_GameControllerRumble(controller, motors.low, motors.high, motors.durationMs);
|
||||
if (slot == 0 && haptics != nullptr) {
|
||||
if (hapticsRumbled && !rumbling) hapticsReconfigureAt = (now + DualSenseHaptics::RumbleSettle).time_since_epoch().count();
|
||||
hapticsRumbled = rumbling;
|
||||
}
|
||||
if (slots[slot].outputState.triggerTouched) {
|
||||
if (isPs5) {
|
||||
TriggerEffectCache::Effect effect{};
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
- [HDR output](../../../core/libs/prx/libSceVideoOut/src/HostHdrProbe.cpp) (libSceVideoOut, libSceSystemService) - HDR output is reported only on Windows; elsewhere it stays SDR: SDL2 and Vulkan expose no output HDR state, and a surface can offer HDR10 formats with HDR off (KDE Wayland with RADV). The console's events for an HDR change are unknown; here every open port's output mode event fires when HDR availability or luminance changes. Console HDR settings (calibrated peak, the SDR-in-HDR conversion block) are not modelled. Surface format changes that leave the swapchain valid are seen only when DXGI's report changes or the swapchain is recreated. `sceSystemServiceGetHdrToneMapLuminance` reports SDR before VideoOut is first used, and no HDR change event fires for the state found at start-up. HDR needs a 10-bit HDR10 swapchain and a monitor DXGI reports in `DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020`; without a usable peak, luminance is 1000 nits peak and full frame, 0 black
|
||||
- [Windows game controllers](../../../core/libs/prx/libSceVideoOut/src/VideoOutDriver.cpp) (libSceVideoOut) - SDL's DirectInput joystick backend is disabled at default hint priority before `SDL_InitSubSystem`, because its device enumeration blocks forever on some vendor HID devices (#1042). XInput and HIDAPI controllers are detected; controllers reachable only through DirectInput are not. Setting `SDL_DIRECTINPUT_ENABLED=1` restores them on hosts without such a device. SDL's Windows.Gaming.Input backend stays on by default. Setting `APS5_NO_WGI` turns it off at default hint priority, for hosts where it faults at `Windows.Gaming.Input.dll+0x10a84` a few seconds into every run: seen on Windows 10 Pro 22H2 (19045) with the Nefarius and Oculus virtual gamepad emulation buses installed and no physical controller connected. With it off, devices and features reachable only through Windows.Gaming.Input are lost: racing wheels, arcade sticks, flight sticks, HID pads without an HIDAPI driver, and Xbox One and Series trigger rumble.
|
||||
- [ImeTextInput](../../../core/libs/prx/libSceVideoOut/src/ImeTextInput.cpp) (libSceVideoOut) forwards SDL_TEXTEDITING with its text cut to 32 bytes by SDL and `start` and `length` read as counts of characters. SDL_TEXTEDITING_EXT (longer text) is not requested, `SDL_SetTextInputRect` is not called so the system candidate window is not placed at the field, and SDL's own text input, started when video starts, is left on outside dialogs. How each platform reports `start` and `length` (characters or UTF-16 units, cursor or selection) is not measured. Closes when: measured on Linux (ibus and fcitx)
|
||||
- [Bluetooth DualSense haptics](../../../core/libs/prx/libSceVideoOut/src/PadInput.cpp) (libSceVideoOut) - the controller's queue depth, the console's filter and the rumble interplay are unmeasured. Vibration ports are averaged to 3 kHz in 16-frame boxes (not the console's low-pass) and sent as report 0x32, one 32-frame block once two are buffered, at most one per 10.67 ms, so reports follow the title's audio clock. The report asks the controller to queue 64 frames (21 ms) to absorb Bluetooth jitter and the title's rate against the controller's crystal; 16 dropped out about once a second on an RX 9070 XT host. The host buffer keeps the newest 160 frames (53 ms). `scePadSetVibration` rumble still goes out as report 0x31, which may take the actuators out of audio mode. A failed write silences the vibration ports, without rumble, until the controller reconnects. Windows only verified. Closes when: the clock difference and the rumble interplay are measured on a title that uses both.
|
||||
- [Bluetooth DualSense haptics](../../../core/libs/prx/libSceVideoOut/src/PadInput.cpp) (libSceVideoOut) - the controller's queue depth, the console's filter and the rumble interplay are unmeasured. Vibration ports are averaged to 3 kHz in 16-frame boxes (not the console's low-pass) and sent as report 0x32, one 32-frame block once two are buffered, at most every 10.67 ms, following the title's audio clock. The report asks the controller to queue 64 frames (21 ms) to absorb Bluetooth jitter and clock drift; 16 dropped out about once a second. The host buffer keeps the newest 160 frames (53 ms). `scePadSetVibration` rumble goes out as SDL's report 0x31 with audio haptics off; the stream resends its own 0x31 100 ms after the rumble stops, as haptics came back changed without it. A failed write silences the vibration ports, without rumble, until the controller reconnects. Windows only. Closes when: the clock difference and the rumble interplay are measured on a title that uses both.
|
||||
|
||||
- The following pending declarations have unverified signatures and behavior; they are parameterless import-resolution declarations and throw through `NotImplemented_nid_no_patch`: [`sceDbgVideoOutAddOutputModeVr60Privilege`](../../../core/libs/prx/libSceVideoOut/Unimplemented.cpp).
|
||||
|
||||
|
||||
Reference in new issue
Block a user