Skip to content

Module.canvas.exitPointerLock is not a function [ONLY if compiling with SIDE_MODULE=2] #18541

@folays

Description

@folays

Version of emscripten/emsdk:

emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.29-git
clang version 16.0.0 (https://github.com/llvm/llvm-project.git 947d529e4194e0567cfbbea99127066f76c87269)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: /usr/local/Cellar/emscripten/3.1.29/libexec/llvm/bin

Failing full example below :

It basically git clone ImGui, and compiles the necessary files unmodified, to launch the "Demo Window".

#!/bin/bash
set -ex

[ -d imgui/ ] || git clone --branch v1.89.2 https://github.com/ocornut/imgui.git

files_imgui="imgui/imgui.cpp imgui/imgui_draw.cpp imgui/imgui_demo.cpp imgui/imgui_widgets.cpp imgui/imgui_tables.cpp"
files_backends="imgui/backends/imgui_impl_sdl.cpp imgui/backends/imgui_impl_opengl3.cpp"
file_main="imgui/examples/example_emscripten_opengl3/main.cpp"

read -d '' -a flags_all <<EOF || true
  -s EXPORT_ALL=1 -fno-exceptions
  -I ./imgui/ -DIMGUI_IMPL_API=extern\ "C"
  -DIMGUI_DISABLE_FILE_FUNCTIONS -DIMGUI_DISABLE_OBSOLETE_FUNCTIONS=1
  -s USE_SDL=2
  -s USE_WEBGL2=1
EOF
read -r -d '' -a flags_debug <<EOF || true
  -s ASSERTIONS=1
  -DDEBUG -D_DEBUG -g
  -s ERROR_ON_UNDEFINED_SYMBOLS=1
EOF

#emcc --clear-cache

em++ -o imgui.wasm    -s SIDE_MODULE=1 $files_imgui    "${flags_all[@]}" -O2
em++ -o backends.wasm -s SIDE_MODULE=1 $files_backends "${flags_all[@]}" -O2 -I ./imgui/backends/

em++ -o web1.html -s MAIN_MODULE=2 imgui.wasm backends.wasm $file_main "${flags_all[@]}" "${flags_debug[@]}" -I ./imgui/backends/

python3 -m http.server 8002

The Problem :

It works well with MAIN_MODULE=1 ; But it wont work with MAIN_MODULE=2, Google Chrome outputs :

Uncaught TypeError: Module.canvas.exitPointerLock is not a function
    at _SDL_ShowCursor (web1.js:6422:28)
    at stubs.<computed> (web1.js:1985:33)
    at 500b98b2:0x17ac
    at _ImGui_ImplSDL2_NewFrame (web1.js:2311:45)
    at main_loop(void*) (web1.wasm:0x6d32)
    [...]

What's weird about it it that there is not much changes needed to make it works ;
There is 3 particular curious behaviours that I observed ;

1) SDL_ShowCursor is the only thing preventing the WHOLE ImGui to works :

--- a/backends/imgui_impl_sdl.cpp
+++ b/backends/imgui_impl_sdl.cpp
@@ -481,7 +481,7 @@ static void ImGui_ImplSDL2_UpdateMouseCursor()
     {
         // Show OS mouse cursor
         SDL_SetCursor(bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]);
-        SDL_ShowCursor(SDL_TRUE);
+//        SDL_ShowCursor(SDL_TRUE);
     }
 }
 

Commenting the above line make it works. (or changing it to SDL_FALSE);

2) Moving the SAME "code execution" of ONLY SDL_ShowCursor to the "main module" also works ;

I mean : this is the "call path" :

main.cpp (main module) calls ImGui_ImplSDL2_NewFrame()
`- which calls ImGui_ImplSDL2_UpdateMouseCursor() at its tail (discards the UpdateGamepads below to simplify)
 `- which calls SDL_ShowCursor(SDL_TRUE) at its tail

If you just do 2 things :

  • comment out the SDL_ShowCursor(SDL_TRUE) inside the "side module" (backends/imgui_impl_sdl.cpp)
  • add SDL_ShowCursor(SDL_TRUE) inside the "main module" just after the call to ImGui_ImplSDL2_NewFrame()

you would agree that the "code path execution" is the same.
(we just moved a call to SDL_ShowCursor , from the tail of the side module, to the tail of the function calling the side module)

Weirdly, it makes it works.

This is my biggest concern, of course as I shown it is work-around-able, but I wonder WHY moving a call from the "side module" to the "main module" makes it works.

Please note that I tried to enforce the SDL_ShowCursor function to not be "stripped / excluded" from the binary, by adding IN ALL CASES a call to it from the "main module", just before calling the "side module"'s ImGui_ImplSDL2_NewFrame() ;

I also tried to add a new function to the "side module", which just call SDL_ShowCursor, which I used to figure out the effect of calling SDL_ShowCursor from the "main module" vs/ with a slight indirection going through the "side module".

The observations holds : the call to SDL_ShowCursor(SDL_TRUE) from the "main module" passes okay, but if we call a one-liner function from the "side module" doing only this call, it does not work anymore.

So that's my observation : all things equal, calling SDL_ShowCursor(SDL_TRUE) from the "main module" works okay, and calling it (instead, or again, does not matter) from the "side module" JUST AFTER does not work.

So that's a little like "doing this thing from the main module works, doing the same thing from the side module does not work".

3) Slight difference in behaviour between MAIN_MODULE=1 and =2 ;

Possibly observable only on my macOS platform, due to high DPI stuff.

I told you that for MAIN_MODULE=1 to =2, to make it work, I just weirdly had to either :

  • comment out the call to SDL_ShowCursor()
  • or move this call to the "main module".

Well, I lied. I mean, it made ImGui mostly works, except that a bug of resolution / high dpi appears.
(the mouse coordinates are not where ImGui think it really is). This fix it :

--- a/examples/example_emscripten_opengl3/main.cpp
+++ b/examples/example_emscripten_opengl3/main.cpp
@@ -48,7 +48,7 @@ int main(int, char**)
     SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
     SDL_DisplayMode current;
     SDL_GetCurrentDisplayMode(0, &current);
-    SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
+    SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE /*| SDL_WINDOW_ALLOW_HIGHDPI*/);
     g_Window = SDL_CreateWindow("Dear ImGui Emscripten example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags);
     g_GLContext = SDL_GL_CreateContext(g_Window);
     if (!g_GLContext)

Of course it fixes it, I just commented some things related to HIGHDPI (without even knowing what I did)

What's weird me out there, is that there is some behaviour differences between MAIN_MODULE=1 and `=2.

Baring any linking or symbol problem, I would then have expected all behaviour to be the same ?

It tickles some curiosity, and maybe be a symptom of a bug.

Kind Regards,

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions