hajimehoshi / ebiten

Ebitengine - A dead simple 2D game engine for Go
https://ebitengine.org
Apache License 2.0
11.12k stars 664 forks source link

Using some usb headsets causes RunGame to wait 10 seconds before launch #3138

Open sedyh opened 1 month ago

sedyh commented 1 month ago

Ebitengine Version

2.8+ (6452cbc)

Operating System

Go Version (go version)

go version go1.23.1 linux/amd64

What steps will reproduce the problem?

Buy one of DEXP Storm Pro or Redragon Inferno Pro usb headset:

Connect it to usb on Windows 10 Pro 22H2 19045.4780.

Run the example:

package main

import (
    "github.com/hajimehoshi/ebiten/v2"
    "log"
)

type Game struct {}

func NewGame() *Game {
    return &Game{}
}

func (g *Game) Update() error {
    log.Println("update")
    return ebiten.Termination
}

func (g *Game) Draw(screen *ebiten.Image) {}

func (g *Game) Layout(w, h int) (int, int) {
    return w, h
}

func main() {
    log.Println("starting")
    ebiten.SetWindowResizingMode(ebiten.WindowResizingModeEnabled)
    ebiten.SetWindowSize(1000, 1000)
    ebiten.SetVsyncEnabled(true)

    log.Println("running")
    op := &ebiten.RunGameOptions{GraphicsLibrary: ebiten.GraphicsLibraryOpenGL}
    if err := ebiten.RunGameWithOptions(NewGame(), op); err != nil {
        log.Fatal(err)
    }
}

What is the expected result?

2024/09/03 23:08:53 starting
2024/09/03 23:08:53 running
2024/09/03 23:08:54 update

https://github.com/user-attachments/assets/8e43bffd-4bf9-415b-92ca-5df184bc3b23

What happens instead?

2024/09/03 23:08:53 starting
2024/09/03 23:08:53 running
2024/09/03 23:09:03 update
0, 0% 99.22%, 9.72s, 75.70%, github.com/hajimehoshi/ebiten/v2/internal/gamepad.(*_IDirectInput8W).EnumDevices
(pprof) top10
Showing nodes accounting for 12.74s, 99.22% of 12.84s total
Dropped 67 nodes (cum <= 0.06s)
Showing top 10 nodes out of 52
      flat  flat%   sum%        cum   cum%
    12.73s 99.14% 99.14%     12.74s 99.22%  runtime.cgocall
     0.01s 0.078% 99.22%      2.87s 22.35%  golang.org/x/sys/windows.(*Proc).Call
         0     0% 99.22%     10.11s 78.74%  github.com/hajimehoshi/ebiten/v2.RunGameWithOptions
         0     0% 99.22%      9.72s 75.70%  github.com/hajimehoshi/ebiten/v2/internal/gamepad.(*_IDirectInput8W).EnumDevices
         0     0% 99.22%      9.83s 76.56%  github.com/hajimehoshi/ebiten/v2/internal/gamepad.(*gamepads).update
         0     0% 99.22%      9.72s 75.70%  github.com/hajimehoshi/ebiten/v2/internal/gamepad.(*nativeGamepadsDesktop).detectConnection
         0     0% 99.22%      0.11s  0.86%  github.com/hajimehoshi/ebiten/v2/internal/gamepad.(*nativeGamepadsDesktop).directInput8Create
         0     0% 99.22%      9.83s 76.56%  github.com/hajimehoshi/ebiten/v2/internal/gamepad.(*nativeGamepadsDesktop).init
         0     0% 99.22%      0.12s  0.93%  github.com/hajimehoshi/ebiten/v2/internal/gamepad.(*nativeGamepadsDesktop).wndProc
         0     0% 99.22%      9.83s 76.56%  github.com/hajimehoshi/ebiten/v2/internal/gamepad.Update (inline)
(pprof)

profile-inside.zip

Related: https://stackoverflow.com/questions/10967795/directinput8-enumdevices-sometimes-painfully-slow

*The owner said that it does not happens in any other game / game engine.

Anything else you feel useful to add?

.
hajimehoshi commented 1 month ago

Maybe https://stackoverflow.com/questions/10967795/directinput8-enumdevices-sometimes-painfully-slow

EDIT: Oh yes, you have already noted that

sedyh commented 1 month ago

Oh yes, you have already noted that

Yeah. It's very strange that this doesn't happen on other directx based games.

hajimehoshi commented 1 month ago

DirectInput 8 might be pretty outdated so I would replace it with a new one.

sedyh commented 1 month ago

I'll be glad to retest this after the update.

hajimehoshi commented 1 month ago

This can happen with other engines

sedyh commented 1 month ago

Looks like a possible fix? https://github.com/godotengine/godot/issues/20566#issuecomment-1730345450

What about updating directinput?

hajimehoshi commented 1 month ago

What about updating directinput?

You mean injecting some code for DirectInput (https://raw.githubusercontent.com/funkkiy/godot/8cc66b6f940ec77df624cf7f0124f6bfaf75dafb/platform/windows/hid_proxy.cpp) rather than updating DirectInput?

hajimehoshi commented 1 month ago

This overwrites HidD_GetProductString and I don't know it is possible to do this. Would we need something like LD_PRELOAD?

EDIT: Even if it is possible, Windows antivirtus software tends to warn or ban software using tricky hacks for DLL https://news.ycombinator.com/item?id=26984206

sedyh commented 1 month ago

You mean injecting some code

That was the first question.

Rather than updating DirectInput

And that was the second separate question about how difficult/long it will be to make this update.

sedyh commented 1 month ago

I heard that SDL had a blacklist for this kind of devices but this doesn't seem like a solution, except for cases where this device is simply connected nearby and not used (and in our case its intended to be used).

hajimehoshi commented 1 month ago

IIUC, adding a device to a blocklist doesn't work since this would not prevent DirectInput from enumerating connected devices.