Haptic woes - Linux and the X360 controller

Hey everyone,

I’m porting a game engine to Linux that uses XInput for force
feedback. I’ve got the game controllers working nicely for input, so I
wanted to simply re-wire the FF subsystem to use SDL_Haptic* API calls
instead.

The thing is, while simple test apps (simulation of a game loop at 60
fps, updating rumble magnitude every frame) work nicely, I can’t get
the haptic feedback to work from inside the game engine, and I cannot
find the culprit. Before I divulge into debugging SDL internals, is
there anything obvious that could be interfering?

I’m using SDL for window and GL context management and keyboard, mouse
and game controller input; threading is done directly via pthreads.
The engine is extensively multithreaded (main thread, rendering thread

  • several workers) and uses OpenAL for audio. All SDL calls (apart
    from GL context management) occur exclusively on the main thread.

I’m opening the haptic device like this:

Controller.Haptic =
SDL_HapticOpenFromJoystick(SDL_GameControllerGetJoystick(Controller.SDLController));

Then initialize the simple rumble effect:

if (Controller.Haptic && SDL_HapticRumbleInit(Controller.Haptic) != 0)
{
SDL_HapticClose(Controller.Haptic);
Controller.Haptic = NULL;
warnf(TEXT("[SDL2 Input] Controller advertises force feedback support,
but effect initialization failed"));
}

The game’s FF subsystem evaluates artist-defined waveforms every game
frame and computes the currently desired rumble magnitude. From what I
understand from the SDL_haptic.h header, it should suffice to call
SDL_HapticRumblePlay():

FLOAT Feedback;
// Update the rumble data
GetRumbleState(DeltaTime, Feedback);
debugf(TEXT("[SDL2 Input] Force feedback power for device %d: %f"),
DeviceID, Feedback);
// Update the motor with the data
// Assume a 33 ms tail (~1 frame at 30 fps); we should be updating it
sooner anyway
if (SDL_HapticRumblePlay(GControllers(DeviceID).Haptic, Feedback, 33) != 0)
warnf(TEXT("[SDL2 Input] Force feedback error for device %d: %s"),
DeviceID, UTF8_TO_TCHAR(SDL_GetError()));

The above code is called every game frame, unless there’s a level
loading (it’s simply not called then). The logs show reasonable
magnitude values in the [0; 1] range being fed to SDL. No SDL errors
are detected throughout.

Any thoughts?

Regards,

Leszek