SimulaVR / Simula

Linux VR Desktop
MIT License
2.91k stars 87 forks source link

Upgrade `./addons/godot-openvr` to fix godot_openvr instability #93

Closed georgewsinger closed 4 years ago

georgewsinger commented 4 years ago

Context. Simula is facing two significant godot_openvr issues that are making it unstable

  1. Launching Godot (with ARVR support) Causes Eventual godot_arvr_process Seg Fault
  2. Game freeze when headset goes to sleep

After upgrading Simula to Godot 3.1, I haven't seen any of (1) so far, and I believe it's possible that fixed things. We're definitely still getting (2) though.

Attempt to upgrade ./addons/godot-openvr. I attempted to upgrade Simula's ./addons/godot-openvr via

# Clone
cd /tmp
git clone --recursive https://github.com/GodotVR/godot_openvr.git godot_openvr

# Compile
cd godot-cpp
scons platform=linux target=release generate_bindings=yes bits=64
cd ..
scons platform=linux target=release

# Copy
mv ~/Simula/addons/godot-openvr ~/Simula/addons/godot-openvr.bak
cp -r ./demo/addons/godot-openvr ~/Simula/addons/godot-openvr

but after launching Simula (w/gdb) I get

(gdb) r
Starting program: /home/george/Simula/bin/godot --path /home/george/Simula/addons/godot-haskell-plugin/../../
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff4b1d700 (LWP 12344)]
[Detaching after fork from child process 12345]
[Detaching after fork from child process 12346]
[New Thread 0x7ffff4072700 (LWP 12347)]
OpenGL ES 2.0 Renderer: GeForce GTX 1070/PCIe/SSE2
[New Thread 0x7fffedc63700 (LWP 12352)]
[New Thread 0x7fffedc22700 (LWP 12353)]
Construct gdnative interface
Construct gdnative interface
[New Thread 0x7fffed97a700 (LWP 12362)]
ERROR: set_msaa: Index p_msaa=8 out of size (5=5)
   At: scene/main/viewport.cpp:2829.
Haskell GDNative initialized
Haskell NativeScript initialized
Registering class Simula
Registering method _ready to class Simula
Registering method _process to class Simula
Registering method on_button_signal to class Simula
Registering class SimulaController
Registering method _process to class SimulaController
Registering method _physics_process to class SimulaController
Registering class SimulaServer
Registering method _ready to class SimulaServer
Registering method _on_WaylandDisplay_ready to class SimulaServer
Registering method _on_WlrXdgShell_new_surface to class SimulaServer
Registering method handle_map_surface to class SimulaServer
Registering method handle_unmap_surface to class SimulaServer
Registering method _on_wlr_key to class SimulaServer
Registering method _on_wlr_modifiers to class SimulaServer
Registering method _on_WlrXWayland_new_surface to class SimulaServer
Registering class SimulaViewSprite
Registering method _input_event to class SimulaViewSprite
Registering method _ready to class SimulaViewSprite
Registering method _handle_destroy to class SimulaViewSprite
Registering method _handle_map to class SimulaViewSprite
Registering method _process to class SimulaViewSprite
Registering method _handle_unmap to class SimulaViewSprite
Registering signal map to class SimulaViewSprite
Registering signal unmap to class SimulaViewSprite
Registering class SimulaCanvasItem
Registering method _process to class SimulaCanvasItem
Registering method _draw to class SimulaCanvasItem

Thread 1 "godot" received signal SIGSEGV, Segmentation fault.
0x000000000159654b in godot_method_bind_ptrcall (p_method_bind=0x0, p_instance=0x4d160c0, 
    p_args=0x7fffffff9360, p_ret=0x7fffffff9358)
    at modules/gdnative/gdnative/gdnative.cpp:69
69      mb->ptrcall(o, p_args, p_ret);

with gdb backtrace

(gdb) bt
#0  0x000000000159654b in godot_method_bind_ptrcall(godot_method_bind*, godot_object*, void const**, void*)
    (p_method_bind=0x0, p_instance=0x4d160c0, p_args=0x7fffffff9360, p_ret=0x7fffffff9358)
    at modules/gdnative/gdnative/gdnative.cpp:69
#1  0x00007fffed4640eb in godot::___godot_icall_int (inst=0x6e2bed0, mb=<optimized out>)
    at include/gen/__icalls.hpp:6399
#2  0x00007fffed4640eb in godot::OS::get_current_video_driver() const
    (this=this@entry=0x6e2bed0) at src/gen/OS.cpp:226
#3  0x00007fffed44ae33 in godot_arvr_initialize(void*) (p_data=0x64505b0)
    at godot-cpp/include/gen/OS.hpp:156
#4  0x00000000015b927a in ARVRInterfaceGDNative::initialize() (this=0x645b6f0)
    at modules/gdnative/arvr/arvr_interface_gdnative.cpp:143
#5  0x0000000001575d0b in MethodBind0R<bool>::call(Object*, Variant const**, int, Variant::CallError&)
    (this=0x5eb13f0, p_object=0x645b6f0, p_args=0x420005e9b8, p_arg_count=0, r_error=...)
    at ./core/method_bind.gen.inc:222
#6  0x00000000015965fa in godot_method_bind_call(godot_method_bind*, godot_object*, godot_variant const**, int, godot_variant_call_error*)
    (p_method_bind=0x5eb13f0, p_instance=0x645b6f0, p_args=0x420005e9b8, p_arg_count=0, p_call_error=0x420005e9c8) at modules/gdnative/gdnative/gdnative.cpp:83
#7  0x00007fffe2d44993 in hs_shim_godot_method_bind_call ()
    at /home/george/Simula/addons/godot-haskell-plugin/.stack-work/install/x86_64-linux-tinfo6/aed48248d5ad6c739134c4336e043f8c41e1fac67b7a02218f17d4d4f872fca7/8.6.3/lib/x86_64-linux-ghc-8.6.3/libHSgodot-haskell-3.1.0.0-2fLCyvlk4a1LWwJbEUJ90a-ghc8.6.3.so
#8  0x00007fffe2cc811c in  ()
    at /home/george/Simula/addons/godot-haskell-plugin/.stack-work/install/x86_64-linux-tinfo6/aed48248d5ad6c739134c4336e043f8c41e1fac67b7a02218f17d4d4f872fca7/8.6.3/lib/x86_64-linux-ghc-8.6.3/libHSgodot-haskell-3.1.0.0-2fLCyvlk4a1LWwJbEUJ90a-ghc8.6.3.so
#9  0x0000000006e2beb0 in  ()
#10 0x00000000054216d0 in  ()
#11 0x000000000000004b in  ()
#12 0x000000000000004a in  ()
#13 0xffffffffffffff50 in  ()
#14 0x0000000005421228 in  ()
#15 0x0000000005421478 in  ()
#16 0x00007ffff702b312 in msort_with_tmp (p=0x420006a109, b=0x5eb13f0, n=283468229048)
    at msort.c:159
#17 0x0000000000001000 in  ()
#18 0x0000000005401ef0 in  ()
#19 0x0000000000000020 in  ()
#20 0x0000000000000d68 in  ()
#21 0x00007ffff7073152 in _IO_new_file_seekoff
    (fp=0x6e2beb0, offset=1, dir=<optimized out>, mode=<optimized out>) at libioP.h:904
#22 0x49820a6992788500 in  ()
#23 0x00007fffffff9810 in  ()
#24 0x00007ffff707c534 in _int_malloc
    (av=av@entry=0x7ffff71c9c40 <main_arena>, bytes=18446744073709551488, bytes@entry=80)
    at malloc.c:4049
#25 0x00007ffff707dcaa in __GI___libc_malloc (bytes=80) at malloc.c:3073
lboklin commented 4 years ago

Have you tried changing the MSAA value?

georgewsinger commented 4 years ago

@lboklin Changing (in ./project.godot) from

quality/filters/msaa=8

to

quality/filters/msaa=3

makes the

ERROR: set_msaa: Index p_msaa=8 out of size (5=5)

error disappear; however, I still get the same segfault.

georgewsinger commented 4 years ago

Some progress. The specific failing function is G.initialize (which wraps ARVRInterfaceGDNative::initialize()) in initVR:

-- | Initialize the ARVRInterface and return the success/failure
initVR :: GodotNode -> GodotARVRInterface -> IO VRInitResult
initVR node vri = do
  ret <- G.initialize vri >>= \case -- ← Problem
    True  -> -- ..
    False -> -- ..
  -- --

This function is auto-generated by godot-haskell, and seems to have the same interface in Godot 3.1 as it did in Godot 3.0. Tracing through the C++ code takes us to this godot_openvr function:

//godot_openvr function
godot_bool godot_arvr_initialize(void *p_data) {
  arvr_data_struct *arvr_data = (arvr_data_struct *)p_data;

  // this should be static once Godot runs but obtain whether we're running GLES2, GLES3 or Vulkan
  arvr_data->video_driver = godot::OS::get_singleton()->get_current_video_driver(); //⟵ Problem

  //..

}

The problematic call is OS::get_current_video_driver(), which came from this commit (6 months ago).

What's weird is that we can successfully call the following from Haskell without it crashing Simula:

os <- getSingleton Godot_OS "OS"
driver <- G.get_current_video_driver os
putStrLn $ "Driver: " ++ (show driver) -- Prints correctly as "1", which designates "GLES2"

This suggests there isn't anything intrinsically wrong with OS::get_current_video_driver(), which is just:

 //os_x11.cpp
int OS_X11::get_current_video_driver() const {
  return video_driver_index;
}

It's still a mystery to me what is causing this segfault.

lboklin commented 4 years ago

Can you try the equivalent in GDScript?

Edit: Without loading the Haskell stuff

georgewsinger commented 4 years ago

@lboklin You mean try calling initialize() from GDScript to see if it crashes as above?

The godot_openvr demo has a similar initialization logic as Simula's and doesn't crash:

# ./demo/Main.gd in godot_openvr
func _ready():
    # Find the interface and initialise
    var arvr_interface = ARVRServer.find_interface("OpenVR")
    if arvr_interface and arvr_interface.initialize():
           # ...

which mirrors in Simula:

-- Simula.hs
ready :: GodotSimula -> [GodotVariant] -> IO ()
ready self _ = do
  openVR >>= initVR (safeCast self) >>= \case
    InitVRSuccess -> do --...
    InitVRFailed  -> return ()
-- ..

-- s.t.
-- | Get the OpenVR ARVRInterface
openVR :: IO GodotARVRInterface
openVR = findInterface OpenVR

-- | Initialize the ARVRInterface and return the success/failure
initVR :: GodotNode -> GodotARVRInterface -> IO VRInitResult
initVR node vri =
  G.initialize vri >>= \case
    True  -> initSuccess
    False -> initFailed
 where
 -- ...