libsdl-org / SDL

Simple Directmedia Layer
https://libsdl.org
zlib License
9.91k stars 1.83k forks source link

Haptic fails to rumble after stdout is used by another call #6744

Closed geniot closed 1 year ago

geniot commented 1 year ago

I'm using SDL2 bindings for GoLang. I'm also cross compiling for a MIPS device (PocketGo handheld console). Strangely when I use stdout haptic stops working. Eg.:

        cmd := exec.Command("amixer", "sget", "Master")
        res, _ := cmd.Output()

It seems that haptic's implementation depends on the usage of stdout. Is there a suggested way to deal with that?

icculus commented 1 year ago

It feels like there might be more going on here. A small test program that reproduces the issue would be very helpful to verify the problem.

geniot commented 1 year ago

Ok, here goes. The GoLang code:

package main

import (
    "github.com/veandco/go-sdl2/sdl"
    "os/exec"
    "strconv"
)

const (
    GCW_BUTTON_L2    = sdl.K_PAGEUP   //rumble
    GCW_BUTTON_R2    = sdl.K_PAGEDOWN //exec output
    GCW_BUTTON_START = sdl.K_RETURN   //quit
)

func main() {
    sdl.Init(sdl.INIT_EVERYTHING)
    window, _ := sdl.CreateWindow(
        "haptic_fail_test",
        sdl.WINDOWPOS_UNDEFINED,
        sdl.WINDOWPOS_UNDEFINED,
        320,
        240,
        sdl.WINDOW_SHOWN|sdl.WINDOW_BORDERLESS)
    defer window.Destroy()

    var haptic *sdl.Haptic
    numHaptics, _ := sdl.NumHaptics()
    if numHaptics > 0 {
        println("Haptics: " + strconv.Itoa(numHaptics))
        println(sdl.HapticName(0))
        haptic, _ = sdl.HapticOpen(0)
        haptic.RumbleInit()
        defer haptic.Close()
    }

    var running = true
    for running {
        for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
            switch t := event.(type) {
            case *sdl.KeyboardEvent:
                if t.State == sdl.PRESSED {
                    if t.Keysym.Sym == GCW_BUTTON_L2 {
                        var err = haptic.RumblePlay(0.33, 500)
                        if err != nil {
                            println(err.Error())
                        }
                    }
                    if t.Keysym.Sym == GCW_BUTTON_R2 {
                        cmd := exec.Command("amixer", "sget", "Master")
                        res, _ := cmd.Output()
                        println(string(res))
                    }
                    if t.Keysym.Sym == GCW_BUTTON_START {
                        running = false
                    }
                }
            }
            break
        }
    }
    sdl.Delay(1000 / 60)

}

The build.sh:

CC='/opt/gcw0-toolchain/usr/bin/mipsel-gcw0-linux-uclibc-gcc' \
 CGO_CFLAGS='-I/opt/gcw0-toolchain/usr/mipsel-gcw0-linux-uclibc/sysroot/usr/include
  -D_REENTRANT' \
 CGO_ENABLED=1 \
 CGO_LDFLAGS='-L/opt/gcw0-toolchain/usr/mipsel-gcw0-linux-uclibc/sysroot/usr/lib -lSDL2' \
 GOARCH=mipsle \
 GOMIPS=softfloat \
 GOOS=linux \
 PKG_CONFIG='/opt/gcw0-toolchain/usr/bin/pkg-config' \
 go build -o tmp/hapticfail.gcw main.go

ldd output:

POCKETGO2V2:/media/data/local/home # ldd hapticfail.gcw 
    libSDL2-2.0.so.0 => /usr/lib/libSDL2-2.0.so.0 (0x77460000)
    libpthread.so.0 => /lib/libpthread.so.0 (0x7743a000)
    libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x77404000)
    libc.so.0 => /lib/libc.so.0 (0x7739e000)
    libm.so.0 => /lib/libm.so.0 (0x77383000)
    libdl.so.0 => /lib/libdl.so.0 (0x7736f000)
    librt.so.0 => /lib/librt.so.0 (0x7735b000)
    ld-uClibc.so.0 => /lib/ld-uClibc.so.0 (0x77573000)

The console log (execution on PocketGo):

POCKETGO2V2:/media/data/local/home # ./hapticfail.gcw 
The path /dev/dri/ cannot be opened or is not available
The path /dev/dri/ cannot be opened or is not available
fbdev_display succesful
Kernel: Vivante GPL kernel driver 4.6.6.1381
Physical address of internal memory: 00000000
* Video memory:
  Internal physical: 0x00000000
  Internal size: 0x00000000
  External physical: 00000000
  External size: 0x00000000
  Contiguous physical: 0x8c7efb00
  Contiguous size: 0x00400000
Succesfully opened device
native_fbdev: 2 buffers of 320x240
Framebuffer format: 6, flip_rb=0
Framebuffer format: 6, flip_rb=0
Haptics: 1
pwm-haptic (0x0,0x0)
Simple mixer control 'Master',0
  Capabilities: volume
  Playback channels: Front Left - Front Right
  Capture channels: Front Left - Front Right
  Limits: 0 - 255
  Front Left: 56 [22%]
  Front Right: 56 [22%]

Simple mixer control 'Master',0
  Capabilities: volume
  Playback channels: Front Left - Front Right
  Capture channels: Front Left - Front Right
  Limits: 0 - 255
  Front Left: 56 [22%]
  Front Right: 56 [22%]

Haptic: Error updating the effect: Invalid argument
Haptic: Error updating the effect: Invalid argument

I pressed L2 a couple of times to make sure rumble works. Then I pressed R2 - I saw exec output in the console. Then I pressed L2 again (2 times). You can see "Error updating the effect".

On PocketGo I entered the terminal mode (disabled UI). Here is how my screen looks like after all these presses:

haptic

5,5,6,5 - five appears on L2, six on R2.

I tried the same without calling cmd.Output():

exec.Command("amixer", "sget", "Master")
//res, _ := cmd.Output()
//println(string(res))

Rumble keeps working. So it's the cmd.Output() call that breaks the Haptic for some reason. Do you have any suggestions how to fix this? Thanks.

slouken commented 1 year ago

SDL 2.0 is now in maintenance mode, and all inactive issues are being closed. If this issue is impacting you, please feel free to reopen it with additional information.