-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Description
Context
This appears to affect both SDL2 and SDL3 (based on my reading of the code). This was discovered in the PCSX2 project, where a slice of Windows users have experienced a regression in force feedback (FFB) quality since the switch from DInput to SDL, while other users with different FFB wheels haven't noticed a thing.
Most racing titles with FFB, past or present, implement FFB primarily by updating the magnitude parameter of a single, always-running constant force. In a DirectInput implementation, that would look something like this:
// C++ psuedocode
// effect is some existing, already-running constant force effect
auto constForce = (DICONSTANTFORCE*)effect.lpvTypeSpecificParams;
constForce->lMagnitude = new_magnitude;
ref->SetParameters(effect, DIEP_TYPESPECIFICPARAMS); // Note that DIEP_TYPESPECIFICPARAMS is the only flag.
I did a lot of low-level digging into USB PID (Physical Interface Device, HID except for haptics) and DirectInput. I'll spare you the details, so here's all you need to know:
- There are two PID reports associated with a force: The "basic" parameters, and the "type-specific" parameters (for a constant force, it's just magnitude.)
- When
DIEP_TYPESPECIFICPARAMSis the only flag set, only the "type-specific" report is sent by DirectInput drivers - Setting any other flags causes the "basic" report to be sent as well.
- This appears to aggravate specific wheels, causing what users describe as a "loss of detail" during rapid updates
- This was tested with an experimental test build that added a toggle to bypass SDL and call DirectInput's
SetParametersdirectly with theDIEP_TYPESPECIFICPARAMSflag. Affected users reported that enabling this setting provided an immediate, noticeable improvement in FFB quality.- I validated with Wireshark that this bypass prevented the redundant report from being sent.
Relevant Code
Inside of SDL_DINPUT_HapticUpdateEffect, all of these flags are set when sending an update to DirectInput:
// src/haptic/windows/SDL_dinputhaptic.c
/* Set the flags. Might be worthwhile to diff temp with loaded effect and
* only change those parameters. */
flags = DIEP_DIRECTION |
DIEP_DURATION |
DIEP_ENVELOPE |
DIEP_STARTDELAY |
DIEP_TRIGGERBUTTON |
DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS;
The comment here already acknowledges that this is known to an extent, but I assume it hadn't yet been known to cause problems.